diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2017-05-27 22:35:03 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2017-05-29 16:52:27 +0300 |
commit | 932399612bdd444cdf7438ef04427864564b41b4 (patch) | |
tree | 3e065c89e4bb30f106d2c16da1a6c4cf358c2d8a /source/blender/draw | |
parent | 330007f571f2bb20d91bdec447072e44ed3f5648 (diff) |
3D grid: Fix precision issue 2/2
We now floor the corner position and use this position as origin.
This gives us perfect derivatives in all cases even if very far from the origin.
Unfortunately this won't fix the low precision of coordinates used for computing the actual grid size, resulting in thick, non-smoothed lines.
Also did a bit of refactor how the axes are drawn.
Diffstat (limited to 'source/blender/draw')
-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; |