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">
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">

View file

@ -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">

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_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;

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_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;

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() {
/* Algorithm "xor" from p. 4 of Marsaglia, "Xorshift RNGs" */
static thread_local uint32_t state = Math::rand();
@ -774,6 +695,123 @@ _ALWAYS_INLINE_ float uniform_rand() {
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) {
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);
}

View file

@ -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;

View file

@ -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));
}
}

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) {
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);

View file

@ -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,

View file

@ -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;

View file

@ -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);

View file

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