public static ObjectBounds GetApproximateXZObjectBounds(this SplineSegment s) { var rot = Quaternion.LookRotation(s.FirstControlPoint.Position.xz().x0z() - s.SecondControlPoint.Position.xz().x0z()); var b = new ObjectBounds(s.Points[0].Position, Vector3.zero, rot); for (var i = 0; i < s.Points.Count; i++) { b.Encapsulate(s.Points[i].Position); } return(b); }
public static Vector3 GetDeltaOnSpline(this SplineSegment s, float naturalT) { var p0 = s.FirstControlPoint.Position; var p1 = s.FirstControlPoint.Position + s.FirstControlPoint.Control; var p2 = s.SecondControlPoint.Position + s.SecondControlPoint.Control; var p3 = s.SecondControlPoint.Position; var a = 3 * Mathf.Pow(1 - naturalT, 2) * (p1 - p0); var b = 6 * (1 - naturalT) * naturalT * (p2 - p1); var c = 3 * Mathf.Pow(naturalT, 2) * (p3 - p2); return(a + b + c); }
public static Vector3 GetNaturalPointOnSpline(this SplineSegment s, float naturalT) { var p0 = s.FirstControlPoint.Position; var p1 = s.FirstControlPoint.Position + s.FirstControlPoint.Control; var p2 = s.SecondControlPoint.Position + s.SecondControlPoint.Control; var p3 = s.SecondControlPoint.Position; var t2 = naturalT * naturalT; var t3 = naturalT * t2; var mt = 1 - naturalT; var mt2 = mt * mt; var mt3 = mt * mt2; return(p0 * mt3 + 3 * p1 * mt2 * naturalT + 3 * p2 * mt * t2 + p3 * t3); }
public static float NaturalToUniformTime(this SplineSegment s, float naturalT) { for (var i = 1; i < s.Points.Count; i++) { var thisPoint = s.Points[i]; var thisNT = thisPoint.NaturalTime; if (naturalT > thisNT) { continue; } var lastPoint = s.Points[i - 1]; var lastNT = lastPoint.NaturalTime; var frac = naturalT - lastNT; var lerp = frac / (thisNT - lastNT); return(Mathf.Lerp(lastPoint.AccumLength / s.Length, thisPoint.AccumLength / s.Length, lerp)); } return(1); }
public static float UniformToNaturalTime(this SplineSegment s, float uniformT) { var length = s.Length; for (var i = 1; i < s.Points.Count; i++) { var thisPoint = s.Points[i]; var thisUt = thisPoint.AccumLength / length; if (uniformT > thisUt) { continue; } var lastPoint = s.Points[i - 1]; var lastUt = lastPoint.AccumLength / length; var frac = uniformT - lastUt; var lerp = frac / (thisUt - lastUt); return(Mathf.Lerp(lastPoint.NaturalTime, thisPoint.NaturalTime, lerp)); } return(1); }
public static float GetClosestUniformTimeOnSpline(this SplineSegment s, Vector3 worldPos, float threshold) { // Basically a binary search along a spline var rangeT = new Vector2(0, 1); while (true) { var midPointT = Mathf.Lerp(rangeT.x, rangeT.y, .5f); var minPos = s.GetUniformPointOnSpline(rangeT.x); var midPos = s.GetUniformPointOnSpline(midPointT); var maxPos = s.GetUniformPointOnSpline(rangeT.y); var firstDist = (minPos - worldPos).magnitude; var midDist = (midPos - worldPos).magnitude; var secondDist = (maxPos - worldPos).magnitude; var firstSegment = firstDist + midDist; var secondSegment = midDist + secondDist; // The current candidate is good enough if (Mathf.Abs(firstDist - secondDist) < threshold) { return(midPointT); } if (firstSegment < secondSegment) { rangeT = new Vector2(rangeT.x, midPointT); } else { rangeT = new Vector2(midPointT, rangeT.y); } } }
public static Vector3 GetUpVector(this SplineSegment s, float naturalT) { return(Vector3.Lerp(s.FirstControlPoint.UpVector, s.SecondControlPoint.UpVector, naturalT)); }
public static Quaternion GetRotation(this SplineSegment s, float naturalT) { return(Quaternion.Euler(Vector3.Lerp(s.FirstControlPoint.Rotation, s.SecondControlPoint.Rotation, naturalT))); }
// Distorts a mesh along a spline public static Mesh DistortAlongSpline(this Mesh sourceMesh, SplineSegment spline, Matrix4x4 meshTransform, float splineStartTime = 0, float splineEndTime = 1, float snapDistance = 0, SplineSegment.ESplineInterpolation splineInterpolation = SplineSegment.ESplineInterpolation.Natural) { var result = new Mesh(); var verts = new List <Vector3>(sourceMesh.vertices); var meshBounds = new Bounds(); for (var i = 0; i < verts.Count; i++) { verts[i] = meshTransform.MultiplyPoint3x4(verts[i]); if (i == 0) { meshBounds.center = verts[i]; } else { meshBounds.Encapsulate(verts[i]); } } //DebugHelper.DrawCube(meshBounds.center, meshBounds.extents, Quaternion.identity, Color.white, 20); var splineLength = spline.Length; var colors = new Color[verts.Count]; // Transform vert from mesh space to spline-axis space for (var i = verts.Count - 1; i >= 0; i--) { var vert = verts[i]; // First is finding the vert on the spline axis var normalizedVert = vert - meshBounds.min; // Normalized vert tells us where it falls on the splines 't' axis normalizedVert = new Vector3( normalizedVert.x / Mathf.Max(float.Epsilon, meshBounds.size.x), normalizedVert.y / Mathf.Max(float.Epsilon, meshBounds.size.y), normalizedVert.z / Mathf.Max(float.Epsilon, meshBounds.size.z)); var t = Mathf.Lerp(splineStartTime, splineEndTime, normalizedVert.x); var dist = t * splineLength; if (dist < snapDistance) { t = 0; } var distRemaining = splineLength - dist; if (distRemaining < snapDistance) { t = 1; } t = Mathf.Clamp01(t); var natT = t; if (splineInterpolation == SplineSegment.ESplineInterpolation.Uniform) { natT = spline.UniformToNaturalTime(t); } //var rotation = spline.GetRotation(natT); var tangent = spline.GetTangent(natT); var splineForward = Quaternion.LookRotation(tangent, spline.GetUpVector(natT)); //var axisRotation = GetAxisRotation(axis); //var uniformT = spline.NaturalToUniformTime(t); var pointAlongSpline = /*transform.worldToLocalMatrix**/ spline.GetUniformPointOnSpline(t); //var vectorFromAxis = GetVectorFromAxis(vert, axis); //var splineAdjustedVert = vert - vectorFromAxis; verts[i] = pointAlongSpline + splineForward * new Vector3(0, vert.y, vert.z); colors[i] = Color.Lerp(Color.black, Color.white, t); } result.SetVertices(verts); result.colors = colors; result.SetTriangles(sourceMesh.GetTriangles(0), 0); result.SetUVs(0, new List <Vector2>(sourceMesh.uv)); return(result); }