rj-action-library/Runtime/Procedural/Parametric/Tube/TubeShape.cs

105 lines
2.5 KiB
C#

using Godot;
using Rokojori;
using System.Collections.Generic;
namespace Rokojori
{
[Tool]
[GlobalClass, Icon("res://addons/rokojori_action_library/Icons/Spline.svg") ]
public partial class TubeShape:Node
{
[Export]
public Spline spline;
[Export]
public Node3D pivotPose;
[Export]
public float tubePosition;
[Export]
public float scale = 1f;
[Export]
public float widthScale = 1f;
[Export]
public float heightScale = 1f;
[Export]
public ShapeOrientationMode shapeOrientationMode = ShapeOrientationMode.Auto;
bool cached = false;
bool shapeForward = true;
SplineCurve radialShape;
public void ClearCache()
{
cached = false;
}
public Pose GetPose( bool undistort, int splineSegments, int radialSegments, Pose pose, Vector2 uv, Vector3 scale, Quaternion twistRotation )
{
if ( ! cached )
{
radialShape = spline.GetCurve();
shapeForward = true;
if ( pivotPose != null )
{
radialShape = radialShape.ApplyPose( Pose.InverseFrom( pivotPose ) );
}
radialShape = radialShape.CloneForXY();
if ( ShapeOrientationMode.Original != shapeOrientationMode )
{
if ( ShapeOrientationMode.Auto == shapeOrientationMode )
{
var path = radialShape.SampleXYPath( radialSegments );
shapeForward = path.isClockwise;
}
if ( ShapeOrientationMode.Reverse == shapeOrientationMode )
{
shapeForward = false;
}
}
cached = true;
}
scale.X *= widthScale * this.scale;
scale.Y *= heightScale * this.scale;
var radialT = ! shapeForward ? uv.X : ( 1f - uv.X );
radialT = undistort ?
radialShape.UtoT( radialT, splineSegments ) :
radialT;
var shapePosition = radialShape.PositionAt( radialT ) * scale;
var shapeTangent = radialShape.TangentAt( radialT, 1f / radialSegments ) * scale;
shapePosition = twistRotation * shapePosition;
shapeTangent = twistRotation * shapeTangent;
var angle = Math3D.AngleXY( shapeTangent ) + Mathf.Pi;
var rotation = Math3D.RotateZ( angle );
var combinedRotation = pose.rotation * rotation;
var rotatedShapePosition = Vector3.Zero;
rotatedShapePosition = pose.rotation * shapePosition;
return Pose.Create( rotatedShapePosition + pose.position, combinedRotation );
}
}
}