diff options
-rw-r--r-- | source/blender/draw/modes/object_mode.c | 32 | ||||
-rw-r--r-- | source/blender/draw/modes/shaders/object_grid_frag.glsl | 121 |
2 files changed, 95 insertions, 58 deletions
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 133995269a4..f557315305d 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -212,8 +212,12 @@ static struct { float grid_settings[5]; float grid_mat[4][4]; int grid_flag; + float grid_normal[3]; + float grid_axes[3]; int zpos_flag; int zneg_flag; + float zplane_normal[3]; + float zplane_axes[3]; bool draw_grid; /* Temp buffer textures */ struct GPUTexture *outlines_depth_tx; @@ -397,7 +401,17 @@ static void OBJECT_engine_init(void *vedata) } } + e_data.grid_normal[0] = (float)((e_data.grid_flag & PLANE_YZ) != 0); + e_data.grid_normal[1] = (float)((e_data.grid_flag & PLANE_XZ) != 0); + e_data.grid_normal[2] = (float)((e_data.grid_flag & PLANE_XY) != 0); + + e_data.grid_axes[0] = (float)((e_data.grid_flag & (PLANE_XZ | PLANE_XY)) != 0); + e_data.grid_axes[1] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XY)) != 0); + e_data.grid_axes[2] = (float)((e_data.grid_flag & (PLANE_YZ | PLANE_XZ)) != 0); + /* Vectors to recover pixel world position. Fix grid precision issue. */ + /* Using pixel at z = 0.0f in ndc space : gives average precision between + * near and far plane. Note that it might not be the best choice. */ copy_v4_fl4(e_data.screenvecs[0], 1.0f, -1.0f, 0.0f, 1.0f); copy_v4_fl4(e_data.screenvecs[1], -1.0f, 1.0f, 0.0f, 1.0f); copy_v4_fl4(e_data.screenvecs[2], -1.0f, -1.0f, 0.0f, 1.0f); @@ -410,6 +424,9 @@ static void OBJECT_engine_init(void *vedata) e_data.screenvecs[i][1] /= e_data.screenvecs[i][3]; /* perspective divide */ e_data.screenvecs[i][2] /= e_data.screenvecs[i][3]; /* perspective divide */ e_data.screenvecs[i][3] = 1.0f; + /* main instability come from this one */ + /* TODO : to make things even more stable, don't use + * invviewmat and derive vectors from camera properties */ mul_m4_v4(invviewmat, e_data.screenvecs[i]); } @@ -444,6 +461,15 @@ static void OBJECT_engine_init(void *vedata) e_data.zpos_flag |= CLIP_ZNEG; e_data.zneg_flag |= CLIP_ZPOS; } + + e_data.zplane_normal[0] = (float)((e_data.zpos_flag & PLANE_YZ) != 0); + e_data.zplane_normal[1] = (float)((e_data.zpos_flag & PLANE_XZ) != 0); + e_data.zplane_normal[2] = (float)((e_data.zpos_flag & PLANE_XY) != 0); + + e_data.zplane_axes[0] = (float)((e_data.zpos_flag & (PLANE_XZ | PLANE_XY)) != 0); + e_data.zplane_axes[1] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XY)) != 0); + e_data.zplane_axes[2] = (float)((e_data.zpos_flag & (PLANE_YZ | PLANE_XZ)) != 0); + } else { e_data.zneg_flag = e_data.zpos_flag = CLIP_ZNEG | CLIP_ZPOS; @@ -775,6 +801,8 @@ static void OBJECT_cache_init(void *vedata) /* Create 3 quads to render ordered transparency Z axis */ DRWShadingGroup *grp = DRW_shgroup_create(e_data.grid_sh, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 1); + DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1); + DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1); DRW_shgroup_uniform_mat4(grp, "ViewProjectionOffsetMatrix", (float *)e_data.grid_mat); DRW_shgroup_uniform_vec3(grp, "cameraPos", e_data.camera_pos, 1); DRW_shgroup_uniform_vec4(grp, "screenvecs[0]", e_data.screenvecs[0], 3); @@ -786,10 +814,14 @@ static void OBJECT_cache_init(void *vedata) grp = DRW_shgroup_create(e_data.grid_sh, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.grid_flag, 1); + DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.grid_normal, 1); + DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1); DRW_shgroup_call_add(grp, quad, mat); grp = DRW_shgroup_create(e_data.grid_sh, psl->grid); DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zpos_flag, 1); + DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1); + DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1); DRW_shgroup_call_add(grp, quad, mat); } diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl index 2db5100e1b3..0196b1a6f98 100644 --- a/source/blender/draw/modes/shaders/object_grid_frag.glsl +++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl @@ -2,10 +2,13 @@ /* Infinite grid * Clément Foucault */ + out vec4 FragColor; uniform mat4 ProjectionMatrix; uniform vec3 cameraPos; +uniform vec3 planeNormal; +uniform vec3 planeAxes; uniform vec3 eye; uniform vec4 gridSettings; uniform vec2 viewportSize; @@ -29,12 +32,12 @@ uniform int gridFlag; #define GRID_LINE_SMOOTH 1.15 -float grid(vec3 uv, vec3 fwidthCos, float grid_size) +float get_grid(vec3 co, vec3 fwidthCos, float grid_size) { float half_size = grid_size / 2.0; /* triangular wave pattern, amplitude is [0, grid_size] */ - vec3 grid_domain = abs(mod(uv + half_size, grid_size) - half_size); - /* modulate by the absolute rate of change of the uvs + vec3 grid_domain = abs(mod(co + half_size, grid_size) - half_size); + /* modulate by the absolute rate of change of the coordinates * (make lines have the same width under perspective) */ grid_domain /= fwidthCos; @@ -44,56 +47,58 @@ float grid(vec3 uv, vec3 fwidthCos, float grid_size) return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH / grid_size, grid_domain.x); } -float axis(float u, float fwidthU, float line_size) +vec3 get_axes(vec3 co, vec3 fwidthCos, float line_size) { - float axis_domain = abs(u); - /* modulate by the absolute rate of change of the uvs + vec3 axes_domain = abs(co); + /* modulate by the absolute rate of change of the coordinates * (make line have the same width under perspective) */ - axis_domain /= fwidthU; + axes_domain /= fwidthCos; - return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH, axis_domain - line_size); + return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH, axes_domain - line_size); } -vec3 get_floor_pos(vec2 uv) +vec3 get_floor_pos(vec2 uv, out vec3 wPos) { - /* if perspective */ - vec3 camera_vec, camera_pos; - vec3 pixel_pos = screenvecs[2].xyz + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz; + vec3 camera_vec, camera_pos, corner_pos; + vec3 floored_pos = planeAxes * floor(screenvecs[2].xyz); + corner_pos = screenvecs[2].xyz - floored_pos; + + vec3 pixel_pos = corner_pos + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz; + /* if perspective */ if (ProjectionMatrix[3][3] == 0.0) { - camera_vec = normalize(pixel_pos - cameraPos); - camera_pos = cameraPos; + camera_pos = cameraPos - floored_pos; + camera_vec = normalize(pixel_pos - camera_pos); } else { - camera_vec = normalize(eye); camera_pos = pixel_pos; + camera_vec = normalize(eye); } - vec3 plane_normal; - if ((gridFlag & PLANE_XZ) > 0) { - plane_normal = vec3(0.0, 1.0, 0.0); - } - else if ((gridFlag & PLANE_YZ) > 0) { - plane_normal = vec3(1.0, 0.0, 0.0); - } - else { - plane_normal = vec3(0.0, 0.0, 1.0); - } - - float p = -dot(plane_normal, camera_pos) / dot(plane_normal, camera_vec); + float p = -dot(planeNormal, camera_pos) / dot(planeNormal, camera_vec); vec3 plane = camera_pos + camera_vec * p; /* fix residual imprecision */ - vec3 mask = vec3(1.0) - plane_normal; - return plane * mask; + plane *= planeAxes; + + /* Recover non-offseted world position */ + wPos = plane + floored_pos; + + return plane; } void main() { vec2 sPos = gl_FragCoord.xy / viewportSize; /* Screen [0,1] position */ - vec3 wPos = get_floor_pos(sPos); - vec3 fwidthCos = fwidth(wPos); + /* To reduce artifacts, use a local version of the positions + * to compute derivatives since they are not position dependant. + * This gets rid of the blocky artifacts. Unfortunately we still + * need the world position for the grid to scale properly from the origin. */ + vec3 gPos, wPos; /* Grid pos., World pos. */ + gPos = get_floor_pos(sPos, wPos); + + vec3 fwidthPos = fwidth(gPos); float dist, fade; /* if persp */ @@ -132,14 +137,14 @@ void main() float blend = fract(-max(grid_res, 0.0)); float lvl = floor(grid_res); - /* from smallest to biggest */ + /* from biggest to smallest */ float scaleA = gridScale * pow(gridSubdiv, max(lvl - 1.0, 0.0)); float scaleB = gridScale * pow(gridSubdiv, max(lvl + 0.0, 0.0)); float scaleC = gridScale * pow(gridSubdiv, max(lvl + 1.0, 1.0)); - float gridA = grid(wPos, fwidthCos, scaleA); - float gridB = grid(wPos, fwidthCos, scaleB); - float gridC = grid(wPos, fwidthCos, scaleC); + float gridA = get_grid(wPos, fwidthPos, scaleA); + float gridB = get_grid(wPos, fwidthPos, scaleB); + float gridC = get_grid(wPos, fwidthPos, scaleC); FragColor = vec4(colorGrid.rgb, gridA * blend); FragColor = mix(FragColor, vec4(mix(colorGrid.rgb, colorGridEmphasise.rgb, blend), 1.0), gridB); @@ -149,35 +154,35 @@ void main() FragColor = vec4(colorGrid.rgb, 0.0); } - if ((gridFlag & AXIS_X) > 0) { - float xAxis; - if ((gridFlag & PLANE_XZ) > 0) { - xAxis = axis(wPos.z, fwidthCos.z, 0.1); + if ((gridFlag & (AXIS_X | AXIS_Y | AXIS_Z)) > 0) { + /* Setup axes 'domains' */ + vec3 axes_dist, axes_fwidth; + + if ((gridFlag & AXIS_X) > 0) { + axes_dist.x = dot(wPos.yz, planeAxes.yz); + axes_fwidth.x = dot(fwidthPos.yz, planeAxes.yz); } - else { - xAxis = axis(wPos.y, fwidthCos.y, 0.1); + if ((gridFlag & AXIS_Y) > 0) { + axes_dist.y = dot(wPos.xz, planeAxes.xz); + axes_fwidth.y = dot(fwidthPos.xz, planeAxes.xz); } - FragColor = mix(FragColor, colorGridAxisX, xAxis); - } - if ((gridFlag & AXIS_Y) > 0) { - float yAxis; - if ((gridFlag & PLANE_YZ) > 0) { - yAxis = axis(wPos.z, fwidthCos.z, 0.1); + if ((gridFlag & AXIS_Z) > 0) { + axes_dist.z = dot(wPos.xy, planeAxes.xy); + axes_fwidth.z = dot(fwidthPos.xy, planeAxes.xy); } - else { - yAxis = axis(wPos.x, fwidthCos.x, 0.1); + + /* Computing all axes at once using vec3 */ + vec3 axes = get_axes(axes_dist, axes_fwidth, 0.1); + + if ((gridFlag & AXIS_X) > 0) { + FragColor = mix(FragColor, colorGridAxisX, axes.x); } - FragColor = mix(FragColor, colorGridAxisY, yAxis); - } - if ((gridFlag & AXIS_Z) > 0) { - float zAxis; - if ((gridFlag & PLANE_YZ) > 0) { - zAxis = axis(wPos.y, fwidthCos.y, 0.1); + if ((gridFlag & AXIS_Y) > 0) { + FragColor = mix(FragColor, colorGridAxisY, axes.y); } - else { - zAxis = axis(wPos.x, fwidthCos.x, 0.1); + if ((gridFlag & AXIS_Z) > 0) { + FragColor = mix(FragColor, colorGridAxisZ, axes.z); } - FragColor = mix(FragColor, colorGridAxisZ, zAxis); } FragColor.a *= fade; |