Browse Source

Merge pull request #44941 from reduz/new-light-attenuation

Change the light attenuation formulas.
Juan Linietsky 4 years ago
parent
commit
c7c03d5fba

+ 10 - 1
modules/lightmapper_rd/lm_compute.glsl

@@ -249,6 +249,15 @@ float quick_hash(vec2 pos) {
 	return fract(sin(dot(pos * 19.19, vec2(49.5791, 97.413))) * 49831.189237);
 }
 
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+	float nd = distance * inv_range;
+	nd *= nd;
+	nd *= nd; // nd^4
+	nd = max(1.0 - nd, 0.0);
+	nd *= nd; // nd^2
+	return nd * pow(max(distance, 0.0001), -decay);
+}
+
 void main() {
 #ifdef MODE_LIGHT_PROBES
 	int probe_index = int(gl_GlobalInvocationID.x);
@@ -300,7 +309,7 @@ void main() {
 
 			d /= lights.data[i].range;
 
-			attenuation = pow(max(1.0 - d, 0.0), lights.data[i].attenuation);
+			attenuation = get_omni_attenuation(d, 1.0 / lights.data[i].range, lights.data[i].attenuation);
 
 			if (lights.data[i].type == LIGHT_TYPE_SPOT) {
 				vec3 rel = normalize(position - light_pos);

+ 10 - 1
servers/rendering/renderer_rd/shaders/giprobe.glsl

@@ -208,6 +208,15 @@ float raymarch(float distance, float distance_adv, vec3 from, vec3 direction) {
 	return occlusion; //max(0.0,distance);
 }
 
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+	float nd = distance * inv_range;
+	nd *= nd;
+	nd *= nd; // nd^4
+	nd = max(1.0 - nd, 0.0);
+	nd *= nd; // nd^2
+	return nd * pow(max(distance, 0.0001), -decay);
+}
+
 bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3 light_pos) {
 	if (lights.data[light].type == LIGHT_TYPE_DIRECTIONAL) {
 		light_pos = pos - lights.data[light].direction * length(vec3(params.limits));
@@ -220,7 +229,7 @@ bool compute_light_vector(uint light, vec3 pos, out float attenuation, out vec3
 			return false;
 		}
 
-		attenuation = pow(clamp(1.0 - distance / lights.data[light].radius, 0.0001, 1.0), lights.data[light].attenuation);
+		attenuation = get_omni_attenuation(distance, 1.0 / lights.data[light].radius, lights.data[light].attenuation);
 
 		if (lights.data[light].type == LIGHT_TYPE_SPOT) {
 			vec3 rel = normalize(pos - light_pos);

+ 11 - 4
servers/rendering/renderer_rd/shaders/scene_forward.glsl

@@ -891,6 +891,15 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex
 
 #endif //USE_NO_SHADOWS
 
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+	float nd = distance * inv_range;
+	nd *= nd;
+	nd *= nd; // nd^4
+	nd = max(1.0 - nd, 0.0);
+	nd *= nd; // nd^2
+	return nd * pow(max(distance, 0.0001), -decay);
+}
+
 void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 albedo, float roughness, float metallic, float specular, float p_blob_intensity,
 #ifdef LIGHT_BACKLIGHT_USED
 		vec3 backlight,
@@ -916,9 +925,8 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
 		inout vec3 diffuse_light, inout vec3 specular_light) {
 	vec3 light_rel_vec = lights.data[idx].position - vertex;
 	float light_length = length(light_rel_vec);
-	float normalized_distance = light_length * lights.data[idx].inv_radius;
 	vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
-	float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), attenuation_energy.x);
+	float omni_attenuation = get_omni_attenuation(light_length, lights.data[idx].inv_radius, attenuation_energy.x);
 	float light_attenuation = omni_attenuation;
 	vec3 shadow_attenuation = vec3(1.0);
 	vec4 color_specular = unpackUnorm4x8(lights.data[idx].color_specular);
@@ -1205,9 +1213,8 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v
 		inout vec3 specular_light) {
 	vec3 light_rel_vec = lights.data[idx].position - vertex;
 	float light_length = length(light_rel_vec);
-	float normalized_distance = light_length * lights.data[idx].inv_radius;
 	vec2 attenuation_energy = unpackHalf2x16(lights.data[idx].attenuation_energy);
-	float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), attenuation_energy.x);
+	float spot_attenuation = get_omni_attenuation(light_length, lights.data[idx].inv_radius, attenuation_energy.x);
 	vec3 spot_dir = lights.data[idx].direction;
 	vec2 spot_att_angle = unpackHalf2x16(lights.data[idx].cone_attenuation_angle);
 	float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_att_angle.y);

+ 12 - 2
servers/rendering/renderer_rd/shaders/sdfgi_direct_light.glsl

@@ -112,6 +112,15 @@ vec2 octahedron_encode(vec3 n) {
 	return n.xy;
 }
 
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+	float nd = distance * inv_range;
+	nd *= nd;
+	nd *= nd; // nd^4
+	nd = max(1.0 - nd, 0.0);
+	nd *= nd; // nd^2
+	return nd * pow(max(distance, 0.0001), -decay);
+}
+
 void main() {
 	uint voxel_index = uint(gl_GlobalInvocationID.x);
 
@@ -184,14 +193,15 @@ void main() {
 				direction = normalize(rel_vec);
 				light_distance = length(rel_vec);
 				rel_vec.y /= params.y_mult;
-				attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation);
+				attenuation = get_omni_attenuation(light_distance, 1.0 / lights.data[i].radius, lights.data[i].attenuation);
+
 			} break;
 			case LIGHT_TYPE_SPOT: {
 				vec3 rel_vec = lights.data[i].position - position;
 				direction = normalize(rel_vec);
 				light_distance = length(rel_vec);
 				rel_vec.y /= params.y_mult;
-				attenuation = pow(clamp(1.0 - length(rel_vec) / lights.data[i].radius, 0.0, 1.0), lights.data[i].attenuation);
+				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) {

+ 15 - 6
servers/rendering/renderer_rd/shaders/volumetric_fog.glsl

@@ -169,6 +169,15 @@ vec3 hash3f(uvec3 x) {
 	return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF));
 }
 
+float get_omni_attenuation(float distance, float inv_range, float decay) {
+	float nd = distance * inv_range;
+	nd *= nd;
+	nd *= nd; // nd^4
+	nd = max(1.0 - nd, 0.0);
+	nd *= nd; // nd^2
+	return nd * pow(max(distance, 0.0001), -decay);
+}
+
 void main() {
 	vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size);
 
@@ -270,14 +279,14 @@ void main() {
 		uint light_index = cluster_data.indices[omni_light_pointer + i];
 
 		vec3 light_pos = lights.data[i].position;
-		float d = distance(lights.data[i].position, view_pos) * lights.data[i].inv_radius;
+		float d = distance(lights.data[i].position, view_pos);
 		vec3 shadow_attenuation = vec3(1.0);
 
-		if (d < 1.0) {
+		if (d * lights.data[i].inv_radius < 1.0) {
 			vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
 			vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
 
-			float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
+			float attenuation = get_omni_attenuation(d, lights.data[i].inv_radius, attenuation_energy.x);
 
 			vec3 light = attenuation_energy.y * color_specular.rgb / M_PI;
 
@@ -326,14 +335,14 @@ void main() {
 
 		vec3 light_pos = lights.data[i].position;
 		vec3 light_rel_vec = lights.data[i].position - view_pos;
-		float d = length(light_rel_vec) * lights.data[i].inv_radius;
+		float d = length(light_rel_vec);
 		vec3 shadow_attenuation = vec3(1.0);
 
-		if (d < 1.0) {
+		if (d * lights.data[i].inv_radius < 1.0) {
 			vec2 attenuation_energy = unpackHalf2x16(lights.data[i].attenuation_energy);
 			vec4 color_specular = unpackUnorm4x8(lights.data[i].color_specular);
 
-			float attenuation = pow(max(1.0 - d, 0.0), attenuation_energy.x);
+			float attenuation = get_omni_attenuation(d, lights.data[i].inv_radius, attenuation_energy.x);
 
 			vec3 spot_dir = lights.data[i].direction;
 			vec2 spot_att_angle = unpackHalf2x16(lights.data[i].cone_attenuation_angle);