137 lines
3.7 KiB
C#
137 lines
3.7 KiB
C#
|
using Godot;
|
||
|
using System.Collections.Generic;
|
||
|
using System;
|
||
|
|
||
|
namespace Rokojori
|
||
|
{
|
||
|
public class SplineCurveCreator
|
||
|
{
|
||
|
bool closed;
|
||
|
|
||
|
public SplineCurve Create( List<SplinePoint> splinePoints, bool close )
|
||
|
{
|
||
|
closed = close;
|
||
|
var points = new List<SplineCurvePoint>();
|
||
|
|
||
|
for ( int i = 0; i < splinePoints.Count; i++ )
|
||
|
{
|
||
|
points.Add( CreatePoint( splinePoints, i ) );
|
||
|
}
|
||
|
|
||
|
if ( closed )
|
||
|
{
|
||
|
points.Add( CreatePoint( splinePoints, 0 ) );
|
||
|
}
|
||
|
|
||
|
return SplineCurve.From( points );
|
||
|
}
|
||
|
|
||
|
SplineCurvePoint CreatePoint( List<SplinePoint> splinePoints, int index )
|
||
|
{
|
||
|
var splineCurvePoint = new SplineCurvePoint();
|
||
|
var splinePoint = splinePoints[ index ];
|
||
|
splineCurvePoint.position = splinePoint.GlobalPosition;
|
||
|
splineCurvePoint.weight = 1f;
|
||
|
|
||
|
splineCurvePoint.tangentBefore.position = GetTangentPosition( splinePoints, index, true );
|
||
|
splineCurvePoint.tangentNext.position = GetTangentPosition( splinePoints, index, false );
|
||
|
|
||
|
splineCurvePoint.tangentBefore.weight = splinePoint.tangentBeforeWeight;
|
||
|
splineCurvePoint.tangentNext.weight = splinePoint.tangentNextWeight;
|
||
|
|
||
|
return splineCurvePoint;
|
||
|
}
|
||
|
|
||
|
public Vector3 GetTangentPosition( List<SplinePoint> splinePoints, int index, bool before )
|
||
|
{
|
||
|
var splinePoint = splinePoints[ index ];
|
||
|
|
||
|
if ( splinePoint.tangentMode == SplinePointTangentMode.Custom )
|
||
|
{
|
||
|
return before ? splinePoint.tangentBefore.GlobalPosition :
|
||
|
splinePoint.tangentNext.GlobalPosition;
|
||
|
}
|
||
|
|
||
|
var previousIndex = index - 1;
|
||
|
|
||
|
if ( previousIndex == -1 )
|
||
|
{
|
||
|
previousIndex = closed ? splinePoints.Count -1 : 0;
|
||
|
}
|
||
|
|
||
|
var nextIndex = index + 1;
|
||
|
|
||
|
if ( nextIndex == splinePoints.Count )
|
||
|
{
|
||
|
nextIndex = closed ? 0 : splinePoints.Count - 1;
|
||
|
}
|
||
|
|
||
|
var previous = splinePoints[ previousIndex ];
|
||
|
var next = splinePoints[ nextIndex ];
|
||
|
|
||
|
var previousPosition = previous.GlobalPosition;
|
||
|
var nextPosition = next.GlobalPosition;
|
||
|
|
||
|
|
||
|
|
||
|
var point = splinePoint.GlobalPosition;
|
||
|
|
||
|
var overshootPrevention = splinePoint.overshootPrevention;
|
||
|
var tangentScale = splinePoint.tangentScale;
|
||
|
var symmetricTangentLength = splinePoint.symmetricTangentLength;
|
||
|
|
||
|
if ( overshootPrevention > 0 )
|
||
|
{
|
||
|
var previousDirection = ( previousPosition - point ) ;
|
||
|
var nextDirection = ( nextPosition - point );
|
||
|
|
||
|
var previousLength = previousDirection.Length();
|
||
|
var nextLength = nextDirection.Length();
|
||
|
|
||
|
if ( previousLength > nextLength )
|
||
|
{
|
||
|
previousPosition = Math3D.Lerp(
|
||
|
previousPosition, point + previousDirection.Normalized() * nextLength,
|
||
|
overshootPrevention
|
||
|
);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
nextPosition = Math3D.Lerp(
|
||
|
nextPosition, point + nextDirection.Normalized() * previousLength,
|
||
|
overshootPrevention
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var direction = nextPosition - previousPosition;
|
||
|
var length = 0f;
|
||
|
|
||
|
var lengthBefore = ( point - previousPosition ).Length();
|
||
|
var lengthNext = ( point - nextPosition ).Length();
|
||
|
|
||
|
var lengthAverage = ( lengthBefore + lengthNext ) * 0.5f;
|
||
|
|
||
|
if ( symmetricTangentLength > 0 )
|
||
|
{
|
||
|
lengthBefore = Mathf.Lerp( lengthBefore, lengthAverage, symmetricTangentLength );
|
||
|
lengthNext = Mathf.Lerp( lengthNext, lengthAverage, symmetricTangentLength );
|
||
|
}
|
||
|
|
||
|
if ( before )
|
||
|
{
|
||
|
length = -lengthBefore;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
length = lengthNext;
|
||
|
}
|
||
|
|
||
|
return point + direction.Normalized() * length * 0.33333f * tangentScale;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|