[Bf-blender-cvs] [03e432bcdbd] blender2.8: Eevee: Implement Sun area lighting and few fixes/opti.

Clément Foucault noreply at git.blender.org
Thu Jan 18 22:43:21 CET 2018


Commit: 03e432bcdbd61ccea2d74065203af199b46b2e83
Author: Clément Foucault
Date:   Thu Jan 18 21:51:23 2018 +0100
Branches: blender2.8
https://developer.blender.org/rB03e432bcdbd61ccea2d74065203af199b46b2e83

Eevee: Implement Sun area lighting and few fixes/opti.

Sun is treated as a unit distant disk like in cycles.

Opti: Since computing the diffuse contribution via LTC is the same as not using the Linear Transformation, we can bypass most of the LTC code.
This replaces the sphere analytical diffuse computation as it gives a more pleasing result very close to cycles' AND cheaper.

Lights power have been retweaked to be coherent with cycles (except sun lamp with large radius where cycles has a non-uniform light distribution).

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

M	source/blender/draw/engines/eevee/eevee_lights.c
M	source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
M	source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
M	source/blender/draw/engines/eevee/shaders/ltc_lib.glsl

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

diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c
index 3a9aaf9ede7..63c0b540cdf 100644
--- a/source/blender/draw/engines/eevee/eevee_lights.c
+++ b/source/blender/draw/engines/eevee/eevee_lights.c
@@ -599,13 +599,14 @@ static void eevee_light_setup(Object *ob, EEVEE_Light *evli)
 	}
 	else if (la->type == LA_SPOT || la->type == LA_LOCAL) {
 		power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(4*r²*Pi²) */
-		        M_PI * M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
+		        M_PI * M_PI * 10.0; /* XXX : Empirical, Fit cycles power */
 
 		/* for point lights (a.k.a radius == 0.0) */
 		// power = M_PI * M_PI * 0.78; /* XXX : Empirical, Fit cycles power */
 	}
 	else {
-		power = 1.0f;
+		power = 1.0f / (4.0f * evli->radius * evli->radius * M_PI * M_PI) * /* 1/(r²*Pi) */
+		        12.5f; /* XXX : Empirical, Fit cycles power */
 	}
 	mul_v3_fl(evli->color, power * la->energy);
 
diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
index 0b215fd0716..ddc7327334c 100644
--- a/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/bsdf_direct_lib.glsl
@@ -28,54 +28,30 @@ float direct_diffuse_sun(LightData ld, vec3 N)
 	return bsdf;
 }
 
-/* From Frostbite PBR Course
- * Analytical irradiance from a sphere with correct horizon handling
- * http://www.frostbite.com/wp-content/uploads/2014/11/course_notes_moving_frostbite_to_pbr.pdf */
+#ifdef USE_LTC
 float direct_diffuse_sphere(LightData ld, vec3 N, vec4 l_vector)
 {
-	float dist = l_vector.w;
-	vec3 L = l_vector.xyz / dist;
-	float radius = max(ld.l_sizex, 0.0001);
-	float costheta = clamp(dot(N, L), -0.999, 0.999);
-	float h = min(ld.l_radius / dist , 0.9999);
-	float h2 = h*h;
-	float costheta2 = costheta * costheta;
-	float bsdf;
-
-	if (costheta2 > h2) {
-		bsdf = M_PI * h2 * clamp(costheta, 0.0, 1.0);
-	}
-	else {
-		float sintheta = sqrt(1.0 - costheta2);
-		float x = sqrt(1.0 / h2 - 1.0);
-		float y = -x * (costheta / sintheta);
-		float sinthetasqrty = sintheta * sqrt(1.0 - y * y);
-		bsdf = (costheta * acos(y) - x * sinthetasqrty) * h2 + atan(sinthetasqrty / x);
-	}
-
-	bsdf = max(bsdf, 0.0);
-	bsdf *= M_1_PI2;
+	float NL = dot(N, l_vector.xyz / l_vector.w);
 
-	return bsdf;
+	return ltc_evaluate_disk_simple(ld.l_radius / l_vector.w, NL);
 }
 
-#ifdef USE_LTC
 float direct_diffuse_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector)
 {
 	vec3 corners[4];
-	corners[0] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up *  ld.l_sizey;
-	corners[1] = l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey;
-	corners[2] = l_vector.xyz + ld.l_right *  ld.l_sizex + ld.l_up * -ld.l_sizey;
-	corners[3] = l_vector.xyz + ld.l_right *  ld.l_sizex + ld.l_up *  ld.l_sizey;
+	corners[0] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up *  ld.l_sizey);
+	corners[1] = normalize(l_vector.xyz + ld.l_right * -ld.l_sizex + ld.l_up * -ld.l_sizey);
+	corners[2] = normalize(l_vector.xyz + ld.l_right *  ld.l_sizex + ld.l_up * -ld.l_sizey);
+	corners[3] = normalize(l_vector.xyz + ld.l_right *  ld.l_sizex + ld.l_up *  ld.l_sizey);
 
-	return ltc_evaluate_quad_diffuse(corners);
+	return ltc_evaluate_quad(corners, N);
 }
-#endif
 
-#if 0
-float direct_diffuse_unit_disc(vec3 N, vec3 L)
+float direct_diffuse_unit_disc(LightData ld, vec3 N, vec3 V)
 {
+	float NL = dot(N, -ld.l_forward);
 
+	return ltc_evaluate_disk_simple(ld.l_radius, NL);
 }
 #endif
 
@@ -125,7 +101,6 @@ vec3 direct_ggx_sphere(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughn
 
 	float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points);
 	bsdf *= brdf_lut.b; /* Bsdf intensity */
-	bsdf *= M_1_PI;
 
 	vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
 
@@ -145,18 +120,37 @@ vec3 direct_ggx_rectangle(LightData ld, vec3 N, vec3 V, vec4 l_vector, float rou
 	vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
 	mat3 ltc_mat = ltc_matrix(ltc_lut);
 
-	float bsdf = ltc_evaluate_quad(N, V, ltc_mat, corners);
+	ltc_transform_quad(N, V, ltc_mat, corners);
+	float bsdf = ltc_evaluate_quad(corners, vec3(0.0, 0.0, 1.0));
 	bsdf *= brdf_lut.b; /* Bsdf intensity */
 
 	vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
 
 	return spec;
 }
-#endif
 
-#if 0
-float direct_ggx_disc(vec3 N, vec3 L)
+vec3 direct_ggx_unit_disc(LightData ld, vec3 N, vec3 V, float roughness, vec3 f0)
 {
+	roughness = clamp(roughness, 0.0004, 0.999); /* Fix low roughness artifacts. */
 
+	vec2 uv = lut_coords(dot(N, V), sqrt(roughness));
+	vec3 brdf_lut = texture(utilTex, vec3(uv, 1.0)).rgb;
+	vec4 ltc_lut = texture(utilTex, vec3(uv, 0.0)).rgba;
+	mat3 ltc_mat = ltc_matrix(ltc_lut);
+
+	vec3 Px = ld.l_right * ld.l_radius;
+	vec3 Py = ld.l_up * ld.l_radius;
+
+	vec3 points[3];
+	points[0] = -ld.l_forward - Px - Py;
+	points[1] = -ld.l_forward + Px - Py;
+	points[2] = -ld.l_forward + Px + Py;
+
+	float bsdf = ltc_evaluate_disk(N, V, ltc_mat, points);
+	bsdf *= brdf_lut.b; /* Bsdf intensity */
+
+	vec3 spec = F_area(f0, brdf_lut.xy) * bsdf;
+
+	return spec;
 }
 #endif
\ No newline at end of file
diff --git a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
index 2bc96b3dc18..799f182af1d 100644
--- a/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/lamps_lib.glsl
@@ -234,8 +234,7 @@ float light_diffuse(LightData ld, vec3 N, vec3 V, vec4 l_vector)
 {
 #ifdef USE_LTC
 	if (ld.l_type == SUN) {
-		/* TODO disk area light */
-		return direct_diffuse_sun(ld, N);
+		return direct_diffuse_unit_disc(ld, N, V);
 	}
 	else if (ld.l_type == AREA) {
 		return direct_diffuse_rectangle(ld, N, V, l_vector);
@@ -257,8 +256,7 @@ vec3 light_specular(LightData ld, vec3 N, vec3 V, vec4 l_vector, float roughness
 {
 #ifdef USE_LTC
 	if (ld.l_type == SUN) {
-		/* TODO disk area light */
-		return direct_ggx_sun(ld, N, V, roughness, f0);
+		return direct_ggx_unit_disc(ld, N, V, roughness, f0);
 	}
 	else if (ld.l_type == AREA) {
 		return direct_ggx_rectangle(ld, N, V, l_vector, roughness, f0);
diff --git a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
index 915e6a5cebc..5c62cb19152 100644
--- a/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
+++ b/source/blender/draw/engines/eevee/shaders/ltc_lib.glsl
@@ -15,17 +15,17 @@ uniform sampler2DArray utilTex;
 #endif /* UTIL_TEX */
 
 /* Diffuse *clipped* sphere integral. */
-float diffuse_sphere_integral_lut(vec3 avg_dir, float form_factor)
+float diffuse_sphere_integral_lut(float avg_dir_z, float form_factor)
 {
-	vec2 uv = vec2(avg_dir.z * 0.5 + 0.5, form_factor);
+	vec2 uv = vec2(avg_dir_z * 0.5 + 0.5, form_factor);
 	uv = uv * (LUT_SIZE - 1.0) / LUT_SIZE + 0.5 / LUT_SIZE;
 
 	return texture(utilTex, vec3(uv, 1.0)).w;
 }
 
-float diffuse_sphere_integral_cheap(vec3 avg_dir, float form_factor)
+float diffuse_sphere_integral_cheap(float avg_dir_z, float form_factor)
 {
-	return max((form_factor * form_factor + avg_dir.z) / (form_factor + 1.0), 0.0);
+	return max((form_factor * form_factor + avg_dir_z) / (form_factor + 1.0), 0.0);
 }
 
 /**
@@ -149,7 +149,7 @@ mat3 ltc_matrix(vec4 lut)
 	return Minv;
 }
 
-float ltc_evaluate_quad(vec3 N, vec3 V, mat3 Minv, vec3 corners[4])
+void ltc_transform_quad(vec3 N, vec3 V, mat3 Minv, inout vec3 corners[4])
 {
 	/* Avoid dot(N, V) == 1 in ortho mode, leading T1 normalize to fail. */
 	V = normalize(V + 1e-8);
@@ -167,24 +167,11 @@ float ltc_evaluate_quad(vec3 N, vec3 V, mat3 Minv, vec3 corners[4])
 	corners[1] = normalize(Minv * corners[1]);
 	corners[2] = normalize(Minv * corners[2]);
 	corners[3] = normalize(Minv * corners[3]);
-
-	/* Approximation using a sphere of the same solid angle than the quad.
-	 * Finding the clipped sphere diffuse integral is easier than clipping the quad. */
-	vec3 avg_dir;
-	avg_dir  = edge_integral_vec(corners[0], corners[1]);
-	avg_dir += edge_integral_vec(corners[1], corners[2]);
-	avg_dir += edge_integral_vec(corners[2], corners[3]);
-	avg_dir += edge_integral_vec(corners[3], corners[0]);
-
-	float form_factor = length(avg_dir);
-
-	float sphere_cosine_integral = form_factor * diffuse_sphere_integral_lut(avg_dir, form_factor);
-
-	return abs(sphere_cosine_integral);
 }
 
-/* Same as above but without the matrix transform. */
-float ltc_evaluate_quad_diffuse(vec3 corners[4])
+/* If corners have already pass through ltc_transform_quad(), then N **MUST** be vec3(0.0, 0.0, 1.0),
+ * corresponding to the Up axis of the shading basis. */
+float ltc_evaluate_quad(vec3 corners[4], vec3 N)
 {
 	/* Approximation using a sphere of the same solid angle than the quad.
 	 * Finding the clipped sphere diffuse integral is easier than clipping the quad. */
@@ -195,10 +182,27 @@ float ltc_evaluate_quad_diffuse(vec3 corners[4])
 	avg_dir += edge_integral_vec(corners[3], corners[0]);
 
 	float form_factor = length(avg_dir);
+	float avg_dir_z = dot(N, avg_dir / form_factor);
 
-	float sphere_cosine_integral = form_factor * diffuse_sphere_integral_lut(avg_dir, form_factor);
+#if 1 /* use tabulated horizon-clipped sphere */
+	return form_factor * diffuse_sphere_integral_lut(avg_dir_z, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+	return form_factor * diffuse_sphere_integral_cheap(avg_dir_z, form_factor);
+#endif
+}
 
-	return abs(sphere_cosine_integral);
+/* If disk does not need to be transformed and is already front facing. */
+float ltc_evaluate_disk_simple(float disk_radius, float NL)
+{
+	float r_sqr = disk_radius * disk_radius;
+	float one_r_sqr = 1.0 + r_sqr;
+	float form_factor = r_sqr * inversesqrt(one_r_sqr * one_r_sqr);
+
+#if 1 /* use tabulated horizon-clipped sphere */
+	return form_factor * diffuse_sphere_integral_lut(NL, form_factor);
+#else /* Less accurate version, a bit cheaper. */
+	return form_factor * diffuse_sphere_integral_cheap(NL, form_factor);
+#endif
 }
 
 /* disk_points are WS vectors from the shading point to the disk "bounding domain" */
@@ -307,13 +311,12 @@ float ltc_evaluate_disk(vec3 N, vec3 V, mat3 Minv, vec3 disk_p

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list