using System; using System.Collections.Generic; using System.Linq; using System.Text; using UnityEngine; namespace SplineMesh { /// /// Imutable class containing all data about a point on a cubic bezier curve. /// public struct CurveSample { public readonly Vector3 location; public readonly Vector3 tangent; public readonly Vector3 up; public readonly Vector2 scale; public readonly float roll; public readonly float distanceInCurve; public readonly float timeInCurve; public readonly CubicBezierCurve curve; private Quaternion rotation; /// /// Rotation is a look-at quaternion calculated from the tangent, roll and up vector. Mixing non zero roll and custom up vector is not advised. /// public Quaternion Rotation { get { if (rotation == Quaternion.identity) { var upVector = Vector3.Cross(tangent, Vector3.Cross(Quaternion.AngleAxis(roll, Vector3.forward) * up, tangent).normalized); rotation = Quaternion.LookRotation(tangent, upVector); } return rotation; } } public CurveSample(Vector3 location, Vector3 tangent, Vector3 up, Vector2 scale, float roll, float distanceInCurve, float timeInCurve, CubicBezierCurve curve) { this.location = location; this.tangent = tangent; this.up = up; this.roll = roll; this.scale = scale; this.distanceInCurve = distanceInCurve; this.timeInCurve = timeInCurve; this.curve = curve; rotation = Quaternion.identity; } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return false; } CurveSample other = (CurveSample)obj; return location == other.location && tangent == other.tangent && up == other.up && scale == other.scale && roll == other.roll && distanceInCurve == other.distanceInCurve && timeInCurve == other.timeInCurve; } public override int GetHashCode() { return base.GetHashCode(); } public static bool operator ==(CurveSample cs1, CurveSample cs2) { return cs1.Equals(cs2); } public static bool operator !=(CurveSample cs1, CurveSample cs2) { return !cs1.Equals(cs2); } /// /// Linearly interpolates between two curve samples. /// /// /// /// /// public static CurveSample Lerp(CurveSample a, CurveSample b, float t) { return new CurveSample( Vector3.Lerp(a.location, b.location, t), Vector3.Lerp(a.tangent, b.tangent, t).normalized, Vector3.Lerp(a.up, b.up, t), Vector2.Lerp(a.scale, b.scale, t), Mathf.Lerp(a.roll, b.roll, t), Mathf.Lerp(a.distanceInCurve, b.distanceInCurve, t), Mathf.Lerp(a.timeInCurve, b.timeInCurve, t), a.curve); } public MeshVertex GetBent(MeshVertex vert) { var res = new MeshVertex(vert.position, vert.normal, vert.uv); // application of scale res.position = Vector3.Scale(res.position, new Vector3(0, scale.y, scale.x)); // application of roll res.position = Quaternion.AngleAxis(roll, Vector3.right) * res.position; res.normal = Quaternion.AngleAxis(roll, Vector3.right) * res.normal; // reset X value res.position.x = 0; // application of the rotation + location Quaternion q = Rotation * Quaternion.Euler(0, -90, 0); res.position = q * res.position + location; res.normal = q * res.normal; return res; } } }