diff --git a/viewport/3d_scaling/README.md b/viewport/3d_scaling/README.md index 4ae20629..43a344fc 100644 --- a/viewport/3d_scaling/README.md +++ b/viewport/3d_scaling/README.md @@ -1,19 +1,15 @@ -# 3D Viewport Scaling +# 3D Resolution Scaling -This demo shows how to scale the 3D viewport rendering without affecting 2D -elements such as the HUD. It also demonstrates how to toggle filtering on a -viewport. This technique can be useful in 2D games as well. For instance, it can -be used to have a "pixel art" viewport for the main game area and a -non-pixel-art viewport for HUD elements. +This demo shows how to downscale the 3D resolution without affecting 2D +elements, to improve performance without making the UI blurry. + +See [Resolution scaling](https://docs.godotengine.org/en/stable/tutorials/3d/resolution_scaling.html) +in the documentation for details. Language: GDScript -Renderer: GLES 2 +Renderer: Forward+ -Check out this demo on the asset library: https://godotengine.org/asset-library/asset/586 +## Screenshot -## Screenshots - -![Screenshot](screenshots/high.png) - -![Screenshot](screenshots/low.png) +![3D Resolution Scaling](screenshots/3d_scaling.webp) diff --git a/viewport/3d_scaling/cubes.tscn b/viewport/3d_scaling/cubes.tscn index b1c3d431..8cdc8107 100644 --- a/viewport/3d_scaling/cubes.tscn +++ b/viewport/3d_scaling/cubes.tscn @@ -1,10 +1,80 @@ -[gd_scene load_steps=2 format=3 uid="uid://bbnebk7xoaoto"] +[gd_scene load_steps=14 format=3 uid="uid://bbnebk7xoaoto"] + +[sub_resource type="Gradient" id="Gradient_20ov5"] +offsets = PackedFloat32Array(0, 0.269231, 0.538462, 1) +colors = PackedColorArray(0, 0, 0, 1, 0.211332, 0.268774, 0.382711, 1, 0.248048, 0.560964, 0.645926, 1, 1, 1, 1, 1) + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_ja65t"] +fractal_type = 2 +fractal_gain = 0.333 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_gdmpo"] +height = 256 +seamless = true +color_ramp = SubResource("Gradient_20ov5") +noise = SubResource("FastNoiseLite_ja65t") + +[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_me6gu"] +panorama = SubResource("NoiseTexture2D_gdmpo") + +[sub_resource type="Sky" id="Sky_5j6vf"] +sky_material = SubResource("PanoramaSkyMaterial_me6gu") + +[sub_resource type="Environment" id="Environment_0v44j"] +background_mode = 2 +sky = SubResource("Sky_5j6vf") +tonemap_mode = 2 +tonemap_white = 6.0 + +[sub_resource type="Gradient" id="Gradient_1dao0"] + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_y7cc2"] +frequency = 0.001 +fractal_type = 2 +fractal_lacunarity = 3.0 +fractal_gain = 1.4 +fractal_weighted_strength = 0.25 +domain_warp_enabled = true +domain_warp_type = 2 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_42rpi"] +seamless = true +color_ramp = SubResource("Gradient_1dao0") +noise = SubResource("FastNoiseLite_y7cc2") + +[sub_resource type="FastNoiseLite" id="FastNoiseLite_rxfm5"] +frequency = 0.001 +fractal_type = 2 +fractal_octaves = 2 +fractal_lacunarity = 3.0 +fractal_gain = 1.4 +fractal_weighted_strength = 0.25 +domain_warp_enabled = true +domain_warp_type = 2 + +[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_gwux6"] +seamless = true +as_normal_map = true +bump_strength = 10.0 +color_ramp = SubResource("Gradient_1dao0") +noise = SubResource("FastNoiseLite_rxfm5") + +[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_sany7"] +albedo_texture = SubResource("NoiseTexture2D_42rpi") +normal_enabled = true +normal_texture = SubResource("NoiseTexture2D_gwux6") +uv1_scale = Vector3(6, 4, 1) +texture_filter = 5 [sub_resource type="BoxMesh" id="1"] +material = SubResource("StandardMaterial3D_sany7") size = Vector3(2, 2, 2) [node name="Cubes" type="Node3D"] +[node name="WorldEnvironment" type="WorldEnvironment" parent="."] +environment = SubResource("Environment_0v44j") + [node name="MeshInstance1" type="MeshInstance3D" parent="."] mesh = SubResource("1") @@ -12,11 +82,36 @@ mesh = SubResource("1") transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, -1) mesh = SubResource("1") +[node name="MeshInstance3" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 3, 0, 0) +mesh = SubResource("1") + +[node name="MeshInstance4" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 1, -1) +mesh = SubResource("1") + +[node name="MeshInstance5" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 6, 0, 0) +mesh = SubResource("1") + +[node name="MeshInstance6" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 1, -1) +mesh = SubResource("1") + +[node name="MeshInstance7" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) +mesh = SubResource("1") + +[node name="MeshInstance8" type="MeshInstance3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2, 1, -1) +mesh = SubResource("1") + [node name="Camera3D" type="Camera3D" parent="."] transform = Transform3D(0.877582, 0.229849, -0.420736, 0, 0.877582, 0.479426, 0.479426, -0.420736, 0.770151, -1.68294, 2.25571, 3.0806) fov = 74.0 [node name="OmniLight3D" type="OmniLight3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.3, 2, 1) +light_energy = 3.0 shadow_enabled = true -shadow_bias = 0.08 +shadow_bias = 0.02 diff --git a/viewport/3d_scaling/default_env.tres b/viewport/3d_scaling/default_env.tres deleted file mode 100644 index 38c88068..00000000 --- a/viewport/3d_scaling/default_env.tres +++ /dev/null @@ -1,10 +0,0 @@ -[gd_resource type="Environment" load_steps=3 format=3 uid="uid://gvgtl0xxtewa"] - -[sub_resource type="ProceduralSkyMaterial" id="ProceduralSkyMaterial_fikmw"] - -[sub_resource type="Sky" id="1"] -sky_material = SubResource("ProceduralSkyMaterial_fikmw") - -[resource] -background_mode = 2 -sky = SubResource("1") diff --git a/viewport/3d_scaling/hud.gd b/viewport/3d_scaling/hud.gd index a6b4bc17..2688cd2d 100644 --- a/viewport/3d_scaling/hud.gd +++ b/viewport/3d_scaling/hud.gd @@ -1,42 +1,34 @@ extends Control -# The 3D viewport's scale factor. For instance, 1.0 is full resolution, -# 0.5 is half resolution and 2.0 is double resolution. Higher values look -# sharper but are slower to render. Values above 1 can be used for supersampling -# (SSAA), but filtering must be enabled for supersampling to work. -var scale_factor = 1.0 -@onready var viewport_container = $SubViewportContainer -@onready var viewport = $SubViewportContainer/SubViewport +# The 3D viewport's shrink factor. For instance, 1 is full resolution, +# 2 is half resolution and 4 is quarter resolution. Lower values look +# sharper but are slower to render. +var scale_factor = 1 +var filter_mode = Viewport.SCALING_3D_MODE_BILINEAR + +@onready var viewport = get_tree().root @onready var scale_label = $VBoxContainer/Scale @onready var filter_label = $VBoxContainer/Filter -func _ready(): - viewport_container.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR - # Required to change the 3D viewport's size when the window is resized. - viewport.size_changed.connect(self._root_viewport_size_changed) +func _ready(): + viewport.scaling_3d_mode = Viewport.SCALING_3D_MODE_BILINEAR func _unhandled_input(event): if event.is_action_pressed("cycle_viewport_resolution"): - scale_factor = wrapf(scale_factor + 0.25, 0.25, 2.25) - viewport.size = get_viewport().size * scale_factor - scale_label.text = "Scale: %s%%" % str(scale_factor * 100) + scale_factor = wrapi(scale_factor + 1, 1, 5) + viewport.scaling_3d_scale = 1.0 / scale_factor + scale_label.text = "Scale: %3.0f%%" % (100.0 / scale_factor) if event.is_action_pressed("toggle_filtering"): - # Toggle the Filter flag on the ViewportTexture. - if viewport_container.texture_filter == CanvasItem.TEXTURE_FILTER_LINEAR: - viewport_container.texture_filter = CanvasItem.TEXTURE_FILTER_NEAREST - filter_label.text = "Filter: Disabled" - else: - viewport_container.texture_filter = CanvasItem.TEXTURE_FILTER_LINEAR - filter_label.text = "Filter: Enabled" - - -# Called when the root's viewport size changes (i.e. when the window is resized). -# This is done to handle multiple resolutions without losing quality. -func _root_viewport_size_changed(): - # The viewport is resized depending on the window height. - # To compensate for the larger resolution, the viewport sprite is scaled down. - viewport.size = get_viewport().size * scale_factor + filter_mode = wrapi(filter_mode + 1, Viewport.SCALING_3D_MODE_BILINEAR, Viewport.SCALING_3D_MODE_MAX) as Viewport.Scaling3DMode + viewport.scaling_3d_mode = filter_mode + filter_label.text = ( + ClassDB.class_get_enum_constants("Viewport", "Scaling3DMode")[filter_mode] + .capitalize() + .replace("3d", "3D") + .replace("Mode", "Mode:") + .replace("Fsr", "FSR") + ) diff --git a/viewport/3d_scaling/hud.tscn b/viewport/3d_scaling/hud.tscn index ebbdaa6f..883f6226 100644 --- a/viewport/3d_scaling/hud.tscn +++ b/viewport/3d_scaling/hud.tscn @@ -10,48 +10,42 @@ layout_mode = 3 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 theme = SubResource("2") script = ExtResource("3") -[node name="SubViewportContainer" type="SubViewportContainer" parent="."] -texture_filter = 1 -anchors_preset = 15 -anchor_right = 1.0 -anchor_bottom = 1.0 -stretch = true - -[node name="SubViewport" type="SubViewport" parent="SubViewportContainer"] -handle_input_locally = false -size = Vector2i(1152, 648) -render_target_update_mode = 4 - -[node name="Cubes" parent="SubViewportContainer/SubViewport" instance=ExtResource("2")] +[node name="Cubes" parent="." instance=ExtResource("2")] [node name="Help" type="Label" parent="."] -anchors_preset = 2 +layout_mode = 0 anchor_top = 1.0 anchor_bottom = 1.0 offset_left = 16.0 offset_top = -106.0 offset_right = 554.0 offset_bottom = -16.0 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 text = "This text will always render at the native resolution. Press Space to adjust the 3D viewport's resolution scaling. -Press Enter to toggle filtering." +Press Enter to cycle filtering modes." [node name="VBoxContainer" type="VBoxContainer" parent="."] +layout_mode = 0 offset_left = 16.0 offset_top = 16.0 offset_right = 124.0 offset_bottom = 76.0 [node name="Scale" type="Label" parent="VBoxContainer"] -offset_right = 111.0 -offset_bottom = 26.0 +layout_mode = 2 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 text = "Scale: 100%" [node name="Filter" type="Label" parent="VBoxContainer"] -offset_top = 30.0 -offset_right = 111.0 -offset_bottom = 56.0 -text = "Filter: Enabled" +layout_mode = 2 +theme_override_colors/font_outline_color = Color(0, 0, 0, 1) +theme_override_constants/outline_size = 4 +text = "Scaling 3D Mode: Bilinear" diff --git a/viewport/3d_scaling/project.godot b/viewport/3d_scaling/project.godot index b15cbc50..a463a813 100644 --- a/viewport/3d_scaling/project.godot +++ b/viewport/3d_scaling/project.godot @@ -18,7 +18,7 @@ be used to have a \"pixel art\" viewport for the main game area and a non-pixel-art viewport for HUD elements." config/tags=PackedStringArray("3d", "demo", "official", "rendering") run/main_scene="res://hud.tscn" -config/features=PackedStringArray("4.2") +config/features=PackedStringArray("4.3") config/icon="res://icon.webp" [display] @@ -30,15 +30,15 @@ window/stretch/aspect="expand" cycle_viewport_resolution={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":32,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } toggle_filtering={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":4194309,"physical_keycode":0,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) ] } [rendering] -environment/defaults/default_environment="res://default_env.tres" +textures/default_filters/anisotropic_filtering_level=4 diff --git a/viewport/3d_scaling/screenshots/3d_scaling.webp b/viewport/3d_scaling/screenshots/3d_scaling.webp new file mode 100644 index 00000000..e5f2b021 Binary files /dev/null and b/viewport/3d_scaling/screenshots/3d_scaling.webp differ diff --git a/viewport/3d_scaling/screenshots/high.png b/viewport/3d_scaling/screenshots/high.png deleted file mode 100644 index 550235b5..00000000 Binary files a/viewport/3d_scaling/screenshots/high.png and /dev/null differ diff --git a/viewport/3d_scaling/screenshots/low.png b/viewport/3d_scaling/screenshots/low.png deleted file mode 100644 index 9913b670..00000000 Binary files a/viewport/3d_scaling/screenshots/low.png and /dev/null differ