Inheritance: MonoBehaviour
Exemplo n.º 1
0
        public static Vector2 Calculate(Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3, float t)
        {
            Vector2 a, b, c, d;
            float   ct = 0;

            if (t < 1f / 3f)
            {
                a  = p0;
                b  = p0;
                c  = p1;
                d  = p2;
                ct = t * 3.0f;
            }
            else if (t > 2f / 3f)
            {
                a  = p1;
                b  = p2;
                c  = p3;
                d  = p3;
                ct = t * 3.0f - 2.0f;
            }
            else
            {
                a  = p0;
                b  = p1;
                c  = p2;
                d  = p3;
                ct = t * 3.0f - 1.0f;
            }

            return(SplineMaths.CalculateCatmullRom(a, b, c, d, ct));
        }
Exemplo n.º 2
0
        public static Vector3 Calculate(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t)
        {
            Vector3 a, b, c, d;
            float   ct = 0;

            if (t < 1f / 3f)
            {
                a  = p0;
                b  = p0;
                c  = p1;
                d  = p2;
                ct = t * 3.0f;
            }
            else if (t > 2f / 3f)
            {
                a  = p1;
                b  = p2;
                c  = p3;
                d  = p3;
                ct = t * 3.0f - 2.0f;
            }
            else
            {
                a  = p0;
                b  = p1;
                c  = p2;
                d  = p3;
                ct = t * 3.0f - 1.0f;
            }

            //            return SplineMaths.CalculateHermite(p0, p1, p2, p3, t, -0.80f, 0);
            //            return SplineMaths.CalculateBezierPoint(p0, p1, p2, p3, t);
            return(SplineMaths.CalculateCatmullRom(a, b, c, d, ct));
        }
Exemplo n.º 3
0
        public static Vector3 Calculate(Vector3 p0, Vector3 p1, Vector3 p2, float t)
        {
            Vector3 a, b, c, d;
            float   ct = 0;

            if (t < 0.5f)
            {
                a  = p0;
                b  = p0;
                c  = p1;
                d  = p2;
                ct = t * 2.0f;
            }
            else if (t > 0.5f)
            {
                a  = p0;
                b  = p1;
                c  = p2;
                d  = p2;
                ct = t * 2.0f - 1.0f;
            }
            else
            {
                return(p1);
            }

            return(SplineMaths.CalculateHermite(a, b, c, d, ct, -0.80f, 0));
//            return SplineMaths.CalculateBezierPoint(a, b, c, d, ct);
//            return SplineMaths.CalculateCatmullRom(a, b, c, d, ct);
        }
Exemplo n.º 4
0
    //Sample nextNormIndex position on the entire curve based on time (0-1)
    public Vector3 GetRightBoundaryPosition(float t)
    {
        float            curveT = 1.0f / numberOfCurves;
        int              point  = Mathf.FloorToInt(t / curveT);
        float            ct     = Mathf.Clamp01((t - point * curveT) * numberOfCurves);
        TrackBuildRPoint pointA = GetPoint(point);
        TrackBuildRPoint pointB = GetPoint(point + 1);

        return(SplineMaths.CalculateBezierPoint(ct, pointA.rightTrackBoundary, pointA.rightForwardControlPoint, pointB.rightBackwardControlPoint, pointB.rightTrackBoundary));
    }
Exemplo n.º 5
0
    public Vector3 GetTrackCross(float t)
    {
        float            curveT  = 1.0f / numberOfCurves;
        int              point   = Mathf.FloorToInt(t / curveT);
        float            ct      = Mathf.Clamp01((t - point * curveT) * numberOfCurves);
        float            hermite = SplineMaths.CalculateHermite(ct);
        TrackBuildRPoint pointA  = GetPoint(point);
        TrackBuildRPoint pointB  = GetPoint(point + 1);

        return(Vector3.Slerp(pointA.trackCross, pointB.trackCross, hermite));
    }
Exemplo n.º 6
0
    public float GetTrackCrownAngle(float t)
    {
        float            curveT  = 1.0f / numberOfCurves;
        int              point   = Mathf.FloorToInt(t / curveT);
        float            ct      = Mathf.Clamp01((t - point * curveT) * numberOfCurves);
        float            hermite = SplineMaths.CalculateHermite(ct);
        TrackBuildRPoint pointA  = GetPoint(point);
        TrackBuildRPoint pointB  = GetPoint(point + 1);

        return(Mathf.LerpAngle(pointA.crownAngle, pointB.crownAngle, hermite));
    }
Exemplo n.º 7
0
    public Vector3 GetTrackDirection(float t)
    {
        float            curveT          = 1.0f / numberOfCurves;
        int              point           = Mathf.FloorToInt(t / curveT);
        float            ct              = Mathf.Clamp01((t - point * curveT) * numberOfCurves);
        float            hermite         = SplineMaths.CalculateHermite(ct);
        TrackBuildRPoint pointA          = GetPoint(point);
        TrackBuildRPoint pointB          = GetPoint(point + 1);
        Quaternion       trackDirectionA = Quaternion.LookRotation(pointA.trackDirection);
        Quaternion       trackDirectionB = Quaternion.LookRotation(pointB.trackDirection);
        Quaternion       trackDirectionQ = Quaternion.Slerp(trackDirectionA, trackDirectionB, hermite);

        return(trackDirectionQ * Vector3.forward);
    }
Exemplo n.º 8
0
    //Sample nextNormIndex position on the entire curve based on time (0-1)
    public Vector3 GetTrackPosition(float t)
    {
        if (realNumberOfPoints < 2)
        {
            Debug.LogError("Not enough points to define a curve");
            return(Vector3.zero);
        }
        float            curveT = 1.0f / numberOfCurves;
        int              point  = Mathf.FloorToInt(t / curveT);
        float            ct     = Mathf.Clamp01((t - point * curveT) * numberOfCurves);
        TrackBuildRPoint pointA = GetPoint(point);
        TrackBuildRPoint pointB = GetPoint(point + 1);

        return(SplineMaths.CalculateBezierPoint(ct, pointA.position, pointA.forwardControlPoint, pointB.backwardControlPoint, pointB.position));
    }
Exemplo n.º 9
0
    public void RecalculateCurves()
    {
        if (_points.Count < 2)//there is no track with only one point :o)
        {
            return;
        }

        if (isDirty)
        {
            _tangentsGenerated = false;
            _lightmapGenerated = false;
            _optimised         = false;
        }

        //calculate approx bezier arc length per curve
        for (int i = 0; i < realNumberOfPoints; i++)
        {
            TrackBuildRPoint pointA        = GetPoint(i);
            TrackBuildRPoint pointB        = GetPoint(i + 1);
            float            thisArcLength = 0;
            thisArcLength       += Vector3.Distance(pointA.position, pointA.forwardControlPoint);
            thisArcLength       += Vector3.Distance(pointA.forwardControlPoint, pointB.backwardControlPoint);
            thisArcLength       += Vector3.Distance(pointB.backwardControlPoint, pointB.position);
            _points[i].arcLength = thisArcLength;
            if (thisArcLength == 0)
            {
                DestroyImmediate(pointA);
                i--;
            }
        }

        for (int i = 0; i < realNumberOfPoints; i++)
        {
            TrackBuildRPoint pointA = GetPoint(i);
            TrackBuildRPoint pointB = GetPoint(i + 1);
            TrackBuildRPoint pointC = GetPoint(i - 1);
            pointA.nextPoint = pointB;
            pointA.lastPoint = pointC;
            pointA.pointName = "point " + i;
        }

        foreach (TrackBuildRPoint curve in _points)
        {
            if (!curve.curveIsDirty)//only recalculate modified points
            {
                continue;
            }

            if (curve.arcLength > 0)
            {
                TrackBuildRPoint pointA = curve;
                TrackBuildRPoint pointB = curve.nextPoint;

                //Build accurate arc length data into curve
                curve.center = Vector3.zero;
                int   arcLengthResolution = Mathf.Max(Mathf.RoundToInt(curve.arcLength * 10), 1);
                float alTime = 1.0f / arcLengthResolution;
                float calculatedTotalArcLength = 0;
                curve.storedArcLengthsFull    = new float[arcLengthResolution];
                curve.storedArcLengthsFull[0] = 0.0f;
                Vector3 pA = curve.position;
                for (int i = 0; i < arcLengthResolution - 1; i++)
                {
                    curve.center += pA;
                    float   altB      = alTime * (i + 1) + alTime;
                    Vector3 pB        = SplineMaths.CalculateBezierPoint(altB, curve.position, curve.forwardControlPoint, pointB.backwardControlPoint, pointB.position);
                    float   arcLength = Vector3.Distance(pA, pB);
                    calculatedTotalArcLength         += arcLength;
                    curve.storedArcLengthsFull[i + 1] = calculatedTotalArcLength;
                    pA = pB;//switch over values so we only calculate the bezier once
                }
                curve.arcLength = calculatedTotalArcLength;
                curve.center   /= arcLengthResolution;

                int storedPointSize = Mathf.RoundToInt(calculatedTotalArcLength / meshResolution);
                curve.storedPointSize = storedPointSize;
                curve.normalisedT     = new float[storedPointSize];
                curve.targetSize      = new float[storedPointSize];
                curve.midPointPerc    = new float[storedPointSize];
                curve.prevNormIndex   = new int[storedPointSize];
                curve.nextNormIndex   = new int[storedPointSize];
                curve.clipArrayLeft   = new bool[storedPointSize];
                curve.clipArrayRight  = new bool[storedPointSize];

                //calculate normalised spline data
                int normalisedIndex = 0;
                curve.normalisedT[0] = 0;
                for (int p = 1; p < storedPointSize; p++)
                {
                    float t            = p / (float)(storedPointSize - 1);
                    float targetLength = t * calculatedTotalArcLength;
                    curve.targetSize[p] = targetLength;
                    int it = 1000;
                    while (targetLength > curve.storedArcLengthsFull[normalisedIndex])
                    {
                        normalisedIndex++;
                        it--;
                        if (it < 0)
                        {
                            curve.normalisedT[p] = 0;
                            break;
                        }
                    }

                    normalisedIndex = Mathf.Min(normalisedIndex, arcLengthResolution);//ensure we've not exceeded the length

                    int prevNormIndex = Mathf.Max((normalisedIndex - 1), 0);
                    int nextNormIndex = normalisedIndex;

                    float lengthBefore       = curve.storedArcLengthsFull[prevNormIndex];
                    float lengthAfter        = curve.storedArcLengthsFull[nextNormIndex];
                    float midPointPercentage = (targetLength - lengthBefore) / (lengthAfter - lengthBefore);
                    curve.midPointPerc[p]  = midPointPercentage;
                    curve.prevNormIndex[p] = prevNormIndex;
                    curve.nextNormIndex[p] = nextNormIndex;
                    float normalisedT = (normalisedIndex + midPointPercentage) / arcLengthResolution;//lerp between the values to get the exact normal T
                    curve.normalisedT[p] = normalisedT;
                }

                curve.sampledPoints              = new Vector3[storedPointSize];
                curve.sampledLeftBoundaryPoints  = new Vector3[storedPointSize];
                curve.sampledRightBoundaryPoints = new Vector3[storedPointSize];
                curve.sampledWidths              = new float[storedPointSize];
                curve.sampledCrowns              = new float[storedPointSize];
                curve.sampledTrackDirections     = new Vector3[storedPointSize];
                curve.sampledTrackUps            = new Vector3[storedPointSize];
                curve.sampledTrackCrosses        = new Vector3[storedPointSize];
                curve.sampledAngles              = new float[storedPointSize];
                for (int p = 0; p < storedPointSize; p++)
                {
                    float tN = curve.normalisedT[p];
                    float tH = SplineMaths.CalculateHermite(tN);
                    curve.sampledPoints[p]              = SplineMaths.CalculateBezierPoint(tN, pointA.position, pointA.forwardControlPoint, pointB.backwardControlPoint, pointB.position);
                    curve.sampledLeftBoundaryPoints[p]  = SplineMaths.CalculateBezierPoint(tN, pointA.leftTrackBoundary, pointA.leftForwardControlPoint, pointB.leftBackwardControlPoint, pointB.leftTrackBoundary);
                    curve.sampledRightBoundaryPoints[p] = SplineMaths.CalculateBezierPoint(tN, pointA.rightTrackBoundary, pointA.rightForwardControlPoint, pointB.rightBackwardControlPoint, pointB.rightTrackBoundary);
                    curve.sampledWidths[p]              = Mathf.LerpAngle(pointA.width, pointB.width, tH);
                    curve.sampledCrowns[p]              = Mathf.LerpAngle(pointA.crownAngle, pointB.crownAngle, tH);
                    curve.sampledTrackUps[p]            = Quaternion.Slerp(pointA.trackUpQ, pointB.trackUpQ, tH) * Vector3.forward;
                    curve.clipArrayLeft[p]              = true;
                    curve.clipArrayRight[p]             = true;
                }
            }
        }
        for (int i = 0; i < numberOfCurves; i++)
        {
            TrackBuildRPoint curve = _points[i];
            if (!curve.curveIsDirty)//only recalculate modified points
            {
                continue;
            }
            if (curve.arcLength > 0)
            {
                int lastCurveIndex         = (i > 0) ? i - 1 : (_looped) ? numberOfCurves - 1 : 0;
                int nextCurveIndex         = (i < numberOfCurves - 1) ? i + 1 : (_looped) ? 0 : numberOfCurves - 1;
                TrackBuildRPoint lastcurve = _points[lastCurveIndex];
                TrackBuildRPoint nextcurve = _points[nextCurveIndex];

                int storedPointSize = curve.storedPointSize;
                for (int p = 0; p < storedPointSize; p++)
                {
                    int pA = p - 1;
                    int pB = p;
                    int pC = p + 1;
                    if (pA < 0)
                    {
                        pA = 0;
                    }
                    if (pC >= storedPointSize)
                    {
                        pC = storedPointSize - 1;
                    }

                    Vector3 sampledPointA = curve.sampledPoints[pA];
                    Vector3 sampledPointB = curve.sampledPoints[pB];
                    Vector3 sampledPointC = curve.sampledPoints[pC];

                    if (p == 0 && lastcurve != null && lastcurve.sampledPoints.Length > 1)
                    {
                        sampledPointA = lastcurve.sampledPoints[lastcurve.storedPointSize - 2];//retrieve the penultimate point from the last curve
                    }
                    if (p == storedPointSize - 1 && nextcurve != null && nextcurve.sampledPoints.Length > 1)
                    {
                        sampledPointC = nextcurve.sampledPoints[1];//retrieve the second point from the next curve
                    }
                    Vector3 sampledTrackDirectionA = (sampledPointB - sampledPointA);
                    Vector3 sampledTrackDirectionB = (sampledPointC - sampledPointB);
                    Vector3 sampledTrackDirection  = (sampledTrackDirectionA + sampledTrackDirectionB).normalized;
                    curve.sampledTrackDirections[pB] = sampledTrackDirection;
                    curve.sampledTrackCrosses[pB]    = Vector3.Cross(curve.sampledTrackUps[pB], sampledTrackDirection);
                    curve.sampledAngles[pB]          = Vector3.Angle(sampledTrackDirectionA, sampledTrackDirectionB) * -Mathf.Sign(Vector3.Dot((sampledTrackDirectionB - sampledTrackDirectionA), curve.sampledTrackCrosses[pB]));

                    curve.clipArrayLeft[pB]  = true;
                    curve.clipArrayRight[pB] = true;
                }
            }
        }

        bool dirtyTextures = false;

        foreach (TrackBuildRTexture texture in _textures)
        {
            if (texture.isDirty)
            {
                dirtyTextures = true;//if nextNormIndex point was dirty, ensure it's rerendered
            }
            texture.isDirty = false;
        }

        foreach (TrackBuildRPoint point in _points)
        {
            if (point.curveIsDirty || dirtyTextures)
            {
                point.shouldReRender = true;//if nextNormIndex point was dirty, ensure it's rerendered
            }
        }
        //clean points
        foreach (TrackBuildRPoint point in _points)
        {
            point.isDirty = false;//reset all points - data is no longer considered dirty
        }
        //recalculate track length
        _trackLength = 0;
        foreach (TrackBuildRPoint curve in _points)
        {
            _trackLength += curve.arcLength;
        }
    }
Exemplo n.º 10
0
    public void RecalculateCurves()
    {
        if (_points.Count < 2)//there is no track with only one point :o)
        {
            return;
        }

        if (isDirty)
        {
            _tangentsGenerated = false;
            _lightmapGenerated = false;
            _optimised         = false;
        }

        //calculate approx bezier arc length per curve
        float roughArcLength = 0;

        for (int i = 0; i < realNumberOfPoints; i++)
        {
            TrackBuildRPoint pointA = GetPoint(i);
            TrackBuildRPoint pointB = GetPoint(i + 1);
            roughArcLength      += Vector3.Distance(pointA.position, pointA.forwardControlPoint);
            roughArcLength      += Vector3.Distance(pointA.forwardControlPoint, pointB.backwardControlPoint);
            roughArcLength      += Vector3.Distance(pointB.backwardControlPoint, pointB.position);
            _points[i].arcLength = roughArcLength;
            if (roughArcLength == 0)
            {
                DestroyImmediate(pointA);
                i--;
            }
        }

        for (int i = 0; i < realNumberOfPoints; i++)
        {
            TrackBuildRPoint pointA = GetPoint(i);
            TrackBuildRPoint pointB = GetPoint(i + 1);
            TrackBuildRPoint pointC = GetPoint(i - 1);
            pointA.nextPoint = pointB;
            pointA.lastPoint = pointC;
            pointA.pointName = "point " + i;
        }

        foreach (TrackBuildRPoint curve in _points)
        {
            if (!curve.curveIsDirty)//only recalculate modified points
            {
                continue;
            }

            if (curve.arcLength > 0)
            {
                TrackBuildRPoint pointA = curve;
                TrackBuildRPoint pointB = curve.nextPoint;

                //Build accurate arc length data into curve
                curve.center = Vector3.zero;
                Vector3 curveA     = pointA.position;
                Vector3 curveP     = pointA.forwardControlPoint;
                Vector3 curveQ     = pointB.backwardControlPoint;
                Vector3 curveB     = pointB.position;
                Vector3 curveALTB  = pointA.leftTrackBoundary;
                Vector3 curveARTB  = pointA.rightTrackBoundary;
                Vector3 curveBLTB  = pointB.leftTrackBoundary;
                Vector3 curveBRTB  = pointB.rightTrackBoundary;
                Vector3 curveALFCP = pointA.leftForwardControlPoint;
//                Vector3 curveALBCP = pointA.leftBackwardControlPoint;
                Vector3 curveARFCP = pointA.rightForwardControlPoint;
//                Vector3 curveARBCP = pointA.rightBackwardControlPoint;
//                Vector3 curveBLFCP = pointB.leftForwardControlPoint;
                Vector3 curveBLBCP = pointB.leftBackwardControlPoint;
//                Vector3 curveBRFCP = pointB.rightForwardControlPoint;
                Vector3 curveBRBCP = pointB.rightBackwardControlPoint;

                int   _dataSize = Mathf.Max(Mathf.RoundToInt(curve.arcLength / meshResolution), 1);
                float normilisePercentAmount = 1.0f / (_dataSize * 10);
                float normalisePercent       = 0;
                float targetMovement         = curve.arcLength / (_dataSize - 1);

                List <float> normValues = new List <float>();
                normValues.Add(0);

                float currentLength  = 0;
                float targetLength   = targetMovement;
                float totalArcLength = 0;

                Vector3 pA = curveA, pB;
                for (; normalisePercent < 1.0f - normilisePercentAmount; normalisePercent += normilisePercentAmount)
                {
                    pB = SplineMaths.CalculateBezierPoint(normalisePercent, curveA, curveP, curveQ, curveB);
                    float arcLength = Vector3.Distance(pA, pB);

                    if (currentLength + arcLength > targetLength)
                    {
                        float lerpPoint = (targetLength - currentLength) / arcLength;
                        float normValue = Mathf.Lerp(normalisePercent, normalisePercent + normilisePercentAmount, lerpPoint);
                        normValues.Add(normValue);
                        curve.center += pB;

                        currentLength = targetLength;
                        targetLength += targetMovement;
                    }

                    currentLength  += arcLength;
                    totalArcLength += arcLength;
                    pA              = pB;
                }
                normValues.Add(1);

                int storedPointSize = normValues.Count;
                curve.normalisedT     = normValues.ToArray();
                curve.arcLength       = totalArcLength;
                curve.center         /= (storedPointSize - 2);
                curve.storedPointSize = storedPointSize;
                curve.clipArrayLeft   = new bool[storedPointSize];
                curve.clipArrayRight  = new bool[storedPointSize];

                curve.sampledPoints              = new Vector3[storedPointSize];
                curve.sampledLeftBoundaryPoints  = new Vector3[storedPointSize];
                curve.sampledRightBoundaryPoints = new Vector3[storedPointSize];
                curve.sampledWidths              = new float[storedPointSize];
                curve.sampledCrowns              = new float[storedPointSize];
                curve.sampledTrackDirections     = new Vector3[storedPointSize];
                curve.sampledTrackUps            = new Vector3[storedPointSize];
                curve.sampledTrackCrosses        = new Vector3[storedPointSize];
                curve.sampledAngles              = new float[storedPointSize];
                for (int p = 0; p < storedPointSize; p++)
                {
                    float tN = curve.normalisedT[p];
                    float tH = SplineMaths.CalculateHermite(tN);
                    curve.sampledPoints[p]              = SplineMaths.CalculateBezierPoint(tN, curveA, curveP, curveQ, curveB);
                    curve.sampledLeftBoundaryPoints[p]  = SplineMaths.CalculateBezierPoint(tN, curveALTB, curveALFCP, curveBLBCP, curveBLTB);
                    curve.sampledRightBoundaryPoints[p] = SplineMaths.CalculateBezierPoint(tN, curveARTB, curveARFCP, curveBRBCP, curveBRTB);
                    curve.sampledWidths[p]              = Mathf.LerpAngle(pointA.width, pointB.width, tH);
                    curve.sampledCrowns[p]              = Mathf.LerpAngle(pointA.crownAngle, pointB.crownAngle, tH);
                    curve.sampledTrackUps[p]            = Quaternion.Slerp(pointA.trackUpQ, pointB.trackUpQ, tH) * Vector3.forward;

                    curve.clipArrayLeft[p]  = true;
                    curve.clipArrayRight[p] = true;
                }
            }
        }
        for (int i = 0; i < numberOfCurves; i++)
        {
            TrackBuildRPoint curve = _points[i];
            if (!curve.curveIsDirty)//only recalculate modified points
            {
                continue;
            }
            if (curve.arcLength > 0)
            {
                int lastCurveIndex         = (i > 0) ? i - 1 : (_looped) ? numberOfCurves - 1 : 0;
                int nextCurveIndex         = (i < numberOfCurves - 1) ? i + 1 : (_looped) ? 0 : numberOfCurves - 1;
                TrackBuildRPoint lastcurve = _points[lastCurveIndex];
                TrackBuildRPoint nextcurve = _points[nextCurveIndex];

                int storedPointSize = curve.storedPointSize;
                for (int p = 0; p < storedPointSize; p++)
                {
                    int pA = p - 1;
                    int pB = p;
                    int pC = p + 1;
                    if (pA < 0)
                    {
                        pA = 0;
                    }
                    if (pC >= storedPointSize)
                    {
                        pC = storedPointSize - 1;
                    }

                    Vector3 sampledPointA = curve.sampledPoints[pA];
                    Vector3 sampledPointB = curve.sampledPoints[pB];
                    Vector3 sampledPointC = curve.sampledPoints[pC];

                    if (p == 0 && lastcurve != null && lastcurve.sampledPoints.Length > 1)
                    {
                        sampledPointA = lastcurve.sampledPoints[lastcurve.storedPointSize - 2];//retrieve the penultimate point from the last curve
                    }
                    if (p == storedPointSize - 1 && nextcurve != null && nextcurve.sampledPoints.Length > 1)
                    {
                        sampledPointC = nextcurve.sampledPoints[1];//retrieve the second point from the next curve
                    }
                    Vector3 sampledTrackDirectionA = (sampledPointB - sampledPointA);
                    Vector3 sampledTrackDirectionB = (sampledPointC - sampledPointB);
                    Vector3 sampledTrackDirection  = (sampledTrackDirectionA + sampledTrackDirectionB).normalized;
                    curve.sampledTrackDirections[pB] = sampledTrackDirection;
                    curve.sampledTrackCrosses[pB]    = Vector3.Cross(curve.sampledTrackUps[pB], sampledTrackDirection);
                    curve.sampledAngles[pB]          = Vector3.Angle(sampledTrackDirectionA, sampledTrackDirectionB) * -Mathf.Sign(Vector3.Dot((sampledTrackDirectionB - sampledTrackDirectionA), curve.sampledTrackCrosses[pB]));

                    curve.clipArrayLeft[pB]  = true;
                    curve.clipArrayRight[pB] = true;
                }
            }
        }

        bool dirtyTextures = false;

        foreach (TrackBuildRTexture texture in _textures)
        {
            if (texture.isDirty)
            {
                dirtyTextures = true;//if nextNormIndex point was dirty, ensure it's rerendered
            }
            texture.isDirty = false;
        }

        foreach (TrackBuildRPoint point in _points)
        {
            if (point.curveIsDirty || dirtyTextures)
            {
                point.shouldReRender = true;//if nextNormIndex point was dirty, ensure it's rerendered
            }
        }
        //clean points
        foreach (TrackBuildRPoint point in _points)
        {
            point.isDirty = false;//reset all points - data is no longer considered dirty
        }
        //recalculate track length
        _trackLength = 0;
        foreach (TrackBuildRPoint curve in _points)
        {
            _trackLength += curve.arcLength;
        }
    }