Merge pull request #50184 from JFonS/cpu_lightmapper_soft_shadows

[3.x] Add soft shadows to the CPU lightmapper
This commit is contained in:
Rémi Verschelde 2021-07-14 12:18:08 +02:00 committed by GitHub
commit aa3a5c9f6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 187 additions and 119 deletions

View file

@ -54,6 +54,9 @@
<member name="light_negative" type="bool" setter="set_negative" getter="is_negative" default="false"> <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. If [code]true[/code], the light's effect is reversed, darkening areas and casting bright shadows.
</member> </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"> <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. 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> </member>
@ -80,46 +83,49 @@
<constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param"> <constant name="PARAM_INDIRECT_ENERGY" value="1" enum="Param">
Constant for accessing [member light_indirect_energy]. Constant for accessing [member light_indirect_energy].
</constant> </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 for accessing [member light_specular].
</constant> </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 for accessing [member OmniLight.omni_range] or [member SpotLight.spot_range].
</constant> </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 for accessing [member OmniLight.omni_attenuation] or [member SpotLight.spot_attenuation].
</constant> </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 for accessing [member SpotLight.spot_angle].
</constant> </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 for accessing [member SpotLight.spot_angle_attenuation].
</constant> </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 for accessing [member shadow_contact].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_max_distance].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_split_1].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_split_2].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_split_3].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_normal_bias].
</constant> </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 for accessing [member shadow_bias].
</constant> </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 for accessing [member DirectionalLight.directional_shadow_bias_split_scale].
</constant> </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. Represents the size of the [enum Param] enum.
</constant> </constant>
<constant name="BAKE_DISABLED" value="0" enum="BakeMode"> <constant name="BAKE_DISABLED" value="0" enum="BakeMode">

View file

@ -4534,46 +4534,52 @@
<constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam"> <constant name="LIGHT_PARAM_ENERGY" value="0" enum="LightParam">
The light's energy. The light's energy.
</constant> </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. The light's influence on specularity.
</constant> </constant>
<constant name="LIGHT_PARAM_RANGE" value="3" enum="LightParam"> <constant name="LIGHT_PARAM_RANGE" value="4" enum="LightParam">
The light's range. The light's range.
</constant> </constant>
<constant name="LIGHT_PARAM_ATTENUATION" value="4" enum="LightParam"> <constant name="LIGHT_PARAM_ATTENUATION" value="5" enum="LightParam">
The light's attenuation. The light's attenuation.
</constant> </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. The spotlight's angle.
</constant> </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. The spotlight's attenuation.
</constant> </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. Scales the shadow color.
</constant> </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. Max distance that shadows will be rendered.
</constant> </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. Proportion of shadow atlas occupied by the first split.
</constant> </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. Proportion of shadow atlas occupied by the second split.
</constant> </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. Proportion of shadow atlas occupied by the third split. The fourth split occupies the rest.
</constant> </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. Normal bias used to offset shadow lookup by object normal. Can be used to fix self-shadowing artifacts.
</constant> </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. Bias the shadow lookup to fix self-shadowing artifacts.
</constant> </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. Increases bias on further splits to fix self-shadowing that only occurs far away from the camera.
</constant> </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. Represents the size of the [enum LightParam] enum.
</constant> </constant>
<constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode"> <constant name="LIGHT_BAKE_DISABLED" value="0" enum="LightBakeMode">

View file

@ -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_ENERGY] = 1.0;
light->param[VS::LIGHT_PARAM_INDIRECT_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_SPECULAR] = 0.5;
light->param[VS::LIGHT_PARAM_RANGE] = 1.0; light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45; light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;

View file

@ -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_ENERGY] = 1.0;
light->param[VS::LIGHT_PARAM_INDIRECT_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_SPECULAR] = 0.5;
light->param[VS::LIGHT_PARAM_RANGE] = 1.0; light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45; light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;

View file

@ -685,85 +685,6 @@ void LightmapperCPU::_plot_triangle(const Vector2 *p_vertices, const Vector3 *p_
} }
} }
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);
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 (light.type == LIGHT_TYPE_SPOT) {
Vector3 light_direction = (position - light.position).normalized();
if (normal.dot(light_direction) >= 0.0) {
continue;
}
float angle = Math::acos(light.direction.dot(light_direction));
if (angle > light.spot_angle) {
continue;
}
float dist = position.distance_to(light.position);
if (dist > light.range) {
continue;
}
LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_direction, parameters.bias, dist);
if (raycaster->intersect(ray)) {
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_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));
}
if (light.type == LIGHT_TYPE_DIRECTIONAL) {
if (normal.dot(light.direction) >= 0.0) {
continue;
}
LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position + normal * parameters.bias, -light.direction, parameters.bias);
if (raycaster->intersect(ray)) {
continue;
}
final_energy = light_energy * MAX(0, normal.dot(-light.direction));
}
lightmap[p_idx].direct_light += final_energy * light.indirect_multiplier;
if (light.bake_direct) {
lightmap[p_idx].output_light += final_energy;
}
}
}
_ALWAYS_INLINE_ float uniform_rand() { _ALWAYS_INLINE_ float uniform_rand() {
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */ /* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
static thread_local uint32_t state = Math::rand(); static thread_local uint32_t state = Math::rand();
@ -774,6 +695,123 @@ _ALWAYS_INLINE_ float uniform_rand() {
return float(state) / float(UINT32_MAX); 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;
Color c = light.color;
Vector3 light_energy = Vector3(c.r, c.g, c.b) * light.energy;
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 (normal.dot(light_to_point) >= 0.0) {
continue;
}
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;
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;
}
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;
}
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();
}
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 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();
LightmapRaycaster::Ray ray = LightmapRaycaster::Ray(position, -light_disk_to_point, parameters.bias, dist);
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;
}
}
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;
}
}
}
void LightmapperCPU::_compute_indirect_light(uint32_t p_idx, void *r_lightmap) { void LightmapperCPU::_compute_indirect_light(uint32_t p_idx, void *r_lightmap) {
LightmapTexel *lightmap = (LightmapTexel *)r_lightmap; LightmapTexel *lightmap = (LightmapTexel *)r_lightmap;
LightmapTexel &texel = lightmap[p_idx]; 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); 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; Light l;
l.type = LIGHT_TYPE_DIRECTIONAL; l.type = LIGHT_TYPE_DIRECTIONAL;
l.direction = p_direction; 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.energy = p_energy;
l.indirect_multiplier = p_indirect_multiplier; l.indirect_multiplier = p_indirect_multiplier;
l.bake_direct = p_bake_direct; l.bake_direct = p_bake_direct;
l.size = p_size;
lights.push_back(l); 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; Light l;
l.type = LIGHT_TYPE_OMNI; l.type = LIGHT_TYPE_OMNI;
l.position = p_position; 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.energy = p_energy;
l.indirect_multiplier = p_indirect_multiplier; l.indirect_multiplier = p_indirect_multiplier;
l.bake_direct = p_bake_direct; l.bake_direct = p_bake_direct;
l.size = p_size;
lights.push_back(l); 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; Light l;
l.type = LIGHT_TYPE_SPOT; l.type = LIGHT_TYPE_SPOT;
l.position = p_position; 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.energy = p_energy;
l.indirect_multiplier = p_indirect_multiplier; l.indirect_multiplier = p_indirect_multiplier;
l.bake_direct = p_bake_direct; l.bake_direct = p_bake_direct;
l.size = p_size;
lights.push_back(l); lights.push_back(l);
} }

View file

@ -62,6 +62,7 @@ class LightmapperCPU : public Lightmapper {
float attenuation; float attenuation;
float spot_angle; float spot_angle;
float spot_attenuation; float spot_attenuation;
float size;
bool bake_direct; bool bake_direct;
}; };
@ -165,9 +166,9 @@ public:
virtual void add_albedo_texture(Ref<Texture> p_texture); virtual void add_albedo_texture(Ref<Texture> p_texture);
virtual void add_emission_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_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_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); 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); 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); 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; int get_bake_texture_count() const;

View file

@ -746,13 +746,13 @@ BakedLightmap::BakeError BakedLightmap::bake(Node *p_from_node, String p_data_sa
if (Object::cast_to<DirectionalLight>(light)) { if (Object::cast_to<DirectionalLight>(light)) {
DirectionalLight *l = 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)) { } else if (Object::cast_to<OmniLight>(light)) {
OmniLight *l = 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)) { } else if (Object::cast_to<SpotLight>(light)) {
SpotLight *l = 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));
} }
} }

View file

@ -141,6 +141,7 @@ PoolVector<Face3> Light::get_faces(uint32_t p_usage_flags) const {
void Light::set_bake_mode(BakeMode p_mode) { void Light::set_bake_mode(BakeMode p_mode) {
bake_mode = p_mode; bake_mode = p_mode;
VS::get_singleton()->light_set_bake_mode(light, VS::LightBakeMode(bake_mode)); VS::get_singleton()->light_set_bake_mode(light, VS::LightBakeMode(bake_mode));
_change_notify();
} }
Light::BakeMode Light::get_bake_mode() const { 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") { if (VisualServer::get_singleton()->is_low_end() && property.name == "shadow_contact") {
property.usage = PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL; 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() { 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_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_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_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_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_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"); 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_ENERGY);
BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY); BIND_ENUM_CONSTANT(PARAM_INDIRECT_ENERGY);
BIND_ENUM_CONSTANT(PARAM_SIZE);
BIND_ENUM_CONSTANT(PARAM_SPECULAR); BIND_ENUM_CONSTANT(PARAM_SPECULAR);
BIND_ENUM_CONSTANT(PARAM_RANGE); BIND_ENUM_CONSTANT(PARAM_RANGE);
BIND_ENUM_CONSTANT(PARAM_ATTENUATION); BIND_ENUM_CONSTANT(PARAM_ATTENUATION);
@ -295,6 +302,7 @@ Light::Light(VisualServer::LightType p_type) {
set_param(PARAM_ENERGY, 1); set_param(PARAM_ENERGY, 1);
set_param(PARAM_INDIRECT_ENERGY, 1); set_param(PARAM_INDIRECT_ENERGY, 1);
set_param(PARAM_SIZE, 0);
set_param(PARAM_SPECULAR, 0.5); set_param(PARAM_SPECULAR, 0.5);
set_param(PARAM_RANGE, 5); set_param(PARAM_RANGE, 5);
set_param(PARAM_ATTENUATION, 1); set_param(PARAM_ATTENUATION, 1);

View file

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

View file

@ -176,9 +176,9 @@ public:
virtual void add_albedo_texture(Ref<Texture> p_texture) = 0; virtual void add_albedo_texture(Ref<Texture> p_texture) = 0;
virtual void add_emission_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_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_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) = 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) = 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 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; virtual int get_bake_texture_count() const = 0;

View file

@ -2002,6 +2002,8 @@ void VisualServer::_bind_methods() {
BIND_ENUM_CONSTANT(LIGHT_SPOT); BIND_ENUM_CONSTANT(LIGHT_SPOT);
BIND_ENUM_CONSTANT(LIGHT_PARAM_ENERGY); 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_SPECULAR);
BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE); BIND_ENUM_CONSTANT(LIGHT_PARAM_RANGE);
BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION); BIND_ENUM_CONSTANT(LIGHT_PARAM_ATTENUATION);

View file

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