summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/classes/EditorSettings.xml15
-rw-r--r--doc/classes/Label.xml1
-rw-r--r--doc/classes/Slider.xml2
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h1
-rw-r--r--editor/editor_settings.cpp2
-rw-r--r--editor/filesystem_dock.cpp143
-rw-r--r--editor/filesystem_dock.h1
-rw-r--r--editor/icons/Terminal.svg1
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp2
-rw-r--r--scene/gui/slider.cpp5
-rw-r--r--scene/gui/slider.h3
-rw-r--r--servers/physics_2d/godot_area_pair_2d.cpp5
-rw-r--r--servers/physics_2d/godot_area_pair_2d.h1
-rw-r--r--servers/physics_2d/godot_shape_2d.cpp3
-rw-r--r--servers/physics_3d/godot_area_pair_3d.cpp10
-rw-r--r--servers/physics_3d/godot_area_pair_3d.h2
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.cpp6
-rw-r--r--servers/rendering/renderer_rd/effects/copy_effects.h3
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp61
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h9
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp2
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl10
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssao.glsl17
-rw-r--r--servers/rendering/renderer_rd/shaders/effects/ssil.glsl17
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/gi.glsl5
-rw-r--r--servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl2
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl43
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl42
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl12
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl1
-rw-r--r--servers/rendering/shader_compiler.cpp5
34 files changed, 391 insertions, 53 deletions
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 93d2bb8548..5c317a5088 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -466,6 +466,21 @@
<member name="filesystem/external_programs/raster_image_editor" type="String" setter="" getter="">
The program that opens raster image files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program.
</member>
+ <member name="filesystem/external_programs/terminal_emulator" type="String" setter="" getter="">
+ The terminal emulator program to use when using [b]Open in Terminal[/b] context menu action in the FileSystem dock. You can enter an absolute path to a program binary, or a path to a program that is present in the [code]PATH[/code] environment variable.
+ If left empty, Godot will use the default terminal emulator for the system:
+ - [b]Windows:[/b] PowerShell
+ - [b]macOS:[/b] Terminal.app
+ - [b]Linux:[/b] The first terminal found on the system in this order: gnome-terminal, konsole, xfce4-terminal, lxterminal, kitty, alacritty, urxvt, xterm.
+ To use Command Prompt (cmd) instead of PowerShell on Windows, enter [code]cmd[/code] in this field and the correct flags will automatically be used.
+ On macOS, make sure to point to the actual program binary located within the [code]Programs/MacOS[/code] folder of the .app bundle, rather than the .app bundle directory.
+ If specifying a custom terminal emulator, you may need to override [member filesystem/external_programs/terminal_emulator_flags] so it opens in the correct folder.
+ </member>
+ <member name="filesystem/external_programs/terminal_emulator_flags" type="String" setter="" getter="">
+ The command-line arguments to pass to the terminal emulator that is run when using [b]Open in Terminal[/b] context menu action in the FileSystem dock. See also [member filesystem/external_programs/terminal_emulator].
+ If left empty, the default flags are [code]{directory}[/code], which is replaced by the absolute path to the directory that is being opened in the terminal.
+ [b]Note:[/b] If the terminal emulator is set to PowerShell, cmd, or Konsole, Godot will automatically prepend arguments to this list, as these terminals require nonstandard arguments to open in the correct folder.
+ </member>
<member name="filesystem/external_programs/vector_image_editor" type="String" setter="" getter="">
The program that opens vector image files when clicking "Open in External Program" option in Filesystem Dock. If not specified, the file will be opened in the system's default program.
</member>
diff --git a/doc/classes/Label.xml b/doc/classes/Label.xml
index 94b1815dce..77ead8fca0 100644
--- a/doc/classes/Label.xml
+++ b/doc/classes/Label.xml
@@ -127,6 +127,7 @@
<theme_item name="outline_size" data_type="constant" type="int" default="0">
Text outline size.
[b]Note:[/b] If using a font with [member FontFile.multichannel_signed_distance_field] enabled, its [member FontFile.msdf_pixel_range] must be set to at least [i]twice[/i] the value of [theme_item outline_size] for outline rendering to look correct. Otherwise, the outline may appear to be cut off earlier than intended.
+ [b]Note:[/b] Using a value that is larger than half the font size is not recommended, as the font outline may fail to be fully closed in this case.
</theme_item>
<theme_item name="shadow_offset_x" data_type="constant" type="int" default="1">
The horizontal offset of the text's shadow.
diff --git a/doc/classes/Slider.xml b/doc/classes/Slider.xml
index 0471b8c275..492b6164bf 100644
--- a/doc/classes/Slider.xml
+++ b/doc/classes/Slider.xml
@@ -33,7 +33,7 @@
</signal>
<signal name="drag_started">
<description>
- Emitted when dragging is started.
+ Emitted when dragging is started. This is emitted before the corresponding [signal Range.value_changed] signal.
</description>
</signal>
</signals>
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index a860793c21..045511321a 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -328,6 +328,7 @@ private:
};
enum {
+ INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
INSTANCE_DATA_FLAG_USE_LIGHTMAP_CAPTURE = 1 << 7,
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 98706a10f2..e6ba39cae7 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -500,6 +500,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/vector_image_editor", "", "")
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/audio_editor", "", "")
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/3d_model_editor", "", "")
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_FILE, "filesystem/external_programs/terminal_emulator", "", "")
+ EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_PLACEHOLDER_TEXT, "filesystem/external_programs/terminal_emulator_flags", "", "Call flags with placeholder: {directory}.");
// Directories
EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_GLOBAL_DIR, "filesystem/directories/autoscan_project_path", "", "")
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 1b966fced1..e5d03942e3 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2135,6 +2135,135 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
}
} break;
+ case FILE_OPEN_IN_TERMINAL: {
+ String fpath = current_path;
+ if (current_path == "Favorites") {
+ fpath = p_selected[0];
+ }
+
+ Vector<String> terminal_emulators;
+ const String terminal_emulator_setting = EDITOR_GET("filesystem/external_programs/terminal_emulator");
+ if (terminal_emulator_setting.is_empty()) {
+ // Figure out a default terminal emulator to use.
+#if defined(WINDOWS_ENABLED)
+ // Default to PowerShell as done by Windows 10 and later.
+ terminal_emulators.push_back("powershell");
+#elif defined(MACOS_ENABLED)
+ terminal_emulators.push_back("/System/Applications/Utilities/Terminal.app");
+#elif defined(LINUXBSD_ENABLED)
+ // Try terminal emulators that ship with common Linux distributions first.
+ terminal_emulators.push_back("gnome-terminal");
+ terminal_emulators.push_back("konsole");
+ terminal_emulators.push_back("xfce4-terminal");
+ terminal_emulators.push_back("lxterminal");
+ terminal_emulators.push_back("kitty");
+ terminal_emulators.push_back("alacritty");
+ terminal_emulators.push_back("urxvt");
+ terminal_emulators.push_back("xterm");
+#endif
+ } else {
+ // Use the user-specified terminal.
+ terminal_emulators.push_back(terminal_emulator_setting);
+ }
+
+ String arguments = EDITOR_GET("filesystem/external_programs/terminal_emulator_flags");
+ if (arguments.is_empty()) {
+ // NOTE: This default value is ignored further below if the terminal executable is `powershell` or `cmd`,
+ // due to these terminals requiring nonstandard syntax to start in a specified folder.
+ arguments = "{directory}";
+ }
+
+#ifdef LINUXBSD_ENABLED
+ String chosen_terminal_emulator;
+ for (const String &terminal_emulator : terminal_emulators) {
+ List<String> test_args; // Required for `execute()`, as it doesn't accept `Vector<String>`.
+ test_args.push_back("-v");
+ test_args.push_back(terminal_emulator);
+ // Silence command name being printed when found. (stderr is already silenced by `OS::execute()` by default.)
+ // FIXME: This doesn't appear to silence stdout.
+ test_args.push_back(">");
+ test_args.push_back("/dev/null");
+ int exit_code = 0;
+ const Error err = OS::get_singleton()->execute("command", test_args, nullptr, &exit_code);
+ if (err == OK && exit_code == EXIT_SUCCESS) {
+ chosen_terminal_emulator = terminal_emulator;
+ break;
+ } else if (err == ERR_CANT_FORK) {
+ ERR_PRINT_ED(vformat(TTR("Couldn't run external program to check for terminal emulator presence: command -v %s"), terminal_emulator));
+ }
+ }
+#else
+ // On Windows and macOS, the first (and only) terminal emulator in the list is always available.
+ String chosen_terminal_emulator = terminal_emulators[0];
+#endif
+
+ List<String> terminal_emulator_args; // Required for `execute()`, as it doesn't accept `Vector<String>`.
+#ifdef LINUXBSD_ENABLED
+ // Prepend default arguments based on the terminal emulator name.
+ // Use `String.ends_with()` so that installations in non-default paths
+ // or `/usr/local/bin` are detected correctly.
+ if (chosen_terminal_emulator.ends_with("konsole")) {
+ terminal_emulator_args.push_back("--workdir");
+ }
+#endif
+
+ bool append_default_args = true;
+
+#ifdef WINDOWS_ENABLED
+ // Prepend default arguments based on the terminal emulator name.
+ // Use `String.get_basename().to_lower()` to handle Windows' case-insensitive paths
+ // with optional file extensions for executables in `PATH`.
+ if (chosen_terminal_emulator.get_basename().to_lower() == "powershell") {
+ terminal_emulator_args.push_back("-noexit");
+ terminal_emulator_args.push_back("-command");
+ terminal_emulator_args.push_back("cd '{directory}'");
+ append_default_args = false;
+ } else if (chosen_terminal_emulator.get_basename().to_lower() == "cmd") {
+ terminal_emulator_args.push_back("/K");
+ terminal_emulator_args.push_back("cd /d {directory}");
+ append_default_args = false;
+ }
+#endif
+
+ Vector<String> arguments_array = arguments.split(" ");
+ for (const String &argument : arguments_array) {
+ if (!append_default_args && argument == "{directory}") {
+ // Prevent appending a `{directory}` placeholder twice when using powershell or cmd.
+ // This allows users to enter the path to cmd or PowerShell in the custom terminal emulator path,
+ // and make it work without having to enter custom arguments.
+ continue;
+ }
+ terminal_emulator_args.push_back(argument);
+ }
+
+ const bool is_directory = fpath.ends_with("/");
+ for (int i = 0; i < terminal_emulator_args.size(); i++) {
+ if (is_directory) {
+ terminal_emulator_args[i] = terminal_emulator_args[i].replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath));
+ } else {
+ terminal_emulator_args[i] = terminal_emulator_args[i].replace("{directory}", ProjectSettings::get_singleton()->globalize_path(fpath).get_base_dir());
+ }
+ }
+
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ // Print full command line to help with troubleshooting.
+ String command_string = chosen_terminal_emulator;
+ for (const String &arg : terminal_emulator_args) {
+ command_string += " " + arg;
+ }
+ print_line("Opening terminal emulator:", command_string);
+ }
+
+ const Error err = OS::get_singleton()->create_process(chosen_terminal_emulator, terminal_emulator_args, nullptr, true);
+ if (err != OK) {
+ String args_string;
+ for (int i = 0; i < terminal_emulator_args.size(); i++) {
+ args_string += terminal_emulator_args[i];
+ }
+ ERR_PRINT_ED(vformat(TTR("Couldn't run external terminal program (error code %d): %s %s\nCheck `filesystem/external_programs/terminal_emulator` and `filesystem/external_programs/terminal_emulator_flags` in the Editor Settings."), err, chosen_terminal_emulator, args_string));
+ }
+ } break;
+
case FILE_OPEN: {
// Open folders.
TreeItem *selected = tree->get_root();
@@ -3055,12 +3184,16 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
// Opening the system file manager is not supported on the Android and web editors.
const bool is_directory = fpath.ends_with("/");
- const String item_text = is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager");
+
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
- p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), item_text);
+ p_popup->set_item_text(p_popup->get_item_index(FILE_SHOW_IN_EXPLORER), is_directory ? TTR("Open in File Manager") : TTR("Show in File Manager"));
+
if (!is_directory) {
p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("ExternalLink")), ED_GET_SHORTCUT("filesystem_dock/open_in_external_program"), FILE_OPEN_EXTERNAL);
}
+
+ p_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
+ p_popup->set_item_text(p_popup->get_item_index(FILE_OPEN_IN_TERMINAL), is_directory ? TTR("Open in Terminal") : TTR("Open Containing Folder in Terminal"));
#endif
current_path = fpath;
@@ -3105,6 +3238,7 @@ void FileSystemDock::_tree_empty_click(const Vector2 &p_pos, MouseButton p_butto
// Opening the system file manager is not supported on the Android and web editors.
tree_popup->add_separator();
tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Filesystem")), ED_GET_SHORTCUT("filesystem_dock/show_in_explorer"), FILE_SHOW_IN_EXPLORER);
+ tree_popup->add_icon_shortcut(get_editor_theme_icon(SNAME("Terminal")), ED_GET_SHORTCUT("filesystem_dock/open_in_terminal"), FILE_OPEN_IN_TERMINAL);
#endif
tree_popup->set_position(tree->get_screen_position() + p_pos);
@@ -3283,6 +3417,8 @@ void FileSystemDock::_tree_gui_input(Ref<InputEvent> p_event) {
_tree_rmb_option(FILE_SHOW_IN_EXPLORER);
} else if (ED_IS_SHORTCUT("filesystem_dock/open_in_external_program", p_event)) {
_tree_rmb_option(FILE_OPEN_EXTERNAL);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/open_in_terminal", p_event)) {
+ _tree_rmb_option(FILE_OPEN_IN_TERMINAL);
} else if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
focus_on_filter();
} else {
@@ -3343,6 +3479,8 @@ void FileSystemDock::_file_list_gui_input(Ref<InputEvent> p_event) {
_file_list_rmb_option(FILE_RENAME);
} else if (ED_IS_SHORTCUT("filesystem_dock/show_in_explorer", p_event)) {
_file_list_rmb_option(FILE_SHOW_IN_EXPLORER);
+ } else if (ED_IS_SHORTCUT("filesystem_dock/open_in_terminal", p_event)) {
+ _file_list_rmb_option(FILE_OPEN_IN_TERMINAL);
} else if (ED_IS_SHORTCUT("editor/open_search", p_event)) {
focus_on_filter();
} else {
@@ -3547,6 +3685,7 @@ FileSystemDock::FileSystemDock() {
// Opening the system file manager or opening in an external program is not supported on the Android and web editors.
ED_SHORTCUT("filesystem_dock/show_in_explorer", TTR("Open in File Manager"));
ED_SHORTCUT("filesystem_dock/open_in_external_program", TTR("Open in External Program"));
+ ED_SHORTCUT("filesystem_dock/open_in_terminal", TTR("Open in Terminal"));
#endif
// Properly translating color names would require a separate HashMap, so for simplicity they are provided as comments.
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index f70afaa65e..d7203c15bd 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -121,6 +121,7 @@ private:
FILE_NEW,
FILE_SHOW_IN_EXPLORER,
FILE_OPEN_EXTERNAL,
+ FILE_OPEN_IN_TERMINAL,
FILE_COPY_PATH,
FILE_COPY_UID,
FOLDER_EXPAND_ALL,
diff --git a/editor/icons/Terminal.svg b/editor/icons/Terminal.svg
new file mode 100644
index 0000000000..5d92bdf8be
--- /dev/null
+++ b/editor/icons/Terminal.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#fff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2"><path d="m2 13 5.0000552-5-5.0000552-5"/><path d="m9 13h5"/></g></svg>
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index ef56e66e85..7242920368 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -117,11 +117,11 @@ void TileSetEditor::_load_texture_files(const Vector<String> &p_paths) {
// Actually create the new source.
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(texture);
+ atlas_source->set_texture_region_size(tile_set->get_tile_size());
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a new atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
- undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
undo_redo->commit_action();
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 586334a0b4..69d281e373 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -64,6 +64,8 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
grab.pos = orientation == VERTICAL ? mb->get_position().y : mb->get_position().x;
+ grab.value_before_dragging = get_as_ratio();
+ emit_signal(SNAME("drag_started"));
double grab_width = (double)grabber->get_width();
double grab_height = (double)grabber->get_height();
@@ -78,12 +80,11 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
grab.active = true;
grab.uvalue = get_as_ratio();
- emit_signal(SNAME("drag_started"));
_notify_shared_value_changed();
} else {
grab.active = false;
- const bool value_changed = !Math::is_equal_approx((double)grab.uvalue, get_as_ratio());
+ const bool value_changed = !Math::is_equal_approx((double)grab.value_before_dragging, get_as_ratio());
emit_signal(SNAME("drag_ended"), value_changed);
}
} else if (scrollable) {
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 05766fa742..07c1d23e32 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -38,7 +38,8 @@ class Slider : public Range {
struct Grab {
int pos = 0;
- double uvalue = 0.0;
+ double uvalue = 0.0; // Value at `pos`.
+ double value_before_dragging = 0.0;
bool active = false;
} grab;
diff --git a/servers/physics_2d/godot_area_pair_2d.cpp b/servers/physics_2d/godot_area_pair_2d.cpp
index bd1540bac8..ca12e30c29 100644
--- a/servers/physics_2d/godot_area_pair_2d.cpp
+++ b/servers/physics_2d/godot_area_pair_2d.cpp
@@ -66,6 +66,7 @@ bool GodotAreaPair2D::pre_solve(real_t p_step) {
if (colliding) {
if (has_space_override) {
+ body_has_attached_area = true;
body->add_area(area);
}
@@ -74,6 +75,7 @@ bool GodotAreaPair2D::pre_solve(real_t p_step) {
}
} else {
if (has_space_override) {
+ body_has_attached_area = false;
body->remove_area(area);
}
@@ -103,7 +105,8 @@ GodotAreaPair2D::GodotAreaPair2D(GodotBody2D *p_body, int p_body_shape, GodotAre
GodotAreaPair2D::~GodotAreaPair2D() {
if (colliding) {
- if (has_space_override) {
+ if (body_has_attached_area) {
+ body_has_attached_area = false;
body->remove_area(area);
}
if (area->has_monitor_callback()) {
diff --git a/servers/physics_2d/godot_area_pair_2d.h b/servers/physics_2d/godot_area_pair_2d.h
index 938b9813b4..eb091288a9 100644
--- a/servers/physics_2d/godot_area_pair_2d.h
+++ b/servers/physics_2d/godot_area_pair_2d.h
@@ -43,6 +43,7 @@ class GodotAreaPair2D : public GodotConstraint2D {
bool colliding = false;
bool has_space_override = false;
bool process_collision = false;
+ bool body_has_attached_area = false;
public:
virtual bool setup(real_t p_step) override;
diff --git a/servers/physics_2d/godot_shape_2d.cpp b/servers/physics_2d/godot_shape_2d.cpp
index dadd8173c6..2b3f496fc0 100644
--- a/servers/physics_2d/godot_shape_2d.cpp
+++ b/servers/physics_2d/godot_shape_2d.cpp
@@ -373,8 +373,7 @@ void GodotCapsuleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_suppo
if (h > 0 && Math::abs(n.x) > segment_is_valid_support_threshold) {
// make it flat
n.y = 0.0;
- n.normalize();
- n *= radius;
+ n.x = SIGN(n.x) * radius;
r_amount = 2;
r_supports[0] = n;
diff --git a/servers/physics_3d/godot_area_pair_3d.cpp b/servers/physics_3d/godot_area_pair_3d.cpp
index 5561210f2d..aaa96f5a28 100644
--- a/servers/physics_3d/godot_area_pair_3d.cpp
+++ b/servers/physics_3d/godot_area_pair_3d.cpp
@@ -67,6 +67,7 @@ bool GodotAreaPair3D::pre_solve(real_t p_step) {
if (colliding) {
if (has_space_override) {
+ body_has_attached_area = true;
body->add_area(area);
}
@@ -75,6 +76,7 @@ bool GodotAreaPair3D::pre_solve(real_t p_step) {
}
} else {
if (has_space_override) {
+ body_has_attached_area = false;
body->remove_area(area);
}
@@ -104,7 +106,8 @@ GodotAreaPair3D::GodotAreaPair3D(GodotBody3D *p_body, int p_body_shape, GodotAre
GodotAreaPair3D::~GodotAreaPair3D() {
if (colliding) {
- if (has_space_override) {
+ if (body_has_attached_area) {
+ body_has_attached_area = false;
body->remove_area(area);
}
if (area->has_monitor_callback()) {
@@ -242,6 +245,7 @@ bool GodotAreaSoftBodyPair3D::pre_solve(real_t p_step) {
if (colliding) {
if (has_space_override) {
+ body_has_attached_area = true;
soft_body->add_area(area);
}
@@ -250,6 +254,7 @@ bool GodotAreaSoftBodyPair3D::pre_solve(real_t p_step) {
}
} else {
if (has_space_override) {
+ body_has_attached_area = false;
soft_body->remove_area(area);
}
@@ -276,7 +281,8 @@ GodotAreaSoftBodyPair3D::GodotAreaSoftBodyPair3D(GodotSoftBody3D *p_soft_body, i
GodotAreaSoftBodyPair3D::~GodotAreaSoftBodyPair3D() {
if (colliding) {
- if (has_space_override) {
+ if (body_has_attached_area) {
+ body_has_attached_area = false;
soft_body->remove_area(area);
}
if (area->has_monitor_callback()) {
diff --git a/servers/physics_3d/godot_area_pair_3d.h b/servers/physics_3d/godot_area_pair_3d.h
index c11fa07827..a2c5df0f7a 100644
--- a/servers/physics_3d/godot_area_pair_3d.h
+++ b/servers/physics_3d/godot_area_pair_3d.h
@@ -44,6 +44,7 @@ class GodotAreaPair3D : public GodotConstraint3D {
bool colliding = false;
bool process_collision = false;
bool has_space_override = false;
+ bool body_has_attached_area = false;
public:
virtual bool setup(real_t p_step) override;
@@ -83,6 +84,7 @@ class GodotAreaSoftBodyPair3D : public GodotConstraint3D {
bool colliding = false;
bool process_collision = false;
bool has_space_override = false;
+ bool body_has_attached_area = false;
public:
virtual bool setup(real_t p_step) override;
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp
index 92bd3a043a..18863d4978 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.cpp
+++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp
@@ -533,7 +533,7 @@ void CopyEffects::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuff
RD::get_singleton()->draw_list_draw(draw_list, true);
}
-void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear) {
+void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y, bool p_force_luminance, bool p_alpha_to_zero, bool p_srgb, RID p_secondary, bool p_multiview, bool p_alpha_to_one, bool p_linear, bool p_normal) {
UniformSetCacheRD *uniform_set_cache = UniformSetCacheRD::get_singleton();
ERR_FAIL_NULL(uniform_set_cache);
MaterialStorage *material_storage = MaterialStorage::get_singleton();
@@ -564,6 +564,10 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe
copy_to_fb.push_constant.luminance_multiplier = prefer_raster_effects ? 2.0 : 1.0;
}
+ if (p_normal) {
+ copy_to_fb.push_constant.flags |= COPY_TO_FB_FLAG_NORMAL;
+ }
+
// setup our uniforms
RID default_sampler = material_storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
diff --git a/servers/rendering/renderer_rd/effects/copy_effects.h b/servers/rendering/renderer_rd/effects/copy_effects.h
index f9dcc42421..60272a2eab 100644
--- a/servers/rendering/renderer_rd/effects/copy_effects.h
+++ b/servers/rendering/renderer_rd/effects/copy_effects.h
@@ -190,6 +190,7 @@ private:
COPY_TO_FB_FLAG_SRGB = (1 << 4),
COPY_TO_FB_FLAG_ALPHA_TO_ONE = (1 << 5),
COPY_TO_FB_FLAG_LINEAR = (1 << 6),
+ COPY_TO_FB_FLAG_NORMAL = (1 << 7),
};
struct CopyToFbPushConstant {
@@ -328,7 +329,7 @@ public:
void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array);
void copy_depth_to_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false);
void copy_depth_to_rect_and_linearize(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y, float p_z_near, float p_z_far);
- void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false);
+ void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID(), bool p_multiview = false, bool alpha_to_one = false, bool p_linear = false, bool p_normal = false);
void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false);
void copy_to_drawlist(RD::DrawListID p_draw_list, RD::FramebufferFormatID p_fb_format, RID p_source_rd_texture, bool p_linear = false);
void copy_raster(RID p_source_texture, RID p_dest_framebuffer);
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 14995d0156..f3cde94149 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -961,13 +961,17 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con
inst->gi_offset_cache = 0xFFFFFFFF;
}
}
-
- if (p_pass_mode == PASS_MODE_COLOR && p_using_motion_pass) {
+ if (p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS || p_pass_mode == PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI || p_pass_mode == PASS_MODE_COLOR) {
bool transform_changed = inst->prev_transform_change_frame == frame;
bool has_mesh_instance = inst->mesh_instance.is_valid();
bool uses_particles = inst->base_flags & INSTANCE_DATA_FLAG_PARTICLES;
bool is_multimesh_with_motion = !uses_particles && (inst->base_flags & INSTANCE_DATA_FLAG_MULTIMESH) && mesh_storage->_multimesh_uses_motion_vectors_offsets(inst->data->base);
- uses_motion = transform_changed || has_mesh_instance || uses_particles || is_multimesh_with_motion;
+ bool is_dynamic = transform_changed || has_mesh_instance || uses_particles || is_multimesh_with_motion;
+ if (p_pass_mode == PASS_MODE_COLOR && p_using_motion_pass) {
+ uses_motion = is_dynamic;
+ } else if (is_dynamic) {
+ flags |= INSTANCE_DATA_FLAGS_DYNAMIC;
+ }
}
}
inst->flags_cache = flags;
@@ -1779,11 +1783,11 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: {
depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS);
- depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
+ depth_pass_clear.push_back(Color(0, 0, 0, 0));
} break;
case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: {
depth_framebuffer = rb_data->get_depth_fb(RenderBufferDataForwardClustered::DEPTH_FB_ROUGHNESS_VOXELGI);
- depth_pass_clear.push_back(Color(0.5, 0.5, 0.5, 0));
+ depth_pass_clear.push_back(Color(0, 0, 0, 0));
depth_pass_clear.push_back(Color(0, 0, 0, 0));
} break;
default: {
@@ -2980,6 +2984,14 @@ void RenderForwardClustered::_update_render_base_uniform_set() {
uniforms.push_back(u);
}
+ {
+ RD::Uniform u;
+ u.binding = 15;
+ u.uniform_type = RD::UNIFORM_TYPE_TEXTURE;
+ u.append_id(best_fit_normal.texture);
+ uniforms.push_back(u);
+ }
+
render_base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, scene_shader.default_shader_rd, SCENE_UNIFORM_SET);
}
}
@@ -4230,6 +4242,44 @@ RenderForwardClustered::RenderForwardClustered() {
shadow_sampler = RD::get_singleton()->sampler_create(sampler);
}
+ {
+ Vector<String> modes;
+ modes.push_back("\n");
+ best_fit_normal.shader.initialize(modes);
+ best_fit_normal.shader_version = best_fit_normal.shader.version_create();
+ best_fit_normal.pipeline = RD::get_singleton()->compute_pipeline_create(best_fit_normal.shader.version_get_shader(best_fit_normal.shader_version, 0));
+
+ RD::TextureFormat tformat;
+ tformat.format = RD::DATA_FORMAT_R8_UNORM;
+ tformat.width = 1024;
+ tformat.height = 1024;
+ tformat.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT;
+ tformat.texture_type = RD::TEXTURE_TYPE_2D;
+ best_fit_normal.texture = RD::get_singleton()->texture_create(tformat, RD::TextureView());
+
+ RID shader = best_fit_normal.shader.version_get_shader(best_fit_normal.shader_version, 0);
+ ERR_FAIL_COND(shader.is_null());
+
+ Vector<RD::Uniform> uniforms;
+
+ {
+ RD::Uniform u;
+ u.binding = 0;
+ u.uniform_type = RD::UNIFORM_TYPE_IMAGE;
+ u.append_id(best_fit_normal.texture);
+ uniforms.push_back(u);
+ }
+ RID uniform_set = RD::get_singleton()->uniform_set_create(uniforms, shader, 0);
+
+ RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin();
+ RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, best_fit_normal.pipeline);
+ RD::get_singleton()->compute_list_bind_uniform_set(compute_list, uniform_set, 0);
+ RD::get_singleton()->compute_list_dispatch_threads(compute_list, tformat.width, tformat.height, 1);
+ RD::get_singleton()->compute_list_end();
+
+ best_fit_normal.shader.version_free(best_fit_normal.shader_version);
+ }
+
render_list_thread_threshold = GLOBAL_GET("rendering/limits/forward_renderer/threaded_render_minimum_instances");
_update_shader_quality_settings();
@@ -4263,6 +4313,7 @@ RenderForwardClustered::~RenderForwardClustered() {
RD::get_singleton()->free(shadow_sampler);
RSG::light_storage->directional_shadow_atlas_set_size(0);
+ RD::get_singleton()->free(best_fit_normal.texture);
{
for (const RID &rid : scene_state.uniform_buffers) {
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 8119e6ff4d..5ff3d9f52a 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h
@@ -40,6 +40,7 @@
#include "servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h"
#include "servers/rendering/renderer_rd/pipeline_cache_rd.h"
#include "servers/rendering/renderer_rd/renderer_scene_render_rd.h"
+#include "servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl.gen.h"
#include "servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl.gen.h"
#include "servers/rendering/renderer_rd/storage_rd/utilities.h"
@@ -164,6 +165,13 @@ class RenderForwardClustered : public RendererSceneRenderRD {
RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture, const RendererRD::MaterialStorage::Samplers &p_samplers);
RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, const RendererRD::MaterialStorage::Samplers &p_samplers, bool p_use_directional_shadow_atlas = false, int p_index = 0);
+ struct BestFitNormal {
+ BestFitNormalShaderRD shader;
+ RID shader_version;
+ RID pipeline;
+ RID texture;
+ } best_fit_normal;
+
enum PassMode {
PASS_MODE_COLOR,
PASS_MODE_SHADOW,
@@ -236,6 +244,7 @@ class RenderForwardClustered : public RendererSceneRenderRD {
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
+ INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
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 3496495245..da96ca2124 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h
@@ -386,6 +386,7 @@ protected:
// When changing any of these enums, remember to change the corresponding enums in the shader files as well.
enum {
+ INSTANCE_DATA_FLAGS_DYNAMIC = 1 << 3,
INSTANCE_DATA_FLAGS_NON_UNIFORM_SCALE = 1 << 4,
INSTANCE_DATA_FLAG_USE_GI_BUFFERS = 1 << 5,
INSTANCE_DATA_FLAG_USE_SDFGI = 1 << 6,
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index d4ed640247..30c9b97aa4 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -773,7 +773,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(const RenderDataRD *p_ren
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_NORMAL_BUFFER && _render_buffers_get_normal_texture(rb).is_valid()) {
Size2 rtsize = texture_storage->render_target_get_size(render_target);
- copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false);
+ copy_effects->copy_to_fb_rect(_render_buffers_get_normal_texture(rb), texture_storage->render_target_get_rd_framebuffer(render_target), Rect2(Vector2(), rtsize), false, false, false, false, RID(), false, false, false, true);
}
if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_OCCLUDERS) {
diff --git a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl
index 6137224162..1b065a8dd3 100644
--- a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl
@@ -20,6 +20,7 @@
#define FLAG_SRGB (1 << 4)
#define FLAG_ALPHA_TO_ONE (1 << 5)
#define FLAG_LINEAR (1 << 6)
+#define FLAG_NORMAL (1 << 7)
#ifdef MULTIVIEW
layout(location = 0) out vec3 uv_interp;
@@ -77,6 +78,7 @@ void main() {
#define FLAG_SRGB (1 << 4)
#define FLAG_ALPHA_TO_ONE (1 << 5)
#define FLAG_LINEAR (1 << 6)
+#define FLAG_NORMAL (1 << 7)
layout(push_constant, std430) uniform Params {
vec4 section;
@@ -192,6 +194,9 @@ void main() {
if (bool(params.flags & FLAG_LINEAR)) {
color.rgb = srgb_to_linear(color.rgb);
}
+ if (bool(params.flags & FLAG_NORMAL)) {
+ color.rgb = normalize(color.rgb * 2.0 - 1.0) * 0.5 + 0.5;
+ }
frag_color = color / params.luminance_multiplier;
#endif // MODE_SET_COLOR
diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
index fecf70bd01..8618f083b3 100644
--- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection.glsl
@@ -65,8 +65,12 @@ void main() {
vec3 vertex = reconstructCSPosition(uv * vec2(params.screen_size), base_depth);
vec4 normal_roughness = imageLoad(source_normal_roughness, ssC);
- vec3 normal = normal_roughness.xyz * 2.0 - 1.0;
+ vec3 normal = normalize(normal_roughness.xyz * 2.0 - 1.0);
float roughness = normal_roughness.w;
+ if (roughness > 0.5) {
+ roughness = 1.0 - roughness;
+ }
+ roughness /= (127.0 / 255.0);
// The roughness cutoff of 0.6 is chosen to match the roughness fadeout from GH-69828.
if (roughness > 0.6) {
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 4df74b8626..51caa67d3c 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
@@ -59,8 +59,13 @@ void main() {
color += texelFetch(source_ssr, ofs, 0);
float d = texelFetch(source_depth, ofs, 0).r;
vec4 nr = texelFetch(source_normal, ofs, 0);
- normal.xyz += nr.xyz * 2.0 - 1.0;
- normal.w += nr.w;
+ normal.xyz += normalize(nr.xyz * 2.0 - 1.0);
+ float roughness = normal.w;
+ if (roughness > 0.5) {
+ roughness = 1.0 - roughness;
+ }
+ roughness /= (127.0 / 255.0);
+ normal.w += roughness;
if (sc_multiview) {
// we're doing a full unproject so we need the value as is.
@@ -81,6 +86,7 @@ void main() {
depth /= 4.0;
normal.xyz = normalize(normal.xyz / 4.0) * 0.5 + 0.5;
normal.w /= 4.0;
+ normal.w = normal.w * (127.0 / 255.0);
} else {
ivec2 ofs = ssC << 1;
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
index 58efc68bc7..8c50bb544d 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssao.glsl
@@ -158,21 +158,16 @@ vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p
return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0);
}
-vec3 decode_normal(vec3 p_encoded_normal) {
- vec3 normal = p_encoded_normal * 2.0 - 1.0;
- return normal;
-}
-
vec3 load_normal(ivec2 p_pos) {
- vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz;
- encoded_normal.z = 1.0 - encoded_normal.z;
- return decode_normal(encoded_normal);
+ vec3 encoded_normal = normalize(imageLoad(source_normal, p_pos).xyz * 2.0 - 1.0);
+ encoded_normal.z = -encoded_normal.z;
+ return encoded_normal;
}
vec3 load_normal(ivec2 p_pos, ivec2 p_offset) {
- vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz;
- encoded_normal.z = 1.0 - encoded_normal.z;
- return decode_normal(encoded_normal);
+ vec3 encoded_normal = normalize(imageLoad(source_normal, p_pos + p_offset).xyz * 2.0 - 1.0);
+ encoded_normal.z = -encoded_normal.z;
+ return encoded_normal;
}
// all vectors in viewspace
diff --git a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
index fac13b0e3f..0b623c1d4e 100644
--- a/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
+++ b/servers/rendering/renderer_rd/shaders/effects/ssil.glsl
@@ -159,21 +159,16 @@ vec4 calculate_edges(const float p_center_z, const float p_left_z, const float p
return clamp((1.3 - edgesLRTB / (p_center_z * 0.040)), 0.0, 1.0);
}
-vec3 decode_normal(vec3 p_encoded_normal) {
- vec3 normal = p_encoded_normal * 2.0 - 1.0;
- return normal;
-}
-
vec3 load_normal(ivec2 p_pos) {
- vec3 encoded_normal = imageLoad(source_normal, p_pos).xyz;
- encoded_normal.z = 1.0 - encoded_normal.z;
- return decode_normal(encoded_normal);
+ vec3 encoded_normal = normalize(imageLoad(source_normal, p_pos).xyz * 2.0 - 1.0);
+ encoded_normal.z = -encoded_normal.z;
+ return encoded_normal;
}
vec3 load_normal(ivec2 p_pos, ivec2 p_offset) {
- vec3 encoded_normal = imageLoad(source_normal, p_pos + p_offset).xyz;
- encoded_normal.z = 1.0 - encoded_normal.z;
- return decode_normal(encoded_normal);
+ vec3 encoded_normal = normalize(imageLoad(source_normal, p_pos + p_offset).xyz * 2.0 - 1.0);
+ encoded_normal.z = -encoded_normal.z;
+ return encoded_normal;
}
// all vectors in viewspace
diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
index 59af9501ba..80ed34cda1 100644
--- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl
@@ -618,6 +618,11 @@ void process_gi(ivec2 pos, vec3 vertex, inout vec4 ambient_light, inout vec4 ref
if (normal.length() > 0.5) {
//valid normal, can do GI
float roughness = normal_roughness.w;
+ bool dynamic_object = roughness > 0.5;
+ if (dynamic_object) {
+ roughness = 1.0 - roughness;
+ }
+ roughness /= (127.0 / 255.0);
vec3 view = -normalize(mat3(scene_data.cam_transform) * (vertex - scene_data.eye_offset[gl_GlobalInvocationID.z].xyz));
vertex = mat3(scene_data.cam_transform) * vertex;
normal = normalize(mat3(scene_data.cam_transform) * normal);
diff --git a/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl b/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl
index 577c6d0cd0..6e9e0f82b3 100644
--- a/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl
+++ b/servers/rendering/renderer_rd/shaders/environment/voxel_gi.glsl
@@ -492,7 +492,7 @@ void main() {
ivec3 pos = params.x_dir * (params.rect_pos.x + pos_xy.x) + params.y_dir * (params.rect_pos.y + pos_xy.y) + abs(params.z_dir) * int(z);
- vec3 normal = imageLoad(source_normal, uv_xy).xyz * 2.0 - 1.0;
+ vec3 normal = normalize(imageLoad(source_normal, uv_xy).xyz * 2.0 - 1.0);
normal = vec3(params.x_dir) * normal.x * mix(1.0, -1.0, params.flip_x) + vec3(params.y_dir) * normal.y * mix(1.0, -1.0, params.flip_y) - vec3(params.z_dir) * normal.z;
vec4 albedo = imageLoad(source_albedo, uv_xy);
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl
new file mode 100644
index 0000000000..8280d192e3
--- /dev/null
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/best_fit_normal.glsl
@@ -0,0 +1,43 @@
+#[compute]
+
+#version 450
+
+#VERSION_DEFINES
+
+layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in;
+
+layout(r8, set = 0, binding = 0) uniform restrict writeonly image2D current_image;
+
+// This shader is used to generate a "best fit normal texture" as described by:
+// https://advances.realtimerendering.com/s2010/Kaplanyan-CryEngine3(SIGGRAPH%202010%20Advanced%20RealTime%20Rendering%20Course).pdf
+// This texture tells you what length of normal can be used to store a unit vector
+// with the lest amount of error.
+
+vec3 quantize(vec3 c) {
+ return round(clamp(c * 0.5 + 0.5, 0.0, 1.0) * 255.0) * (1.0 / 255.0) * 2.0 - 1.0;
+}
+
+float find_minimum_error(vec3 normal) {
+ float min_error = 100000.0;
+ float t_best = 0.0;
+ for (float nstep = 1.5; nstep < 127.5; ++nstep) {
+ float t = nstep / 127.5;
+ vec3 vp = normal * t;
+ vec3 quantizedp = quantize(vp);
+ vec3 vdiff = (quantizedp - vp) / t;
+ float error = max(abs(vdiff.x), max(abs(vdiff.y), abs(vdiff.z)));
+ if (error < min_error) {
+ min_error = error;
+ t_best = t;
+ }
+ }
+ return t_best;
+}
+
+void main() {
+ vec2 uv = vec2(gl_GlobalInvocationID.xy) * vec2(1.0 / 1024.0) + vec2(0.5 / 1024.0);
+ uv.y *= uv.x;
+
+ vec3 dir = vec3(uv.x, uv.y, 1.0);
+ imageStore(current_image, ivec2(gl_GlobalInvocationID.xy), vec4(find_minimum_error(dir), 1.0, 1.0, 1.0));
+}
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 e17fa0ce90..930d981494 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
@@ -868,6 +868,28 @@ uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) {
#endif //!MODE_RENDER DEPTH
+#if defined(MODE_RENDER_NORMAL_ROUGHNESS) || defined(MODE_RENDER_MATERIAL)
+// https://advances.realtimerendering.com/s2010/Kaplanyan-CryEngine3(SIGGRAPH%202010%20Advanced%20RealTime%20Rendering%20Course).pdf
+vec3 encode24(vec3 v) {
+ // Unsigned normal (handles most symmetry)
+ vec3 vNormalUns = abs(v);
+ // Get the major axis for our collapsed cubemap lookup
+ float maxNAbs = max(vNormalUns.z, max(vNormalUns.x, vNormalUns.y));
+ // Get the collapsed cubemap texture coordinates
+ vec2 vTexCoord = vNormalUns.z < maxNAbs ? (vNormalUns.y < maxNAbs ? vNormalUns.yz : vNormalUns.xz) : vNormalUns.xy;
+ vTexCoord /= maxNAbs;
+ vTexCoord = vTexCoord.x < vTexCoord.y ? vTexCoord.yx : vTexCoord.xy;
+ // Stretch:
+ vTexCoord.y /= vTexCoord.x;
+ float fFittingScale = texture(sampler2D(best_fit_normal_texture, SAMPLER_NEAREST_CLAMP), vTexCoord).r;
+ // Make vector touch unit cube
+ vec3 result = v / maxNAbs;
+ // scale the normal to get the best fit
+ result *= fFittingScale;
+ return result;
+}
+#endif // MODE_RENDER_NORMAL_ROUGHNESS
+
void fragment_shader(in SceneData scene_data) {
uint instance_index = instance_index_interp;
@@ -1519,18 +1541,18 @@ void fragment_shader(in SceneData scene_data) {
vec2 base_coord = screen_uv;
vec2 closest_coord = base_coord;
#ifdef USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(base_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0));
#else // USE_MULTIVIEW
- float closest_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0);
+ float closest_ang = dot(normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), base_coord, 0.0).xyz * 2.0 - 1.0));
#endif // USE_MULTIVIEW
for (int i = 0; i < 4; i++) {
const vec2 neighbors[4] = vec2[](vec2(-1, 0), vec2(1, 0), vec2(0, -1), vec2(0, 1));
vec2 neighbour_coord = base_coord + neighbors[i] * scene_data.screen_pixel_size;
#ifdef USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, normalize(textureLod(sampler2DArray(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), vec3(neighbour_coord, ViewIndex), 0.0).xyz * 2.0 - 1.0));
#else // USE_MULTIVIEW
- float neighbour_ang = dot(normal, textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0);
+ float neighbour_ang = dot(normal, normalize(textureLod(sampler2D(normal_roughness_buffer, SAMPLER_LINEAR_CLAMP), neighbour_coord, 0.0).xyz * 2.0 - 1.0));
#endif // USE_MULTIVIEW
if (neighbour_ang > closest_ang) {
closest_ang = neighbour_ang;
@@ -2302,7 +2324,7 @@ void fragment_shader(in SceneData scene_data) {
albedo_output_buffer.rgb = albedo;
albedo_output_buffer.a = alpha;
- normal_output_buffer.rgb = normal * 0.5 + 0.5;
+ normal_output_buffer.rgb = encode24(normal) * 0.5 + 0.5;
normal_output_buffer.a = 0.0;
depth_output_buffer.r = -vertex.z;
@@ -2316,7 +2338,15 @@ void fragment_shader(in SceneData scene_data) {
#endif
#ifdef MODE_RENDER_NORMAL_ROUGHNESS
- normal_roughness_output_buffer = vec4(normal * 0.5 + 0.5, roughness);
+ normal_roughness_output_buffer = vec4(encode24(normal) * 0.5 + 0.5, roughness);
+
+ // We encode the dynamic static into roughness.
+ // Values over 0.5 are dynamic, under 0.5 are static.
+ normal_roughness_output_buffer.w = normal_roughness_output_buffer.w * (127.0 / 255.0);
+ if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_DYNAMIC)) {
+ normal_roughness_output_buffer.w = 1.0 - normal_roughness_output_buffer.w;
+ }
+ normal_roughness_output_buffer.w = normal_roughness_output_buffer.w;
#ifdef MODE_RENDER_VOXEL_GI
if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_VOXEL_GI)) { // process voxel_gi_instances
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
index 5cde975f94..441cf3c80c 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered_inc.glsl
@@ -48,6 +48,7 @@ draw_call;
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+#define INSTANCE_FLAGS_DYNAMIC (1 << 3)
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 6)
@@ -163,6 +164,8 @@ sdfgi;
layout(set = 0, binding = 14) uniform sampler DEFAULT_SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP;
+layout(set = 0, binding = 15) uniform texture2D best_fit_normal_texture;
+
/* Set 1: Render Pass (changes per render pass) */
layout(set = 1, binding = 0, std140) uniform SceneDataBlock {
@@ -328,6 +331,15 @@ layout(set = 1, binding = 34) uniform texture2D ssil_buffer;
#endif
+vec4 normal_roughness_compatibility(vec4 p_normal_roughness) {
+ float roughness = p_normal_roughness.w;
+ if (roughness > 0.5) {
+ roughness = 1.0 - roughness;
+ }
+ roughness /= (127.0 / 255.0);
+ return vec4(normalize(p_normal_roughness.xyz * 2.0 - 1.0) * 0.5 + 0.5, roughness);
+}
+
/* Set 2 Skeleton & Instancing (can change per item) */
layout(set = 2, binding = 0, std430) restrict readonly buffer Transforms {
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
index cc3e5f6a14..7674e905e1 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile_inc.glsl
@@ -29,6 +29,7 @@ draw_call;
layout(set = 0, binding = 2) uniform sampler shadow_sampler;
+#define INSTANCE_FLAGS_DYNAMIC (1 << 3)
#define INSTANCE_FLAGS_NON_UNIFORM_SCALE (1 << 4)
#define INSTANCE_FLAGS_USE_GI_BUFFERS (1 << 5)
#define INSTANCE_FLAGS_USE_SDFGI (1 << 6)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 1e95cdde0c..880c13096e 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -1191,6 +1191,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
// we will add logic to automatically switch between
// sampler2D and sampler2D array and vec2 UV and vec3 UV.
bool multiview_uv_needed = false;
+ bool is_normal_roughness_texture = false;
for (int i = 1; i < onode->arguments.size(); i++) {
if (i > 1) {
@@ -1259,7 +1260,6 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
// Need to map from texture to sampler in order to sample when using Vulkan GLSL.
String sampler_name;
bool is_depth_texture = false;
- bool is_normal_roughness_texture = false;
if (actions.custom_samplers.has(texture_uniform)) {
sampler_name = actions.custom_samplers[texture_uniform];
@@ -1340,6 +1340,9 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (is_screen_texture && !texture_func_returns_data && actions.apply_luminance_multiplier) {
code = "(" + code + " * vec4(vec3(sc_luminance_multiplier), 1.0))";
}
+ if (is_normal_roughness_texture) {
+ code = "normal_roughness_compatibility(" + code + ")";
+ }
} break;
case SL::OP_INDEX: {
code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);