[Bf-blender-cvs] [3e4b9d2b5a6] blender2.8: Eevee: Initial implementation of planar reflections.

Clément Foucault noreply at git.blender.org
Mon Jun 19 10:48:12 CEST 2017


Commit: 3e4b9d2b5a6479ef71cdedf980bcd714f4f94d56
Author: Clément Foucault
Date:   Sat Jun 17 00:08:03 2017 +0200
Branches: blender2.8
https://developer.blender.org/rB3e4b9d2b5a6479ef71cdedf980bcd714f4f94d56

Eevee: Initial implementation of planar reflections.

Still pretty barebone: No roughness support, No normal distortion support.

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

M	source/blender/draw/engines/eevee/eevee_data.c
M	source/blender/draw/engines/eevee/eevee_engine.c
M	source/blender/draw/engines/eevee/eevee_lightprobes.c
M	source/blender/draw/engines/eevee/eevee_materials.c
M	source/blender/draw/engines/eevee/eevee_private.h
M	source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl
M	source/blender/draw/engines/eevee/shaders/lit_surface_frag.glsl

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

diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c
index 9dfc3e5f07b..da1f5317dab 100644
--- a/source/blender/draw/engines/eevee/eevee_data.c
+++ b/source/blender/draw/engines/eevee/eevee_data.c
@@ -54,6 +54,7 @@ static void eevee_scene_layer_data_free(void *storage)
 	MEM_SAFE_FREE(sldata->probes);
 	DRW_UBO_FREE_SAFE(sldata->probe_ubo);
 	DRW_UBO_FREE_SAFE(sldata->grid_ubo);
+	DRW_UBO_FREE_SAFE(sldata->planar_ubo);
 	DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb);
 	DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb);
 	DRW_TEXTURE_FREE_SAFE(sldata->probe_rt);
diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c
index c13351be43c..325758f4eb9 100644
--- a/source/blender/draw/engines/eevee/eevee_engine.c
+++ b/source/blender/draw/engines/eevee/eevee_engine.c
@@ -57,7 +57,7 @@ static void EEVEE_engine_init(void *ved)
 
 	EEVEE_materials_init();
 	EEVEE_lights_init(sldata);
-	EEVEE_lightprobes_init(sldata);
+	EEVEE_lightprobes_init(sldata, vedata);
 	EEVEE_effects_init(vedata);
 }
 
@@ -134,7 +134,7 @@ static void EEVEE_draw_scene(void *vedata)
 	EEVEE_draw_shadows(sldata, psl);
 
 	/* Refresh Probes */
-	EEVEE_lightprobes_refresh(sldata, psl);
+	EEVEE_lightprobes_refresh(sldata, vedata);
 
 	/* Attach depth to the hdr buffer and bind it */	
 	DRW_framebuffer_texture_detach(dtxl->depth);
diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c
index bfb1b43e28b..a58c338b14b 100644
--- a/source/blender/draw/engines/eevee/eevee_lightprobes.c
+++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c
@@ -59,6 +59,7 @@ static struct {
 	struct GPUShader *probe_cube_display_sh;
 
 	struct GPUTexture *hammersley;
+	struct GPUTexture *planar_depth;
 
 	bool update_world;
 	bool world_ready_to_shade;
@@ -112,7 +113,46 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples)
 	return tex;
 }
 
-void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
+static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref)
+{
+	/* XXX TODO OPTIMISATION : This is a complete waist of texture memory.
+	 * Instead of allocating each planar probe for each viewport,
+	 * only alloc them once using the biggest viewport resolution. */
+	EEVEE_FramebufferList *fbl = vedata->fbl;
+	EEVEE_TextureList *txl = vedata->txl;
+
+	const float *viewport_size = DRW_viewport_size_get();
+
+	/* TODO get screen percentage from layer setting */
+	// const DRWContextState *draw_ctx = DRW_context_state_get();
+	// SceneLayer *sl = draw_ctx->sl;
+	float screen_percentage = 1.0f;
+
+	int width = (int)(viewport_size[0] * screen_percentage);
+	int height = (int)(viewport_size[1] * screen_percentage);
+
+	/* We need an Array texture so allocate it ourself */
+	if (!txl->planar_pool && (num_planar_ref > 0)) {
+		txl->planar_pool = DRW_texture_create_2D_array(width, height, max_ff(1, num_planar_ref),
+		                                                 DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL);
+	}
+	else if (txl->planar_pool && (num_planar_ref == 0)) {
+		DRW_TEXTURE_FREE_SAFE(txl->planar_pool);
+	}
+
+	if (num_planar_ref > 0) {
+		/* NOTE : Depth buffer is 2D but the planar_pool tex is 2D array.
+		 * DRW_framebuffer_init binds the whole texture making the framebuffer invalid.
+		 * To overcome this, we bind the planar pool ourselves later */
+
+		DRWFboTexture tex = {&e_data.planar_depth, DRW_TEX_DEPTH_24, DRW_TEX_TEMP};
+
+		DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type,
+		                     width, height, &tex, 1);
+	}
+}
+
+void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata, EEVEE_Data *UNUSED(vedata))
 {
 	/* Shaders */
 	if (!e_data.probe_filter_glossy_sh) {
@@ -195,6 +235,7 @@ void EEVEE_lightprobes_init(EEVEE_SceneLayerData *sldata)
 		sldata->probes->specular_toggle = true;
 		sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL);
 		sldata->grid_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightGrid) * MAX_GRID, NULL);
+		sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL);
 	}
 
 	/* Setup Render Target Cubemap */
@@ -215,8 +256,10 @@ void EEVEE_lightprobes_cache_init(EEVEE_SceneLayerData *sldata, EEVEE_PassList *
 
 	pinfo->num_cube = 1; /* at least one for the world */
 	pinfo->num_grid = 1;
+	pinfo->num_planar = 0;
 	memset(pinfo->probes_cube_ref, 0, sizeof(pinfo->probes_cube_ref));
 	memset(pinfo->probes_grid_ref, 0, sizeof(pinfo->probes_grid_ref));
+	memset(pinfo->probes_planar_ref, 0, sizeof(pinfo->probes_planar_ref));
 
 	{
 		psl->probe_background = DRW_pass_create("World Probe Pass", DRW_STATE_WRITE_COLOR);
@@ -356,17 +399,122 @@ void EEVEE_lightprobes_cache_add(EEVEE_SceneLayerData *sldata, Object *ob)
 		pinfo->probes_cube_ref[pinfo->num_cube] = ob;
 		pinfo->num_cube++;
 	}
+	else if (probe->type == LIGHTPROBE_TYPE_PLANAR) {
+		pinfo->probes_planar_ref[pinfo->num_planar] = ob;
+		pinfo->num_planar++;
+	}
 	else { /* GRID */
 		pinfo->probes_grid_ref[pinfo->num_grid] = ob;
 		pinfo->num_grid++;
 	}
 }
 
+/* TODO find a nice name to push it to math_matrix.c */
+static void scale_m4_v3(float R[4][4], float v[3])
+{
+	for (int i = 0; i < 4; ++i)
+		mul_v3_v3(R[i], v);
+}
+
+static void EEVEE_planar_reflections_updates(EEVEE_SceneLayerData *sldata)
+{
+	EEVEE_LightProbesInfo *pinfo = sldata->probes;
+	Object *ob;
+	float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4];
+
+	float viewmat[4][4], winmat[4][4];
+	DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW);
+	DRW_viewport_matrix_get(winmat, DRW_MAT_WIN);
+
+	zero_m4(rangemat);
+	rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f;
+	rangemat[3][0] = rangemat[3][1] = rangemat[3][2] = 0.5f;
+	rangemat[3][3] = 1.0f;
+
+	/* PLANAR REFLECTION */
+	for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) {
+		LightProbe *probe = (LightProbe *)ob->data;
+		EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i];
+		EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(ob);
+
+		/* Computing mtx : matrix that mirror position around object's XY plane. */
+		normalize_m4_m4(normat, ob->obmat);  /* object > world */
+		invert_m4_m4(imat, normat); /* world > object */
+
+		float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */
+		scale_m4_v3(imat, reflect); /* world > object > mirrored obj */
+		mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */
+
+		/* Reflect Camera Matrix. */
+		mul_m4_m4m4(ped->viewmat, viewmat, mtx);
+
+		/* TODO FOV margin */
+		float winmat_fov[4][4];
+		copy_m4_m4(winmat_fov, winmat);
+
+		/* Apply Perspective Matrix. */
+		mul_m4_m4m4(ped->persmat, winmat_fov, ped->viewmat);
+
+		/* This is the matrix used to reconstruct texture coordinates.
+		 * We use the original view matrix because it does not create
+		 * visual artifacts if receiver is not perfectly aligned with
+		 * the planar reflection probe. */
+		mul_m4_m4m4(eplanar->reflectionmat, winmat_fov, viewmat); /* TODO FOV margin */
+		/* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */
+		mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat);
+
+		/* TODO frustum check. */
+		ped->need_update = true;
+
+		/* Compute clip plane equation / normal. */
+		float refpoint[3];
+		copy_v3_v3(eplanar->plane_equation, ob->obmat[2]);
+		normalize_v3(eplanar->plane_equation); /* plane normal */
+		mul_v3_v3fl(refpoint, eplanar->plane_equation, -probe->clipsta);
+		add_v3_v3(refpoint, ob->obmat[3]);
+		eplanar->plane_equation[3] = -dot_v3v3(eplanar->plane_equation, refpoint);
+
+		/* Compute XY clip planes. */
+		normalize_v3_v3(eplanar->clip_vec_x, ob->obmat[0]);
+		normalize_v3_v3(eplanar->clip_vec_y, ob->obmat[1]);
+
+		float vec[3] = {0.0f, 0.0f, 0.0f};
+		vec[0] = 1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+		mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+		eplanar->clip_edge_x_pos = dot_v3v3(eplanar->clip_vec_x, vec);
+
+		vec[0] = 0.0f; vec[1] = 1.0f; vec[2] = 0.0f;
+		mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+		eplanar->clip_edge_y_pos = dot_v3v3(eplanar->clip_vec_y, vec);
+
+		vec[0] = -1.0f; vec[1] = 0.0f; vec[2] = 0.0f;
+		mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+		eplanar->clip_edge_x_neg = dot_v3v3(eplanar->clip_vec_x, vec);
+
+		vec[0] = 0.0f; vec[1] = -1.0f; vec[2] = 0.0f;
+		mul_m4_v3(ob->obmat, vec); /* Point on the edge */
+		eplanar->clip_edge_y_neg = dot_v3v3(eplanar->clip_vec_y, vec);
+
+		/* Facing factors */
+		float max_angle = max_ff(1e-2f, probe->falloff) * M_PI * 0.5f;
+		float min_angle = 0.0f;
+		eplanar->facing_scale = 1.0f / max_ff(1e-8f, cosf(min_angle) - cosf(max_angle));
+		eplanar->facing_bias = -min_ff(1.0f - 1e-8f, cosf(max_angle)) * eplanar->facing_scale;
+
+		/* Distance factors */
+		float max_dist = probe->distinf;
+		float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf;
+		eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist);
+		eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale;
+	}
+}
+
 static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassList *psl, EEVEE_StorageList *stl)
 {
 	EEVEE_LightProbesInfo *pinfo = sldata->probes;
 	Object *ob;
 
+	/* CUBE REFLECTION */
 	for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) {
 		LightProbe *probe = (LightProbe *)ob->data;
 		EEVEE_LightProbe *eprobe = &pinfo->probe_data[i];
@@ -406,6 +554,7 @@ static void EEVEE_lightprobes_updates(EEVEE_SceneLayerData *sldata, EEVEE_PassLi
 		}
 	}
 
+	/* IRRADIANCE GRID */
 	int offset = 1; /* to account for the world probe */
 	for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_GRID); i++) {
 		LightProbe *probe = (LightProbe *)ob->data;
@@ -485,6 +634,14 @@ void EEVEE_lightprobes_cache_finish(EEVEE_SceneLayerData *sldata, EEVEE_Data *ve
 		DRW_TEXTURE_FREE_SAFE(sldata->probe_pool);
 	}
 
+	if (pinfo->num_planar != pinfo->cache_num_planar) {
+		DRW_TEXTURE_FREE_SAFE(vedata->txl->planar_pool);
+		pinfo->cache_num_planar = pinfo->num_planar;
+	}
+
+	/* XXX this should be run each frame as it

@@ Diff output truncated at 10240 characters. @@




More information about the Bf-blender-cvs mailing list