146 lines
4.8 KiB
C#
146 lines
4.8 KiB
C#
![]() |
|
||
|
using Godot;
|
||
|
using Rokojori;
|
||
|
using System.Collections.Generic;
|
||
|
|
||
|
namespace Rokojori
|
||
|
{
|
||
|
|
||
|
public class TubeGeometry
|
||
|
{
|
||
|
public SplineCurve curve;
|
||
|
public TubeShape[] shapes = [];
|
||
|
|
||
|
public TubeGeometrySettings settings;
|
||
|
|
||
|
public MeshGeometry CreateMesh()
|
||
|
{
|
||
|
int splineSegments = settings.fixedSplineSegmentDivisions;
|
||
|
|
||
|
if ( TubeSegmentMode.Fixed_Division != settings.segmentMode )
|
||
|
{
|
||
|
splineSegments = Mathf.CeilToInt( curve.ComputeLength( curve.points.Count * 3 ) / settings.splineSegmentLength );
|
||
|
|
||
|
if ( TubeSegmentMode.Maximum_Of_Both == settings.segmentMode )
|
||
|
{
|
||
|
splineSegments = Mathf.Max( splineSegments, settings.fixedSplineSegmentDivisions );
|
||
|
}
|
||
|
if ( TubeSegmentMode.Minimum_Of_Both == settings.segmentMode )
|
||
|
{
|
||
|
splineSegments = Mathf.Min( splineSegments, settings.fixedSplineSegmentDivisions );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var shapesList = new List<TubeShape>();
|
||
|
|
||
|
if ( shapes != null && shapes.Length > 0 )
|
||
|
{
|
||
|
shapesList.AddRange( shapes );
|
||
|
Lists.Sort( shapesList, s => s.tubePosition );
|
||
|
|
||
|
shapesList.ForEach( s => s.ClearCache() );
|
||
|
|
||
|
}
|
||
|
|
||
|
System.Func<Vector2,Pose> uvFunction = ( Vector2 uv ) =>
|
||
|
{
|
||
|
var t = settings.undistortSplineSegments ? curve.ComputeTforNormalizedCurveLength( uv.Y, splineSegments ) : uv.Y;
|
||
|
var index = curve.NormalizedToPointIndex( t );
|
||
|
var pose = curve.PoseAt( t );
|
||
|
// RJLog.Log( "Pose at t:", t, "rot:", pose.rotation, "pos", pose.position );
|
||
|
var radiusSize = settings.radius * ( settings.radiusSizeCurve == null ? 1 : settings.radiusSizeCurve.Sample( t ) );
|
||
|
var sizeX = radiusSize;
|
||
|
var sizeY = radiusSize;
|
||
|
var twistOffset = 0f;
|
||
|
|
||
|
if ( settings.radiusWidthCurve != null )
|
||
|
{
|
||
|
sizeX *= settings.radiusWidthCurve.Sample( t );
|
||
|
}
|
||
|
|
||
|
if ( settings.radiusHeightCurve != null )
|
||
|
{
|
||
|
sizeY *= settings.radiusHeightCurve.Sample( t );
|
||
|
}
|
||
|
|
||
|
if ( settings.scaleRadiusByPathTransforms )
|
||
|
{
|
||
|
|
||
|
var splineScale = curve.SmoothStepScaleByPointIndex( index );
|
||
|
|
||
|
if ( settings.scaleRadiusByPathTransforms )
|
||
|
{
|
||
|
sizeX *= splineScale.X;
|
||
|
sizeY *= splineScale.Y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ( settings.twistCurve != null )
|
||
|
{
|
||
|
twistOffset = Mathf.DegToRad( settings.twistCurve.Sample( t ) );
|
||
|
}
|
||
|
|
||
|
twistOffset += Mathf.DegToRad( curve.SmoothStepTwistByPointIndex( index ) * 360 );
|
||
|
|
||
|
var twistRotation = Math3D.RotateZ( twistOffset ).Normalized();
|
||
|
|
||
|
var scale = new Vector3( sizeX, sizeY, 0 );
|
||
|
|
||
|
if ( shapesList.Count > 0 )
|
||
|
{
|
||
|
if ( shapesList.Count == 1 )
|
||
|
{
|
||
|
return shapesList[ 0 ].GetPose( settings.undistortSplineSegments, splineSegments, settings.radialSegments, pose, uv, scale, twistRotation );
|
||
|
}
|
||
|
|
||
|
var lerpResult = Lists.LerpIndex( shapesList, uv.Y, s => s.tubePosition );
|
||
|
|
||
|
|
||
|
var closestShape = shapesList[ lerpResult.closestIndex ];
|
||
|
var secondShape = shapesList[ lerpResult.secondIndex ];
|
||
|
|
||
|
var closestPose = closestShape.GetPose( settings.undistortSplineSegments, splineSegments, settings.radialSegments, pose, uv, scale, twistRotation );
|
||
|
var secondPose = secondShape.GetPose( settings.undistortSplineSegments, splineSegments, settings.radialSegments, pose, uv, scale, twistRotation );
|
||
|
|
||
|
var smoothLerp = Mathf.SmoothStep( 0f, 1f, lerpResult.lerpAmount );
|
||
|
return Pose.Lerp( closestPose, secondPose, smoothLerp );
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
var angle = uv.X * 2f * Mathf.Pi * ( sizeX / sizeY );
|
||
|
var circlePose = Pose.Create( Vector3.Zero, pose.rotation * Math3D.RotateZ( angle ) );
|
||
|
|
||
|
|
||
|
circlePose.rotation = circlePose.rotation.Normalized();
|
||
|
var circleStart = Vector3.Up * radiusSize * scale;
|
||
|
|
||
|
|
||
|
|
||
|
var positionOnCircle = circlePose.Apply( circleStart );
|
||
|
|
||
|
return Pose.Create( positionOnCircle + pose.position, circlePose.rotation );
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
var mg = MeshGeometry.CreateFromUVFunction( uvFunction,
|
||
|
settings.radialSegments, splineSegments, settings.useFullUVQuads
|
||
|
);
|
||
|
|
||
|
if ( TubeGeometrySettings.CapType.Flat == settings.startCapType )
|
||
|
{
|
||
|
var startCapMG = MeshGeometry.CreateCapUVFunction( uvFunction, settings.radialSegments, true );
|
||
|
mg.Add( startCapMG );
|
||
|
}
|
||
|
|
||
|
if ( TubeGeometrySettings.CapType.Flat == settings.endCapType )
|
||
|
{
|
||
|
var endCapMG = MeshGeometry.CreateCapUVFunction( uvFunction, settings.radialSegments, false );
|
||
|
mg.Add( endCapMG );
|
||
|
}
|
||
|
|
||
|
return mg;
|
||
|
}
|
||
|
}
|
||
|
}
|