Reallusion Importer/Shaders, Native LODs, Selectors
This commit is contained in:
parent
f025656b97
commit
8520186939
|
@ -0,0 +1,97 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="RemoveVirtualCamera3D.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs8"><linearGradient
|
||||
inkscape:collect="never"
|
||||
id="linearGradient3074"><stop
|
||||
style="stop-color:#e26708;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3070" /><stop
|
||||
style="stop-color:#bb3c00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3072" /></linearGradient><radialGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="radialGradient3076"
|
||||
cx="30.688875"
|
||||
cy="30.069115"
|
||||
fx="30.688875"
|
||||
fy="30.069115"
|
||||
r="14.05412"
|
||||
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="linearGradient45010"
|
||||
x1="-31.87768"
|
||||
y1="22.065159"
|
||||
x2="-31.87768"
|
||||
y2="48.78738"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(101.16951,-6.5921995)" /><linearGradient
|
||||
id="linearGradient45008"><stop
|
||||
style="stop-color:#e14500;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop45004" /><stop
|
||||
style="stop-color:#e17900;stop-opacity:1;"
|
||||
offset="0.59811592"
|
||||
id="stop45012" /><stop
|
||||
style="stop-color:#e19c00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop45006" /></linearGradient><linearGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="linearGradient46715"
|
||||
x1="31.917692"
|
||||
y1="47.524929"
|
||||
x2="31.917692"
|
||||
y2="22.632998"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(1.7923447e-6)" /></defs><sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="8.0000004"
|
||||
inkscape:cx="-8.8124996"
|
||||
inkscape:cy="-12.687499"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g2210"
|
||||
showguides="false" /><g
|
||||
id="g2210"
|
||||
transform="matrix(0.54328517,0,0,0.54328517,-9.4489315,-11.300948)"><path
|
||||
fill="#fc7f7f"
|
||||
id="path66330"
|
||||
style="fill:#f78500;fill-opacity:1;stroke:none;stroke-width:1.65067;stroke-dasharray:3.30134, 1.65067;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 34.253693,25.773391 a 4.9507597,4.9507597 0 0 0 -4.951825,4.581599 4.9507597,4.9507597 0 1 0 -4.952696,8.327678 l -8.37e-4,3.59095 a 1.6502534,1.6502534 0 0 0 1.649872,1.650636 l 9.901519,0.0022 a 1.6502534,1.6502534 0 0 0 1.650638,-1.649869 l 3.84e-4,-1.650254 4.949993,3.301659 0.0022,-9.901519 -4.951529,3.299355 6.78e-4,-2.920952 a 4.9507597,4.9507597 0 0 0 -3.298458,-8.631545 z" /><g
|
||||
id="g15102"
|
||||
style="stroke:#f00b00;stroke-opacity:1"><path
|
||||
style="fill:none;fill-opacity:1;stroke:#f00b00;stroke-width:3.68131;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="m 20.72898,24.341266 22.77693,22.3702"
|
||||
id="path14277"
|
||||
sodipodi:nodetypes="cc" /><path
|
||||
style="fill:none;fill-opacity:1;stroke:#f00b00;stroke-width:3.68131;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="m 43.50591,24.341266 -22.77693,22.3702"
|
||||
id="path15098"
|
||||
sodipodi:nodetypes="cc" /></g><path
|
||||
fill="#fc7f7f"
|
||||
id="path15104"
|
||||
style="fill:#f78500;fill-opacity:0.68461537;stroke:none;stroke-width:1.65067;stroke-dasharray:3.30134, 1.65067;stroke-dashoffset:0;stroke-opacity:1"
|
||||
d="m 34.253693,25.773391 a 4.9507597,4.9507597 0 0 0 -4.951825,4.581599 4.9507597,4.9507597 0 1 0 -4.952696,8.327678 l -8.37e-4,3.59095 a 1.6502534,1.6502534 0 0 0 1.649872,1.650636 l 9.901519,0.0022 a 1.6502534,1.6502534 0 0 0 1.650638,-1.649869 l 3.84e-4,-1.650254 4.949993,3.301659 0.0022,-9.901519 -4.951529,3.299355 6.78e-4,-2.920952 a 4.9507597,4.9507597 0 0 0 -3.298458,-8.631545 z" /></g></svg>
|
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://beh11ebwsi3nj"
|
||||
path="res://.godot/imported/RemoveVirtualCamera3D.svg-b229129ca4dd411d22a781c703e04259.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/rokojori_action_library/Icons/RemoveVirtualCamera3D.svg"
|
||||
dest_files=["res://.godot/imported/RemoveVirtualCamera3D.svg-b229129ca4dd411d22a781c703e04259.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
|
|
@ -0,0 +1,101 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
height="16"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
version="1.1"
|
||||
id="svg4"
|
||||
sodipodi:docname="SetActiveVirtualCamera3D.svg"
|
||||
inkscape:version="1.2.2 (732a01da63, 2022-12-09)"
|
||||
xml:space="preserve"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"><defs
|
||||
id="defs8"><linearGradient
|
||||
inkscape:collect="never"
|
||||
id="linearGradient3074"><stop
|
||||
style="stop-color:#e26708;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop3070" /><stop
|
||||
style="stop-color:#bb3c00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop3072" /></linearGradient><radialGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="radialGradient3076"
|
||||
cx="30.688875"
|
||||
cy="30.069115"
|
||||
fx="30.688875"
|
||||
fy="30.069115"
|
||||
r="14.05412"
|
||||
gradientUnits="userSpaceOnUse" /><linearGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="linearGradient45010"
|
||||
x1="-31.87768"
|
||||
y1="22.065159"
|
||||
x2="-31.87768"
|
||||
y2="48.78738"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(101.16951,-6.5921995)" /><linearGradient
|
||||
id="linearGradient45008"><stop
|
||||
style="stop-color:#e14500;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop45004" /><stop
|
||||
style="stop-color:#e17900;stop-opacity:1;"
|
||||
offset="0.59811592"
|
||||
id="stop45012" /><stop
|
||||
style="stop-color:#e19c00;stop-opacity:1;"
|
||||
offset="1"
|
||||
id="stop45006" /></linearGradient><linearGradient
|
||||
xlink:href="#linearGradient45008"
|
||||
id="linearGradient46715"
|
||||
x1="31.917692"
|
||||
y1="47.524929"
|
||||
x2="31.917692"
|
||||
y2="22.632998"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="translate(1.7923447e-6)" /></defs><sodipodi:namedview
|
||||
id="namedview6"
|
||||
pagecolor="#505050"
|
||||
bordercolor="#eeeeee"
|
||||
borderopacity="1"
|
||||
inkscape:showpageshadow="0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pagecheckerboard="0"
|
||||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="22.627418"
|
||||
inkscape:cx="12.308077"
|
||||
inkscape:cy="11.203223"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="g2210" /><g
|
||||
id="g2210"
|
||||
transform="matrix(0.54328517,0,0,0.54328517,-9.4489315,-11.300948)"><path
|
||||
d="m 37.699583,28.035024 a 3.6424849,3.6424849 0 0 0 -3.642486,3.371726 3.6424849,3.6424849 0 1 0 -3.642484,6.127874 v 2.642016 a 1.2141617,1.2141617 0 0 0 1.214163,1.21416 h 7.284971 a 1.2141617,1.2141617 0 0 0 1.21416,-1.21416 v -1.214163 l 3.642488,2.428323 v -7.284969 l -3.642488,2.428323 v -2.149068 a 3.6424849,3.6424849 0 0 0 -2.428324,-6.350062 z"
|
||||
fill="#fc7f7f"
|
||||
id="path66330"
|
||||
style="fill:#f78500;fill-opacity:1;stroke:none;stroke-width:1.21414;stroke-opacity:1" /><path
|
||||
id="rect401"
|
||||
style="color:#000000;fill:#f7b200;fill-opacity:1;stroke-width:1.84065;stroke-linecap:round;stroke-linejoin:round;-inkscape-stroke:none;paint-order:markers stroke fill"
|
||||
d="m 19.840427,20.92696 c -1.240775,0 -2.297223,1.052853 -2.297223,2.293627 v 4.623206 h 3.681308 v -3.235525 h 3.21036 V 20.92696 Z m 19.959591,0 v 3.681308 h 3.249905 v 3.235525 h 3.681308 v -4.623206 c 0,-1.240774 -1.056447,-2.293627 -2.297223,-2.293627 z M 17.543204,43.208939 v 4.544115 c 0,1.240774 1.056448,2.297222 2.297223,2.297222 h 4.594445 v -3.681308 h -3.21036 v -3.160029 z m 25.506719,0 v 3.160029 h -3.249905 v 3.681308 h 4.63399 c 1.240776,0 2.297223,-1.056448 2.297223,-2.297222 v -4.544115 z" /><path
|
||||
sodipodi:type="star"
|
||||
style="fill:#f7b200;fill-opacity:1;stroke-width:3.68131;stroke-linecap:round;stroke-linejoin:round;paint-order:markers stroke fill"
|
||||
id="path9403"
|
||||
inkscape:flatsided="true"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="-5.8778248"
|
||||
sodipodi:cy="-1.4584076"
|
||||
sodipodi:r1="3.1847413"
|
||||
sodipodi:r2="1.5923707"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m -2.6930835,-1.4584076 -4.7771119,2.7580668 0,-5.5161337 z"
|
||||
transform="matrix(1.3392575,0,0,1.3392575,30.388942,37.803361)"
|
||||
inkscape:transform-center-x="-0.5793031" /></g></svg>
|
After Width: | Height: | Size: 4.5 KiB |
|
@ -0,0 +1,37 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cwtmomxhbrhh4"
|
||||
path="res://.godot/imported/SetActiveVirtualCamera3D.svg-daa089c09a78ae1c001e1e1ec4c40af0.ctex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://addons/rokojori_action_library/Icons/SetActiveVirtualCamera3D.svg"
|
||||
dest_files=["res://.godot/imported/SetActiveVirtualCamera3D.svg-daa089c09a78ae1c001e1e1ec4c40af0.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
|
|
@ -66,8 +66,8 @@
|
|||
inkscape:deskcolor="#505050"
|
||||
showgrid="false"
|
||||
inkscape:zoom="22.627418"
|
||||
inkscape:cx="8.1538247"
|
||||
inkscape:cy="2.320194"
|
||||
inkscape:cx="12.308077"
|
||||
inkscape:cy="11.203223"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1017"
|
||||
inkscape:window-x="-8"
|
||||
|
@ -76,7 +76,7 @@
|
|||
inkscape:current-layer="g2210" /><g
|
||||
id="g2210"
|
||||
transform="matrix(0.54328517,0,0,0.54328517,-9.4489315,-11.300948)"><path
|
||||
d="m 35.176642,24.424961 a 6.0553193,6.0553193 0 0 0 -6.05532,5.605205 6.0553193,6.0553193 0 1 0 -6.055318,10.187067 v 4.392124 a 2.0184399,2.0184399 0 0 0 2.018441,2.018439 h 12.11064 a 2.0184399,2.0184399 0 0 0 2.018439,-2.018439 v -2.018441 l 6.055322,4.03688 V 34.517157 l -6.055322,4.036879 V 34.981395 A 6.0553193,6.0553193 0 0 0 35.176642,24.424961 Z"
|
||||
d="m 34.728314,26.051881 a 5.1679073,5.1679073 0 0 0 -5.167908,4.783758 5.1679073,5.1679073 0 1 0 -5.167906,8.694144 v 3.748454 a 1.7226359,1.7226359 0 0 0 1.722637,1.722635 h 10.335816 a 1.7226359,1.7226359 0 0 0 1.722635,-1.722635 v -1.722636 l 5.167909,3.445271 V 34.665058 l -5.167909,3.445271 v -3.049068 a 5.1679073,5.1679073 0 0 0 -3.445274,-9.00938 z"
|
||||
fill="#fc7f7f"
|
||||
id="path66330"
|
||||
style="fill:#f78500;fill-opacity:1;stroke:none;stroke-width:2.01842;stroke-opacity:1" /></g></svg>
|
||||
style="fill:#f78500;fill-opacity:1;stroke:none;stroke-width:1.72262;stroke-opacity:1" /></g></svg>
|
||||
|
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class ActionReference : Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/ConditionalAction.svg")]
|
||||
public partial class Once : Action
|
||||
{
|
||||
[Export]
|
||||
public Action action;
|
||||
|
||||
[Export]
|
||||
public bool canTrigger = true;
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
if ( ! canTrigger )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
canTrigger = false;
|
||||
Action.Trigger( action );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://crm7o7w0gumhn
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class IterateActions : Action
|
||||
{
|
||||
[ExportGroup( "Read Only")]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class LoadScene : SequenceAction
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class SetNodeState : Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class CopyMousePosition : Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass, Tool ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class CopyPose : Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass ]
|
||||
[Tool][GlobalClass ]
|
||||
public partial class LerpPosition : Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class PlayParticles:Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class PlaySound:Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/OnEvent.svg") ]
|
||||
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/OnEvent.svg") ]
|
||||
public partial class OnPhysicsProcess : Node
|
||||
{
|
||||
/** <summary for="field actions">Actions to execute</summary>*/
|
||||
|
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/OnEvent.svg") ]
|
||||
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/OnEvent.svg") ]
|
||||
public partial class OnReady : Node
|
||||
{
|
||||
/** <summary for="field actions">Actions to execute</summary>*/
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Parallel.svg") ]
|
||||
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Parallel.svg") ]
|
||||
public partial class Parallel : SequenceAction
|
||||
{
|
||||
public enum Mode
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
|
||||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool][GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Parallel.svg") ]
|
||||
public partial class RepeatSequence : SequenceAction
|
||||
{
|
||||
[Export]
|
||||
public Action action;
|
||||
|
||||
|
||||
[Export]
|
||||
public int maxNumRepeats = 3;
|
||||
|
||||
[Export]
|
||||
public float maxRepeatDuration = 60;
|
||||
|
||||
[Export]
|
||||
public TimeLine timeLine;
|
||||
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
|
||||
var id = DispatchStart();
|
||||
|
||||
if ( ! ( action is SequenceAction ) )
|
||||
{
|
||||
Trigger( action );
|
||||
DispatchEnd( id );
|
||||
return;
|
||||
}
|
||||
|
||||
var sa = (SequenceAction) action;
|
||||
|
||||
var executed = 0;
|
||||
|
||||
System.Action<SequenceActionFinishedEvent> callBack = null;
|
||||
|
||||
var tl = TimeLineManager.Ensure( timeLine );
|
||||
|
||||
if ( maxNumRepeats <= 0 && ( tl == null || maxRepeatDuration <= 0 ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var startTime = tl.position;
|
||||
var endTime = tl.position + maxRepeatDuration;
|
||||
|
||||
callBack = ( a )=>
|
||||
{
|
||||
if ( ! a.success )
|
||||
{
|
||||
DispatchCancelled( id );
|
||||
sa.onSequenceDone.RemoveAction( callBack );
|
||||
return;
|
||||
}
|
||||
|
||||
executed ++;
|
||||
|
||||
var finished = ( maxNumRepeats > 0 && executed >= maxNumRepeats ) ||
|
||||
( tl != null && tl.position >= endTime );
|
||||
|
||||
if ( finished )
|
||||
{
|
||||
DispatchEnd( id );
|
||||
sa.onSequenceDone.RemoveAction( callBack );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
Trigger( action );
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
sa.onSequenceDone.AddAction( callBack );
|
||||
|
||||
|
||||
Trigger( action );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://j41ppn275x8i
|
|
@ -4,7 +4,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class Delay : SequenceAction
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass ]
|
||||
public partial class TweenTimeLineSpeed:SequenceAction
|
||||
{
|
||||
[Export]
|
||||
public TimeLine targetTimeLine;
|
||||
|
||||
[Export]
|
||||
public float timeLineSpeed;
|
||||
|
||||
[Export]
|
||||
public TweenType tweenType = new TweenTimeCurve();
|
||||
|
||||
[Export]
|
||||
public bool cacheSpeedOnStart = true;
|
||||
|
||||
[Export]
|
||||
public TimeLine tweenTimeLine;
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
if ( targetTimeLine == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tl = tweenTimeLine == null ? TimeLineManager.Get().realtimeTimeline : tweenTimeLine;
|
||||
|
||||
var start = targetTimeLine.position;
|
||||
|
||||
var fromSpeed = targetTimeLine.runner.speed;
|
||||
var toSpeed = timeLineSpeed;
|
||||
|
||||
|
||||
var sequenceID = DispatchStart();
|
||||
|
||||
var tweenType = this.tweenType;
|
||||
|
||||
if ( tweenType == null )
|
||||
{
|
||||
tweenType = TweenTimeCurve.defaultCurve;
|
||||
}
|
||||
|
||||
TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(),
|
||||
( span, type )=>
|
||||
{
|
||||
var timeNow = tl.position;
|
||||
var elapsed = timeNow - start;
|
||||
|
||||
var state = tweenType.GetTweenPhaseForPhase( span.phase );
|
||||
|
||||
if ( ! cacheSpeedOnStart )
|
||||
{
|
||||
toSpeed = timeLineSpeed;
|
||||
}
|
||||
|
||||
var lerpedSpeed = Mathf.Lerp( fromSpeed, toSpeed, state );
|
||||
|
||||
targetTimeLine.runner.speed = lerpedSpeed;
|
||||
|
||||
if ( type == TimeLineSpanUpdateType.End )
|
||||
{
|
||||
DispatchEnd( sequenceID );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://b33s5utxleah2
|
|
@ -0,0 +1,70 @@
|
|||
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass ]
|
||||
public partial class TweenParticles:SequenceAction
|
||||
{
|
||||
[Export]
|
||||
public GpuParticles3D particles3D;
|
||||
|
||||
[Export]
|
||||
public TweenParticlesData tweenParticlesData;
|
||||
|
||||
[Export]
|
||||
public TweenType tweenType = new TweenTimeCurve();
|
||||
|
||||
[Export]
|
||||
public TimeLine timeLine;
|
||||
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
if ( particles3D == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tl = TimeLineManager.Ensure( timeLine );
|
||||
|
||||
var start = tl.position;
|
||||
|
||||
var fromData = new TweenParticlesData();
|
||||
fromData.CopyFrom( particles3D );
|
||||
var lerpData = tweenParticlesData.Clone( true );
|
||||
|
||||
var sequenceID = DispatchStart();
|
||||
|
||||
var tweenType = this.tweenType;
|
||||
|
||||
if ( tweenType == null )
|
||||
{
|
||||
tweenType = TweenTimeCurve.defaultCurve;
|
||||
}
|
||||
|
||||
TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(),
|
||||
( span, type )=>
|
||||
{
|
||||
var timeNow = tl.position;
|
||||
var elapsed = timeNow - start;
|
||||
|
||||
var state = tweenType.GetTweenPhaseForPhase( span.phase );
|
||||
|
||||
TweenParticlesData.LerpTo( fromData, tweenParticlesData, state, lerpData );
|
||||
|
||||
lerpData.CopyTo( particles3D );
|
||||
|
||||
if ( type == TimeLineSpanUpdateType.End )
|
||||
{
|
||||
DispatchEnd( sequenceID );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://seym2gxpvk7j
|
|
@ -0,0 +1,120 @@
|
|||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass ]
|
||||
public partial class TweenParticlesData:Resource
|
||||
{
|
||||
|
||||
[Export]
|
||||
public FloatValue amount;
|
||||
|
||||
[Export]
|
||||
public FloatValue amountRatio;
|
||||
|
||||
[ExportGroup("Time")]
|
||||
[Export]
|
||||
public FloatValue lifeTime;
|
||||
|
||||
[Export]
|
||||
public FloatValue speedScale;
|
||||
|
||||
[Export]
|
||||
public FloatValue explosiveness;
|
||||
|
||||
[Export]
|
||||
public FloatValue randomness;
|
||||
|
||||
|
||||
public virtual TweenParticlesData Clone( bool deepClone )
|
||||
{
|
||||
var clone = new TweenParticlesData();
|
||||
|
||||
clone.amount = FloatValue.Clone( amount, deepClone );
|
||||
clone.amountRatio = FloatValue.Clone( amountRatio, deepClone );
|
||||
clone.lifeTime = FloatValue.Clone( lifeTime, deepClone );
|
||||
|
||||
clone.speedScale = FloatValue.Clone( speedScale, deepClone );
|
||||
clone.explosiveness = FloatValue.Clone( explosiveness, deepClone );
|
||||
clone.randomness = FloatValue.Clone( randomness, deepClone );
|
||||
|
||||
return clone;
|
||||
|
||||
}
|
||||
|
||||
public virtual void CopyFrom( GpuParticles3D particles )
|
||||
{
|
||||
amount = FloatValue.Create( particles.Amount );
|
||||
amountRatio = FloatValue.Create( particles.AmountRatio );
|
||||
lifeTime = FloatValue.Create( particles.Lifetime );
|
||||
|
||||
speedScale = FloatValue.Create( particles.SpeedScale );
|
||||
explosiveness = FloatValue.Create( particles.Explosiveness );
|
||||
randomness = FloatValue.Create( particles.Randomness );
|
||||
}
|
||||
|
||||
|
||||
public virtual void CopyFrom( TweenParticlesData tweenLightData )
|
||||
{
|
||||
amount = tweenLightData.amount;
|
||||
amountRatio = tweenLightData.amountRatio;
|
||||
lifeTime = tweenLightData.lifeTime;
|
||||
|
||||
speedScale = tweenLightData.speedScale;
|
||||
explosiveness = tweenLightData.explosiveness;
|
||||
randomness = tweenLightData.randomness;
|
||||
}
|
||||
|
||||
public virtual void CopyTo( GpuParticles3D particles )
|
||||
{
|
||||
if ( amount != null )
|
||||
{
|
||||
particles.Amount = Mathf.RoundToInt( amount.value );
|
||||
|
||||
}
|
||||
|
||||
if ( amountRatio != null )
|
||||
{
|
||||
particles.AmountRatio = amountRatio.value;
|
||||
particles.Emitting = amountRatio.value > 0;
|
||||
}
|
||||
|
||||
if ( lifeTime != null )
|
||||
{
|
||||
particles.Lifetime = lifeTime.value;
|
||||
}
|
||||
|
||||
|
||||
if ( speedScale != null )
|
||||
{
|
||||
particles.SpeedScale = speedScale.value;
|
||||
}
|
||||
|
||||
if ( explosiveness != null )
|
||||
{
|
||||
particles.Explosiveness = explosiveness.value;
|
||||
}
|
||||
|
||||
if ( randomness != null )
|
||||
{
|
||||
particles.Randomness = randomness.value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void LerpTo( TweenParticlesData a, TweenParticlesData b, float lerpAmount, TweenParticlesData output )
|
||||
{
|
||||
FloatValue.Lerp( a.amount, b.amount, lerpAmount, output.amount );
|
||||
FloatValue.Lerp( a.amountRatio, b.amountRatio, lerpAmount, output.amountRatio );
|
||||
FloatValue.Lerp( a.lifeTime, b.lifeTime, lerpAmount, output.lifeTime );
|
||||
|
||||
FloatValue.Lerp( a.speedScale, b.speedScale, lerpAmount, output.speedScale );
|
||||
FloatValue.Lerp( a.explosiveness, b.explosiveness, lerpAmount, output.explosiveness );
|
||||
FloatValue.Lerp( a.randomness, b.randomness, lerpAmount, output.randomness );
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://bvrtvo7tdhft6
|
|
@ -0,0 +1,91 @@
|
|||
|
||||
using System;
|
||||
using Godot;
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass ]
|
||||
public partial class TweenPosition:SequenceAction
|
||||
{
|
||||
[Export]
|
||||
public Node3D target;
|
||||
|
||||
[Export]
|
||||
public Node3D endPosition;
|
||||
|
||||
[Export]
|
||||
public Vector3 endOffset;
|
||||
|
||||
[Export]
|
||||
public TweenType tweenType = new TweenTimeCurve();
|
||||
|
||||
|
||||
[Export]
|
||||
public bool cacheEndPositionOnStart = true;
|
||||
|
||||
[Export]
|
||||
public TimeLine timeLine;
|
||||
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
if ( target == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var tl = TimeLineManager.Ensure( timeLine );
|
||||
|
||||
var start = tl.position;
|
||||
|
||||
var fromPosition = target.GlobalPosition;
|
||||
var toPosition = endOffset;
|
||||
|
||||
if ( endPosition != null )
|
||||
{
|
||||
toPosition += endPosition.GlobalPosition;
|
||||
}
|
||||
|
||||
var sequenceID = DispatchStart();
|
||||
|
||||
var tweenType = this.tweenType;
|
||||
|
||||
if ( tweenType == null )
|
||||
{
|
||||
tweenType = TweenTimeCurve.defaultCurve;
|
||||
}
|
||||
|
||||
TimeLineManager.ScheduleSpanIn( tl, 0, tweenType.GetTweenDuration(),
|
||||
( span, type )=>
|
||||
{
|
||||
var timeNow = tl.position;
|
||||
var elapsed = timeNow - start;
|
||||
|
||||
var state = tweenType.GetTweenPhaseForPhase( span.phase );
|
||||
|
||||
if ( ! cacheEndPositionOnStart )
|
||||
{
|
||||
toPosition = endOffset;
|
||||
|
||||
if ( endPosition != null )
|
||||
{
|
||||
toPosition += endPosition.GlobalPosition;
|
||||
}
|
||||
}
|
||||
|
||||
var lerpedPosition = fromPosition.Lerp( toPosition, state );
|
||||
|
||||
target.GlobalPosition = lerpedPosition;
|
||||
|
||||
if ( type == TimeLineSpanUpdateType.End )
|
||||
{
|
||||
DispatchEnd( sequenceID );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://n4etptbiekhq
|
|
@ -8,6 +8,11 @@ namespace Rokojori
|
|||
[GlobalClass ]
|
||||
public partial class TweenType : Resource
|
||||
{
|
||||
public virtual void SetFromAndTo( object a, object b )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public virtual float GetTweenDuration()
|
||||
{
|
||||
return 0.5f;
|
||||
|
|
|
@ -5,7 +5,7 @@ using System.Text;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class SineWaveTest: Node
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -66,5 +66,20 @@ namespace Rokojori
|
|||
ints.ForEach( i => list.AddRange( BitConverter.GetBytes( i ) ) );
|
||||
return list;
|
||||
}
|
||||
|
||||
public static List<byte> Convert( List<Vector4> v )
|
||||
{
|
||||
var list = new List<byte>();
|
||||
v.ForEach(
|
||||
f =>
|
||||
{
|
||||
list.AddRange( BitConverter.GetBytes( f.X ) );
|
||||
list.AddRange( BitConverter.GetBytes( f.Y ) );
|
||||
list.AddRange( BitConverter.GetBytes( f.Z ) );
|
||||
list.AddRange( BitConverter.GetBytes( f.W ) );
|
||||
}
|
||||
);
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,47 @@
|
|||
using Godot;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public static class ColorX
|
||||
{
|
||||
public static Color From( List<float> floats, float basis = 1.0f )
|
||||
{
|
||||
if ( floats.Count == 1 )
|
||||
{
|
||||
var grey = floats[ 0 ] / basis;
|
||||
return new Color( grey, grey, grey, 1 );
|
||||
}
|
||||
|
||||
if ( floats.Count == 2 )
|
||||
{
|
||||
var grey = floats[ 0 ] / basis;
|
||||
var alpha = floats[ 1 ] / basis;
|
||||
return new Color( grey, grey, grey, alpha );
|
||||
}
|
||||
|
||||
if ( floats.Count == 3 )
|
||||
{
|
||||
var r = floats[ 0 ] / basis;
|
||||
var g = floats[ 1 ] / basis;
|
||||
var b = floats[ 2 ] / basis;
|
||||
|
||||
return new Color( r, g, b, 1 );
|
||||
}
|
||||
|
||||
if ( floats.Count == 4 )
|
||||
{
|
||||
var r = floats[ 0 ] / basis;
|
||||
var g = floats[ 1 ] / basis;
|
||||
var b = floats[ 2 ] / basis;
|
||||
var alpha = floats[ 3 ] / basis;
|
||||
|
||||
return new Color( r, g, b, alpha );
|
||||
}
|
||||
|
||||
return new Color( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
public static Color UnblendBlack( this Color c, float treshold = 0 )
|
||||
{
|
||||
if ( c.A <= treshold )
|
||||
|
@ -62,6 +100,83 @@ namespace Rokojori
|
|||
return color.Gamma( 2.2f );
|
||||
}
|
||||
|
||||
public static Vector3 ToVector3( this Color color )
|
||||
{
|
||||
return new Vector3( color.R, color.G, color.B );
|
||||
}
|
||||
|
||||
public static Vector4 ToVector4( this Color color )
|
||||
{
|
||||
return new Vector4( color.R, color.G, color.B, color.A );
|
||||
}
|
||||
|
||||
public static Color ToColor( this Vector4 color )
|
||||
{
|
||||
return new Color( color.X, color.Y, color.Z, color.W );
|
||||
}
|
||||
|
||||
public static Color ToColor( this Vector3 color )
|
||||
{
|
||||
return new Color( color.X, color.Y, color.Z, 1f );
|
||||
}
|
||||
|
||||
public static Color ToColor( this Vector3 vec, float alpha = 1 )
|
||||
{
|
||||
return new Color( vec.X, vec.Y, vec.Z, alpha);
|
||||
}
|
||||
|
||||
public static Color ToColor( this Vector2 vec, float b = 0, float alpha = 1 )
|
||||
{
|
||||
return new Color( vec.X, vec.Y, b, alpha);
|
||||
}
|
||||
|
||||
public enum EdgeMode
|
||||
{
|
||||
Clamp,
|
||||
Repeat,
|
||||
TransparentBlack,
|
||||
}
|
||||
|
||||
|
||||
public static Color GetPixel( this Image image, int x, int y, EdgeMode mode )
|
||||
{
|
||||
if ( x < 0 || y < 0 || x >= image.GetSize().X || y >= image.GetSize().Y )
|
||||
{
|
||||
if ( mode == EdgeMode.TransparentBlack )
|
||||
{
|
||||
return new Color( 0, 0, 0, 0 );
|
||||
}
|
||||
|
||||
if ( mode == EdgeMode.Repeat )
|
||||
{
|
||||
x = MathX.Repeat( x, image.GetSize().X );
|
||||
y = MathX.Repeat( y, image.GetSize().Y );
|
||||
}
|
||||
|
||||
if ( mode == EdgeMode.Clamp )
|
||||
{
|
||||
x = Mathf.Clamp( x, 0, image.GetSize().X );
|
||||
y = Mathf.Clamp( y, 0, image.GetSize().Y );
|
||||
}
|
||||
}
|
||||
|
||||
return image.GetPixel( x, y );
|
||||
}
|
||||
|
||||
|
||||
public static Color Sample( this Image image, Vector2 uv, EdgeMode mode )
|
||||
{
|
||||
var pixelUV = uv * image.GetSize();
|
||||
var lowUV = pixelUV.FloorToInt().Max( 0 );
|
||||
var highUV = ( lowUV + Vector2I.One ).Min( image.GetSize() - Vector2I.One );
|
||||
|
||||
var mix = pixelUV - lowUV;
|
||||
|
||||
var xTop = Lerp( image.GetPixel( lowUV.X, lowUV.Y, mode ), image.GetPixel( highUV.X, lowUV.Y, mode ), mix.X );
|
||||
var xLow = Lerp( image.GetPixel( highUV.X, lowUV.Y, mode ), image.GetPixel( highUV.X, highUV.Y, mode ), mix.X );
|
||||
|
||||
return Lerp( xTop, xLow, mix.Y );
|
||||
}
|
||||
|
||||
public static Color Blend( Color bottom, Color top )
|
||||
{
|
||||
|
@ -151,10 +266,10 @@ namespace Rokojori
|
|||
|
||||
public static Color BlendColor( Color bottom, Color top )
|
||||
{
|
||||
var hslA = HSLColor.FromRGBA( bottom );
|
||||
var hslB = HSLColor.FromRGBA( top );
|
||||
var hslBottom = HSLColor.FromRGBA( bottom );
|
||||
var hslTop = HSLColor.FromRGBA( top );
|
||||
|
||||
var combined = bottom.A == 0 ? bottom : (Color)( new HSLColor( hslB.h, hslB.s, hslA.l, top.A ) );
|
||||
var combined = bottom.A == 0 ? bottom : (Color)( new HSLColor( hslTop.h, hslTop.s, hslBottom.l, top.A ) );
|
||||
|
||||
return ColorX.Blend( bottom, combined );
|
||||
}
|
||||
|
@ -211,11 +326,6 @@ namespace Rokojori
|
|||
return new Color( rgb.X, rgb.Y, rgb.Z, a );
|
||||
}
|
||||
|
||||
public static Vector4 ToVector4( Color c )
|
||||
{
|
||||
return new Vector4( c.R, c.G, c.B, c.A );
|
||||
}
|
||||
|
||||
public static Color FromVector4( Vector4 c )
|
||||
{
|
||||
return new Color( c.X, c.Y, c.Z, c.W );
|
||||
|
|
|
@ -81,8 +81,11 @@ namespace Rokojori
|
|||
|
||||
public static HSLColor FromRGBA( Color c )
|
||||
{
|
||||
float h, s, l, a;
|
||||
a = c.A;
|
||||
float h = 0;
|
||||
float s = 0;
|
||||
float l = 0;
|
||||
float a = c.A;
|
||||
|
||||
|
||||
float cmin = Mathf.Min( Mathf.Min( c.R, c.G ), c.B );
|
||||
float cmax = Mathf.Max( Mathf.Max( c.R, c.G ), c.B );
|
||||
|
|
|
@ -33,5 +33,87 @@ namespace Rokojori
|
|||
return Mathf.RadToDeg( rads );
|
||||
}
|
||||
|
||||
public static float ComputePixelDensityVertical( float fovDegrees, float distance, Vector2 screenSize )
|
||||
{
|
||||
float fovRadians = Mathf.DegToRad( fovDegrees );
|
||||
|
||||
float verticalViewSize = 2.0f * distance * Mathf.Tan( fovRadians / 2.0f );
|
||||
|
||||
float screenHeightPixels = screenSize.Y;
|
||||
|
||||
float pixelDensity = screenHeightPixels / verticalViewSize;
|
||||
|
||||
return pixelDensity;
|
||||
}
|
||||
|
||||
public static float ComputeSizeOfPixelVertical( float fovDegrees, float distance, Vector2 screenSize )
|
||||
{
|
||||
return ComputePixelDensityVertical( fovDegrees, distance, screenSize );
|
||||
}
|
||||
|
||||
|
||||
public static float ComputePixelDistanceForSizeVertical( float fovDegrees, float size, Vector2 screenSize )
|
||||
{
|
||||
float fovRadians = Mathf.DegToRad(fovDegrees);
|
||||
float screenHeightPixels = screenSize.Y;
|
||||
|
||||
float pixelDensity = 1.0f / size;
|
||||
|
||||
float distance = screenHeightPixels / (2.0f * pixelDensity * Mathf.Tan(fovRadians / 2.0f));
|
||||
|
||||
return distance;
|
||||
|
||||
}
|
||||
|
||||
public static float ComputePixelDensityHorizontal(float fovDegrees, float distance, Vector2 screenSize)
|
||||
{
|
||||
float aspectRatio = screenSize.X / screenSize.Y;
|
||||
|
||||
float verticalFovRad = Mathf.DegToRad( fovDegrees );
|
||||
|
||||
float horizontalFovRad = 2.0f * Mathf.Atan(Mathf.Tan( verticalFovRad / 2.0f ) * aspectRatio);
|
||||
|
||||
float horizontalViewSize = 2.0f * distance * Mathf.Tan( horizontalFovRad / 2.0f );
|
||||
|
||||
float pixelDensity = screenSize.X / horizontalViewSize;
|
||||
|
||||
return pixelDensity;
|
||||
}
|
||||
|
||||
public static Vector3 GlobalToView( Transform3D transform, Vector3 globalPosition )
|
||||
{
|
||||
return globalPosition * transform;
|
||||
}
|
||||
|
||||
public static Vector3 ViewToClip( Projection cameraProjection, Vector3 viewPosition )
|
||||
{
|
||||
var clip = cameraProjection * viewPosition;
|
||||
return clip;
|
||||
}
|
||||
|
||||
public static Vector2 ClipToScreen( Vector3 clipPosition )
|
||||
{
|
||||
var size = Vector2.One;
|
||||
var clip = clipPosition.XY() * 0.5f + new Vector2( 0.5f, 0.5f );
|
||||
return clip * size;
|
||||
}
|
||||
|
||||
public static Vector2 ClipToScreen( Vector3 clipPosition, Vector2 screenPixelSize )
|
||||
{
|
||||
var clip = clipPosition.XY() * 0.5f + new Vector2( 0.5f, 0.5f );
|
||||
return clip * screenPixelSize;
|
||||
}
|
||||
|
||||
|
||||
public static Vector2 GlobalToScreen( Vector3 globalPosition, Transform3D cameraTransform, Projection cameraProjection, Vector2 screenPixelSize )
|
||||
{
|
||||
var view = GlobalToView( cameraTransform, globalPosition );
|
||||
var clip = ViewToClip( cameraProjection, view );
|
||||
var screen = ClipToScreen( clip, screenPixelSize );
|
||||
|
||||
return screen;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
namespace Rokojori
|
||||
{
|
||||
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class RJAnimatableBody3D:AnimatableBody3D
|
||||
{
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
namespace Rokojori
|
||||
{
|
||||
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class RJCharacterBody3D:CharacterBody3D
|
||||
{
|
||||
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
using Godot;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class GodotEditorHelper
|
||||
{
|
||||
public static string AbsoluteToResourcePath( string path )
|
||||
{
|
||||
#if TOOLS
|
||||
|
||||
if ( path != null )
|
||||
{
|
||||
return ProjectSettings.LocalizePath( path );
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
public static bool IsProjectPath( string path )
|
||||
{
|
||||
return path.StartsWith( "res://" ) || path.StartsWith( "user://" );
|
||||
}
|
||||
|
||||
public static void UpdateFile( string path )
|
||||
{
|
||||
#if TOOLS
|
||||
|
||||
if ( ! IsProjectPath( path ) )
|
||||
{
|
||||
var pathBefore = path;
|
||||
path = AbsoluteToResourcePath( path );
|
||||
RJLog.Log( "Converted path", pathBefore, ">>", path );
|
||||
}
|
||||
|
||||
var filesystem = EditorInterface.Singleton.GetResourceFilesystem();
|
||||
filesystem.ReimportFiles( [ path ] );
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://c8ypyibkyf0ms
|
|
@ -29,6 +29,18 @@ namespace Rokojori
|
|||
|
||||
}
|
||||
|
||||
public static T FindSibling<T>( this Node node, Func<T,bool> evaluater = null ) where T:Node
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var sibling = NodesWalker.Get().FindSibling( node, n => n as T != null );
|
||||
|
||||
return sibling as T;
|
||||
}
|
||||
|
||||
public static T Find<T>( Node root, NodePathLocatorType type = NodePathLocatorType.DirectChildren, int parentOffset = 0 ) where T:Node
|
||||
{
|
||||
var it = root;
|
||||
|
@ -245,6 +257,17 @@ namespace Rokojori
|
|||
return;
|
||||
}
|
||||
|
||||
public static double StartAsyncTimer( this Node node )
|
||||
{
|
||||
return Async.StartTimer();
|
||||
}
|
||||
|
||||
public static async Task<double> WaitForAsyncTimer( this Node node, double time )
|
||||
{
|
||||
time = await Async.WaitIfExceeded( time, node );
|
||||
return time;
|
||||
}
|
||||
|
||||
public static T CreateChild<T>( this Node parent, string name = null ) where T:Node,new()
|
||||
{
|
||||
return CreateChildIn<T>( parent, name );
|
||||
|
|
|
@ -40,5 +40,7 @@ namespace Rokojori
|
|||
|
||||
return n.GetChildCount();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -12,12 +12,13 @@ namespace Rokojori
|
|||
[Export]
|
||||
public string path = "";
|
||||
|
||||
[Export]
|
||||
public bool load
|
||||
[ExportToolButton( "Read" )]
|
||||
public Callable ReadButton => Callable.From(
|
||||
()=>
|
||||
{
|
||||
get => false;
|
||||
set { if ( value ) LoadScene(); }
|
||||
LoadScene();
|
||||
}
|
||||
);
|
||||
|
||||
[Export]
|
||||
public bool exportJSON = false;
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace Rokojori
|
|||
{
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null || index<0 || index >= NumChildren( p ) )
|
||||
if ( p == null || index < 0 || index >= NumChildren( p ) )
|
||||
{ return null; }
|
||||
|
||||
return ChildAt( p, index );
|
||||
|
@ -74,11 +74,97 @@ namespace Rokojori
|
|||
public bool HasSiblingAt( N node, int index )
|
||||
{
|
||||
var p = Parent( node );
|
||||
if ( p == null || index<0 || index >= NumChildren( p ) )
|
||||
{ return false; }
|
||||
if ( p == null || index < 0 || index >= NumChildren( p ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public int NumSiblings( N node )
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return NumChildren( p ) - 1;
|
||||
}
|
||||
|
||||
public void IterateSiblings( N node, Action<N> action )
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var numChildren = NumChildren( p );
|
||||
|
||||
for ( int i = 0; i < numChildren; i++ )
|
||||
{
|
||||
var child = ChildAt( p, i );
|
||||
|
||||
if ( child == node )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
action( child );
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public N FindSibling( N node, Func<N,bool> evaluater )
|
||||
{
|
||||
if ( node == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var p = Parent( node );
|
||||
|
||||
if ( p == null )
|
||||
{
|
||||
return null ;
|
||||
}
|
||||
|
||||
var numChildren = NumChildren( p );
|
||||
|
||||
for ( int i = 0; i < numChildren; i++ )
|
||||
{
|
||||
var child = ChildAt( p, i );
|
||||
|
||||
if ( child == node )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var result = evaluater( child );
|
||||
|
||||
if ( result )
|
||||
{
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public N FirstChild( N node )
|
||||
{
|
||||
|
|
|
@ -2,13 +2,21 @@ using Godot;
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Grabbable.svg")]
|
||||
public partial class Grabbable:Node3D
|
||||
public partial class Grabbable:Node3D, iEnablable
|
||||
{
|
||||
|
||||
[Export]
|
||||
public bool enabled = true;
|
||||
public bool IsEnabled() => enabled;
|
||||
public void SetEnabled( bool enabled ) { this.enabled = enabled; }
|
||||
|
||||
|
||||
[Export]
|
||||
public Action onGrab;
|
||||
|
||||
|
@ -21,14 +29,46 @@ namespace Rokojori
|
|||
[Export]
|
||||
public RigidBody3D rigidBody3D;
|
||||
|
||||
[Export] Pointable pointable;
|
||||
|
||||
[Export]
|
||||
public bool disablePointableDuringGrab = true;
|
||||
|
||||
[ExportGroup("Read Only")]
|
||||
[Export]
|
||||
public Grabber grabber;
|
||||
|
||||
protected bool enablePointableOnRelease = false;
|
||||
|
||||
public void SetGrabber( Grabber grabber )
|
||||
{
|
||||
this.grabber = grabber;
|
||||
|
||||
|
||||
if ( grabber != null && ( disablePointableDuringGrab || grabber.disablePointableDuringGrab ) )
|
||||
{
|
||||
if ( pointable == null )
|
||||
{
|
||||
pointable = this.FindSibling<Pointable>();
|
||||
}
|
||||
|
||||
if ( pointable != null )
|
||||
{
|
||||
pointable.enabled = false;
|
||||
enablePointableOnRelease = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ( grabber == null )
|
||||
{
|
||||
if ( pointable != null && enablePointableOnRelease )
|
||||
{
|
||||
pointable.enabled = true;
|
||||
}
|
||||
|
||||
enablePointableOnRelease = false;
|
||||
}
|
||||
|
||||
if ( this.grabber != null )
|
||||
{
|
||||
Action.Trigger( onGrab );
|
||||
|
|
|
@ -5,7 +5,7 @@ using Godot.Collections;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Grabber.svg")]
|
||||
public partial class Grabber:Node3D, SensorInputHandler
|
||||
{
|
||||
|
@ -27,6 +27,9 @@ namespace Rokojori
|
|||
[Export]
|
||||
public Node3D grabOffset;
|
||||
|
||||
[Export]
|
||||
public bool disablePointableDuringGrab = true;
|
||||
|
||||
[Export]
|
||||
public Smoothing positionSmoothing;
|
||||
|
||||
|
@ -39,6 +42,7 @@ namespace Rokojori
|
|||
|
||||
|
||||
|
||||
|
||||
public override void _Ready()
|
||||
{
|
||||
SensorManager.Register( this, button );
|
||||
|
|
|
@ -5,10 +5,15 @@ using Godot.Collections;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Interactable.svg")]
|
||||
public partial class Interactable:Node3D
|
||||
public partial class Interactable:Node3D, iEnablable
|
||||
{
|
||||
[Export]
|
||||
public bool enabled = true;
|
||||
public bool IsEnabled() => enabled;
|
||||
public void SetEnabled( bool enabled ) { this.enabled = enabled; }
|
||||
|
||||
[Export]
|
||||
public Action onInteraction;
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ using Godot.Collections;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Interactor.svg")]
|
||||
public partial class Interactor:Node3D, SensorInputHandler
|
||||
{
|
||||
|
|
|
@ -5,10 +5,18 @@ using Godot.Collections;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
[Tool]
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/Pointable.svg")]
|
||||
public partial class Pointable:Node3D
|
||||
public partial class Pointable:Node3D, iEnablable
|
||||
{
|
||||
[Export]
|
||||
public bool enabled = true;
|
||||
|
||||
public bool IsEnabled() => enabled;
|
||||
public void SetEnabled( bool enabled ) { this.enabled = enabled; }
|
||||
|
||||
|
||||
|
||||
[Export]
|
||||
public int pointingPriority;
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class InteractiveSelector:Selector
|
||||
{
|
||||
[Export]
|
||||
public Trillean isPointable = Trillean.Any;
|
||||
|
||||
[Export]
|
||||
public Trillean pointableEnabled = Trillean.Any;
|
||||
|
||||
[Export]
|
||||
public Trillean isGrabbable = Trillean.Any;
|
||||
|
||||
[Export]
|
||||
public Trillean grabbableEnabled = Trillean.Any;
|
||||
|
||||
[Export]
|
||||
public Trillean isInteractable = Trillean.Any;
|
||||
|
||||
[Export]
|
||||
public Trillean interactableEnabled = Trillean.Any;
|
||||
|
||||
|
||||
public override bool Selects( Node node )
|
||||
{
|
||||
if ( ! Matches<Pointable>( node, isPointable, pointableEnabled ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! Matches<Grabbable>( node, isGrabbable, grabbableEnabled ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! Matches<Interactable>( node, isInteractable, interactableEnabled ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Matches<T>( Node node, Trillean isType, Trillean isEnabled ) where T:Node,iEnablable
|
||||
{
|
||||
var childNode = Nodes.Find<T>( node );
|
||||
|
||||
if ( ! TrilleanLogic.Matches( isType, childNode != null ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ( ! TrilleanLogic.Matches( isEnabled, childNode != null && childNode.IsEnabled() ) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://bcqxkle5dxw3c
|
|
@ -0,0 +1,23 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class SetPointableEnabled:Action
|
||||
{
|
||||
[Export]
|
||||
public Pointable pointable;
|
||||
|
||||
[Export]
|
||||
public bool enabled = true;
|
||||
|
||||
protected override void _OnTrigger()
|
||||
{
|
||||
pointable.enabled = enabled;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://vfc8utojwc0b
|
|
@ -0,0 +1,14 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
||||
public interface iEnablable
|
||||
{
|
||||
public bool IsEnabled();
|
||||
public void SetEnabled( bool enabled );
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://do5nirsv6cj67
|
|
@ -0,0 +1,104 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class LODCameraDistanceLevel
|
||||
{
|
||||
public Mesh mesh;
|
||||
public Material material;
|
||||
public float distance;
|
||||
}
|
||||
|
||||
public class LODBuilder
|
||||
{
|
||||
public enum Mode
|
||||
{
|
||||
CameraDistance
|
||||
}
|
||||
|
||||
Mode mode = Mode.CameraDistance;
|
||||
|
||||
public static LODBuilder ByCameraDistance()
|
||||
{
|
||||
var builder = new LODBuilder();
|
||||
|
||||
builder.mode = Mode.CameraDistance;
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
List<LODCameraDistanceLevel> levels = new List<LODCameraDistanceLevel>();
|
||||
|
||||
Material material;
|
||||
|
||||
public LODBuilder SetMaterial( Material material )
|
||||
{
|
||||
this.material = material;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public LODBuilder Add( float distance, Mesh mesh, Material material = null )
|
||||
{
|
||||
var level = new LODCameraDistanceLevel
|
||||
{
|
||||
mesh = mesh,
|
||||
distance = distance,
|
||||
material = material
|
||||
};
|
||||
|
||||
levels.Add( level );
|
||||
return this;
|
||||
}
|
||||
|
||||
public LODNode Create( Node parent, string name = "LOD" )
|
||||
{
|
||||
var lodNode = parent.CreateChild<LODNode>( name );
|
||||
|
||||
var arrangement = new LODArrangement();
|
||||
|
||||
levels.Sort( ( a, b ) => Mathf.Sign( a.distance - b.distance ) );
|
||||
|
||||
var maxMap = new Dictionary<LODCameraDistanceLevel, float>();
|
||||
|
||||
for ( int i = 0; i < levels.Count; i++ )
|
||||
{
|
||||
if ( ( i + 1 ) < levels.Count )
|
||||
{
|
||||
maxMap[ levels[ i ] ] = levels[ i + 1 ].distance;
|
||||
}
|
||||
else
|
||||
{
|
||||
maxMap[ levels[ i ] ] = 10000f;
|
||||
}
|
||||
}
|
||||
|
||||
levels[ 0 ].distance = 0;
|
||||
|
||||
levels.ForEach(
|
||||
( l )=>
|
||||
{
|
||||
var level = new LODLevel();
|
||||
var distanceRule = new LODCameraDistanceRule();
|
||||
distanceRule.minDistance = l.distance;
|
||||
distanceRule.maxDistance = maxMap[ l ];
|
||||
|
||||
level.visibilityRules = [ distanceRule ];
|
||||
level.mesh = l.mesh;
|
||||
level.material = l.material != null ? l.material : material;
|
||||
arrangement.levels = arrangement.levels.Add( level );
|
||||
}
|
||||
);
|
||||
|
||||
lodNode.arrangement = arrangement;
|
||||
|
||||
|
||||
return lodNode;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://c6bp7sk6mtglv
|
|
@ -15,7 +15,7 @@ namespace Rokojori
|
|||
|
||||
public override bool Evaluate( LODNode lodNode )
|
||||
{
|
||||
return false;
|
||||
return Range.Contains( minDistance, maxDistance, lodNode.distance );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class LODMeshCreator:Node
|
||||
{
|
||||
[Export]
|
||||
public MeshInstance3D[] meshes;
|
||||
|
||||
[Export]
|
||||
public float[] distances;
|
||||
|
||||
[Export]
|
||||
public Mesh.PrimitiveType primitiveType = Mesh.PrimitiveType.Triangles;
|
||||
|
||||
[Export]
|
||||
public bool generateTangents = true;
|
||||
|
||||
[ExportToolButton("Create")]
|
||||
public Callable CreateButton => Callable.From( ()=>{ Create(); } );
|
||||
|
||||
[ExportGroup("Output")]
|
||||
[Export]
|
||||
public MeshInstance3D lodMesh;
|
||||
|
||||
public async Task Create()
|
||||
{
|
||||
var list = new List<MeshGeometry>();
|
||||
|
||||
var index = 0;
|
||||
|
||||
foreach ( var m in meshes )
|
||||
{
|
||||
var mg = MeshGeometry.From( m.Mesh as ArrayMesh );
|
||||
mg.lodEdgeLength = distances[ index ];
|
||||
index++;
|
||||
|
||||
await this.RequestNextFrame();
|
||||
}
|
||||
|
||||
var mesh = MeshGeometry.GenerateLODMesh( list, primitiveType, null, generateTangents );
|
||||
|
||||
await this.RequestNextFrame();
|
||||
|
||||
this.DestroyChildren();
|
||||
|
||||
await this.RequestNextFrame();
|
||||
|
||||
lodMesh = this.CreateChild<MeshInstance3D>( "LODMesh" );
|
||||
lodMesh.Mesh = mesh;
|
||||
lodMesh.Mesh.SurfaceSetMaterial( 0, MaterialSurfaceContainer.GetActiveFrom( meshes[ 0 ] ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://cmvumubfr1hvu
|
|
@ -1,7 +1,6 @@
|
|||
using Godot;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot.Collections;
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
|
@ -9,9 +8,22 @@ namespace Rokojori
|
|||
[GlobalClass]
|
||||
public partial class LODNode:MeshInstance3D
|
||||
{
|
||||
|
||||
[Export]
|
||||
public LODArrangement arrangement;
|
||||
|
||||
[Export]
|
||||
public int currentLevelIndex = -1;
|
||||
|
||||
[Export]
|
||||
public int drawElements = 0;
|
||||
|
||||
[Export]
|
||||
public float distanceScale = 1;
|
||||
|
||||
[Export]
|
||||
public MeshInstance3D lod0;
|
||||
|
||||
LODLevel _currentLevel;
|
||||
|
||||
public override void _Process( double delta )
|
||||
|
@ -33,10 +45,34 @@ namespace Rokojori
|
|||
return;
|
||||
}
|
||||
|
||||
currentLevelIndex = arrangement.levels.IndexOf( level );
|
||||
|
||||
if ( lod0 != null )
|
||||
{
|
||||
lod0.Visible = currentLevelIndex == 0;
|
||||
}
|
||||
|
||||
if ( ! faceCount.ContainsKey( level.mesh ) )
|
||||
{
|
||||
if ( level.mesh is ArrayMesh am )
|
||||
{
|
||||
faceCount[ level.mesh ] = am.SurfaceGetArrayIndexLen( 0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
faceCount[ level.mesh ] = level.mesh.GetFaces().Length;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
drawElements = faceCount[ level.mesh ];
|
||||
Mesh = level.mesh;
|
||||
MaterialOverride = level.material;
|
||||
}
|
||||
|
||||
Dictionary<Mesh,int> faceCount = new Dictionary<Mesh,int>();
|
||||
|
||||
|
||||
public Camera3D camera
|
||||
{
|
||||
|
@ -73,6 +109,8 @@ namespace Rokojori
|
|||
|
||||
_cameraDirection = ( GlobalPosition - camera.GlobalPosition );
|
||||
|
||||
_hasCameraDirection = true;
|
||||
|
||||
return _cameraDirection;
|
||||
}
|
||||
}
|
||||
|
@ -86,12 +124,14 @@ namespace Rokojori
|
|||
{
|
||||
if ( _hasDistance )
|
||||
{
|
||||
return _distance;
|
||||
return _distance * distanceScale;
|
||||
}
|
||||
|
||||
_distance = cameraDirection.Length();
|
||||
|
||||
return _distance;
|
||||
_hasDistance = true;
|
||||
|
||||
return _distance * distanceScale;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -109,6 +149,8 @@ namespace Rokojori
|
|||
|
||||
_pitch = Math3D.GlobalPitch( cameraDirection );
|
||||
|
||||
_hasPitch = true;
|
||||
|
||||
return _pitch;
|
||||
}
|
||||
}
|
||||
|
@ -127,6 +169,8 @@ namespace Rokojori
|
|||
|
||||
_yaw = Math3D.GlobalYaw( cameraDirection );
|
||||
|
||||
_hasYaw = true;
|
||||
|
||||
return _yaw;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,262 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class OcTree<T>:OcTreeNode<T>
|
||||
{
|
||||
protected Func<T,Vector3> _getPosition;
|
||||
protected Func<List<T>,List<T>> _combinePoints;
|
||||
protected Func<List<T>,List<T>, float,List<T>> _smoothPoints;
|
||||
|
||||
protected Vector3 _min;
|
||||
protected Vector3 _max;
|
||||
protected float _rootCellSize;
|
||||
|
||||
protected int _maxDepth = 64;
|
||||
public int maxDepth => _maxDepth;
|
||||
|
||||
public OcTree( Func<T,Vector3> getPosition, Vector3 min, Vector3 max, float rootCellSize, int maxDepth )
|
||||
{
|
||||
this._getPosition = getPosition;
|
||||
this._min = min;
|
||||
this._max = max;
|
||||
this._rootCellSize = rootCellSize;
|
||||
this._maxDepth = maxDepth;
|
||||
|
||||
CreateRootCells();
|
||||
|
||||
}
|
||||
|
||||
public void SetCombiner( Func<List<T>,List<T>> combinePoints )
|
||||
{
|
||||
this._combinePoints = combinePoints;
|
||||
}
|
||||
|
||||
public void SetSmoother( Func<List<T>,List<T>,float,List<T>> smoothPoints )
|
||||
{
|
||||
this._smoothPoints = smoothPoints;
|
||||
}
|
||||
|
||||
|
||||
public List<T> CombinePoints( List<T> values )
|
||||
{
|
||||
return _combinePoints( values );
|
||||
}
|
||||
|
||||
public List<T> SmoothPoints( List<T> targetValues, List<T> sourceSmoothing, float amount )
|
||||
{
|
||||
return _smoothPoints( targetValues, sourceSmoothing, amount );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
List<OcTreeCell<T>> _rootCells = new List<OcTreeCell<T>>();
|
||||
public List<OcTreeCell<T>> rootCells => _rootCells;
|
||||
|
||||
public bool Insert( List<T> data )
|
||||
{
|
||||
var result = true;
|
||||
|
||||
data.ForEach(
|
||||
( d )=>
|
||||
{
|
||||
result = result && Insert( d );
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public bool Insert( T data )
|
||||
{
|
||||
var rootCell = GetRootCell( _getPosition( data ) );
|
||||
|
||||
if ( rootCell == null )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( ! rootCell.box.ContainsPoint( GetPosition( data ) ) )
|
||||
{
|
||||
RJLog.Log( "Box not containing point", rootCell.rootCellIndex );
|
||||
}
|
||||
|
||||
return rootCell.Insert( data );
|
||||
}
|
||||
|
||||
public int GetLevelForSize( float size )
|
||||
{
|
||||
var level = 0;
|
||||
var it = _rootCellSize;
|
||||
|
||||
while ( it > size )
|
||||
{
|
||||
level ++;
|
||||
it /= 2f;
|
||||
}
|
||||
|
||||
return level;
|
||||
}
|
||||
|
||||
public float GetSizeForLevel( int level )
|
||||
{
|
||||
var it = 0;
|
||||
var size = _rootCellSize;
|
||||
|
||||
while ( it < level )
|
||||
{
|
||||
size /= 2f;
|
||||
it ++;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
public void CombineUntilSize( float size )
|
||||
{
|
||||
CombineUntilLevel( GetLevelForSize( size ) );
|
||||
}
|
||||
|
||||
|
||||
public void CombineUntilLevel( int minLevel, float smoothDown = 0.2f )
|
||||
{
|
||||
var levelMap = GetLevelMap();
|
||||
var levels = levelMap.Keys.ToList();
|
||||
levels.Sort();
|
||||
var maxLevel = levels.Last();
|
||||
|
||||
for ( int i = maxLevel - 1; i > minLevel; i-- )
|
||||
{
|
||||
levelMap[ i ].ForEach(
|
||||
( c )=>
|
||||
{
|
||||
c.Combine();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if ( smoothDown > 0 )
|
||||
{
|
||||
for ( int i = minLevel + 1; i < maxLevel - 1; i++ )
|
||||
{
|
||||
levelMap[ i ].ForEach(
|
||||
( c )=>
|
||||
{
|
||||
c.SmoothDown( smoothDown );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public MapList<int,OcTreeCell<T>> GetLevelMap()
|
||||
{
|
||||
var walker = new OcTreeWalker<T>();
|
||||
|
||||
var levelMap = new MapList<int,OcTreeCell<T>>();
|
||||
|
||||
walker.Iterate(
|
||||
this,
|
||||
( n )=>
|
||||
{
|
||||
if ( n is OcTree<T> tree )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var c = n as OcTreeCell<T>;
|
||||
|
||||
levelMap.Add( c.depth, c );
|
||||
}
|
||||
);
|
||||
|
||||
return levelMap;
|
||||
}
|
||||
|
||||
Vector3 _startOffset = Vector3.Zero;
|
||||
Vector3I _rootCellDimensions = Vector3I.Zero;
|
||||
|
||||
public Vector3I PositionToRootIndex( Vector3 position )
|
||||
{
|
||||
position -= _startOffset;
|
||||
|
||||
var index = ( position / ( Vector3.One * _rootCellSize ) ).FloorToInt();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public Vector3 GetPosition( T data )
|
||||
{
|
||||
return _getPosition( data );
|
||||
}
|
||||
|
||||
public OcTreeCell<T> GetRootCell( Vector3 position )
|
||||
{
|
||||
var rootIndex = PositionToRootIndex( position );
|
||||
return GetRootCellByRootIndex( rootIndex );
|
||||
}
|
||||
|
||||
public OcTreeCell<T> GetRootCellByRootIndex( Vector3I rootCellIndex )
|
||||
{
|
||||
var rootCellFlatIndex = MathX.MultiIndexToFlatIndex( rootCellIndex, _rootCellDimensions );
|
||||
|
||||
if ( rootCellFlatIndex < 0 || rootCellFlatIndex >= _rootCells.Count )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return _rootCells[ rootCellFlatIndex ];
|
||||
}
|
||||
|
||||
|
||||
void CreateRootCells()
|
||||
{
|
||||
var rootCellSize3 = Vector3.One * _rootCellSize;
|
||||
var start = _min.SnapFloored( rootCellSize3 );
|
||||
var end = _max.SnapCeiled( rootCellSize3 );
|
||||
|
||||
var num = ( ( end - start ) / rootCellSize3 ).RoundToInt();
|
||||
|
||||
_rootCellDimensions = num;
|
||||
_startOffset = start;
|
||||
|
||||
for ( int x = 0; x < num.X ; x ++ )
|
||||
{
|
||||
for ( int y = 0; y < num.Y; y++ )
|
||||
{
|
||||
for ( int z = 0; z < num.Z; z++ )
|
||||
{
|
||||
var rootIndex = new Vector3I( x, y, z );
|
||||
var min = rootIndex * rootCellSize3 + start;
|
||||
var max = min + rootCellSize3;
|
||||
|
||||
var cell = OcTreeCell<T>.Create( this, min, max, _rootCells.Count );
|
||||
|
||||
_rootCells.Add( cell );
|
||||
|
||||
// var positionRootIndex = PositionToRootIndex( cell.center );
|
||||
|
||||
// RJLog.Log(
|
||||
// "Creating root cell",
|
||||
// "Roots Index:", _rootCells.Count - 1,
|
||||
// "Cell Index:", cell.rootCellIndex,
|
||||
// "Center:", cell.center,
|
||||
// "RootIndex:", rootIndex,
|
||||
// "Get Self ByRootIndex:", GetRootCellByRootIndex( rootIndex ) == cell,
|
||||
// "RootIndex From Position: ", positionRootIndex,
|
||||
// "Get Self ByRootIndex From Position:", GetRootCellByRootIndex( positionRootIndex ) == cell
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://byv0j4gqliwii
|
|
@ -0,0 +1,202 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class OcTreeCell<T>:OcTreeNode<T>
|
||||
{
|
||||
OcTreeCell<T> _parent;
|
||||
public OcTreeCell<T> parent => _parent;
|
||||
|
||||
OcTree<T> _tree;
|
||||
public OcTree<T> tree => _tree;
|
||||
|
||||
List<OcTreeCell<T>> _cells;
|
||||
public List<OcTreeCell<T>> cells => _cells;
|
||||
|
||||
|
||||
public int numCells => _cells == null ? 0 : cells.Count;
|
||||
|
||||
List<T> _values;
|
||||
public List<T> values => _values;
|
||||
|
||||
int _depth;
|
||||
public int depth => _depth;
|
||||
|
||||
Vector3 _center;
|
||||
public Vector3 center => _center;
|
||||
|
||||
Vector3 _size;
|
||||
public Vector3 size => _size;
|
||||
|
||||
bool _isCombined = false;
|
||||
public bool isCombined => _isCombined;
|
||||
public bool canBeCombined => ! isLeaf && ! isCombined && numCells > 0;
|
||||
|
||||
|
||||
public bool isRoot => _parent == null;
|
||||
public bool isEmpty => _cells == null || _cells.Count == 0;
|
||||
public bool isLeaf => _depth == tree.maxDepth;
|
||||
|
||||
Box3 _box;
|
||||
public Box3 box => _box;
|
||||
|
||||
int _rootCellIndex = -1;
|
||||
public int rootCellIndex => _rootCellIndex;
|
||||
|
||||
|
||||
public static OcTreeCell<T> Create( OcTree<T> tree, Vector3 min, Vector3 max, int rootIndex )
|
||||
{
|
||||
var cell = new OcTreeCell<T>();
|
||||
cell._tree = tree;
|
||||
cell._center = (max + min ) / 2f;
|
||||
cell._size = ( max - min );
|
||||
cell._depth = 0;
|
||||
cell._box = Box3.Create( min, max );
|
||||
cell._rootCellIndex = rootIndex;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
public static OcTreeCell<T> Create( OcTreeCell<T> parent, int depth, Vector3 min, Vector3 max )
|
||||
{
|
||||
var cell = new OcTreeCell<T>();
|
||||
cell._parent = parent;
|
||||
cell._tree = parent.tree;
|
||||
cell._center = (max + min ) / 2f;
|
||||
cell._size = ( max - min );
|
||||
cell._depth = depth;
|
||||
cell._box = Box3.Create( min, max );
|
||||
cell._rootCellIndex = parent.rootCellIndex;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
public Vector3 GetPointWithPolarUVW( Vector3 polarUVW )
|
||||
{
|
||||
var halfSize = _size / 2f;
|
||||
|
||||
return _center + halfSize * polarUVW;
|
||||
}
|
||||
|
||||
public bool Insert( T data )
|
||||
{
|
||||
if ( isLeaf )
|
||||
{
|
||||
if ( _values == null )
|
||||
{
|
||||
_values = new List<T>();
|
||||
}
|
||||
|
||||
values.Add( data );
|
||||
return true;
|
||||
}
|
||||
|
||||
Nest();
|
||||
|
||||
var position = tree.GetPosition( data );
|
||||
|
||||
var cell = GetChildCellFor( position );
|
||||
|
||||
if ( cell == null )
|
||||
{
|
||||
RJLog.Log( "No cell found in:", this.depth, this.center, ">> for: ", position );
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return cell.Insert( data );
|
||||
}
|
||||
|
||||
public void SmoothDown( float amount )
|
||||
{
|
||||
if ( isLeaf || cells == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cells.ForEach(
|
||||
( c )=>
|
||||
{
|
||||
c._values = tree.SmoothPoints( c.values, values, amount );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
public void Combine()
|
||||
{
|
||||
if ( isLeaf || isCombined )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( numCells == 0 )
|
||||
{
|
||||
_isCombined = true;
|
||||
return;
|
||||
}
|
||||
|
||||
var cellPoints = new List<T>();
|
||||
cells.ForEach(
|
||||
c =>
|
||||
{
|
||||
if ( c.values == null )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cellPoints.AddRange( c.values );
|
||||
}
|
||||
);
|
||||
|
||||
_values = tree.CombinePoints( cellPoints );
|
||||
_isCombined = true;
|
||||
}
|
||||
|
||||
public OcTreeCell<T> GetChildCellFor( Vector3 position )
|
||||
{
|
||||
return _cells.Find( c => c.box.ContainsPoint( position ) );
|
||||
}
|
||||
|
||||
|
||||
public void Nest()
|
||||
{
|
||||
if ( _cells != null && _cells.Count == 8 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_cells = new List<OcTreeCell<T>>();
|
||||
|
||||
for ( int x = -1; x < 1; x ++ )
|
||||
{
|
||||
var x0 = x;
|
||||
var x1 = x + 1;
|
||||
|
||||
for ( int y = -1; y < 1; y ++ )
|
||||
{
|
||||
var y0 = y;
|
||||
var y1 = y + 1;
|
||||
|
||||
for ( int z = -1; z < 1; z ++ )
|
||||
{
|
||||
var z0 = z;
|
||||
var z1 = z + 1;
|
||||
|
||||
var min = GetPointWithPolarUVW( new Vector3( x0, y0, z0 ) );
|
||||
var max = GetPointWithPolarUVW( new Vector3( x1, y1, z1 ) );
|
||||
|
||||
_cells.Add( Create( this, depth + 1, min, max ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://bkg701bcjl3nu
|
|
@ -0,0 +1,14 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class OcTreeNode<T>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://dyyollc58p3l6
|
|
@ -0,0 +1,53 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class OcTreeWalker<T>:TreeWalker<OcTreeNode<T>>
|
||||
{
|
||||
public override OcTreeNode<T> Parent( OcTreeNode<T> node )
|
||||
{
|
||||
if ( node is OcTree<T> )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var cell = node as OcTreeCell<T>;
|
||||
|
||||
return cell.isRoot ? cell.tree : cell.parent;
|
||||
}
|
||||
|
||||
public override int NumChildren( OcTreeNode<T> node )
|
||||
{
|
||||
if ( node is OcTree<T> tree )
|
||||
{
|
||||
return tree.rootCells.Count;
|
||||
}
|
||||
|
||||
var cell = node as OcTreeCell<T>;
|
||||
|
||||
return cell.numCells;
|
||||
}
|
||||
|
||||
public override OcTreeNode<T> ChildAt( OcTreeNode<T> node, int index )
|
||||
{
|
||||
if ( index < 0 || index >= NumChildren( node ) )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if ( node is OcTree<T> tree )
|
||||
{
|
||||
return tree.rootCells[ index ];
|
||||
}
|
||||
|
||||
var cell = node as OcTreeCell<T>;
|
||||
|
||||
return cell.cells[ index ];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://u5ybxjw7q03t
|
|
@ -0,0 +1,51 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori.PointClouds
|
||||
{
|
||||
public class Point
|
||||
{
|
||||
public Vector3 position;
|
||||
public Color color;
|
||||
public Vector3 normal;
|
||||
public Vector2 uv;
|
||||
|
||||
public Point Lerp( Point point, float amount )
|
||||
{
|
||||
var p = new Point();
|
||||
|
||||
p.position = position.Lerp( point.position, amount );
|
||||
p.normal = normal.Lerp( point.normal, amount ).Normalized();
|
||||
p.uv = uv.Lerp( point.uv, amount );
|
||||
p.color = color.ToVector4().Lerp( point.color.ToVector4(), amount ).ToColor();
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
public static Point AsAverage( List<Point> points )
|
||||
{
|
||||
var p = new Point();
|
||||
|
||||
var color = new Vector4();
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
var d = 1f / ( i + 1 );
|
||||
p.position += d * ( points[ i ].position - p.position );
|
||||
p.normal += d * ( points[ i ].normal - p.normal );
|
||||
p.uv += d * ( points[ i ].uv - p.uv );
|
||||
color += d * ( points[ i ].color.ToVector4() - color );
|
||||
}
|
||||
|
||||
p.normal = p.normal.Normalized();
|
||||
p.color = color.ToColor();
|
||||
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://cwoel0qagkx5l
|
|
@ -0,0 +1,66 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rokojori.PointClouds
|
||||
{
|
||||
public class PointCloud
|
||||
{
|
||||
public List<Point> points = new List<Point>();
|
||||
|
||||
public Vector3 center;
|
||||
|
||||
public void ComputeCenter()
|
||||
{
|
||||
center = Math3D.ComputeAverage( points, p => p.position );
|
||||
}
|
||||
|
||||
public Box3 boundingBox;
|
||||
|
||||
public void ComputeBoundingBox()
|
||||
{
|
||||
boundingBox = Box3.Create( points, p => p.position );
|
||||
}
|
||||
|
||||
public void SortByDistanceToCenter()
|
||||
{
|
||||
ComputeCenter();
|
||||
|
||||
points.Sort(
|
||||
( a, b ) =>
|
||||
{
|
||||
var dA = ( a.position - center ).LengthSquared();
|
||||
var dB = ( b.position - center ).LengthSquared();
|
||||
|
||||
return Mathf.Sign( dB - dA );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public ArrayMesh GenerateMesh( float normalOffset = 0f )
|
||||
{
|
||||
var mg = GenerateMeshGeometry( normalOffset );
|
||||
return mg.GenerateMesh( Mesh.PrimitiveType.Points, null, false );
|
||||
}
|
||||
|
||||
public MeshGeometry GenerateMeshGeometry( float normalOffset = 0f )
|
||||
{
|
||||
var mg = new MeshGeometry( true, false, true, false );
|
||||
mg.customMeshAttributes.Add( new MeshAttributeVector4List( 0 ) );
|
||||
mg.customMeshAttributes.Add( new MeshAttributeVector4List( 1 ) );
|
||||
|
||||
points.ForEach(
|
||||
( p ) =>
|
||||
{
|
||||
mg.AddPoint( p.position + p.normal * normalOffset, p.color.srgbToLinear(), p.normal, 0, p.uv, 1 );
|
||||
}
|
||||
);
|
||||
|
||||
return mg;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://box2fnynegqik
|
|
@ -0,0 +1,258 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
namespace Rokojori.PointClouds
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class PointCloudGenerator:Node3D
|
||||
{
|
||||
[Export]
|
||||
public MeshInstance3D mesh;
|
||||
|
||||
[Export]
|
||||
public PointCloudSampler.SampleMode sampleMode = PointCloudSampler.SampleMode.Center;
|
||||
|
||||
[Export]
|
||||
public float samplingPixelDensity = 0.01f;
|
||||
|
||||
[Export]
|
||||
public float outputPixelDensity = 0.5f;
|
||||
|
||||
[Export]
|
||||
|
||||
public int numPoints = 0;
|
||||
|
||||
[Export]
|
||||
public int squareTexture;
|
||||
|
||||
[Export]
|
||||
public Material material;
|
||||
|
||||
[Export]
|
||||
public bool createOutputs = false;
|
||||
|
||||
[Export]
|
||||
public MeshInstance3D[] outputs;
|
||||
|
||||
[ExportGroup("Lerping")]
|
||||
[Export]
|
||||
public Curve lowerLerp;
|
||||
|
||||
[Export]
|
||||
public Curve higherLerp;
|
||||
|
||||
[Export]
|
||||
public int lerpSteps;
|
||||
|
||||
[ExportGroup("")]
|
||||
|
||||
[Export]
|
||||
public LODNode lod;
|
||||
|
||||
|
||||
[Export]
|
||||
bool working = false;
|
||||
|
||||
[Export]
|
||||
public string[] outputInfos = [];
|
||||
|
||||
[ExportToolButton( "Generate")]
|
||||
public Callable GenerateButton => Callable.From(
|
||||
() =>
|
||||
{
|
||||
GeneratePointCloud();
|
||||
}
|
||||
);
|
||||
|
||||
public async void GeneratePointCloud()
|
||||
{
|
||||
if ( working )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
working = true;
|
||||
numPoints = -1;
|
||||
this.LogInfo( "Generating Point Cloud" );
|
||||
|
||||
|
||||
var sampler = new PointCloudSampler();
|
||||
|
||||
if ( samplingPixelDensity > 0 )
|
||||
{
|
||||
sampler.densityResolution = samplingPixelDensity;
|
||||
}
|
||||
|
||||
sampler.materials = Materials.GetAll<Material>( mesh );
|
||||
sampler.albedoTexture = sampler.materials.Map( m => Texture2DPropertyName.albedoTexture );
|
||||
sampler.albedo = sampler.materials.Map( m => ColorPropertyName.albedo ); ;
|
||||
|
||||
var cloud = await sampler.SampleFromMesh( sampleMode, (ArrayMesh) mesh.Mesh, this );
|
||||
|
||||
this.LogInfo( "Sampled mesh" );
|
||||
|
||||
var time = Async.GetTimeMS();
|
||||
// cloud.ComputeBoundingBox();
|
||||
|
||||
time = Async.PrintAndUpdateMS( time );
|
||||
|
||||
var longestCM = cloud.boundingBox.size.MaxDimension() * 100f;
|
||||
var nextP2CM = MathX.NextPowerOfTwo( longestCM );
|
||||
var rootSize = nextP2CM / 100f;
|
||||
var ocMin = cloud.boundingBox.center - Vector3.One * rootSize;
|
||||
var ocMax = cloud.boundingBox.center + Vector3.One * rootSize;
|
||||
var depth = Mathf.CeilToInt( MathX.Exponent( 2, rootSize/ samplingPixelDensity ) );
|
||||
|
||||
var ocTree = new PointCloudOcTree( ocMin, ocMax, rootSize, depth );
|
||||
|
||||
var minSize = ocTree.GetSizeForLevel( depth );
|
||||
|
||||
this.LogInfo( "OcTree MinDepth", minSize._CM() );
|
||||
|
||||
this.RequestNextFrame();
|
||||
time = Async.PrintAndUpdateMS( time, "Inserting to octree" );
|
||||
ocTree.Insert( cloud.points );
|
||||
time = Async.PrintAndUpdateMS( time, "Inserting to octree Done" );
|
||||
var level = ocTree.GetLevelForSize( outputPixelDensity );
|
||||
|
||||
this.LogInfo( "Combining" );
|
||||
this.RequestNextFrame();
|
||||
time = Async.PrintAndUpdateMS( time, "Combining" );
|
||||
|
||||
ocTree.normalSeperation = false;
|
||||
ocTree.CombineUntilLevel( level );
|
||||
|
||||
time = Async.PrintAndUpdateMS( time, "Combining Done" );
|
||||
|
||||
this.LogInfo( "Combining level", level, "Max Level", depth );
|
||||
|
||||
|
||||
|
||||
this.LogInfo( "Cloud Points:", cloud.points.Count );
|
||||
|
||||
if ( outputs != null )
|
||||
{
|
||||
outputs = [];
|
||||
}
|
||||
|
||||
|
||||
|
||||
this.DestroyChildren();
|
||||
|
||||
|
||||
var levelMap = ocTree.GetLevelMap();
|
||||
|
||||
var levelInstances = new List<MeshInstance3D>();
|
||||
|
||||
var lodBuilder = LODBuilder.ByCameraDistance();
|
||||
|
||||
lodBuilder.SetMaterial( material );
|
||||
|
||||
// lodBuilder.Add( 0, mesh.Mesh, mesh.GetSurfaceOverrideMaterial( 0 ) );
|
||||
|
||||
var meshGeometries = new List<MeshGeometry>();
|
||||
|
||||
var infos = new List<string>();
|
||||
|
||||
for ( int i = level + 1; i < depth; i++ )
|
||||
{
|
||||
var filledLevels = levelMap[ i ].Filter( l => l.values != null );
|
||||
var points = new List<Point>();
|
||||
|
||||
filledLevels.ForEach(
|
||||
l =>
|
||||
{
|
||||
points.AddRange( l.values );
|
||||
}
|
||||
);
|
||||
|
||||
var pc = new PointCloud();
|
||||
pc.points = points;
|
||||
pc.ComputeCenter();
|
||||
pc.SortByDistanceToCenter();
|
||||
|
||||
var levelSize = ocTree.GetSizeForLevel( i );
|
||||
var distance = Cameras.ComputePixelDistanceForSizeVertical( 60, levelSize, new Vector2( 1920, 1080 ) ) * 4;
|
||||
|
||||
// this.LogInfo(
|
||||
// "Level", i,
|
||||
// "Points", pc.points.Count,
|
||||
// "Size", RegexUtility._CM( levelSize ),
|
||||
// "Distance", RegexUtility._M( distance )
|
||||
// );
|
||||
|
||||
var mg = pc.GenerateMeshGeometry( levelSize/2f );
|
||||
meshGeometries.Add( mg );
|
||||
|
||||
|
||||
infos.Add(
|
||||
RJLog.Stringify(
|
||||
"Level", i,
|
||||
"Points", pc.points.Count,
|
||||
"Size", levelSize._CM(),
|
||||
"Vertices", mg.numVertices,
|
||||
"Normals", mg.numNormals,
|
||||
"UVs", mg.numUV2s,
|
||||
"Colors", mg.numColors
|
||||
)
|
||||
);
|
||||
|
||||
var t = MathX.Map( i, level + 1, depth - 1, 1, 0 );
|
||||
mg.lodEdgeLength = levelSize;
|
||||
// mg.ApplyTranslation( new Vector3( 100 * t, 0, 0 ) );
|
||||
|
||||
var mesh = pc.GenerateMesh( levelSize / 2f );
|
||||
|
||||
lodBuilder.Add( levelSize, mesh );
|
||||
|
||||
if ( createOutputs )
|
||||
{
|
||||
var meshInstance = this.CreateChild<MeshInstance3D>();
|
||||
meshInstance.Mesh = mesh;
|
||||
meshInstance.MaterialOverride = material;
|
||||
|
||||
levelInstances.Add( meshInstance );
|
||||
}
|
||||
}
|
||||
|
||||
if ( createOutputs )
|
||||
{
|
||||
outputs = levelInstances.ToArray();
|
||||
}
|
||||
|
||||
outputInfos = infos.ToArray();
|
||||
|
||||
var lodMesh = this.CreateChild<MeshInstance3D>( "LOD Mesh" );
|
||||
meshGeometries.Reverse();
|
||||
var mainGeometry = meshGeometries[ 0 ];
|
||||
var lerpingData = new LODLerpingData();
|
||||
lerpingData.lowerLevelWeights = lowerLerp;
|
||||
lerpingData.higherLevelWeights = higherLerp;
|
||||
lerpingData.lerpSteps = lerpSteps;
|
||||
lodMesh.Mesh = MeshGeometry.GeneratePointsLODMesh( meshGeometries, lerpingData, false );
|
||||
|
||||
lodMesh.SetSurfaceOverrideMaterial( 0, material );
|
||||
|
||||
lod = lodBuilder.Create( this, "LOD" );
|
||||
lod.lod0 = lod.CreateChild<MeshInstance3D>();
|
||||
lod.lod0.Mesh = mesh.Mesh;
|
||||
lod.lod0.MaterialOverride = mesh.GetSurfaceOverrideMaterial( 0 );
|
||||
lod.distanceScale = 4;
|
||||
|
||||
|
||||
// cloud.SortByDistanceToCenter();
|
||||
|
||||
// numPoints = cloud.points.Count;
|
||||
// squareTexture = (int)Mathf.Pow( numPoints, 0.5f );
|
||||
// output.Mesh = cloud.GenerateMesh();
|
||||
|
||||
working = false;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://v88dkcabl6kd
|
|
@ -0,0 +1,94 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rokojori.PointClouds
|
||||
{
|
||||
public class PointCloudOcTree:OcTree<Point>
|
||||
{
|
||||
List<Vector3> compressedNormals = new List<Vector3>()
|
||||
{
|
||||
Vector3.Up,
|
||||
Vector3.Down,
|
||||
Vector3.Forward,
|
||||
Vector3.Back,
|
||||
Vector3.Right,
|
||||
Vector3.Left
|
||||
};
|
||||
|
||||
public bool normalSeperation = false;
|
||||
|
||||
public PointCloudOcTree( Vector3 min, Vector3 max, float rootCellSize, int maxDepth )
|
||||
:base( null, min, max, rootCellSize, maxDepth )
|
||||
{
|
||||
this._getPosition = GetPointPosition;
|
||||
this._combinePoints = CombinePoints;
|
||||
this._smoothPoints = SmoothPoints;
|
||||
}
|
||||
|
||||
protected Vector3 GetPointPosition( Point p )
|
||||
{
|
||||
return p.position;
|
||||
}
|
||||
|
||||
protected int GetNormalIndex( Vector3 normal )
|
||||
{
|
||||
var closest = -1;
|
||||
var closestDistance = 100f;
|
||||
|
||||
for ( int i = 0; i < compressedNormals.Count; i++ )
|
||||
{
|
||||
var d = compressedNormals[ i ].DistanceSquaredTo( normal );
|
||||
|
||||
if ( d < closestDistance )
|
||||
{
|
||||
closestDistance = d;
|
||||
closest = i;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return closest;
|
||||
|
||||
}
|
||||
|
||||
protected List<Point> CombinePoints( List<Point> points )
|
||||
{
|
||||
if ( normalSeperation )
|
||||
{
|
||||
var lists = compressedNormals.Map( c => new List<Point>() );
|
||||
|
||||
points.ForEach(
|
||||
( p )=>
|
||||
{
|
||||
var normalIndex = GetNormalIndex( p.normal );
|
||||
lists[ normalIndex ].Add( p );
|
||||
}
|
||||
);
|
||||
|
||||
lists = lists.Filter( n => n.Count > 0 );
|
||||
|
||||
|
||||
return lists.Map( l => Point.AsAverage( l ) );
|
||||
}
|
||||
|
||||
return new List<Point>(){ Point.AsAverage( points ) };
|
||||
}
|
||||
|
||||
protected List<Point> SmoothPoints( List<Point> targets, List<Point> points, float amount )
|
||||
{
|
||||
if ( targets == null || points == null )
|
||||
{
|
||||
return targets;
|
||||
}
|
||||
|
||||
var average = Point.AsAverage( points );
|
||||
return targets.Map( t => t.Lerp( average, amount ) );;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://dhn11j8cvbexf
|
|
@ -0,0 +1,406 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Rokojori.PointClouds
|
||||
{
|
||||
|
||||
public class PointCloudSampler
|
||||
{
|
||||
public enum SampleMode
|
||||
{
|
||||
Center,
|
||||
Vertices,
|
||||
CenterAndVertices,
|
||||
Density
|
||||
}
|
||||
|
||||
public List<Material> materials;
|
||||
public List<Texture2DPropertyName> albedoTexture;
|
||||
public List<ColorPropertyName> albedo;
|
||||
public float densityResolution = 0.2f;
|
||||
|
||||
List<Image> albedoTextureImages;
|
||||
|
||||
SampleMode mode;
|
||||
|
||||
ArrayMesh mesh;
|
||||
Node worker;
|
||||
|
||||
PointCloud pointCloud;
|
||||
|
||||
|
||||
|
||||
public PointCloud SampleFromMeshSync( SampleMode sampleMode, ArrayMesh mesh, Node worker )
|
||||
{
|
||||
this.mode = sampleMode;
|
||||
this.mesh = mesh;
|
||||
this.worker = worker;
|
||||
|
||||
pointCloud = new PointCloud();
|
||||
|
||||
GrabTextureImages();
|
||||
|
||||
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
|
||||
{
|
||||
SampleSurfaceSync( mesh, i );
|
||||
}
|
||||
|
||||
return pointCloud;
|
||||
|
||||
}
|
||||
|
||||
public async Task<PointCloud> SampleFromMesh( SampleMode sampleMode, ArrayMesh mesh, Node worker )
|
||||
{
|
||||
|
||||
this.mode = sampleMode;
|
||||
this.mesh = mesh;
|
||||
this.worker = worker;
|
||||
|
||||
pointCloud = new PointCloud();
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
GrabTextureImages();
|
||||
|
||||
for ( int i = 0; i < mesh.GetSurfaceCount(); i++ )
|
||||
{
|
||||
await SampleSurface( mesh, i );
|
||||
}
|
||||
|
||||
}
|
||||
catch ( System.Exception e )
|
||||
{
|
||||
worker.LogError( e );
|
||||
}
|
||||
|
||||
return pointCloud;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GrabTextureImages()
|
||||
{
|
||||
var index = -1;
|
||||
|
||||
albedoTextureImages = new List<Image>();
|
||||
|
||||
albedoTexture.ForEach(
|
||||
( at )=>
|
||||
{
|
||||
index++;
|
||||
|
||||
if ( at == null )
|
||||
{
|
||||
albedoTextureImages.Add( null );
|
||||
}
|
||||
|
||||
var material = materials[ index ];
|
||||
var texture = at.Get( material );
|
||||
|
||||
if ( texture == null )
|
||||
{
|
||||
albedoTextureImages.Add( null );
|
||||
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
var image = texture.GetImage();
|
||||
|
||||
albedoTextureImages.Add( image );
|
||||
}
|
||||
);
|
||||
|
||||
// worker.LogInfo( "Added image:", albedoTextureImages.Count );
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void SampleSurfaceSync( ArrayMesh mesh, int surface )
|
||||
{
|
||||
if ( SampleMode.Density == mode )
|
||||
{
|
||||
SampleDensitySync( mesh, surface );
|
||||
return;
|
||||
}
|
||||
|
||||
SampleSimpleSync( mesh, surface );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SampleDensitySync( ArrayMesh mesh, int surface )
|
||||
{
|
||||
var mdt = new MeshDataTool();
|
||||
mdt.CreateFromSurface( mesh, surface );
|
||||
|
||||
var nullTriangles = 0;
|
||||
var numFaces = mdt.GetFaceCount();
|
||||
var subDivs = 0;
|
||||
|
||||
|
||||
for ( int i = 0; i < mdt.GetFaceCount(); i++ )
|
||||
{
|
||||
// time = await Async.WaitIfExceeded( time, worker );
|
||||
|
||||
var positions = new List<Vector3>();
|
||||
var normals = new List<Vector3>();
|
||||
var uvs = new List<Vector2>();
|
||||
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
var index = mdt.GetFaceVertex( i, j );
|
||||
|
||||
var p = mdt.GetVertex( index );
|
||||
var uv = mdt.GetVertexUV( index );
|
||||
var n = mdt.GetVertexNormal( index );
|
||||
|
||||
positions.Add( p );
|
||||
uvs.Add( uv );
|
||||
normals.Add( n );
|
||||
}
|
||||
|
||||
var triangle = Triangle3.CreateFrom( positions );
|
||||
|
||||
AddPoints( positions, uvs, normals );
|
||||
|
||||
var minArea = densityResolution;
|
||||
|
||||
var points = new List<Vector3>();
|
||||
triangle.GetSubdivisionPoints( points, minArea );
|
||||
|
||||
|
||||
// worker.LogInfo( triangle.area, points.Count );
|
||||
|
||||
|
||||
points.ForEach(
|
||||
( p )=>
|
||||
{
|
||||
var uv = (Vector2) triangle.Lerp( p, uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] );
|
||||
var n = (Vector3) triangle.Lerp( p, normals[ 0 ], normals[ 1 ], normals[ 2 ] );
|
||||
|
||||
AddPoint( p, uv, n );
|
||||
subDivs ++;
|
||||
}
|
||||
);
|
||||
|
||||
// if ( triangle.area > minArea || triangle.longestEdgeLength > densityResolution )
|
||||
// {
|
||||
// worker.LogInfo( area );
|
||||
// subDivs++;
|
||||
// }
|
||||
|
||||
// triangle = triangle.Shrink( densityResolution );
|
||||
|
||||
// if ( triangle == null )
|
||||
// {
|
||||
// nullTriangles++;
|
||||
// }
|
||||
|
||||
|
||||
// var maxIterations = 1000;
|
||||
// var iteration = 0;
|
||||
|
||||
// while ( iteration < maxIterations && triangle != null && ( triangle.area > minArea || triangle.longestEdgeLength > densityResolution ) )
|
||||
// {
|
||||
// var newUVs = positions.Map( p => (Vector2) triangle.Lerp( p, uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] ) );
|
||||
// var newNormals = positions.Map( p => (Vector3) triangle.Lerp( p, normals[ 0 ], normals[ 1 ], normals[ 2 ] ) );
|
||||
|
||||
// positions = triangle.points;
|
||||
// uvs = newUVs;
|
||||
// normals = newNormals;
|
||||
|
||||
// AddPoints( positions, uvs, normals );
|
||||
|
||||
// triangle = triangle.Shrink( densityResolution );
|
||||
|
||||
// iteration ++;
|
||||
// }
|
||||
}
|
||||
|
||||
worker.LogInfo( "Tris:", numFaces, "Nulls:", nullTriangles, "Subs:", subDivs );
|
||||
}
|
||||
|
||||
void AddPoints( List<Vector3> p, List<Vector2> u, List<Vector3> n )
|
||||
{
|
||||
for ( int i = 0; i < p.Count; i++ )
|
||||
{
|
||||
AddPoint( p[ i ], u[ i ], n[ i ] );
|
||||
}
|
||||
}
|
||||
|
||||
void AddPoint( Vector3 p, Vector2 u, Vector3 n )
|
||||
{
|
||||
var point = new Point();
|
||||
point.color = Colors.White;
|
||||
point.position = p;
|
||||
point.normal = n;
|
||||
point.uv = u;
|
||||
pointCloud.points.Add( point );
|
||||
}
|
||||
|
||||
public async Task SampleSurface( ArrayMesh mesh, int surface )
|
||||
{
|
||||
await SampleSimple( mesh, surface );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void SampleSimpleSync( ArrayMesh mesh, int surface )
|
||||
{
|
||||
var mdt = new MeshDataTool();
|
||||
mdt.CreateFromSurface( mesh, surface );
|
||||
|
||||
|
||||
var sampleVertices = SampleMode.Vertices == mode || SampleMode.CenterAndVertices == mode;
|
||||
var sampleCenter = SampleMode.Center == mode || SampleMode.CenterAndVertices == mode;
|
||||
|
||||
for ( int i = 0; i < mdt.GetFaceCount(); i++ )
|
||||
{
|
||||
// time = await Async.WaitIfExceeded( time, worker );
|
||||
|
||||
var center = new Vector3( 0, 0, 0 );
|
||||
var centerColor = new Vector4( 0, 0, 0, 0 );
|
||||
var centerNormal = new Vector3( 0, 0, 0 );
|
||||
var centerUV = new Vector2( 0, 0 );
|
||||
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
var index = mdt.GetFaceVertex( i, j );
|
||||
|
||||
var p = mdt.GetVertex( index );
|
||||
var uv = mdt.GetVertexUV( index );
|
||||
var n = mdt.GetVertexNormal( index );
|
||||
var color = Colors.White;
|
||||
|
||||
var image = albedoTextureImages[ surface ];
|
||||
|
||||
if ( image != null )
|
||||
{
|
||||
color = image.Sample( uv, ColorX.EdgeMode.Repeat );
|
||||
}
|
||||
|
||||
|
||||
|
||||
center += p;
|
||||
centerColor += color.ToVector4();
|
||||
centerNormal += n;
|
||||
centerUV += uv;
|
||||
|
||||
if ( sampleVertices )
|
||||
{
|
||||
var point = new Point();
|
||||
point.color = color;
|
||||
point.position = p;
|
||||
point.normal = n;
|
||||
point.uv = uv;
|
||||
pointCloud.points.Add( point );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( sampleCenter )
|
||||
{
|
||||
var point = new Point();
|
||||
point.color = ( centerColor / 3.0f ).ToColor();
|
||||
point.position = center / 3.0f;
|
||||
point.normal = centerNormal / 3.0f;
|
||||
point.uv = centerUV / 3.0f;
|
||||
pointCloud.points.Add( point );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async Task SampleSimple( ArrayMesh mesh, int surface )
|
||||
{
|
||||
var mdt = new MeshDataTool();
|
||||
mdt.CreateFromSurface( mesh, surface );
|
||||
|
||||
|
||||
var sampleVertices = SampleMode.Vertices == mode || SampleMode.CenterAndVertices == mode;
|
||||
var sampleCenter = SampleMode.Center == mode || SampleMode.CenterAndVertices == mode;
|
||||
|
||||
var time = Async.StartTimer();
|
||||
|
||||
var faces = mdt.GetFaceCount();
|
||||
|
||||
for ( int i = 0; i < faces; i++ )
|
||||
{
|
||||
time = await Async.WaitIfExceeded( time, worker );
|
||||
|
||||
if ( i % 10000 == 0 )
|
||||
{
|
||||
worker.LogInfo( "Tris:", i + "/" + faces, RegexUtility._FFF( ( 100f * i ) / (float)faces ) );
|
||||
}
|
||||
|
||||
var center = new Vector3( 0, 0, 0 );
|
||||
var centerColor = new Vector4( 0, 0, 0, 0 );
|
||||
var centerNormal = new Vector3( 0, 0, 0 );
|
||||
var centerUV = new Vector2( 0, 0 );
|
||||
|
||||
for ( int j = 0; j < 3; j++ )
|
||||
{
|
||||
var index = mdt.GetFaceVertex( i, j );
|
||||
|
||||
var p = mdt.GetVertex( index );
|
||||
var uv = mdt.GetVertexUV( index );
|
||||
var n = mdt.GetVertexNormal( index );
|
||||
var color = Colors.White;
|
||||
|
||||
var image = albedoTextureImages[ surface ];
|
||||
|
||||
if ( image != null )
|
||||
{
|
||||
color = image.Sample( uv, ColorX.EdgeMode.Repeat );
|
||||
}
|
||||
|
||||
|
||||
|
||||
center += p;
|
||||
centerColor += color.ToVector4();
|
||||
centerNormal += n;
|
||||
centerUV += uv;
|
||||
|
||||
if ( sampleVertices )
|
||||
{
|
||||
var point = new Point();
|
||||
point.color = color;
|
||||
point.position = p;
|
||||
point.normal = n;
|
||||
point.uv = uv;
|
||||
pointCloud.points.Add( point );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( sampleCenter )
|
||||
{
|
||||
var point = new Point();
|
||||
point.color = ( centerColor / 3.0f ).ToColor();
|
||||
point.position = center / 3.0f;
|
||||
point.normal = centerNormal / 3.0f;
|
||||
point.uv = centerUV / 3.0f;
|
||||
pointCloud.points.Add( point );
|
||||
}
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
pointCloud.boundingBox = Box3.Create( center, center );
|
||||
}
|
||||
else
|
||||
{
|
||||
pointCloud.boundingBox.IncludePoint( center );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://dfksgo3wn58ts
|
|
@ -44,6 +44,21 @@ namespace Rokojori
|
|||
return b;
|
||||
}
|
||||
|
||||
public static Box3 Create<T>( List<T> data, System.Func<T,Vector3> getPosition )
|
||||
{
|
||||
var min = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue );
|
||||
var max = new Vector3( -float.MaxValue, -float.MaxValue, -float.MaxValue );
|
||||
|
||||
for ( int i = 0; i < data.Count; i++ )
|
||||
{
|
||||
var p = getPosition( data[ i ] );
|
||||
min = min.Min( p );
|
||||
max = max.Max( p );
|
||||
}
|
||||
|
||||
return Create( min, max );
|
||||
}
|
||||
|
||||
public Vector3 size => max - min;
|
||||
|
||||
public void IncludePoint( Vector3 p )
|
||||
|
|
|
@ -114,7 +114,7 @@ namespace Rokojori
|
|||
|
||||
if ( i01 == null || ! ContainsPoint( (Vector2) i01 ) )
|
||||
{
|
||||
RJLog.Log( "i01", i01, i01 != null ? ContainsPoint( (Vector2) i01 ) : false );
|
||||
// RJLog.Log( "i01", i01, i01 != null ? ContainsPoint( (Vector2) i01 ) : false );
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ namespace Rokojori
|
|||
|
||||
if ( i12 == null || ! ContainsPoint( (Vector2) i12 ) )
|
||||
{
|
||||
RJLog.Log( "i12", i12, i12 != null ? ContainsPoint( (Vector2) i12 ) : false );
|
||||
// RJLog.Log( "i12", i12, i12 != null ? ContainsPoint( (Vector2) i12 ) : false );
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -130,7 +130,7 @@ namespace Rokojori
|
|||
|
||||
if ( i20 == null || ! ContainsPoint( (Vector2) i20 ) )
|
||||
{
|
||||
RJLog.Log( "i20", i20, i20 != null ? ContainsPoint( (Vector2) i20 ) : false );
|
||||
// RJLog.Log( "i20", i20, i20 != null ? ContainsPoint( (Vector2) i20 ) : false );
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,6 +30,17 @@ namespace Rokojori
|
|||
_needsUpdate = true;
|
||||
}
|
||||
|
||||
public static Triangle3 CreateFrom( List<Vector3> points, int offset = 0 )
|
||||
{
|
||||
var t = new Triangle3(
|
||||
points[ 0 ],
|
||||
points[ 1 ],
|
||||
points[ 2 ]
|
||||
);
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
public static Triangle3 CreateFrom( MeshGeometry mg, int a, int b, int c )
|
||||
{
|
||||
var t = new Triangle3(
|
||||
|
@ -145,6 +156,7 @@ namespace Rokojori
|
|||
|
||||
public float area => ComputeTriangleArea( a, b, c );
|
||||
|
||||
|
||||
public bool Intersects( Line3 line )
|
||||
{
|
||||
var planePoint = _plane.IntersectLine( line );
|
||||
|
@ -268,6 +280,11 @@ namespace Rokojori
|
|||
return LerpCurve3.FromPoints( GetPoint( 0 ), GetPoint( 1 ), GetPoint( 2 ) );
|
||||
}
|
||||
|
||||
public List<Vector3> points => new List<Vector3>(){ a, b, c };
|
||||
|
||||
|
||||
|
||||
|
||||
public Vector3 GetPoint( int i )
|
||||
{
|
||||
if ( i == 0 )
|
||||
|
@ -286,6 +303,22 @@ namespace Rokojori
|
|||
return a;
|
||||
}
|
||||
|
||||
public Line3 GetEdge( int i )
|
||||
{
|
||||
var p0 = GetPoint( i );
|
||||
var p1 = GetPoint( i % 3 );
|
||||
|
||||
return Line3.Create( p0, p1 );
|
||||
}
|
||||
|
||||
public float GetEdgeLength( int i )
|
||||
{
|
||||
return GetEdge( i ).length;
|
||||
}
|
||||
|
||||
public float longestEdgeLength => MathX.Min( GetEdgeLength( 0 ), GetEdgeLength( 1 ), GetEdgeLength( 2 ) );
|
||||
public float shortestEdgeLength => MathX.Max( GetEdgeLength( 0 ), GetEdgeLength( 1 ), GetEdgeLength( 2 ) );
|
||||
|
||||
void SetPointsToLine( Line3 line, int index )
|
||||
{
|
||||
line.Set( GetPoint( index ), GetPoint( ( index + 1 ) % 3 ) );
|
||||
|
@ -484,6 +517,48 @@ namespace Rokojori
|
|||
return new Triangle3( Math3D.XYasXZ( t.a ), Math3D.XYasXZ( t.b ), Math3D.XYasXZ( t.c ) );
|
||||
}
|
||||
|
||||
public List<Triangle3> CenterSplit()
|
||||
{
|
||||
var m = center;
|
||||
|
||||
var subs = new List<Triangle3>
|
||||
{
|
||||
new Triangle3( a, b, m ),
|
||||
new Triangle3( b, c, m ),
|
||||
new Triangle3( c, a, m )
|
||||
};
|
||||
|
||||
return subs;
|
||||
}
|
||||
|
||||
public void GetSubdivisionPoints( List<Vector3> output, float minArea )
|
||||
{
|
||||
var processingList = new List<Triangle3>();
|
||||
|
||||
processingList.Add( this );
|
||||
|
||||
while ( processingList.Count > 0 )
|
||||
{
|
||||
var tri = processingList.Shift();
|
||||
output.Add( tri.center );
|
||||
|
||||
var subs = tri.CenterSplit();
|
||||
|
||||
subs.ForEach(
|
||||
st =>
|
||||
{
|
||||
if ( st.area > minArea )
|
||||
{
|
||||
processingList.Add( st );
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static bool InsideTriangle( Vector3 point, Vector3 a, Vector3 b, Vector3 c )
|
||||
|
@ -533,7 +608,66 @@ namespace Rokojori
|
|||
return new Vector3( 1f - u - v, v, u );
|
||||
}
|
||||
|
||||
public Vector3? GetBaryCentricCoordinate( Vector3 point )
|
||||
{
|
||||
return GetBaryCentricCoordinate( point, a, b, c );
|
||||
}
|
||||
|
||||
public Vector4? Lerp( Vector3 p, Vector4 x, Vector4 y, Vector4 z )
|
||||
{
|
||||
var bary = GetBaryCentricCoordinate( p );
|
||||
|
||||
if ( bary == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var w = ( Vector3 ) bary;
|
||||
|
||||
return w.Lerp( x, y, z );
|
||||
}
|
||||
|
||||
public Vector3? Lerp( Vector3 p, Vector3 x, Vector3 y, Vector3 z )
|
||||
{
|
||||
var bary = GetBaryCentricCoordinate( p );
|
||||
|
||||
if ( bary == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var w = ( Vector3 ) bary;
|
||||
|
||||
return w.Lerp( x, y, z );
|
||||
}
|
||||
|
||||
public Vector2? Lerp( Vector3 p, Vector2 x, Vector2 y, Vector2 z )
|
||||
{
|
||||
var bary = GetBaryCentricCoordinate( p );
|
||||
|
||||
if ( bary == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var w = ( Vector3 ) bary;
|
||||
|
||||
return w.Lerp( x, y, z );
|
||||
}
|
||||
|
||||
public float? Lerp( Vector3 p, float x, float y, float z )
|
||||
{
|
||||
var bary = GetBaryCentricCoordinate( p );
|
||||
|
||||
if ( bary == null )
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var w = ( Vector3 ) bary;
|
||||
|
||||
return w.Lerp( x, y, z );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -6,8 +6,23 @@ using System;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class Math2D
|
||||
public static class Math2D
|
||||
{
|
||||
public static Vector2I RoundToInt( this Vector2 v )
|
||||
{
|
||||
return new Vector2I( Mathf.RoundToInt( v.X ), Mathf.RoundToInt( v.Y ) );
|
||||
}
|
||||
|
||||
public static Vector2I FloorToInt( this Vector2 v )
|
||||
{
|
||||
return new Vector2I( Mathf.FloorToInt( v.X ), Mathf.FloorToInt( v.Y ) );
|
||||
}
|
||||
|
||||
public static Vector2I CeilToInt( this Vector2 v )
|
||||
{
|
||||
return new Vector2I( Mathf.CeilToInt( v.X ), Mathf.CeilToInt( v.Y ) );
|
||||
}
|
||||
|
||||
public static float LookingAtEachOtherAngle( Vector2 lookDirectionA, Vector2 lookDirectionB )
|
||||
{
|
||||
return Dot( lookDirectionA, lookDirectionB );
|
||||
|
@ -90,5 +105,40 @@ namespace Rokojori
|
|||
{
|
||||
return clockwise ? Rotate90DegreesRight( v ) : Rotate90DegreesLeft( v );
|
||||
}
|
||||
|
||||
public static Vector2 ComputeAverage( List<Vector2> points )
|
||||
{
|
||||
if ( points == null || points.Count == 0 )
|
||||
{
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector2.Zero;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
mean += ( points[ i ] - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
|
||||
}
|
||||
|
||||
public static Vector2 ComputeAverage<T>( List<T> containers, Func<T,Vector2> getPoint )
|
||||
{
|
||||
if ( containers == null || containers.Count == 0 )
|
||||
{
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector2.Zero;
|
||||
|
||||
for ( int i = 0; i < containers.Count; i++ )
|
||||
{
|
||||
mean += ( getPoint( containers[ i ] ) - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,98 @@ namespace Rokojori
|
|||
return LookingAtEachOther( fromDirection, to - from );
|
||||
}
|
||||
|
||||
public static Vector4 Lerp( this Vector3 w, Vector4 x, Vector4 y, Vector4 z )
|
||||
{
|
||||
return w.X * x + w.Y * y + w.Z * z;
|
||||
}
|
||||
|
||||
public static Vector3 Lerp( this Vector3 w, Vector3 x, Vector3 y, Vector3 z )
|
||||
{
|
||||
return w.X * x + w.Y * y + w.Z * z;
|
||||
}
|
||||
|
||||
|
||||
public static Vector2 Lerp( this Vector3 w, Vector2 x, Vector2 y, Vector2 z )
|
||||
{
|
||||
return w.X * x + w.Y * y + w.Z * z;
|
||||
}
|
||||
|
||||
public static float Lerp( this Vector3 w, float x, float y, float z )
|
||||
{
|
||||
return w.X * x + w.Y * y + w.Z * z;
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 ComputeAverage( List<Vector3> points )
|
||||
{
|
||||
if ( points == null || points.Count == 0 )
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector3.Zero;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
mean += ( points[ i ] - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static Vector3 ComputeAverage<T>( List<T> containers, Func<T,Vector3> getPoint )
|
||||
{
|
||||
if ( containers == null || containers.Count == 0 )
|
||||
{
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector3.Zero;
|
||||
|
||||
for ( int i = 0; i < containers.Count; i++ )
|
||||
{
|
||||
mean += ( getPoint( containers[ i ] ) - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
}
|
||||
|
||||
public static Vector4 ComputeAverage( List<Vector4> points )
|
||||
{
|
||||
if ( points == null || points.Count == 0 )
|
||||
{
|
||||
return Vector4.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector4.Zero;
|
||||
|
||||
for ( int i = 0; i < points.Count; i++ )
|
||||
{
|
||||
mean += ( points[ i ] - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
|
||||
}
|
||||
|
||||
public static Vector4 ComputeAverage<T>( List<T> containers, Func<T,Vector4> getPoint )
|
||||
{
|
||||
if ( containers == null || containers.Count == 0 )
|
||||
{
|
||||
return Vector4.Zero;
|
||||
}
|
||||
|
||||
var mean = Vector4.Zero;
|
||||
|
||||
for ( int i = 0; i < containers.Count; i++ )
|
||||
{
|
||||
mean += ( getPoint( containers[ i ] ) - mean ) / ( i + 1 );
|
||||
}
|
||||
|
||||
return mean;
|
||||
}
|
||||
|
||||
public static Transform3D TRS( Vector3 translation, Quaternion rotation, Vector3 scale )
|
||||
{
|
||||
|
@ -267,6 +359,40 @@ namespace Rokojori
|
|||
return quaternion;
|
||||
}
|
||||
|
||||
public static Vector3 GetMin<T>( List<T> data, Func<T,Vector3> getPosition )
|
||||
{
|
||||
var min = new Vector3( float.MaxValue, float.MaxValue, float.MaxValue );
|
||||
|
||||
for ( int i = 0; i < data.Count; i++ )
|
||||
{
|
||||
min = min.Min( getPosition( data[ i ] ) );
|
||||
}
|
||||
|
||||
return min;
|
||||
}
|
||||
|
||||
public static Vector3 GetMax<T>( List<T> data, Func<T,Vector3> getPosition )
|
||||
{
|
||||
var max = new Vector3( -float.MaxValue, -float.MaxValue, -float.MaxValue );
|
||||
|
||||
for ( int i = 0; i < data.Count; i++ )
|
||||
{
|
||||
max = max.Max( getPosition( data[ i ] ) );
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
|
||||
public static float MaxDimension( this Vector3 v )
|
||||
{
|
||||
return MathX.Max( v.X, v.Y, v.Z );
|
||||
}
|
||||
|
||||
public static float MinDimension( this Vector3 v )
|
||||
{
|
||||
return MathX.Min( v.X, v.Y, v.Z );
|
||||
}
|
||||
|
||||
public static Vector3 MinGlobalPosition( Node3D a, Node3D b )
|
||||
{
|
||||
return a.GlobalPosition.Min( b.GlobalPosition );
|
||||
|
@ -287,7 +413,7 @@ namespace Rokojori
|
|||
return a.Position.Max( b.Position );
|
||||
}
|
||||
|
||||
public static Vector3 SnapRounded( Vector3 v, Vector3 snapping )
|
||||
public static Vector3 SnapRounded( this Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapRounded( v.X, snapping.X );
|
||||
v.Y = MathX.SnapRounded( v.Y, snapping.Y );
|
||||
|
@ -296,7 +422,7 @@ namespace Rokojori
|
|||
return v;
|
||||
}
|
||||
|
||||
public static Vector3 SnapRoundedXZ( Vector3 v, float snapX, float snapZ )
|
||||
public static Vector3 SnapRoundedXZ( this Vector3 v, float snapX, float snapZ )
|
||||
{
|
||||
v.X = MathX.SnapRounded( v.X, snapX );
|
||||
v.Z = MathX.SnapRounded( v.Z, snapZ );
|
||||
|
@ -304,7 +430,7 @@ namespace Rokojori
|
|||
return v;
|
||||
}
|
||||
|
||||
public static Vector3 SnapCeiled( Vector3 v, Vector3 snapping )
|
||||
public static Vector3 SnapCeiled( this Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapCeiled( v.X, snapping.X );
|
||||
v.Y = MathX.SnapCeiled( v.Y, snapping.Y );
|
||||
|
@ -313,7 +439,7 @@ namespace Rokojori
|
|||
return v;
|
||||
}
|
||||
|
||||
public static Vector3 SnapFloored( Vector3 v, Vector3 snapping )
|
||||
public static Vector3 SnapFloored( this Vector3 v, Vector3 snapping )
|
||||
{
|
||||
v.X = MathX.SnapFloored( v.X, snapping.X );
|
||||
v.Y = MathX.SnapFloored( v.Y, snapping.Y );
|
||||
|
@ -322,6 +448,51 @@ namespace Rokojori
|
|||
return v;
|
||||
}
|
||||
|
||||
public static Vector3I RoundToInt( this Vector3 v )
|
||||
{
|
||||
return new Vector3I( Mathf.RoundToInt( v.X ) , Mathf.RoundToInt( v.Y ), Mathf.RoundToInt( v.Z ) );
|
||||
}
|
||||
|
||||
public static Vector3I FloorToInt( this Vector3 v )
|
||||
{
|
||||
return new Vector3I( Mathf.FloorToInt( v.X ) , Mathf.FloorToInt( v.Y ), Mathf.FloorToInt( v.Z ) );
|
||||
}
|
||||
|
||||
public static Vector3I CeilToInt( this Vector3 v )
|
||||
{
|
||||
return new Vector3I( Mathf.CeilToInt( v.X ) , Mathf.CeilToInt( v.Y ), Mathf.CeilToInt( v.Z ) );
|
||||
}
|
||||
|
||||
public static Vector2 XY( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.X, v.Y );
|
||||
}
|
||||
|
||||
public static Vector2 YX( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.Y, v.X );
|
||||
}
|
||||
|
||||
public static Vector2 XZ( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.X, v.Z );
|
||||
}
|
||||
|
||||
public static Vector2 ZX( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.Z, v.X );
|
||||
}
|
||||
|
||||
public static Vector2 YZ( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.Y, v.Z );
|
||||
}
|
||||
|
||||
public static Vector2 ZY( this Vector3 v )
|
||||
{
|
||||
return new Vector2( v.Y, v.Z );
|
||||
}
|
||||
|
||||
public static Basis AlignUp( Basis basis, Vector3 upDirection )
|
||||
{
|
||||
basis.Y = upDirection;
|
||||
|
@ -329,6 +500,7 @@ namespace Rokojori
|
|||
return basis.Orthonormalized();
|
||||
}
|
||||
|
||||
|
||||
public static Quaternion AlignUp( Quaternion rotation, Vector3 upDirection )
|
||||
{
|
||||
var basis = new Basis( rotation );
|
||||
|
|
|
@ -6,7 +6,7 @@ using System;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
public class MathX
|
||||
public static class MathX
|
||||
{
|
||||
public const float fps120Delta = 1/120f;
|
||||
|
||||
|
@ -144,6 +144,60 @@ namespace Rokojori
|
|||
}
|
||||
|
||||
|
||||
|
||||
public static int MultiIndexToFlatIndex( List<int> indices, List<int> sizes )
|
||||
{
|
||||
var index = 0;
|
||||
var scale = 1;
|
||||
|
||||
for ( int i = sizes.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
index += indices[ i ] * scale;
|
||||
scale *= sizes[ i ];
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public static int MultiIndexToFlatIndex( Vector3I indices, Vector3I sizes )
|
||||
{
|
||||
var index = 0;
|
||||
|
||||
index += indices.Z;
|
||||
index += indices.Y * sizes.Z;
|
||||
index += indices.X * sizes.Z * sizes.Y;
|
||||
return index;
|
||||
}
|
||||
|
||||
public static List<int> FlatIndexToMultiIndex( int index, List<int> sizes, List<int> multiIndex = null )
|
||||
{
|
||||
multiIndex = multiIndex == null ? new List<int>( new int[ sizes.Count ] ) : multiIndex;
|
||||
|
||||
for ( int i = sizes.Count - 1; i >= 0; i-- )
|
||||
{
|
||||
multiIndex[ i ] = index % sizes[ i ];
|
||||
index /= sizes[i];
|
||||
}
|
||||
|
||||
return multiIndex;
|
||||
}
|
||||
|
||||
public static Vector3I FlatIndexToMultiIndex( int index, Vector3I sizes )
|
||||
{
|
||||
var multiIndex = Vector3I.Zero;
|
||||
|
||||
multiIndex.Z = index % sizes.Z;
|
||||
index /= sizes.Z;
|
||||
|
||||
multiIndex.Y = index % sizes.Y;
|
||||
index /= sizes.Y;
|
||||
|
||||
multiIndex.X = index % sizes.X;
|
||||
|
||||
return multiIndex;
|
||||
}
|
||||
|
||||
|
||||
public const float DegreesToRadians = Mathf.Pi / 180f;
|
||||
public const float RadiansToDegrees = 180f / Mathf.Pi;
|
||||
|
||||
|
@ -428,6 +482,23 @@ namespace Rokojori
|
|||
return max;
|
||||
}
|
||||
|
||||
public static float CurveAverage( this Curve c, int numSamples = 20 )
|
||||
{
|
||||
if ( c == null )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var value = 0f;
|
||||
|
||||
for ( int i = 0; i < numSamples; i++ )
|
||||
{
|
||||
value += c.Sample( (float) i / ( numSamples - 1 ) );
|
||||
}
|
||||
|
||||
return value / numSamples;
|
||||
}
|
||||
|
||||
public static List<float> GetCurveWeights( Curve curve, int num, bool normalize = true )
|
||||
{
|
||||
var sum = 0f;
|
||||
|
|
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class LANNetworkBackend:NetworkBackend
|
||||
{
|
||||
SceneMultiplayer multiplayer;
|
||||
|
|
|
@ -3,7 +3,7 @@ using Godot;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass,Icon("res://addons/rokojori_action_library/Icons/NetworkManager.svg")]
|
||||
[Tool][GlobalClass,Icon("res://addons/rokojori_action_library/Icons/NetworkManager.svg")]
|
||||
public partial class NetworkManager:Node
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class AddNetworkNodes:Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class JoinSession:Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class NetworkSessionRequest:Resource
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class StartSession:Action
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class NetworkTransform3D:NetworkNode
|
||||
{
|
||||
[Export]
|
||||
|
|
|
@ -4,7 +4,7 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Rokojori
|
||||
{
|
||||
[GlobalClass]
|
||||
[Tool][GlobalClass]
|
||||
public partial class NetworkTransform3DType:Resource
|
||||
{
|
||||
[ExportCategory("Position")]
|
||||
|
|
|
@ -2,6 +2,7 @@ using System.Collections;
|
|||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
|
@ -24,6 +25,9 @@ namespace Rokojori
|
|||
[Export]
|
||||
public bool updateAlways;
|
||||
|
||||
[Export]
|
||||
public Material material;
|
||||
|
||||
[ExportGroup( "Patch")]
|
||||
[Export]
|
||||
public float patchSize = 2;
|
||||
|
@ -233,6 +237,21 @@ namespace Rokojori
|
|||
[Export]
|
||||
public int currentLODLevel = -1;
|
||||
|
||||
[Export]
|
||||
public bool generateLODMesh = false;
|
||||
|
||||
[Export]
|
||||
public float customLODEdgeLength = 0;
|
||||
|
||||
[Export]
|
||||
public int lodLerpSteps = 2;
|
||||
|
||||
[Export]
|
||||
public Curve lowCurve = MathX.Curve( 0, 1 );
|
||||
|
||||
[Export]
|
||||
public Curve highCurve = MathX.Curve( 0, 1 );
|
||||
|
||||
// SerializedGodotObject _cached;
|
||||
|
||||
public override void _Process( double delta )
|
||||
|
@ -287,7 +306,7 @@ namespace Rokojori
|
|||
return bladeSegments * 2 * ComputeNumBlades();
|
||||
}
|
||||
|
||||
public void CreatePatch()
|
||||
public async Task CreatePatch()
|
||||
{
|
||||
if ( blades == 0 && bladesX == 0 && bladesZ == 0)
|
||||
{
|
||||
|
@ -311,17 +330,11 @@ namespace Rokojori
|
|||
lodLevels = new GrassPatchLODLevel[]{};
|
||||
}
|
||||
|
||||
if ( output == null )
|
||||
{
|
||||
|
||||
this.DestroyChildren();
|
||||
this.output = this.CreateChild<MeshInstance3D>( "Grass Patch Mesh" );
|
||||
}
|
||||
|
||||
|
||||
var mg = new MeshGeometry();
|
||||
|
||||
|
||||
var cellSizeX = ( patchSizeX + patchSize ) / ( bladesX + blades );
|
||||
var cellSizeZ = ( patchSizeZ + patchSize ) / ( bladesZ + blades );
|
||||
|
||||
var random = new LCG();
|
||||
random.SetSeed( 1712 + seed );
|
||||
|
@ -332,6 +345,96 @@ namespace Rokojori
|
|||
|
||||
X_numBlades = 0;
|
||||
|
||||
if ( ! generateLODMesh )
|
||||
{
|
||||
var mg = CreatePatchGeometry();
|
||||
X_numTriangles = mg.indices.Count / 3;
|
||||
output.Mesh = mg.GenerateMesh();
|
||||
output.Mesh.SurfaceSetMaterial( 0, material );
|
||||
}
|
||||
else
|
||||
{
|
||||
var cachedCurrentLODLevel = currentLODLevel;
|
||||
|
||||
try
|
||||
{
|
||||
var mgs = new List<MeshGeometry>();
|
||||
|
||||
var numTris = 0;
|
||||
|
||||
var time = this.StartAsyncTimer();
|
||||
var edgeLength = ( MathX.CurveAverage( bladeHeight ) * MathX.CurveAverage( bladeScale ) ) / bladeSegments;
|
||||
|
||||
if ( customLODEdgeLength > 0 )
|
||||
{
|
||||
edgeLength = customLODEdgeLength;
|
||||
}
|
||||
|
||||
this.LogInfo( "Edge Length", edgeLength );
|
||||
|
||||
for ( int i = 0; i < lodLevels.Length + 1; i++ )
|
||||
{
|
||||
time = await this.WaitForAsyncTimer( time );
|
||||
|
||||
var lodIndex = i - 1;
|
||||
currentLODLevel = lodIndex;
|
||||
|
||||
var lodEdgeLengthScale = 1f;
|
||||
|
||||
if ( lodIndex >= 0 )
|
||||
{
|
||||
lodEdgeLengthScale = lodLevels[ lodIndex ].lodEdgeLengthScale;
|
||||
}
|
||||
|
||||
var lodMG = CreatePatchGeometry();
|
||||
lodMG.lodEdgeLength = edgeLength * lodEdgeLengthScale;
|
||||
numTris += lodMG.vertices.Count;
|
||||
|
||||
lodMG.ApplyTranslation( new Vector3( 0, 0, 0 ) ) ;
|
||||
mgs.Add( lodMG );
|
||||
}
|
||||
|
||||
X_numTriangles = numTris;
|
||||
|
||||
LODLerpingData lerpingData = null;
|
||||
|
||||
if ( lodLerpSteps > 0 )
|
||||
{
|
||||
lerpingData = new LODLerpingData();
|
||||
lerpingData.lowerLevelWeights = lowCurve;
|
||||
lerpingData.higherLevelWeights = highCurve;
|
||||
lerpingData.lerpSteps = lodLerpSteps;
|
||||
}
|
||||
|
||||
output.Mesh = MeshGeometry.GenerateTrianglesLODMesh( mgs, lerpingData, false );
|
||||
output.Mesh.SurfaceSetMaterial( 0, material );
|
||||
|
||||
|
||||
}
|
||||
catch ( System.Exception e )
|
||||
{
|
||||
this.LogError( e );
|
||||
}
|
||||
|
||||
currentLODLevel = cachedCurrentLODLevel;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool debugBlade = false;
|
||||
|
||||
MeshGeometry CreatePatchGeometry()
|
||||
{
|
||||
var random = new LCG();
|
||||
random.SetSeed( 1712 + seed );
|
||||
|
||||
var mg = new MeshGeometry();
|
||||
|
||||
var cellSizeX = ( patchSizeX + patchSize ) / ( bladesX + blades );
|
||||
var cellSizeZ = ( patchSizeZ + patchSize ) / ( bladesZ + blades );
|
||||
|
||||
|
||||
var allBladesX = bladesX + blades;
|
||||
var allBladesZ = bladesZ + blades;
|
||||
|
||||
|
@ -369,6 +472,11 @@ namespace Rokojori
|
|||
|
||||
var bladeMG = CreateBlade( random, worldPosition );
|
||||
|
||||
if ( bladeMG.numNormals == 0 || bladeMG.numUVs == 0 )
|
||||
{
|
||||
this.LogInfo( "Invalid mg" );
|
||||
}
|
||||
|
||||
if ( filterValue > filterTreshold )
|
||||
{
|
||||
continue;
|
||||
|
@ -417,6 +525,11 @@ namespace Rokojori
|
|||
}
|
||||
}
|
||||
|
||||
if ( mg.numNormals == 0 || mg.numUVs == 0 )
|
||||
{
|
||||
this.LogInfo( "Invalid mg" );
|
||||
}
|
||||
|
||||
|
||||
if ( centerPatch )
|
||||
{
|
||||
|
@ -431,6 +544,11 @@ namespace Rokojori
|
|||
var turbulenceAmount = random.Sample( vertexTurbulenceAmount );
|
||||
var turbulenceScale = Vector3.One * ( vertexTurbulenceScale == null ? 1 : random.Sample( vertexTurbulenceScale ) );
|
||||
|
||||
if ( currentLODLevel != -1 )
|
||||
{
|
||||
turbulenceAmount *= lodLevels[ currentLODLevel ].turbulenceScale;
|
||||
}
|
||||
|
||||
if ( vertexTurbulenceScaleX != null )
|
||||
{
|
||||
turbulenceScale.X *= random.Sample( vertexTurbulenceScaleX );
|
||||
|
@ -479,16 +597,10 @@ namespace Rokojori
|
|||
mg.ScaleZForY( scaleZForY );
|
||||
}
|
||||
|
||||
return mg;
|
||||
|
||||
|
||||
X_numTriangles = mg.indices.Count / 3;
|
||||
|
||||
|
||||
output.Mesh = mg.GenerateMesh();
|
||||
}
|
||||
|
||||
bool debugBlade = false;
|
||||
|
||||
MeshGeometry CreateBlade( RandomEngine random, Vector3 position )
|
||||
{
|
||||
// if ( debugBlade )
|
||||
|
|
|
@ -23,8 +23,14 @@ namespace Rokojori
|
|||
[Export( PropertyHint.Range, "0,1")]
|
||||
public float filter = 1;
|
||||
|
||||
[Export]
|
||||
public float turbulenceScale = 0f;
|
||||
|
||||
[Export]
|
||||
public Trillean allowTrianglesOnEnd;
|
||||
|
||||
[Export]
|
||||
public float lodEdgeLengthScale = 1;
|
||||
|
||||
}
|
||||
}
|
|
@ -5,7 +5,6 @@ render_mode blend_mix, depth_draw_opaque, cull_back, diffuse_burley, specular_sc
|
|||
|
||||
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Math.gdshaderinc"
|
||||
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Transform.gdshaderinc"
|
||||
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Noise.gdshaderinc"
|
||||
#include "res://addons/rokojori_action_library/Runtime/Shading/Library/Colors.gdshaderinc"
|
||||
|
||||
uniform vec4 albedo : source_color;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Godot;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
||||
|
||||
namespace Rokojori
|
||||
{
|
||||
[Tool]
|
||||
[GlobalClass]
|
||||
public partial class PixelDensityTool:Node
|
||||
{
|
||||
[Export]
|
||||
public float fovDegrees = 60;
|
||||
|
||||
[Export]
|
||||
public Vector2 screenSize = new Vector2( 1920, 1080 );
|
||||
|
||||
[Export]
|
||||
public float startDistance = 1;
|
||||
|
||||
[Export]
|
||||
public float endDistance = 4000;
|
||||
|
||||
[Export]
|
||||
public int numEntries = 20;
|
||||
|
||||
[Export]
|
||||
public float densityTablePower = 2;
|
||||
|
||||
|
||||
|
||||
[ExportToolButton( "Compute Pixel Density Tables")]
|
||||
public Callable ExecuteButton => Callable.From( () =>
|
||||
{
|
||||
var list = new List<string>();
|
||||
for ( int i = 0; i < numEntries; i++ )
|
||||
{
|
||||
var t = i / ( float ) ( numEntries - 1f );
|
||||
t = Mathf.Pow( t, densityTablePower );
|
||||
var distance = Mathf.Lerp( startDistance, endDistance, t );
|
||||
|
||||
var pixelDensity = Cameras.ComputePixelDensityVertical( fovDegrees, distance, screenSize );
|
||||
var minSize = 1f / pixelDensity;
|
||||
|
||||
list.Add( "[" + distance._M()+ "] density: " + pixelDensity._FF() + "px/m - size:" + ( minSize < 1 ? minSize._CM() : minSize._M() ) + " " );
|
||||
|
||||
}
|
||||
|
||||
distanceToPixelSize = list.ToArray();
|
||||
}
|
||||
);
|
||||
|
||||
[Export]
|
||||
public string[] distanceToPixelSize;
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
uid://cgavpqkqwoh8c
|
|
@ -0,0 +1 @@
|
|||
uid://dglam3n6d2cwf
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue