Bläddra i källkod

Merge pull request #41308 from JFonS/fix_spotlight_attenuation

Invert spotlight angle attenuation
Rémi Verschelde 4 år sedan
förälder
incheckning
ce332859e9

+ 2 - 2
modules/lightmapper_rd/lightmapper_rd.cpp

@@ -93,8 +93,8 @@ void LightmapperRD::add_spot_light(bool p_static, const Vector3 &p_position, con
 	l.direction[2] = p_direction.z;
 	l.range = p_range;
 	l.attenuation = p_attenuation;
-	l.spot_angle = Math::deg2rad(p_spot_angle);
-	l.spot_attenuation = p_spot_attenuation;
+	l.cos_spot_angle = Math::cos(Math::deg2rad(p_spot_angle));
+	l.inv_spot_attenuation = 1.0f / p_spot_attenuation;
 	l.color[0] = p_color.r;
 	l.color[1] = p_color.g;
 	l.color[2] = p_color.b;

+ 2 - 2
modules/lightmapper_rd/lightmapper_rd.h

@@ -54,8 +54,8 @@ class LightmapperRD : public Lightmapper {
 		float size;
 		float range;
 		float attenuation;
-		float spot_angle;
-		float spot_attenuation;
+		float cos_spot_angle;
+		float inv_spot_attenuation;
 		uint32_t static_bake;
 		uint32_t pad[3];
 

+ 2 - 2
modules/lightmapper_rd/lm_common_inc.glsl

@@ -56,8 +56,8 @@ struct Light {
 
 	float range;
 	float attenuation;
-	float spot_angle;
-	float spot_attenuation;
+	float cos_spot_angle;
+	float inv_spot_attenuation;
 
 	bool static_bake;
 	uint pad[3];

+ 7 - 4
modules/lightmapper_rd/lm_compute.glsl

@@ -313,13 +313,16 @@ void main() {
 
 			if (lights.data[i].type == LIGHT_TYPE_SPOT) {
 				vec3 rel = normalize(position - light_pos);
-				float angle = acos(dot(rel, lights.data[i].direction));
-				if (angle > lights.data[i].spot_angle) {
+				float cos_spot_angle = lights.data[i].cos_spot_angle;
+				float cos_angle = dot(rel, lights.data[i].direction);
+
+				if (cos_angle < cos_spot_angle) {
 					continue; //invisible, dont try
 				}
 
-				float d = clamp(angle / lights.data[i].spot_angle, 0, 1);
-				attenuation *= pow(1.0 - d, lights.data[i].spot_attenuation);
+				float scos = max(cos_angle, cos_spot_angle);
+				float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle));
+				attenuation *= 1.0 - pow(spot_rim, lights.data[i].inv_spot_attenuation);
 			}
 		}
 

+ 8 - 8
servers/rendering/renderer_rd/renderer_scene_render_rd.cpp

@@ -1611,8 +1611,8 @@ void RendererSceneRenderRD::_pre_process_gi(RID p_render_buffers, const Transfor
 				lights[idx].has_shadow = storage->light_has_shadow(li->light);
 				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
 				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
-				lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE));
-				lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+				lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+				lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
 				idx++;
 			}
@@ -4539,8 +4539,8 @@ void RendererSceneRenderRD::gi_probe_update(RID p_probe, bool p_update_light_ins
 				l.color[1] = color.g;
 				l.color[2] = color.b;
 
-				l.spot_angle_radians = Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE));
-				l.spot_attenuation = storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+				l.cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+				l.inv_spot_attenuation = 1.0f / storage->light_get_param(light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
 				Transform xform = light_instance_get_base_transform(light_instance);
 
@@ -6491,9 +6491,9 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const
 
 		light_data.size = size;
 
-		light_data.cone_attenuation = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+		light_data.inv_spot_attenuation = 1.0f / storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 		float spot_angle = storage->light_get_param(base, RS::LIGHT_PARAM_SPOT_ANGLE);
-		light_data.cone_angle = Math::cos(Math::deg2rad(spot_angle));
+		light_data.cos_spot_angle = Math::cos(Math::deg2rad(spot_angle));
 
 		light_data.mask = storage->light_get_cull_mask(base);
 
@@ -8094,8 +8094,8 @@ void RendererSceneRenderRD::_render_sdfgi_static_lights(RID p_render_buffers, ui
 				lights[idx].has_shadow = storage->light_has_shadow(li->light);
 				lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION);
 				lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE);
-				lights[idx].spot_angle = Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE));
-				lights[idx].spot_attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
+				lights[idx].cos_spot_angle = Math::cos(Math::deg2rad(storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ANGLE)));
+				lights[idx].inv_spot_attenuation = 1.0f / storage->light_get_param(li->light, RS::LIGHT_PARAM_SPOT_ATTENUATION);
 
 				idx++;
 			}

+ 6 - 6
servers/rendering/renderer_rd/renderer_scene_render_rd.h

@@ -406,10 +406,10 @@ private:
 		float attenuation;
 
 		float color[3];
-		float spot_angle_radians;
+		float cos_spot_angle;
 
 		float position[3];
-		float spot_attenuation;
+		float inv_spot_attenuation;
 
 		float direction[3];
 		uint32_t has_shadow;
@@ -1146,8 +1146,8 @@ private:
 			float attenuation;
 
 			uint32_t type;
-			float spot_angle;
-			float spot_attenuation;
+			float cos_spot_angle;
+			float inv_spot_attenuation;
 			float radius;
 
 			float shadow_color[4];
@@ -1362,8 +1362,8 @@ private:
 			float color[3];
 			float attenuation;
 
-			float cone_attenuation;
-			float cone_angle;
+			float inv_spot_attenuation;
+			float cos_spot_angle;
 			float specular_amount;
 			uint32_t shadow_enabled;
 

+ 8 - 6
servers/rendering/renderer_rd/shaders/giprobe.glsl

@@ -51,10 +51,10 @@ struct Light {
 	float attenuation;
 
 	vec3 color;
-	float spot_angle_radians;
+	float cos_spot_angle;
 
 	vec3 position;
-	float spot_attenuation;
+	float inv_spot_attenuation;
 
 	vec3 direction;
 	bool has_shadow;
@@ -233,13 +233,15 @@ bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3
 
 		if (lights.data[light].type == LIGHT_TYPE_SPOT) {
 			vec3 rel = normalize(pos - light_pos);
-			float angle = acos(dot(rel, lights.data[light].direction));
-			if (angle > lights.data[light].spot_angle_radians) {
+			float cos_spot_angle = lights.data[light].cos_spot_angle;
+			float cos_angle = dot(rel, lights.data[light].direction);
+			if (cos_angle < cos_spot_angle) {
 				return false;
 			}
 
-			float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
-			attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+			float scos = max(cos_angle, cos_spot_angle);
+			float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle));
+			attenuation *= 1.0 - pow(spot_rim, lights.data[light].inv_spot_attenuation);
 		}
 	}
 

+ 8 - 6
servers/rendering/renderer_rd/shaders/giprobe_write.glsl

@@ -43,10 +43,10 @@ struct Light {
 	float attenuation;
 
 	vec3 color;
-	float spot_angle_radians;
+	float cos_spot_angle;
 
 	vec3 position;
-	float spot_attenuation;
+	float inv_spot_attenuation;
 
 	vec3 direction;
 	bool has_shadow;
@@ -146,13 +146,15 @@ bool compute_light_vector(uint light, uint cell, vec3 pos, out float attenuation
 
 		if (lights.data[light].type == LIGHT_TYPE_SPOT) {
 			vec3 rel = normalize(pos - light_pos);
-			float angle = acos(dot(rel, lights.data[light].direction));
-			if (angle > lights.data[light].spot_angle_radians) {
+			float cos_spot_angle = lights.data[light].cos_spot_angle;
+			float cos_angle = dot(rel, lights.data[light].direction);
+			if (cos_angle < cos_spot_angle) {
 				return false;
 			}
 
-			float d = clamp(angle / lights.data[light].spot_angle_radians, 0, 1);
-			attenuation *= pow(1.0 - d, lights.data[light].spot_attenuation);
+			float scos = max(cos_angle, cos_spot_angle);
+			float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle));
+			attenuation *= 1.0 - pow(spot_rim, lights.data[light].inv_spot_attenuation);
 		}
 	}
 

+ 11 - 8
servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl

@@ -67,8 +67,8 @@ struct Light {
 	float attenuation;
 
 	uint type;
-	float spot_angle;
-	float spot_attenuation;
+	float cos_spot_angle;
+	float inv_spot_attenuation;
 	float radius;
 
 	vec4 shadow_color;
@@ -266,13 +266,16 @@ void main() {
 				rel_vec.y /= params.y_mult;
 				attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation);
 
-				float angle = acos(dot(normalize(rel_vec), -lights.data[i].direction));
-				if (angle > lights.data[i].spot_angle) {
-					attenuation = 0.0;
-				} else {
-					float d = clamp(angle / lights.data[i].spot_angle, 0, 1);
-					attenuation *= pow(1.0 - d, lights.data[i].spot_attenuation);
+				float cos_spot_angle = lights.data[i].cos_spot_angle;
+				float cos_angle = dot(-direction, lights.data[i].direction);
+
+				if (cos_angle < cos_spot_angle) {
+					continue;
 				}
+
+				float scos = max(cos_angle, cos_spot_angle);
+				float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - cos_spot_angle));
+				attenuation *= 1.0 - pow(spot_rim, lights.data[i].inv_spot_attenuation);
 			} break;
 		}