summaryrefslogtreecommitdiffstats
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/SCsub2
-rw-r--r--servers/audio/effects/audio_effect_hard_limiter.cpp161
-rw-r--r--servers/audio/effects/audio_effect_hard_limiter.h89
-rw-r--r--servers/display/SCsub5
-rw-r--r--servers/display/native_menu.cpp (renamed from servers/native_menu.cpp)14
-rw-r--r--servers/display/native_menu.h (renamed from servers/native_menu.h)1
-rw-r--r--servers/display_server.cpp10
-rw-r--r--servers/display_server.h4
-rw-r--r--servers/navigation_server_3d.cpp5
-rw-r--r--servers/physics_3d/godot_collision_solver_3d_sat.cpp2
-rw-r--r--servers/physics_3d/godot_shape_3d.cpp4
-rw-r--r--servers/physics_server_3d.cpp10
-rw-r--r--servers/register_server_types.cpp4
-rw-r--r--servers/rendering/dummy/storage/light_storage.h1
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp203
-rw-r--r--servers/rendering/renderer_canvas_cull.h38
-rw-r--r--servers/rendering/renderer_canvas_render.h36
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/debug_effects.cpp4
-rw-r--r--servers/rendering/renderer_rd/effects/fsr2.cpp3
-rw-r--r--servers/rendering/renderer_rd/effects/ss_effects.cpp8
-rw-r--r--servers/rendering/renderer_rd/environment/fog.cpp8
-rw-r--r--servers/rendering/renderer_rd/environment/gi.cpp11
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp7
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp31
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp4
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h2
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp4
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp13
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/gi.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/sky.glsl8
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl4
-rw-r--r--servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl11
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.h23
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp5
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp7
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp5
-rw-r--r--servers/rendering/renderer_scene_cull.cpp83
-rw-r--r--servers/rendering/renderer_scene_cull.h7
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.cpp7
-rw-r--r--servers/rendering/renderer_scene_occlusion_cull.h52
-rw-r--r--servers/rendering/renderer_viewport.cpp57
-rw-r--r--servers/rendering/renderer_viewport.h1
-rw-r--r--servers/rendering/rendering_device.cpp20
-rw-r--r--servers/rendering/rendering_device.h2
-rw-r--r--servers/rendering/rendering_device_driver.h2
-rw-r--r--servers/rendering/rendering_device_graph.cpp6
-rw-r--r--servers/rendering/rendering_light_culler.cpp18
-rw-r--r--servers/rendering/rendering_light_culler.h33
-rw-r--r--servers/rendering/rendering_server_default.cpp11
-rw-r--r--servers/rendering/rendering_server_default.h18
-rw-r--r--servers/rendering/storage/light_storage.h1
-rw-r--r--servers/rendering_server.cpp10
-rw-r--r--servers/rendering_server.h18
-rw-r--r--servers/text/text_server_extension.cpp9
-rw-r--r--servers/text/text_server_extension.h2
-rw-r--r--servers/text_server.cpp1
-rw-r--r--servers/text_server.h1
67 files changed, 991 insertions, 176 deletions
diff --git a/servers/SCsub b/servers/SCsub
index 2e4430f030..736bed68ec 100644
--- a/servers/SCsub
+++ b/servers/SCsub
@@ -7,7 +7,6 @@ env.servers_sources = []
env.add_source_files(env.servers_sources, "audio_server.cpp")
env.add_source_files(env.servers_sources, "camera_server.cpp")
env.add_source_files(env.servers_sources, "display_server.cpp")
-env.add_source_files(env.servers_sources, "native_menu.cpp")
env.add_source_files(env.servers_sources, "navigation_server_2d.cpp")
env.add_source_files(env.servers_sources, "navigation_server_3d.cpp")
env.add_source_files(env.servers_sources, "physics_server_2d.cpp")
@@ -19,6 +18,7 @@ env.add_source_files(env.servers_sources, "text_server.cpp")
SConscript("audio/SCsub")
SConscript("camera/SCsub")
SConscript("debugger/SCsub")
+SConscript("display/SCsub")
SConscript("extensions/SCsub")
SConscript("movie_writer/SCsub")
SConscript("navigation/SCsub")
diff --git a/servers/audio/effects/audio_effect_hard_limiter.cpp b/servers/audio/effects/audio_effect_hard_limiter.cpp
new file mode 100644
index 0000000000..e717557af2
--- /dev/null
+++ b/servers/audio/effects/audio_effect_hard_limiter.cpp
@@ -0,0 +1,161 @@
+/**************************************************************************/
+/* audio_effect_hard_limiter.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#include "audio_effect_hard_limiter.h"
+
+#include "servers/audio_server.h"
+
+void AudioEffectHardLimiterInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
+ float sample_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ float ceiling = Math::db_to_linear(base->ceiling);
+ float release = base->release;
+ float attack = base->attack;
+ float pre_gain = Math::db_to_linear(base->pre_gain);
+
+ for (int i = 0; i < p_frame_count; i++) {
+ float sample_left = p_src_frames[i].left;
+ float sample_right = p_src_frames[i].right;
+
+ sample_left *= pre_gain;
+ sample_right *= pre_gain;
+
+ float largest_sample = MAX(ABS(sample_left), ABS(sample_right));
+
+ release_factor = MAX(0.0, release_factor - 1.0 / sample_rate);
+ release_factor = MIN(release_factor, release);
+
+ if (release_factor > 0.0) {
+ gain = Math::lerp(gain_target, 1.0f, 1.0f - release_factor / release);
+ }
+
+ if (largest_sample * gain > ceiling) {
+ gain_target = ceiling / largest_sample;
+ release_factor = release;
+ attack_factor = attack;
+ }
+
+ // Lerp gain over attack time to avoid distortion.
+ attack_factor = MAX(0.0f, attack_factor - 1.0f / sample_rate);
+ if (attack_factor > 0.0) {
+ gain = Math::lerp(gain_target, gain, 1.0f - attack_factor / attack);
+ }
+
+ int bucket_id = gain_bucket_cursor / gain_bucket_size;
+
+ // If first item within the current bucket, reset the bucket.
+ if (gain_bucket_cursor % gain_bucket_size == 0) {
+ gain_buckets[bucket_id] = 1.0f;
+ }
+
+ gain_buckets[bucket_id] = MIN(gain_buckets[bucket_id], gain);
+
+ gain_bucket_cursor = (gain_bucket_cursor + 1) % gain_samples_to_store;
+
+ for (int j = 0; j < (int)gain_buckets.size(); j++) {
+ gain = MIN(gain, gain_buckets[j]);
+ }
+
+ // Introduce latency by grabbing the AudioFrame stored previously,
+ // then overwrite it with current audioframe, then update circular
+ // buffer cursor.
+ float dst_buffer_left = sample_buffer_left[sample_cursor];
+ float dst_buffer_right = sample_buffer_right[sample_cursor];
+
+ sample_buffer_left[sample_cursor] = sample_left;
+ sample_buffer_right[sample_cursor] = sample_right;
+
+ sample_cursor = (sample_cursor + 1) % sample_buffer_left.size();
+
+ p_dst_frames[i].left = dst_buffer_left * gain;
+ p_dst_frames[i].right = dst_buffer_right * gain;
+ }
+}
+
+Ref<AudioEffectInstance> AudioEffectHardLimiter::instantiate() {
+ Ref<AudioEffectHardLimiterInstance> ins;
+ ins.instantiate();
+ ins->base = Ref<AudioEffectHardLimiter>(this);
+
+ float mix_rate = AudioServer::get_singleton()->get_mix_rate();
+
+ for (int i = 0; i < (int)Math::ceil(mix_rate * attack) + 1; i++) {
+ ins->sample_buffer_left.push_back(0.0f);
+ ins->sample_buffer_right.push_back(0.0f);
+ }
+
+ ins->gain_samples_to_store = (int)Math::ceil(mix_rate * (attack + sustain) + 1);
+ ins->gain_bucket_size = (int)(mix_rate * attack);
+
+ for (int i = 0; i < ins->gain_samples_to_store; i += ins->gain_bucket_size) {
+ ins->gain_buckets.push_back(1.0f);
+ }
+
+ return ins;
+}
+
+void AudioEffectHardLimiter::set_ceiling_db(float p_ceiling) {
+ ceiling = p_ceiling;
+}
+
+float AudioEffectHardLimiter::get_ceiling_db() const {
+ return ceiling;
+}
+
+float AudioEffectHardLimiter::get_pre_gain_db() const {
+ return pre_gain;
+}
+
+void AudioEffectHardLimiter::set_pre_gain_db(const float p_pre_gain) {
+ pre_gain = p_pre_gain;
+}
+
+float AudioEffectHardLimiter::get_release() const {
+ return release;
+}
+
+void AudioEffectHardLimiter::set_release(const float p_release) {
+ release = p_release;
+}
+
+void AudioEffectHardLimiter::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_ceiling_db", "ceiling"), &AudioEffectHardLimiter::set_ceiling_db);
+ ClassDB::bind_method(D_METHOD("get_ceiling_db"), &AudioEffectHardLimiter::get_ceiling_db);
+
+ ClassDB::bind_method(D_METHOD("set_pre_gain_db", "p_pre_gain"), &AudioEffectHardLimiter::set_pre_gain_db);
+ ClassDB::bind_method(D_METHOD("get_pre_gain_db"), &AudioEffectHardLimiter::get_pre_gain_db);
+
+ ClassDB::bind_method(D_METHOD("set_release", "p_release"), &AudioEffectHardLimiter::set_release);
+ ClassDB::bind_method(D_METHOD("get_release"), &AudioEffectHardLimiter::get_release);
+
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain_db", PROPERTY_HINT_RANGE, "-24,24,0.01,suffix:dB"), "set_pre_gain_db", "get_pre_gain_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ceiling_db", PROPERTY_HINT_RANGE, "-24,0.0,0.01,suffix:dB"), "set_ceiling_db", "get_ceiling_db");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "release", PROPERTY_HINT_RANGE, "0.01,3,0.01"), "set_release", "get_release");
+}
diff --git a/servers/audio/effects/audio_effect_hard_limiter.h b/servers/audio/effects/audio_effect_hard_limiter.h
new file mode 100644
index 0000000000..7e28480797
--- /dev/null
+++ b/servers/audio/effects/audio_effect_hard_limiter.h
@@ -0,0 +1,89 @@
+/**************************************************************************/
+/* audio_effect_hard_limiter.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/**************************************************************************/
+
+#ifndef AUDIO_EFFECT_HARD_LIMITER_H
+#define AUDIO_EFFECT_HARD_LIMITER_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectHardLimiter;
+
+class AudioEffectHardLimiterInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectHardLimiterInstance, AudioEffectInstance);
+ friend class AudioEffectHardLimiter;
+ Ref<AudioEffectHardLimiter> base;
+
+private:
+ int sample_cursor = 0;
+
+ float release_factor = 0;
+ float attack_factor = 0;
+ float gain = 1;
+ float gain_target = 1;
+
+ LocalVector<float> sample_buffer_left;
+ LocalVector<float> sample_buffer_right;
+
+ int gain_samples_to_store = 0;
+ int gain_bucket_cursor = 0;
+ int gain_bucket_size = 0;
+ LocalVector<float> gain_buckets;
+
+public:
+ virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override;
+};
+
+class AudioEffectHardLimiter : public AudioEffect {
+ GDCLASS(AudioEffectHardLimiter, AudioEffect);
+
+ friend class AudioEffectHardLimiterInstance;
+ float pre_gain = 0.0f;
+ float ceiling = -0.3f;
+ float sustain = 0.02f;
+ float release = 0.1f;
+ const float attack = 0.002;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_ceiling_db(float p_ceiling);
+ float get_ceiling_db() const;
+
+ void set_release(float p_release);
+ float get_release() const;
+
+ void set_pre_gain_db(float p_pre_gain);
+ float get_pre_gain_db() const;
+
+ Ref<AudioEffectInstance> instantiate() override;
+};
+
+#endif // AUDIO_EFFECT_HARD_LIMITER_H
diff --git a/servers/display/SCsub b/servers/display/SCsub
new file mode 100644
index 0000000000..86681f9c74
--- /dev/null
+++ b/servers/display/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.servers_sources, "*.cpp")
diff --git a/servers/native_menu.cpp b/servers/display/native_menu.cpp
index d1894ba6c3..ca46560c7c 100644
--- a/servers/native_menu.cpp
+++ b/servers/display/native_menu.cpp
@@ -68,6 +68,7 @@ void NativeMenu::_bind_methods() {
ClassDB::bind_method(D_METHOD("find_item_index_with_text", "rid", "text"), &NativeMenu::find_item_index_with_text);
ClassDB::bind_method(D_METHOD("find_item_index_with_tag", "rid", "tag"), &NativeMenu::find_item_index_with_tag);
+ ClassDB::bind_method(D_METHOD("find_item_index_with_submenu", "rid", "submenu_rid"), &NativeMenu::find_item_index_with_submenu);
ClassDB::bind_method(D_METHOD("is_item_checked", "rid", "idx"), &NativeMenu::is_item_checked);
ClassDB::bind_method(D_METHOD("is_item_checkable", "rid", "idx"), &NativeMenu::is_item_checkable);
@@ -263,6 +264,19 @@ int NativeMenu::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag)
return -1;
}
+int NativeMenu::find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const {
+ if (!has_menu(p_rid) || !has_menu(p_submenu_rid)) {
+ return -1;
+ }
+ int count = get_item_count(p_rid);
+ for (int i = 0; i < count; i++) {
+ if (p_submenu_rid == get_item_submenu(p_rid, i)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
bool NativeMenu::is_item_checked(const RID &p_rid, int p_idx) const {
WARN_PRINT("Global menus are not supported on this platform.");
return false;
diff --git a/servers/native_menu.h b/servers/display/native_menu.h
index f65e193972..2bc061a216 100644
--- a/servers/native_menu.h
+++ b/servers/display/native_menu.h
@@ -102,6 +102,7 @@ public:
virtual int find_item_index_with_text(const RID &p_rid, const String &p_text) const;
virtual int find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const;
+ virtual int find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const;
virtual bool is_item_checked(const RID &p_rid, int p_idx) const;
virtual bool is_item_checkable(const RID &p_rid, int p_idx) const;
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 72228c25f2..9ceb6909fe 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -645,22 +645,22 @@ void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) {
Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) {
WARN_PRINT("Native dialogs not supported by this display server.");
- return OK;
+ return ERR_UNAVAILABLE;
}
Error DisplayServer::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) {
WARN_PRINT("Native dialogs not supported by this display server.");
- return OK;
+ return ERR_UNAVAILABLE;
}
Error DisplayServer::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) {
WARN_PRINT("Native dialogs not supported by this display server.");
- return OK;
+ return ERR_UNAVAILABLE;
}
Error DisplayServer::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) {
WARN_PRINT("Native dialogs not supported by this display server.");
- return OK;
+ return ERR_UNAVAILABLE;
}
int DisplayServer::keyboard_get_layout_count() const {
@@ -1014,6 +1014,8 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(FEATURE_SCREEN_CAPTURE);
BIND_ENUM_CONSTANT(FEATURE_STATUS_INDICATOR);
BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT);
+ BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE);
BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE);
BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN);
diff --git a/servers/display_server.h b/servers/display_server.h
index 85b791ca69..f1a98c2c17 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -36,7 +36,7 @@
#include "core/os/os.h"
#include "core/variant/callable.h"
-#include "native_menu.h"
+#include "display/native_menu.h"
class Texture2D;
class Image;
@@ -140,6 +140,8 @@ public:
FEATURE_SCREEN_CAPTURE,
FEATURE_STATUS_INDICATOR,
FEATURE_NATIVE_HELP,
+ FEATURE_NATIVE_DIALOG_INPUT,
+ FEATURE_NATIVE_DIALOG_FILE,
};
virtual bool has_feature(Feature p_feature) const = 0;
diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp
index a8e36a615f..e460bcb9c6 100644
--- a/servers/navigation_server_3d.cpp
+++ b/servers/navigation_server_3d.cpp
@@ -235,6 +235,7 @@ NavigationServer3D::NavigationServer3D() {
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true);
GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true);
+ GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true);
GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true);
@@ -293,7 +294,11 @@ void NavigationServer3D::set_debug_enabled(bool p_enabled) {
debug_enabled = p_enabled;
if (debug_dirty) {
+ navigation_debug_dirty = true;
callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred();
+
+ avoidance_debug_dirty = true;
+ callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred();
}
#endif // DEBUG_ENABLED
}
diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index beaa30eb84..c53c8481f4 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -1962,7 +1962,7 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D
// Points of B, cylinder lateral surface.
for (int i = 0; i < 3; i++) {
- const Vector3 &point = vertex[i];
+ const Vector3 point = vertex[i] - p_transform_a.origin;
Vector3 axis = Plane(cyl_axis).project(point).normalized();
if (axis.dot(normal) < 0.0) {
axis *= -1.0;
diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp
index 872d26aff6..ea389ff59c 100644
--- a/servers/physics_3d/godot_shape_3d.cpp
+++ b/servers/physics_3d/godot_shape_3d.cpp
@@ -2016,9 +2016,7 @@ void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y
Vector3 pos_local = shape_aabb.position + local_origin;
Vector3 clamped_point(p_point);
- clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + shape_aabb.size.x);
- clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + shape_aabb.size.y);
- clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.z + shape_aabb.size.z);
+ clamped_point = p_point.clamp(pos_local, pos_local + shape_aabb.size);
r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5);
r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5);
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 15d43ff5dd..f56ef11c14 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -985,6 +985,9 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING);
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY);
BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_STIFFNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS);
@@ -994,11 +997,18 @@ void PhysicsServer3D::_bind_methods() {
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY);
BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_DAMPING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_MAX);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR);
BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR);
+ BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_MAX);
ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer3D::joint_get_type);
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 4e49129941..c03c0b7a40 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -43,6 +43,7 @@
#include "audio/effects/audio_effect_distortion.h"
#include "audio/effects/audio_effect_eq.h"
#include "audio/effects/audio_effect_filter.h"
+#include "audio/effects/audio_effect_hard_limiter.h"
#include "audio/effects/audio_effect_limiter.h"
#include "audio/effects/audio_effect_panner.h"
#include "audio/effects/audio_effect_phaser.h"
@@ -56,11 +57,11 @@
#include "camera/camera_feed.h"
#include "camera_server.h"
#include "debugger/servers_debugger.h"
+#include "display/native_menu.h"
#include "display_server.h"
#include "movie_writer/movie_writer.h"
#include "movie_writer/movie_writer_mjpeg.h"
#include "movie_writer/movie_writer_pngwav.h"
-#include "native_menu.h"
#include "rendering/renderer_compositor.h"
#include "rendering/renderer_rd/framebuffer_cache_rd.h"
#include "rendering/renderer_rd/storage_rd/render_data_rd.h"
@@ -210,6 +211,7 @@ void register_server_types() {
GDREGISTER_CLASS(AudioEffectDelay);
GDREGISTER_CLASS(AudioEffectCompressor);
GDREGISTER_CLASS(AudioEffectLimiter);
+ GDREGISTER_CLASS(AudioEffectHardLimiter);
GDREGISTER_CLASS(AudioEffectPitchShift);
GDREGISTER_CLASS(AudioEffectPhaser);
diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h
index a76305cdaa..0a9602b603 100644
--- a/servers/rendering/dummy/storage/light_storage.h
+++ b/servers/rendering/dummy/storage/light_storage.h
@@ -91,6 +91,7 @@ public:
void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override {}
void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {}
void light_instance_mark_visible(RID p_light_instance) override {}
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override { return false; }
/* PROBE API */
virtual RID reflection_probe_allocate() override { return RID(); }
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 8e342375f8..e32164ea98 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -32,6 +32,7 @@
#include "core/config/project_settings.h"
#include "core/math/geometry_2d.h"
+#include "core/math/transform_interpolator.h"
#include "renderer_viewport.h"
#include "rendering_server_default.h"
#include "rendering_server_globals.h"
@@ -81,7 +82,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
if (r_items) {
r_items[r_index] = child_items[i];
child_items[i]->ysort_xform = p_transform;
- child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]);
+ child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.columns[2]);
child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr;
child_items[i]->ysort_modulate = p_modulate;
child_items[i]->ysort_index = r_index;
@@ -98,7 +99,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2
r_index++;
if (child_items[i]->sort_y) {
- _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z);
+ _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform_curr, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z);
}
}
}
@@ -244,7 +245,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
}
}
- Transform2D xform = ci->xform;
+ Transform2D final_xform;
+ if (!_interpolation_data.interpolation_enabled || !ci->interpolated) {
+ final_xform = ci->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f);
+ }
+
Transform2D parent_xform = p_parent_xform;
Point2 repeat_size = p_repeat_size;
@@ -258,19 +266,19 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
ci->repeat_times = repeat_times;
if (repeat_size.x || repeat_size.y) {
- rect.size += repeat_size * repeat_times / ci->xform.get_scale();
+ rect.size += repeat_size * repeat_times / final_xform.get_scale();
rect.position -= repeat_size * (repeat_times / 2);
}
}
if (snapping_2d_transforms_to_pixel) {
- xform.columns[2] = xform.columns[2].round();
+ final_xform.columns[2] = final_xform.columns[2].round();
parent_xform.columns[2] = parent_xform.columns[2].round();
}
- xform = parent_xform * xform;
+ final_xform = parent_xform * final_xform;
- Rect2 global_rect = xform.xform(rect);
+ Rect2 global_rect = final_xform.xform(rect);
global_rect.position += p_clip_rect.position;
if (ci->use_parent_material && p_material_owner) {
@@ -324,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
child_item_count = ci->ysort_children_count + 1;
child_items = (Item **)alloca(child_item_count * sizeof(Item *));
- ci->ysort_xform = ci->xform.affine_inverse();
+ ci->ysort_xform = final_xform.affine_inverse();
ci->ysort_pos = Vector2();
ci->ysort_modulate = Color(1, 1, 1, 1);
ci->ysort_index = 0;
@@ -337,7 +345,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
sorter.sort(child_items, child_item_count);
for (i = 0; i < child_item_count; i++) {
- _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times);
+ _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -347,7 +355,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
canvas_group_from = r_z_last_list[zidx];
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
}
} else {
RendererCanvasRender::Item *canvas_group_from = nullptr;
@@ -361,14 +369,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2
if (!child_items[i]->behind && !use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
}
- _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
+ _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from);
for (int i = 0; i < child_item_count; i++) {
if (child_items[i]->behind || use_canvas_group) {
continue;
}
- _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
+ _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times);
}
}
}
@@ -512,7 +520,16 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(canvas_item);
- canvas_item->xform = p_transform;
+ if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) {
+ if (!canvas_item->on_interpolate_transform_list) {
+ _interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item);
+ canvas_item->on_interpolate_transform_list = true;
+ } else {
+ DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size() > 0);
+ }
+ }
+
+ canvas_item->xform_curr = p_transform;
}
void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) {
@@ -1622,6 +1639,26 @@ bool RendererCanvasCull::canvas_item_get_debug_redraw() const {
return debug_redraw;
}
+void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->xform_prev = canvas_item->xform_curr;
+}
+
+// Useful especially for origin shifting.
+void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) {
+ Item *canvas_item = canvas_item_owner.get_or_null(p_item);
+ ERR_FAIL_NULL(canvas_item);
+ canvas_item->xform_prev = p_transform * canvas_item->xform_prev;
+ canvas_item->xform_curr = p_transform * canvas_item->xform_curr;
+}
+
void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_NULL(canvas_item);
@@ -1720,7 +1757,16 @@ void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform
RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
ERR_FAIL_NULL(clight);
- clight->xform = p_transform;
+ if (_interpolation_data.interpolation_enabled && clight->interpolated) {
+ if (!clight->on_interpolate_transform_list) {
+ _interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light);
+ clight->on_interpolate_transform_list = true;
+ } else {
+ DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size() > 0);
+ }
+ }
+
+ clight->xform_curr = p_transform;
}
void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) {
@@ -1839,6 +1885,25 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo
clight->shadow_smooth = p_smooth;
}
+void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->xform_prev = clight->xform_curr;
+}
+
+void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) {
+ RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light);
+ ERR_FAIL_NULL(clight);
+ clight->xform_prev = p_transform * clight->xform_prev;
+ clight->xform_curr = p_transform * clight->xform_curr;
+}
+
RID RendererCanvasCull::canvas_light_occluder_allocate() {
return canvas_light_occluder_owner.allocate_rid();
}
@@ -1911,7 +1976,16 @@ void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, con
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
ERR_FAIL_NULL(occluder);
- occluder->xform = p_xform;
+ if (_interpolation_data.interpolation_enabled && occluder->interpolated) {
+ if (!occluder->on_interpolate_transform_list) {
+ _interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder);
+ occluder->on_interpolate_transform_list = true;
+ } else {
+ DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size() > 0);
+ }
+ }
+
+ occluder->xform_curr = p_xform;
}
void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) {
@@ -1921,6 +1995,25 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in
occluder->light_mask = p_mask;
}
+void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->interpolated = p_interpolated;
+}
+
+void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->xform_prev = occluder->xform_curr;
+}
+
+void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) {
+ RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder);
+ ERR_FAIL_NULL(occluder);
+ occluder->xform_prev = p_transform * occluder->xform_prev;
+ occluder->xform_curr = p_transform * occluder->xform_curr;
+}
+
RID RendererCanvasCull::canvas_occluder_polygon_allocate() {
return canvas_light_occluder_polygon_owner.allocate_rid();
}
@@ -2075,6 +2168,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_item_owner.owns(p_rid)) {
Item *canvas_item = canvas_item_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(canvas_item, true);
+ _interpolation_data.notify_free_canvas_item(p_rid, *canvas_item);
if (canvas_item->parent.is_valid()) {
if (canvas_owner.owns(canvas_item->parent)) {
@@ -2114,6 +2208,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_light_owner.owns(p_rid)) {
RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(canvas_light, true);
+ _interpolation_data.notify_free_canvas_light(p_rid, *canvas_light);
if (canvas_light->canvas.is_valid()) {
Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas);
@@ -2129,6 +2224,7 @@ bool RendererCanvasCull::free(RID p_rid) {
} else if (canvas_light_occluder_owner.owns(p_rid)) {
RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(occluder, true);
+ _interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder);
if (occluder->polygon.is_valid()) {
LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon);
@@ -2186,6 +2282,81 @@ void RendererCanvasCull::finalize() {
_free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon");
}
+void RendererCanvasCull::tick() {
+ if (_interpolation_data.interpolation_enabled) {
+ update_interpolation_tick(true);
+ }
+}
+
+void RendererCanvasCull::update_interpolation_tick(bool p_process) {
+#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \
+ /* Detect any that were on the previous transform list that are no longer active. */ \
+ for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \
+ const RID &rid = (*_interpolation_data.m_list_prev)[n]; \
+ m_type *item = m_owner_list.get_or_null(rid); \
+ /* no longer active? (either the instance deleted or no longer being transformed) */ \
+ if (item && !item->on_interpolate_transform_list) { \
+ item->xform_prev = item->xform_curr; \
+ } \
+ } \
+ /* and now for any in the transform list (being actively interpolated), */ \
+ /* keep the previous transform value up to date and ready for next tick */ \
+ if (p_process) { \
+ for (unsigned int n = 0; n < _interpolation_data.m_list_curr->size(); n++) { \
+ const RID &rid = (*_interpolation_data.m_list_curr)[n]; \
+ m_type *item = m_owner_list.get_or_null(rid); \
+ if (item) { \
+ item->xform_prev = item->xform_curr; \
+ item->on_interpolate_transform_list = false; \
+ } \
+ } \
+ } \
+ SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \
+ _interpolation_data.m_list_curr->clear();
+
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner);
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RendererCanvasRender::Light, canvas_light_owner);
+ GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner);
+
+#undef GODOT_UPDATE_INTERPOLATION_TICK
+}
+
+void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item) {
+ r_canvas_item.on_interpolate_transform_list = false;
+
+ if (!interpolation_enabled) {
+ return;
+ }
+
+ // If the instance was on any of the lists, remove.
+ canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid);
+ canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid);
+}
+
+void RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light) {
+ r_canvas_light.on_interpolate_transform_list = false;
+
+ if (!interpolation_enabled) {
+ return;
+ }
+
+ // If the instance was on any of the lists, remove.
+ canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid);
+ canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid);
+}
+
+void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder) {
+ r_canvas_light_occluder.on_interpolate_transform_list = false;
+
+ if (!interpolation_enabled) {
+ return;
+ }
+
+ // If the instance was on any of the lists, remove.
+ canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid);
+ canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid);
+}
+
RendererCanvasCull::RendererCanvasCull() {
z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *));
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index d733a7bed2..961506ca28 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -271,6 +271,10 @@ public:
void canvas_item_set_debug_redraw(bool p_enabled);
bool canvas_item_get_debug_redraw() const;
+ void canvas_item_set_interpolated(RID p_item, bool p_interpolated);
+ void canvas_item_reset_physics_interpolation(RID p_item);
+ void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform);
+
RID canvas_light_allocate();
void canvas_light_initialize(RID p_rid);
@@ -297,6 +301,10 @@ public:
void canvas_light_set_shadow_color(RID p_light, const Color &p_color);
void canvas_light_set_shadow_smooth(RID p_light, float p_smooth);
+ void canvas_light_set_interpolated(RID p_light, bool p_interpolated);
+ void canvas_light_reset_physics_interpolation(RID p_light);
+ void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform);
+
RID canvas_light_occluder_allocate();
void canvas_light_occluder_initialize(RID p_rid);
@@ -307,6 +315,10 @@ public:
void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform);
void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask);
+ void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated);
+ void canvas_light_occluder_reset_physics_interpolation(RID p_occluder);
+ void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform);
+
RID canvas_occluder_polygon_allocate();
void canvas_occluder_polygon_initialize(RID p_rid);
@@ -336,6 +348,32 @@ public:
void finalize();
+ /* INTERPOLATION */
+
+ void tick();
+ void update_interpolation_tick(bool p_process = true);
+ void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; }
+
+ struct InterpolationData {
+ void notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item);
+ void notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light);
+ void notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder);
+
+ LocalVector<RID> canvas_item_transform_update_lists[2];
+ LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0];
+ LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1];
+
+ LocalVector<RID> canvas_light_transform_update_lists[2];
+ LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0];
+ LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1];
+
+ LocalVector<RID> canvas_light_occluder_transform_update_lists[2];
+ LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0];
+ LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1];
+
+ bool interpolation_enabled = false;
+ } _interpolation_data;
+
RendererCanvasCull();
~RendererCanvasCull();
};
diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h
index cf8f6dcb2e..4a56548932 100644
--- a/servers/rendering/renderer_canvas_render.h
+++ b/servers/rendering/renderer_canvas_render.h
@@ -51,9 +51,12 @@ public:
};
struct Light {
- bool enabled;
+ bool enabled : 1;
+ bool on_interpolate_transform_list : 1;
+ bool interpolated : 1;
Color color;
- Transform2D xform;
+ Transform2D xform_curr;
+ Transform2D xform_prev;
float height;
float energy;
float scale;
@@ -97,6 +100,8 @@ public:
Light() {
version = 0;
enabled = true;
+ on_interpolate_transform_list = false;
+ interpolated = true;
color = Color(1, 1, 1);
shadow_color = Color(0, 0, 0, 0);
height = 0;
@@ -307,11 +312,17 @@ public:
Rect2 rect;
};
- Transform2D xform;
- bool clip;
- bool visible;
- bool behind;
- bool update_when_visible;
+ // For interpolation we store the current local xform,
+ // and the previous xform from the previous tick.
+ Transform2D xform_curr;
+ Transform2D xform_prev;
+
+ bool clip : 1;
+ bool visible : 1;
+ bool behind : 1;
+ bool update_when_visible : 1;
+ bool on_interpolate_transform_list : 1;
+ bool interpolated : 1;
struct CanvasGroup {
RS::CanvasGroupMode mode;
@@ -472,6 +483,8 @@ public:
texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT;
texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT;
repeat_source = false;
+ on_interpolate_transform_list = false;
+ interpolated = true;
}
virtual ~Item() {
clear();
@@ -487,12 +500,15 @@ public:
virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0;
struct LightOccluderInstance {
- bool enabled;
+ bool enabled : 1;
+ bool on_interpolate_transform_list : 1;
+ bool interpolated : 1;
RID canvas;
RID polygon;
RID occluder;
Rect2 aabb_cache;
- Transform2D xform;
+ Transform2D xform_curr;
+ Transform2D xform_prev;
Transform2D xform_cache;
int light_mask;
bool sdf_collision;
@@ -502,6 +518,8 @@ public:
LightOccluderInstance() {
enabled = true;
+ on_interpolate_transform_list = false;
+ interpolated = false;
sdf_collision = false;
next = nullptr;
light_mask = 1;
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index abbe04b5b2..1568867663 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -583,7 +583,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe
RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_rect);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer)));
RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0);
if (p_secondary.is_valid()) {
@@ -982,7 +982,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con
RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode);
ERR_FAIL_COND(shader.is_null());
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_region);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer)));
RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array());
RD::get_singleton()->draw_list_set_push_constant(draw_list, &copy_to_fb.push_constant, sizeof(CopyToFbPushConstant));
diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp
index a57a65fd5a..017ad41fdc 100644
--- a/servers/rendering/renderer_rd/effects/debug_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp
@@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
// And draw our frustum.
RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb);
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect);
RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
@@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj
rect.size.x *= atlas_rect_norm.size.x;
rect.size.y *= atlas_rect_norm.size.y;
- draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect);
+ draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect);
pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id);
RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline);
diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp
index bebbf51d51..925352a7d1 100644
--- a/servers/rendering/renderer_rd/effects/fsr2.cpp
+++ b/servers/rendering/renderer_rd/effects/fsr2.cpp
@@ -527,6 +527,7 @@ FSR2Effect::FSR2Effect() {
"\n#define FFX_GLSL 1\n"
"\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n"
"\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n"
+ "\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n"
"\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n"
"\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n";
@@ -808,7 +809,7 @@ FSR2Effect::~FSR2Effect() {
FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) {
FSR2Context *context = memnew(RendererRD::FSR2Context);
- context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE;
+ context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED;
context->fsr_desc.maxRenderSize.width = p_internal_size.x;
context->fsr_desc.maxRenderSize.height = p_internal_size.y;
context->fsr_desc.displaySize.width = p_target_size.x;
diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp
index bdd687d9f4..3db82c8fbd 100644
--- a/servers/rendering/renderer_rd/effects/ss_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp
@@ -483,8 +483,12 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin
downsample_uniform_set = uniform_set_cache->get_cache_vec(shader, 2, u_depths);
}
- float depth_linearize_mul = -p_projection.columns[3][2] * 0.5;
- float depth_linearize_add = p_projection.columns[2][2];
+ Projection correction;
+ correction.set_depth_correction(false);
+ Projection temp = correction * p_projection;
+
+ float depth_linearize_mul = -temp.columns[3][2];
+ float depth_linearize_add = temp.columns[2][2];
if (depth_linearize_mul * depth_linearize_add < 0) {
depth_linearize_add = -depth_linearize_add;
}
diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp
index 1d144bedcf..48537a97d9 100644
--- a/servers/rendering/renderer_rd/environment/fog.cpp
+++ b/servers/rendering/renderer_rd/environment/fog.cpp
@@ -509,9 +509,7 @@ Vector3i Fog::_point_get_position_in_froxel_volume(const Vector3 &p_point, float
fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread));
fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5);
- fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x);
- fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y);
- fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z);
+ fog_position = fog_position.clamp(Vector3(), fog_size);
return Vector3i(fog_position);
}
@@ -680,8 +678,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P
max = Vector3i(1, 1, 1);
for (int j = 0; j < 8; j++) {
- min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z));
- max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z));
+ min = min.min(points[j]);
+ max = max.max(points[j]);
}
kernel_size = max - min;
diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp
index 78214ede0b..c7752f8a86 100644
--- a/servers/rendering/renderer_rd/environment/gi.cpp
+++ b/servers/rendering/renderer_rd/environment/gi.cpp
@@ -3407,7 +3407,7 @@ void GI::init(SkyRD *p_sky) {
RD::PipelineDepthStencilState ds;
ds.enable_depth_test = true;
ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0);
}
@@ -3575,7 +3575,7 @@ void GI::init(SkyRD *p_sky) {
RD::PipelineDepthStencilState ds;
ds.enable_depth_test = true;
ds.enable_depth_write = true;
- ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) {
// TODO check if version is enabled
@@ -3810,8 +3810,13 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor
rbgi->scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData));
}
+ Projection correction;
+ correction.set_depth_correction(false);
+
for (uint32_t v = 0; v < p_view_count; v++) {
- RendererRD::MaterialStorage::store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]);
+ Projection temp = correction * p_projections[v];
+
+ RendererRD::MaterialStorage::store_camera(temp.inverse(), scene_data.inv_projection[v]);
scene_data.eye_offset[v][0] = p_eye_offsets[v].x;
scene_data.eye_offset[v][1] = p_eye_offsets[v].y;
scene_data.eye_offset[v][2] = p_eye_offsets[v].z;
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 41609dc74d..27c07f23fa 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -141,7 +141,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) {
for (int i = 0; i < SKY_VERSION_MAX; i++) {
RD::PipelineDepthStencilState depth_stencil_state;
depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) {
RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i);
@@ -1174,6 +1174,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
}
Projection correction;
+ correction.set_depth_correction(false, true);
correction.add_jitter_offset(p_jitter);
sky_scene_state.view_count = p_view_count;
@@ -1184,10 +1185,12 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
for (uint32_t i = 0; i < p_view_count; i++) {
Projection view_inv_projection = (correction * p_view_projections[i]).inverse();
if (p_view_count > 1) {
+ // Reprojection is used when we need to have things in combined space.
RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]);
} else {
+ // This is unused so just reset to identity.
Projection ident;
- RendererRD::MaterialStorage::store_camera(correction, sky_scene_state.ubo.combined_reprojection[i]);
+ RendererRD::MaterialStorage::store_camera(ident, sky_scene_state.ubo.combined_reprojection[i]);
}
RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]);
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 33bb5459f2..0e69ad99b8 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -546,6 +546,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis
VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW);
VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS);
VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MOTION_VECTORS);
+ VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_SEPARATE_SPECULAR | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS);
+ VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_TRANSPARENT | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS);
default: {
ERR_FAIL_MSG("Invalid color pass flag combination " + itos(p_params->color_pass_flags));
}
@@ -1130,6 +1132,7 @@ void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) {
}
if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) {
+ RENDER_TIMESTAMP("Render SDFGI");
Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI);
float exposure_normalization = 1.0;
@@ -1401,7 +1404,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
}
}
- //cube shadows are rendered in their own way
+ RENDER_TIMESTAMP("Render OmniLight Shadows");
+ // Cube shadows are rendered in their own way.
for (const int &index : p_render_data->cube_shadows) {
_render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform);
}
@@ -1457,6 +1461,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
// drawcalls per eye/view. It will all sync up at the barrier.
if (p_use_ssao || p_use_ssil) {
+ RENDER_TIMESTAMP("Prepare Depth for SSAO/SSIL");
// Convert our depth buffer data to linear data in
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
ss_effects->downsample_depth(rb, v, p_render_data->scene_data->view_projection[v]);
@@ -1472,6 +1477,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
}
}
+ RENDER_TIMESTAMP("Pre Opaque Render");
+
if (current_cluster_builder) {
// Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create
// our cluster data. We use reprojection in the shader to adjust for our left/right eye.
@@ -1504,6 +1511,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
}
if (rb_data.is_valid()) {
+ RENDER_TIMESTAMP("Update Volumetric Fog");
bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count);
_update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes);
}
@@ -1965,6 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
WARN_PRINT_ONCE("Pre opaque rendering effects can't access resolved depth buffers.");
}
+ RENDER_TIMESTAMP("Process Pre Opaque Compositor Effects");
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_OPAQUE, p_render_data);
}
@@ -1976,6 +1985,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
_pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID());
+ RENDER_TIMESTAMP("Render Opaque Pass");
+
RD::get_singleton()->draw_command_begin_label("Render Opaque Pass");
p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count;
@@ -1986,8 +1997,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
_setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass);
- RENDER_TIMESTAMP("Render Opaque Pass");
-
RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true);
{
@@ -2012,7 +2021,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags;
RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer;
RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, spec_constant_base_flags);
- _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0);
+ _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0);
}
RD::get_singleton()->draw_command_end_label();
@@ -2051,6 +2060,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
+ RENDER_TIMESTAMP("Process Post Opaque Compositor Effects");
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_OPAQUE, p_render_data);
}
@@ -2111,6 +2121,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
{
+ RENDER_TIMESTAMP("Process Post Sky Compositor Effects");
// Don't need to check for depth or color resolve here, we've already triggered it.
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_SKY, p_render_data);
}
@@ -2188,6 +2199,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
}
}
+ RENDER_TIMESTAMP("Process Pre Transparent Compositor Effects");
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data);
}
@@ -2232,6 +2244,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
RD::get_singleton()->draw_command_end_label();
{
+ RENDER_TIMESTAMP("Process Post Transparent Compositor Effects");
_process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT, p_render_data);
}
@@ -2627,7 +2640,7 @@ void RenderForwardClustered::_render_shadow_end() {
for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
- _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect);
}
RD::get_singleton()->draw_command_end_label();
@@ -2727,7 +2740,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end();
}
@@ -2777,7 +2790,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance
Color(0, 0, 0, 0),
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region);
const int uv_offset_count = 9;
static const Vector2 uv_offsets[uv_offset_count] = {
@@ -2883,7 +2896,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu
}
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false);
- _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2());
+ _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, Rect2());
}
RD::get_singleton()->draw_command_end_label();
@@ -4263,7 +4276,7 @@ RenderForwardClustered::RenderForwardClustered() {
sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST;
sampler.min_filter = RD::SAMPLER_FILTER_NEAREST;
sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
+ sampler.compare_op = RD::COMPARE_OP_GREATER;
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
index 12af8822b4..1f12d92754 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -379,7 +379,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0>
_FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
- void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
+ void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
void _update_instance_data_buffer(RenderListType p_render_list);
void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true);
diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
index 0b504eca0a..209fabeddf 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -260,7 +260,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable"));
@@ -827,7 +827,7 @@ void fragment() {
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
+ sampler.compare_op = RD::COMPARE_OP_GREATER;
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
}
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index ac93aca6bb..48c9cda253 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -777,7 +777,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
// can't do blit subpass because we're scaling
using_subpass_post_process = false;
- } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
+ } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes) || environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) {
// can't do blit subpass because we're using post processes
using_subpass_post_process = false;
}
@@ -984,7 +984,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
}
}
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0);
RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer);
if (copy_canvas) {
@@ -1385,7 +1385,7 @@ void RenderForwardMobile::_render_shadow_end() {
for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) {
RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from);
- _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect);
+ _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect);
}
RD::get_singleton()->draw_command_end_label();
@@ -1437,7 +1437,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c
Color(0, 0, 0, 0),
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region);
_render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count);
RD::get_singleton()->draw_list_end();
}
@@ -1483,7 +1483,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *>
Color(0, 0, 0, 0)
};
- RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region);
+ RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region);
const int uv_offset_count = 9;
static const Vector2 uv_offsets[uv_offset_count] = {
@@ -2835,6 +2835,11 @@ RenderForwardMobile::~RenderForwardMobile() {
for (const RID &rid : scene_state.uniform_buffers) {
RD::get_singleton()->free(rid);
}
+ for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) {
+ if (scene_state.instance_buffer[i].is_valid()) {
+ RD::get_singleton()->free(scene_state.instance_buffer[i]);
+ }
+ }
RD::get_singleton()->free(scene_state.lightmap_buffer);
RD::get_singleton()->free(scene_state.lightmap_capture_buffer);
memdelete_arr(scene_state.lightmap_captures);
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
index 5c02204627..f29503e5ec 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -350,7 +350,7 @@ private:
template <PassMode p_pass_mode>
_FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
void _render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element);
- void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
+ void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
RenderList render_list[RENDER_LIST_MAX];
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index 95ba76a707..a2f112669c 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -271,7 +271,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
if (depth_test != DEPTH_TEST_DISABLED) {
depth_stencil_state.enable_depth_test = true;
- depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL;
+ depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL;
depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false;
}
@@ -731,7 +731,7 @@ void fragment() {
sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.min_filter = RD::SAMPLER_FILTER_LINEAR;
sampler.enable_compare = true;
- sampler.compare_op = RD::COMPARE_OP_LESS;
+ sampler.compare_op = RD::COMPARE_OP_GREATER;
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 673afc53e5..6f56711151 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -34,6 +34,7 @@
#include "core/math/geometry_2d.h"
#include "core/math/math_defs.h"
#include "core/math/math_funcs.h"
+#include "core/math/transform_interpolator.h"
#include "renderer_compositor_rd.h"
#include "servers/rendering/renderer_rd/storage_rd/material_storage.h"
#include "servers/rendering/renderer_rd/storage_rd/particles_storage.h"
@@ -427,7 +428,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform;
if (p_offset.x || p_offset.y) {
- base_transform *= Transform2D(0, p_offset / p_item->xform.get_scale());
+ base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed.
}
Transform2D draw_transform;
@@ -1366,7 +1367,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p
ERR_CONTINUE(!clight);
}
- Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss
+ Transform2D final_xform;
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !l->interpolated) {
+ final_xform = l->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(l->xform_prev, l->xform_curr, final_xform, f);
+ }
+ // Convert light position to canvas coordinates, as all computation is done in canvas coordinates to avoid precision loss.
+ Vector2 canvas_light_pos = p_canvas_transform.xform(final_xform.get_origin());
state.light_uniforms[index].position[0] = canvas_light_pos.x;
state.light_uniforms[index].position[1] = canvas_light_pos.y;
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
index fe770ac065..48c1b0a3f6 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl
@@ -32,9 +32,9 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh;
float get_depth_at_pos(vec2 uv) {
float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0;
if (params.orthogonal) {
- depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0;
} else {
- depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near));
}
return depth;
}
diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
index 947aa793d9..2010b58474 100644
--- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl
@@ -53,9 +53,9 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight;
float get_depth_at_pos(vec2 uv) {
float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0;
if (params.orthogonal) {
- depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0;
} else {
- depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
+ depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near));
}
return depth;
}
diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
index e77d0de719..3fb93dda35 100644
--- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl
@@ -77,8 +77,8 @@ void main() {
float depth_fix = 1.0 / dot(normal, unorm);
depth = 2.0 * depth - 1.0;
- float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near));
- depth = (linear_depth * depth_fix) / params.z_far;
-
+ float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near));
+ // linear_depth equal to view space depth
+ depth = (params.z_far - linear_depth * depth_fix) / params.z_far;
gl_FragDepth = depth;
}
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
index 51caa67d3c..d9e21b8cd1 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl
@@ -98,9 +98,9 @@ void main() {
// unproject our Z value so we can use it directly.
depth = depth * 2.0 - 1.0;
if (params.orthogonal) {
- depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0;
+ depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0;
} else {
- depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near));
+ depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near));
}
depth = -depth;
}
diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
index 80ed34cda1..480172f9dc 100644
--- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
@@ -174,9 +174,9 @@ vec3 reconstruct_position(ivec2 screen_pos) {
pos.z = pos.z * 2.0 - 1.0;
if (params.orthogonal) {
- pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0;
+ pos.z = -(pos.z * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0;
} else {
- pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near));
+ pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + pos.z * (params.z_far - params.z_near));
}
pos.z = -pos.z;
diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
index 4e5b11aed8..35457a2482 100644
--- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl
@@ -25,7 +25,7 @@ params;
void main() {
vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0));
uv_interp = base_arr[gl_VertexIndex];
- gl_Position = vec4(uv_interp, 1.0, 1.0);
+ gl_Position = vec4(uv_interp, 0.0, 1.0);
}
#[fragment]
@@ -158,7 +158,7 @@ vec3 interleaved_gradient_noise(vec2 pos) {
vec4 volumetric_fog_process(vec2 screen_uv) {
#ifdef USE_MULTIVIEW
- vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * (vec4(screen_uv * 2.0 - 1.0, 1.0, 1.0) * sky_scene_data.z_far);
+ vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * vec4(screen_uv * 2.0 - 1.0, 0.0, 1.0); // Unproject at the far plane
vec3 fog_pos = vec3(reprojected.xy / reprojected.w, 1.0) * 0.5 + 0.5;
#else
vec3 fog_pos = vec3(screen_uv, 1.0);
@@ -187,9 +187,11 @@ void main() {
vec3 cube_normal;
#ifdef USE_MULTIVIEW
// In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject.
- vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0);
+ vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 0.0, 1.0); // unproject at the far plane
vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject;
cube_normal = unprojected.xyz / unprojected.w;
+
+ // Unproject will give us the position between the eyes, need to re-offset
cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz;
#else
cube_normal.z = -1.0;
diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
index 57b9a4c320..d0cfe6a3b8 100644
--- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl
@@ -416,7 +416,7 @@ void main() {
}
float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r;
- float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * INV_FOG_FADE);
+ float shadow = exp(min(0.0, (pssm_coord.z - depth)) * z_range * INV_FOG_FADE);
shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance
@@ -519,7 +519,7 @@ void main() {
float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
- shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE));
+ shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE));
}
total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy;
}
@@ -597,7 +597,7 @@ void main() {
float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r;
- shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE));
+ shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE));
}
total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy;
}
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index 6eae64c04e..359d7799e5 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -487,8 +487,8 @@ void vertex_shader(vec3 vertex_input,
#ifdef MODE_RENDER_DEPTH
if (scene_data.pancake_shadows) {
- if (gl_Position.z <= 0.00001) {
- gl_Position.z = 0.00001;
+ if (gl_Position.z >= 0.9999) {
+ gl_Position.z = 0.9999;
}
}
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index 259edc63a0..c26313092b 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -475,8 +475,8 @@ void main() {
#ifdef MODE_RENDER_DEPTH
if (scene_data.pancake_shadows) {
- if (gl_Position.z <= 0.00001) {
- gl_Position.z = 0.00001;
+ if (gl_Position.z >= 0.9999) {
+ gl_Position.z = 0.9999;
}
}
#endif // MODE_RENDER_DEPTH
diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
index e9722bad1f..47e6fe5873 100644
--- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl
@@ -454,7 +454,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0);
vec3 tangent = normalize(cross(v0, basis_normal));
vec3 bitangent = normalize(cross(tangent, basis_normal));
- float z_norm = shadow_len * omni_lights.data[idx].inv_radius;
+ float z_norm = 1.0 - shadow_len * omni_lights.data[idx].inv_radius;
tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale;
@@ -479,7 +479,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
pos.xy = uv_rect.xy + pos.xy * uv_rect.zw;
float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r;
- if (d < z_norm) {
+ if (d > z_norm) {
blocker_average += d;
blocker_count += 1.0;
}
@@ -488,11 +488,11 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
if (blocker_count > 0.0) {
//blockers found, do soft shadow
blocker_average /= blocker_count;
- float penumbra = (z_norm - blocker_average) / blocker_average;
+ float penumbra = (z_norm + blocker_average) / blocker_average;
tangent *= penumbra;
bitangent *= penumbra;
- z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
+ z_norm += omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias;
shadow = 0.0;
for (uint i = 0; i < sc_penumbra_shadow_samples; i++) {
@@ -536,6 +536,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) {
vec2 pos = shadow_sample.xy / shadow_sample.z;
float depth = shadow_len - omni_lights.data[idx].shadow_bias;
depth *= omni_lights.data[idx].inv_radius;
+ depth = 1.0 - depth;
shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity);
}
@@ -706,7 +707,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) {
vec4 v = vec4(vertex + normal_bias, 1.0);
vec4 splane = (spot_lights.data[idx].shadow_matrix * v);
- splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
+ splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius);
splane /= splane.w;
float shadow;
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index cf8c29e624..d1ff9fc362 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -668,7 +668,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits;
for (int j = 0; j < 4; j++) {
Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect;
- Projection matrix = light_instance->shadow_transform[j].camera;
+ Projection correction;
+ correction.set_depth_correction(false, true, false);
+ Projection matrix = correction * light_instance->shadow_transform[j].camera;
float split = light_instance->shadow_transform[MIN(limit, j)].split;
Projection bias;
@@ -967,7 +969,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
Projection bias;
bias.set_light_bias();
- Projection cm = light_instance->shadow_transform[0].camera;
+ Projection correction;
+ correction.set_depth_correction(false, true, false);
+ Projection cm = correction * light_instance->shadow_transform[0].camera;
Projection shadow_mtx = bias * cm * modelview;
RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix);
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h
index b3d6bf5254..f152cc5dae 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h
@@ -590,6 +590,29 @@ public:
virtual void light_instance_set_shadow_transform(RID p_light_instance, const Projection &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override;
virtual void light_instance_mark_visible(RID p_light_instance) override;
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light_instance, const Vector3 &p_position) const override {
+ const LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
+ ERR_FAIL_NULL_V(light_instance, false);
+ const Light *light = light_owner.get_or_null(light_instance->light);
+ ERR_FAIL_NULL_V(light, false);
+
+ if (!light->shadow) {
+ return false;
+ }
+
+ if (!light->distance_fade) {
+ return true;
+ }
+
+ real_t distance = p_position.distance_to(light_instance->transform.origin);
+
+ if (distance > light->distance_fade_shadow + light->distance_fade_length) {
+ return false;
+ }
+
+ return true;
+ }
+
_FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) {
LightInstance *li = light_instance_owner.get_or_null(p_light_instance);
return li->light;
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index e78b8de4db..c9c7c53d04 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -1388,6 +1388,11 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) {
}
}
void ParticlesStorage::update_particles() {
+ if (!particle_update_list.first()) {
+ return;
+ }
+
+ RENDER_TIMESTAMP("Update GPUParticles");
uint32_t frame = RSG::rasterizer->get_frame_number();
bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0;
while (particle_update_list.first()) {
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index 8dc74820e2..c5d74d395f 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -128,6 +128,13 @@ void RenderSceneBuffersRD::cleanup() {
free_named_texture(E.value);
}
named_textures.clear();
+
+ // Clear weight_buffer / blur textures.
+ for (const WeightBuffers &weight_buffer : weight_buffers) {
+ if (weight_buffer.weight.is_valid()) {
+ RD::get_singleton()->free(weight_buffer.weight);
+ }
+ }
}
void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) {
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index dd94982f1a..da046bf6b1 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -2965,7 +2965,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
dd.emission_rect[3] = 0;
}
- Color modulate = decal->modulate;
+ Color modulate = decal->modulate.srgb_to_linear();
dd.modulate[0] = modulate.r;
dd.modulate[1] = modulate.g;
dd.modulate[2] = modulate.b;
@@ -3637,8 +3637,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) {
}
rt->process_size = size * scale / 100;
- rt->process_size.x = MAX(rt->process_size.x, 1);
- rt->process_size.y = MAX(rt->process_size.y, 1);
+ rt->process_size = rt->process_size.max(Size2i(1, 1));
tformat.format = RD::DATA_FORMAT_R16G16_SINT;
tformat.width = rt->process_size.width;
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index aa69cd8539..bc1b75c4eb 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -1720,6 +1720,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) {
idata.base_rid = p_instance->base;
idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1;
idata.visibility_index = p_instance->visibility_index;
+ idata.occlusion_timeout = 0;
for (Instance *E : p_instance->visibility_dependencies) {
Instance *dep_instance = E;
@@ -2775,7 +2776,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0)
#define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata))
#define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check)
-#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near))
+#define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near, cull_data.scenario->instance_data[i].occlusion_timeout))
if (!HIDDEN_BY_VISIBILITY_CHECKS) {
if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) {
@@ -3028,6 +3029,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
light_culler->prepare_camera(p_camera_data->main_transform, p_camera_data->main_projection);
Scenario *scenario = scenario_owner.get_or_null(p_scenario);
+ Vector3 camera_position = p_camera_data->main_transform.origin;
ERR_FAIL_COND(p_render_buffers.is_null());
@@ -3037,7 +3039,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
if (p_reflection_probe.is_null()) {
//no rendering code here, this is only to set up what needs to be done, request regions, etc.
- scene_render->sdfgi_update(p_render_buffers, p_environment, p_camera_data->main_transform.origin); //update conditions for SDFGI (whether its used or not)
+ scene_render->sdfgi_update(p_render_buffers, p_environment, camera_position); //update conditions for SDFGI (whether its used or not)
}
RENDER_TIMESTAMP("Update Visibility Dependencies");
@@ -3050,7 +3052,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
VisibilityCullData visibility_cull_data;
visibility_cull_data.scenario = scenario;
visibility_cull_data.viewport_mask = scenario->viewport_visibility_masks[p_viewport];
- visibility_cull_data.camera_position = p_camera_data->main_transform.origin;
+ visibility_cull_data.camera_position = camera_position;
for (int i = scenario->instance_visibility.get_bin_count() - 1; i > 0; i--) { // We skip bin 0
visibility_cull_data.cull_offset = scenario->instance_visibility.get_bin_start(i);
@@ -3219,16 +3221,20 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c
}
}
- // Positional Shadowss
+ // Positional Shadows
for (uint32_t i = 0; i < (uint32_t)scene_cull_result.lights.size(); i++) {
Instance *ins = scene_cull_result.lights[i];
- if (!p_shadow_atlas.is_valid() || !RSG::light_storage->light_has_shadow(ins->base)) {
+ if (!p_shadow_atlas.is_valid()) {
continue;
}
InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
+ if (!RSG::light_storage->light_instance_is_shadow_visible_at_position(light->instance, camera_position)) {
+ continue;
+ }
+
float coverage = 0.f;
{ //compute coverage
@@ -3567,43 +3573,47 @@ void RendererSceneCull::render_probes() {
bool busy = false;
- while (ref_probe) {
- SelfList<InstanceReflectionProbeData> *next = ref_probe->next();
- RID base = ref_probe->self()->owner->base;
+ if (ref_probe) {
+ RENDER_TIMESTAMP("Render ReflectionProbes");
- switch (RSG::light_storage->reflection_probe_get_update_mode(base)) {
- case RS::REFLECTION_PROBE_UPDATE_ONCE: {
- if (busy) { //already rendering something
- break;
- }
+ while (ref_probe) {
+ SelfList<InstanceReflectionProbeData> *next = ref_probe->next();
+ RID base = ref_probe->self()->owner->base;
- bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step);
- if (done) {
- done_list.push_back(ref_probe);
- } else {
- ref_probe->self()->render_step++;
- }
+ switch (RSG::light_storage->reflection_probe_get_update_mode(base)) {
+ case RS::REFLECTION_PROBE_UPDATE_ONCE: {
+ if (busy) { // Already rendering something.
+ break;
+ }
- busy = true; //do not render another one of this kind
- } break;
- case RS::REFLECTION_PROBE_UPDATE_ALWAYS: {
- int step = 0;
- bool done = false;
- while (!done) {
- done = _render_reflection_probe_step(ref_probe->self()->owner, step);
- step++;
- }
+ bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step);
+ if (done) {
+ done_list.push_back(ref_probe);
+ } else {
+ ref_probe->self()->render_step++;
+ }
- done_list.push_back(ref_probe);
- } break;
- }
+ busy = true; // Do not render another one of this kind.
+ } break;
+ case RS::REFLECTION_PROBE_UPDATE_ALWAYS: {
+ int step = 0;
+ bool done = false;
+ while (!done) {
+ done = _render_reflection_probe_step(ref_probe->self()->owner, step);
+ step++;
+ }
- ref_probe = next;
- }
+ done_list.push_back(ref_probe);
+ } break;
+ }
- // Now remove from our list
- for (SelfList<InstanceReflectionProbeData> *rp : done_list) {
- reflection_probe_render_list.remove(rp);
+ ref_probe = next;
+ }
+
+ // Now remove from our list
+ for (SelfList<InstanceReflectionProbeData> *rp : done_list) {
+ reflection_probe_render_list.remove(rp);
+ }
}
/* VOXEL GIS */
@@ -4252,6 +4262,7 @@ RendererSceneCull::RendererSceneCull() {
indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame");
thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances");
thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)WorkerThreadPool::get_singleton()->get_thread_count()); //make sure there is at least one thread per CPU
+ RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection");
dummy_occlusion_culling = memnew(RendererSceneOcclusionCull);
diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h
index 341ba0e3b0..0039d14475 100644
--- a/servers/rendering/renderer_scene_cull.h
+++ b/servers/rendering/renderer_scene_cull.h
@@ -286,6 +286,13 @@ public:
Instance *instance = nullptr;
int32_t parent_array_index = -1;
int32_t visibility_index = -1;
+
+ // Each time occlusion culling determines an instance is visible,
+ // set this to occlusion_frame plus some delay.
+ // Once the timeout is reached, allow the instance to be occlusion culled.
+ // This creates a delay for occlusion culling, which prevents flickering
+ // when jittering the raster occlusion projection.
+ uint64_t occlusion_timeout = 0;
};
struct InstanceVisibilityData {
diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp
index c4f0177c73..1f0239411a 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.cpp
+++ b/servers/rendering/renderer_scene_occlusion_cull.cpp
@@ -43,6 +43,8 @@ const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = {
Vector3(1, 1, 1)
};
+bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false;
+
bool RendererSceneOcclusionCull::HZBuffer::is_empty() const {
return sizes.is_empty();
}
@@ -66,6 +68,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() {
}
void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) {
+ occlusion_buffer_size = p_size;
+
if (p_size == Size2i()) {
clear();
return;
@@ -124,6 +128,9 @@ void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) {
}
void RendererSceneOcclusionCull::HZBuffer::update_mips() {
+ // Keep this up to date as a local to be used for occlusion timers.
+ occlusion_frame = Engine::get_singleton()->get_frames_drawn();
+
if (sizes.is_empty()) {
return;
}
diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h
index 565b393094..5adba5dc6a 100644
--- a/servers/rendering/renderer_scene_occlusion_cull.h
+++ b/servers/rendering/renderer_scene_occlusion_cull.h
@@ -53,19 +53,15 @@ public:
PackedByteArray debug_data;
float debug_tex_range = 0.0f;
- public:
- bool is_empty() const;
- virtual void clear();
- virtual void resize(const Size2i &p_size);
-
- void update_mips();
+ uint64_t occlusion_frame = 0;
+ Size2i occlusion_buffer_size;
- _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const {
+ _FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const {
if (is_empty()) {
return false;
}
- Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5]));
+ Vector3 closest_point = p_cam_position.clamp(Vector3(p_bounds[0], p_bounds[1], p_bounds[2]), Vector3(p_bounds[3], p_bounds[4], p_bounds[5]));
if (closest_point == p_cam_position) {
return false;
@@ -154,7 +150,47 @@ public:
return !visible;
}
+ public:
+ static bool occlusion_jitter_enabled;
+
+ bool is_empty() const;
+ virtual void clear();
+ virtual void resize(const Size2i &p_size);
+
+ void update_mips();
+
+ // Thin wrapper around _is_occluded(),
+ // allowing occlusion timers to delay the disappearance
+ // of objects to prevent flickering when using jittering.
+ _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, uint64_t &r_occlusion_timeout) const {
+ bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near);
+
+ // Special case, temporal jitter disabled,
+ // so we don't use occlusion timers.
+ if (!occlusion_jitter_enabled) {
+ return occluded;
+ }
+
+ if (!occluded) {
+//#define DEBUG_RASTER_OCCLUSION_JITTER
+#ifdef DEBUG_RASTER_OCCLUSION_JITTER
+ r_occlusion_timeout = occlusion_frame + 1;
+#else
+ r_occlusion_timeout = occlusion_frame + 9;
+#endif
+ } else if (r_occlusion_timeout) {
+ // Regular timeout, allow occlusion culling
+ // to proceed as normal after the delay.
+ if (occlusion_frame >= r_occlusion_timeout) {
+ r_occlusion_timeout = 0;
+ }
+ }
+
+ return occluded && !r_occlusion_timeout;
+ }
+
RID get_debug_texture();
+ const Size2i &get_occlusion_buffer_size() const { return occlusion_buffer_size; }
virtual ~HZBuffer(){};
};
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index baa198626c..31d5a9074c 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -31,6 +31,7 @@
#include "renderer_viewport.h"
#include "core/config/project_settings.h"
+#include "core/math/transform_interpolator.h"
#include "core/object/worker_thread_pool.h"
#include "renderer_canvas_cull.h"
#include "renderer_scene_cull.h"
@@ -339,7 +340,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
if (!F->enabled) {
continue;
}
- F->xform_cache = xf * F->xform;
+
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
+ F->xform_cache = xf * F->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
+ F->xform_cache = xf * F->xform_cache;
+ }
if (sdf_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
F->next = occluders;
@@ -378,7 +386,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
Vector2 offset = tsize / 2.0;
cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize);
- cl->xform_cache = xf * cl->xform;
+
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
+ cl->xform_cache = xf * cl->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
+ cl->xform_cache = xf * cl->xform_cache;
+ }
if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) {
cl->filter_next_ptr = lights;
@@ -386,7 +401,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
Transform2D scale;
scale.scale(cl->rect_cache.size);
scale.columns[2] = cl->rect_cache.position;
- cl->light_shader_xform = xf * cl->xform * scale;
+ cl->light_shader_xform = cl->xform_cache * scale;
if (cl->use_shadow) {
cl->shadows_next_ptr = lights_with_shadow;
if (lights_with_shadow == nullptr) {
@@ -406,7 +421,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
if (cl->enabled) {
cl->filter_next_ptr = directional_lights;
directional_lights = cl;
- cl->xform_cache = xf * cl->xform;
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) {
+ cl->xform_cache = xf * cl->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f);
+ cl->xform_cache = xf * cl->xform_cache;
+ }
cl->xform_cache.columns[2] = Vector2(); //translation is pointless
if (cl->use_shadow) {
cl->shadows_next_ptr = directional_lights_with_shadow;
@@ -441,7 +462,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
if (!F->enabled) {
continue;
}
- F->xform_cache = xf * F->xform;
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
+ F->xform_cache = xf * F->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
+ F->xform_cache = xf * F->xform_cache;
+ }
if (shadow_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) {
F->next = occluders;
occluders = F;
@@ -521,7 +548,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) {
if (!F->enabled) {
continue;
}
- F->xform_cache = xf * F->xform;
+ if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) {
+ F->xform_cache = xf * F->xform_curr;
+ } else {
+ real_t f = Engine::get_singleton()->get_physics_interpolation_fraction();
+ TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f);
+ F->xform_cache = xf * F->xform_cache;
+ }
Transform2D localizer = F->xform_cache.affine_inverse();
for (int j = 0; j < point_count; j++) {
@@ -769,8 +802,6 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) {
} else
#endif // _3D_DISABLED
{
- RSG::texture_storage->render_target_set_override(vp->render_target, RID(), RID(), RID());
-
RSG::scene->set_debug_draw_mode(vp->debug_draw);
// render standard mono camera
@@ -1029,6 +1060,13 @@ void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpda
viewport->update_mode = p_mode;
}
+RS::ViewportUpdateMode RendererViewport::viewport_get_update_mode(RID p_viewport) const {
+ Viewport *viewport = viewport_owner.get_or_null(p_viewport);
+ ERR_FAIL_NULL_V(viewport, RS::VIEWPORT_UPDATE_DISABLED);
+
+ return viewport->update_mode;
+}
+
RID RendererViewport::viewport_get_render_target(RID p_viewport) const {
const Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL_V(viewport, RID());
@@ -1158,6 +1196,9 @@ void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canva
void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_NULL(viewport);
+ if (viewport->transparent_bg == p_enabled) {
+ return;
+ }
RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled);
viewport->transparent_bg = p_enabled;
diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h
index 90c29618b3..5107398c54 100644
--- a/servers/rendering/renderer_viewport.h
+++ b/servers/rendering/renderer_viewport.h
@@ -236,6 +236,7 @@ public:
void viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias);
void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode);
+ RS::ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const;
void viewport_set_vflip(RID p_viewport, bool p_enable);
void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode);
diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp
index 7dfff0b76f..2b6644e893 100644
--- a/servers/rendering/rendering_device.cpp
+++ b/servers/rendering/rendering_device.cpp
@@ -5089,7 +5089,8 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ
draw_list = nullptr;
compute_list = nullptr;
- if (main_instance) {
+ bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable");
+ if (main_instance && project_pipeline_cache_enable) {
// Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache.
pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s",
OS::get_singleton()->get_current_rendering_method(),
@@ -5223,8 +5224,12 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
case DRIVER_RESOURCE_LOGICAL_DEVICE:
case DRIVER_RESOURCE_PHYSICAL_DEVICE:
case DRIVER_RESOURCE_TOPMOST_OBJECT:
+ break;
case DRIVER_RESOURCE_COMMAND_QUEUE:
+ driver_id = main_queue.id;
+ break;
case DRIVER_RESOURCE_QUEUE_FAMILY:
+ driver_id = main_queue_family.id;
break;
case DRIVER_RESOURCE_TEXTURE:
case DRIVER_RESOURCE_TEXTURE_VIEW:
@@ -5232,19 +5237,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
Texture *tex = texture_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(tex, 0);
- driver_id = tex->driver_id;
+ driver_id = tex->driver_id.id;
} break;
case DRIVER_RESOURCE_SAMPLER: {
RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(sampler_driver_id, 0);
- driver_id = *sampler_driver_id;
+ driver_id = (*sampler_driver_id).id;
} break;
case DRIVER_RESOURCE_UNIFORM_SET: {
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(uniform_set, 0);
- driver_id = uniform_set->driver_id;
+ driver_id = uniform_set->driver_id.id;
} break;
case DRIVER_RESOURCE_BUFFER: {
Buffer *buffer = nullptr;
@@ -5261,19 +5266,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r
}
ERR_FAIL_NULL_V(buffer, 0);
- driver_id = buffer->driver_id;
+ driver_id = buffer->driver_id.id;
} break;
case DRIVER_RESOURCE_COMPUTE_PIPELINE: {
ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(compute_pipeline, 0);
- driver_id = compute_pipeline->driver_id;
+ driver_id = compute_pipeline->driver_id.id;
} break;
case DRIVER_RESOURCE_RENDER_PIPELINE: {
RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid);
ERR_FAIL_NULL_V(render_pipeline, 0);
- driver_id = render_pipeline->driver_id;
+ driver_id = render_pipeline->driver_id.id;
} break;
default: {
ERR_FAIL_V(0);
@@ -5549,6 +5554,7 @@ void RenderingDevice::_bind_methods() {
ClassDB::bind_method(D_METHOD("compute_list_set_push_constant", "compute_list", "buffer", "size_bytes"), &RenderingDevice::_compute_list_set_push_constant);
ClassDB::bind_method(D_METHOD("compute_list_bind_uniform_set", "compute_list", "uniform_set", "set_index"), &RenderingDevice::compute_list_bind_uniform_set);
ClassDB::bind_method(D_METHOD("compute_list_dispatch", "compute_list", "x_groups", "y_groups", "z_groups"), &RenderingDevice::compute_list_dispatch);
+ ClassDB::bind_method(D_METHOD("compute_list_dispatch_indirect", "compute_list", "buffer", "offset"), &RenderingDevice::compute_list_dispatch_indirect);
ClassDB::bind_method(D_METHOD("compute_list_add_barrier", "compute_list"), &RenderingDevice::compute_list_add_barrier);
ClassDB::bind_method(D_METHOD("compute_list_end"), &RenderingDevice::compute_list_end);
diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h
index 9a898a2fca..c8277024cf 100644
--- a/servers/rendering/rendering_device.h
+++ b/servers/rendering/rendering_device.h
@@ -1103,7 +1103,7 @@ private:
public:
DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color());
- DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
+ DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2());
void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color);
void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline);
diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h
index 09a0412941..e9464ba321 100644
--- a/servers/rendering/rendering_device_driver.h
+++ b/servers/rendering/rendering_device_driver.h
@@ -128,7 +128,7 @@ public:
#define DEFINE_ID(m_name) \
struct m_name##ID : public ID { \
- _ALWAYS_INLINE_ operator bool() const { return id != 0; } \
+ _ALWAYS_INLINE_ explicit operator bool() const { return id != 0; } \
_ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) { \
id = p_other.id; \
return *this; \
diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp
index 4b85d1c2bf..adac7ee3eb 100644
--- a/servers/rendering/rendering_device_graph.cpp
+++ b/servers/rendering/rendering_device_graph.cpp
@@ -261,7 +261,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
}
if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) {
- if (resource_tracker->parent->texture_driver_id != 0) {
+ if (resource_tracker->parent->texture_driver_id.id != 0) {
// If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it.
_add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
}
@@ -324,7 +324,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command.");
} else {
// Delete the slice from the dirty list and revert it to the usage of the parent.
- if (current_tracker->texture_driver_id != 0) {
+ if (current_tracker->texture_driver_id.id != 0) {
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
// Merge the area of the slice with the current tracking area of the command and indicate it's a write usage as well.
@@ -383,7 +383,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr
while (current_tracker != nullptr) {
current_tracker->reset_if_outdated(tracking_frame);
- if (current_tracker->texture_driver_id != 0) {
+ if (current_tracker->texture_driver_id.id != 0) {
// Transition all slices to the layout of the parent resource.
_add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count);
}
diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp
index fdf0d73654..0889898f0b 100644
--- a/servers/rendering/rendering_light_culler.cpp
+++ b/servers/rendering/rendering_light_culler.cpp
@@ -427,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
uint8_t *entry = &data.LUT_entries[lookup][0];
int n_edges = data.LUT_entry_sizes[lookup] - 1;
+ const Vector3 &pt2 = p_light_source.pos;
+
for (int e = 0; e < n_edges; e++) {
int i0 = entry[e];
int i1 = entry[e + 1];
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
// Last to 0 edge.
@@ -446,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan
const Vector3 &pt0 = data.frustum_points[i0];
const Vector3 &pt1 = data.frustum_points[i1];
- // Create plane from 3 points.
- Plane p(pt0, pt1, p_light_source.pos);
- r_cull_planes.add_cull_plane(p);
+ if (!_is_colinear_tri(pt0, pt1, pt2)) {
+ // Create plane from 3 points.
+ Plane p(pt0, pt1, pt2);
+ r_cull_planes.add_cull_plane(p);
+ }
}
#ifdef LIGHT_CULLER_DEBUG_LOGGING
diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h
index 602543850a..0bf975430b 100644
--- a/servers/rendering/rendering_light_culler.h
+++ b/servers/rendering/rendering_light_culler.h
@@ -163,6 +163,39 @@ private:
bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1);
+ // Avoid adding extra culling planes derived from near colinear triangles.
+ // The normals derived from these will be inaccurate, and can lead to false
+ // culling of objects that should be within the light volume.
+ bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const {
+ // Lengths of sides a, b and c.
+ float la = (p_b - p_a).length();
+ float lb = (p_c - p_b).length();
+ float lc = (p_c - p_a).length();
+
+ // Get longest side into lc.
+ if (lb < la) {
+ SWAP(la, lb);
+ }
+ if (lc < lb) {
+ SWAP(lb, lc);
+ }
+
+ // Prevent divide by zero.
+ if (lc > 0.00001f) {
+ // If the summed length of the smaller two
+ // sides is close to the length of the longest side,
+ // the points are colinear, and the triangle is near degenerate.
+ float ld = ((la + lb) - lc) / lc;
+
+ // ld will be close to zero for colinear tris.
+ return ld < 0.00001f;
+ }
+
+ // Don't create planes from tiny triangles,
+ // they won't be accurate.
+ return true;
+ }
+
// Internal version uses LightSource.
bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source);
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index b4c539dcff..5bf0ab0ba6 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -80,6 +80,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
uint64_t time_usec = OS::get_singleton()->get_ticks_usec();
+ RENDER_TIMESTAMP("Prepare Render Frame");
RSG::scene->update(); //update scenes stuff before updating instances
frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0;
@@ -370,6 +371,16 @@ void RenderingServerDefault::_thread_loop() {
_finish();
}
+/* INTERPOLATION */
+
+void RenderingServerDefault::tick() {
+ RSG::canvas->tick();
+}
+
+void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) {
+ RSG::canvas->set_physics_interpolation_enabled(p_enabled);
+}
+
/* EVENT QUEUING */
void RenderingServerDefault::sync() {
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index 99fd683e1d..c50472c0cd 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -625,6 +625,7 @@ public:
FUNC2(viewport_set_texture_mipmap_bias, RID, float)
FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode)
+ FUNC1RC(ViewportUpdateMode, viewport_get_update_mode, RID)
FUNC1RC(RID, viewport_get_render_target, RID)
FUNC1RC(RID, viewport_get_texture, RID)
@@ -926,6 +927,10 @@ public:
FUNC1(canvas_item_set_debug_redraw, bool)
FUNC0RC(bool, canvas_item_get_debug_redraw)
+ FUNC2(canvas_item_set_interpolated, RID, bool)
+ FUNC1(canvas_item_reset_physics_interpolation, RID)
+ FUNC2(canvas_item_transform_physics_interpolation, RID, const Transform2D &)
+
FUNCRIDSPLIT(canvas_light)
FUNC2(canvas_light_set_mode, RID, CanvasLightMode)
@@ -952,6 +957,10 @@ public:
FUNC2(canvas_light_set_shadow_color, RID, const Color &)
FUNC2(canvas_light_set_shadow_smooth, RID, float)
+ FUNC2(canvas_light_set_interpolated, RID, bool)
+ FUNC1(canvas_light_reset_physics_interpolation, RID)
+ FUNC2(canvas_light_transform_physics_interpolation, RID, const Transform2D &)
+
FUNCRIDSPLIT(canvas_light_occluder)
FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID)
FUNC2(canvas_light_occluder_set_enabled, RID, bool)
@@ -960,6 +969,10 @@ public:
FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &)
FUNC2(canvas_light_occluder_set_light_mask, RID, int)
+ FUNC2(canvas_light_occluder_set_interpolated, RID, bool)
+ FUNC1(canvas_light_occluder_reset_physics_interpolation, RID)
+ FUNC2(canvas_light_occluder_transform_physics_interpolation, RID, const Transform2D &)
+
FUNCRIDSPLIT(canvas_occluder_polygon)
FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool)
@@ -1021,6 +1034,11 @@ public:
}
}
+ /* INTERPOLATION */
+
+ virtual void tick() override;
+ virtual void set_physics_interpolation_enabled(bool p_enabled) override;
+
/* EVENT QUEUING */
virtual void request_frame_drawn_callback(const Callable &p_callable) override;
diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h
index d439598f3d..6a0adfa596 100644
--- a/servers/rendering/storage/light_storage.h
+++ b/servers/rendering/storage/light_storage.h
@@ -98,6 +98,7 @@ public:
virtual bool light_instances_can_render_shadow_cube() const {
return true;
}
+ virtual bool light_instance_is_shadow_visible_at_position(RID p_light, const Vector3 &p_position) const = 0;
/* PROBE API */
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 1ed0424839..96d317ebd3 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -2783,6 +2783,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("viewport_set_fsr_sharpness", "viewport", "sharpness"), &RenderingServer::viewport_set_fsr_sharpness);
ClassDB::bind_method(D_METHOD("viewport_set_texture_mipmap_bias", "viewport", "mipmap_bias"), &RenderingServer::viewport_set_texture_mipmap_bias);
ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode);
+ ClassDB::bind_method(D_METHOD("viewport_get_update_mode", "viewport"), &RenderingServer::viewport_get_update_mode);
ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode);
ClassDB::bind_method(D_METHOD("viewport_get_render_target", "viewport"), &RenderingServer::viewport_get_render_target);
ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture);
@@ -3219,6 +3220,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate);
ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate);
ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent);
+ ClassDB::bind_method(D_METHOD("canvas_item_set_interpolated", "item", "interpolated"), &RenderingServer::canvas_item_set_interpolated);
+ ClassDB::bind_method(D_METHOD("canvas_item_reset_physics_interpolation", "item"), &RenderingServer::canvas_item_reset_physics_interpolation);
+ ClassDB::bind_method(D_METHOD("canvas_item_transform_physics_interpolation", "item", "transform"), &RenderingServer::canvas_item_transform_physics_interpolation);
/* Primitives */
@@ -3302,6 +3306,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color);
ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth);
ClassDB::bind_method(D_METHOD("canvas_light_set_blend_mode", "light", "mode"), &RenderingServer::canvas_light_set_blend_mode);
+ ClassDB::bind_method(D_METHOD("canvas_light_set_interpolated", "light", "interpolated"), &RenderingServer::canvas_light_set_interpolated);
+ ClassDB::bind_method(D_METHOD("canvas_light_reset_physics_interpolation", "light"), &RenderingServer::canvas_light_reset_physics_interpolation);
+ ClassDB::bind_method(D_METHOD("canvas_light_transform_physics_interpolation", "light", "transform"), &RenderingServer::canvas_light_transform_physics_interpolation);
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_POINT);
BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_DIRECTIONAL);
@@ -3324,6 +3331,9 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_as_sdf_collision", "occluder", "enable"), &RenderingServer::canvas_light_occluder_set_as_sdf_collision);
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform);
ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_interpolated", "occluder", "interpolated"), &RenderingServer::canvas_light_occluder_set_interpolated);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_reset_physics_interpolation", "occluder"), &RenderingServer::canvas_light_occluder_reset_physics_interpolation);
+ ClassDB::bind_method(D_METHOD("canvas_light_occluder_transform_physics_interpolation", "occluder", "transform"), &RenderingServer::canvas_light_occluder_transform_physics_interpolation);
/* CANVAS LIGHT OCCLUDER POLYGON */
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index a67ae0a66c..8f0150f180 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -873,6 +873,7 @@ public:
};
virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0;
+ virtual ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const = 0;
enum ViewportClearMode {
VIEWPORT_CLEAR_ALWAYS,
@@ -1476,6 +1477,10 @@ public:
virtual void canvas_item_set_debug_redraw(bool p_enabled) = 0;
virtual bool canvas_item_get_debug_redraw() const = 0;
+ virtual void canvas_item_set_interpolated(RID p_item, bool p_interpolated) = 0;
+ virtual void canvas_item_reset_physics_interpolation(RID p_item) = 0;
+ virtual void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) = 0;
+
/* CANVAS LIGHT */
virtual RID canvas_light_create() = 0;
@@ -1523,6 +1528,10 @@ public:
virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0;
virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0;
+ virtual void canvas_light_set_interpolated(RID p_light, bool p_interpolated) = 0;
+ virtual void canvas_light_reset_physics_interpolation(RID p_light) = 0;
+ virtual void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) = 0;
+
/* CANVAS LIGHT OCCLUDER */
virtual RID canvas_light_occluder_create() = 0;
@@ -1533,6 +1542,10 @@ public:
virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0;
virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0;
+ virtual void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) = 0;
+ virtual void canvas_light_occluder_reset_physics_interpolation(RID p_occluder) = 0;
+ virtual void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) = 0;
+
/* CANVAS LIGHT OCCLUDER POLYGON */
virtual RID canvas_occluder_polygon_create() = 0;
@@ -1604,6 +1617,11 @@ public:
virtual void free(RID p_rid) = 0; // Free RIDs associated with the rendering server.
+ /* INTERPOLATION */
+
+ virtual void tick() = 0;
+ virtual void set_physics_interpolation_enabled(bool p_enabled) = 0;
+
/* EVENT QUEUING */
virtual void request_frame_drawn_callback(const Callable &p_callable) = 0;
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index eb9f1c1484..53e1d119fd 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -341,6 +341,7 @@ void TextServerExtension::_bind_methods() {
GDVIRTUAL_BIND(_string_to_upper, "string", "language");
GDVIRTUAL_BIND(_string_to_lower, "string", "language");
+ GDVIRTUAL_BIND(_string_to_title, "string", "language");
GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text");
@@ -1507,6 +1508,14 @@ String TextServerExtension::string_to_upper(const String &p_string, const String
return p_string;
}
+String TextServerExtension::string_to_title(const String &p_string, const String &p_language) const {
+ String ret;
+ if (GDVIRTUAL_CALL(_string_to_title, p_string, p_language, ret)) {
+ return ret;
+ }
+ return p_string;
+}
+
String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const {
String ret;
if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) {
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index 84d68de4fa..53d30abee4 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -566,8 +566,10 @@ public:
virtual String string_to_upper(const String &p_string, const String &p_language = "") const override;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const override;
+ virtual String string_to_title(const String &p_string, const String &p_language = "") const override;
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
+ GDVIRTUAL2RC(String, _string_to_title, const String &, const String &);
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index 078ee27753..fac9e32d01 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -491,6 +491,7 @@ void TextServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL(""));
ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL(""));
+ ClassDB::bind_method(D_METHOD("string_to_title", "string", "language"), &TextServer::string_to_title, DEFVAL(""));
ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text);
diff --git a/servers/text_server.h b/servers/text_server.h
index 4a16ae64e8..396d7ca8e5 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -546,6 +546,7 @@ public:
// Other string operations.
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
+ virtual String string_to_title(const String &p_string, const String &p_language = "") const = 0;
TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;