rj-action-library/Runtime/Procedural/Parametric/Spline/SplineMesh.cs

84 lines
2.2 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 SplineMesh : Action
{
[Export]
public Spline spline;
[Export]
public float splineRadius = 0.5f;
[Export]
public float resolutionU = 0.1f;
[Export]
public int maxSegmentsU = 64;
[Export]
public float resolutionV = 0.5f;
[Export]
public int maxSegmentsV = 1024;
[Export]
public MeshInstance3D output;
[Export]
public bool undistortSplineSegments = false;
protected override void _OnTrigger()
{
CreateMesh();
}
public void CreateMesh()
{
var curve = spline.GetCurve();
var length = curve.ComputeLength( 100 );
var numPoints = Mathf.Clamp( length / resolutionU, 2, maxSegmentsU );
var uSegments = (int) ( Mathf.Clamp( splineRadius * 2f * 3.14f / resolutionV, 3, maxSegmentsV ) );
var vSegments = (int) ( numPoints - 1 );
var uvFunction = ( Vector2 uv ) =>
{
var t = undistortSplineSegments ? curve.ComputeTforNormalizedCurveLength( uv.Y, vSegments ) : uv.Y;
var index = curve.NormalizedToPointIndex( t );
var pose = curve.PoseAt( t );
var radiusSize = splineRadius;
var angle = uv.X * 2f * Mathf.Pi;
var circlePose = Pose.Create( Vector3.Zero, pose.rotation * Math3D.RotateZ( angle ) );
circlePose.rotation = circlePose.rotation.Normalized();
var circleStart = Vector3.Up * radiusSize;
var positionOnCircle = circlePose.Apply( circleStart );
return Pose.Create( positionOnCircle + pose.position, circlePose.rotation );
};
var mg = MeshGeometry.CreateFromUVFunction( uvFunction, uSegments, vSegments );
mg.Add( MeshGeometry.CreateCapUVFunction( uvFunction, uSegments, true ) );
mg.Add( MeshGeometry.CreateCapUVFunction( uvFunction, uSegments, false ) );
if ( output == null )
{
output = this.CreateChild<MeshInstance3D>( "Spline MeshInstance");
}
output.Mesh = mg.GenerateMesh();
}
}
}