[Bf-blender-cvs] [60ddea77581] blender2.8: Workbench: Shadows: Add frustum check and camera occlusion test.

Clément Foucault noreply at git.blender.org
Sat May 26 23:23:41 CEST 2018


Commit: 60ddea7758128283f3ed3a15a2f8448691a811a8
Author: Clément Foucault
Date:   Sat May 26 22:28:35 2018 +0200
Branches: blender2.8
https://developer.blender.org/rB60ddea7758128283f3ed3a15a2f8448691a811a8

Workbench: Shadows: Add frustum check and camera occlusion test.

If the object is manifold and the camera is in the shadow side, we can
use the depth fail method to fix the inverted shadow glitch.

Unfortunately this does not really work for non-manifold.

Implementation details:
We try to be as efficient as we can, we precompute camera near plane
projected into 2D shadow space so we can test for intersection with the
shadow boundbox easily.

As the intersection test is done in 2D it's pretty fast.
Unfortunately, this means the shadow bounds are all aligned to the same
space and are not the smallest bound we could extract.

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

M	source/blender/draw/engines/workbench/workbench_deferred.c
M	source/blender/draw/engines/workbench/workbench_private.h
M	source/blender/draw/engines/workbench/workbench_studiolight.c
M	source/blender/draw/intern/DRW_render.h
M	source/blender/draw/intern/draw_manager_exec.c

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

diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c
index 9969a6b7127..b9dcb6bff8d 100644
--- a/source/blender/draw/engines/workbench/workbench_deferred.c
+++ b/source/blender/draw/engines/workbench/workbench_deferred.c
@@ -49,6 +49,10 @@
 
 // #define DEBUG_SHADOW_VOLUME
 
+#ifdef DEBUG_SHADOW_VOLUME
+#  include "draw_debug.h"
+#endif
+
 static struct {
 	struct GPUShader *prepass_sh_cache[MAX_SHADERS];
 	struct GPUShader *composite_sh_cache[MAX_SHADERS];
@@ -161,6 +165,7 @@ static void workbench_init_object_data(ObjectEngineData *engine_data)
 {
 	WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)engine_data;
 	data->object_id = e_data.next_object_id++;
+	data->shadow_bbox_dirty = true;
 }
 
 void workbench_deferred_engine_init(WORKBENCH_Data *vedata)
@@ -369,6 +374,8 @@ void workbench_deferred_cache_init(WORKBENCH_Data *vedata)
 			DRW_shgroup_uniform_float(grp, "shadowShift", &scene->display.shadow_shift, 1);
 			DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL);
 #endif
+
+			studiolight_update_light(wpd, e_data.display.light_direction);
 		}
 		else {
 			psl->composite_pass = DRW_pass_create(
@@ -542,44 +549,60 @@ void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob)
 					WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_object_engine_data_ensure(
 					        ob, &draw_engine_workbench_solid, sizeof(WORKBENCH_ObjectData), &workbench_init_object_data, NULL);
 
-					invert_m4_m4(ob->imat, ob->obmat);
-					mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction);
+					if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) {
 
-					DRWShadingGroup *grp;
-					/* TODO(fclem): only use shadow pass technique if camera is not in shadow. */
-					const bool use_shadow_pass_technique = true;
-					if (use_shadow_pass_technique) {
-						if (is_manifold) {
-							grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
-						}
-						else {
-							grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
+						invert_m4_m4(ob->imat, ob->obmat);
+						mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction);
+
+						DRWShadingGroup *grp;
+						bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow(wpd, ob, engine_object_data);
+
+						/* Unless we expose a parameter to the user, it's better to use the depth pass technique if the object is
+						 * non manifold. Exposing a switch to the user to force depth fail in this case can be beneficial for
+						 * planes and non-closed terrains. */
+						if (!is_manifold) {
+							use_shadow_pass_technique = true;
 						}
-						DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
-						DRW_shgroup_call_object_add(grp, geom_shadow, ob);
-					}
-					else {
-						/* TODO(fclem): only use caps if they are in the view frustum. */
-						const bool need_caps = true;
-						if (need_caps) {
+
+						if (use_shadow_pass_technique) {
 							if (is_manifold) {
-								grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, psl->shadow_depth_fail_caps_mani_pass);
+								grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass);
 							}
 							else {
-								grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
+								grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass);
 							}
 							DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
-							DRW_shgroup_call_object_add(grp, DRW_cache_object_surface_get(ob), ob);
-						}
-
-						if (is_manifold) {
-							grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
+							DRW_shgroup_call_add(grp, geom_shadow, ob->obmat);
+#ifdef DEBUG_SHADOW_VOLUME
+							DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f});
+#endif
 						}
 						else {
-							grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
+							/* TODO(fclem): only use caps if they are in the view frustum. */
+							const bool need_caps = true;
+							if (need_caps) {
+								if (is_manifold) {
+									grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, psl->shadow_depth_fail_caps_mani_pass);
+								}
+								else {
+									grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass);
+								}
+								DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+								DRW_shgroup_call_add(grp, DRW_cache_object_surface_get(ob), ob->obmat);
+							}
+
+							if (is_manifold) {
+								grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass);
+							}
+							else {
+								grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass);
+							}
+							DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
+							DRW_shgroup_call_add(grp, geom_shadow, ob->obmat);
+#ifdef DEBUG_SHADOW_VOLUME
+							DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f});
+#endif
 						}
-						DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1);
-						DRW_shgroup_call_object_add(grp, geom_shadow, ob);
 					}
 				}
 			}
diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h
index 9f520121919..7ef951abf84 100644
--- a/source/blender/draw/engines/workbench/workbench_private.h
+++ b/source/blender/draw/engines/workbench/workbench_private.h
@@ -127,6 +127,14 @@ typedef struct WORKBENCH_PrivateData {
 #endif
 	WORKBENCH_UBO_World world_data;
 	float shadow_multiplier;
+	float cached_shadow_direction[3];
+	float shadow_mat[4][4];
+	float shadow_inv[4][4];
+	float shadow_near_corners[4][3]; /* Near plane corners in shadow space. */
+	float shadow_near_min[2]; /* min and max of shadow_near_corners. allow fast test */
+	float shadow_near_max[2];
+	float shadow_near_sides[2][4]; /* This is a parallelogram, so only 2 normal and distance to the edges. */
+	bool shadow_changed;
 } WORKBENCH_PrivateData; /* Transient data */
 
 typedef struct WORKBENCH_MaterialData {
@@ -151,6 +159,9 @@ typedef struct WORKBENCH_ObjectData {
 	int recalc;
 	/* Shadow direction in local object space. */
 	float shadow_dir[3];
+	float shadow_min[3], shadow_max[3]; /* Min, max in shadow space */
+	BoundBox shadow_bbox;
+	bool shadow_bbox_dirty;
 
 	int object_id;
 } WORKBENCH_ObjectData;
@@ -191,6 +202,9 @@ void workbench_material_set_normal_world_matrix(
 
 /* workbench_studiolight.c */
 void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd);
+void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]);
+bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed);
+bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, Object *ob, WORKBENCH_ObjectData *oed);
 
 /* workbench_data.c */
 void workbench_private_data_init(WORKBENCH_PrivateData *wpd);
diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c
index 2142be3eaf4..a1cf4cdb4bc 100644
--- a/source/blender/draw/engines/workbench/workbench_studiolight.c
+++ b/source/blender/draw/engines/workbench/workbench_studiolight.c
@@ -27,7 +27,10 @@
 #include "DRW_engine.h"
 #include "workbench_private.h"
 
+#include "BKE_object.h"
+
 #include "BLI_math.h"
+#include "BKE_global.h"
 
 void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd)
 {
@@ -40,3 +43,134 @@ void studiolight_update_world(StudioLight *sl, WORKBENCH_UBO_World *wd)
 	copy_v3_v3(wd->diffuse_light_z_pos, sl->diffuse_light[STUDIOLIGHT_Z_POS]);
 	copy_v3_v3(wd->diffuse_light_z_neg, sl->diffuse_light[STUDIOLIGHT_Z_NEG]);
 }
+
+static void compute_parallel_lines_nor_and_dist(const float v1[2], const float v2[2], const float v3[2], float r_line[2])
+{
+	sub_v2_v2v2(r_line, v2, v1);
+	/* Find orthogonal vector. */
+	SWAP(float, r_line[0], r_line[1]);
+	r_line[0] = -r_line[0];
+	/* Edge distances. */
+	r_line[2] = dot_v2v2(r_line, v1);
+	r_line[3] = dot_v2v2(r_line, v3);
+	/* Make sure r_line[2] is the minimum. */
+	if (r_line[2] > r_line[3]) {
+		SWAP(float, r_line[2], r_line[3]);
+	}
+}
+
+void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3])
+{
+	wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f);
+
+	if (wpd->shadow_changed) {
+		float up[3] = {0.0f, 0.0f, 1.0f};
+		unit_m4(wpd->shadow_mat);
+
+		/* TODO fix singularity. */
+		copy_v3_v3(wpd->shadow_mat[2], light_direction);
+		cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up);
+		normalize_v3(wpd->shadow_mat[0]);
+		cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]);
+
+		invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat);
+
+		copy_v3_v3(wpd->cached_shadow_direction, light_direction);
+
+	}
+
+	BoundBox frustum_corners;
+	DRW_culling_frustum_corners_get(&frustum_corners);
+
+	mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]);
+	mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]);
+	mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]);
+	mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]);
+
+	INIT_MINMAX2(wpd->shadow_near_min, wpd->shadow_near_max);
+	for (int i = 0; i < 4; ++i) {
+		minmax_v2v2_v2(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]);
+	}
+
+	compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0], wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_sides[0]);
+	compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1], wpd->shadow_near_corners[2], wpd->shadow_near_corners[0], wpd->shadow_near_sides[1]);
+}
+
+static BoundBox *studio

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list