public SplineFragmentEnumerator(zzOldISpline spline, float minStepProduct) { interpolator = new SplineInterpolatorEnumerator(spline, minStepProduct); started = false; curPos = Vector3.zero; lastPos = Vector3.zero; }
public SplineInterpolatorEnumerator(zzOldISpline spline, float minStepProduct) { started = false; this.spline = spline; this.minStepProduct = Mathf.Max(minStepProduct, -0.5F, Mathf.Min(minStepProduct, 0.98F)); curControlAIdx = -1; curControlBIdx = -1; curPos = Vector3.zero; curProgress = 0F; hasLastStepPos = false; lastStepPos = Vector3.zero; lastStep = 0.33F; }
/// <summary> /// Returns an enumerator that returns segments along an ISpline. For smoother splines, choose a /// minIntersegmentDotProduct that is closer to 1 (maximum 0.98F). For rougher splines, choose a /// minIntersegmentDotProduct that is closer to -1 (minimum -0.5F). A choise of 0 would allow angles /// up to but no larger than 90 degrees between adjacent spline segments. /// </summary> /// <remarks> /// SplineSegmentEnumerator is a small wrapper around SplineInterpolatorEnumerator that remembers /// the last position traversed to two points at a time. /// </remarks> public static SplineFragmentEnumerator TraverseFragments(this zzOldISpline spline, float minIntersegmentDotProduct = 0.9F) { return(new SplineFragmentEnumerator(spline, minIntersegmentDotProduct)); }
/// <summary> /// Returns an enumerator that will return points along an ISpline. For smoother splines, choose a /// minInterstepDotProduct that is closer to 1 (maximum 0.98F). For rougher splines, choose a /// minInterstepDotProduct that is closer to -1 (minimum -0.5F). A choice of 0 would allow angles /// up to but no larger than 90 degrees between adjacent spline segments. /// </summary> /// <remarks> /// The segment formed by each step returned and the previous step returned will have a dot product /// no smaller than minInterstepDotProduct with the segment formed by the previous step returned and /// the step before that. This enforces a maximum on cos(theta) where theta is the angle between any /// two adjacent segments in the spline. Specifically, the maximum angle could be calculated as /// arccos(minInterstepDotProduct). /// </remarks> public static SplineInterpolatorEnumerator Traverse(this zzOldISpline spline, float minInterstepDotProduct = 0.9F) { return(new SplineInterpolatorEnumerator(spline, minInterstepDotProduct)); }
/// <summary> /// Generates a quad-based spline mesh based on the input spline and provided spline thickness. /// The spline will be oriented so that its first segment faces towards initNormalFacingReference. /// Subsequent segments will rotate their normal/binormal directions based on the FromToRotation /// from one segment to the next. /// </summary> public static void GenerateQuadSplineMesh(ref List <Vector3> verts, ref List <int> indices, zzOldISpline spline, float splineThickness, Vector3 initNormalFacingReference, float minSplineSegmentDotProduct = 0.9F) { s_meshPoints.Clear(); s_threePositionsBuffer.Clear(); s_twoPointsBuffer.Clear(); float halfThickness = splineThickness * 0.5F; // Traverse the spline, constructing SplineMeshPoints with precalculated normals and binormals // to make mesh construction more straight-forward. SplineMeshPoints will be converted into // connected quads for the spline mesh in the next step. Vector3 normal = Vector3.zero; Vector3 binormal = Vector3.zero; bool firstPointAdded = false; int count = 0; foreach (Vector3 pointOnSpline in spline.Traverse(minSplineSegmentDotProduct)) { // Add a placeholder SplineMeshPoint, to be fixed later using information from neighboring points. s_threePositionsBuffer.Add(pointOnSpline); count++; // With a buffer of three positions, we have enough information for the center point. if (s_threePositionsBuffer.IsFull) { var p0 = s_threePositionsBuffer.Get(0); var p1 = s_threePositionsBuffer.Get(1); var p2 = s_threePositionsBuffer.Get(2); // (Special case for the first position in the spline.) if (!firstPointAdded) { normal = (initNormalFacingReference - p0).normalized; Vector3 tangent = (p1 - p0).normalized; binormal = (Vector3.Cross(tangent, normal)).normalized; normal = (Vector3.Cross(binormal, tangent)).normalized; // Ensure basis directions are orthogonal. // Add the first spline mesh point, with a good normal (using the direction towards the camera // as a reasonable basis). s_meshPoints.Add(new SplineMeshPoint() { position = p0, normal = normal, binormal = binormal }); firstPointAdded = true; } // Use neighbor information to fill in information for the center point in the buffer. Vector3 p0Normal = s_meshPoints[s_meshPoints.Count - 1].normal; Vector3 p0Binormal = s_meshPoints[s_meshPoints.Count - 1].binormal; Quaternion segmentRotation = Quaternion.FromToRotation((p1 - p0), (p2 - p1)); normal = segmentRotation * p0Normal; binormal = segmentRotation * p0Binormal; s_meshPoints.Add(new SplineMeshPoint() { position = p1, normal = normal, binormal = binormal }); } } // (Finally, add the last spline mesh point.) s_meshPoints.Add(new SplineMeshPoint() { position = s_threePositionsBuffer.Get(2), normal = normal, binormal = binormal }); // Return early if there aren't enough spline mesh points. if (s_meshPoints.Count < 2) { return; } // Using a prepared list of SplineMeshPoints, construct the mesh by building connected quads. firstPointAdded = false; foreach (SplineMeshPoint meshPoint in s_meshPoints) { s_twoPointsBuffer.Add(meshPoint); if (s_twoPointsBuffer.IsFull) { SplineMeshPoint p0 = s_twoPointsBuffer.Get(0); SplineMeshPoint p1 = s_twoPointsBuffer.Get(1); // (Special case for the first position in the spline.) if (!firstPointAdded) { binormal = p0.binormal; verts.Add(p0.position + binormal * halfThickness); verts.Add(p0.position - binormal * halfThickness); firstPointAdded = true; } binormal = (p0.binormal + p1.binormal).normalized; addIncrementalQuad(verts, indices, p1.position + binormal * halfThickness, p1.position - binormal * halfThickness); } } // (Finally, add the last quad.) addIncrementalQuad(verts, indices, s_meshPoints[s_meshPoints.Count - 1].position + binormal * halfThickness, s_meshPoints[s_meshPoints.Count - 1].position - binormal * halfThickness); }