using System; using Unity.Mathematics; namespace UnityEngine.Splines { /// /// This struct contains position and tangent data for a knot. /// The class stores a collection of BezierKnot that form a series of connected /// . 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). /// [Serializable] public struct BezierKnot: ISerializationCallbackReceiver { /// /// The position of the knot. On a cubic bezier curve, this is equivalent to or /// , depending on whether this knot is forming the first or second control point /// of the curve. /// public float3 Position; /// /// The tangent leading into this knot. On a cubic bezier curve, this value is used to calculate /// when used as the second knot in a curve. /// public float3 TangentIn; /// /// The tangent following this knot. On a cubic bezier curve, this value is used to calculate /// when used as the first knot in a curve. /// public float3 TangentOut; /// /// Rotation of the knot. /// public quaternion Rotation; /// /// Create a new BezierKnot struct. /// /// The position of the knot relative to the spline. public BezierKnot(float3 position) { Position = position; TangentIn = float3.zero; TangentOut = float3.zero; Rotation = quaternion.identity; } /// /// Create a new BezierKnot struct. /// /// The position of the knot relative to the spline. /// The leading tangent to this knot. /// The following tangent to this knot. /// The rotation of the knot relative to the spline. public BezierKnot(float3 position, float3 tangentIn, float3 tangentOut, quaternion rotation) { Position = position; TangentIn = tangentIn; TangentOut = tangentOut; Rotation = rotation; } /// /// Multiply the position and tangents by a matrix. /// /// The matrix to multiply. /// A new BezierKnot multiplied by matrix. 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); } /// /// Knot position addition. This operation only applies to the position, tangents and rotation are unmodified. /// /// The target knot. /// The value to add. /// A new BezierKnot where position is the sum of knot.position and rhs. public static BezierKnot operator +(BezierKnot knot, float3 rhs) { return new BezierKnot(knot.Position + rhs, knot.TangentIn, knot.TangentOut, knot.Rotation); } /// /// Knot position subtraction. This operation only applies to the position, tangents and rotation are unmodified. /// /// The target knot. /// The value to subtract. /// A new BezierKnot where position is the sum of knot.position minus rhs. public static BezierKnot operator -(BezierKnot knot, float3 rhs) { return new BezierKnot(knot.Position - rhs, knot.TangentIn, knot.TangentOut, knot.Rotation); } /// /// See ISerializationCallbackReceiver. /// public void OnBeforeSerialize() {} /// /// See ISerializationCallbackReceiver. /// 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; } } }