Implement distance fade properties in ReflectionProbe
This can be used to fade reflection probes, similar to Decal nodes. This can bring significant performance improvements, especially for reflection probes with shadows enabled and when using the Always update mode. Note that distance fade is still disabled by default (like for Decal), which means the default reflection probe rendering behavior is unchanged. TODO: - Don't update reflection probes when outside the distance. This is especially important for reflection probes with the Always update mode. - Make reflections and ambient lighting blend with the background sky when Intensity is lower than 1.0. This is required for proper fading.
This commit is contained in:
parent
dc4b616596
commit
0aa5c1b718
13 changed files with 122 additions and 3 deletions
|
@ -28,6 +28,15 @@
|
|||
<member name="cull_mask" type="int" setter="set_cull_mask" getter="get_cull_mask" default="1048575">
|
||||
Sets the cull mask which determines what objects are drawn by this probe. Every [VisualInstance3D] with a layer included in this cull mask will be rendered by the probe. To improve performance, it is best to only include large objects which are likely to take up a lot of space in the reflection.
|
||||
</member>
|
||||
<member name="distance_fade_begin" type="float" setter="set_distance_fade_begin" getter="get_distance_fade_begin" default="40.0">
|
||||
The distance from the camera at which the reflection probe begins to fade away (in 3D units).
|
||||
</member>
|
||||
<member name="distance_fade_enabled" type="bool" setter="set_enable_distance_fade" getter="is_distance_fade_enabled" default="false">
|
||||
If [code]true[/code], the reflection probe will smoothly fade away when far from the active [Camera3D] starting at [member distance_fade_begin]. This acts as a form of level of detail (LOD). The reflection probe will fade out over [member distance_fade_begin] + [member distance_fade_length], after which it will be culled and not sent to the shader at all. Use this to reduce the number of active reflection probes in a scene and thus improve performance.
|
||||
</member>
|
||||
<member name="distance_fade_length" type="float" setter="set_distance_fade_length" getter="get_distance_fade_length" default="10.0">
|
||||
Distance over which the reflection probe fades. The reflection probe's intensity is progressively reduced over this distance and is completely invisible at the end.
|
||||
</member>
|
||||
<member name="enable_shadows" type="bool" setter="set_enable_shadows" getter="are_shadows_enabled" default="false">
|
||||
If [code]true[/code], computes shadows in the reflection probe. This makes the reflection probe slower to render; you may want to disable this if using the [constant UPDATE_ALWAYS] [member update_mode].
|
||||
</member>
|
||||
|
|
|
@ -2617,6 +2617,16 @@
|
|||
Sets the render cull mask for this reflection probe. Only instances with a matching cull mask will be rendered by this probe. Equivalent to [member ReflectionProbe.cull_mask].
|
||||
</description>
|
||||
</method>
|
||||
<method name="reflection_probe_set_distance_fade">
|
||||
<return type="void" />
|
||||
<param index="0" name="probe" type="RID" />
|
||||
<param index="1" name="enable" type="bool" />
|
||||
<param index="2" name="begin" type="float" />
|
||||
<param index="3" name="length" type="float" />
|
||||
<description>
|
||||
Sets the distance fade for this reflection probe. This acts as a form of level of detail (LOD) and can be used to improve performance. Equivalent to [member ReflectionProbe.distance_fade_enabled], [member ReflectionProbe.distance_fade_begin], and [member ReflectionProbe.distance_fade_length].
|
||||
</description>
|
||||
</method>
|
||||
<method name="reflection_probe_set_enable_box_projection">
|
||||
<return type="void" />
|
||||
<param index="0" name="probe" type="RID" />
|
||||
|
|
|
@ -418,6 +418,9 @@ void LightStorage::reflection_probe_set_enable_box_projection(RID p_probe, bool
|
|||
void LightStorage::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {
|
||||
}
|
||||
|
||||
void LightStorage::reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) {
|
||||
}
|
||||
|
||||
void LightStorage::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
|
||||
}
|
||||
|
||||
|
|
|
@ -118,6 +118,9 @@ struct ReflectionProbe {
|
|||
bool interior = false;
|
||||
bool box_projection = false;
|
||||
bool enable_shadows = false;
|
||||
bool distance_fade = false;
|
||||
float distance_fade_begin = 40.0;
|
||||
float distance_fade_length = 10.0;
|
||||
uint32_t cull_mask = (1 << 20) - 1;
|
||||
float mesh_lod_threshold = 0.01;
|
||||
float baked_exposure = 1.0;
|
||||
|
@ -337,6 +340,7 @@ public:
|
|||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) override;
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
|
||||
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
|
||||
|
|
|
@ -153,6 +153,34 @@ bool ReflectionProbe::are_shadows_enabled() const {
|
|||
return enable_shadows;
|
||||
}
|
||||
|
||||
void ReflectionProbe::set_enable_distance_fade(bool p_enable) {
|
||||
distance_fade_enabled = p_enable;
|
||||
RS::get_singleton()->reflection_probe_set_distance_fade(probe, distance_fade_enabled, distance_fade_begin, distance_fade_length);
|
||||
notify_property_list_changed();
|
||||
}
|
||||
|
||||
bool ReflectionProbe::is_distance_fade_enabled() const {
|
||||
return distance_fade_enabled;
|
||||
}
|
||||
|
||||
void ReflectionProbe::set_distance_fade_begin(real_t p_distance) {
|
||||
distance_fade_begin = p_distance;
|
||||
RS::get_singleton()->reflection_probe_set_distance_fade(probe, distance_fade_enabled, distance_fade_begin, distance_fade_length);
|
||||
}
|
||||
|
||||
real_t ReflectionProbe::get_distance_fade_begin() const {
|
||||
return distance_fade_begin;
|
||||
}
|
||||
|
||||
void ReflectionProbe::set_distance_fade_length(real_t p_length) {
|
||||
distance_fade_length = p_length;
|
||||
RS::get_singleton()->reflection_probe_set_distance_fade(probe, distance_fade_enabled, distance_fade_begin, distance_fade_length);
|
||||
}
|
||||
|
||||
real_t ReflectionProbe::get_distance_fade_length() const {
|
||||
return distance_fade_length;
|
||||
}
|
||||
|
||||
void ReflectionProbe::set_cull_mask(uint32_t p_layers) {
|
||||
cull_mask = p_layers;
|
||||
RS::get_singleton()->reflection_probe_set_cull_mask(probe, p_layers);
|
||||
|
@ -184,6 +212,12 @@ void ReflectionProbe::_validate_property(PropertyInfo &p_property) const {
|
|||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
}
|
||||
|
||||
if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) {
|
||||
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
|
||||
}
|
||||
|
||||
VisualInstance3D::_validate_property(p_property);
|
||||
}
|
||||
|
||||
void ReflectionProbe::_bind_methods() {
|
||||
|
@ -220,6 +254,15 @@ void ReflectionProbe::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_enable_shadows", "enable"), &ReflectionProbe::set_enable_shadows);
|
||||
ClassDB::bind_method(D_METHOD("are_shadows_enabled"), &ReflectionProbe::are_shadows_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_enable_distance_fade", "enable"), &ReflectionProbe::set_enable_distance_fade);
|
||||
ClassDB::bind_method(D_METHOD("is_distance_fade_enabled"), &ReflectionProbe::is_distance_fade_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_distance_fade_begin", "distance"), &ReflectionProbe::set_distance_fade_begin);
|
||||
ClassDB::bind_method(D_METHOD("get_distance_fade_begin"), &ReflectionProbe::get_distance_fade_begin);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_distance_fade_length", "distance"), &ReflectionProbe::set_distance_fade_length);
|
||||
ClassDB::bind_method(D_METHOD("get_distance_fade_length"), &ReflectionProbe::get_distance_fade_length);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_cull_mask", "layers"), &ReflectionProbe::set_cull_mask);
|
||||
ClassDB::bind_method(D_METHOD("get_cull_mask"), &ReflectionProbe::get_cull_mask);
|
||||
|
||||
|
@ -242,6 +285,11 @@ void ReflectionProbe::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "ambient_color", PROPERTY_HINT_COLOR_NO_ALPHA), "set_ambient_color", "get_ambient_color");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ambient_color_energy", PROPERTY_HINT_RANGE, "0,16,0.01"), "set_ambient_color_energy", "get_ambient_color_energy");
|
||||
|
||||
ADD_GROUP("Distance Fade", "distance_fade_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "distance_fade_enabled"), "set_enable_distance_fade", "is_distance_fade_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_begin", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_begin", "get_distance_fade_begin");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "distance_fade_length", PROPERTY_HINT_RANGE, "0.0,4096.0,0.01,or_greater,suffix:m"), "set_distance_fade_length", "get_distance_fade_length");
|
||||
|
||||
BIND_ENUM_CONSTANT(UPDATE_ONCE);
|
||||
BIND_ENUM_CONSTANT(UPDATE_ALWAYS);
|
||||
|
||||
|
|
|
@ -62,6 +62,9 @@ private:
|
|||
float ambient_color_energy = 1.0;
|
||||
float mesh_lod_threshold = 1.0;
|
||||
|
||||
bool distance_fade_enabled = false;
|
||||
real_t distance_fade_begin = 40.0;
|
||||
real_t distance_fade_length = 10.0;
|
||||
uint32_t cull_mask = (1 << 20) - 1;
|
||||
UpdateMode update_mode = UPDATE_ONCE;
|
||||
|
||||
|
@ -106,6 +109,15 @@ public:
|
|||
void set_enable_shadows(bool p_enable);
|
||||
bool are_shadows_enabled() const;
|
||||
|
||||
void set_enable_distance_fade(bool p_enable);
|
||||
bool is_distance_fade_enabled() const;
|
||||
|
||||
void set_distance_fade_begin(real_t p_distance);
|
||||
real_t get_distance_fade_begin() const;
|
||||
|
||||
void set_distance_fade_length(real_t p_length);
|
||||
real_t get_distance_fade_length() const;
|
||||
|
||||
void set_cull_mask(uint32_t p_layers);
|
||||
uint32_t get_cull_mask() const;
|
||||
|
||||
|
|
|
@ -106,6 +106,7 @@ public:
|
|||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override {}
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override {}
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override {}
|
||||
virtual void reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) override {}
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override {}
|
||||
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override {}
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override {}
|
||||
|
|
|
@ -1108,6 +1108,15 @@ void LightStorage::reflection_probe_set_enable_shadows(RID p_probe, bool p_enabl
|
|||
reflection_probe->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_REFLECTION_PROBE);
|
||||
}
|
||||
|
||||
void LightStorage::reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) {
|
||||
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
|
||||
ERR_FAIL_COND(!reflection_probe);
|
||||
|
||||
reflection_probe->distance_fade = p_enable;
|
||||
reflection_probe->distance_fade_begin = p_begin;
|
||||
reflection_probe->distance_fade_length = p_length;
|
||||
}
|
||||
|
||||
void LightStorage::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {
|
||||
ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe);
|
||||
ERR_FAIL_COND(!reflection_probe);
|
||||
|
@ -1625,10 +1634,15 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
|
|||
continue;
|
||||
}
|
||||
|
||||
Transform3D transform = rpi->transform;
|
||||
const real_t distance = -p_camera_inverse_transform.xform(rpi->transform.origin).z;
|
||||
const ReflectionProbe *probe = reflection_probe_owner.get_or_null(rpi->probe);
|
||||
if (probe->distance_fade && distance > probe->distance_fade_begin + probe->distance_fade_length) {
|
||||
// Don't use this reflection probe, as it's invisible.
|
||||
continue;
|
||||
}
|
||||
|
||||
reflection_sort[reflection_count].probe_instance = rpi;
|
||||
reflection_sort[reflection_count].depth = -p_camera_inverse_transform.xform(transform.origin).z;
|
||||
reflection_sort[reflection_count].depth = distance;
|
||||
reflection_count++;
|
||||
}
|
||||
|
||||
|
@ -1665,7 +1679,17 @@ void LightStorage::update_reflection_probe_buffer(RenderDataRD *p_render_data, c
|
|||
reflection_ubo.box_offset[2] = origin_offset.z;
|
||||
reflection_ubo.mask = probe->cull_mask;
|
||||
|
||||
reflection_ubo.intensity = probe->intensity;
|
||||
float fade = 1.0;
|
||||
if (probe->distance_fade) {
|
||||
const real_t distance = -p_camera_inverse_transform.xform(rpi->transform.origin).z;
|
||||
|
||||
if (distance > probe->distance_fade_begin) {
|
||||
// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
|
||||
fade = Math::smoothstep(0.0f, 1.0f, 1.0f - float(distance - probe->distance_fade_begin) / probe->distance_fade_length);
|
||||
}
|
||||
}
|
||||
reflection_ubo.intensity = probe->intensity * fade;
|
||||
|
||||
reflection_ubo.ambient_mode = probe->ambient_mode;
|
||||
|
||||
reflection_ubo.exterior = !probe->interior;
|
||||
|
|
|
@ -230,6 +230,9 @@ private:
|
|||
bool interior = false;
|
||||
bool box_projection = false;
|
||||
bool enable_shadows = false;
|
||||
bool distance_fade = false;
|
||||
float distance_fade_begin = 40.0;
|
||||
float distance_fade_length = 10.0;
|
||||
uint32_t cull_mask = (1 << 20) - 1;
|
||||
float mesh_lod_threshold = 0.01;
|
||||
float baked_exposure = 1.0;
|
||||
|
@ -793,6 +796,7 @@ public:
|
|||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) override;
|
||||
virtual void reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) override;
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) override;
|
||||
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) override;
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) override;
|
||||
|
|
|
@ -391,6 +391,7 @@ public:
|
|||
FUNC2(reflection_probe_set_as_interior, RID, bool)
|
||||
FUNC2(reflection_probe_set_enable_box_projection, RID, bool)
|
||||
FUNC2(reflection_probe_set_enable_shadows, RID, bool)
|
||||
FUNC4(reflection_probe_set_distance_fade, RID, bool, float, float)
|
||||
FUNC2(reflection_probe_set_cull_mask, RID, uint32_t)
|
||||
FUNC2(reflection_probe_set_resolution, RID, int)
|
||||
FUNC2(reflection_probe_set_mesh_lod_threshold, RID, float)
|
||||
|
|
|
@ -114,6 +114,7 @@ public:
|
|||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_distance_fade(RID p_probe, bool p_enable, float p_begin, float p_length) = 0;
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_ratio) = 0;
|
||||
|
||||
|
|
|
@ -1966,6 +1966,7 @@ void RenderingServer::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("reflection_probe_set_as_interior", "probe", "enable"), &RenderingServer::reflection_probe_set_as_interior);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_box_projection", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_box_projection);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_enable_shadows", "probe", "enable"), &RenderingServer::reflection_probe_set_enable_shadows);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_distance_fade", "probe", "enable", "begin", "length"), &RenderingServer::reflection_probe_set_distance_fade);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_cull_mask", "probe", "layers"), &RenderingServer::reflection_probe_set_cull_mask);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_resolution", "probe", "resolution"), &RenderingServer::reflection_probe_set_resolution);
|
||||
ClassDB::bind_method(D_METHOD("reflection_probe_set_mesh_lod_threshold", "probe", "pixels"), &RenderingServer::reflection_probe_set_mesh_lod_threshold);
|
||||
|
|
|
@ -544,6 +544,7 @@ public:
|
|||
virtual void reflection_probe_set_as_interior(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) = 0;
|
||||
virtual void reflection_probe_set_distance_fade(RID p_probe, bool p_enabled, float p_begin, float p_length) = 0;
|
||||
virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) = 0;
|
||||
virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution) = 0;
|
||||
virtual void reflection_probe_set_mesh_lod_threshold(RID p_probe, float p_pixels) = 0;
|
||||
|
|
Loading…
Reference in a new issue