├── .gitignore ├── Control3D.gd ├── LICENSE.md ├── Node3D.png ├── Node3D.png.import ├── Node3D.svg ├── Node3D.svg.import ├── plugin.cfg ├── plugin.gd └── screenshots ├── .gdignore ├── Screenshot 2023-09-05 034316.png └── Screenshot 2023-09-05 034316.png.import /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot 3 | 4 | # Godot-specific ignores 5 | .import 6 | export.cfg 7 | export_presets.cfg 8 | 9 | # Imported translations (automatically generated from CSV files) 10 | .translation 11 | 12 | # Mono-specific ignores 13 | .mono 14 | data_ 15 | mono_crash..json -------------------------------------------------------------------------------- /Control3D.gd: -------------------------------------------------------------------------------- 1 | ##A node used as the parent of other control nodes to display them in 3D. 2 | @tool class_name Control3D extends MeshInstance3D 3 | 4 | ##The size of the [QuadMesh]. 5 | @export var size:Vector2 = Vector2(1, 1) : 6 | set(value): 7 | size = value 8 | mesh.size = value 9 | if force_viewport_aspect_ratio: 10 | set_viewport_size(value*viewport_resolution_scale) 11 | 12 | ##The resolution of the [SubViewport]. 13 | @export var viewport_resolution:Vector2 = Vector2(512, 512): 14 | set(value): 15 | viewport_resolution = value 16 | set_viewport_size(value) 17 | 18 | ##If set to true it overwrites the [SubViewport]s size with size*viewport_resolution_scale. 19 | @export var force_viewport_aspect_ratio:bool = false 20 | ##Only used if force_viewport_aspect_ratio is set to true. 21 | ##Overwrites the [SubViewport]s size with size*viewport_resolution_scale. 22 | @export var viewport_resolution_scale:int = 512: 23 | set(value): 24 | viewport_resolution_scale = value 25 | if force_viewport_aspect_ratio: 26 | set_viewport_size(size*value) 27 | 28 | ##Sets the billboard mode of the [QuadMesh]. 29 | @export_enum("Disabled", "Enabled", "Y-Billboard") var billboard_mode:int = 0 : 30 | set(value): 31 | billboard_mode = value 32 | mesh.surface_get_material(0).billboard_mode = value 33 | 34 | ##Refreshes the [SubViewport]s children. Meant only for use in the editor 35 | @export var force_refresh_viewport:bool = false: 36 | set(value): 37 | refresh_viewport() 38 | 39 | func _ready() -> void: 40 | var subViewport := SubViewport.new() 41 | subViewport.name = "SubViewport" 42 | subViewport.disable_3d = true 43 | add_child(subViewport, true) 44 | set_viewport_size(viewport_resolution) 45 | if force_viewport_aspect_ratio: set_viewport_size(size*viewport_resolution_scale) 46 | mesh = QuadMesh.new() 47 | mesh.size = size 48 | var mat := StandardMaterial3D.new() 49 | mat.albedo_texture = $SubViewport.get_texture() 50 | mat.billboard_mode = billboard_mode 51 | mat.shading_mode = mat.SHADING_MODE_UNSHADED 52 | mesh.surface_set_material(0, mat) 53 | if Engine.is_editor_hint(): return 54 | for child in get_children(): 55 | if child is Control: 56 | remove_child(child) 57 | $SubViewport.add_child(child) 58 | 59 | ##Gets all of the [SubViewport]s child nodes 60 | func get_control_nodes(include_internal: bool = false) -> Array[Node]: 61 | return $SubViewport.get_children(include_internal) 62 | 63 | ##Deletes all of the [SubViewport]s children 64 | func clear_viewport(): 65 | for child in get_control_nodes(): 66 | child.queue_free() 67 | 68 | ##Adds all [Control] node children to the [SubViewport] 69 | func add_control_to_viewport(): 70 | for child in get_children(): 71 | if child is Control: 72 | var new = child.duplicate() 73 | $SubViewport.add_child(new) 74 | 75 | ##Sets the size of the [SubViewport] 76 | func set_viewport_size(s:Vector2): 77 | if has_node('SubViewport') == false: 78 | return 79 | $SubViewport.size = s 80 | 81 | ##Calls clears the [SubViewport]s children then adds the new [Control] nodes 82 | func refresh_viewport(): 83 | clear_viewport() 84 | add_control_to_viewport() 85 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright 2023 Evan Watson 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /Node3D.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Evanator05/Control3D/52fa02c9bd5686fb69bb64da5f8833647962a751/Node3D.png -------------------------------------------------------------------------------- /Node3D.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://os71hqidchct" 6 | path="res://.godot/imported/Node3D.png-a2eda8e0b4088a11cc7a905f4d1e720c.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/control3d/Node3D.png" 14 | dest_files=["res://.godot/imported/Node3D.png-a2eda8e0b4088a11cc7a905f4d1e720c.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | -------------------------------------------------------------------------------- /Node3D.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /Node3D.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://buenc0kedbeqq" 6 | path="res://.godot/imported/Node3D.svg-751a67f2dddd679a32da0570f6660194.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/control3d/Node3D.svg" 14 | dest_files=["res://.godot/imported/Node3D.svg-751a67f2dddd679a32da0570f6660194.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=1.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="Control3D" 4 | description="adds the Control3D node" 5 | author="Evanator" 6 | version="" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | 4 | 5 | func _enter_tree(): 6 | add_custom_type("Control3D", "MeshInstance3D", preload("res://addons/control3d/Control3D.gd"), preload("res://addons/control3d/Node3D.svg")) 7 | 8 | 9 | func _exit_tree(): 10 | remove_custom_type("Control3D") 11 | -------------------------------------------------------------------------------- /screenshots/.gdignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /screenshots/Screenshot 2023-09-05 034316.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Evanator05/Control3D/52fa02c9bd5686fb69bb64da5f8833647962a751/screenshots/Screenshot 2023-09-05 034316.png -------------------------------------------------------------------------------- /screenshots/Screenshot 2023-09-05 034316.png.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bkakabv1x002h" 6 | path="res://.godot/imported/Screenshot 2023-09-05 034316.png-a912bb74eefa1fa0944dd00ad094eb2d.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/control3d/screenshots/Screenshot 2023-09-05 034316.png" 14 | dest_files=["res://.godot/imported/Screenshot 2023-09-05 034316.png-a912bb74eefa1fa0944dd00ad094eb2d.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | --------------------------------------------------------------------------------