124 lines
5.3 KiB
C#
124 lines
5.3 KiB
C#
|
using System;
|
||
|
using Unity.Mathematics;
|
||
|
|
||
|
namespace UnityEngine.Splines
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// This struct contains position and tangent data for a knot.
|
||
|
/// The <see cref="Spline"/> class stores a collection of BezierKnot that form a series of connected
|
||
|
/// <see cref="BezierCurve"/>. Each knot contains a Position, Tangent In, and Tangent Out. When a Spline is not
|
||
|
/// closed, the first and last knots will contain an extraneous tangent (in and out, respectively).
|
||
|
/// </summary>
|
||
|
[Serializable]
|
||
|
public struct BezierKnot: ISerializationCallbackReceiver
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// The position of the knot. On a cubic bezier curve, this is equivalent to <see cref="BezierCurve.P0"/> or
|
||
|
/// <see cref="BezierCurve.P3"/>, depending on whether this knot is forming the first or second control point
|
||
|
/// of the curve.
|
||
|
/// </summary>
|
||
|
public float3 Position;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The tangent leading into this knot. On a cubic bezier curve, this value is used to calculate
|
||
|
/// <see cref="BezierCurve.P2"/> when used as the second knot in a curve.
|
||
|
/// </summary>
|
||
|
public float3 TangentIn;
|
||
|
|
||
|
/// <summary>
|
||
|
/// The tangent following this knot. On a cubic bezier curve, this value is used to calculate
|
||
|
/// <see cref="BezierCurve.P1"/> when used as the first knot in a curve.
|
||
|
/// </summary>
|
||
|
public float3 TangentOut;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Rotation of the knot.
|
||
|
/// </summary>
|
||
|
public quaternion Rotation;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create a new BezierKnot struct.
|
||
|
/// </summary>
|
||
|
/// <param name="position">The position of the knot relative to the spline.</param>
|
||
|
public BezierKnot(float3 position)
|
||
|
{
|
||
|
Position = position;
|
||
|
TangentIn = float3.zero;
|
||
|
TangentOut = float3.zero;
|
||
|
Rotation = quaternion.identity;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Create a new BezierKnot struct.
|
||
|
/// </summary>
|
||
|
/// <param name="position">The position of the knot relative to the spline.</param>
|
||
|
/// <param name="tangentIn">The leading tangent to this knot.</param>
|
||
|
/// <param name="tangentOut">The following tangent to this knot.</param>
|
||
|
/// <param name="rotation">The rotation of the knot relative to the spline.</param>
|
||
|
public BezierKnot(float3 position, float3 tangentIn, float3 tangentOut, quaternion rotation)
|
||
|
{
|
||
|
Position = position;
|
||
|
TangentIn = tangentIn;
|
||
|
TangentOut = tangentOut;
|
||
|
Rotation = rotation;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Multiply the position and tangents by a matrix.
|
||
|
/// </summary>
|
||
|
/// <param name="matrix">The matrix to multiply.</param>
|
||
|
/// <returns>A new BezierKnot multiplied by matrix.</returns>
|
||
|
public BezierKnot Transform(float4x4 matrix)
|
||
|
{
|
||
|
var rotation = math.mul(new quaternion(matrix), Rotation);
|
||
|
var invRotation = math.inverse(rotation);
|
||
|
// Tangents need to be scaled, so rotation should be applied to them.
|
||
|
// No need however to use the translation as this is only a direction.
|
||
|
return new BezierKnot(
|
||
|
math.transform(matrix, Position),
|
||
|
math.rotate(invRotation, math.rotate(matrix, math.rotate(Rotation,TangentIn))),
|
||
|
math.rotate(invRotation, math.rotate(matrix, math.rotate(Rotation,TangentOut))),
|
||
|
rotation);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Knot position addition. This operation only applies to the position, tangents and rotation are unmodified.
|
||
|
/// </summary>
|
||
|
/// <param name="knot">The target knot.</param>
|
||
|
/// <param name="rhs">The value to add.</param>
|
||
|
/// <returns>A new BezierKnot where position is the sum of knot.position and rhs.</returns>
|
||
|
public static BezierKnot operator +(BezierKnot knot, float3 rhs)
|
||
|
{
|
||
|
return new BezierKnot(knot.Position + rhs, knot.TangentIn, knot.TangentOut, knot.Rotation);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Knot position subtraction. This operation only applies to the position, tangents and rotation are unmodified.
|
||
|
/// </summary>
|
||
|
/// <param name="knot">The target knot.</param>
|
||
|
/// <param name="rhs">The value to subtract.</param>
|
||
|
/// <returns>A new BezierKnot where position is the sum of knot.position minus rhs.</returns>
|
||
|
public static BezierKnot operator -(BezierKnot knot, float3 rhs)
|
||
|
{
|
||
|
return new BezierKnot(knot.Position - rhs, knot.TangentIn, knot.TangentOut, knot.Rotation);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// See ISerializationCallbackReceiver.
|
||
|
/// </summary>
|
||
|
public void OnBeforeSerialize() {}
|
||
|
|
||
|
/// <summary>
|
||
|
/// See ISerializationCallbackReceiver.
|
||
|
/// </summary>
|
||
|
public void OnAfterDeserialize()
|
||
|
{
|
||
|
// Ensures that when adding the first knot via Unity inspector
|
||
|
// or when deserializing knot that did not have the rotation field prior,
|
||
|
// rotation is deserialized to identity instead of (0, 0, 0, 0) which does not represent a valid rotation.
|
||
|
if (math.lengthsq(Rotation) == 0f)
|
||
|
Rotation = quaternion.identity;
|
||
|
}
|
||
|
}
|
||
|
}
|