public static List <InterpolationTransform> GetTransforms_UpRef(_Curve curve, List <float> tValues, Vector3 upRef) { List <InterpolationTransform> orientations = new List <InterpolationTransform>(); foreach (float t in tValues) { InterpolationTransform transform = InterpolationTransform.GetTransform_UpRef(curve, t, upRef); orientations.Add(transform); } return(orientations); }
public static List <InterpolationTransform> GetTransforms_FrenetNormal(_Curve curve, List <float> tValues) { List <InterpolationTransform> transforms = new List <InterpolationTransform>(); foreach (float t in tValues) { InterpolationTransform transform = InterpolationTransform.GetTransform_FrenetNormal(curve, t); transforms.Add(transform); } return(transforms); }
public static List <InterpolationTransform> GetTransforms_InterpolateBetweenUpVectors( _Curve curve, List <float> tValues, Vector3 upRefStart, Vector3 upRefEnd) { List <InterpolationTransform> transforms = new List <InterpolationTransform>(); foreach (float t in tValues) { InterpolationTransform transform = InterpolationTransform.GetTransform_InterpolateBetweenUpVectors(curve, t, upRefStart, upRefEnd); transforms.Add(transform); } return(transforms); }
public static InterpolationTransform GetTransform_FrenetNormal(_Curve curve, float t) { //Position on the curve at point t Vector3 pos = curve.GetPosition(t); //Forward direction (tangent) on the curve at point t Vector3 forwardDir = curve.GetTangent(t); Vector3 secondDerivativeVec = curve.GetSecondDerivativeVec(t); MyQuaternion orientation = InterpolationTransform.GetOrientation_FrenetNormal(forwardDir, secondDerivativeVec); InterpolationTransform trans = new InterpolationTransform(pos, orientation); return(trans); }
// // Alternative 1.5. Similar to Alternative 1, but we know the up vector at both the start and end position // public static InterpolationTransform GetTransform_InterpolateBetweenUpVectors( _Curve curve, float t, Vector3 upRefStart, Vector3 upRefEnd) { //Position on the curve at point t Vector3 pos = curve.GetPosition(t); //Forward direction (tangent) on the curve at point t Vector3 forwardDir = curve.GetTangent(t); //Interpolate between the start and end up vector to get an up vector at a t position Vector3 interpolatedUpDir = Vector3.Normalize(BezierLinear.GetPosition(upRefStart, upRefEnd, t)); MyQuaternion orientation = InterpolationTransform.GetOrientation_UpRef(forwardDir, interpolatedUpDir); InterpolationTransform trans = new InterpolationTransform(pos, orientation); return(trans); }
public static InterpolationTransform GetTransform_UpRef(_Curve curve, float t, Vector3 upRef) { //Position on the curve at point t Vector3 pos = curve.GetPosition(t); //Forward direction (tangent) on the curve at point t Vector3 forwardDir = curve.GetTangent(t); //A simple way to get the other directions is to use LookRotation with just forward dir as parameter //Then the up direction will always be the world up direction, and it calculates the right direction //This idea is not working for all possible curve orientations //MyQuaternion orientation = new MyQuaternion(forwardDir); //Your own reference up vector MyQuaternion orientation = InterpolationTransform.GetOrientation_UpRef(forwardDir, upRef); InterpolationTransform trans = new InterpolationTransform(pos, orientation); return(trans); }
// // Get a Transform (includes position and orientation) at point t // public InterpolationTransform GetTransform(float t) { //Same as when we calculate t MyVector3 interpolation_1_2 = _Interpolation.BezierQuadratic(posA, handleB, handleA, t); MyVector3 interpolation_2_3 = _Interpolation.BezierQuadratic(posA, posB, handleB, t); MyVector3 finalInterpolation = _Interpolation.BezierLinear(interpolation_1_2, interpolation_2_3, t); //This direction is always tangent to the curve MyVector3 forwardDir = MyVector3.Normalize(interpolation_2_3 - interpolation_1_2); //A simple way to get the other directions is to use LookRotation with just forward dir as parameter //Then the up direction will always be the world up direction, and it calculates the right direction Quaternion orientation = Quaternion.LookRotation(forwardDir.ToVector3()); InterpolationTransform trans = new InterpolationTransform(finalInterpolation, orientation); return(trans); }
//Not defined for a single point, you always need a previous transform //public static InterpolationTransform InterpolationTransform GetTransform_RotationMinimisingFrame() //{ //} public static List <InterpolationTransform> GetTransforms_RotationMinimisingFrame(_Curve curve, List <float> tValues, Vector3 upRef) { List <InterpolationTransform> transforms = new List <InterpolationTransform>(); for (int i = 0; i < tValues.Count; i++) { float t = tValues[i]; //Position on the curve at point t Vector3 position = curve.GetPosition(t); //Forward direction (tangent) on the curve at point t Vector3 tangent = curve.GetTangent(t); //At first pos we dont have a previous transform if (i == 0) { //Just use one of the other algorithms available to generate a transform at a single position MyQuaternion orientation = InterpolationTransform.GetOrientation_UpRef(tangent, upRef); InterpolationTransform transform = new InterpolationTransform(position, orientation); transforms.Add(transform); } else { //To calculate the orientation for this point, we need data from the previous point on the curve InterpolationTransform previousTransform = transforms[i - 1]; MyQuaternion orientation = InterpolationTransform.GetOrientation_RotationFrame(position, tangent, previousTransform); InterpolationTransform transform = new InterpolationTransform(position, orientation); transforms.Add(transform); } } return(transforms); }
//Generate a mesh public static Mesh GenerateMesh(List <InterpolationTransform> transforms, MeshProfile profile, float profileScale) { if (profile == null) { Debug.Log("You need to assign a mesh profile"); return(null); } if (transforms == null || transforms.Count <= 1) { Debug.Log("You need more transforms"); return(null); } //Test that the profile is correct //InterpolationTransform testTrans = transforms[1]; //DisplayMeshProfile(profile, testTrans, profileScale); //Vertices List <UnityEngine.Vector3> vertices = new List <UnityEngine.Vector3>(); //Normals List <UnityEngine.Vector3> normals = new List <UnityEngine.Vector3>(); for (int step = 0; step < transforms.Count; step++) { InterpolationTransform thisTransform = transforms[step]; for (int i = 0; i < profile.vertices.Length; i++) { MyVector2 localPos2d = profile.vertices[i].point; Vector3 localPos = new Vector3(localPos2d.x, localPos2d.y, 0f); Vector3 pos = thisTransform.LocalToWorld_Pos(localPos * profileScale); vertices.Add(pos.ToVector3()); //Normals MyVector2 localNormal2d = profile.vertices[i].normal; Vector3 localNormal = new Vector3(localNormal2d.x, localNormal2d.y, 0f); Vector3 normal = thisTransform.LocalToWorld_Dir(localNormal); normals.Add(normal.ToVector3()); } } //Triangles List <int> triangles = new List <int>(); //We connect the first transform with the next transform, ignoring the last transform because it doesnt have a next for (int step = 0; step < transforms.Count - 1; step++) { //The index where this profile starts in the list of all vertices in the entire mesh int profileIndexThis = step * profile.vertices.Length; //The index where the next profile starts int profileIndexNext = (step + 1) * profile.vertices.Length; //Each line has 2 points for (int line = 0; line < profile.lineIndices.Length; line++) { int lineIndexA = profile.lineIndices[line].x; int lineIndexB = profile.lineIndices[line].y; //Now we can identify the vertex we need in the list of all vertices in the entire mesh //The current profile int thisA = profileIndexThis + lineIndexA; int thisB = profileIndexThis + lineIndexB; //The next profile int nextA = profileIndexNext + lineIndexA; int nextB = profileIndexNext + lineIndexB; //Build two triangles triangles.Add(thisA); triangles.Add(nextA); triangles.Add(nextB); triangles.Add(thisB); triangles.Add(thisA); triangles.Add(nextB); } } Mesh mesh = new Mesh(); mesh.vertices = vertices.ToArray(); mesh.triangles = triangles.ToArray(); mesh.normals = normals.ToArray(); //mesh.RecalculateNormals(); return(mesh); }
// // Alternative 3. Rotation Minimising Frame (also known as "Parallel Transport Frame" or "Bishop Frame") // //Gets its stability by incrementally rotating a coordinate system (= frame) as it is translate along the curve //Has to be computed for the entire curve because we need the previous frame (previousTransform) belonging to a point before this point //Is initalized by using "Fixed Up" or "Frenet Normal" public static MyQuaternion GetOrientation_RotationFrame(Vector3 position, Vector3 tangent, InterpolationTransform previousTransform) { /* * //This version is from https://pomax.github.io/bezierinfo/#pointvectors3d * //Reflect the known frame onto the next point, by treating the plane through the curve at the point exactly between the next and previous points as a "mirror" * MyVector3 v1 = position - previousTransform.position; * * float c1 = MyVector3.Dot(v1, v1); * * MyVector3 riL = previousTransform.Right - v1 * (2f / c1) * MyVector3.Dot(v1, previousTransform.Right); * * MyVector3 tiL = previousTransform.Forward - v1 * (2f / c1) * MyVector3.Dot(v1, previousTransform.Forward); * * //This gives the next point a tangent vector that's essentially pointing in the opposite direction of what it should be, and a normal that's slightly off-kilter * //reflect the vectors of our "mirrored frame" a second time, but this time using the plane through the "next point" itself as "mirror". * MyVector3 v2 = tangent - tiL; * * float c2 = MyVector3.Dot(v2, v2); * * //Now we can calculate the normal and right vector belonging to this orientation * MyVector3 right = riL - v2 * (2f / c2) * MyVector3.Dot(v2, riL); * * //The source has right x tangent, but then every second normal is flipped * MyVector3 normal = MyVector3.Cross(tangent, right); * * MyQuaternion orientation = new MyQuaternion(tangent, normal); */ //This version is from Game Programming Gems 2: The Parallel Transport Frame //They generate the same result and this one is easier to understand //The two tangents Vector3 T1 = previousTransform.Forward; Vector3 T2 = tangent; //You move T1 to the new position, so A is a vector going from the new position Vector3 A = Vector3.Cross(T1, T2); //This is the angle between T1 and T2 float alpha = Mathf.Acos(Vector3.Dot(T1, T2) / (Vector3.Magnitude(T1) * Vector3.Magnitude(T2))); //Now rotate the previous frame around axis A with angle alpha MyQuaternion F1 = previousTransform.orientation; MyQuaternion F2 = MyQuaternion.RotateQuaternion(F1, alpha * Mathf.Rad2Deg, A); MyQuaternion orientation = F2; return(orientation); }