diff options
33 files changed, 546 insertions, 84 deletions
diff --git a/core/math/camera_matrix.cpp b/core/math/camera_matrix.cpp index c4981b954b..c36070e47f 100644 --- a/core/math/camera_matrix.cpp +++ b/core/math/camera_matrix.cpp @@ -145,7 +145,7 @@ void CameraMatrix::set_for_hmd(int p_eye, real_t p_aspect, real_t p_intraocular_ f3 *= p_oversample; // always apply KEEP_WIDTH aspect ratio - f3 *= p_aspect; + f3 /= p_aspect; switch (p_eye) { case 1: { // left eye diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 6de82e602b..93402dcb20 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -426,6 +426,9 @@ <member name="display/window/ios/hide_home_indicator" type="bool" setter="" getter="" default="true"> If [code]true[/code], the home indicator is hidden automatically. This only affects iOS devices without a physical home button. </member> + <member name="display/window/subwindows/embed_subwindows" type="bool" setter="" getter="" default="false"> + If [code]true[/code], uses subwindows (windows rendered entirely by engine) instead of OS-specific windows. + </member> <member name="display/window/size/always_on_top" type="bool" setter="" getter="" default="false"> Force the window to be always on top. </member> diff --git a/doc/classes/SubViewport.xml b/doc/classes/SubViewport.xml index 561e5d1a15..dc3d748496 100644 --- a/doc/classes/SubViewport.xml +++ b/doc/classes/SubViewport.xml @@ -7,45 +7,51 @@ <tutorials> </tutorials> <methods> - <method name="get_size" qualifiers="const"> - <return type="Vector2i"> - </return> - <description> - </description> - </method> - <method name="set_size"> - <return type="void"> - </return> - <argument index="0" name="size" type="Vector2i"> - </argument> - <description> - </description> - </method> </methods> <members> <member name="arvr" type="bool" setter="set_use_arvr" getter="is_using_arvr" default="false"> + If [code]true[/code], the sub-viewport will be used in AR/VR process. </member> <member name="render_target_clear_mode" type="int" setter="set_clear_mode" getter="get_clear_mode" enum="SubViewport.ClearMode" default="0"> + The clear mode when the sub-viewport is used as a render target. </member> <member name="render_target_update_mode" type="int" setter="set_update_mode" getter="get_update_mode" enum="SubViewport.UpdateMode" default="2"> + The update mode when the sub-viewport is used as a render target. + </member> + <member name="size" type="Vector2i" setter="set_size" getter="get_size" default="Vector2i( 0, 0 )"> + The width and height of the sub-viewport. + </member> + <member name="size_2d_override" type="Vector2i" setter="set_size_2d_override" getter="get_size_2d_override" default="Vector2i( 0, 0 )"> + The 2D size override of the sub-viewport. If either the width or height is [code]0[/code], the override is disabled. + </member> + <member name="size_2d_override_stretch" type="bool" setter="set_size_2d_override_stretch" getter="is_size_2d_override_stretch_enabled" default="false"> + If [code]true[/code], the 2D size override affects stretch as well. </member> </members> <constants> <constant name="UPDATE_DISABLED" value="0" enum="UpdateMode"> + Do not update the render target. </constant> <constant name="UPDATE_ONCE" value="1" enum="UpdateMode"> + Update the render target once, then switch to [constant UPDATE_DISABLED]. </constant> <constant name="UPDATE_WHEN_VISIBLE" value="2" enum="UpdateMode"> + Update the render target only when it is visible. This is the default value. </constant> <constant name="UPDATE_WHEN_PARENT_VISIBLE" value="3" enum="UpdateMode"> + Update the render target only when the its parent is visible. </constant> <constant name="UPDATE_ALWAYS" value="4" enum="UpdateMode"> + Always update the render target. </constant> <constant name="CLEAR_MODE_ALWAYS" value="0" enum="ClearMode"> + Always clear the render target before drawing. </constant> <constant name="CLEAR_MODE_NEVER" value="1" enum="ClearMode"> + Never clear the render target. </constant> <constant name="CLEAR_MODE_ONLY_NEXT_FRAME" value="2" enum="ClearMode"> + Clear the render target next frame, then switch to [constant CLEAR_MODE_NEVER]. </constant> </constants> </class> diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 205d5f2944..e7c1eaf777 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -369,6 +369,11 @@ void EditorNode::_notification(int p_what) { RS::get_singleton()->environment_glow_set_use_bicubic_upscale(glow_bicubic); RS::EnvironmentSSRRoughnessQuality ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); RS::get_singleton()->environment_set_ssr_roughness_quality(ssr_roughness_quality); + RS::SubSurfaceScatteringQuality sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality"))); + RS::get_singleton()->sub_surface_scattering_set_quality(sss_quality); + float sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); + float sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale"); + RS::get_singleton()->sub_surface_scattering_set_scale(sss_scale, sss_depth_scale); } ResourceImporterTexture::get_singleton()->update_imports(); @@ -3973,8 +3978,9 @@ void EditorNode::_dock_make_float() { Control *dock = dock_slot[dock_popup_selected]->get_current_tab_control(); ERR_FAIL_COND(!dock); - Size2 dock_size = dock->get_size(); //remember size - Point2 dock_screen_pos = dock->get_global_position() + get_tree()->get_root()->get_position(); + const Size2i borders = Size2i(4, 4) * EDSCALE; + Size2 dock_size = dock->get_size() + borders * 2; //remember size + Point2 dock_screen_pos = dock->get_global_position() + get_tree()->get_root()->get_position() - borders; print_line("dock pos: " + dock->get_global_position() + " window pos: " + get_tree()->get_root()->get_position()); int dock_index = dock->get_index(); @@ -3988,10 +3994,10 @@ void EditorNode::_dock_make_float() { window->add_child(p); MarginContainer *margin = memnew(MarginContainer); margin->set_anchors_and_margins_preset(Control::PRESET_WIDE); - margin->add_theme_constant_override("margin_right", 4 * EDSCALE); - margin->add_theme_constant_override("margin_top", 4 * EDSCALE); - margin->add_theme_constant_override("margin_left", 4 * EDSCALE); - margin->add_theme_constant_override("margin_bottom", 4 * EDSCALE); + margin->add_theme_constant_override("margin_right", borders.width); + margin->add_theme_constant_override("margin_top", borders.height); + margin->add_theme_constant_override("margin_left", borders.width); + margin->add_theme_constant_override("margin_bottom", borders.height); window->add_child(margin); dock->set_anchors_and_margins_preset(Control::PRESET_WIDE); margin->add_child(dock); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 7ce6e3edb8..5d5bb1242d 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -341,6 +341,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::FLOAT, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); + _initial_set("interface/editor/single_window_mode", false); + hints["interface/editor/single_window_mode"] = PropertyInfo(Variant::BOOL, "interface/editor/single_window_mode", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/hide_console_window", false); _initial_set("interface/editor/save_each_scene_on_quit", true); // Regression _initial_set("interface/editor/quit_confirmation", true); diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 663068b2b5..a9af29ddf2 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -997,6 +997,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // LinkButton theme->set_stylebox("focus", "LinkButton", style_empty); theme->set_color("font_color", "LinkButton", font_color); + theme->set_color("font_color_hover", "LinkButton", font_color_hl); + theme->set_color("font_color_pressed", "LinkButton", accent_color); + theme->set_color("font_color_disabled", "LinkButton", font_color_disabled); // TooltipPanel Ref<StyleBoxFlat> style_tooltip = style_popup->duplicate(); diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 23be42aaea..22f6aedeaa 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -450,8 +450,8 @@ void ImportDock::_reimport() { String importer_name = params->importer->get_importer_name(); - if (params->checking) { - //update only what edited (checkboxes) + if (params->checking && config->get_value("remap", "importer") == params->importer->get_importer_name()) { + //update only what is edited (checkboxes) if the importer is the same for (List<PropertyInfo>::Element *E = params->properties.front(); E; E = E->next()) { if (params->checked.has(E->get().name)) { config->set_value("params", E->get().name, params->values[E->get().name]); @@ -558,7 +558,7 @@ ImportDock::ImportDock() { hb->add_spacer(); reimport_confirm = memnew(ConfirmationDialog); - reimport_confirm->get_ok()->set_text(TTR("Save scenes, re-import and restart")); + reimport_confirm->get_ok()->set_text(TTR("Save Scenes, Re-Import, and Restart")); add_child(reimport_confirm); reimport_confirm->connect("confirmed", callable_mp(this, &ImportDock::_reimport_and_restart)); diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index 9267c0df5c..c06f62a8c1 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -1362,7 +1362,6 @@ AnimationNodeStateMachineEditor::AnimationNodeStateMachineEditor() { name_edit = memnew(LineEdit); name_edit_popup->add_child(name_edit); name_edit->set_anchors_and_margins_preset(PRESET_WIDE); - name_edit_popup->add_child(name_edit); name_edit->connect("text_entered", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited)); name_edit->connect("focus_exited", callable_mp(this, &AnimationNodeStateMachineEditor::_name_edited_focus_out)); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index b30cd89c96..04ec5ae043 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -1205,12 +1205,9 @@ ProjectExportDialog::ProjectExportDialog() { custom_features = memnew(LineEdit); custom_features->connect("text_changed", callable_mp(this, &ProjectExportDialog::_custom_features_changed)); feature_vb->add_margin_child(TTR("Custom (comma-separated):"), custom_features); - Panel *features_panel = memnew(Panel); custom_feature_display = memnew(RichTextLabel); - features_panel->add_child(custom_feature_display); - custom_feature_display->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 10 * EDSCALE); custom_feature_display->set_v_size_flags(Control::SIZE_EXPAND_FILL); - feature_vb->add_margin_child(TTR("Feature List:"), features_panel, true); + feature_vb->add_margin_child(TTR("Feature List:"), custom_feature_display, true); sections->add_child(feature_vb); // Script export parameters. diff --git a/main/main.cpp b/main/main.cpp index 2a525dbe5a..a53e52e485 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1723,7 +1723,9 @@ bool Main::start() { } #endif - if (single_window) { + bool embed_subwindows = GLOBAL_DEF("display/window/subwindows/embed_subwindows", false); + + if (single_window || (!project_manager && !editor && embed_subwindows)) { sml->get_root()->set_embed_subwindows_hint(true); } ResourceLoader::add_custom_loaders(); @@ -1942,6 +1944,12 @@ bool Main::start() { #ifdef TOOLS_ENABLED if (editor) { + bool editor_embed_subwindows = EditorSettings::get_singleton()->get_setting("interface/editor/single_window_mode"); + + if (editor_embed_subwindows) { + sml->get_root()->set_embed_subwindows_hint(true); + } + if (game_path != GLOBAL_GET("application/run/main_scene") || !editor_node->has_scenes_in_session()) { Error serr = editor_node->load_scene(local_game_path); if (serr != OK) diff --git a/methods.py b/methods.py index 89a229e4ab..805ae256c3 100644 --- a/methods.py +++ b/methods.py @@ -598,7 +598,11 @@ def detect_darwin_sdk_path(platform, env): def is_vanilla_clang(env): if not using_clang(env): return False - version = subprocess.check_output([env["CXX"], "--version"]).strip().decode("utf-8") + try: + version = subprocess.check_output([env.subst(env["CXX"]), "--version"]).strip().decode("utf-8") + except (subprocess.CalledProcessError, OSError): + print("Couldn't parse CXX environment variable to infer compiler version.") + return False return not version.startswith("Apple") diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp index 6be74d8d29..905af399b3 100644 --- a/scene/gui/file_dialog.cpp +++ b/scene/gui/file_dialog.cpp @@ -46,9 +46,9 @@ VBoxContainer *FileDialog::get_vbox() { void FileDialog::_theme_changed() { - Color font_color = vbc->get_theme_color("font_color", "ToolButton"); - Color font_color_hover = vbc->get_theme_color("font_color_hover", "ToolButton"); - Color font_color_pressed = vbc->get_theme_color("font_color_pressed", "ToolButton"); + Color font_color = vbox->get_theme_color("font_color", "ToolButton"); + Color font_color_hover = vbox->get_theme_color("font_color_hover", "ToolButton"); + Color font_color_pressed = vbox->get_theme_color("font_color_pressed", "ToolButton"); dir_up->add_theme_color_override("icon_color_normal", font_color); dir_up->add_theme_color_override("icon_color_hover", font_color_hover); @@ -73,9 +73,9 @@ void FileDialog::_notification(int p_what) { } if (p_what == NOTIFICATION_ENTER_TREE) { - dir_up->set_icon(vbc->get_theme_icon("parent_folder")); - refresh->set_icon(vbc->get_theme_icon("reload")); - show_hidden->set_icon(vbc->get_theme_icon("toggle_hidden")); + dir_up->set_icon(vbox->get_theme_icon("parent_folder", "FileDialog")); + refresh->set_icon(vbox->get_theme_icon("reload", "FileDialog")); + show_hidden->set_icon(vbox->get_theme_icon("toggle_hidden", "FileDialog")); _theme_changed(); } } @@ -429,8 +429,8 @@ void FileDialog::update_file_list() { dir_access->list_dir_begin(); TreeItem *root = tree->create_item(); - Ref<Texture2D> folder = vbc->get_theme_icon("folder"); - const Color folder_color = vbc->get_theme_color("folder_icon_modulate"); + Ref<Texture2D> folder = vbox->get_theme_icon("folder", "FileDialog"); + const Color folder_color = vbox->get_theme_color("folder_icon_modulate", "FileDialog"); List<String> files; List<String> dirs; @@ -528,7 +528,7 @@ void FileDialog::update_file_list() { } if (mode == FILE_MODE_OPEN_DIR) { - ti->set_custom_color(0, vbc->get_theme_color("files_disabled")); + ti->set_custom_color(0, vbox->get_theme_color("files_disabled", "FileDialog")); ti->set_selectable(0, false); } Dictionary d; @@ -888,9 +888,9 @@ FileDialog::FileDialog() { mode_overrides_title = true; - vbc = memnew(VBoxContainer); - add_child(vbc); - vbc->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); + vbox = memnew(VBoxContainer); + add_child(vbox); + vbox->connect("theme_changed", callable_mp(this, &FileDialog::_theme_changed)); mode = FILE_MODE_SAVE_FILE; set_title(RTR("Save a File")); @@ -933,11 +933,11 @@ FileDialog::FileDialog() { makedir->set_text(RTR("Create Folder")); makedir->connect("pressed", callable_mp(this, &FileDialog::_make_dir)); hbc->add_child(makedir); - vbc->add_child(hbc); + vbox->add_child(hbc); tree = memnew(Tree); tree->set_hide_root(true); - vbc->add_margin_child(RTR("Directories & Files:"), tree, true); + vbox->add_margin_child(RTR("Directories & Files:"), tree, true); file_box = memnew(HBoxContainer); file_box->add_child(memnew(Label(RTR("File:")))); @@ -950,7 +950,7 @@ FileDialog::FileDialog() { filter->set_h_size_flags(Control::SIZE_EXPAND_FILL); filter->set_clip_text(true); // too many extensions overflows it file_box->add_child(filter); - vbc->add_child(file_box); + vbox->add_child(file_box); dir_access = DirAccess::create(DirAccess::ACCESS_RESOURCES); access = ACCESS_RESOURCES; @@ -993,7 +993,6 @@ FileDialog::FileDialog() { update_dir(); set_hide_on_ok(false); - vbox = vbc; invalidated = true; if (register_func) diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h index 295ae023d1..6faf02d55d 100644 --- a/scene/gui/file_dialog.h +++ b/scene/gui/file_dialog.h @@ -70,7 +70,6 @@ private: ConfirmationDialog *makedialog; LineEdit *makedirname; - VBoxContainer *vbc; Button *makedir; Access access; //Button *action; diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp index 5fb2243aff..3ab5e5427d 100644 --- a/scene/gui/rich_text_label.cpp +++ b/scene/gui/rich_text_label.cpp @@ -582,13 +582,14 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int & } else { cw = drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], fx_color); } - } else if (previously_visible) { + } else if (previously_visible && c[i] != '\t') { backtrack += font->get_char_size(fx_char, c[i + 1]).x; } p_char_count++; if (c[i] == '\t') { cw = tab_size * font->get_char_size(' ').width; + backtrack = MAX(0, backtrack - cw); } ofs += cw; diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp index 5fcd4bf009..06d6e81786 100644 --- a/scene/main/viewport.cpp +++ b/scene/main/viewport.cpp @@ -879,13 +879,14 @@ void Viewport::update_canvas_items() { _update_canvas_items(this); } -void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) { +void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated) { - if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_override == size_override && to_screen_rect != p_to_screen_rect) + if (size == p_size && size_allocated == p_allocated && stretch_transform == p_stretch_transform && p_size_2d_override == size_2d_override && to_screen_rect != p_to_screen_rect) return; + size = p_size; size_allocated = p_allocated; - size_override = p_size_override; + size_2d_override = p_size_2d_override; stretch_transform = p_stretch_transform; to_screen_rect = p_to_screen_rect; @@ -904,6 +905,9 @@ void Viewport::_set_size(const Size2i &p_size, const Size2i &p_size_override, co Size2i Viewport::_get_size() const { return size; } +Size2i Viewport::_get_size_2d_override() const { + return size_2d_override; +} bool Viewport::_is_size_allocated() const { return size_allocated; } @@ -918,8 +922,8 @@ Rect2 Viewport::get_visible_rect() const { r = Rect2(Point2(), size); } - if (size_override != Size2i()) { - r.size = size_override; + if (size_2d_override != Size2i()) { + r.size = size_2d_override; } return r; @@ -3614,18 +3618,40 @@ void SubViewport::set_use_arvr(bool p_use_arvr) { RS::get_singleton()->viewport_set_use_arvr(get_viewport_rid(), arvr); } - bool SubViewport::is_using_arvr() { return arvr; } void SubViewport::set_size(const Size2i &p_size) { - _set_size(p_size, Size2i(), Rect2i(), Transform2D(), true); + _set_size(p_size, _get_size_2d_override(), Rect2i(), _stretch_transform(), true); } Size2i SubViewport::get_size() const { return _get_size(); } +void SubViewport::set_size_2d_override(const Size2i &p_size) { + + _set_size(_get_size(), p_size, Rect2i(), _stretch_transform(), true); +} +Size2i SubViewport::get_size_2d_override() const { + + return _get_size_2d_override(); +} + +void SubViewport::set_size_2d_override_stretch(bool p_enable) { + + if (p_enable == size_2d_override_stretch) { + return; + } + + size_2d_override_stretch = p_enable; + _set_size(_get_size(), _get_size_2d_override(), Rect2i(), _stretch_transform(), true); +} +bool SubViewport::is_size_2d_override_stretch_enabled() const { + + return size_2d_override_stretch; +} + void SubViewport::set_update_mode(UpdateMode p_mode) { update_mode = p_mode; @@ -3641,7 +3667,6 @@ void SubViewport::set_clear_mode(ClearMode p_mode) { clear_mode = p_mode; RS::get_singleton()->viewport_set_clear_mode(get_viewport_rid(), RS::ViewportClearMode(p_mode)); } - SubViewport::ClearMode SubViewport::get_clear_mode() const { return clear_mode; @@ -3651,6 +3676,18 @@ DisplayServer::WindowID SubViewport::get_window_id() const { return DisplayServer::INVALID_WINDOW_ID; } +Transform2D SubViewport::_stretch_transform() { + + Transform2D transform = Transform2D(); + Size2i view_size_2d_override = _get_size_2d_override(); + if (size_2d_override_stretch && view_size_2d_override.width > 0 && view_size_2d_override.height > 0) { + Size2 scale = _get_size() / view_size_2d_override; + transform.scale(scale); + } + + return transform; +} + void SubViewport::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { @@ -3668,6 +3705,12 @@ void SubViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("set_size", "size"), &SubViewport::set_size); ClassDB::bind_method(D_METHOD("get_size"), &SubViewport::get_size); + ClassDB::bind_method(D_METHOD("set_size_2d_override", "size"), &SubViewport::set_size_2d_override); + ClassDB::bind_method(D_METHOD("get_size_2d_override"), &SubViewport::get_size_2d_override); + + ClassDB::bind_method(D_METHOD("set_size_2d_override_stretch", "enable"), &SubViewport::set_size_2d_override_stretch); + ClassDB::bind_method(D_METHOD("is_size_2d_override_stretch_enabled"), &SubViewport::is_size_2d_override_stretch_enabled); + ClassDB::bind_method(D_METHOD("set_update_mode", "mode"), &SubViewport::set_update_mode); ClassDB::bind_method(D_METHOD("get_update_mode"), &SubViewport::get_update_mode); @@ -3675,6 +3718,9 @@ void SubViewport::_bind_methods() { ClassDB::bind_method(D_METHOD("get_clear_mode"), &SubViewport::get_clear_mode); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "arvr"), "set_use_arvr", "is_using_arvr"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size_2d_override"), "set_size_2d_override", "get_size_2d_override"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "size_2d_override_stretch"), "set_size_2d_override_stretch", "is_size_2d_override_stretch_enabled"); ADD_GROUP("Render Target", "render_target_"); ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_clear_mode", PROPERTY_HINT_ENUM, "Always,Never,Next Frame"), "set_clear_mode", "get_clear_mode"); ADD_PROPERTY(PropertyInfo(Variant::INT, "render_target_update_mode", PROPERTY_HINT_ENUM, "Disabled,Once,When Visible,Always"), "set_update_mode", "get_update_mode"); @@ -3692,6 +3738,7 @@ void SubViewport::_bind_methods() { SubViewport::SubViewport() { arvr = false; + size_2d_override_stretch = false; update_mode = UPDATE_WHEN_VISIBLE; clear_mode = CLEAR_MODE_ALWAYS; } diff --git a/scene/main/viewport.h b/scene/main/viewport.h index 8982869783..d603294ed5 100644 --- a/scene/main/viewport.h +++ b/scene/main/viewport.h @@ -203,7 +203,7 @@ private: Transform2D stretch_transform; Size2i size; - Size2i size_override; + Size2i size_2d_override; bool size_allocated; RID contact_2d_debug; @@ -434,9 +434,10 @@ private: SubWindowResize _sub_window_get_resize_margin(Window *p_subwindow, const Point2 &p_point); protected: - void _set_size(const Size2i &p_size, const Size2i &p_size_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated); + void _set_size(const Size2i &p_size, const Size2i &p_size_2d_override, const Rect2i &p_to_screen_rect, const Transform2D &p_stretch_transform, bool p_allocated); Size2i _get_size() const; + Size2i _get_size_2d_override() const; bool _is_size_allocated() const; void _notification(int p_what); @@ -589,19 +590,27 @@ private: UpdateMode update_mode; ClearMode clear_mode; bool arvr; + bool size_2d_override_stretch; protected: static void _bind_methods(); virtual DisplayServer::WindowID get_window_id() const; + Transform2D _stretch_transform(); void _notification(int p_what); public: void set_size(const Size2i &p_size); Size2i get_size() const; + void set_size_2d_override(const Size2i &p_size); + Size2i get_size_2d_override() const; + void set_use_arvr(bool p_use_arvr); bool is_using_arvr(); + void set_size_2d_override_stretch(bool p_enable); + bool is_size_2d_override_stretch_enabled() const; + void set_update_mode(UpdateMode p_mode); UpdateMode get_update_mode() const; diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp index 84c1c9d734..85adc8c5f1 100644 --- a/scene/resources/material.cpp +++ b/scene/resources/material.cpp @@ -444,6 +444,9 @@ void BaseMaterial3D::_update_shader() { case DEPTH_DRAW_DISABLED: code += ",depth_draw_never"; break; } + if (features[FEATURE_SUBSURACE_SCATTERING] && flags[FLAG_SUBSURFACE_MODE_SKIN]) { + code += ",sss_mode_skin"; + } if (transparency == TRANSPARENCY_ALPHA_DEPTH_PRE_PASS) { code += ",depth_prepass_alpha"; } @@ -2284,6 +2287,7 @@ void BaseMaterial3D::_bind_methods() { ADD_GROUP("Subsurf Scatter", "subsurf_scatter_"); ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_enabled"), "set_feature", "get_feature", FEATURE_SUBSURACE_SCATTERING); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "subsurf_scatter_strength", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_subsurface_scattering_strength", "get_subsurface_scattering_strength"); + ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "subsurf_scatter_skin_mode"), "set_flag", "get_flag", FLAG_SUBSURFACE_MODE_SKIN); ADD_PROPERTYI(PropertyInfo(Variant::OBJECT, "subsurf_scatter_texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture", TEXTURE_SUBSURFACE_SCATTERING); ADD_GROUP("Transmission", "transmission_"); @@ -2436,6 +2440,7 @@ void BaseMaterial3D::_bind_methods() { BIND_ENUM_CONSTANT(FLAG_USE_SHADOW_TO_OPACITY); BIND_ENUM_CONSTANT(FLAG_USE_TEXTURE_REPEAT); BIND_ENUM_CONSTANT(FLAG_INVERT_HEIGHTMAP); + BIND_ENUM_CONSTANT(FLAG_SUBSURFACE_MODE_SKIN); BIND_ENUM_CONSTANT(FLAG_MAX); BIND_ENUM_CONSTANT(DIFFUSE_BURLEY); diff --git a/scene/resources/material.h b/scene/resources/material.h index 0c9352baf4..57f9038bf5 100644 --- a/scene/resources/material.h +++ b/scene/resources/material.h @@ -218,6 +218,7 @@ public: FLAG_USE_SHADOW_TO_OPACITY, FLAG_USE_TEXTURE_REPEAT, FLAG_INVERT_HEIGHTMAP, + FLAG_SUBSURFACE_MODE_SKIN, FLAG_MAX }; diff --git a/servers/rendering/rasterizer.h b/servers/rendering/rasterizer.h index 6676b00723..d77963b3dd 100644 --- a/servers/rendering/rasterizer.h +++ b/servers/rendering/rasterizer.h @@ -266,6 +266,9 @@ public: virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0; virtual bool screen_space_roughness_limiter_is_active() const = 0; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + virtual bool free(RID p_rid) = 0; virtual void update() = 0; diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp index 3b22cb4d9d..2d881dbd37 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.cpp @@ -461,6 +461,53 @@ void RasterizerEffectsRD::screen_space_reflection(RID p_diffuse, RID p_normal, R RD::get_singleton()->compute_list_end(); } +void RasterizerEffectsRD::sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RenderingServer::SubSurfaceScatteringQuality p_quality) { + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + + int32_t x_groups = (p_screen_size.width - 1) / 8 + 1; + int32_t y_groups = (p_screen_size.height - 1) / 8 + 1; + + Plane p = p_camera.xform4(Plane(1, 0, -1, 1)); + p.normal /= p.d; + float unit_size = p.normal.x; + + { //scale color and depth to half + sss.push_constant.camera_z_far = p_camera.get_z_far(); + sss.push_constant.camera_z_near = p_camera.get_z_near(); + sss.push_constant.orthogonal = p_camera.is_orthogonal(); + sss.push_constant.unit_size = unit_size; + sss.push_constant.screen_size[0] = p_screen_size.x; + sss.push_constant.screen_size[1] = p_screen_size.y; + sss.push_constant.vertical = false; + sss.push_constant.scale = p_scale; + sss.push_constant.depth_scale = p_depth_scale; + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, sss.pipelines[p_quality - 1]); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse2), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + + RD::get_singleton()->compute_list_add_barrier(compute_list); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_diffuse2), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_diffuse), 1); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_depth), 2); + + sss.push_constant.vertical = true; + RD::get_singleton()->compute_list_set_push_constant(compute_list, &sss.push_constant, sizeof(SubSurfaceScatteringPushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, x_groups, y_groups, 1); + + RD::get_singleton()->compute_list_end(); + } +} + void RasterizerEffectsRD::merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection) { RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_DISCARD, Vector<Color>()); @@ -1063,8 +1110,7 @@ void RasterizerEffectsRD::render_sky(RD::DrawListID p_list, float p_time, RID p_ RasterizerEffectsRD::RasterizerEffectsRD() { - { - // Initialize blur + { // Initialize blur Vector<String> blur_modes; blur_modes.push_back("\n#define MODE_GAUSSIAN_BLUR\n"); blur_modes.push_back("\n#define MODE_GAUSSIAN_GLOW\n"); @@ -1356,6 +1402,21 @@ RasterizerEffectsRD::RasterizerEffectsRD() { ssr_scale.pipeline = RD::get_singleton()->compute_pipeline_create(ssr_scale.shader.version_get_shader(ssr_scale.shader_version, 0)); } + { + Vector<String> sss_modes; + sss_modes.push_back("\n#define USE_11_SAMPLES\n"); + sss_modes.push_back("\n#define USE_17_SAMPLES\n"); + sss_modes.push_back("\n#define USE_25_SAMPLES\n"); + + sss.shader.initialize(sss_modes); + + sss.shader_version = sss.shader.version_create(); + + for (int i = 0; i < sss_modes.size(); i++) { + sss.pipelines[i] = RD::get_singleton()->compute_pipeline_create(sss.shader.version_get_shader(sss.shader_version, i)); + } + } + RD::SamplerState sampler; sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; @@ -1400,16 +1461,22 @@ RasterizerEffectsRD::~RasterizerEffectsRD() { RD::get_singleton()->free(default_mipmap_sampler); RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + blur.shader.version_free(blur.shader_version); - roughness.shader.version_free(roughness.shader_version); - tonemap.shader.version_free(tonemap.shader_version); - luminance_reduce.shader.version_free(luminance_reduce.shader_version); - copy.shader.version_free(copy.shader_version); bokeh.shader.version_free(bokeh.shader_version); - ssao.minify_shader.version_free(ssao.minify_shader_version); - ssao.gather_shader.version_free(ssao.gather_shader_version); - ssao.blur_shader.version_free(ssao.blur_shader_version); - roughness_limiter.shader.version_free(roughness_limiter.shader_version); + copy.shader.version_free(copy.shader_version); cubemap_downsampler.shader.version_free(cubemap_downsampler.shader_version); filter.shader.version_free(filter.shader_version); + luminance_reduce.shader.version_free(luminance_reduce.shader_version); + roughness.shader.version_free(roughness.shader_version); + roughness_limiter.shader.version_free(roughness_limiter.shader_version); + specular_merge.shader.version_free(specular_merge.shader_version); + ssao.blur_shader.version_free(ssao.blur_shader_version); + ssao.gather_shader.version_free(ssao.gather_shader_version); + ssao.minify_shader.version_free(ssao.minify_shader_version); + ssr.shader.version_free(ssr.shader_version); + ssr_filter.shader.version_free(ssr_filter.shader_version); + ssr_scale.shader.version_free(ssr_scale.shader_version); + sss.shader.version_free(sss.shader_version); + tonemap.shader.version_free(tonemap.shader_version); } diff --git a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h index 32eb8c8cda..27f051d194 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_effects_rd.h @@ -48,6 +48,7 @@ #include "servers/rendering/rasterizer_rd/shaders/ssao.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_blur.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/ssao_minify.glsl.gen.h" +#include "servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl.gen.h" #include "servers/rendering/rasterizer_rd/shaders/tonemap.glsl.gen.h" #include "servers/rendering_server.h" @@ -480,6 +481,29 @@ class RasterizerEffectsRD { RID pipeline; } ssr_scale; + struct SubSurfaceScatteringPushConstant { + + int32_t screen_size[2]; + float camera_z_far; + float camera_z_near; + + uint32_t vertical; + uint32_t orthogonal; + float unit_size; + float scale; + + float depth_scale; + uint32_t pad[3]; + }; + + struct SubSurfaceScattering { + + SubSurfaceScatteringPushConstant push_constant; + SubsurfaceScatteringShaderRD shader; + RID shader_version; + RID pipelines[3]; //3 quality levels + } sss; + RID default_sampler; RID default_mipmap_sampler; RID index_buffer; @@ -571,6 +595,7 @@ public: void screen_space_reflection(RID p_diffuse, RID p_normal, RS::EnvironmentSSRRoughnessQuality p_roughness_quality, RID p_roughness, RID p_blur_radius, RID p_blur_radius2, RID p_metallic, const Color &p_metallic_mask, RID p_depth, RID p_scale_depth, RID p_scale_normal, RID p_output, RID p_output_blur, const Size2i &p_screen_size, int p_max_steps, float p_fade_in, float p_fade_out, float p_tolerance, const CameraMatrix &p_camera); void merge_specular(RID p_dest_framebuffer, RID p_specular, RID p_base, RID p_reflection); + void sub_surface_scattering(RID p_diffuse, RID p_diffuse2, RID p_depth, const CameraMatrix &p_camera, const Size2i &p_screen_size, float p_scale, float p_depth_scale, RS::SubSurfaceScatteringQuality p_quality); RasterizerEffectsRD(); ~RasterizerEffectsRD(); diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp index 6094fbb36f..685c30b5b8 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_high_end_rd.cpp @@ -1795,6 +1795,14 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor render_list.clear(); _fill_render_list(p_cull_result, p_cull_count, PASS_MODE_COLOR, render_buffer == nullptr); + bool using_sss = render_buffer && scene_state.used_sss && sub_surface_scattering_get_quality() != RS::SUB_SURFACE_SCATTERING_QUALITY_DISABLED; + + if (using_sss) { + using_separate_specular = true; + render_buffer->ensure_specular(); + using_separate_specular = true; + opaque_specular_framebuffer = render_buffer->color_specular_fb; + } RID radiance_uniform_set; bool draw_sky = false; @@ -1894,8 +1902,8 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor RENDER_TIMESTAMP("Render Opaque Pass"); - bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !scene_state.used_sss; - bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr; + bool can_continue_color = !scene_state.used_screen_texture && !using_ssr && !using_sss; + bool can_continue_depth = !scene_state.used_depth_texture && !using_ssr && !using_sss; { @@ -1904,10 +1912,15 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor //regular forward for now Vector<Color> c; - c.push_back(clear_color.to_linear()); if (using_separate_specular) { + Color cc = clear_color.to_linear(); + cc.a = 0; //subsurf scatter must be 0 + c.push_back(cc); c.push_back(Color(0, 0, 0, 0)); + } else { + c.push_back(clear_color.to_linear()); } + RID framebuffer = using_separate_specular ? opaque_specular_framebuffer : opaque_framebuffer; RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, keep_color ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CLEAR, will_continue_color ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, depth_pre_pass ? (using_ssao ? RD::INITIAL_ACTION_KEEP : RD::INITIAL_ACTION_CONTINUE) : RD::INITIAL_ACTION_CLEAR, will_continue_depth ? RD::FINAL_ACTION_CONTINUE : RD::FINAL_ACTION_READ, c, 1.0, 0); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(framebuffer), render_list.elements, render_list.element_count, false, using_separate_specular ? PASS_MODE_COLOR_SPECULAR : PASS_MODE_COLOR, render_buffer == nullptr, radiance_uniform_set, render_buffers_uniform_set); @@ -1950,10 +1963,9 @@ void RasterizerSceneHighEndRD::_render_scene(RID p_render_buffer, const Transfor if (using_separate_specular) { - if (scene_state.used_sss) { + if (using_sss) { RENDER_TIMESTAMP("Sub Surface Scattering"); - - //_process_sss() + _process_sss(p_render_buffer, p_cam_projection); } if (using_ssr) { @@ -2620,6 +2632,8 @@ RasterizerSceneHighEndRD::RasterizerSceneHighEndRD(RasterizerStorageRD *p_storag actions.render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions.render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + actions.render_mode_defines["sss_mode_skin"] = "#define SSS_MODE_SKIN\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); if (!force_blinn) { diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp index af86d145ad..e4c5f1c984 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.cpp @@ -3203,6 +3203,26 @@ void RasterizerSceneRD::_free_render_buffer_data(RenderBuffers *rb) { } } +void RasterizerSceneRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { + + RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + ERR_FAIL_COND(!rb); + + bool can_use_effects = rb->width >= 8 && rb->height >= 8; + + if (!can_use_effects) { + //just copy + return; + } + + if (rb->blur[0].texture.is_null()) { + _allocate_blur_textures(rb); + _render_buffers_uniform_set_changed(p_render_buffers); + } + + storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); +} + void RasterizerSceneRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); @@ -3547,6 +3567,19 @@ void RasterizerSceneRD::render_buffers_configure(RID p_render_buffers, RID p_ren _render_buffers_uniform_set_changed(p_render_buffers); } +void RasterizerSceneRD::sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality) { + sss_quality = p_quality; +} + +RS::SubSurfaceScatteringQuality RasterizerSceneRD::sub_surface_scattering_get_quality() const { + return sss_quality; +} + +void RasterizerSceneRD::sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) { + sss_scale = p_scale; + sss_depth_scale = p_depth_scale; +} + int RasterizerSceneRD::get_roughness_layers() const { return roughness_layers; } @@ -4101,6 +4134,9 @@ RasterizerSceneRD::RasterizerSceneRD(RasterizerStorageRD *p_storage) { screen_space_roughness_limiter_curve = GLOBAL_GET("rendering/quality/filters/screen_space_roughness_limiter_curve"); glow_bicubic_upscale = int(GLOBAL_GET("rendering/quality/glow/upscale_mode")) > 0; ssr_roughness_quality = RS::EnvironmentSSRRoughnessQuality(int(GLOBAL_GET("rendering/quality/screen_space_reflection/roughness_quality"))); + sss_quality = RS::SubSurfaceScatteringQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_quality"))); + sss_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_scale"); + sss_depth_scale = GLOBAL_GET("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale"); } RasterizerSceneRD::~RasterizerSceneRD() { diff --git a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h index 11a8555d22..3f71f7dbc1 100644 --- a/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h +++ b/servers/rendering/rasterizer_rd/rasterizer_scene_rd.h @@ -93,6 +93,7 @@ protected: void _process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection); void _process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_roughness_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive); + void _process_sss(RID p_render_buffers, const CameraMatrix &p_camera); void _setup_sky(RID p_environment, const Vector3 &p_position, const Size2i p_screen_size); void _update_sky(RID p_environment, const CameraMatrix &p_projection, const Transform &p_transform); @@ -698,6 +699,9 @@ private: RS::DOFBlurQuality dof_blur_quality = RS::DOF_BLUR_QUALITY_MEDIUM; RS::DOFBokehShape dof_blur_bokeh_shape = RS::DOF_BOKEH_HEXAGON; bool dof_blur_use_jitter = false; + RS::SubSurfaceScatteringQuality sss_quality = RS::SUB_SURFACE_SCATTERING_QUALITY_MEDIUM; + float sss_scale = 0.05; + float sss_depth_scale = 0.01; mutable RID_Owner<CameraEffects> camera_effects_owner; @@ -1110,6 +1114,10 @@ public: virtual bool screen_space_roughness_limiter_is_active() const; virtual float screen_space_roughness_limiter_get_curve() const; + virtual void sub_surface_scattering_set_quality(RS::SubSurfaceScatteringQuality p_quality); + RS::SubSurfaceScatteringQuality sub_surface_scattering_get_quality() const; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale); + int get_roughness_layers() const; bool is_using_radiance_cubemap_array() const; diff --git a/servers/rendering/rasterizer_rd/shaders/SCsub b/servers/rendering/rasterizer_rd/shaders/SCsub index ade0418bd2..04a43e3251 100644 --- a/servers/rendering/rasterizer_rd/shaders/SCsub +++ b/servers/rendering/rasterizer_rd/shaders/SCsub @@ -25,4 +25,5 @@ if "RD_GLSL" in env["BUILDERS"]: env.RD_GLSL("screen_space_reflection.glsl") env.RD_GLSL("screen_space_reflection_filter.glsl") env.RD_GLSL("screen_space_reflection_scale.glsl") + env.RD_GLSL("subsurface_scattering.glsl") env.RD_GLSL("specular_merge.glsl") diff --git a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl index 07f4770b14..955ae2e588 100644 --- a/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl +++ b/servers/rendering/rasterizer_rd/shaders/scene_high_end.glsl @@ -1697,6 +1697,9 @@ FRAGMENT_SHADER_CODE #else +#ifdef SSS_MODE_SKIN + sss_strength = -sss_strength; +#endif diffuse_buffer = vec4(emission + diffuse_light + ambient_light, sss_strength); specular_buffer = vec4(specular_light, metallic); diff --git a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl index 671e289ed0..1a5dd5ab55 100644 --- a/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl +++ b/servers/rendering/rasterizer_rd/shaders/screen_space_reflection_filter.glsl @@ -69,8 +69,6 @@ float gauss_weight(float p_val) { return mix(gauss_table[idx], gauss_table[idx + 1], c); } -#define GAUSS_WEIGHT(m_val) gauss_table[clamp(int(m_val * float(GAUSS_TABLE_SIZE - 1)), 0, GAUSS_TABLE_SIZE - 1)] - #define M_PI 3.14159265359 vec3 reconstructCSPosition(vec2 S, float z) { @@ -105,17 +103,14 @@ void do_filter(inout vec4 accum, inout float accum_radius, inout float divisor, break; } - float contrib = 0.0; if (d < radius) { - contrib += gauss_weight(d / radius); - } - if (contrib > 0.0) { - accum += imageLoad(source_ssr, tc) * contrib; + float w = gauss_weight(d / radius); + accum += imageLoad(source_ssr, tc) * w; #ifndef VERTICAL_PASS - accum_radius += r * contrib; + accum_radius += r * w; #endif - divisor += contrib; + divisor += w; } } } diff --git a/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl new file mode 100644 index 0000000000..41f8fde3ca --- /dev/null +++ b/servers/rendering/rasterizer_rd/shaders/subsurface_scattering.glsl @@ -0,0 +1,198 @@ +/* clang-format off */ +[compute] + +#version 450 + +VERSION_DEFINES + + + +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; + +/* clang-format on */ + +#ifdef USE_25_SAMPLES +const int kernel_size = 13; + +const vec2 kernel[kernel_size] = vec2[]( + vec2(0.530605, 0.0), + vec2(0.0211412, 0.0208333), + vec2(0.0402784, 0.0833333), + vec2(0.0493588, 0.1875), + vec2(0.0410172, 0.333333), + vec2(0.0263642, 0.520833), + vec2(0.017924, 0.75), + vec2(0.0128496, 1.02083), + vec2(0.0094389, 1.33333), + vec2(0.00700976, 1.6875), + vec2(0.00500364, 2.08333), + vec2(0.00333804, 2.52083), + vec2(0.000973794, 3.0)); + +const vec4 skin_kernel[kernel_size] = vec4[]( + vec4(0.530605, 0.613514, 0.739601, 0), + vec4(0.0211412, 0.0459286, 0.0378196, 0.0208333), + vec4(0.0402784, 0.0657244, 0.04631, 0.0833333), + vec4(0.0493588, 0.0367726, 0.0219485, 0.1875), + vec4(0.0410172, 0.0199899, 0.0118481, 0.333333), + vec4(0.0263642, 0.0119715, 0.00684598, 0.520833), + vec4(0.017924, 0.00711691, 0.00347194, 0.75), + vec4(0.0128496, 0.00356329, 0.00132016, 1.02083), + vec4(0.0094389, 0.00139119, 0.000416598, 1.33333), + vec4(0.00700976, 0.00049366, 0.000151938, 1.6875), + vec4(0.00500364, 0.00020094, 5.28848e-005, 2.08333), + vec4(0.00333804, 7.85443e-005, 1.2945e-005, 2.52083), + vec4(0.000973794, 1.11862e-005, 9.43437e-007, 3)); + +#endif //USE_25_SAMPLES + +#ifdef USE_17_SAMPLES +const int kernel_size = 9; +const vec2 kernel[kernel_size] = vec2[]( + vec2(0.536343, 0.0), + vec2(0.0324462, 0.03125), + vec2(0.0582416, 0.125), + vec2(0.0571056, 0.28125), + vec2(0.0347317, 0.5), + vec2(0.0216301, 0.78125), + vec2(0.0144609, 1.125), + vec2(0.0100386, 1.53125), + vec2(0.00317394, 2.0)); + +const vec4 skin_kernel[kernel_size] = vec4[]( + vec4(0.536343, 0.624624, 0.748867, 0), + vec4(0.0324462, 0.0656718, 0.0532821, 0.03125), + vec4(0.0582416, 0.0659959, 0.0411329, 0.125), + vec4(0.0571056, 0.0287432, 0.0172844, 0.28125), + vec4(0.0347317, 0.0151085, 0.00871983, 0.5), + vec4(0.0216301, 0.00794618, 0.00376991, 0.78125), + vec4(0.0144609, 0.00317269, 0.00106399, 1.125), + vec4(0.0100386, 0.000914679, 0.000275702, 1.53125), + vec4(0.00317394, 0.000134823, 3.77269e-005, 2)); +#endif //USE_17_SAMPLES + +#ifdef USE_11_SAMPLES +const int kernel_size = 6; +const vec2 kernel[kernel_size] = vec2[]( + vec2(0.560479, 0.0), + vec2(0.0771802, 0.08), + vec2(0.0821904, 0.32), + vec2(0.03639, 0.72), + vec2(0.0192831, 1.28), + vec2(0.00471691, 2.0)); + +const vec4 skin_kernel[kernel_size] = vec4[]( + + vec4(0.560479, 0.669086, 0.784728, 0), + vec4(0.0771802, 0.113491, 0.0793803, 0.08), + vec4(0.0821904, 0.0358608, 0.0209261, 0.32), + vec4(0.03639, 0.0130999, 0.00643685, 0.72), + vec4(0.0192831, 0.00282018, 0.00084214, 1.28), + vec4(0.00471691, 0.000184771, 5.07565e-005, 2)); + +#endif //USE_11_SAMPLES + +layout(push_constant, binding = 1, std430) uniform Params { + + ivec2 screen_size; + float camera_z_far; + float camera_z_near; + + bool vertical; + bool orthogonal; + float unit_size; + float scale; + + float depth_scale; + uint pad[3]; +} +params; + +layout(set = 0, binding = 0) uniform sampler2D source_image; +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D dest_image; +layout(set = 2, binding = 0) uniform sampler2D source_depth; + +void do_filter(inout vec3 color_accum, inout vec3 divisor, vec2 uv, vec2 step, bool p_skin) { + + // Accumulate the other samples: + for (int i = 1; i < kernel_size; i++) { + // Fetch color and depth for current sample: + vec2 offset = uv + kernel[i].y * step; + vec4 color = texture(source_image, offset); + + if (abs(color.a) < 0.001) { + break; //mix no more + } + + vec3 w; + if (p_skin) { + //skin + w = skin_kernel[i].rgb; + } else { + w = vec3(kernel[i].x); + } + + color_accum += color.rgb * w; + divisor += w; + } +} + +void main() { + + // Pixel being shaded + ivec2 ssC = ivec2(gl_GlobalInvocationID.xy); + + if (any(greaterThan(ssC, params.screen_size))) { //too large, do nothing + return; + } + + vec2 uv = (vec2(ssC) + 0.5) / vec2(params.screen_size); + + // Fetch color of current pixel: + vec4 base_color = texture(source_image, uv); + float strength = abs(base_color.a); + + if (strength > 0.0) { + + vec2 dir = params.vertical ? vec2(0.0, 1.0) : vec2(1.0, 0.0); + + // Fetch linear depth of current pixel: + float depth = texture(source_depth, uv).r * 2.0 - 1.0; + float depth_scale; + + 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_scale = params.unit_size; //remember depth is negative by default in OpenGL + } 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_scale = params.unit_size / depth; //remember depth is negative by default in OpenGL + } + + float scale = mix(params.scale, depth_scale, params.depth_scale); + + // Calculate the final step to fetch the surrounding pixels: + vec2 step = scale * dir; + step *= strength; + step /= 3.0; + // Accumulate the center sample: + + vec3 divisor; + bool skin = bool(base_color.a < 0.0); + + if (skin) { + //skin + divisor = skin_kernel[0].rgb; + } else { + divisor = vec3(kernel[0].x); + } + + vec3 color = base_color.rgb * divisor; + + do_filter(color, divisor, uv, step, skin); + do_filter(color, divisor, uv, -step, skin); + + base_color.rgb = color / divisor; + } + + imageStore(dest_image, ssC, base_color); +} diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 8480aa30fc..267efdbacb 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -541,6 +541,8 @@ public: BIND5(environment_set_fog_height, RID, bool, float, float, float) BIND2(screen_space_roughness_limiter_set_active, bool, float) + BIND1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality) + BIND2(sub_surface_scattering_set_scale, float, float) /* CAMERA EFFECTS */ diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index 13dad3ec18..d0f711838c 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -456,6 +456,8 @@ public: FUNC5(environment_set_fog_height, RID, bool, float, float, float) FUNC2(screen_space_roughness_limiter_set_active, bool, float) + FUNC1(sub_surface_scattering_set_quality, SubSurfaceScatteringQuality) + FUNC2(sub_surface_scattering_set_scale, float, float) FUNCRID(camera_effects) diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index ba7b992e51..78fa2c2690 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -168,6 +168,8 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SPATIAL].modes.push_back("depth_test_disabled"); + shader_modes[RS::SHADER_SPATIAL].modes.push_back("sss_mode_skin"); + shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_back"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_front"); shader_modes[RS::SHADER_SPATIAL].modes.push_back("cull_disabled"); diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 55afd78fda..d417567a23 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2362,6 +2362,13 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/quality/screen_space_reflection/roughness_quality", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/screen_space_reflection/roughness_quality", PropertyInfo(Variant::INT, "rendering/quality/screen_space_reflection/roughness_quality", PROPERTY_HINT_ENUM, "Disabled (Fastest),Low, Medium, High (Slowest)")); + + GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_quality", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_quality", PropertyInfo(Variant::INT, "rendering/quality/subsurface_scattering/subsurface_scattering_quality", PROPERTY_HINT_ENUM, "Disabled, Low (Fastest),Medium, High (Slowest)")); + GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_scale", 0.05); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); + GLOBAL_DEF("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", 0.01); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PropertyInfo(Variant::FLOAT, "rendering/quality/subsurface_scattering/subsurface_scattering_depth_scale", PROPERTY_HINT_RANGE, "0.001,1,0.001")); } RenderingServer::~RenderingServer() { diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 9726a71f0c..ac8e92be59 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -782,6 +782,16 @@ public: virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_curve) = 0; + enum SubSurfaceScatteringQuality { + SUB_SURFACE_SCATTERING_QUALITY_DISABLED, + SUB_SURFACE_SCATTERING_QUALITY_LOW, + SUB_SURFACE_SCATTERING_QUALITY_MEDIUM, + SUB_SURFACE_SCATTERING_QUALITY_HIGH, + }; + + virtual void sub_surface_scattering_set_quality(SubSurfaceScatteringQuality p_quality) = 0; + virtual void sub_surface_scattering_set_scale(float p_scale, float p_depth_scale) = 0; + /* CAMERA EFFECTS */ virtual RID camera_effects_create() = 0; |