From 092cf6fc03075817eb8b56322947e5de1aab5b53 Mon Sep 17 00:00:00 2001 From: TwistedTwigleg Date: Fri, 18 Jan 2019 16:17:18 -0500 Subject: [PATCH] Rewrote most of the code in the gui_in_3d demo. Now the demo supports viewports of different sizes, different sized quads, and has comments explaining what the code is doing --- viewport/gui_in_3d/Gui_in_3D.tscn | 381 +++++++++++++++++++++++++++-- viewport/gui_in_3d/gui_3d.gd | 98 +++++--- viewport/gui_in_3d/icon.png.import | 3 - viewport/gui_in_3d/project.godot | 11 +- 4 files changed, 423 insertions(+), 70 deletions(-) diff --git a/viewport/gui_in_3d/Gui_in_3D.tscn b/viewport/gui_in_3d/Gui_in_3D.tscn index 9242826f..5a94b583 100644 --- a/viewport/gui_in_3d/Gui_in_3D.tscn +++ b/viewport/gui_in_3d/Gui_in_3D.tscn @@ -1,21 +1,63 @@ -[gd_scene load_steps=15 format=2] +[gd_scene load_steps=16 format=2] [ext_resource path="res://gui_3d.gd" type="Script" id=1] +[ext_resource path="res://icon.png" type="Texture" id=2] [sub_resource type="PlaneMesh" id=1] +custom_aabb = AABB( 0, 0, 0, 0, 0, 0 ) +size = Vector2( 3, 2 ) +subdivide_width = 0 +subdivide_depth = 0 + [sub_resource type="ViewportTexture" id=2] + +resource_local_to_scene = true flags = 5 viewport_path = NodePath("Viewport") [sub_resource type="SpatialMaterial" id=3] resource_local_to_scene = true +render_priority = 0 +flags_transparent = true flags_unshaded = true flags_albedo_tex_force_srgb = true params_diffuse_mode = 1 albedo_texture = SubResource( 2 ) +metallic = 0.0 +metallic_specular = 0.5 +metallic_texture_channel = 0 +roughness = 0.0 +roughness_texture_channel = 0 +emission_enabled = true +emission = Color( 0, 0, 0, 1 ) +emission_energy = 1.0 +emission_operator = 0 +emission_on_uv2 = false +normal_enabled = false +rim_enabled = false +clearcoat_enabled = false +anisotropy_enabled = false +ao_enabled = false +depth_enabled = false +subsurf_scatter_enabled = false +transmission_enabled = false +refraction_enabled = false +detail_enabled = false +uv1_scale = Vector3( 1, 1, 1 ) +uv1_offset = Vector3( 0, 0, 0 ) +uv1_triplanar = false +uv1_triplanar_sharpness = 1.0 +uv2_scale = Vector3( 1, 1, 1 ) +uv2_offset = Vector3( 0, 0, 0 ) +uv2_triplanar = false +uv2_triplanar_sharpness = 1.0 +proximity_fade_enable = false +distance_fade_enable = false +_sections_unfolded = [ "Albedo", "Flags" ] [sub_resource type="GDScript" id=4] + script/source = "tool extends Object func e(): @@ -23,7 +65,8 @@ func e(): " [sub_resource type="BoxShape" id=5] -extents = Vector3( 1, 1, 0.01 ) + +extents = Vector3( 1.5, 1, 0.01 ) script = SubResource( 4 ) [sub_resource type="Animation" id=6] @@ -44,7 +87,13 @@ tracks/0/keys = { [sub_resource type="PlaneMesh" id=7] +custom_aabb = AABB( 0, 0, 0, 0, 0, 0 ) +size = Vector2( 2, 2 ) +subdivide_width = 0 +subdivide_depth = 0 + [sub_resource type="GDScript" id=8] + script/source = "tool extends Object func e(): @@ -52,6 +101,7 @@ func e(): " [sub_resource type="GDScript" id=9] + script/source = "tool extends Object func e(): @@ -59,6 +109,7 @@ func e(): " [sub_resource type="GDScript" id=10] + script/source = "tool extends Object func e(): @@ -67,11 +118,18 @@ func e(): [sub_resource type="CubeMesh" id=11] +custom_aabb = AABB( 0, 0, 0, 0, 0, 0 ) +size = Vector3( 2, 2, 2 ) +subdivide_width = 0 +subdivide_height = 0 +subdivide_depth = 0 + [sub_resource type="SpatialMaterial" id=12] albedo_color = Color( 0.722656, 0.791992, 1, 1 ) roughness = 0.0 [sub_resource type="GDScript" id=13] + script/source = "tool extends Object func e(): @@ -80,52 +138,293 @@ func e(): [node name="Gui_in_3D" type="Spatial"] script = ExtResource( 1 ) +quad_mesh_size = Vector2( 3, 2 ) +quad_node_scale = 1 [node name="Viewport" type="Viewport" parent="."] editor/display_folded = true -size = Vector2( 180, 180 ) +arvr = false +size = Vector2( 280, 180 ) +own_world = false +world = null transparent_bg = true hdr = false usage = 0 render_target_v_flip = true +render_target_clear_mode = 0 +render_target_update_mode = 2 +audio_listener_enable_2d = false +audio_listener_enable_3d = false +physics_object_picking = false +gui_disable_input = false +gui_snap_controls_to_pixels = true +shadow_atlas_size = 0 +shadow_atlas_quad_0 = 2 +shadow_atlas_quad_1 = 2 +shadow_atlas_quad_2 = 3 +shadow_atlas_quad_3 = 4 +_sections_unfolded = [ "Render Target", "Rendering" ] -[node name="GUI" type="Control" parent="Viewport"] -margin_right = 40.0 -margin_bottom = 40.0 +[node name="GUI" type="Control" parent="Viewport" index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_right = 280.0 +margin_bottom = 180.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false mouse_filter = 1 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +_sections_unfolded = [ "Mouse", "Rect" ] + +[node name="Panel" type="Panel" parent="Viewport/GUI" index="0"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +_sections_unfolded = [ "Rect" ] + +[node name="Label" type="Label" parent="Viewport/GUI" index="1"] [node name="Label" type="Label" parent="Viewport/GUI"] margin_left = 44.0 margin_top = 27.0 margin_right = 121.0 margin_bottom = 41.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 2 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 4 text = "Hello world!" -[node name="Button" type="Button" parent="Viewport/GUI"] -margin_left = 18.0 +[node name="Button" type="Button" parent="Viewport/GUI" index="2"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 14.0 margin_top = 46.0 -margin_right = 155.0 -margin_bottom = 73.0 +margin_right = 154.0 +margin_bottom = 74.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +enabled_focus_mode = 2 +shortcut = null +group = null text = "A button!" +flat = false +align = 1 +_sections_unfolded = [ "Rect" ] + +[node name="TextEdit" type="LineEdit" parent="Viewport/GUI" index="3"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 14.0 +margin_top = 87.0 +margin_right = 154.0 +margin_bottom = 111.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 1 +size_flags_horizontal = 1 +size_flags_vertical = 1 +focus_mode = 2 +context_menu_enabled = true +placeholder_alpha = 0.6 +caret_blink = false +caret_blink_speed = 0.65 +caret_position = 0 +_sections_unfolded = [ "Rect" ] + +[node name="HSlider" type="HSlider" parent="Viewport/GUI" index="4"] [node name="HSlider" type="HSlider" parent="Viewport/GUI"] margin_left = 14.0 margin_top = 118.0 -margin_right = 157.0 +margin_right = 154.0 margin_bottom = 134.0 -[node name="TextEdit" type="LineEdit" parent="Viewport/GUI"] -margin_left = 18.0 -margin_top = 87.0 -margin_right = 156.0 -margin_bottom = 111.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 0 +min_value = 0.0 +max_value = 100.0 +step = 1.0 +page = 0.0 +value = 0.0 +exp_edit = false +rounded = false +editable = true +tick_count = 0 +ticks_on_borders = false +focus_mode = 2 +_sections_unfolded = [ "Rect" ] + +[node name="ColorRect" type="ColorRect" parent="Viewport/GUI" index="5"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 180.0 +margin_top = 26.0 +margin_right = 244.0 +margin_bottom = 90.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +color = Color( 1, 0, 0, 1 ) +_sections_unfolded = [ "Rect" ] + +[node name="TextureRect" type="TextureRect" parent="Viewport/GUI/ColorRect" index="0"] + +anchor_left = 0.5 +anchor_top = 0.5 +anchor_right = 0.5 +anchor_bottom = 0.5 +margin_left = -20.0 +margin_top = -20.0 +margin_right = 20.0 +margin_bottom = 20.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +mouse_filter = 1 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +texture = ExtResource( 2 ) +expand = true +stretch_mode = 0 + +[node name="VSlider" type="VSlider" parent="Viewport/GUI" index="6"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 260.0 +margin_top = 26.0 +margin_right = 276.0 +margin_bottom = 166.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 0 +size_flags_vertical = 1 +min_value = 0.0 +max_value = 100.0 +step = 1.0 +page = 0.0 +value = 0.0 +exp_edit = false +rounded = false +editable = true +tick_count = 0 +ticks_on_borders = false +focus_mode = 2 +_sections_unfolded = [ "Rect" ] + +[node name="OptionButton" type="OptionButton" parent="Viewport/GUI" index="7"] + +anchor_left = 0.0 +anchor_top = 0.0 +anchor_right = 0.0 +anchor_bottom = 0.0 +margin_left = 170.0 +margin_top = 111.0 +margin_right = 252.0 +margin_bottom = 165.0 +rect_pivot_offset = Vector2( 0, 0 ) +rect_clip_content = false +focus_mode = 2 +mouse_filter = 0 +mouse_default_cursor_shape = 0 +size_flags_horizontal = 1 +size_flags_vertical = 1 +toggle_mode = false +action_mode = 0 +enabled_focus_mode = 2 +shortcut = null +group = null +text = "Item 0" +flat = false +align = 0 +items = [ "Item 0", null, false, -1, null, "Item 1", null, false, -1, null, "Item 2", null, false, -1, null ] +selected = 0 +_sections_unfolded = [ "Rect" ] + +[node name="Area" type="Area" parent="." index="1"] [node name="Area" type="Area" parent="."] input_ray_pickable = true input_capture_on_drag = true -[node name="Quad" type="MeshInstance" parent="Area"] -transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0 ) +space_override = 0 +gravity_point = false +gravity_distance_scale = 0.0 +gravity_vec = Vector3( 0, -1, 0 ) +gravity = 9.8 +linear_damp = 0.1 +angular_damp = 1.0 +priority = 0.0 +monitoring = true +monitorable = true +collision_layer = 1 +collision_mask = 1 +audio_bus_override = false +audio_bus_name = "Master" +reverb_bus_enable = false +reverb_bus_name = "Master" +reverb_bus_amount = 0.0 +reverb_bus_uniformity = 0.0 +_sections_unfolded = [ "Transform" ] + +[node name="Quad" type="MeshInstance" parent="Area" index="0"] + +transform = Transform( -1, -1.50996e-007, -6.60024e-015, 0, -4.37114e-008, 1, -1.50996e-007, 1, 4.37114e-008, 0, 0, 0 ) +layers = 1 +material_override = null +cast_shadow = 1 +extra_cull_margin = 0.0 +use_in_baked_light = false +lod_min_distance = 0.0 +lod_min_hysteresis = 0.0 +lod_max_distance = 0.0 +lod_max_hysteresis = 0.0 mesh = SubResource( 1 ) material/0 = SubResource( 3 ) @@ -144,25 +443,58 @@ omni_range = 10.0 [node name="Camera_Move" type="AnimationPlayer" parent="."] autoplay = "Move_camera" +playback_process_mode = 1 +playback_default_blend_time = 0.0 +playback_speed = 0.25 anims/Move_camera = SubResource( 6 ) +blend_times = [ ] +_sections_unfolded = [ "Playback Options" ] + +[node name="3D_background" type="Spatial" parent="." index="5"] [node name="3D_background" type="Spatial" parent="."] editor/display_folded = true -[node name="Wall" type="MeshInstance" parent="3D_background"] -transform = Transform( 4, 0, 0, 0, -1.74846e-07, -4, 0, 4, -1.74846e-07, -2.60819, 0.589247, -2.08943 ) +[node name="Wall" type="MeshInstance" parent="3D_background" index="0"] + +transform = Transform( 4, 0, 0, 0, -1.74846e-007, -4, 0, 4, -1.74846e-007, -2.60819, 0.589247, -2.08943 ) +layers = 1 +material_override = null +cast_shadow = 1 +extra_cull_margin = 0.0 +use_in_baked_light = false +lod_min_distance = 0.0 +lod_min_hysteresis = 0.0 +lod_max_distance = 0.0 +lod_max_hysteresis = 0.0 mesh = SubResource( 7 ) material/0 = null script = SubResource( 8 ) -[node name="Wall2" type="MeshInstance" parent="3D_background"] -transform = Transform( 4, 0, 0, 0, -1.74846e-07, -4, 0, 4, -1.74846e-07, 5.08055, 0.589247, -2.08943 ) +transform = Transform( 4, 0, 0, 0, -1.74846e-007, -4, 0, 4, -1.74846e-007, 5.08055, 0.589247, -2.08943 ) +layers = 1 +material_override = null +cast_shadow = 1 +extra_cull_margin = 0.0 +use_in_baked_light = false +lod_min_distance = 0.0 +lod_min_hysteresis = 0.0 +lod_max_distance = 0.0 +lod_max_hysteresis = 0.0 mesh = SubResource( 7 ) material/0 = null script = SubResource( 8 ) -[node name="Wall3" type="MeshInstance" parent="3D_background"] -transform = Transform( -1.74846e-07, -4, 0, -1.74846e-07, 7.64274e-15, -4, 4, -1.74846e-07, -1.74846e-07, 9.04446, 0.589247, 1.62058 ) +transform = Transform( -1.74846e-007, -4, 0, -1.74846e-007, 7.64274e-015, -4, 4, -1.74846e-007, -1.74846e-007, 9.04446, 0.589247, 1.62058 ) +layers = 1 +material_override = null +cast_shadow = 1 +extra_cull_margin = 0.0 +use_in_baked_light = false +lod_min_distance = 0.0 +lod_min_hysteresis = 0.0 +lod_max_distance = 0.0 +lod_max_hysteresis = 0.0 mesh = SubResource( 7 ) material/0 = null script = SubResource( 9 ) @@ -190,4 +522,5 @@ transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2.88761, 2.01326, 0.374871 ) mesh = SubResource( 11 ) material/0 = SubResource( 12 ) script = SubResource( 13 ) +_sections_unfolded = [ "Transform" ] diff --git a/viewport/gui_in_3d/gui_3d.gd b/viewport/gui_in_3d/gui_3d.gd index 93a356f6..38184d03 100644 --- a/viewport/gui_in_3d/gui_3d.gd +++ b/viewport/gui_in_3d/gui_3d.gd @@ -1,13 +1,23 @@ extends Spatial # Member variables +# The size of the quad mesh itself. +# NOTE: Do not apply the scale of the MeshInstance node, just the scale of the quad mesh! +export (Vector2) var quad_mesh_size = Vector2(3, 2) +# The scale of the quad node. It is assumed that the node is scaled evenly across the X, Y, and Z axes. +export (float) var quad_node_scale = 1 +# The position of the last processed input touch/mouse event. var prev_pos = null +# The last non-empty click_pos position. We need this to simulate drag events. var last_click_pos = null +# The viewport we want to interact with. var viewport = null +# A empty Vector3 used for comparison. +var empty_vector = Vector3(0,0,0) func _input(event): - # Check if the event is a non-mouse event + # Check if the event is a non-mouse/non-touch event var is_mouse_event = false var mouse_events = [InputEventMouseButton, InputEventMouseMotion, InputEventScreenDrag, InputEventScreenTouch] for mouse_event in mouse_events: @@ -15,56 +25,78 @@ func _input(event): is_mouse_event = true break - # If it is, then pass the event to the viewport + # If the event is not a mouse/touch event, then pass the event to the viewport as we do not + # need to do any conversions for these events. if is_mouse_event == false: viewport.input(event) # Mouse events for Area -func _on_area_input_event(_camera, event, click_pos, _click_normal, _shape_idx): - # Use click pos (click in 3d space, convert to area space) - var pos = get_node("Area").get_global_transform().affine_inverse() - # the click pos is not zero, then use it to convert from 3D space to area space - if click_pos.x != 0 or click_pos.y != 0 or click_pos.z != 0: - pos *= click_pos +func _on_area_input_event(camera, event, click_pos, click_normal, shape_idx): + # If click_pos is not empty, then we want to store it so we can use it to simulate drag events. + if click_pos != empty_vector: last_click_pos = click_pos - else: - # Otherwise, we have a motion event and need to use our last click pos - # and move it according to the relative position of the event. - # NOTE: this is not an exact 1-1 conversion, but it's pretty close - pos *= last_click_pos + + var pos + if click_pos == empty_vector: + # Convert the last known click pos, last_click_pos, from world coordinate space to a coordinate space + # relative to the Area node. + # NOTE: affine_inverse accounts for the Area node's scale, rotation, and translation in the scene! + pos = get_node("Area").global_transform.affine_inverse()*last_click_pos + + # If the event is has some form of dragging, then we need to simulate that drag in code. + # NOTE: this is not a perfect solution, but it works okay. if event is InputEventMouseMotion or event is InputEventScreenDrag: pos.x += event.relative.x / viewport.size.x - pos.y += event.relative.y / viewport.size.y - last_click_pos = pos - - # Convert to 2D - pos = Vector2(pos.x, pos.y) - - # Convert to viewport coordinate system - # Convert pos to a range from (0 - 1) - pos.y *= -1 - pos += Vector2(1, 1) - pos = pos / 2 - - # Convert pos to be in range of the viewport - pos.x *= viewport.size.x - pos.y *= viewport.size.y + pos.y -= event.relative.y / viewport.size.y + + # Update last_click_pos with the newest version of pos, with adjustments for quad size. + last_click_pos = pos * quad_node_scale + + else: + # Convert click_pos from world coordinate space to a coordinate space relative to the Area node. + # NOTE: affine_inverse accounts for the Area node's scale, rotation, and translation in the scene! + pos = get_node("Area").global_transform.affine_inverse()*click_pos - # Set the position in event + # convert the relative event position from 3D to 2D + pos = Vector2(pos.x, -pos.y) + + # Right now the event position's range is the following: (-quad_size/2) -> (quad_size/2) + # We need to convert it into the following range: 0 -> quad_size + pos.x += quad_mesh_size.x/2 + pos.y += quad_mesh_size.y/2 + # Then we need to convert it into the following range: 0 -> 1 + pos.x = pos.x/quad_mesh_size.x + pos.y = pos.y/quad_mesh_size.y + # Finally, we convert the position to the following range: 0 -> viewport.size + pos.x = pos.x * viewport.size.x + pos.y = pos.y * viewport.size.y + # We need to do these conversions so the event's position is in the viewport's coordinate system. + + # Set the event's position and global position. event.position = pos event.global_position = pos - if not prev_pos: - prev_pos = pos + + # If the event is a mouse motion event... if event is InputEventMouseMotion: - event.relative = pos - prev_pos + # If there is not a stored previous position, then we'll assume there is no relative motion. + if prev_pos == null: + event.relative = Vector2(0, 0) + # If there is a stored previous position, then we'll calculate the relative position by subtracting + # the previous position from the new position. This will give us the distance the event traveled from prev_pos + else: + event.relative = pos - prev_pos + + # Update prev_pos with the position we just calculated. prev_pos = pos - # Send the event to the viewport + # Finally, send the processed input event to the viewport. viewport.input(event) func _ready(): + # Get the Viewport node and assign it to viewport for later use. viewport = get_node("Viewport") + # Connect the input_event signal to the _on_area_input_event function. get_node("Area").connect("input_event", self, "_on_area_input_event") diff --git a/viewport/gui_in_3d/icon.png.import b/viewport/gui_in_3d/icon.png.import index c3c58805..0041ef86 100644 --- a/viewport/gui_in_3d/icon.png.import +++ b/viewport/gui_in_3d/icon.png.import @@ -7,10 +7,7 @@ path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" [deps] source_file="res://icon.png" -source_md5="434c8eb4c3320b4afd88f7a34b3a12d6" - dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ] -dest_md5="a6b3d106eb33d75fd3532a8554f6daaa" [params] diff --git a/viewport/gui_in_3d/project.godot b/viewport/gui_in_3d/project.godot index 26b2de43..88015c38 100644 --- a/viewport/gui_in_3d/project.godot +++ b/viewport/gui_in_3d/project.godot @@ -6,12 +6,7 @@ ; [section] ; section goes between [] ; param=value ; assign values to parameters -config_version=4 - -_global_script_classes=[ ] -_global_script_class_icons={ - -} +config_version=3 [application] @@ -19,10 +14,6 @@ config/name="GUI in 3D" run/main_scene="res://Gui_in_3D.tscn" config/icon="res://icon.png" -[debug] - -gdscript/warnings/return_value_discarded=false - [gdnative] singletons=[ ]