Add a viewport 3D scaling demo

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 by using TextureRect to display the
ViewportTexture delivered by the Viewport node.
This commit is contained in:
Hugo Locurcio
2020-02-16 00:41:43 +01:00
parent 05801f9389
commit b927ea3c63
9 changed files with 266 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
# 3D 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 by using TextureRect to display the ViewportTexture
delivered by the Viewport node. 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.
ViewportContainer can also be used to display a viewport in a GUI, but it
doesn't offer the ability to enable filtering.

View File

@@ -0,0 +1,9 @@
[gd_resource type="Environment" load_steps=2 format=2]
[sub_resource type="ProceduralSky" id=1]
sky_top_color = Color( 0.207843, 0.239216, 0.254902, 1 )
sky_horizon_color = Color( 0.466667, 0.478431, 0.490196, 1 )
[resource]
background_mode = 2
background_sky = SubResource( 1 )

View File

@@ -0,0 +1,42 @@
extends Control
# The viewport is displayed using a TextureRect node instead of a ViewportContainer.
# This allows filtering the texture that's displayed in the root viewport.
# 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 this to work.
var scale_factor = 1.0
onready var texture_rect = $TextureRect
onready var viewport = $TextureRect/Viewport
onready var scale_label = $VBoxContainer/Scale
onready var filter_label = $VBoxContainer/Filter
func _ready():
# Required to change the 3D viewport's size when the window is resized.
# warning-ignore:return_value_discarded
get_viewport().connect("size_changed", self, "_root_viewport_size_changed")
func _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)
if event.is_action_pressed("toggle_filtering"):
# Toggle the Filter flag on the ViewportTexture.
texture_rect.texture.flags ^= ImageTexture.FLAG_FILTER
var filter_enabled = texture_rect.texture.flags & ImageTexture.FLAG_FILTER
filter_label.text = "Filter: %s" % ("Enabled" if filter_enabled else "Disabled")
# 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

View File

@@ -0,0 +1,104 @@
[gd_scene load_steps=7 format=2]
[ext_resource path="res://noto_sans_ui_regular.ttf" type="DynamicFontData" id=1]
[ext_resource path="res://spatial.tscn" type="PackedScene" id=2]
[ext_resource path="res://hud.gd" type="Script" id=3]
[sub_resource type="DynamicFont" id=1]
size = 20
font_data = ExtResource( 1 )
[sub_resource type="Theme" id=2]
default_font = SubResource( 1 )
[sub_resource type="ViewportTexture" id=3]
viewport_path = NodePath("TextureRect/Viewport")
[node name="HUD" type="Control"]
anchor_right = 1.0
anchor_bottom = 1.0
theme = SubResource( 2 )
script = ExtResource( 3 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
texture = SubResource( 3 )
expand = true
flip_v = true
__meta__ = {
"_edit_use_anchors_": false,
"_editor_description_": ""
}
[node name="Viewport" type="Viewport" parent="TextureRect"]
size = Vector2( 1024, 600 )
handle_input_locally = false
usage = 3
render_target_update_mode = 3
shadow_atlas_size = 4096
[node name="Spatial" parent="TextureRect/Viewport" instance=ExtResource( 2 )]
[node name="ViewportContainer" type="ViewportContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Help" type="Label" parent="."]
anchor_top = 1.0
anchor_bottom = 1.0
margin_left = 16.0
margin_top = -106.0
margin_right = 554.0
margin_bottom = -16.0
custom_fonts/font = SubResource( 1 )
custom_colors/font_color_shadow = Color( 0, 0, 0, 0.752941 )
custom_constants/shadow_offset_x = 2
custom_constants/shadow_offset_y = 2
custom_constants/shadow_as_outline = 0
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."
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 16.0
margin_top = 16.0
margin_right = 124.0
margin_bottom = 76.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Scale" type="Label" parent="VBoxContainer"]
margin_right = 137.0
margin_bottom = 28.0
custom_colors/font_color_shadow = Color( 0, 0, 0, 0.752941 )
custom_constants/shadow_offset_x = 2
custom_constants/shadow_offset_y = 2
custom_constants/shadow_as_outline = 0
text = "Scale: 100%"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Filter" type="Label" parent="VBoxContainer"]
margin_top = 32.0
margin_right = 137.0
margin_bottom = 60.0
custom_colors/font_color_shadow = Color( 0, 0, 0, 0.752941 )
custom_constants/shadow_offset_x = 2
custom_constants/shadow_offset_y = 2
custom_constants/shadow_as_outline = 0
text = "Filter: Disabled"
__meta__ = {
"_edit_use_anchors_": false
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -0,0 +1,34 @@
[remap]
importer="texture"
type="StreamTexture"
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://icon.png"
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
[params]
compress/mode=0
compress/lossy_quality=0.7
compress/hdr_mode=0
compress/bptc_ldr=0
compress/normal_map=0
flags/repeat=0
flags/filter=true
flags/mipmaps=false
flags/anisotropic=false
flags/srgb=2
process/fix_alpha_border=true
process/premult_alpha=false
process/HDR_as_SRGB=false
process/invert_color=false
stream=false
size_limit=0
detect_3d=true
svg/scale=1.0

Binary file not shown.

View File

@@ -0,0 +1,43 @@
; Engine configuration file.
; It's best edited using the editor UI and not directly,
; since the parameters that go here are not all obvious.
;
; Format:
; [section] ; section goes between []
; param=value ; assign values to parameters
config_version=4
_global_script_classes=[ ]
_global_script_class_icons={
}
[application]
config/name="3D Viewport Scaling"
run/main_scene="res://hud.tscn"
config/icon="res://icon.png"
[display]
window/stretch/mode="2d"
window/stretch/aspect="expand"
[input]
cycle_viewport_resolution={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":32,"unicode":0,"echo":false,"script":null)
]
}
toggle_filtering={
"deadzone": 0.5,
"events": [ Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":0,"alt":false,"shift":false,"control":false,"meta":false,"command":false,"pressed":false,"scancode":16777221,"unicode":0,"echo":false,"script":null)
]
}
[rendering]
quality/intended_usage/framebuffer_allocation=3
environment/default_environment="res://default_env.tres"

View File

@@ -0,0 +1,23 @@
[gd_scene load_steps=2 format=2]
[sub_resource type="CubeMesh" id=1]
[node name="Spatial" type="Spatial"]
[node name="MeshInstance" type="MeshInstance" parent="."]
mesh = SubResource( 1 )
material/0 = null
[node name="MeshInstance2" type="MeshInstance" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, -1 )
mesh = SubResource( 1 )
material/0 = null
[node name="Camera" type="Camera" parent="."]
transform = Transform( 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="OmniLight" type="OmniLight" parent="."]
transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.3, 2, 1 )
shadow_enabled = true
shadow_bias = 0.08