Переглянути джерело

Add soft shadows to the CPU lightmapper

Adds the "light_size" property to Lights. It's only considered in baked
lightmaps for soft shadowing purposes.
JFonS 4 роки тому
батько
коміт
a2ba7910ba

+ 20 - 14
doc/classes/Light.xml

@@ -54,6 +54,9 @@
 		<member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false">
 			If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
 		</member>
+		<member name="light_size" type="float" setter="set_param" getter="get_param" default="0.0">
+			The size of the light in Godot units. Only considered in baked lightmaps and only if [member light_bake_mode] is set to [constant BAKE_ALL]. Increasing this value will make the shadows appear blurrier. This can be used to simulate area lights to an extent.
+		</member>
 		<member name="light_specular" type="float" setter="set_param" getter="get_param" default="0.5">
 			The intensity of the specular blob in objects affected by the light. At [code]0[/code], the light becomes a pure diffuse light. When not baking emission, this can be used to avoid unrealistic reflections when placing lights above an emissive surface.
 		</member>
@@ -80,46 +83,49 @@
 		<constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param">
 			Constant for accessing [member light_indirect_energy].
 		</constant>
-		<constant name="PARAM_SPECULAR" value="2" enum="Param">
+		<constant name="PARAM_SIZE" value="2" enum="Param">
+			Constant for accessing [member light_size].
+		</constant>
+		<constant name="PARAM_SPECULAR" value="3" enum="Param">
 			Constant for accessing [member light_specular].
 		</constant>
-		<constant name="PARAM_RANGE" value="3" enum="Param">
+		<constant name="PARAM_RANGE" value="4" enum="Param">
 			Constant for accessing [member OmniLight.omni_range] or [member SpotLight.spot_range].
 		</constant>
-		<constant name="PARAM_ATTENUATION" value="4" enum="Param">
+		<constant name="PARAM_ATTENUATION" value="5" enum="Param">
 			Constant for accessing [member OmniLight.omni_attenuation] or [member SpotLight.spot_attenuation].
 		</constant>
-		<constant name="PARAM_SPOT_ANGLE" value="5" enum="Param">
+		<constant name="PARAM_SPOT_ANGLE" value="6" enum="Param">
 			Constant for accessing [member SpotLight.spot_angle].
 		</constant>
-		<constant name="PARAM_SPOT_ATTENUATION" value="6" enum="Param">
+		<constant name="PARAM_SPOT_ATTENUATION" value="7" enum="Param">
 			Constant for accessing [member SpotLight.spot_angle_attenuation].
 		</constant>
-		<constant name="PARAM_CONTACT_SHADOW_SIZE" value="7" enum="Param">
+		<constant name="PARAM_CONTACT_SHADOW_SIZE" value="8" enum="Param">
 			Constant for accessing [member shadow_contact].
 		</constant>
-		<constant name="PARAM_SHADOW_MAX_DISTANCE" value="8" enum="Param">
+		<constant name="PARAM_SHADOW_MAX_DISTANCE" value="9" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_max_distance].
 		</constant>
-		<constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="Param">
+		<constant name="PARAM_SHADOW_SPLIT_1_OFFSET" value="10" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_split_1].
 		</constant>
-		<constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="Param">
+		<constant name="PARAM_SHADOW_SPLIT_2_OFFSET" value="11" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_split_2].
 		</constant>
-		<constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="Param">
+		<constant name="PARAM_SHADOW_SPLIT_3_OFFSET" value="12" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_split_3].
 		</constant>
-		<constant name="PARAM_SHADOW_NORMAL_BIAS" value="12" enum="Param">
+		<constant name="PARAM_SHADOW_NORMAL_BIAS" value="13" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_normal_bias].
 		</constant>
-		<constant name="PARAM_SHADOW_BIAS" value="13" enum="Param">
+		<constant name="PARAM_SHADOW_BIAS" value="14" enum="Param">
 			Constant for accessing [member shadow_bias].
 		</constant>
-		<constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="14" enum="Param">
+		<constant name="PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="Param">
 			Constant for accessing [member DirectionalLight.directional_shadow_bias_split_scale].
 		</constant>
-		<constant name="PARAM_MAX" value="15" enum="Param">
+		<constant name="PARAM_MAX" value="16" enum="Param">
 			Represents the size of the [enum Param] enum.
 		</constant>
 		<constant name="BAKE_DISABLED" value="0" enum="BakeMode">

+ 20 - 14
doc/classes/VisualServer.xml

@@ -4534,46 +4534,52 @@
 		<constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam">
 			The light's energy.
 		</constant>
-		<constant name="LIGHT_PARAM_SPECULAR" value="2" enum="LightParam">
+		<constant name="LIGHT_PARAM_INDIRECT_ENERGY" value="1" enum="LightParam">
+			Secondary multiplier used with indirect light (light bounces).
+		</constant>
+		<constant name="LIGHT_PARAM_SIZE" value="2" enum="LightParam">
+			The light's size, currently only used for soft shadows in baked lightmaps.
+		</constant>
+		<constant name="LIGHT_PARAM_SPECULAR" value="3" enum="LightParam">
 			The light's influence on specularity.
 		</constant>
-		<constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam">
+		<constant name="LIGHT_PARAM_RANGE" value="4" enum="LightParam">
 			The light's range.
 		</constant>
-		<constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam">
+		<constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam">
 			The light's attenuation.
 		</constant>
-		<constant name="LIGHT_PARAM_SPOT_ANGLE" value="5" enum="LightParam">
+		<constant name="LIGHT_PARAM_SPOT_ANGLE" value="6" enum="LightParam">
 			The spotlight's angle.
 		</constant>
-		<constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="6" enum="LightParam">
+		<constant name="LIGHT_PARAM_SPOT_ATTENUATION" value="7" enum="LightParam">
 			The spotlight's attenuation.
 		</constant>
-		<constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="7" enum="LightParam">
+		<constant name="LIGHT_PARAM_CONTACT_SHADOW_SIZE" value="8" enum="LightParam">
 			Scales the shadow color.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="8" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_MAX_DISTANCE" value="9" enum="LightParam">
 			Max distance that shadows will be rendered.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="9" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET" value="10" enum="LightParam">
 			Proportion of shadow atlas occupied by the first split.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="10" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET" value="11" enum="LightParam">
 			Proportion of shadow atlas occupied by the second split.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="11" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET" value="12" enum="LightParam">
 			Proportion of shadow atlas occupied by the third split. The fourth split occupies the rest.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="12" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_NORMAL_BIAS" value="13" enum="LightParam">
 			Normal bias used to offset shadow lookup by object normal. Can be used to fix self-shadowing artifacts.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_BIAS" value="13" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_BIAS" value="14" enum="LightParam">
 			Bias the shadow lookup to fix self-shadowing artifacts.
 		</constant>
-		<constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="14" enum="LightParam">
+		<constant name="LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE" value="15" enum="LightParam">
 			Increases bias on further splits to fix self-shadowing that only occurs far away from the camera.
 		</constant>
-		<constant name="LIGHT_PARAM_MAX" value="15" enum="LightParam">
+		<constant name="LIGHT_PARAM_MAX" value="16" enum="LightParam">
 			Represents the size of the [enum LightParam] enum.
 		</constant>
 		<constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode">

+ 1 - 0
drivers/gles2/rasterizer_storage_gles2.cpp

@@ -3756,6 +3756,7 @@ RID RasterizerStorageGLES2::light_create(VS::LightType p_type) {
 
 	light->param[VS::LIGHT_PARAM_ENERGY] = 1.0;
 	light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+	light->param[VS::LIGHT_PARAM_SIZE] = 0.0;
 	light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5;
 	light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
 	light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;

+ 1 - 0
drivers/gles3/rasterizer_storage_gles3.cpp

@@ -5261,6 +5261,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) {
 
 	light->param[VS::LIGHT_PARAM_ENERGY] = 1.0;
 	light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+	light->param[VS::LIGHT_PARAM_SIZE] = 0.0;
 	light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5;
 	light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
 	light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;

+ 99 - 58
modules/lightmapper_cpu/lightmapper_cpu.cpp

@@ -685,78 +685,126 @@ void LightmapperCPU::_plot_triangle(const Vector2 *p_vertices, const Vector3 *p_
 	}
 }
 
+_ALWAYS_INLINE_ float uniform_rand() {
+	/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
+	static thread_local uint32_t state = Math::rand();
+	state ^= state << 13;
+	state ^= state >> 17;
+	state ^= state << 5;
+	/* implicit conversion from 'unsigned int' to 'float' changes value from 4294967295 to 4294967296 */
+	return float(state) / float(UINT32_MAX);
+}
+
 void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
 	LightmapTexel *lightmap = (LightmapTexel *)r_lightmap;
 	for (unsigned int i = 0; i < lights.size(); ++i) {
 		const Light &light = lights[i];
 		Vector3 normal = lightmap[p_idx].normal;
 		Vector3 position = lightmap[p_idx].pos;
-		Vector3 final_energy;
 		Color c = light.color;
 		Vector3 light_energy = Vector3(c.r, c.g, c.b) * light.energy;
 
-		if (light.type == LIGHT_TYPE_OMNI) {
-			Vector3 light_direction = (position - light.position).normalized();
-			if (normal.dot(light_direction) >= 0.0) {
-				continue;
-			}
-			float dist = position.distance_to(light.position);
+		Vector3 light_to_point = light.direction;
+		if (light.type == LIGHT_TYPE_OMNI || light.type == LIGHT_TYPE_SPOT) {
+			light_to_point = (position - light.position).normalized();
+		}
 
-			if (dist <= light.range) {
-				LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_direction, parameters.bias, dist - parameters.bias);
-				if (raycaster->intersect(ray)) {
-					continue;
-				}
-				float att = powf(1.0 - dist / light.range, light.attenuation);
-				final_energy = light_energy * att * MAX(0, normal.dot(-light_direction));
-			}
+		if (normal.dot(light_to_point) >= 0.0) {
+			continue;
 		}
 
-		if (light.type == LIGHT_TYPE_SPOT) {
-			Vector3 light_direction = (position - light.position).normalized();
-			if (normal.dot(light_direction) >= 0.0) {
+		float dist;
+		float attenuation;
+		float soft_shadowing_disk_size;
+
+		if (light.type == LIGHT_TYPE_OMNI || light.type == LIGHT_TYPE_SPOT) {
+			dist = position.distance_to(light.position);
+			if (dist > light.range) {
 				continue;
 			}
+			soft_shadowing_disk_size = light.size / dist;
 
-			float angle = Math::acos(light.direction.dot(light_direction));
+			if (light.type == LIGHT_TYPE_OMNI) {
+				attenuation = powf(1.0 - dist / light.range, light.attenuation);
+			} else /* (light.type == LIGHT_TYPE_SPOT) */ {
+				float angle = Math::acos(light.direction.dot(light_to_point));
 
-			if (angle > light.spot_angle) {
-				continue;
-			}
+				if (angle > light.spot_angle) {
+					continue;
+				}
 
-			float dist = position.distance_to(light.position);
-			if (dist > light.range) {
-				continue;
+				float normalized_dist = dist * (1.0f / MAX(0.001f, light.range));
+				float norm_light_attenuation = Math::pow(MAX(1.0f - normalized_dist, 0.001f), light.attenuation);
+
+				float spot_cutoff = Math::cos(light.spot_angle);
+				float scos = MAX(light_to_point.dot(light.direction), spot_cutoff);
+				float spot_rim = (1.0f - scos) / (1.0f - spot_cutoff);
+				attenuation = norm_light_attenuation * (1.0f - pow(MAX(spot_rim, 0.001f), light.spot_attenuation));
 			}
+		} else /*if (light.type == LIGHT_TYPE_DIRECTIONAL)*/ {
+			dist = INFINITY;
+			attenuation = 1.0f;
+			soft_shadowing_disk_size = light.size;
+		}
 
-			LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_direction, parameters.bias, dist);
-			if (raycaster->intersect(ray)) {
-				continue;
+		float penumbra = 0.0f;
+		if (light.size > 0.0) {
+			Vector3 light_to_point_tan;
+			Vector3 light_to_point_bitan;
+
+			if (light.type == LIGHT_TYPE_OMNI || light.type == LIGHT_TYPE_SPOT) {
+				light_to_point = (position - light.position).normalized();
+				Vector3 aux = light_to_point.y < 0.777 ? Vector3(0, 1, 0) : Vector3(1, 0, 0);
+				light_to_point_tan = light_to_point.cross(aux).normalized();
+				light_to_point_bitan = light_to_point.cross(light_to_point_tan).normalized();
+			} else /*if (light.type == LIGHT_TYPE_DIRECTIONAL)*/ {
+				Vector3 aux = light_to_point.y < 0.777 ? Vector3(0, 1, 0) : Vector3(1, 0, 0);
+				light_to_point_tan = light_to_point.cross(aux).normalized();
+				light_to_point_bitan = light_to_point.cross(light_to_point_tan).normalized();
 			}
 
-			float normalized_dist = dist * (1.0f / MAX(0.001f, light.range));
-			float norm_light_attenuation = Math::pow(MAX(1.0f - normalized_dist, 0.001f), light.attenuation);
+			const static int shadowing_rays_check_penumbra_denom = 2;
+			int shadowing_ray_count = parameters.samples;
+
+			int hits = 0;
+			Vector3 light_disk_to_point = light_to_point;
+			for (int j = 0; j < shadowing_ray_count; j++) {
+				// Optimization:
+				// Once already casted an important proportion of rays, if all are hits or misses,
+				// assume we're not in the penumbra so we can infer the rest would have the same result
+				if (j == shadowing_ray_count / shadowing_rays_check_penumbra_denom) {
+					if (hits == j) {
+						// Assume totally lit
+						hits = shadowing_ray_count;
+						break;
+					} else if (hits == 0) {
+						// Assume totally dark
+						hits = 0;
+						break;
+					}
+				}
 
-			float spot_cutoff = Math::cos(light.spot_angle);
-			float scos = MAX(light_direction.dot(light.direction), spot_cutoff);
-			float spot_rim = (1.0f - scos) / (1.0f - spot_cutoff);
-			norm_light_attenuation *= 1.0f - pow(MAX(spot_rim, 0.001f), light.spot_attenuation);
-			final_energy = light_energy * norm_light_attenuation * MAX(0, normal.dot(-light_direction));
-		}
+				float r = uniform_rand();
+				float a = uniform_rand() * Math_TAU;
+				Vector2 disk_sample = (r * Vector2(Math::cos(a), Math::sin(a))) * soft_shadowing_disk_size;
+				light_disk_to_point = (light_to_point + disk_sample.x * light_to_point_tan + disk_sample.y * light_to_point_bitan).normalized();
 
-		if (light.type == LIGHT_TYPE_DIRECTIONAL) {
-			if (normal.dot(light.direction) >= 0.0) {
-				continue;
-			}
+				LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_disk_to_point, parameters.bias, dist);
+				if (raycaster->intersect(ray)) {
+					continue;
+				}
 
-			LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position + normal * parameters.bias, -light.direction, parameters.bias);
-			if (raycaster->intersect(ray)) {
-				continue;
+				hits++;
+			}
+			penumbra = (float)hits / shadowing_ray_count;
+		} else {
+			LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_to_point, parameters.bias, dist);
+			if (!raycaster->intersect(ray)) {
+				penumbra = 1.0f;
 			}
-
-			final_energy = light_energy * MAX(0, normal.dot(-light.direction));
 		}
 
+		Vector3 final_energy = attenuation * penumbra * light_energy * MAX(0, normal.dot(-light_to_point));
 		lightmap[p_idx].direct_light += final_energy * light.indirect_multiplier;
 		if (light.bake_direct) {
 			lightmap[p_idx].output_light += final_energy;
@@ -764,16 +812,6 @@ void LightmapperCPU::_compute_direct_light(uint32_t p_idx, void *r_lightmap) {
 	}
 }
 
-_ALWAYS_INLINE_ float uniform_rand() {
-	/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
-	static thread_local uint32_t state = Math::rand();
-	state ^= state << 13;
-	state ^= state >> 17;
-	state ^= state << 5;
-	/* implicit conversion from 'unsigned int' to 'float' changes value from 4294967295 to 4294967296 */
-	return float(state) / float(UINT32_MAX);
-}
-
 void LightmapperCPU::_compute_indirect_light(uint32_t p_idx, void *r_lightmap) {
 	LightmapTexel *lightmap = (LightmapTexel *)r_lightmap;
 	LightmapTexel &texel = lightmap[p_idx];
@@ -1583,7 +1621,7 @@ void LightmapperCPU::add_mesh(const MeshData &p_mesh, Vector2i p_size) {
 	mesh_instances.push_back(mi);
 }
 
-void LightmapperCPU::add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier) {
+void LightmapperCPU::add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size) {
 	Light l;
 	l.type = LIGHT_TYPE_DIRECTIONAL;
 	l.direction = p_direction;
@@ -1591,10 +1629,11 @@ void LightmapperCPU::add_directional_light(bool p_bake_direct, const Vector3 &p_
 	l.energy = p_energy;
 	l.indirect_multiplier = p_indirect_multiplier;
 	l.bake_direct = p_bake_direct;
+	l.size = p_size;
 	lights.push_back(l);
 }
 
-void LightmapperCPU::add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation) {
+void LightmapperCPU::add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size) {
 	Light l;
 	l.type = LIGHT_TYPE_OMNI;
 	l.position = p_position;
@@ -1604,10 +1643,11 @@ void LightmapperCPU::add_omni_light(bool p_bake_direct, const Vector3 &p_positio
 	l.energy = p_energy;
 	l.indirect_multiplier = p_indirect_multiplier;
 	l.bake_direct = p_bake_direct;
+	l.size = p_size;
 	lights.push_back(l);
 }
 
-void LightmapperCPU::add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation) {
+void LightmapperCPU::add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) {
 	Light l;
 	l.type = LIGHT_TYPE_SPOT;
 	l.position = p_position;
@@ -1620,6 +1660,7 @@ void LightmapperCPU::add_spot_light(bool p_bake_direct, const Vector3 &p_positio
 	l.energy = p_energy;
 	l.indirect_multiplier = p_indirect_multiplier;
 	l.bake_direct = p_bake_direct;
+	l.size = p_size;
 	lights.push_back(l);
 }
 

+ 4 - 3
modules/lightmapper_cpu/lightmapper_cpu.h

@@ -62,6 +62,7 @@ class LightmapperCPU : public Lightmapper {
 		float attenuation;
 		float spot_angle;
 		float spot_attenuation;
+		float size;
 		bool bake_direct;
 	};
 
@@ -165,9 +166,9 @@ public:
 	virtual void add_albedo_texture(Ref<Texture> p_texture);
 	virtual void add_emission_texture(Ref<Texture> p_texture);
 	virtual void add_mesh(const MeshData &p_mesh, Vector2i p_size);
-	virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier);
-	virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation);
-	virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation);
+	virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size);
+	virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size);
+	virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size);
 	virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_bake_userdata = nullptr, BakeStepFunc p_substep_function = nullptr);
 
 	int get_bake_texture_count() const;

+ 3 - 3
scene/3d/baked_lightmap.cpp

@@ -746,13 +746,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
 
 		if (Object::cast_to<DirectionalLight>(light)) {
 			DirectionalLight *l = Object::cast_to<DirectionalLight>(light);
-			lightmapper->add_directional_light(light->get_bake_mode() == Light::BAKE_ALL, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY));
+			lightmapper->add_directional_light(light->get_bake_mode() == Light::BAKE_ALL, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY), l->get_param(Light::PARAM_SIZE));
 		} else if (Object::cast_to<OmniLight>(light)) {
 			OmniLight *l = Object::cast_to<OmniLight>(light);
-			lightmapper->add_omni_light(light->get_bake_mode() == Light::BAKE_ALL, xf.origin, l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY), l->get_param(Light::PARAM_RANGE), l->get_param(Light::PARAM_ATTENUATION));
+			lightmapper->add_omni_light(light->get_bake_mode() == Light::BAKE_ALL, xf.origin, l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY), l->get_param(Light::PARAM_RANGE), l->get_param(Light::PARAM_ATTENUATION), l->get_param(Light::PARAM_SIZE));
 		} else if (Object::cast_to<SpotLight>(light)) {
 			SpotLight *l = Object::cast_to<SpotLight>(light);
-			lightmapper->add_spot_light(light->get_bake_mode() == Light::BAKE_ALL, xf.origin, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY), l->get_param(Light::PARAM_RANGE), l->get_param(Light::PARAM_ATTENUATION), l->get_param(Light::PARAM_SPOT_ANGLE), l->get_param(Light::PARAM_SPOT_ATTENUATION));
+			lightmapper->add_spot_light(light->get_bake_mode() == Light::BAKE_ALL, xf.origin, -xf.basis.get_axis(Vector3::AXIS_Z).normalized(), l->get_color(), l->get_param(Light::PARAM_ENERGY), l->get_param(Light::PARAM_INDIRECT_ENERGY), l->get_param(Light::PARAM_RANGE), l->get_param(Light::PARAM_ATTENUATION), l->get_param(Light::PARAM_SPOT_ANGLE), l->get_param(Light::PARAM_SPOT_ATTENUATION), l->get_param(Light::PARAM_SIZE));
 		}
 	}
 

+ 8 - 0
scene/3d/light.cpp

@@ -141,6 +141,7 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
 void Light::set_bake_mode(BakeMode p_mode) {
 	bake_mode = p_mode;
 	VS::get_singleton()->light_set_bake_mode(light, VS::LightBakeMode(bake_mode));
+	_change_notify();
 }
 
 Light::BakeMode Light::get_bake_mode() const {
@@ -196,6 +197,10 @@ void Light::_validate_property(PropertyInfo &property) const {
 	if (VisualServer::get_singleton()->is_low_end() && property.name == "shadow_contact") {
 		property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
 	}
+
+	if (bake_mode != BAKE_ALL && property.name == "light_size") {
+		property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL;
+	}
 }
 
 void Light::_bind_methods() {
@@ -230,6 +235,7 @@ void Light::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::COLOR, "light_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_color", "get_color");
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_ENERGY);
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_indirect_energy", PROPERTY_HINT_RANGE, "0,16,0.01,or_greater"), "set_param", "get_param", PARAM_INDIRECT_ENERGY);
+	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_size", PROPERTY_HINT_RANGE, "0,1,0.01,or_greater"), "set_param", "get_param", PARAM_SIZE);
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "light_negative"), "set_negative", "is_negative");
 	ADD_PROPERTYI(PropertyInfo(Variant::REAL, "light_specular", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_param", "get_param", PARAM_SPECULAR);
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "light_bake_mode", PROPERTY_HINT_ENUM, "Disable,Indirect,All"), "set_bake_mode", "get_bake_mode");
@@ -246,6 +252,7 @@ void Light::_bind_methods() {
 
 	BIND_ENUM_CONSTANT(PARAM_ENERGY);
 	BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY);
+	BIND_ENUM_CONSTANT(PARAM_SIZE);
 	BIND_ENUM_CONSTANT(PARAM_SPECULAR);
 	BIND_ENUM_CONSTANT(PARAM_RANGE);
 	BIND_ENUM_CONSTANT(PARAM_ATTENUATION);
@@ -295,6 +302,7 @@ Light::Light(VisualServer::LightType p_type) {
 
 	set_param(PARAM_ENERGY, 1);
 	set_param(PARAM_INDIRECT_ENERGY, 1);
+	set_param(PARAM_SIZE, 0);
 	set_param(PARAM_SPECULAR, 0.5);
 	set_param(PARAM_RANGE, 5);
 	set_param(PARAM_ATTENUATION, 1);

+ 1 - 0
scene/3d/light.h

@@ -43,6 +43,7 @@ public:
 	enum Param {
 		PARAM_ENERGY = VS::LIGHT_PARAM_ENERGY,
 		PARAM_INDIRECT_ENERGY = VS::LIGHT_PARAM_INDIRECT_ENERGY,
+		PARAM_SIZE = VS::LIGHT_PARAM_SIZE,
 		PARAM_SPECULAR = VS::LIGHT_PARAM_SPECULAR,
 		PARAM_RANGE = VS::LIGHT_PARAM_RANGE,
 		PARAM_ATTENUATION = VS::LIGHT_PARAM_ATTENUATION,

+ 3 - 3
scene/3d/lightmapper.h

@@ -176,9 +176,9 @@ public:
 	virtual void add_albedo_texture(Ref<Texture> p_texture) = 0;
 	virtual void add_emission_texture(Ref<Texture> p_texture) = 0;
 	virtual void add_mesh(const MeshData &p_mesh, Vector2i p_size) = 0;
-	virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier) = 0;
-	virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation) = 0;
-	virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation) = 0;
+	virtual void add_directional_light(bool p_bake_direct, const Vector3 &p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_size) = 0;
+	virtual void add_omni_light(bool p_bake_direct, const Vector3 &p_position, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_size) = 0;
+	virtual void add_spot_light(bool p_bake_direct, const Vector3 &p_position, const Vector3 p_direction, const Color &p_color, float p_energy, float p_indirect_multiplier, float p_range, float p_attenuation, float p_spot_angle, float p_spot_attenuation, float p_size) = 0;
 	virtual BakeError bake(BakeQuality p_quality, bool p_use_denoiser, int p_bounces, float p_bias, bool p_generate_atlas, int p_max_texture_size, const Ref<Image> &p_environment_panorama, const Basis &p_environment_transform, BakeStepFunc p_step_function = nullptr, void *p_step_userdata = nullptr, BakeStepFunc p_substep_function = nullptr) = 0;
 
 	virtual int get_bake_texture_count() const = 0;

+ 2 - 0
servers/visual_server.cpp

@@ -2002,6 +2002,8 @@ void VisualServer::_bind_methods() {
 	BIND_ENUM_CONSTANT(LIGHT_SPOT);
 
 	BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY);
+	BIND_ENUM_CONSTANT(LIGHT_PARAM_INDIRECT_ENERGY);
+	BIND_ENUM_CONSTANT(LIGHT_PARAM_SIZE);
 	BIND_ENUM_CONSTANT(LIGHT_PARAM_SPECULAR);
 	BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE);
 	BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION);

+ 1 - 0
servers/visual_server.h

@@ -411,6 +411,7 @@ public:
 
 		LIGHT_PARAM_ENERGY,
 		LIGHT_PARAM_INDIRECT_ENERGY,
+		LIGHT_PARAM_SIZE,
 		LIGHT_PARAM_SPECULAR,
 		LIGHT_PARAM_RANGE,
 		LIGHT_PARAM_ATTENUATION,