瀏覽代碼

Merge pull request #95888 from clayjohn/Lightmap-SH-coefficients

Use correct lightmap coefficients to ensure that the directional lightmap mode looks correct
Rémi Verschelde 1 年之前
父節點
當前提交
68d188d521

+ 4 - 10
drivers/gles3/shaders/scene.glsl

@@ -1813,16 +1813,10 @@ void main() {
 
 		vec3 n = normalize(lightmap_normal_xform * normal);
 
-		ambient_light += lm_light_l0 * 0.282095f;
-		ambient_light += lm_light_l1n1 * 0.32573 * n.y * lightmap_exposure_normalization;
-		ambient_light += lm_light_l1_0 * 0.32573 * n.z * lightmap_exposure_normalization;
-		ambient_light += lm_light_l1p1 * 0.32573 * n.x * lightmap_exposure_normalization;
-		if (metallic > 0.01) { // Since the more direct bounced light is lost, we can kind of fake it with this trick.
-			vec3 r = reflect(normalize(-vertex), normal);
-			specular_light += lm_light_l1n1 * 0.32573 * r.y * lightmap_exposure_normalization;
-			specular_light += lm_light_l1_0 * 0.32573 * r.z * lightmap_exposure_normalization;
-			specular_light += lm_light_l1p1 * 0.32573 * r.x * lightmap_exposure_normalization;
-		}
+		ambient_light += lm_light_l0 * lightmap_exposure_normalization;
+		ambient_light += lm_light_l1n1 * n.y * lightmap_exposure_normalization;
+		ambient_light += lm_light_l1_0 * n.z * lightmap_exposure_normalization;
+		ambient_light += lm_light_l1p1 * n.x * lightmap_exposure_normalization;
 #else
 #ifdef LIGHTMAP_BICUBIC_FILTER
 		ambient_light += textureArray_bicubic(lightmap_textures, uvw, lightmap_texture_size).rgb * lightmap_exposure_normalization;

+ 15 - 2
modules/lightmapper_rd/lightmapper_rd.cpp

@@ -915,7 +915,7 @@ LightmapperRD::BakeError LightmapperRD::_denoise_oidn(RenderingDevice *p_rd, RID
 	return BAKE_OK;
 }
 
-LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function) {
+LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata) {
 	RID denoise_params_buffer = p_rd->uniform_buffer_create(sizeof(DenoiseParams));
 	DenoiseParams denoise_params;
 	denoise_params.spatial_bandwidth = 5.0f;
@@ -978,6 +978,11 @@ LightmapperRD::BakeError LightmapperRD::_denoise(RenderingDevice *p_rd, Ref<RDSh
 				p_rd->sync();
 			}
 		}
+		if (p_step_function) {
+			int percent = (s + 1) * 100 / p_atlas_slices;
+			float p = float(s) / p_atlas_slices * 0.1;
+			p_step_function(0.8 + p, vformat(RTR("Denoising %d%%"), percent), p_bake_userdata, false);
+		}
 	}
 
 	p_rd->free(compute_shader_denoise);
@@ -1581,6 +1586,14 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 		Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
 		img->save_exr("res://2_light_primary_" + itos(i) + ".exr", false);
 	}
+
+	if (p_bake_sh) {
+		for (int i = 0; i < atlas_slices * 4; i++) {
+			Vector<uint8_t> s = rd->texture_get_data(light_accum_tex, i);
+			Ref<Image> img = Image::create_from_data(atlas_size.width, atlas_size.height, false, Image::FORMAT_RGBAH, s);
+			img->save_exr("res://2_light_primary_accum_" + itos(i) + ".exr", false);
+		}
+	}
 #endif
 
 	/* SECONDARY (indirect) LIGHT PASS(ES) */
@@ -1804,7 +1817,7 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
 			} else {
 				// JNLM (built-in).
 				SWAP(light_accum_tex, light_accum_tex2);
-				error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, p_bake_sh, p_step_function);
+				error = _denoise(rd, compute_shader, compute_base_uniform_set, push_constant, light_accum_tex2, normal_tex, light_accum_tex, p_denoiser_strength, p_denoiser_range, atlas_size, atlas_slices, p_bake_sh, p_step_function, p_bake_userdata);
 			}
 			if (unlikely(error != BAKE_OK)) {
 				return error;

+ 1 - 1
modules/lightmapper_rd/lightmapper_rd.h

@@ -272,7 +272,7 @@ class LightmapperRD : public Lightmapper {
 	void _raster_geometry(RenderingDevice *rd, Size2i atlas_size, int atlas_slices, int grid_size, AABB bounds, float p_bias, Vector<int> slice_triangle_count, RID position_tex, RID unocclude_tex, RID normal_tex, RID raster_depth_buffer, RID rasterize_shader, RID raster_base_uniform);
 
 	BakeError _dilate(RenderingDevice *rd, Ref<RDShaderFile> &compute_shader, RID &compute_base_uniform_set, PushConstant &push_constant, RID &source_light_tex, RID &dest_light_tex, const Size2i &atlas_size, int atlas_slices);
-	BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function);
+	BakeError _denoise(RenderingDevice *p_rd, Ref<RDShaderFile> &p_compute_shader, const RID &p_compute_base_uniform_set, PushConstant &p_push_constant, RID p_source_light_tex, RID p_source_normal_tex, RID p_dest_light_tex, float p_denoiser_strength, int p_denoiser_range, const Size2i &p_atlas_size, int p_atlas_slices, bool p_bake_sh, BakeStepFunc p_step_function, void *p_bake_userdata);
 
 	Error _store_pfm(RenderingDevice *p_rd, RID p_atlas_tex, int p_index, const Size2i &p_atlas_size, const String &p_name);
 	Ref<Image> _read_pfm(const String &p_name);

+ 20 - 10
modules/lightmapper_rd/lm_compute.glsl

@@ -649,15 +649,20 @@ void main() {
 			light_for_texture += light;
 
 #ifdef USE_SH_LIGHTMAPS
+			// These coefficients include the factored out SH evaluation, diffuse convolution, and final application, as well as the BRDF 1/PI and the spherical monte carlo factor.
+			// LO: 1/(2*sqrtPI) * 1/(2*sqrtPI) * PI * PI * 1/PI = 0.25
+			// L1: sqrt(3/(4*pi)) * sqrt(3/(4*pi)) * (PI*2/3) * (2 * PI) * 1/PI = 1.0
+			// Note: This only works because we aren't scaling, rotating, or combing harmonics, we are just directing applying them in the shader.
+
 			float c[4] = float[](
-					0.282095, //l0
-					0.488603 * light_dir.y, //l1n1
-					0.488603 * light_dir.z, //l1n0
-					0.488603 * light_dir.x //l1p1
+					0.25, //l0
+					light_dir.y, //l1n1
+					light_dir.z, //l1n0
+					light_dir.x //l1p1
 			);
 
 			for (uint j = 0; j < 4; j++) {
-				sh_accum[j].rgb += light * c[j] * 8.0;
+				sh_accum[j].rgb += light * c[j] * bake_params.exposure_normalization;
 			}
 #endif
 		}
@@ -710,15 +715,20 @@ void main() {
 		vec3 light = trace_indirect_light(position, ray_dir, noise, texel_size_world_space);
 
 #ifdef USE_SH_LIGHTMAPS
+		// These coefficients include the factored out SH evaluation, diffuse convolution, and final application, as well as the BRDF 1/PI and the spherical monte carlo factor.
+		// LO: 1/(2*sqrtPI) * 1/(2*sqrtPI) * PI * PI * 1/PI = 0.25
+		// L1: sqrt(3/(4*pi)) * sqrt(3/(4*pi)) * (PI*2/3) * (2 * PI) * 1/PI = 1.0
+		// Note: This only works because we aren't scaling, rotating, or combing harmonics, we are just directing applying them in the shader.
+
 		float c[4] = float[](
-				0.282095, //l0
-				0.488603 * ray_dir.y, //l1n1
-				0.488603 * ray_dir.z, //l1n0
-				0.488603 * ray_dir.x //l1p1
+				0.25, //l0
+				ray_dir.y, //l1n1
+				ray_dir.z, //l1n0
+				ray_dir.x //l1p1
 		);
 
 		for (uint j = 0; j < 4; j++) {
-			sh_accum[j].rgb += light * c[j] * 8.0;
+			sh_accum[j].rgb += light * c[j];
 		}
 #else
 		light_accum += light;

+ 4 - 10
servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl

@@ -1532,16 +1532,10 @@ void fragment_shader(in SceneData scene_data) {
 			vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
 			float en = lightmaps.data[ofs].exposure_normalization;
 
-			ambient_light += lm_light_l0 * 0.282095f * en;
-			ambient_light += lm_light_l1n1 * 0.32573 * n.y * en;
-			ambient_light += lm_light_l1_0 * 0.32573 * n.z * en;
-			ambient_light += lm_light_l1p1 * 0.32573 * n.x * en;
-			if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
-				vec3 r = reflect(normalize(-vertex), normal);
-				specular_light += lm_light_l1n1 * 0.32573 * r.y * en;
-				specular_light += lm_light_l1_0 * 0.32573 * r.z * en;
-				specular_light += lm_light_l1p1 * 0.32573 * r.x * en;
-			}
+			ambient_light += lm_light_l0 * en;
+			ambient_light += lm_light_l1n1 * n.y * en;
+			ambient_light += lm_light_l1_0 * n.z * en;
+			ambient_light += lm_light_l1p1 * n.x * en;
 
 		} else {
 			if (sc_use_lightmap_bicubic_filter) {

+ 4 - 11
servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl

@@ -1291,17 +1291,10 @@ void main() {
 			vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
 			float exposure_normalization = lightmaps.data[ofs].exposure_normalization;
 
-			ambient_light += lm_light_l0 * 0.282095f;
-			ambient_light += lm_light_l1n1 * 0.32573 * n.y * exposure_normalization;
-			ambient_light += lm_light_l1_0 * 0.32573 * n.z * exposure_normalization;
-			ambient_light += lm_light_l1p1 * 0.32573 * n.x * exposure_normalization;
-			if (metallic > 0.01) { // since the more direct bounced light is lost, we can kind of fake it with this trick
-				vec3 r = reflect(normalize(-vertex), normal);
-				specular_light += lm_light_l1n1 * 0.32573 * r.y * exposure_normalization;
-				specular_light += lm_light_l1_0 * 0.32573 * r.z * exposure_normalization;
-				specular_light += lm_light_l1p1 * 0.32573 * r.x * exposure_normalization;
-			}
-
+			ambient_light += lm_light_l0 * exposure_normalization;
+			ambient_light += lm_light_l1n1 * n.y * exposure_normalization;
+			ambient_light += lm_light_l1_0 * n.z * exposure_normalization;
+			ambient_light += lm_light_l1p1 * n.x * exposure_normalization;
 		} else {
 			if (sc_use_lightmap_bicubic_filter) {
 				ambient_light += textureArray_bicubic(lightmap_textures[ofs], uvw, lightmaps.data[ofs].light_texture_size).rgb * lightmaps.data[ofs].exposure_normalization;