Example #1
0
 /// <summary>
 /// Applies the SplineUser modifiers to the provided sample
 /// </summary>
 /// <param name="sample"></param>
 public void ModifySample(SplineSample sample)
 {
     offsetModifier.Apply(sample);
     _rotationModifier.Apply(sample);
     _colorModifier.Apply(sample);
     _sizeModifier.Apply(sample);
 }
        public override void Apply(SplineSample result)
        {
            if (keys.Count == 0)
            {
                return;
            }
            base.Apply(result);

            Quaternion offset = Quaternion.identity, look = result.rotation;

            for (int i = 0; i < keys.Count; i++)
            {
                if (keys[i].useLookTarget && keys[i].target != null)
                {
                    Quaternion lookDir = Quaternion.LookRotation(keys[i].target.position - result.position);
                    look = Quaternion.Slerp(look, lookDir, keys[i].Evaluate(result.percent));
                }
                else
                {
                    Quaternion euler = Quaternion.Euler(keys[i].rotation.x, keys[i].rotation.y, keys[i].rotation.z);
                    offset = Quaternion.Slerp(offset, offset * euler, keys[i].Evaluate(result.percent));
                }
            }
            Quaternion rotation       = look * offset;
            Vector3    invertedNormal = Quaternion.Inverse(result.rotation) * result.normal;

            result.direction = rotation * Vector3.forward;
            result.normal    = rotation * invertedNormal;
        }
Example #3
0
        /// <summary>
        /// Same as Spline.Evaluate but the results are transformed by the computer's transform
        /// </summary>
        /// <param name="from">Start position [0-1]</param>
        /// <param name="to">Target position [from-1]</param>
        /// <returns></returns>
        public void Evaluate(ref SplineSample[] results, double from = 0.0, double to = 1.0)
        {
            if (!hasSamples)
            {
                results = new SplineSample[0];
                return;
            }
            Spline.FormatFromTo(ref from, ref to);
            int    fromIndex, toIndex;
            double lerp;

            GetSamplingValues(from, out fromIndex, out lerp);
            GetSamplingValues(to, out toIndex, out lerp);
            if (lerp > 0.0 && toIndex < Count - 1)
            {
                toIndex++;
            }
            int clippedIterations = toIndex - fromIndex + 1;

            if (results == null)
            {
                results = new SplineSample[clippedIterations];
            }
            else if (results.Length != clippedIterations)
            {
                results = new SplineSample[clippedIterations];
            }
            results[0] = Evaluate(from);
            results[results.Length - 1] = Evaluate(to);
            for (int i = 1; i < results.Length - 1; i++)
            {
                results[i] = samples[i + fromIndex];
            }
        }
Example #4
0
        /// <summary>
        /// Evaluate the spline at the given time and return a SplineSample
        /// </summary>
        /// <param name="percent">Percent of evaluation [0-1]</param>
        public SplineSample Evaluate(double percent)
        {
            SplineSample result = new SplineSample();

            Evaluate(result, percent);
            return(result);
        }
Example #5
0
        /// <summary>
        /// Evaluate the spline at the position of a given point and return a SplineSample
        /// </summary>
        /// <param name="pointIndex">Point index</param>
        public SplineSample Evaluate(int pointIndex)
        {
            SplineSample result = new SplineSample();

            Evaluate(result, GetPointPercent(pointIndex));
            return(result);
        }
Example #6
0
        public static SplineSample Lerp(SplineSample a, SplineSample b, double t)
        {
            SplineSample result = new SplineSample();

            Lerp(a, b, t, result);
            return(result);
        }
Example #7
0
        public SplineSample Evaluate(double percent)
        {
            SplineSample result = new SplineSample();

            Evaluate(UnclipPercent(percent), result);
            result.percent = DMath.Clamp01(percent);
            return(result);
        }
Example #8
0
 public void CopyFrom(SplineSample input)
 {
     position  = input.position;
     direction = input.direction;
     normal    = input.normal;
     color     = input.color;
     size      = input.size;
     percent   = input.percent;
 }
Example #9
0
 public SplineSample(SplineSample input)
 {
     position  = input.position;
     normal    = input.normal;
     direction = input.direction;
     color     = input.color;
     size      = input.size;
     percent   = input.percent;
 }
Example #10
0
 public void CopyFrom(SplineSample input)
 {
     position = input.position;
     forward  = input.forward;
     up       = input.up;
     color    = input.color;
     size     = input.size;
     percent  = input.percent;
 }
Example #11
0
 public static void Lerp(SplineSample a, SplineSample b, float t, SplineSample target)
 {
     target.position = DMath.LerpVector3(a.position, b.position, t);
     target.forward  = Vector3.Slerp(a.forward, b.forward, t);
     target.up       = Vector3.Slerp(a.up, b.up, t);
     target.color    = Color.Lerp(a.color, b.color, t);
     target.size     = Mathf.Lerp(a.size, b.size, t);
     target.percent  = DMath.Lerp(a.percent, b.percent, t);
 }
Example #12
0
 public SplineSample(SplineSample input)
 {
     position = input.position;
     up       = input.up;
     forward  = input.forward;
     color    = input.color;
     size     = input.size;
     percent  = input.percent;
 }
Example #13
0
 public virtual void Project(Vector3 position, SplineSample result, double from = 0.0, double to = 1.0)
 {
     if (_spline == null)
     {
         return;
     }
     sampleCollection.Project(position, _spline.pointCount, result, UnclipPercent(from), UnclipPercent(to));
     ClipPercent(ref result.percent);
 }
Example #14
0
 public static void Lerp(SplineSample a, SplineSample b, float t, SplineSample target)
 {
     target.position  = DMath.LerpVector3(a.position, b.position, t);
     target.direction = Vector3.Slerp(a.direction, b.direction, t);
     target.normal    = Vector3.Slerp(a.normal, b.normal, t);
     target.color     = Color.Lerp(a.color, b.color, t);
     target.size      = Mathf.Lerp(a.size, b.size, t);
     target.percent   = DMath.Lerp(a.percent, b.percent, t);
 }
Example #15
0
 public override void Apply(SplineSample result)
 {
     if (keys.Count == 0)
     {
         return;
     }
     for (int i = 0; i < keys.Count; i++)
     {
         result.size += keys[i].Evaluate(result.percent) * keys[i].scale.magnitude;
     }
 }
Example #16
0
        public float GetSpeed(SplineSample sample)
        {
            float speed = 0f;

            for (int i = 0; i < keys.Count; i++)
            {
                float lerp = keys[i].Evaluate(sample.percent);
                speed += keys[i].speed * lerp;
            }
            return(speed);
        }
Example #17
0
        public override void Apply(SplineSample result)
        {
            if (keys.Count == 0)
            {
                return;
            }
            base.Apply(result);
            Vector2 offset = Evaluate(result.percent);

            result.position += result.right * offset.x + result.up * offset.y;
        }
Example #18
0
 public override void Apply(SplineSample result)
 {
     if (keys.Count == 0)
     {
         return;
     }
     base.Apply(result);
     for (int i = 0; i < keys.Count; i++)
     {
         result.color = keys[i].Blend(result.color, keys[i].Evaluate(result.percent));
     }
 }
Example #19
0
        public Vector2 GetScale(SplineSample sample)
        {
            Vector2 scale = Vector2.one;

            for (int i = 0; i < keys.Count; i++)
            {
                float   lerp            = keys[i].Evaluate(sample.percent);
                Vector2 scaleMultiplier = Vector2.Lerp(Vector2.one, keys[i].scale, lerp);
                scale.x *= scaleMultiplier.x;
                scale.y *= scaleMultiplier.y;
            }
            return(scale);
        }
Example #20
0
        void Draw(SplineSample[] points, ref float[,] drawLayer, ref float[,] alphaLayer)
        {
            List <SplineSample> selectedPoints = new List <SplineSample>();
            Point last = new Point();

            //Filter out points that are too close to each other
            for (int i = 0; i < points.Length; i++)
            {
                Point current = ToHeightmapCoords(points[i].position + points[i].up * offset);
                if (i == 0 || i == points.Length - 1)
                {
                    last = new Point(current.x, current.y);
                    selectedPoints.Add(points[i]);
                }
                else if (Vector2.Distance(new Vector2(current.x, current.y), new Vector2(last.x, last.y)) >= 1.5f)
                {
                    selectedPoints.Add(points[i]);
                    last = new Point(current.x, current.y);
                }
            }
            if (selectedPoints.Count <= 1)
            {
                return;
            }
            TerrainPaintPoint[] paintPoints = new TerrainPaintPoint[selectedPoints.Count];
            for (int i = 0; i < selectedPoints.Count; i++)
            {
                ConvertToPaintPoint(selectedPoints[i], ref paintPoints[i]);
            }
            //Paint the points
            for (int i = 0; i < paintPoints.Length - 1; i++)
            {
                promptSave = true;
                PaintSegment(paintPoints[i], paintPoints[i + 1], ref drawLayer, ref alphaLayer);
            }

            SplineSample exResult = selectedPoints[0];

            exResult.position += exResult.position - selectedPoints[1].position;
            TerrainPaintPoint exPoint = null;

            ConvertToPaintPoint(exResult, ref exPoint);
            PaintSegment(paintPoints[0], exPoint, ref drawLayer, ref alphaLayer, false, false);

            exResult           = selectedPoints[selectedPoints.Count - 1];
            exResult.position += exResult.position - selectedPoints[selectedPoints.Count - 2].position;
            ConvertToPaintPoint(exResult, ref exPoint);
            PaintSegment(paintPoints[paintPoints.Length - 1], exPoint, ref drawLayer, ref alphaLayer, false, false);
            //Extrapolate the ending and the begining
        }
Example #21
0
        /// <summary>
        /// Evaluates the spline segment and writes uniformly spaced results to the array
        /// </summary>
        /// <param name="from">Start position [0-1]</param>
        /// <param name="to">Target position [from-1]</param>
        /// <returns></returns>
        public void EvaluateUniform(ref SplineSample[] samples, ref double[] originalSamplePercents, double from = 0.0, double to = 1.0)
        {
            if (points.Length == 0)
            {
                samples = new SplineSample[0];
                return;
            }
            from = DMath.Clamp01(from);
            to   = DMath.Clamp(to, from, 1.0);
            double fromValue         = from * (iterations - 1);
            double toValue           = to * (iterations - 1);
            int    clippedIterations = DMath.CeilInt(toValue) - DMath.FloorInt(fromValue) + 1;

            if (samples == null || samples.Length != clippedIterations)
            {
                samples = new SplineSample[clippedIterations];
            }
            if (originalSamplePercents == null || originalSamplePercents.Length != clippedIterations)
            {
                originalSamplePercents = new double[clippedIterations];
            }
            for (int i = 0; i < samples.Length; i++)
            {
                if (samples[i] == null)
                {
                    samples[i] = new SplineSample();
                }
            }
            float lengthStep = CalculateLength(from, to) / (iterations - 1);

            Evaluate(samples[0], from);
            samples[0].percent = originalSamplePercents[0] = from;
            double lastPercent = from;
            float  moved       = 0f;

            for (int i = 1; i < samples.Length - 1; i++)
            {
                Evaluate(samples[i], Travel(lastPercent, lengthStep, out moved, Direction.Forward));
                lastPercent = samples[i].percent;
                originalSamplePercents[i] = lastPercent;
                samples[i].percent        = DMath.Lerp(from, to, (double)i / (samples.Length - 1));
            }
            Evaluate(samples[samples.Length - 1], to);
            samples[samples.Length - 1].percent = originalSamplePercents[originalSamplePercents.Length - 1] = to;
        }
Example #22
0
        void PaintHeightMap(Terrain terrain, SplineComputer computer, ref float[,] drawLayer, ref float[,] alphaLayer)
        {
            if (heights == null)
            {
                GetBase();
            }
            SplineSample[] results = new SplineSample[computer.iterations];
            computer.Evaluate(ref results, clipFrom, clipTo);

            /*
             * for(int i = 0; i < results.Length; i++)
             * {
             *  float percent = (float)i/(results.Length-1);
             *  results[i] = computer.Evaluate(percent);
             * }
             */
            Draw(results, ref drawLayer, ref alphaLayer);
        }
Example #23
0
        /// <summary>
        /// Same as Spline.Evaluate but the result is transformed by the computer's transform
        /// </summary>
        /// <param name="result"></param>
        /// <param name="percent"></param>
        public void Evaluate(double percent, SplineSample result)
        {
            if (!hasSamples)
            {
                result = new SplineSample();
                return;
            }
            int    index;
            double lerp;

            GetSamplingValues(percent, out index, out lerp);
            if (lerp > 0.0)
            {
                SplineSample.Lerp(samples[index], samples[index + 1], lerp, result);
            }
            else
            {
                result.CopyFrom(samples[index]);
            }
        }
Example #24
0
        TerrainPaintPoint ConvertToPaintPoint(SplineSample result, ref TerrainPaintPoint paintPoint)
        {
            paintPoint = new TerrainPaintPoint();
            Vector3 right      = -Vector3.Cross(result.forward, result.up).normalized *size * 0.5f * result.size;
            Vector3 leftPoint  = result.position - right + result.up * offset;
            Vector3 rightPoint = result.position + right + result.up * offset;

            paintPoint.center        = ToHeightmapCoords(result.position + result.up * offset);
            paintPoint.leftPoint     = ToHeightmapCoords(leftPoint);
            paintPoint.rightPoint    = ToHeightmapCoords(rightPoint);
            paintPoint.leftHeight    = ToHeightmapValue(leftPoint.y);
            paintPoint.rightHeight   = ToHeightmapValue(rightPoint.y);
            paintPoint.floatDiameter = Vector2.Distance(new Vector2(leftPoint.x, leftPoint.z), new Vector2(rightPoint.x, rightPoint.z));
            if (paintPoint.leftHeight > maxDrawHeight)
            {
                maxDrawHeight = paintPoint.leftHeight;
            }
            if (paintPoint.rightHeight > maxDrawHeight)
            {
                maxDrawHeight = paintPoint.rightHeight;
            }
            return(paintPoint);
        }
Example #25
0
        /// <summary>
        /// Evaluates the spline segment and writes the results to the array
        /// </summary>
        /// <param name="from">Start position [0-1]</param>
        /// <param name="to">Target position [from-1]</param>
        /// <returns></returns>
        public void Evaluate(ref SplineSample[] samples, double from = 0.0, double to = 1.0)
        {
            if (points.Length == 0)
            {
                samples = new SplineSample[0];
                return;
            }
            from = DMath.Clamp01(from);
            to   = DMath.Clamp(to, from, 1.0);
            double fromValue         = from * (iterations - 1);
            double toValue           = to * (iterations - 1);
            int    clippedIterations = DMath.CeilInt(toValue) - DMath.FloorInt(fromValue) + 1;

            if (samples == null)
            {
                samples = new SplineSample[clippedIterations];
            }
            else if (samples.Length != clippedIterations)
            {
                samples = new SplineSample[clippedIterations];
            }
            double percent = from;
            double ms      = moveStep;
            int    index   = 0;

            while (true)
            {
                samples[index] = Evaluate(percent);
                index++;
                if (index >= samples.Length)
                {
                    break;
                }
                percent = DMath.Move(percent, to, ms);
            }
        }
Example #26
0
        /// <summary>
        /// Evaluate the splien at the given time and write the result to the "result" object
        /// </summary>
        /// <param name="result">The result output</param>
        /// <param name="percent">Percent of evaluation [0-1]</param>
        public void Evaluate(SplineSample result, double percent)
        {
            if (points.Length == 0)
            {
                result = new SplineSample();
                return;
            }
            percent = DMath.Clamp01(percent);
            if (closed && points.Length <= 2)
            {
                closed = false;
            }
            if (points.Length == 1)
            {
                result.position = points[0].position;
                result.up       = points[0].normal;
                result.forward  = Vector3.forward;
                result.size     = points[0].size;
                result.color    = points[0].color;
                result.percent  = percent;
                return;
            }

            double  doubleIndex = (points.Length - 1) * percent;
            int     pointIndex  = Mathf.Clamp(DMath.FloorInt(doubleIndex), 0, points.Length - 2);
            double  getPercent  = doubleIndex - pointIndex;
            Vector3 point       = EvaluatePosition(percent);

            result.position = point;
            result.percent  = percent;
            if (pointIndex <= points.Length - 2)
            {
                SplinePoint nextPoint = points[pointIndex + 1];
                if (pointIndex == points.Length - 2 && closed)
                {
                    nextPoint = points[0];
                }
                float valueInterpolation = (float)getPercent;
                if (customValueInterpolation != null)
                {
                    if (customValueInterpolation.length > 0)
                    {
                        valueInterpolation = customValueInterpolation.Evaluate(valueInterpolation);
                    }
                }
                float normalInterpolation = (float)getPercent;
                if (customNormalInterpolation != null)
                {
                    if (customNormalInterpolation.length > 0)
                    {
                        normalInterpolation = customNormalInterpolation.Evaluate(normalInterpolation);
                    }
                }
                result.size  = Mathf.Lerp(points[pointIndex].size, nextPoint.size, valueInterpolation);
                result.color = Color.Lerp(points[pointIndex].color, nextPoint.color, valueInterpolation);
                result.up    = Vector3.Slerp(points[pointIndex].normal, nextPoint.normal, normalInterpolation);
            }
            else
            {
                if (closed)
                {
                    result.size  = points[0].size;
                    result.color = points[0].color;
                    result.up    = points[0].normal;
                }
                else
                {
                    result.size  = points[pointIndex].size;
                    result.color = points[pointIndex].color;
                    result.up    = points[pointIndex].normal;
                }
            }
            if (type == Type.BSpline)
            {
                double step = 1.0 / (iterations - 1);
                if (percent <= 1.0 - step && percent >= step)
                {
                    result.forward = EvaluatePosition(percent + step) - EvaluatePosition(percent - step);
                }
                else
                {
                    Vector3 back = Vector3.zero, front = Vector3.zero;
                    if (closed)
                    {
                        if (percent < step)
                        {
                            back = EvaluatePosition(1.0 - (step - percent));
                        }
                        else
                        {
                            back = EvaluatePosition(percent - step);
                        }
                        if (percent > 1.0 - step)
                        {
                            front = EvaluatePosition(step - (1.0 - percent));
                        }
                        else
                        {
                            front = EvaluatePosition(percent + step);
                        }
                        result.forward = front - back;
                    }
                    else
                    {
                        back           = result.position - EvaluatePosition(percent - step);
                        front          = EvaluatePosition(percent + step) - result.position;
                        result.forward = Vector3.Slerp(front, back, back.magnitude / front.magnitude);
                    }
                }
            }
            else
            {
                EvaluateTangent(ref result.forward, percent);
            }
            result.forward.Normalize();
        }
Example #27
0
 /// <summary>
 /// Evaluate the splien at the given point and write the result to the "result" object
 /// </summary>
 /// <param name="result">The result output</param>
 /// <param name="pointIndex">Point index</param>
 public void Evaluate(SplineSample result, int pointIndex)
 {
     Evaluate(result, GetPointPercent(pointIndex));
 }
Example #28
0
        /// <summary>
        /// Same as Spline.Project but the point is transformed by the computer's transform.
        /// </summary>
        /// <param name="position">Point in space</param>
        /// <param name="subdivide">Subdivisions default: 4</param>
        /// <param name="from">Sample from [0-1] default: 0f</param>
        /// <param name="to">Sample to [0-1] default: 1f</param>
        /// <param name="mode">Mode to use the method in. Cached uses the cached samples while Calculate is more accurate but heavier</param>
        /// <param name="subdivisions">Subdivisions for the Calculate mode. Don't assign if not using Calculated mode.</param>
        /// <returns></returns>
        public void Project(Vector3 position, int controlPointCount, SplineSample result, double from = 0.0, double to = 1.0)
        {
            if (!hasSamples)
            {
                return;
            }
            if (Count == 1)
            {
                if (result == null)
                {
                    result = new SplineSample(samples[0]);
                }
                else
                {
                    result.CopyFrom(samples[0]);
                }
                return;
            }
            Spline.FormatFromTo(ref from, ref to);
            //First make a very rough sample of the from-to region
            int steps = (controlPointCount - 1) * 6; //Sampling six points per segment is enough to find the closest point range
            int step  = Count / steps;

            if (step < 1)
            {
                step = 1;
            }
            float  minDist   = (position - samples[0].position).sqrMagnitude;
            int    fromIndex = 0;
            int    toIndex   = Count - 1;
            double lerp;

            if (from != 0.0)
            {
                GetSamplingValues(from, out fromIndex, out lerp);
            }
            if (to != 1.0)
            {
                GetSamplingValues(to, out toIndex, out lerp);
                if (lerp > 0.0 && toIndex < Count - 1)
                {
                    toIndex++;
                }
            }
            int checkFrom = fromIndex;
            int checkTo   = toIndex;

            //Find the closest point range which will be checked in detail later
            for (int i = fromIndex; i <= toIndex; i += step)
            {
                if (i > toIndex)
                {
                    i = toIndex;
                }
                float dist = (position - samples[i].position).sqrMagnitude;
                if (dist < minDist)
                {
                    minDist   = dist;
                    checkFrom = Mathf.Max(i - step, 0);
                    checkTo   = Mathf.Min(i + step, Count - 1);
                }
                if (i == toIndex)
                {
                    break;
                }
            }
            minDist = (position - samples[checkFrom].position).sqrMagnitude;

            int index = checkFrom;

            //Find the closest result within the range
            for (int i = checkFrom + 1; i <= checkTo; i++)
            {
                float dist = (position - samples[i].position).sqrMagnitude;
                if (dist < minDist)
                {
                    minDist = dist;
                    index   = i;
                }
            }
            //Project the point on the line between the two closest samples
            int backIndex = index - 1;

            if (backIndex < 0)
            {
                backIndex = 0;
            }
            int frontIndex = index + 1;

            if (frontIndex > Count - 1)
            {
                frontIndex = Count - 1;
            }
            Vector3 back             = LinearAlgebraUtility.ProjectOnLine(samples[backIndex].position, samples[index].position, position);
            Vector3 front            = LinearAlgebraUtility.ProjectOnLine(samples[index].position, samples[frontIndex].position, position);
            float   backLength       = (samples[index].position - samples[backIndex].position).magnitude;
            float   frontLength      = (samples[index].position - samples[frontIndex].position).magnitude;
            float   backProjectDist  = (back - samples[backIndex].position).magnitude;
            float   frontProjectDist = (front - samples[frontIndex].position).magnitude;

            if (backIndex < index && index < frontIndex)
            {
                if ((position - back).sqrMagnitude < (position - front).sqrMagnitude)
                {
                    SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result);
                    if (sampleMode == SplineComputer.SampleMode.Uniform)
                    {
                        result.percent = DMath.Lerp(GetSamplePercent(backIndex), GetSamplePercent(index), backProjectDist / backLength);
                    }
                }
                else
                {
                    SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result);
                    if (sampleMode == SplineComputer.SampleMode.Uniform)
                    {
                        result.percent = DMath.Lerp(GetSamplePercent(frontIndex), GetSamplePercent(index), frontProjectDist / frontLength);
                    }
                }
            }
            else if (backIndex < index)
            {
                SplineSample.Lerp(samples[backIndex], samples[index], backProjectDist / backLength, result);
                if (sampleMode == SplineComputer.SampleMode.Uniform)
                {
                    result.percent = DMath.Lerp(GetSamplePercent(backIndex), GetSamplePercent(index), backProjectDist / backLength);
                }
            }
            else
            {
                SplineSample.Lerp(samples[frontIndex], samples[index], frontProjectDist / frontLength, result);
                if (sampleMode == SplineComputer.SampleMode.Uniform)
                {
                    result.percent = DMath.Lerp(GetSamplePercent(frontIndex), GetSamplePercent(index), frontProjectDist / frontLength);
                }
            }

            if (Count > 1 && from == 0.0 && to == 1.0 && result.percent < samples[1].percent) //Handle looped splines
            {
                Vector3 projected = LinearAlgebraUtility.ProjectOnLine(samples[Count - 1].position, samples[Count - 2].position, position);
                if ((position - projected).sqrMagnitude < (position - result.position).sqrMagnitude)
                {
                    double l = LinearAlgebraUtility.InverseLerp(samples[Count - 1].position, samples[Count - 2].position, projected);
                    SplineSample.Lerp(samples[Count - 1], samples[Count - 2], l, result);
                    if (sampleMode == SplineComputer.SampleMode.Uniform)
                    {
                        result.percent = DMath.Lerp(GetSamplePercent(Count - 1), GetSamplePercent(Count - 2), l);
                    }
                }
            }
        }
Example #29
0
 public void Lerp(SplineSample b, float t)
 {
     Lerp(this, b, t, this);
 }
Example #30
0
 public void Lerp(SplineSample b, double t)
 {
     Lerp(this, b, t, this);
 }