private void OnDrawGizmos() { //3d MyVector3 posA = transPointA.position.ToMyVector3(); MyVector3 posB = transPointB.position.ToMyVector3(); MyVector3 handleA = transHandleA.position.ToMyVector3(); MyVector3 handleB = transHandleB.position.ToMyVector3(); InterpolationTransform myTransA = new InterpolationTransform(posA, new MyQuaternion(transPointA.rotation)); InterpolationTransform myTransB = new InterpolationTransform(posB, new MyQuaternion(transPointB.rotation)); //Interpolate between coordinates in 3d //BezierLinearTest(posA, posB); //BezierQuadraticTest(posA, posB, handleA); //BezierQuadraticTest_EqualSteps(posA, posB, handleA); //BezierCubicTest(posA, posB, handleA, handleB); //BezierCubicTest_EqualSteps(posA, posB, handleA, handleB); BezierCubicTest_Transform(myTransA, myTransB, transPointA.localScale.z, transPointB.localScale.z); //CatmullRomTest(posA, posB, handleA, handleB); //Interpolation between values //OtherInterpolations(posA, posB); }
//Display a MeshProfile at a certain InterpolationTransform public static void DisplayMeshProfile(MeshProfile profile, InterpolationTransform transform, float profileScale) { //Display the points //Convert all vertices from 2d to 3d in global space //List<MyVector3> positions_3d = profile.vertices.Select(s => // testTrans.LocalToWorld(new MyVector3(s.point.x, s.point.y, 0f) * profileScale) //).ToList(); List <Vector3> positions_3d = new List <Vector3>(); foreach (Vertex v in profile.vertices) { MyVector2 localPos2d = v.point; MyVector3 localPos = new MyVector3(localPos2d.x, localPos2d.y, 0f); MyVector3 pos = transform.LocalToWorld_Pos(localPos * profileScale); positions_3d.Add(pos.ToVector3()); } DisplayPoints(positions_3d); //Display how the points are connected with lines Gizmos.color = Color.white; for (int i = 0; i < profile.lineIndices.Length; i++) { Vector3 pos_1 = positions_3d[profile.lineIndices[i].x]; Vector3 pos_2 = positions_3d[profile.lineIndices[i].y]; Gizmos.DrawLine(pos_1, pos_2); } //Display normals at each point Gizmos.color = Color.blue; //Convert all normals from 2d to 3d in global space List <Vector3> normals_3d = new List <Vector3>(); foreach (Vertex v in profile.vertices) { MyVector2 normal2d = v.normal; MyVector3 normal = new MyVector3(normal2d.x, normal2d.y, 0f); MyVector3 worldNormal = transform.LocalToWorld_Dir(normal); normals_3d.Add(worldNormal.ToVector3()); } DisplayDirections(positions_3d, normals_3d, 0.5f, Color.magenta); }
private void CatmullRomTest(MyVector3 posA, MyVector3 posB, MyVector3 handleA, MyVector3 handleB) { CatmullRom catmullRomCurve = new CatmullRom(posA, posB, handleA, handleB); //Store the interpolated values so we later can display them List <Vector3> positions = new List <Vector3>(); List <Vector3> tangents = new List <Vector3>(); List <float> tValues = new List <float>(); //Loop between 0 and 1 in steps, where 1 step is minimum //So if steps is 5 then the line will be cut in 5 sections int steps = 5; float stepSize = 1f / (float)steps; float t = 0f; //+1 becuase wa also have to include the first point for (int i = 0; i < steps + 1; i++) { //Debug.Log(t); MyVector3 interpolatedPos = CatmullRom.GetPosition(posA, posB, handleA, handleB, t); positions.Add(interpolatedPos.ToVector3()); MyVector3 interpolatedTangent = CatmullRom.GetTangent(posA, posB, handleA, handleB, t); tangents.Add(interpolatedTangent.ToVector3()); tValues.Add(t); t += stepSize; } List <InterpolationTransform> transforms = InterpolationTransform.GetTransforms_RotationMinimisingFrame(catmullRomCurve, tValues, MyVector3.Up); //Display //DisplayInterpolation.DisplayCurve(positions, useRandomColor: true); DisplayInterpolation.DisplayCurve(positions, Color.black); //The actual curve for comparison DisplayInterpolation.DisplayCurve(catmullRomCurve, Color.gray); //The control points //The start and end values and the handle points DisplayInterpolation.DisplayHandle(handleA.ToVector3(), posA.ToVector3()); DisplayInterpolation.DisplayHandle(handleB.ToVector3(), posB.ToVector3()); //Other stuff //DisplayInterpolation.DisplayDirections(positions, tangents, 1f, Color.blue); DisplayInterpolation.DisplayOrientations(transforms, 1f); }
/// <summary> /// Interpolates Positionof the given transform to the provided Position /// </summary> /// <param name="transform">The Transform to manipulate</param> /// <param name="scale">Scale to interpolate to</param> /// <param name="duration">The amount of time in seconds the interpolation should take</param> /// <param name="finished">Delegate function that is called when the interpolation is finished</param> /// <param name="progressMapping">A delegate function to map a value between 0 and 1 used as the progress for lerping that returns a new value between 0 and 1</param> /// <returns></returns> public static Coroutine Interpolate(this Transform transform, Vector3 scale, float duration, Action finished, Func <float, float> progressMapping = null) { InterpolationTransform target = new InterpolationTransform(); target.scale = scale; target.valuesToUse = 4; // 00000100 return(CoroutineHost.StartTrackedCoroutine(InterpolateTransform(transform, target, duration, Space.Self, progressMapping, finished), transform, INTERPOLATION_COROUTINE_TAG)); }
/// <summary> /// Interpolates Rotation of the given transform to the provided Rotation /// </summary> /// <param name="transform">The Transform to manipulate</param> /// <param name="rotation">Rotation to interpolate to</param> /// <param name="duration">The amount of time in seconds the interpolation should take</param> /// <param name="space">Operate in world or local space</param> /// <param name="finished">Delegate function that is called when the interpolation is finished</param> /// <param name="progressMapping">A delegate function to map a value between 0 and 1 used as the progress for lerping that returns a new value between 0 and 1</param> /// <returns></returns> public static Coroutine Interpolate(this Transform transform, Quaternion rotation, float duration, Space space, Action finished, Func <float, float> progressMapping = null) { InterpolationTransform target = new InterpolationTransform(); target.rotation = rotation; target.valuesToUse = 2; // 00000010 return(CoroutineHost.StartTrackedCoroutine(InterpolateTransform(transform, target, duration, space, progressMapping, finished), transform, INTERPOLATION_COROUTINE_TAG)); }
/// <summary> /// Interpolates Positionof the given transform to the provided Position /// </summary> /// <param name="transform">The Transform to manipulate</param> /// <param name="position">Position to interpolate to</param> /// <param name="duration">The amount of time in seconds the interpolation should take</param> /// <param name="space">Operate in world or local space</param> /// <param name="progressMapping">A delegate function to map a value between 0 and 1 used as the progress for lerping that returns a new value between 0 and 1</param> /// <returns></returns> public static Coroutine Interpolate(this Transform transform, Vector3 position, float duration, Space space, Func <float, float> progressMapping = null) { InterpolationTransform target = new InterpolationTransform(); target.position = position; target.valuesToUse = 1; // 00000001 return(CoroutineHost.StartTrackedCoroutine(InterpolateTransform(transform, target, duration, space, progressMapping, null), transform, INTERPOLATION_COROUTINE_TAG)); }
private void BezierCubic(MyVector3 posA, MyVector3 posB, MyVector3 handleA, MyVector3 handleB) { //Store the interpolated values so we later can display them List <Vector3> interpolatedValues = new List <Vector3>(); //Loop between 0 and 1 in steps, where 1 step is minimum //So if steps is 5 then the line will be cut in 5 sections int steps = 20; float stepSize = 1f / (float)steps; float t = 0f; //+1 becuase wa also have to include the first point for (int i = 0; i < steps + 1; i++) { //Debug.Log(t); MyVector3 interpolatedPos = _Interpolation.BezierCubic(posA, posB, handleA, handleB, t); interpolatedValues.Add(interpolatedPos.ToVector3()); t += stepSize; } //Display the curve DisplayInterpolatedValues(interpolatedValues, useRandomColor: true); //Display the start and end values and the handle points DisplayHandle(handleA.ToVector3(), posA.ToVector3()); DisplayHandle(handleB.ToVector3(), posB.ToVector3()); //Display other related data //Get the orientation of the point at t BezierCubic bezierCubic = new BezierCubic(posA, posB, handleA, handleB); InterpolationTransform trans = bezierCubic.GetTransform(tSliderValue); //Multiply the orientation with a direction vector to rotate the direction Vector3 forwardDir = trans.Forward.ToVector3(); //- right vector because in this test files we are looking from above //so -right looks like up even though in the actual coordinate system it is -right Vector3 upDir = -trans.Right.ToVector3(); Vector3 slidePos = _Interpolation.BezierCubic(posA, posB, handleA, handleB, tSliderValue).ToVector3(); TestAlgorithmsHelpMethods.DisplayArrow(slidePos, slidePos + forwardDir * 2f, 0.2f, Color.blue); TestAlgorithmsHelpMethods.DisplayArrow(slidePos, slidePos + upDir * 2f, 0.2f, Color.blue); Gizmos.color = Color.red; Gizmos.DrawWireSphere(slidePos, 0.15f); }
/// <summary> /// Interpolates Position, Rotation and Scale of the given transform to the provided Transform /// </summary> /// <param name="transform">The Transform to manipulate</param> /// <param name="targetTransform">The Transform to interpolate to</param> /// <param name="duration">The amount of time in seconds the interpolation should take</param> /// <param name="space">Operate in world or local space</param> /// <param name="finished">Delegate function that is called when the interpolation is finished</param> /// <param name="progressMapping">A delegate function to map a value between 0 and 1 used as the progress for lerping that returns a new value between 0 and 1</param> /// <returns></returns> public static Coroutine Interpolate(this Transform transform, Transform targetTransform, float duration, Space space, Action finished, Func <float, float> progressMapping = null) { InterpolationTransform target = new InterpolationTransform(); if (space == Space.Self) { target.position = targetTransform.localPosition; target.rotation = targetTransform.localRotation; } else { target.position = targetTransform.position; target.rotation = targetTransform.rotation; } target.scale = targetTransform.localScale; target.valuesToUse = 7; // 00000111 return(CoroutineHost.StartTrackedCoroutine(InterpolateTransform(transform, target, duration, space, progressMapping, finished), transform, INTERPOLATION_COROUTINE_TAG)); }
/// <summary> /// Interpolates Position, Rotation and Scale of the given transform /// </summary> /// <param name="trans">The transform to manipulate</param> /// <param name="targetTrans">Container for target position, rotation and scale, containing info which of these values to use</param> /// <param name="duration">The amount of time in seconds the interpolation should take</param> /// <param name="space">Operate in world or local space</param> /// <param name="progressMapping">A delegate function to map a value between 0 and 1 used as the progress for lerping that returns a new value between 0 and 1</param> /// <param name="finished">Delegate function that is called when the interpolation is finished</param> /// <returns></returns> private static IEnumerator InterpolateTransform(Transform trans, InterpolationTransform targetTrans, float duration, Space space, Func <float, float> progressMapping, Action finished) { //Create neede variables Vector3 startPos = space == Space.Self ? trans.localPosition : trans.position; Quaternion startRot = space == Space.Self ? trans.localRotation : trans.rotation; ; Vector3 startScale = trans.localScale; ; // fins out which values we should interpolate bool usePos = targetTrans.valuesToUse.GetBitValue(0); bool useRot = targetTrans.valuesToUse.GetBitValue(1); bool useScale = targetTrans.valuesToUse.GetBitValue(2); float progress = 0; while (progress < 1) { // map progress float mappedProgress = progressMapping?.Invoke(progress) ?? progress; // interpolate position if needed if (usePos) { Vector3 lerpedPos = Vector3.LerpUnclamped(startPos, targetTrans.position, mappedProgress); if (space == Space.Self) { trans.localPosition = lerpedPos; } else { trans.position = lerpedPos; } } // interpolate rotation if needed if (useRot) { Quaternion lerpedRot = Quaternion.LerpUnclamped(startRot, targetTrans.rotation, mappedProgress); if (space == Space.Self) { trans.localRotation = lerpedRot; } else { trans.rotation = lerpedRot; } } // interpolate scale if needed if (useScale) { Vector3 lerpedScale = Vector3.LerpUnclamped(startScale, targetTrans.scale, mappedProgress); trans.localScale = lerpedScale; } yield return(null); progress += Time.deltaTime / duration; } // set final values if (usePos) { if (space == Space.Self) { trans.localPosition = targetTrans.position; } else { trans.position = targetTrans.position; } } if (useRot) { if (space == Space.Self) { trans.localRotation = targetTrans.rotation; } else { trans.rotation = targetTrans.rotation; } } if (useScale) { trans.localScale = targetTrans.scale; } // call delegate if (finished != null) { finished(); } }
//Uses transforms as start and end position, the length of the handles is determines by the z scale of each transform private void BezierCubicTest_Transform(InterpolationTransform transA, InterpolationTransform transB, float scaleA, float scaleB) { MyVector3 posA = transA.position; MyVector3 posB = transB.position; //The forward vector should move along from a to b MyVector3 handleA = posA + transA.Forward * scaleA; MyVector3 handleB = posB + -transB.Forward * scaleB; BezierCubic curve = new BezierCubic(posA, posB, handleA, handleB); //The interpolated values List <Vector3> positions = new List <Vector3>(); List <float> tValues = new List <float>(); //Loop between 0 and 1 in steps, where 1 step is minimum //So if steps is 5 then the line will be cut in 5 sections int steps = 30; float t_stepSize = 1f / (float)steps; float t = 0f; //+1 becuase wa also have to include the first point for (int i = 0; i < steps + 1; i++) { //Debug.Log(t); MyVector3 interpolatedPos = BezierCubic.GetPosition(posA, posB, handleA, handleB, t); positions.Add(interpolatedPos.ToVector3()); tValues.Add(t); t += t_stepSize; } //Different orientation algorithms List <InterpolationTransform> transforms = InterpolationTransform.GetTransforms_InterpolateBetweenUpVectors(curve, tValues, transA.Up, transB.Up); //List<InterpolationTransform> transforms = InterpolationTransform.GetTransforms_UpRef(curve, tValues, transA.Up); //List<InterpolationTransform> transforms = InterpolationTransform.GetTransforms_FrenetNormal(curve, tValues); //List<InterpolationTransform> transforms = InterpolationTransform.GetTransforms_RotationMinimisingFrame(curve, tValues, transA.Up); //The curve DisplayInterpolation.DisplayCurve(positions, useRandomColor: true); //The start and end values and the handle points DisplayInterpolation.DisplayHandle(handleA.ToVector3(), posA.ToVector3()); DisplayInterpolation.DisplayHandle(handleB.ToVector3(), posB.ToVector3()); //Display transform DisplayInterpolation.DisplayOrientations(transforms, 1f); //Mesh Mesh extrudedMesh = ExtrudeMeshAlongCurve.GenerateMesh(transforms, meshProfile, 0.25f); if (extrudedMesh != null && displayMeshFilter != null) { displayMeshFilter.sharedMesh = extrudedMesh; } }
private void BezierCubicTest_EqualSteps(MyVector3 posA, MyVector3 posB, MyVector3 handleA, MyVector3 handleB) { //Create a curve which is the data structure used in the following calculations BezierCubic bezierCubic = new BezierCubic(posA, posB, handleA, handleB); //Step 1. Calculate the length of the entire curve //This is needed so we know for how long we should walk each step float lengthNaive = InterpolationHelpMethods.GetLength_Naive(bezierCubic, steps: 20, tEnd: 1f); float lengthExact = InterpolationHelpMethods.GetLength_SimpsonsRule(bezierCubic, tStart: 0f, tEnd: 1f); //Debug.Log("Naive length: " + lengthNaive + " Exact length: " + lengthExact); //Step 2. Convert the t's to be percentage along the curve //Save the accurate t at each position on the curve List <float> accurateTs = new List <float>(); //The number of sections we want to divide the curve into int steps = 20; //Important not to confuse this with the step size we use to iterate t //This step size is distance in m float curveLength = lengthNaive; float curveLength_stepSize = curveLength / (float)steps; float t_stepSize = 1f / (float)steps; float t = 0f; float distanceTravelled = 0f; for (int i = 0; i < steps + 1; i++) { //MyVector3 inaccuratePos = bezierCubic.GetPosition(t); //Calculate the t needed to get to this distance along the curve //Method 1 //float accurateT = InterpolationHelpMethods.Find_t_FromDistance_Iterative(bezierCubic, distanceTravelled, length); //Method 2 float accurateT = InterpolationHelpMethods.Find_t_FromDistance_Lookup(bezierCubic, distanceTravelled, accumulatedDistances: null); accurateTs.Add(accurateT); //Debug.Log(accurateT); //Test that the derivative calculations are working //float dEst = InterpolationHelpMethods.EstimateDerivative(bezierCubic, t); //float dAct = bezierCubic.ExactDerivative(t); //Debug.Log("Estimated derivative: " + dEst + " Actual derivative: " + dAct); //Debug.Log("Distance " + distanceTravelled); //Move on to next iteration distanceTravelled += curveLength_stepSize; t += t_stepSize; } //Step3. Use the new t's to get information from the curve //The interpolated positions List <Vector3> actualPositions = new List <Vector3>(); //Save the tangent at each position on the curve List <Vector3> tangents = new List <Vector3>(); //Save the orientation, which includes the tangent //List<InterpolationTransform> orientations = new List<InterpolationTransform>(); for (int i = 0; i < accurateTs.Count; i++) { float accurateT = accurateTs[i]; //Position on the curve MyVector3 actualPos = bezierCubic.GetPosition(accurateT); actualPositions.Add(actualPos.ToVector3()); //Tangent at each position MyVector3 tangentDir = BezierCubic.GetTangent(posA, posB, handleA, handleB, accurateT); tangents.Add(tangentDir.ToVector3()); //Orientation, which includes both position and tangent //InterpolationTransform orientation = InterpolationTransform.GetTransform(bezierCubic, accurateT); //orientations.Add(orientation); } //The orientation at each t position MyVector3 startUpRef = MyVector3.Up; List <InterpolationTransform> orientationsFrames = InterpolationTransform.GetTransforms_RotationMinimisingFrame(bezierCubic, accurateTs, startUpRef); //Display stuff //The curve which is split into steps //DisplayInterpolation.DisplayCurve(actualPositions, useRandomColor: true); DisplayInterpolation.DisplayCurve(actualPositions, Color.gray); //The start and end values and the handle points DisplayInterpolation.DisplayHandle(handleA.ToVector3(), posA.ToVector3()); DisplayInterpolation.DisplayHandle(handleB.ToVector3(), posB.ToVector3()); //The actual Bezier cubic for reference DisplayInterpolation.DisplayCurve(bezierCubic, Color.black); //Handles.DrawBezier(posA.ToVector3(), posB.ToVector3(), handleA.ToVector3(), handleB.ToVector3(), Color.black, EditorGUIUtility.whiteTexture, 1f); //The tangents //DisplayInterpolation.DisplayDirections(actualPositions, tangents, 1f, Color.red); //The orientation //DisplayInterpolation.DisplayOrientations(orientations, 1f); DisplayInterpolation.DisplayOrientations(orientationsFrames, 1f); //Extrude mesh along the curve //InterpolationTransform testTrans = orientationsFrames[1]; //MyVector3 pos = testTrans.LocalToWorld(MyVector3.Up * 2f); //MyVector3 pos = testTrans.LocalToWorld(MyVector3.Right * 2f); //Gizmos.DrawSphere(pos.ToVector3(), 0.1f); //DisplayInterpolation.DisplayExtrudedMesh(orientationsFrames, meshProfile); }
private void BezierQuadraticTest_EqualSteps(MyVector3 posA, MyVector3 posB, MyVector3 handle) { //Create a curve which is the data structure used in the following calculations BezierQuadratic bezierQuadratic = new BezierQuadratic(posA, posB, handle); //Step 1. Calculate the length of the entire curve //This is needed to so we know how long we should walk each step float lengthNaive = InterpolationHelpMethods.GetLength_Naive(bezierQuadratic, steps: 20, tEnd: 1f); float lengthExact = InterpolationHelpMethods.GetLength_SimpsonsRule(bezierQuadratic, tStart: 0f, tEnd: 1f); //Debug.Log("Naive length: " + lengthNaive + " Exact length: " + lengthExact); //Step 2. Convert the t's to be percentage along the curve //Save the accurate t at each position on the curve List <float> accurateTs = new List <float>(); int steps = 5; //Important not to confuse this with the step size we use to iterate t //This step size is distance in m float length = lengthNaive; float lengthStepSize = length / (float)steps; float stepSize = 1f / (float)steps; float t = 0f; float distanceTravelled = 0f; for (int i = 0; i < steps + 1; i++) { //MyVector3 inaccuratePos = bezierCubic.GetInterpolatedValue(t); //Calculate t to get to this distance //Method 1 //float accurateT = InterpolationHelpMethods.Find_t_FromDistance_Iterative(bezierQuadratic, distanceTravelled, length); //Method 2 float accurateT = InterpolationHelpMethods.Find_t_FromDistance_Lookup(bezierQuadratic, distanceTravelled, accumulatedDistances: null); accurateTs.Add(accurateT); //Test that the derivative calculations are working //float dEst = InterpolationHelpMethods.EstimateDerivative(bezierQuadratic, t); //float dAct = bezierQuadratic.GetDerivative(t); //Debug.Log("Estimated derivative: " + dEst + " Actual derivative: " + dAct); //Debug.Log("Distance " + distanceTravelled); //Move on to next iteration distanceTravelled += lengthStepSize; t += stepSize; } //Get the data we want from the curve //Store the interpolated values so we later can display them List <Vector3> actualPositions = new List <Vector3>(); // List <Vector3> tangents = new List <Vector3>(); //Orientation, which includes the tangent and position List <InterpolationTransform> orientations = new List <InterpolationTransform>(); for (int i = 0; i < accurateTs.Count; i++) { float accurateT = accurateTs[i]; MyVector3 actualPos = bezierQuadratic.GetPosition(accurateT); actualPositions.Add(actualPos.ToVector3()); MyVector3 tangent = bezierQuadratic.GetTangent(accurateT); tangents.Add(tangent.ToVector3()); //Orientation, which includes both position and tangent InterpolationTransform orientation = InterpolationTransform.GetTransform_UpRef(bezierQuadratic, accurateT, MyVector3.Up); orientations.Add(orientation); } //Display //Unity doesnt have a built-in method to display an accurate Qudratic bezier, so we have to create our own //DisplayInterpolation.DisplayBezierQuadratic(bezierQuadratic, Color.black); DisplayInterpolation.DisplayCurve(bezierQuadratic, Color.black); //DisplayInterpolation.DisplayCurve(actualPositions, useRandomColor: true); DisplayInterpolation.DisplayCurve(actualPositions, Color.gray); //Display the start and end values and the handle points DisplayInterpolation.DisplayHandle(handle.ToVector3(), posA.ToVector3()); DisplayInterpolation.DisplayHandle(handle.ToVector3(), posB.ToVector3()); //Stuff on the curve //DisplayInterpolation.DisplayDirections(actualPositions, tangents, 1f, Color.red); DisplayInterpolation.DisplayOrientations(orientations, 1f); }