viewporttexture experiment

This commit is contained in:
soul-walker 2024-04-19 13:15:35 +08:00
parent e7894a9af0
commit f2bea7f892
82 changed files with 8599 additions and 1 deletions

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,34 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://c3feq8rrkjo6u"
path="res://.godot/imported/platform.gltf-a8d62adaec6449e0d7d69986454becc1.scn"
[deps]
source_file="res://Assets/models/platform/platform.gltf"
dest_files=["res://.godot/imported/platform.gltf-a8d62adaec6449e0d7d69986454becc1.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
import_script/path=""
_subresources={}
gltf/naming_version=1
gltf/embedded_image_handling=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dpt1fqi7kbhog"
path.s3tc="res://.godot/imported/platform_116plsmoxingT.jpg-29d10181717c21ba5ff9a649fa80e19d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_116plsmoxingT.jpg"
dest_files=["res://.godot/imported/platform_116plsmoxingT.jpg-29d10181717c21ba5ff9a649fa80e19d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://of8xlp10kuyf"
path.s3tc="res://.godot/imported/platform_1225zhantai.jpg-59db1024fbfe2d16a8400af12e5054c1.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_1225zhantai.jpg"
dest_files=["res://.godot/imported/platform_1225zhantai.jpg-59db1024fbfe2d16a8400af12e5054c1.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dyich8bbx40fo"
path.s3tc="res://.godot/imported/platform_2cengtietu_zst.png-b1afb7c124792069329f4f2332f41751.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_2cengtietu_zst.png"
dest_files=["res://.godot/imported/platform_2cengtietu_zst.png-b1afb7c124792069329f4f2332f41751.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 330 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://2xtf03ecucxo"
path.s3tc="res://.godot/imported/platform_DKL_dimian111.jpg-c39631cac4e1cc1aa2552b0806cfd308.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_DKL_dimian111.jpg"
dest_files=["res://.godot/imported/platform_DKL_dimian111.jpg-c39631cac4e1cc1aa2552b0806cfd308.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d4ivipjugyuqr"
path.s3tc="res://.godot/imported/platform_Godot_yanganqi.jpg-2afa7f3bb84666a93cbc91be92fba730.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_Godot_yanganqi.jpg"
dest_files=["res://.godot/imported/platform_Godot_yanganqi.jpg-2afa7f3bb84666a93cbc91be92fba730.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 378 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bq6p4qky4hvri"
path.s3tc="res://.godot/imported/platform_PBM_dandu_WUMING1.jpg-413386ed5a497e083284b10e1e5f923d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_PBM_dandu_WUMING1.jpg"
dest_files=["res://.godot/imported/platform_PBM_dandu_WUMING1.jpg-413386ed5a497e083284b10e1e5f923d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dk4vvknrcwfvr"
path.s3tc="res://.godot/imported/platform_QLS_qiangmian001.jpg-6a104d86c010c1b5fafed81ea997ae0f.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_QLS_qiangmian001.jpg"
dest_files=["res://.godot/imported/platform_QLS_qiangmian001.jpg-6a104d86c010c1b5fafed81ea997ae0f.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bg6xr40jjqp4k"
path.s3tc="res://.godot/imported/platform_haerbin_jz_menkuangyanse87.png-21cc209b4c0b1410d881df18062d8204.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_haerbin_jz_menkuangyanse87.png"
dest_files=["res://.godot/imported/platform_haerbin_jz_menkuangyanse87.png-21cc209b4c0b1410d881df18062d8204.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 173 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bgr2aan4t7hjn"
path.s3tc="res://.godot/imported/platform_haerbin_jz_wuzhanming.jpg-5fab5605d6646e259783c08d8bf2235d.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_haerbin_jz_wuzhanming.jpg"
dest_files=["res://.godot/imported/platform_haerbin_jz_wuzhanming.jpg-5fab5605d6646e259783c08d8bf2235d.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cbk3yy5d07an4"
path.s3tc="res://.godot/imported/platform_platform_haerbin_dandu_kongbai.jpg-f622e722f7041499de9aab939068a762.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/platform/platform_platform_haerbin_dandu_kongbai.jpg"
dest_files=["res://.godot/imported/platform_platform_haerbin_dandu_kongbai.jpg-f622e722f7041499de9aab939068a762.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,58 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://smgws0tjgxn0"
path="res://.godot/imported/screenDoor.gltf-2a7804e98628e0c27770453c210039f4.scn"
[deps]
source_file="res://Assets/models/screendoor/screenDoor.gltf"
dest_files=["res://.godot/imported/screenDoor.gltf-2a7804e98628e0c27770453c210039f4.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
import_script/path=""
_subresources={
"nodes": {
"PATH:CX1_CM1_Y": {
"import/skip_import": true
},
"PATH:CX1_CM1_Z": {
"import/skip_import": true
},
"PATH:JH_GD_JJTC": {
"import/skip_import": true
},
"PATH:JH_GD_MTD": {
"import/skip_import": true
},
"PATH:JH_GD_PSL": {
"import/skip_import": true
},
"PATH:PBM1_PBM1_Y": {
"import/skip_import": true
},
"PATH:PBM1_PBM1_Z": {
"import/skip_import": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=2

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cnlrebvyfclut"
path.s3tc="res://.godot/imported/screenDoor_dt12.png-892d68978e70a4be806ff93224f2addc.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/screendoor/screenDoor_dt12.png"
dest_files=["res://.godot/imported/screenDoor_dt12.png-892d68978e70a4be806ff93224f2addc.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bf2g7lwwpw20j"
path.s3tc="res://.godot/imported/screenDoor_dtnb2.jpg-ca214319985668ec5306eaef1c89aafb.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/screendoor/screenDoor_dtnb2.jpg"
dest_files=["res://.godot/imported/screenDoor_dtnb2.jpg-ca214319985668ec5306eaef1c89aafb.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

View File

@ -0,0 +1,36 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dgnm1fstl304k"
path.s3tc="res://.godot/imported/screenDoor_haerbin_jz_menkuangyanse87.png-6903df0f73aebbb4399e2ae103deeb80.s3tc.ctex"
metadata={
"imported_formats": ["s3tc_bptc"],
"vram_texture": true
}
generator_parameters={}
[deps]
source_file="res://Assets/models/screendoor/screenDoor_haerbin_jz_menkuangyanse87.png"
dest_files=["res://.godot/imported/screenDoor_haerbin_jz_menkuangyanse87.png-6903df0f73aebbb4399e2ae103deeb80.s3tc.ctex"]
[params]
compress/mode=2
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=true
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=0

Binary file not shown.

View File

@ -0,0 +1,34 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://bcf3gajson13b"
path="res://.godot/imported/PBMceshi.fbx-45fcb4bc9dddc37e79a3cdadb4450f0d.scn"
[deps]
source_file="res://Assets/models/screendoor1/PBMceshi.fbx"
dest_files=["res://.godot/imported/PBMceshi.fbx-45fcb4bc9dddc37e79a3cdadb4450f0d.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
import_script/path=""
_subresources={}
gltf/naming_version=1
gltf/embedded_image_handling=1

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,49 @@
[remap]
importer="scene"
importer_version=1
type="PackedScene"
uid="uid://biot7d8s87d3y"
path="res://.godot/imported/screenDoor.gltf-4281b97e561fd9ddbbabbdde45e6cb26.scn"
[deps]
source_file="res://Assets/models/screendoor1/screenDoor.gltf"
dest_files=["res://.godot/imported/screenDoor.gltf-4281b97e561fd9ddbbabbdde45e6cb26.scn"]
[params]
nodes/root_type=""
nodes/root_name=""
nodes/apply_root_scale=true
nodes/root_scale=1.0
meshes/ensure_tangents=true
meshes/generate_lods=true
meshes/create_shadow_meshes=true
meshes/light_baking=1
meshes/lightmap_texel_size=0.2
meshes/force_disable_compression=false
skins/use_named_skins=true
animation/import=true
animation/fps=30
animation/trimming=false
animation/remove_immutable_tracks=true
import_script/path=""
_subresources={
"nodes": {
"PATH:CX1_CM1_Y": {
"import/skip_import": true
},
"PATH:CX1_CM1_Z": {
"import/skip_import": true
},
"PATH:JH_GD_JJTC": {
"import/skip_import": true
},
"PATH:JH_GD_PSL": {
"import/skip_import": true
}
}
}
gltf/naming_version=1
gltf/embedded_image_handling=3

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<path d="m1 10v-4h5v-4l8 6-8 6v-4z" fill="#8da5f3" fill-opacity=".75" stroke="#8da5f3" stroke-linecap="square" stroke-miterlimit="3.2" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 299 B

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://ccvsqublgnwk0"
path="res://.godot/imported/Arrow.svg-b46ebbd21161668ed7fc97a1bf0ae30d.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/2d_shapes/Arrow.svg"
dest_files=["res://.godot/imported/Arrow.svg-b46ebbd21161668ed7fc97a1bf0ae30d.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="6" fill="#8da5f3" fill-opacity=".75" stroke="#8da5f3" stroke-width="2"/>
</svg>

After

Width:  |  Height:  |  Size: 243 B

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c02gsg1f7ra7j"
path="res://.godot/imported/Ellipse.svg-e4aaeb997f8842e6f1a13ab55b032b66.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/2d_shapes/Ellipse.svg"
dest_files=["res://.godot/imported/Ellipse.svg-e4aaeb997f8842e6f1a13ab55b032b66.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

21
addons/2d_shapes/LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Dener Rosa (Technocat Dev)
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:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
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.

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://bwefvbkl1pprc"
path="res://.godot/imported/Node2D.svg-0add0097836c9633a7297abed46e1eeb.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/2d_shapes/Node2D.svg"
dest_files=["res://.godot/imported/Node2D.svg-0add0097836c9633a7297abed46e1eeb.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
<rect x="2.9231" y="2.9231" width="10.154" height="10.154" fill="#8da5f3" fill-opacity=".75" stroke="#8da5f3" stroke-linecap="square" stroke-miterlimit="3.2" stroke-width="1.8462"/>
</svg>

After

Width:  |  Height:  |  Size: 327 B

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c57gmrid7ke0b"
path="res://.godot/imported/Rectangle.svg-36544af2e53ec1a165ec7b3fc3c2b2d0.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/2d_shapes/Rectangle.svg"
dest_files=["res://.godot/imported/Rectangle.svg-36544af2e53ec1a165ec7b3fc3c2b2d0.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

View File

@ -0,0 +1,32 @@
extends "res://addons/2d_shapes/handles/ScalarHandle.gd"
const ScalarHandle = preload("ScalarHandle.gd")
const Arrow = preload("../shapes/Arrow.gd")
var square: bool
func _init(selected_shape: Arrow, position: Vector2, scalar_: String, axis_: Vector2 = Vector2.DOWN, square_: bool = false):
super(selected_shape, position, scalar_, axis_)
var transform_viewport := selected_shape.get_viewport_transform()
var transform_global := selected_shape.get_global_transform_with_canvas()
var target = selected_shape.target
var arrow_rotation := target.angle() + PI / 2
var arrow_transform := Transform2D(arrow_rotation, target)
var handle_position := transform_viewport * transform_global * arrow_transform * position
transform = Transform2D(arrow_rotation, handle_position)
square = square_
func draw(overlay: Control):
if square:
var global_rotation := shape.global_rotation
overlay.draw_set_transform_matrix(transform.rotated_local(global_rotation))
var rect := Rect2(Vector2(2,2), Vector2(4,4))
overlay.draw_rect(Rect2(Vector2(-5,-5), Vector2(10,10)), Color.BLACK)
overlay.draw_rect(Rect2(Vector2(-4,-4), Vector2(8,8)), Color.WHITE)
overlay.draw_rect(Rect2(Vector2(-3,-3), Vector2(6,6)), Color.ORANGE_RED)
overlay.draw_set_transform_matrix(Transform2D())
else:
super.draw(overlay)

View File

@ -0,0 +1,38 @@
extends Node
const GeometricShape = preload("../shapes/GeometricShape.gd")
var transform: Transform2D
var shape: GeometricShape
func get_local_mouse_position() -> Vector2:
var event_position = shape.get_viewport().get_mouse_position()
var global_transform = shape.get_global_transform_with_canvas()
return global_transform.affine_inverse() * transform.affine_inverse() * event_position
func draw(overlay: Control) -> void:
printerr('Function overlay was not implemented')
pass
func start_drag(event: InputEventMouseButton) -> void:
printerr('Function start_drag was not implemented')
pass
func drag(event: InputEventMouseMotion) -> void:
printerr('Function drag was not implemented')
pass
func end_drag(undo_redo: EditorUndoRedoManager) -> void:
printerr('Function end_drag was not implemented')
pass
func on_shift_pressed(is_pressed: bool) -> void:
pass

View File

@ -0,0 +1,57 @@
extends Handle
const Handle = preload("Handle.gd")
const triangle_height_proportion = sqrt(3.0) / 2.0
var scalar: String
var axis: Vector2
var drag_start : Dictionary = {
'mouse_position': Vector2()
}
func _init(selected_shape: GeometricShape, position: Vector2, scalar_: String, axis_: Vector2 = Vector2.DOWN):
var transform_viewport := selected_shape.get_viewport_transform()
var transform_global := selected_shape.get_global_transform_with_canvas()
var pos = transform_viewport * transform_global * position
shape = selected_shape
scalar = scalar_
axis = axis_
transform = Transform2D(0.0, pos)
func draw(overlay: Control):
overlay.draw_set_transform_matrix(transform)
overlay.draw_circle(Vector2.ZERO, 6, Color.BLACK)
overlay.draw_circle(Vector2.ZERO, 5, Color.WHITE)
overlay.draw_circle(Vector2.ZERO, 4, Color.ROYAL_BLUE)
overlay.draw_set_transform_matrix(Transform2D())
func start_drag(event: InputEventMouseButton):
drag_start = {
scalar: shape[scalar],
'mouse_position': get_local_mouse_position()
}
func drag(event: InputEvent) -> void:
var event_position = get_local_mouse_position()
var drag_delta: Vector2 = event_position - drag_start['mouse_position']
shape[scalar] = drag_start[scalar] + drag_delta.dot(axis)
shape.queue_redraw()
func end_drag(undo_redo: EditorUndoRedoManager):
undo_redo.create_action("Set %s to %s" % [scalar, shape[scalar]])
undo_redo.add_do_property(shape, scalar, shape[scalar])
undo_redo.add_do_method(shape, "generate_geometry")
undo_redo.add_undo_property(shape, scalar, drag_start[scalar])
undo_redo.add_undo_method(shape, "generate_geometry")
undo_redo.commit_action()

View File

@ -0,0 +1,114 @@
extends Handle
const Handle = preload("Handle.gd")
const position_offsets := [
Vector2(-0.5, -0.5),
Vector2(0, -0.5),
Vector2(0.5, -0.5),
Vector2(0.5, 0),
Vector2(0.5, 0.5),
Vector2(0, 0.5),
Vector2(-0.5, 0.5),
Vector2(-0.5, 0)
]
const size_transforms := [
-Vector2.ONE,
Vector2.UP,
Vector2(1, -1),
Vector2.RIGHT,
Vector2.ONE,
Vector2.DOWN,
Vector2(-1, 1),
Vector2.LEFT,
]
var _index: int
var size_transform: Vector2
var keep_aspect_ratio := false
# previous drag state
var drag_start : Dictionary = {
'size': Vector2(),
'transform': Transform2D(),
'position': Vector2(),
'mouse_position': Vector2()
}
func _init(selected_shape: GeometricShape, index: int):
var transform_viewport := selected_shape.get_viewport_transform()
var transform_global := selected_shape.get_global_transform_with_canvas()
var pos = transform_viewport * transform_global * (position_offsets[index] * selected_shape.size)
shape = selected_shape
transform = Transform2D(0.0, pos)
_index = index
size_transform = size_transforms[index]
func draw(overlay: Control):
var global_rotation := shape.global_rotation
overlay.draw_set_transform_matrix(transform.rotated_local(global_rotation))
var rect := Rect2(Vector2(2,2), Vector2(4,4))
overlay.draw_rect(Rect2(Vector2(-5,-5), Vector2(10,10)), Color.BLACK)
overlay.draw_rect(Rect2(Vector2(-4,-4), Vector2(8,8)), Color.WHITE)
overlay.draw_rect(Rect2(Vector2(-3,-3), Vector2(6,6)), Color.ORANGE_RED)
if _index == 0:
var transform_global := shape.get_global_transform_with_canvas()
var transform_viewport := shape.get_viewport_transform()
var scale_total := transform_viewport.get_scale() * transform_global.get_scale()
var bounding_rect = Rect2(Vector2.ZERO, scale_total * shape.size)
overlay.draw_rect(bounding_rect, Color.ORANGE_RED, false, 1)
overlay.draw_set_transform_matrix(Transform2D())
func start_drag(event: InputEventMouseButton):
drag_start = {
'size': shape.size,
'transform': shape.get_global_transform_with_canvas(),
'position': shape.position,
'mouse_position': get_local_mouse_position()
}
func drag(event: InputEvent) -> void:
var event_position = drag_start_get_local_mouse_position()
var drag_delta: Vector2 = event_position - drag_start['mouse_position']
var new_size = drag_start['size'] + drag_delta * size_transform
if shape.is_fixed_aspect_ratio() or keep_aspect_ratio:
var fit_x := Vector2(new_size.x, new_size.x / drag_start['size'].aspect())
var fit_y := Vector2(new_size.y * drag_start['size'].aspect(), new_size.y)
shape.size = fit_x if size_transform.x else fit_y
else:
shape.size = new_size
var delta_size = shape.size - drag_start['size']
# Transform proportionally to size change
var position_transform = position_offsets[_index]
shape.position = drag_start['position'] + shape.transform.basis_xform(position_transform * delta_size)
shape.queue_redraw()
func drag_start_get_local_mouse_position():
var event_position = shape.get_viewport().get_mouse_position()
var global_transform = drag_start['transform']
return global_transform.affine_inverse() * transform.affine_inverse() * event_position
func end_drag(undo_redo: EditorUndoRedoManager):
undo_redo.create_action("Resize shape to %s" % shape.size)
undo_redo.add_do_property(shape, "size", shape.size)
undo_redo.add_do_property(shape, "position", shape.position)
undo_redo.add_do_method(shape, "generate_geometry")
undo_redo.add_undo_property(shape, "size", drag_start['size'])
undo_redo.add_undo_property(shape, "position", drag_start['position'])
undo_redo.add_undo_method(shape, "generate_geometry")
undo_redo.commit_action()
func on_shift_pressed(is_pressed: bool):
keep_aspect_ratio = is_pressed

View File

@ -0,0 +1,78 @@
extends Handle
const Handle = preload("Handle.gd")
const Arrow = preload("../shapes/Arrow.gd")
const triangle_height_proportion = sqrt(3.0) / 2.0
var drag_start : Dictionary = {
'target': Vector2(),
'mouse_position': Vector2()
}
var snap_angle := false
func _init(selected_shape: Arrow):
var transform_viewport := selected_shape.get_viewport_transform()
var transform_global := selected_shape.get_global_transform_with_canvas()
var target = selected_shape.target
var arrow_rotation := target.angle() + PI / 2
var arrow_transform := Transform2D(arrow_rotation, target)
var handle_position = transform_viewport * transform_global * arrow_transform * Vector2()
transform = Transform2D(0.0, handle_position)
shape = selected_shape
func draw(overlay: Control):
var transform_global := shape.get_global_transform_with_canvas()
var transformed_target := transform_global.basis_xform(shape.target)
var arrow_rotation := transformed_target.angle() + PI / 2
overlay.draw_set_transform_matrix(transform.rotated_local(arrow_rotation))
overlay.draw_colored_polygon(triangle(14.0), Color.BLACK)
overlay.draw_colored_polygon(triangle(11.0), Color.WHITE)
overlay.draw_colored_polygon(triangle(8.0), Color.ORANGE_RED)
overlay.draw_set_transform_matrix(Transform2D())
func triangle(height: float) -> PackedVector2Array:
var side = height / triangle_height_proportion
return [
Vector2(-side / 2, height / 2),
Vector2(0, -height / 2),
Vector2(side / 2, height / 2),
]
func start_drag(event: InputEventMouseButton):
drag_start = {
'target': shape.target,
'mouse_position': get_local_mouse_position()
}
func drag(event: InputEvent) -> void:
var event_position = get_local_mouse_position()
var drag_delta: Vector2 = event_position - drag_start['mouse_position']
var new_target: Vector2 = drag_start['target'] + drag_delta
if snap_angle:
var modulo := fmod(new_target.angle() + shape.global_rotation + TAU - PI / 24, PI / 12)
var angle := new_target.angle() - modulo + PI / 24
shape.target = new_target.length() * Vector2(cos(angle), sin(angle))
else:
shape.target = new_target
shape.queue_redraw()
func end_drag(undo_redo: EditorUndoRedoManager):
undo_redo.create_action("Set target to %s" % shape.target)
undo_redo.add_do_property(shape, "target", shape.target)
undo_redo.add_do_method(shape, "generate_geometry")
undo_redo.add_undo_property(shape, "target", drag_start['target'])
undo_redo.add_undo_method(shape, "generate_geometry")
undo_redo.commit_action()
func on_shift_pressed(is_pressed: bool) -> void:
snap_angle = is_pressed

View File

@ -0,0 +1,7 @@
[plugin]
name="2D Shapes"
description="Geometric shapes for prototyping and animation"
author="Technocat Dev"
version="0.1.0"
script="plugin.gd"

View File

@ -0,0 +1,93 @@
@tool
extends EditorPlugin
const GeometricShape = preload("./shapes/GeometricShape.gd")
const Handle = preload("./handles/Handle.gd")
var selected_shape: GeometricShape
var dragged_handle: Handle = null
var handles : Array
var is_holding_shift := false
#== node ==
func _enter_tree() -> void:
add_custom_type("Rectangle", "Node2D", preload("./shapes/Rectangle.gd"), preload("Rectangle.svg"))
add_custom_type("Ellipse", "Node2D", preload("./shapes/Ellipse.gd"), preload("Ellipse.svg"))
add_custom_type("Arrow", "Node2D", preload("./shapes/Arrow.gd"), preload("Arrow.svg"))
add_undo_redo_inspector_hook_callback(undo_redo_callback)
func _exit_tree() -> void:
remove_custom_type("Rectangle")
remove_custom_type("Ellipse")
remove_custom_type("Arrow")
remove_undo_redo_inspector_hook_callback(undo_redo_callback)
#== plugin ==
var undo_redo_callback = func (undo_redo: Object, modified_object:Object, property: String, new_value: Variant):
if modified_object is GeometricShape:
update_overlays()
func _handles(object : Object) -> bool:
return object is GeometricShape
func _edit(object: Object) -> void:
if object is GeometricShape:
selected_shape = object
update_overlays()
func _make_visible(visible : bool) -> void:
if not selected_shape:
return
if not visible:
selected_shape = null
update_overlays()
#== drawing handles ==
func _forward_canvas_draw_over_viewport(overlay: Control) -> void:
if selected_shape and selected_shape.is_inside_tree():
handles = selected_shape.draw_handles(overlay)
func _forward_canvas_gui_input(event: InputEvent) -> bool:
if not selected_shape or not selected_shape.visible:
return false
# Clicking and releasing the click
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
for handle: Handle in handles:
if not handle.transform.origin.distance_to(event.position) < 10:
continue
handle.start_drag(event)
dragged_handle = handle
dragged_handle.on_shift_pressed(is_holding_shift)
return true
elif dragged_handle:
dragged_handle.drag(event)
dragged_handle.end_drag(get_undo_redo())
dragged_handle = null
return true
# Dragging
if event is InputEventMouseMotion and dragged_handle:
dragged_handle.drag(event)
update_overlays()
return true
# Pressing Shift
if event is InputEventKey and event.keycode == KEY_SHIFT:
is_holding_shift = event.is_pressed()
if dragged_handle:
dragged_handle.on_shift_pressed(event.is_pressed())
return true
return false

View File

@ -0,0 +1,157 @@
@tool
@icon("res://addons/2d_shapes/Arrow.svg")
class_name Arrow extends GeometricShape
const GeometricShape = preload("GeometricShape.gd")
const TargetHandle = preload("../handles/TargetHandle.gd")
const ArrowScalarHandle = preload("../handles/ArrowScalarHandle.gd")
const default_corner_radius := 10.0
@export var target: Vector2 = Vector2.RIGHT * default_corner_radius * 10:
get:
return target
set(value):
var min_length := head_length + corner_radius
target = value if value.length() > min_length else min_length * value.normalized()
generate_geometry()
@export var corner_radius: float = default_corner_radius:
get:
return corner_radius
set(value):
corner_radius = clamp(value, 0, min(head_width - stem_width, head_length, stem_width) / 2)
generate_geometry()
@export var head_length: float = default_corner_radius * 5:
get:
return head_length
set(value):
var arrow_length = target.length()
head_length = clamp(value, corner_radius * 2, arrow_length - corner_radius)
generate_geometry()
@export var head_width: float = default_corner_radius * 6:
get:
return head_width
set(value):
head_width = clamp(value, corner_radius * 2 + stem_width, 10000)
generate_geometry()
@export var stem_width: float = default_corner_radius * 2:
get:
return stem_width
set(value):
stem_width = clamp(value, 2 * corner_radius, head_width - 2 * corner_radius)
generate_geometry()
func _ready():
generate_geometry()
func generate_geometry():
var arrow_rotation := -target.angle() - PI / 2
var arrow_length := target.length()
var head_transform := Transform2D(arrow_rotation, Vector2(0, arrow_length))
var nock_transform := Transform2D(arrow_rotation, Vector2.ZERO)
polygon = head(head_transform)
polygon.append_array(nock(nock_transform))
queue_redraw()
func head(head_transform: Transform2D) -> PackedVector2Array:
# Find circles' centers
var left_circle_center = Vector2(-head_width / 2 + corner_radius, head_length - corner_radius)
var top_circle_center = Vector2(0, corner_radius)
var right_circle_center = Vector2(head_width / 2 - corner_radius, head_length - corner_radius)
var points: PackedVector2Array = [Vector2(-stem_width / 2, head_length)]
# Left
var left_start_angle = 3 * PI / 2
var left_end_angle = -left_circle_center.angle_to_point(top_circle_center) + PI / 2
points.append_array(arc(left_start_angle, left_end_angle, left_circle_center, corner_radius))
# Top
var top_end_angle = -left_end_angle + PI
points.append_array(arc(left_end_angle, top_end_angle, top_circle_center, corner_radius))
# Right
points.append_array(arc(top_end_angle, left_start_angle, right_circle_center, corner_radius))
points.append(Vector2(stem_width / 2, head_length))
for i in range(points.size()):
points[i] *= head_transform
return points
func nock(nock_transform: Transform2D) -> PackedVector2Array:
var center_x = stem_width / 2 - corner_radius
var points: PackedVector2Array = arc(0.0, -PI / 2, Vector2(center_x, -corner_radius), corner_radius)
points.append_array(arc(-PI / 2, PI, Vector2(-center_x, -corner_radius), corner_radius))
for i in range(points.size()):
points[i] *= nock_transform
return points
func draw_handles(overlay: Control) -> Array:
var arrow_length := target.length()
var handles = []
handles.push_back(TargetHandle.new(self))
handles.push_back(ArrowScalarHandle.new(self, Vector2(head_width / 2 - corner_radius, head_length), 'corner_radius', Vector2.LEFT))
handles.push_back(ArrowScalarHandle.new(self, Vector2(0, head_length), 'head_length', Vector2.DOWN, true))
handles.push_back(ArrowScalarHandle.new(self, Vector2(-head_width / 2, head_length - corner_radius), 'head_width', Vector2.LEFT * 2, true))
handles.push_back(ArrowScalarHandle.new(self, Vector2(stem_width / 2, head_length + (arrow_length - head_length - corner_radius) / 2), 'stem_width', Vector2.RIGHT * 2, true))
for i in range(handles.size() - 1, -1, -1):
handles[i].draw(overlay)
return handles
#func round_corners(points: PackedVector2Array) -> PackedVector2Array:
#var new_points: PackedVector2Array = [points[0]]
#for i in range(0, points.size() - 2):
#var point1: Vector2 = points[i]
#var point2: Vector2 = points[i + 1]
#var point3: Vector2 = points[i + 2]
#
#var line_1_angle = positive_angle(-point2.angle_to_point(point1))
#var line_2_angle = positive_angle(-point2.angle_to_point(point3))
#var midway_angle = (line_1_angle + line_2_angle) / 2.0
#var half_inside_angle = angle_difference(line_1_angle, line_2_angle) / 2.0
#
#var center_distance = corner_radius / sin(half_inside_angle)
#
#var circle_center = point2 + center_distance * Vector2(cos(midway_angle), -sin(midway_angle))
#
#var corner_points = corner(line_1_angle - PI / 2, line_2_angle + PI / 2, circle_center)
#new_points.append_array(corner_points)
#new_points.append(points[-1])
#
#return new_points
#func max_corner_radius(points: PackedVector2Array) -> float:
#var result = INF
#for i in range(0, points.size() - 2):
#var point1: Vector2 = points[i]
#var point2: Vector2 = points[i + 1]
#var point3: Vector2 = points[i + 2]
#
#var line_1_angle = positive_angle(-point2.angle_to_point(point1))
#var line_2_angle = positive_angle(-point2.angle_to_point(point3))
#var half_inside_angle = angle_difference(line_1_angle, line_2_angle) / 2.0
#
#var distance_1 := point2.distance_to(point1) if i == 0 else point2.distance_to(point1) / 2
#var distance_2 := point2.distance_to(point3) if i == points.size() - 3 else point2.distance_to(point3) / 2
#var max_radius = min(distance_1 * tan(half_inside_angle), distance_2 * tan(half_inside_angle))
#result = min(result, max_radius)
#return result

View File

@ -0,0 +1,65 @@
@tool
@icon("res://addons/2d_shapes/Ellipse.svg")
class_name Ellipse
extends GeometricShape
const GeometricShape = preload("GeometricShape.gd")
const SizeHandle = preload("../handles/SizeHandle.gd")
const default_size := 60.0
func _ready():
generate_geometry()
@export var size: Vector2 = Vector2(default_size, default_size):
get:
return size
set(value):
if circle:
var fit_x := Vector2(value.x, value.x)
var fit_y := Vector2(value.y, value.y)
value = fit_x if size.y == value.y else fit_y
size.x = clamp(value.x, 3, 10000)
size.y = clamp(value.y, 3, 10000)
generate_geometry()
@export var circle: bool = false:
get:
return circle
set(value):
circle = value
size = size
func is_fixed_aspect_ratio() -> bool:
return circle
func generate_geometry():
polygon = arc(TAU, 0, Vector2.ZERO, min(size.x, size.y) / 2)
for i in range(polygon.size()):
polygon[i][size.max_axis_index()] *= max(size.x, size.y) / min(size.x, size.y)
queue_redraw()
func draw_handles(overlay: Control) -> Array:
var handles = []
# Starting from top-left, clockwise order.
for i in range(8):
handles.push_back(SizeHandle.new(self, i))
# On click, the first handle on the array has priority. Visuals should reflect
# that by drawing the first handle on top.
for i in range(handles.size() - 1, -1, -1):
handles[i].draw(overlay)
return handles

View File

@ -0,0 +1,87 @@
extends Node2D
var polygon : PackedVector2Array
@export_enum("Filled", "Outline", "Filled + Outline") var style: int = 0:
get:
return style
set(value):
style = value
queue_redraw()
@export var outline_width: int = 1:
get:
return outline_width
set(value):
outline_width = clamp(value, 0.01, 1000)
queue_redraw()
@export var fill_color: Color = Color.WHITE:
get:
return fill_color
set(value):
fill_color = value
queue_redraw()
@export var outline_color: Color = Color.BLACK:
get:
return outline_color
set(value):
outline_color = value
queue_redraw()
func _draw():
if style == 0 or style == 2:
# Polygon is assumed to be open, i.e. its last vertex is not equal the first
# Closed polygons may fail triangulation!
draw_colored_polygon(polygon, fill_color)
if style == 1 or style == 2:
var closed_polygon = polygon.duplicate()
closed_polygon.push_back(polygon[0])
draw_polyline(closed_polygon, outline_color, outline_width)
func arc(start: float, end: float, center: Vector2, radius: float) -> PackedVector2Array:
"""Draw arc in clockwise direction"""
if radius < 0.01: # Skip drawing if radius is too close to zero
return [center]
if start < end:
start += TAU
var step: float = max(asin(4 / radius), 0.1) # Trying to keep distance between points at ~4
var angle := start - step
var coords: PackedVector2Array = []
var start_point = Vector2(cos(start) * radius + center.x, -sin(start) * radius + center.y)
var end_point = Vector2(cos(end) * radius + center.x, -sin(end) * radius + center.y)
coords.push_back(start_point)
while angle > end:
var point = Vector2(cos(angle) * radius + center.x, -sin(angle) * radius + center.y)
if not point.distance_squared_to(end_point) < 8.0:
coords.push_back(point)
angle -= step
coords.push_back(end_point)
return coords
func draw_handles(overlay: Control) -> Array:
printerr('Function draw_handles was not implemented')
return []
func generate_geometry() -> void:
printerr('Function generate_geometry was not implemented')
func is_fixed_aspect_ratio() -> bool:
printerr('Function is_fixed_aspect_ratio was not implemented')
return false

View File

@ -0,0 +1,95 @@
@tool
@icon("res://addons/2d_shapes/Rectangle.svg")
class_name Rectangle
extends GeometricShape
const GeometricShape = preload("GeometricShape.gd")
const Handle = preload("../handles/Handle.gd")
const SizeHandle = preload("../handles/SizeHandle.gd")
const ScalarHandle = preload("../handles/ScalarHandle.gd")
const default_corner_radius := 20.0
const default_size := default_corner_radius * 3.0
func _ready():
generate_geometry()
@export var size: Vector2 = Vector2(default_size, default_size):
get:
return size
set(value):
if square:
var fit_x := Vector2(value.x, value.x)
var fit_y := Vector2(value.y, value.y)
value = fit_x if size.y == value.y else fit_y
size.x = clamp(value.x, corner_radius * 2, 10000)
size.y = clamp(value.y, corner_radius * 2, 10000)
generate_geometry()
@export var corner_radius: float = default_corner_radius:
get:
return corner_radius
set(value):
corner_radius = clamp(value, 0.0, size[size.min_axis_index()] / 2)
generate_geometry()
@export var square: bool = false:
get:
return square
set(value):
square = value
size = size
func is_fixed_aspect_ratio() -> bool:
return square
func generate_geometry():
polygon = []
polygon.append_array(top_left_corner())
polygon.append_array(top_right_corner())
polygon.append_array(bottom_right_corner())
polygon.append_array(bottom_left_corner())
for i in range(polygon.size()):
polygon[i] -= size / 2
queue_redraw()
func top_left_corner() -> PackedVector2Array:
return arc(PI, PI/2, Vector2(corner_radius, corner_radius), corner_radius)
func top_right_corner() -> Array:
return arc(PI/2, 0, Vector2(size.x - corner_radius, corner_radius), corner_radius)
func bottom_right_corner() -> Array:
return arc(2 * PI, 1.5 * PI, Vector2(size.x - corner_radius, size.y - corner_radius), corner_radius)
func bottom_left_corner() -> Array:
return arc(1.5 * PI, PI, Vector2(corner_radius, size.y - corner_radius), corner_radius)
func draw_handles(overlay: Control) -> Array:
var half_size := size / 2
var handles = []
handles.push_back(ScalarHandle.new(self, Vector2(half_size.x, -half_size.y + corner_radius), 'corner_radius'))
# Starting from top-left, clockwise order.
for i in range(8):
handles.push_back(SizeHandle.new(self, i))
# On click, the first handle on the array has priority. Visuals should reflect
# that by drawing the first handle on top.
for i in range(handles.size() - 1, -1, -1):
handles[i].draw(overlay)
return handles

View File

@ -0,0 +1,56 @@
extends Node
class_name Spherical
var radius: float
var phi: float
var theta: float
func _init(_radius: float = 1, _phi: float = 0, _theta: float = 0):
radius = _radius
phi = _phi
theta = _theta
func set_to(_radius: float, _phi: float, _theta: float):
radius = _radius
phi = _phi
theta = _theta
func copy(_other_spherical: Spherical):
radius = _other_spherical._radius
phi = _other_spherical._phi
theta = _other_spherical._theta
func make_safe() -> void:
var precision: float = 0.0000000000001
phi = max(precision, min(PI - precision, phi))
func set_from_vector(v: Vector3):
self.set_from_cartesian_coords(v.x, v.y, v.z)
func dampen(damping_factor:float) ->bool:
theta *= (1 - damping_factor)
phi *= (1 - damping_factor)
if abs(theta) < 0.001:
theta = 0.0
if abs(phi) < 0.001:
phi = 0.0
if theta == 0 and phi == 0:
radius = 0
return abs(theta) > 0 or abs(phi) > 0
func set_from_cartesian_coords(x: float, y: float, z: float):
radius = sqrt(x * x + y * y + z * z)
if radius == 0:
theta = 0
phi = 0
else:
theta = atan2(x, z)
phi = acos(clamp(y / radius, -1, 1))
func apply_to_vector(vector: Vector3) -> Vector3:
var sin_phi_radius = sin(phi) * radius
vector.x = sin_phi_radius * sin(theta)
vector.y = cos(phi) * radius
vector.z = sin_phi_radius * cos(theta)
return vector

View File

@ -0,0 +1,398 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="100mm"
height="100mm"
viewBox="0 0 100 100"
version="1.1"
id="svg5"
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
sodipodi:docname="godot-orbit-controls.svg"
inkscape:export-filename="C:\Users\Luca\repos\godot_orbit_controls\icon-432-foreground.png"
inkscape:export-xdpi="109.728"
inkscape:export-ydpi="109.728"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="true"
inkscape:document-units="mm"
showgrid="false"
inkscape:snap-bbox="true"
inkscape:bbox-paths="true"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="true"
inkscape:snap-bbox-midpoints="true"
inkscape:object-paths="true"
inkscape:snap-intersection-paths="true"
inkscape:snap-midpoints="true"
inkscape:snap-smooth-nodes="true"
inkscape:snap-object-midpoints="true"
inkscape:snap-center="true"
inkscape:snap-text-baseline="true"
inkscape:snap-page="true"
inkscape:zoom="1.4854841"
inkscape:cx="122.85557"
inkscape:cy="173.68075"
inkscape:window-width="1920"
inkscape:window-height="1009"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="layer2"
showguides="true"
inkscape:guide-bbox="true">
<inkscape:grid
type="xygrid"
id="grid6909" />
</sodipodi:namedview>
<defs
id="defs2">
<marker
style="overflow:visible"
id="marker1226"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="scale(0.3) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round"
id="path1224" />
</marker>
<marker
style="overflow:visible;"
id="marker1216"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="scale(0.2) rotate(180) translate(6,0)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt;"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path1214" />
</marker>
<marker
style="overflow:visible;"
id="Arrow1Send"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow1Send"
inkscape:isstock="true">
<path
transform="scale(0.2) rotate(180) translate(6,0)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt;"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
id="path901" />
</marker>
<marker
style="overflow:visible"
id="marker1198"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="scale(0.3) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round"
id="path916" />
</marker>
<marker
style="overflow:visible;"
id="marker1189"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Send"
inkscape:isstock="true">
<path
transform="scale(0.3) rotate(180) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round;"
id="path919" />
</marker>
<marker
style="overflow:visible"
id="marker1180"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleOutS"
inkscape:isstock="true">
<path
transform="scale(0.2)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1178" />
</marker>
<marker
style="overflow:visible"
id="EmptyTriangleInS"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="EmptyTriangleInS"
inkscape:isstock="true">
<path
transform="scale(-0.2) translate(-3.0,0)"
style="fill-rule:evenodd;fill:context-fill;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1043" />
</marker>
<marker
style="overflow:visible"
id="EmptyTriangleOutM"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="EmptyTriangleOutM"
inkscape:isstock="true">
<path
transform="scale(0.4) translate(-4.5,0)"
style="fill-rule:evenodd;fill:context-fill;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1049" />
</marker>
<marker
style="overflow:visible"
id="Scissors"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Scissors"
inkscape:isstock="true">
<path
style="fill:context-stroke;"
d="M 9.0898857,-3.6061018 C 8.1198849,-4.7769976 6.3697607,-4.7358294 5.0623558,-4.2327734 L -3.1500488,-1.1548705 C -5.5383421,-2.4615840 -7.8983361,-2.0874077 -7.8983361,-2.7236578 C -7.8983361,-3.2209742 -7.4416699,-3.1119800 -7.5100293,-4.4068519 C -7.5756648,-5.6501286 -8.8736064,-6.5699315 -10.100428,-6.4884954 C -11.327699,-6.4958500 -12.599867,-5.5553341 -12.610769,-4.2584343 C -12.702194,-2.9520479 -11.603560,-1.7387447 -10.304005,-1.6532027 C -8.7816644,-1.4265411 -6.0857470,-2.3487593 -4.8210600,-0.082342643 C -5.7633447,1.6559151 -7.4350844,1.6607341 -8.9465707,1.5737277 C -10.201445,1.5014928 -11.708664,1.8611256 -12.307219,3.0945882 C -12.885586,4.2766744 -12.318421,5.9591904 -10.990470,6.3210002 C -9.6502788,6.8128279 -7.8098011,6.1912892 -7.4910978,4.6502760 C -7.2454393,3.4624530 -8.0864637,2.9043186 -7.7636052,2.4731223 C -7.5199917,2.1477623 -5.9728246,2.3362771 -3.2164999,1.0982979 L 5.6763468,4.2330688 C 6.8000164,4.5467672 8.1730685,4.5362646 9.1684433,3.4313614 L -0.051640930,-0.053722219 L 9.0898857,-3.6061018 z M -9.2179159,-5.5066058 C -7.9233569,-4.7838060 -8.0290767,-2.8230356 -9.3743431,-2.4433169 C -10.590861,-2.0196559 -12.145370,-3.2022863 -11.757521,-4.5207817 C -11.530373,-5.6026336 -10.104134,-6.0014137 -9.2179159,-5.5066058 z M -9.1616516,2.5107591 C -7.8108215,3.0096239 -8.0402087,5.2951947 -9.4138723,5.6023681 C -10.324932,5.9187072 -11.627422,5.4635705 -11.719569,4.3902287 C -11.897178,3.0851737 -10.363484,1.9060805 -9.1616516,2.5107591 z "
id="schere" />
</marker>
<marker
style="overflow:visible"
id="TriangleOutS"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleOutS"
inkscape:isstock="true">
<path
transform="scale(0.2)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path1034" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Sstart"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Sstart"
inkscape:isstock="true">
<path
transform="scale(0.3) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round"
id="path5281" />
</marker>
<marker
style="overflow:visible"
id="marker8294"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleInS"
inkscape:isstock="true">
<path
transform="scale(-0.2)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path8292" />
</marker>
<marker
style="overflow:visible"
id="marker8202"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleInS"
inkscape:isstock="true">
<path
transform="scale(-0.2)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path8200" />
</marker>
<marker
style="overflow:visible;"
id="Arrow2Send"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Send"
inkscape:isstock="true">
<path
transform="scale(0.3) rotate(180) translate(-2.3,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round;"
id="path5284" />
</marker>
<marker
style="overflow:visible"
id="TriangleInS"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="TriangleInS"
inkscape:isstock="true">
<path
transform="scale(-0.2)"
style="fill-rule:evenodd;fill:context-stroke;stroke:context-stroke;stroke-width:1.0pt"
d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
id="path5390" />
</marker>
<marker
style="overflow:visible"
id="Arrow2Lstart"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Lstart"
inkscape:isstock="true">
<path
transform="scale(1.1) translate(1,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round"
id="path5269" />
</marker>
<marker
style="overflow:visible;"
id="Arrow2Lend"
refX="0.0"
refY="0.0"
orient="auto"
inkscape:stockid="Arrow2Lend"
inkscape:isstock="true">
<path
transform="scale(1.1) rotate(180) translate(1,0)"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
style="fill-rule:evenodd;fill:context-stroke;stroke-width:0.62500000;stroke-linejoin:round;"
id="path5272" />
</marker>
</defs>
<g
inkscape:label="Layer"
inkscape:groupmode="layer"
id="layer1"
style="display:none">
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891"
cx="12.5"
cy="12.5"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-1"
cx="65.533005"
cy="34.466991"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-2"
cx="12.5"
cy="87.5"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-29"
cx="87.5"
cy="87.5"
r="12.5" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 H 87.499999"
id="path6313" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 V 12.5"
id="path6512" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 65.533008,34.466992"
id="path6512-6" />
</g>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="Foreground"
style="display:inline">
<g
id="g1025"
transform="matrix(0.39797964,0,0,0.39797964,30.101018,30.101018)">
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-21"
cx="12.5"
cy="12.5"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-1-4"
cx="65.533005"
cy="34.466991"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-2-3"
cx="12.5"
cy="87.5"
r="12.5" />
<circle
style="fill:#a5efac;fill-opacity:1;stroke:none;stroke-width:78.1248;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:normal"
id="path5891-29-2"
cx="87.5"
cy="87.5"
r="12.5" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 H 87.499999"
id="path6313-7" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 V 12.5"
id="path6512-4" />
<path
style="fill:none;stroke:#a5efac;stroke-width:12.5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 12.5,87.499999 65.533008,34.466992"
id="path6512-6-6" />
</g>
</g>
<g
inkscape:groupmode="layer"
id="g1043"
inkscape:label="Background"
style="display:none">
<rect
style="fill:#262c3b;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.264583"
id="rect1147"
width="100"
height="100"
x="0"
y="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -0,0 +1,37 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dfiu3jqg4w85u"
path="res://.godot/imported/godot-orbit-controls.svg-88feaaf0a954aecc34fd3f505575a187.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/orbit-controls/godot-orbit-controls.svg"
dest_files=["res://.godot/imported/godot-orbit-controls.svg-88feaaf0a954aecc34fd3f505575a187.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1
svg/scale=1.0
editor/scale_with_editor_scale=false
editor/convert_colors_with_editor_theme=false

Binary file not shown.

After

Width:  |  Height:  |  Size: 391 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://d20432vdtcyfj"
path="res://.godot/imported/node-icon.png-4ab6d8b229d64bf1f2a5d02276cf9ecd.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/orbit-controls/node-icon.png"
dest_files=["res://.godot/imported/node-icon.png-4ab6d8b229d64bf1f2a5d02276cf9ecd.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -0,0 +1,865 @@
@tool
extends Control
# SIGNALS #
signal start
signal change
signal end
# ENUMS #
enum MOUSE {
LEFT = 0,
MIDDLE = 1,
RIGHT = 2,
ROTATE = 0,
DOLLY = 1,
PAN = 2
}
enum STATE {
NONE = 0,
ROTATE = 1,
DOLLY = 2,
PAN = 3,
TOUCH_ROTATE = 4,
TOUCH_PAN = 5,
TOUCH_DOLLY_PAN = 6,
TOUCH_DOLLY_ROTATE = 7
}
enum TOUCH {
ROTATE,
PAN,
DOLLY_PAN,
DOLLY_ROTATE
}
const EPSILON:float = 0.0001
### PROPERTIES IN INSPECTOR ###
@export_category("Orbit Control Settings")
@export
var enabled: bool = true
@export
var debug: bool = false
@export_node_path("Camera3D")
var _camera: NodePath = NodePath()
var camera:Camera3D = null
@export_group("Target")
@export
var target: Vector3 = Vector3(0, 0, 0)
# AUTO-ROTATE
@export_group("Auto Rotate")
@export
var auto_rotate: bool = false
@export_range(0.001, 10.0)
var auto_rotate_speed: float = 1.0
# ROTATE
@export_group("Rotate")
@export
var enable_rotate: bool = true
@export_range(0.001, 10.0)
var rotate_speed: float = 1.0
# DOLLY (Perspective Cam only)
@export_group("Dolly")
@export_range(0.001, 100.0)
var min_distance: float = 0.001
@export_range(0.001, 100.0)
var max_distance: float = 100.0
# ZOOM (Orthographic Camera only)
@export_group("Zoom")
@export
var enable_zoom: bool = true
@export_range(0.001, 100.0)
var zoom_speed: float = 1.0
@export_range(0.001, 100.0)
var min_zoom: float = 0.001
@export_range(0.001, 100.0)
var max_zoom: float = 100.0
# LIMITS
@export_group("Limits")
@export_range(0, 180, 0.001, "radians")
var min_polar_angle: float = 0
@export_range(0, 180, 0.001, "radians")
var max_polar_angle: float = PI
@export_range(-360, 360, 0.001, "radians")
var min_azimuth_angle: float = - TAU
@export_range(-360, 360, 0.001, "radians")
var max_azimuth_angle: float = TAU
# DAMPING
@export_group("Damping")
@export
var enable_damping: bool = true
@export_range(0.001, 0.99)
var damping_factor: float = 0.05
# PAN
@export_group("Pan")
@export
var enable_pan: bool = true
@export_range(0.001, 10.00)
var pan_speed: float = 1.0
@export
var screen_space_panning: bool = false
@export_range(0.001, 100.00)
var key_pan_speed: float = 7.0
### END OF PROPERTIES ###
# Internal State
var radius: float = 1.0
var debug_layer: CanvasLayer = null
var debug_nodes = {}
# HELPERS
var spherical = Spherical.new()
var spherical_delta = Spherical.new()
# On rotate (left click)
var rotate_start = Vector2(0, 0)
var rotate_end = Vector2(0, 0)
var rotate_delta = Vector2(0, 0)
# On pan (right click)
var pan_start = Vector2(0, 0)
var pan_end = Vector2(0, 0)
var pan_delta = Vector2(0, 0)
# on Dolly
var dolly_start = Vector2(0, 0)
var dolly_end = Vector2(0, 0)
var dolly_delta = Vector2(0, 0)
var pointers = []
var pointerPositions = {}
# Other
var orbit_scale: float = 1
var pan_offset = Vector3(0, 0, 0)
var needs_update:bool = true
var mouse_buttons = { "LEFT": MOUSE.ROTATE, "MIDDLE": MOUSE.DOLLY, "RIGHT": MOUSE.PAN }
var touches = { "ONE": TOUCH.ROTATE, "TWO": TOUCH.DOLLY_PAN }
var state = STATE.NONE
# for reset
var target0: Vector3 = Vector3(0, 0, 0)
var position0: Vector3 = Vector3(0, 0, 0)
var zoom0: float = 1.0
var valid: bool = false
func _ready() -> void:
# Code to run in-game
if not Engine.is_editor_hint():
valid = check_camera()
# for reset
target0 = target
position0 = camera.position
zoom0 = camera.fov
if debug:
enable_debug()
func _process(delta: float) -> void:
if not valid:
return
if needs_update:
update()
if debug:
debug_nodes["state"].text = "STATE: " + STATE.keys()[state]
func update() -> void:
needs_update = auto_rotate
var offset: Vector3 = Vector3(0, 0, 0)
# the current position of the camera
var position: Vector3 = camera.position
# the current offset, copies the position into offset
# and subtracts the target vector
# copy the camera position to offset
offset = position
# subtract the target position
offset -= target
# set the spherical coords to this offset vector
spherical.set_from_vector(offset)
# enable auto rotate if configured
if auto_rotate && state == STATE.NONE:
rotate_left(get_auto_rotation_angle())
# # Dampen the actual spherical with the damping every frame
if enable_damping:
spherical.theta += spherical_delta.theta * damping_factor
spherical.phi += spherical_delta.phi * damping_factor
else: # or without damping
spherical.theta += spherical_delta.theta
spherical.phi += spherical_delta.phi
# restrict theta to be between desired limits
var _min = min_azimuth_angle + EPSILON
var _max = max_azimuth_angle - EPSILON
# some is_finite() check missing here, as godot does not seem to allow infinite numbers anyway
if _min < - PI:
_min += TAU
elif _min > PI:
_min -= TAU
if _max < - PI:
_max += TAU
elif _max > PI:
_max -= TAU
if _min <= _max:
spherical.theta = max(_min, min(_max, spherical.theta))
else:
if spherical.theta > (_min + _max / float(2)):
spherical.theta = max(_min, spherical.theta)
else:
spherical.theta = min(_max, spherical.theta)
# restrict phi to be between desired limits
spherical.phi = clampf(spherical.phi, min_polar_angle + EPSILON, max_polar_angle - EPSILON)
spherical.make_safe()
spherical.radius *= orbit_scale
# restrict radius to be between desired limits
spherical.radius = max(min_distance, min(max_distance, spherical.radius))
# move target to panned location
if enable_damping:
target += pan_offset * damping_factor
else:
target += pan_offset
offset = spherical.apply_to_vector(offset)
position = target + offset
camera.look_at_from_position(position, target, Vector3.UP)
emit_signal("change")
# Dampen the delta spherical by the damping factor
if enable_damping:
# only update during _process when still dampening
needs_update = spherical_delta.dampen(damping_factor) or auto_rotate
pan_offset *= (1 - damping_factor)
if pan_offset.length_squared() > 0.001:
needs_update = true
else:
spherical_delta.set_from_cartesian_coords(0, 0, 0)
pan_offset = Vector3.ZERO
orbit_scale = 1
func _unhandled_input(event: InputEvent) -> void:
if enabled == false:
return
# ON MOUSE DOWN (left, middle, right)
if event is InputEventMouseButton and (event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT or event.button_index == MOUSE_BUTTON_MIDDLE) and event.pressed:
on_mouse_down(event)
# ON MOUSE UP
if event is InputEventMouseButton and not event.pressed:
on_mouse_up(event)
if event is InputEventMouseMotion:
# Windows has a bug that triggers an InputEventMouseMotion event on
# releasing button clicks # with event.relative = 0, 0
# so filtering that out
if not event.relative == Vector2.ZERO:
on_mouse_move(event)
# ON MOUSE WHEEL
if event is InputEventMouseButton and (event.button_index == MOUSE_BUTTON_WHEEL_DOWN or event.button_index == MOUSE_BUTTON_WHEEL_UP):
on_mouse_wheel(event)
# ON TOUCH
if event is InputEventScreenTouch:
if event.pressed:
on_touch_down(event)
else:
on_touch_up(event)
# ON TOUCH DRAG
if event is InputEventScreenDrag:
on_touch_move(event)
func save_state() -> void:
target0 = target
position0 = camera.position
zoom0 = camera.fov
func reset() -> void:
target = target0
camera.position = position0
camera.fov = zoom0
update()
state = STATE.NONE
### Functions ###
## Getters
func get_polar_angle() -> float:
return spherical.phi
func get_azimuthal_angle() -> float:
return spherical.theta
func get_distance() -> float:
return camera.position.distance_squared_to(target)
func get_auto_rotation_angle() -> float:
return (TAU / 360) * auto_rotate_speed
func get_zoom_scale() -> float:
return pow(0.95, zoom_speed)
### ROTATION ###
func rotate_left(angle: float) -> void:
spherical_delta.theta -= angle
func rotate_up(angle: float) -> void:
spherical_delta.phi -= angle
### DOLLY ###
func dolly_out(dolly_scale: float) -> void:
if camera.projection == Camera3D.PROJECTION_PERSPECTIVE:
orbit_scale /= dolly_scale
elif camera.projection == Camera3D.PROJECTION_ORTHOGONAL:
camera.size = max(min_zoom, min(max_zoom, camera.size))
#zoom changed = true
else:
print("Unknown camera type detected. Zooming disabled")
enable_zoom = false
func dolly_in(dolly_scale: float) -> void:
if camera.projection == Camera3D.PROJECTION_PERSPECTIVE:
orbit_scale *= dolly_scale
elif camera.projection == Camera3D.PROJECTION_ORTHOGONAL:
camera.size = max(min_zoom, min(max_zoom, camera.size / dolly_scale))
else:
print("Unknown camera type detected. Zooming disabled")
enable_zoom = false
### PAN ###
func pan(delta_x, delta_y) -> void:
var offset = Vector3()
if camera.projection == Camera3D.PROJECTION_PERSPECTIVE:
var position = camera.position
offset = position - target
var target_distance = offset.length()
# half of the FOV is the vertical center of the screen
target_distance *= tan(camera.fov / 2.0) * PI / 180.0
pan_left(2 * delta_x * target_distance / get_viewport().get_size().y, camera.transform)
#pan_up(1, camera.transform)
pan_up(2 * delta_y * target_distance / get_viewport().get_size().y, camera.transform)
elif camera.projection == Camera3D.PROJECTION_ORTHOGONAL:
#pan_left(delta_y)
pass
else:
print("Unknown camera type - pan disabled")
enable_pan = false
func pan_left(distance, matrix) -> void:
var v = Vector3()
# get x column of camera
v = matrix.basis.x
v *= - distance
pan_offset += v
func pan_up(distance, matrix) -> void:
var v = Vector3()
if screen_space_panning:
v = matrix.basis.x
else:
v = matrix.basis.y
v.cross(Vector3(0, 1, 0))
v *= distance
pan_offset += v
### POINTER HANDLING
func add_pointer(event):
pointers.push_back(event)
func remove_pointer(event):
pointerPositions.erase(event.index)
for i in pointers.size():
if pointers[i].index == event.index:
pointers.remove(i)
return
func track_pointer(event):
var pointer_index = 0
var position = Vector2()
# a mouse event does not have an index
# and assume there are no more than one mouse pointer
if not event is InputEventMouse:
pointer_index = event.index
if not pointerPositions.has(pointer_index):
pointerPositions[pointer_index] = Vector2(0, 0)
pointerPositions[pointer_index].x = event.position.x
pointerPositions[pointer_index].y = event.position.y
# "on_" functions define the first action after the input event
func on_mouse_down(event):
var mouse_action = null
match event.button_index:
MOUSE_BUTTON_LEFT:
mouse_action = mouse_buttons.LEFT
MOUSE_BUTTON_MIDDLE:
mouse_action = mouse_buttons.MIDDLE
MOUSE_BUTTON_RIGHT:
mouse_action = mouse_buttons.RIGHT
_:
mouse_action = -1 # why not none?
match mouse_action:
MOUSE.DOLLY:
if not enable_zoom: return
handle_mouse_down_dolly(event)
state = STATE.DOLLY
MOUSE.ROTATE:
#if event.ctrlKey or event.metaKey or event.shiftkey
#if not enable pan: return
#handle_mouse_down_pan(event)
#state = STATE.PAN
#else
if not enable_rotate: return
handle_mouse_down_rotate(event)
state = STATE.ROTATE
MOUSE.PAN:
#if event.ctrlKey or event.metaKey or event.shiftkey
#if not enable pan: return
#handle_mouse_down_rotate(event)
#state = STATE.PAN
#else
if not enable_pan: return
handle_mouse_down_pan(event)
state = STATE.PAN
_:
state = STATE.NONE
if not state == STATE.NONE:
emit_signal("start")
func on_mouse_move(event):
#print("on_mouse_move")
#track_pointer(event)
match state:
STATE.ROTATE:
if not enable_rotate: return
handle_mouse_move_rotate(event)
STATE.DOLLY:
if not enable_zoom: return
handle_mouse_move_dolly(event)
STATE.PAN:
if not enable_pan: return
handle_mouse_move_pan(event)
func on_mouse_wheel(event):
if enabled == false or enable_zoom == false or state != STATE.NONE:
return
emit_signal("start")
handle_mouse_wheel(event)
emit_signal("end")
func on_touch_down(event):
add_pointer(event)
track_pointer(event)
match pointers.size():
1:
match touches.ONE:
TOUCH.ROTATE:
if enable_rotate == false:
return
handle_touch_start_rotate()
state = STATE.TOUCH_ROTATE
TOUCH.PAN:
if enable_pan == false:
return
handle_touch_start_pan()
state = STATE.TOUCH_PAN
_:
state = STATE.NONE
2:
match touches.TWO:
TOUCH.DOLLY_PAN:
if enable_zoom == false && enable_pan == false:
return
handle_touch_start_dolly_pan()
state = STATE.TOUCH_DOLLY_PAN
TOUCH.DOLLY_ROTATE:
if enable_zoom == false && enable_rotate == false:
return
state = STATE.TOUCH_DOLLY_ROTATE
_:
state = STATE.NONE
_:
state = STATE.NONE
if state != STATE.NONE:
emit_signal("start")
func on_touch_up(event):
remove_pointer(event)
# how can I re-evaluate the state?
# e.g. we are in touch_dolly_pan and lift one finger.
# We should be in touch_rotate state then and not NONE
state = STATE.NONE
func on_mouse_up(event):
# remove_pointer not needed here
# how can I re-evaluate the state?
# e.g. we are in touch_dolly_pan and lift one finger.
# We should be in touch_rotate state then and not NONE
state = STATE.NONE
# calls handle_-functions depending on number of pointers
func on_touch_move(event):
track_pointer(event)
match state:
STATE.TOUCH_ROTATE:
if enable_rotate == false:
return
handle_touch_move_rotate(event)
update()
STATE.TOUCH_PAN:
if enable_pan == false:
return
handle_touch_move_pan(event)
update()
STATE.TOUCH_DOLLY_PAN:
if enable_zoom == false && enable_pan == false:
return
handle_touch_move_dolly_pan(event)
update()
STATE.TOUCH_DOLLY_ROTATE:
if enable_zoom == false && enable_rotate == false:
return
#handle_touch_move_dolly_rotate(event)
update()
_:
state = STATE.NONE
func handle_mouse_down_rotate(event: InputEventMouseButton) -> void:
rotate_start = event.position
func handle_mouse_move_rotate(event: InputEventMouseMotion) -> void:
rotate_end = event.position
rotate_delta = (rotate_end - rotate_start) * rotate_speed
rotate_left(2 * PI * rotate_delta.x / get_viewport().size.y) # yes, height
rotate_up(2 * PI * rotate_delta.y / get_viewport().size.y)
rotate_start = rotate_end
update()
func handle_mouse_down_pan(event: InputEventMouseButton) -> void:
pan_start = event.position
func handle_mouse_move_pan(event: InputEventMouseMotion) -> void:
pan_end = event.position
pan_delta = (pan_end - pan_start) * pan_speed * 20.0
pan(pan_delta.x, pan_delta.y)
pan_start = pan_end
update()
func handle_mouse_down_dolly(event: InputEventMouseButton) -> void:
dolly_start = event.position
func handle_mouse_move_dolly(event: InputEventMouseMotion) -> void:
dolly_end = event.position
dolly_delta = dolly_end - dolly_start
if dolly_delta.y > 0:
dolly_out(get_zoom_scale())
elif dolly_delta.y < 0:
dolly_in(get_zoom_scale())
dolly_start = dolly_end
update()
func handle_mouse_wheel(event):
if event.button_index == MOUSE_BUTTON_WHEEL_UP:
dolly_in(get_zoom_scale())
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
dolly_out(get_zoom_scale())
update()
func get_second_pointer_position(event) -> Vector2:
var pointer = null
if event.index == pointers[0].index:
pointer = pointers[1]
else:
pointer = pointers[0]
return pointerPositions[pointer.index]
func handle_touch_start_rotate():
if pointers.size() == 1:
rotate_start.x = pointers[0].position.x
rotate_start.y = pointers[0].position.y
else:
var x = 0.5 * (pointers[0].position.x + pointers[1].position.x)
var y = 0.5 * (pointers[0].position.y + pointers[1].position.y)
rotate_start.x = x
rotate_start.y = y
func handle_touch_move_rotate(event):
if pointers.size() == 1:
rotate_end = event.position
else:
var position = get_second_pointer_position(event)
var x = 0.5 * (event.position.x + position.x)
var y = 0.5 * (event.position.y + position.y)
rotate_end.x = x
rotate_end.y = y
rotate_delta = (rotate_end - rotate_start) * rotate_speed
rotate_left(2 * PI * rotate_delta.x / get_viewport().size.y)
rotate_up(2 * PI * rotate_delta.y / get_viewport().size.y)
rotate_start = rotate_end
func handle_touch_move_pan(event):
if pointers.size() == 1:
pan_end.x = event.position.x
pan_end.y = event.position.y
else:
var position = get_second_pointer_position(event)
var x = 0.5 * (event.position.x + position.x)
var y = 0.5 * (event.position.y + position.y)
pan_end.x = x
pan_end.y = y
pan_delta = (pan_end - pan_start) * pan_speed * 20.0
pan(pan_delta.x, pan_delta.y)
pan_start = pan_end
func handle_touch_start_dolly_pan():
if enable_zoom:
handle_touch_start_dolly()
if enable_pan:
handle_touch_start_pan()
func handle_touch_start_dolly():
var dx = pointers[0].position.x - pointers[1].position.x
var dy = pointers[0].position.y - pointers[1].position.y
var distance = sqrt(dx * dx + dy * dy)
dolly_start.x = 0
dolly_start.y = distance
func handle_touch_start_pan():
if pointers.size() == 1:
pan_start.x = pointers[0].position.x
pan_start.y = pointers[0].position.y
else:
var x = 0.5 * (pointers[0].position.x + pointers[1].position.x)
var y = 0.5 * (pointers[0].position.y + pointers[1].position.y)
pan_start.x = x
pan_start.y = y
func handle_touch_move_dolly_pan(event):
if enable_zoom:
handle_touch_move_dolly(event)
if enable_pan:
handle_touch_move_pan(event)
func handle_touch_move_dolly(event):
var position = get_second_pointer_position(event)
var dx = event.position.x - position.x
var dy = event.position.y - position.y
var distance = sqrt(dx * dx + dy * dy)
dolly_end.x = 0
dolly_end.y = distance
dolly_delta.x = 0
dolly_delta.y = pow(dolly_end.y / dolly_start.y, zoom_speed)
dolly_out(dolly_delta.y)
dolly_start = dolly_end
### HELPER FUNCTIONS AND UTILITIES ###
# Check if the camera variable is actually a camera, print an error if not
func check_camera() -> bool:
if _camera:
camera = get_node(_camera)
if not camera.is_class("Camera3D"):
printerr("Selected Camera3D is not a camera.")
return false
else:
return true
else:
printerr("No camera provided")
return false
# Adds a debug overlay that shows current projection mode and state
func enable_debug():
debug_layer = CanvasLayer.new()
debug_layer.name = "debug_layer"
var v_box_container = VBoxContainer.new()
v_box_container.name = "list"
v_box_container.offset_left = 15
v_box_container.offset_top = 15
debug_layer.add_child(v_box_container)
var root_viewport = get_tree().get_root()
var label = Label.new()
var projection = "PERSPECTIVE" if camera.projection == Camera3D.PROJECTION_PERSPECTIVE else "ORTHOGRAPHIC"
label.text = "OrbitControls Debug (%s)" % projection
label.set("theme_override_colors/font_color", Color(1.0, 0.5, 0.5))
add_to_debug(label, "Heading")
add_string_to_debug("state")
add_string_to_debug("pointers")
root_viewport.call_deferred("add_child", debug_layer)
# Adds a string to the debug UI
func add_string_to_debug(name: String):
var string = Label.new()
string.name = name
add_to_debug(string, name)
# Adds Control nodes of any type to debug UI
func add_to_debug(control: Control, name: String) -> void:
var list = debug_layer.get_node("list")
list.add_child(control)
debug_nodes[name] = control

View File

@ -0,0 +1,7 @@
[plugin]
name="Orbit Controls"
description="Orbit Controls for the Godot Engine"
author="Luca Junge"
version="1.0"
script="plugin.gd"

View File

@ -0,0 +1,13 @@
@tool
extends EditorPlugin
func _enter_tree():
# Initialization of the plugin goes here.
# Add the new type with a name, a parent type, a script and an icon.
add_custom_type("OrbitControls", "Control", preload("orbit-controls.gd"), preload("node-icon.png"))
func _exit_tree():
# Clean-up of the plugin goes here.
# Always remember to remove it from the engine when deactivated.
remove_custom_type("OrbitControls")

64
experiments/Sphere3D.gd Normal file
View File

@ -0,0 +1,64 @@
extends MeshInstance3D
var rings = 50
var radial_segments = 50
var radius = 1
func _ready():
var surface_array = []
surface_array.resize(Mesh.ARRAY_MAX)
# PackedVector**Arrays for mesh construction.
var verts = PackedVector3Array()
var uvs = PackedVector2Array()
var normals = PackedVector3Array()
var indices = PackedInt32Array()
#######################################
# Vertex indices.
var thisrow = 0
var prevrow = 0
var point = 0
# Loop over rings.
for i in range(rings + 1):
var v = float(i) / rings
var w = sin(PI * v)
var y = cos(PI * v)
# Loop over segments in ring.
for j in range(radial_segments + 1):
var u = float(j) / radial_segments
var x = sin(u * PI * 2.0)
var z = cos(u * PI * 2.0)
var vert = Vector3(x * radius * w, y * radius, z * radius * w)
verts.append(vert)
normals.append(vert.normalized())
uvs.append(Vector2(u, v))
point += 1
# Create triangles in ring using indices.
if i > 0 and j > 0:
indices.append(prevrow + j - 1)
indices.append(prevrow + j)
indices.append(thisrow + j - 1)
indices.append(prevrow + j)
indices.append(thisrow + j)
indices.append(thisrow + j - 1)
prevrow = thisrow
thisrow = point
#######################################
# Assign arrays to surface array.
surface_array[Mesh.ARRAY_VERTEX] = verts
surface_array[Mesh.ARRAY_TEX_UV] = uvs
surface_array[Mesh.ARRAY_NORMAL] = normals
surface_array[Mesh.ARRAY_INDEX] = indices
# Create mesh surface from mesh array.
# No blendshapes, lods, or compression used.
mesh.add_surface_from_arrays(Mesh.PRIMITIVE_TRIANGLES, surface_array)
ResourceSaver.save(mesh, "res://experiments/sphere.tres", ResourceSaver.FLAG_COMPRESS)

View File

@ -0,0 +1,5 @@
[gd_scene load_steps=2 format=3 uid="uid://crsvssw78ow3t"]
[ext_resource type="PackedScene" uid="uid://bcf3gajson13b" path="res://Assets/models/screendoor1/PBMceshi.fbx" id="1_rbo8q"]
[node name="Root Scene" instance=ExtResource("1_rbo8q")]

5
experiments/lcb.gd Normal file
View File

@ -0,0 +1,5 @@
extends Node3D
func _on_button_pressed():
print("LCB 按钮按下")

39
experiments/lcb.tscn Normal file
View File

@ -0,0 +1,39 @@
[gd_scene load_steps=4 format=3 uid="uid://b5c3atssvhkwy"]
[ext_resource type="PackedScene" uid="uid://smgws0tjgxn0" path="res://Assets/models/screendoor/screenDoor.gltf" id="1_3e1st"]
[ext_resource type="Script" path="res://experiments/lcb.gd" id="2_e83ig"]
[sub_resource type="ViewportTexture" id="ViewportTexture_x5cm6"]
viewport_path = NodePath("LCB_Lable")
[node name="LCB" instance=ExtResource("1_3e1st")]
script = ExtResource("2_e83ig")
[node name="JH_GD_LCB" parent="." index="0"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.0218282, -0.0190198, -0.0356126)
[node name="LCB_Lable" type="SubViewport" parent="." index="1"]
size = Vector2i(64, 32)
[node name="ColorRect" type="ColorRect" parent="LCB_Lable" index="0"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
color = Color(0, 0.0901961, 1, 1)
[node name="Button" type="Button" parent="LCB_Lable" index="1"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
theme_override_font_sizes/font_size = 32
text = "LCB"
[node name="Sprite3D" type="Sprite3D" parent="." index="2"]
transform = Transform3D(0.255803, 0, 0, 0, 0.255803, 0, 0, 0, 0.255803, -0.0167608, 0.0950372, 0)
texture = SubResource("ViewportTexture_x5cm6")
[connection signal="pressed" from="LCB_Lable/Button" to="." method="_on_button_pressed"]

View File

@ -0,0 +1,43 @@
extends MeshInstance3D
var fnl = FastNoiseLite.new()
var mdt = MeshDataTool.new()
func _ready():
fnl.frequency = 0.7
mdt.create_from_surface(mesh, 0)
for i in range(mdt.get_vertex_count()):
var vertex = mdt.get_vertex(i).normalized()
# Push out vertex by noise.
vertex = vertex * (fnl.get_noise_3dv(vertex) * 0.5 + 0.75)
mdt.set_vertex(i, vertex)
# Calculate vertex normals, face-by-face.
for i in range(mdt.get_face_count()):
# Get the index in the vertex array.
var a = mdt.get_face_vertex(i, 0)
var b = mdt.get_face_vertex(i, 1)
var c = mdt.get_face_vertex(i, 2)
# Get vertex position using vertex index.
var ap = mdt.get_vertex(a)
var bp = mdt.get_vertex(b)
var cp = mdt.get_vertex(c)
# Calculate face normal.
var n = (bp - cp).cross(ap - bp).normalized()
# Add face normal to current vertex normal.
# This will not result in perfect normals, but it will be close.
mdt.set_vertex_normal(a, n + mdt.get_vertex_normal(a))
mdt.set_vertex_normal(b, n + mdt.get_vertex_normal(b))
mdt.set_vertex_normal(c, n + mdt.get_vertex_normal(c))
# Run through vertices one last time to normalize normals and
# set color to normal.
for i in range(mdt.get_vertex_count()):
var v = mdt.get_vertex_normal(i).normalized()
mdt.set_vertex_normal(i, v)
mdt.set_vertex_color(i, Color(v.x, v.y, v.z))
mesh.clear_surfaces()
mdt.commit_to_surface(mesh)

View File

@ -0,0 +1,8 @@
[gd_scene load_steps=3 format=3 uid="uid://n8hg1w1lmcm3"]
[ext_resource type="Script" path="res://experiments/mesh_data_tool_test.gd" id="1_2dsdn"]
[ext_resource type="ArrayMesh" uid="uid://ckftec7be6bqo" path="res://experiments/sphere.tres" id="1_qreen"]
[node name="MeshInstance3D" type="MeshInstance3D"]
mesh = ExtResource("1_qreen")
script = ExtResource("1_2dsdn")

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=3 format=3 uid="uid://0vitvgnvrwmy"]
[ext_resource type="Script" path="res://experiments/Sphere3D.gd" id="1_5iw5b"]
[sub_resource type="ArrayMesh" id="ArrayMesh_x6cuk"]
[node name="MeshInstance3D" type="MeshInstance3D"]
mesh = SubResource("ArrayMesh_x6cuk")
script = ExtResource("1_5iw5b")

View File

@ -0,0 +1,7 @@
[gd_scene load_steps=2 format=3 uid="uid://ce2vptio0yxxc"]
[ext_resource type="PackedScene" uid="uid://smgws0tjgxn0" path="res://Assets/models/screendoor/screenDoor.gltf" id="1_57jqk"]
[node name="platform" type="Node3D"]
[node name="screenDoor" parent="." instance=ExtResource("1_57jqk")]

View File

@ -0,0 +1,9 @@
[gd_scene load_steps=2 format=3 uid="uid://bmiexmyoh0ehv"]
[ext_resource type="PackedScene" uid="uid://c3feq8rrkjo6u" path="res://Assets/models/platform/platform.gltf" id="1_pyn6g"]
[node name="platform" instance=ExtResource("1_pyn6g")]
[node name="Label3D" type="Label3D" parent="DX" index="0"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3.0204, 0, 0.203499)
text = "车站一"

6
experiments/psd_panel.gd Normal file
View File

@ -0,0 +1,6 @@
@tool
extends Node3D
#func _ready():
#var lt = $LabelTexture.get_texture()
#$Sprite3D.texture = lt

View File

@ -0,0 +1,18 @@
[gd_scene load_steps=4 format=3 uid="uid://c63e3ugq35q5g"]
[ext_resource type="Script" path="res://experiments/psd_panel.gd" id="1_wg3fd"]
[ext_resource type="PackedScene" uid="uid://c5vvgu50akjwl" path="res://experiments/psd_panel_ui.tscn" id="2_rtht1"]
[sub_resource type="ViewportTexture" id="ViewportTexture_c2vxd"]
viewport_path = NodePath("LabelTexture")
[node name="PSD_Panel" type="Node3D"]
script = ExtResource("1_wg3fd")
[node name="LabelTexture" type="SubViewport" parent="."]
size = Vector2i(2048, 256)
[node name="PSD_Panel_UI" parent="LabelTexture" instance=ExtResource("2_rtht1")]
[node name="Sprite3D" type="Sprite3D" parent="."]
texture = SubResource("ViewportTexture_c2vxd")

View File

@ -0,0 +1,41 @@
@tool
extends Node2D
var stationLabelNode: PackedScene = preload("res://experiments/station_label.tscn")
class StationLable:
var name: String
var enName: String
var current: bool
func _init(n, en, cur):
name = n
enName = en
current = cur
var stations = [
StationLable.new("会展中心", "Exhibition Center", true),
StationLable.new("世纪大道", "Century Avenue", false),
StationLable.new("交通大学", "JiaoTong Univercity", false),
StationLable.new("市图书馆", "City Library", false),
StationLable.new("中心医院", "Central Hospital", false),
StationLable.new("未来路", "Wei lai lu", false),
StationLable.new("火车站", "train station", false),
StationLable.new("人民广场", "People's Square", false),
StationLable.new("体育中心", "sports center", false),
]
var reverseStations = stations.reverse()
func _ready():
print(stationLabelNode)
for i in stations.size():
var slable = stations[i]
print(slable.name, slable.enName, slable.current)
if slable.current:
$VBoxContainer/CurrentStationName.text = slable.name
$VBoxContainer/EnName.text = slable.enName
var slScene = stationLabelNode.instantiate()
slScene._init_station_name_and_position(slable.name, slable.enName, i)
$Container.add_child(slScene)

View File

@ -0,0 +1,37 @@
[gd_scene load_steps=2 format=3 uid="uid://c5vvgu50akjwl"]
[ext_resource type="Script" path="res://experiments/psd_panel_ui.gd" id="1_cmik1"]
[node name="PSD_Panel_UI" type="Node2D"]
script = ExtResource("1_cmik1")
[node name="ColorRect" type="ColorRect" parent="."]
offset_right = 43.0
offset_bottom = 25.0
scale = Vector2(36.8932, 11.8384)
color = Color(0.564706, 0.564706, 0.564706, 1)
[node name="VBoxContainer" type="VBoxContainer" parent="."]
offset_left = 136.0
offset_top = 64.0
offset_right = 420.0
offset_bottom = 146.0
alignment = 1
[node name="CurrentStationName" type="Label" parent="VBoxContainer"]
layout_mode = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_colors/font_shadow_color = Color(0, 0, 0, 1)
theme_override_font_sizes/font_size = 36
text = "当前车站"
horizontal_alignment = 1
[node name="EnName" type="Label" parent="VBoxContainer"]
layout_mode = 2
theme_override_colors/font_color = Color(0, 0, 0, 1)
theme_override_font_sizes/font_size = 20
text = "Current Station"
horizontal_alignment = 1
[node name="Container" type="Node2D" parent="."]
position = Vector2(584, 64)

View File

@ -0,0 +1,13 @@
[gd_scene load_steps=3 format=3 uid="uid://crpmwcp85khdr"]
[ext_resource type="PackedScene" uid="uid://biot7d8s87d3y" path="res://Assets/models/screendoor1/screenDoor.gltf" id="1_tvcny"]
[ext_resource type="Script" path="res://experiments/screendoor_lcb.gd" id="2_5qyph"]
[node name="screenDoor" instance=ExtResource("1_tvcny")]
[node name="JH_GD_LCB" parent="." index="0"]
script = ExtResource("2_5qyph")
[node name="Label3D" type="Label3D" parent="JH_GD_LCB" index="0"]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.147186, 0)
text = "LCB"

View File

@ -0,0 +1,5 @@
extends MeshInstance3D
func _ready():
var gp = global_position
print(gp)

14
experiments/sphere.tres Normal file

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,6 @@
extends Node2D
func _init_station_name_and_position(name, enName, i):
$StationName/Name.text = name
$StationName/EnName.text = enName
self.translate(Vector2(100 * i, 0))

View File

@ -0,0 +1,66 @@
[gd_scene load_steps=3 format=3 uid="uid://d27g0ew7giua3"]
[ext_resource type="Script" path="res://addons/2d_shapes/shapes/Ellipse.gd" id="1_a73g8"]
[ext_resource type="Script" path="res://experiments/station_label.gd" id="1_ch36d"]
[node name="StationLabel" type="Node2D"]
position = Vector2(64, 88)
script = ExtResource("1_ch36d")
[node name="StationName" type="Control" parent="."]
layout_mode = 3
anchors_preset = 0
offset_left = -24.0
offset_top = -8.0
offset_right = -24.0
offset_bottom = -8.0
rotation = -0.785397
size_flags_horizontal = 8
size_flags_vertical = 8
metadata/_edit_use_anchors_ = true
[node name="Name" type="Label" parent="StationName"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -24.0
offset_top = -11.5
offset_right = 24.0
offset_bottom = 11.5
grow_horizontal = 2
grow_vertical = 2
pivot_offset = Vector2(24, 11.5)
size_flags_horizontal = 4
theme_override_colors/font_color = Color(0, 0, 0, 1)
text = "车站名"
metadata/_edit_use_anchors_ = true
[node name="EnName" type="Label" parent="StationName"]
layout_mode = 1
anchors_preset = 8
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
offset_left = -48.0
offset_top = 12.0
offset_right = 44.0
offset_bottom = 35.0
grow_horizontal = 2
grow_vertical = 2
pivot_offset = Vector2(46, 11.5)
theme_override_colors/font_color = Color(0, 0, 0, 1)
text = "Exhibition Center"
metadata/_edit_use_anchors_ = true
[node name="Ellipse" type="Node2D" parent="."]
position = Vector2(48, -72)
script = ExtResource("1_a73g8")
size = Vector2(14, 14)
circle = true
style = 2
outline_width = 2
outline_color = Color(1, 0, 0, 1)

11
experiments/test_3d.gd Normal file
View File

@ -0,0 +1,11 @@
extends Node3D
@onready var camera = $Camera3D
func _ready():
var sp = get_screen_position($LCB)
print("3D物体在屏幕上的位置: ", sp)
func get_screen_position(mesh_instance):
var global_position = mesh_instance.global_transform.origin
return camera.unproject_position(global_position)

39
experiments/test_3d.tscn Normal file
View File

@ -0,0 +1,39 @@
[gd_scene load_steps=7 format=3 uid="uid://4ygkabji3g16"]
[ext_resource type="PackedScene" uid="uid://bmiexmyoh0ehv" path="res://experiments/platform1.tscn" id="1_cq2ki"]
[ext_resource type="Script" path="res://experiments/test_3d.gd" id="1_uqsdo"]
[ext_resource type="PackedScene" uid="uid://crpmwcp85khdr" path="res://experiments/screen_door_t1.tscn" id="2_rvfj7"]
[ext_resource type="PackedScene" uid="uid://b5c3atssvhkwy" path="res://experiments/lcb.tscn" id="3_htmjl"]
[ext_resource type="PackedScene" uid="uid://c63e3ugq35q5g" path="res://experiments/psd_panel.tscn" id="4_wjde3"]
[sub_resource type="Environment" id="Environment_mybsf"]
ambient_light_color = Color(0.831373, 0.290196, 0.556863, 1)
ambient_light_energy = 6.23
[node name="Node3D" type="Node3D"]
script = ExtResource("1_uqsdo")
[node name="platform" parent="." instance=ExtResource("1_cq2ki")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.16258, 0)
[node name="LCB" parent="." instance=ExtResource("3_htmjl")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.58244, 2.40247, -7.38809)
[node name="PSD_Panel" parent="." instance=ExtResource("4_wjde3")]
transform = Transform3D(0.381944, 0, 0, 0, 0.381944, 0, 0, 0, 0.381944, 4.13301, 1.83159, -7.03252)
[node name="screenDoor" parent="." instance=ExtResource("2_rvfj7")]
[node name="WorldEnvironment" type="WorldEnvironment" parent="."]
environment = SubResource("Environment_mybsf")
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="."]
transform = Transform3D(0.775947, 2.3125e-07, -0.630798, 0.387003, 0.789684, 0.476054, 0.498131, -0.613514, 0.612753, -0.369306, 2.06538, 1.72595)
light_energy = 4.962
[node name="Camera3D" type="Camera3D" parent="."]
transform = Transform3D(1, 0, 0, 0, 0.92041, 0.390956, 0, -0.390956, 0.92041, 4.25592, 2.82422, -2.07876)
projection = 1
current = true
fov = 23.7
size = 4.56913

View File

@ -11,7 +11,7 @@ config_version=5
[application]
config/name="godot_experiments"
run/main_scene="res://UI/stand.tscn"
run/main_scene="res://experiments/test_3d.tscn"
config/features=PackedStringArray("4.2", "GL Compatibility")
config/icon="res://icon.svg"
@ -22,6 +22,19 @@ window/size/viewport_height=1080
window/size/initial_position_type=0
window/stretch/mode="canvas_items"
[editor_plugins]
enabled=PackedStringArray("res://addons/2d_shapes/plugin.cfg", "res://addons/orbit-controls/plugin.cfg")
[importer_defaults]
animation_library={
"gltf/embedded_image_handling": 2
}
scene={
"gltf/embedded_image_handling": 2
}
[rendering]
renderer/rendering_method="gl_compatibility"