[Bf-blender-cvs] [e104d823761] blender2.8: Object Mode Engine: Fixing the 3D grid 1/2

Clément Foucault noreply at git.blender.org
Mon May 29 15:52:54 CEST 2017


Commit: e104d82376134acd9b6c8729f271a03e83b64003
Author: Clément Foucault
Date:   Sat May 27 12:48:25 2017 +0200
Branches: blender2.8
https://developer.blender.org/rBe104d82376134acd9b6c8729f271a03e83b64003

Object Mode Engine: Fixing the 3D grid 1/2

Do not use the inverse perspective matrix inside the shader to recover world positions.
That leads to severe float imprecision leading to nasty artifacts.

Instead we compute the world view vector for each pixels and do a ray to plane intersection.
We are still getting low precision derivatives when going far away from the origin, and thus artifacts.

This commit also fixes the non-appearing negative Z axis in 3D view.

===================================================================

M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_manager.c
M	source/blender/draw/modes/object_mode.c
M	source/blender/draw/modes/shaders/object_grid_frag.glsl
M	source/blender/draw/modes/shaders/object_grid_vert.glsl

===================================================================

diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h
index 5c1c978806b..695027c5de6 100644
--- a/source/blender/draw/intern/DRW_render.h
+++ b/source/blender/draw/intern/DRW_render.h
@@ -307,6 +307,7 @@ typedef enum {
 	DRW_MAT_VIEW,
 	DRW_MAT_VIEWINV,
 	DRW_MAT_WIN,
+	DRW_MAT_WININV,
 } DRWViewportMatrixType;
 
 void DRW_viewport_init(const bContext *C);
diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c
index bbe3787dada..11c717a5373 100644
--- a/source/blender/draw/intern/draw_manager.c
+++ b/source/blender/draw/intern/draw_manager.c
@@ -2224,6 +2224,9 @@ void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type)
 		case DRW_MAT_WIN:
 			copy_m4_m4(mat, rv3d->winmat);
 			break;
+		case DRW_MAT_WININV:
+			invert_m4_m4(mat, rv3d->winmat);
+			break;
 		default:
 			BLI_assert(!"Matrix type invalid");
 			break;
diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c
index f308021a3c8..735c1173353 100644
--- a/source/blender/draw/modes/object_mode.c
+++ b/source/blender/draw/modes/object_mode.c
@@ -208,6 +208,7 @@ static struct {
 	GPUShader *part_prim_sh;
 	GPUShader *part_axis_sh;
 	float camera_pos[3];
+	float screenvecs[3][4];
 	float grid_settings[5];
 	float grid_mat[4][4];
 	int grid_flag;
@@ -306,7 +307,8 @@ static void OBJECT_engine_init(void *vedata)
 
 	{
 		/* Grid precompute */
-		float viewinvmat[4][4], winmat[4][4], invwinmat[4][4], viewmat[4][4];
+		float invviewmat[4][4], invwinmat[4][4];
+		float viewmat[4][4], winmat[4][4];
 		const DRWContextState *draw_ctx = DRW_context_state_get();
 		View3D *v3d = draw_ctx->v3d;
 		Scene *scene = draw_ctx->scene;
@@ -321,10 +323,11 @@ static void OBJECT_engine_init(void *vedata)
 
 		DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
 		DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
-		DRW_viewport_matrix_get(viewinvmat, DRW_MAT_VIEWINV);
+		DRW_viewport_matrix_get(invwinmat, DRW_MAT_WININV);
+		DRW_viewport_matrix_get(invviewmat, DRW_MAT_VIEWINV);
 
 		/* Setup camera pos */
-		copy_v3_v3(e_data.camera_pos, viewinvmat[3]);
+		copy_v3_v3(e_data.camera_pos, invviewmat[3]);
 
 		/* if perps */
 		if (winmat[3][3] == 0.0f) {
@@ -333,13 +336,11 @@ static void OBJECT_engine_init(void *vedata)
 			    {1.0f, -1.0f, -1.0f, 1.0f},
 			    {-1.0f, 1.0f, -1.0f, 1.0f}
 			};
-			/* invert the proj matrix */
-			invert_m4_m4(invwinmat, winmat);
 
 			/* convert the view vectors to view space */
 			for (int i = 0; i < 2; i++) {
 				mul_m4_v4(invwinmat, viewvecs[i]);
-				mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* normalize */
+				mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); /* perspective divide */
 			}
 
 			fov = angle_v3v3(viewvecs[0], viewvecs[1]) / 2.0f;
@@ -356,6 +357,7 @@ static void OBJECT_engine_init(void *vedata)
 				e_data.grid_flag |= SHOW_AXIS_Y;
 			if (show_floor)
 				e_data.grid_flag |= SHOW_GRID;
+
 		}
 		else {
 			float viewdist = 1.0f / max_ff(fabsf(winmat[0][0]), fabsf(winmat[1][1]));
@@ -393,12 +395,31 @@ static void OBJECT_engine_init(void *vedata)
 			}
 		}
 
+		/* Vectors to recover pixel world position. Fix grid precision issue. */
+		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);
+
+		for (int i = 0; i < 3; i++) {
+			/* Doing 2 steps to recover world position of the corners of the frustum.
+			 * Using the inverse perspective matrix is giving very low precision output. */
+			mul_m4_v4(invwinmat, e_data.screenvecs[i]);
+			e_data.screenvecs[i][0] /= e_data.screenvecs[i][3]; /* perspective divide */
+			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;
+			mul_m4_v4(invviewmat, e_data.screenvecs[i]);
+		}
+
+		sub_v3_v3(e_data.screenvecs[0], e_data.screenvecs[2]);
+		sub_v3_v3(e_data.screenvecs[1], e_data.screenvecs[2]);
+
 		/* Z axis if needed */
 		if (((rv3d->view == RV3D_VIEW_USER) || (rv3d->persp != RV3D_ORTHO)) && show_axis_z) {
 			e_data.zpos_flag = SHOW_AXIS_Z;
 
 			float zvec[4] = {0.0f, 0.0f, -1.0f, 0.0f};
-			mul_m4_v4(viewinvmat, zvec);
+			mul_m4_v4(invviewmat, zvec);
 
 			/* z axis : chose the most facing plane */
 			if (fabsf(zvec[0]) < fabsf(zvec[1])) {
@@ -754,9 +775,11 @@ static void OBJECT_cache_init(void *vedata)
 		DRW_shgroup_uniform_int(grp, "gridFlag", &e_data.zneg_flag, 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);
 		DRW_shgroup_uniform_vec4(grp, "gridSettings", e_data.grid_settings, 1);
 		DRW_shgroup_uniform_float(grp, "gridOneOverLogSubdiv", &e_data.grid_settings[4], 1);
 		DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo);
+		DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1);
 		DRW_shgroup_call_add(grp, quad, mat);
 
 		grp = DRW_shgroup_create(e_data.grid_sh, psl->grid);
diff --git a/source/blender/draw/modes/shaders/object_grid_frag.glsl b/source/blender/draw/modes/shaders/object_grid_frag.glsl
index 9b1283e46af..2db5100e1b3 100644
--- a/source/blender/draw/modes/shaders/object_grid_frag.glsl
+++ b/source/blender/draw/modes/shaders/object_grid_frag.glsl
@@ -2,14 +2,14 @@
 /* Infinite grid
  * Clément Foucault */
 
-in vec3 wPos;
-
 out vec4 FragColor;
 
 uniform mat4 ProjectionMatrix;
 uniform vec3 cameraPos;
 uniform vec3 eye;
 uniform vec4 gridSettings;
+uniform vec2 viewportSize;
+uniform vec4 screenvecs[3];
 uniform float gridOneOverLogSubdiv;
 
 #define gridDistance      gridSettings.x
@@ -54,8 +54,45 @@ float axis(float u, float fwidthU, float line_size)
 	return 1.0 - smoothstep(0.0, GRID_LINE_SMOOTH, axis_domain - line_size);
 }
 
+vec3 get_floor_pos(vec2 uv)
+{
+	/* if perspective */
+	vec3 camera_vec, camera_pos;
+	vec3 pixel_pos = screenvecs[2].xyz + uv.x * screenvecs[0].xyz + uv.y * screenvecs[1].xyz;
+
+	if (ProjectionMatrix[3][3] == 0.0) {
+		camera_vec = normalize(pixel_pos - cameraPos);
+		camera_pos = cameraPos;
+	}
+	else {
+		camera_vec = normalize(eye);
+		camera_pos = pixel_pos;
+	}
+
+	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);
+	vec3 plane = camera_pos + camera_vec * p;
+
+	/* fix residual imprecision */
+	vec3 mask = vec3(1.0) - plane_normal;
+	return plane * mask;
+}
+
 void main()
 {
+	vec2 sPos = gl_FragCoord.xy / viewportSize; /* Screen [0,1] position */
+	vec3 wPos = get_floor_pos(sPos);
+
 	vec3 fwidthCos = fwidth(wPos);
 
 	float dist, fade;
diff --git a/source/blender/draw/modes/shaders/object_grid_vert.glsl b/source/blender/draw/modes/shaders/object_grid_vert.glsl
index 2da8e45c560..2ecbfa8e11f 100644
--- a/source/blender/draw/modes/shaders/object_grid_vert.glsl
+++ b/source/blender/draw/modes/shaders/object_grid_vert.glsl
@@ -22,8 +22,6 @@ uniform int gridFlag;
 
 in vec3 pos;
 
-out vec3 wPos;
-
 void main()
 {
 	vec3 vert_pos, proj_camera_pos;
@@ -47,20 +45,19 @@ void main()
 		vert_pos *= gridDistance * 2.0;
 	}
 	else {
-		float viewdist = 1.0f / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1]));
+		float viewdist = 1.0 / min(abs(ProjectionMatrix[0][0]), abs(ProjectionMatrix[1][1]));
 		vert_pos *= viewdist * gridDistance * 2.0;
 	}
 
-	vec3 realPos = proj_camera_pos +  vert_pos;
+	vec3 realPos = proj_camera_pos + vert_pos;
 
 	/* Used for additional Z axis */
 	if ((gridFlag & CLIP_Z_POS) > 0) {
 		realPos.z = max(realPos.z, 0.0);
 	}
 	if ((gridFlag & CLIP_Z_NEG) > 0) {
-		realPos.z = min(realPos.z, 0.0);
+		realPos.z = min(-realPos.z, 0.0);
 	}
 
 	gl_Position = ViewProjectionOffsetMatrix * vec4(realPos, 1.0);
-	wPos = realPos;
 }




More information about the Bf-blender-cvs mailing list