- Home /
Fix ugly extrusions (Quaternions)?
I'm using the extrusion routine in the Unity3D procedural examples. I have a path of points along which I am extruding a "tube" based on a circle profile.
I get these ugly "turnovers" (pictures below) that I reckon are a result of this section of the extrusion code:
if (sections.length < 2) return;
var worldToLocal = transform.worldToLocalMatrix;
var finalSections = new Matrix4x4[sections.length];
var previousRotation : Quaternion;
for (var i=0;i<sections.length;i++)
{
if (autoCalculateOrientation)
{
if (i == 0)
{
var direction = sections[0].point - sections[1].point;
var rotation = Quaternion.LookRotation(direction, Vector3.up);
previousRotation = rotation;
finalSections[i] = worldToLocal * Matrix4x4.TRS(newPosition, rotation, Vector3.one);
}
else if (i != sections.length - 1)
{
direction = sections[i].point - sections[i+1].point;
rotation = Quaternion.LookRotation(direction, Vector3.up);
if (Quaternion.Angle (previousRotation, rotation) > 20)
rotation = Quaternion.Slerp(previousRotation, rotation, 0.5);
previousRotation = rotation;
finalSections[i] = worldToLocal * Matrix4x4.TRS(sections[i].point, rotation, Vector3.one);
}
else finalSections[i] = finalSections[i-1];
}
else
{
if (i == 0)
{
finalSections[i] = Matrix4x4.identity;
}
else finalSections[i] = worldToLocal * sections[i].matrix;
}
}
I'm wondering if there's a way to prevent these turnovers. Possibly reverse the rotation specified by the Quaternion? I've tried changing the parameter of the quaternion - vector.right, vector.up, vector.forward, etc. That doesn't correct anything.
Thanks for any suggestions or corrections!
Answer by Jesse Anders · Mar 14, 2011 at 10:53 AM
The 'parallel transport frame' should solve your problem. (For details, search online for 'parallel transport frame', or search the forum archives over at gamedev.net, as it's been discussed quite a few times there.)
Ah. That certainly looks like the place to find a solution.
If you have solved the problem.Cound you give me somg advices or a example.Thanks a lot!!!
Answer by morbidcamel · Dec 24, 2013 at 03:19 AM
Hi All,
I took the liberty of translating the PTF logic from Cinder (Github) as I have a similar problem. Let me know if this helps:
public static class ParallelTransportFrame
{
// Parallel Transport Frames
//
// These methods compute a set of reference frames, defined by their
// transformation matrix, along a curve. It is designed so that the
// array of points and the array of matrices used to fetch these routines
// don't need to be ordered as the curve.
//
// A typical usage would be :
//
// m[0] = Imath::firstFrame( p[0], p[1], p[2] );
// for( int i = 1; i < n - 1; i++ )
// {
// m[i] = Imath::nextFrame( m[i-1], p[i-1], p[i], t[i-1], t[i] );
// }
// m[n-1] = Imath::lastFrame( m[n-2], p[n-2], p[n-1] );
//
// See Graphics Gems I for the underlying algorithm.
// These are also called Parallel Transport Frames
// see Game Programming Gems 2, Section 2.5
public static Matrix4x4 FirstFrame(
Vector3 firstPoint,
Vector3 secondPoint,
Vector3 thirdPoint )
{
Vector3 t = ( secondPoint - firstPoint ).normalized;
Vector3 n = Vector3.Cross(t, thirdPoint - firstPoint ).normalized;
if( n == Vector3.zero )
{
int i = Mathf.Abs( t[0] ) < Mathf.Abs( t[1] ) ? 0 : 1;
if( Mathf.Abs( t[2] ) < Mathf.Abs( t[i] ) ) i = 2;
Vector3 v = Vector3.zero;
v[i] = 1.0f;
n = Vector3.Cross( t, v ).normalized;
}
Vector3 b = Vector3.Cross(t, n);
Matrix4x4 M = Matrix4x4.zero;
M[0] = b[0]; M[1] = b[1]; M[2] = b[2]; M[3] = 0.0f;
M[4] = n[0]; M[5] = n[1]; M[6] = n[2]; M[7] = 0.0f;
M[8] = t[0]; M[9] = t[1]; M[10] = t[2]; M[11] = 0.0f;
M[12] = firstPoint[0]; M[13] = firstPoint[1]; M[14] = firstPoint[2]; M[15] = 1.0f;
return M;
}
public static Matrix4x4 CreateRotation(this Vector3 axis, float angle)
{
Vector3 unit = axis.normalized;
float sine = Mathf.Sin( angle );
float cosine = Mathf.Cos( angle );
Matrix4x4 ret = Matrix4x4.zero;
ret[ 0] = unit.x * unit.x * (1 - cosine) + cosine;
ret[ 1] = unit.x * unit.y * (1 - cosine) + unit.z * sine;
ret[ 2] = unit.x * unit.z * (1 - cosine) - unit.y * sine;
ret[ 3] = 0;
ret[ 4] = unit.x * unit.y * (1 - cosine) - unit.z * sine;
ret[ 5] = unit.y * unit.y * (1 - cosine) + cosine;
ret[ 6] = unit.y * unit.z * (1 - cosine) + unit.x * sine;
ret[ 7] = 0;
ret[ 8] = unit.x * unit.z * (1 - cosine) + unit.y * sine;
ret[ 9] = unit.y * unit.z * (1 - cosine) - unit.x * sine;
ret[10] = unit.z * unit.z * (1 - cosine) + cosine;
ret[11] = 0;
ret[12] = 0;
ret[13] = 0;
ret[14] = 0;
ret[15] = 1;
return ret;
}
public static Matrix4x4 CreateTranslation( this Vector3 v, float w = 1f )
{
Matrix4x4 ret = Matrix4x4.zero;
ret[12] = v.x;
ret[13] = v.y;
ret[14] = v.z;
ret[15] = w;
return ret;
}
public static Matrix4x4 NextFrame(
this Matrix4x4 prevMatrix,
Vector3 prevPoint,
Vector3 curPoint,
Vector3 prevTangent,
Vector3 curTangent)
{
Vector3 a = Vector3.zero; // Rotation axis.
float r = 0; // Rotation angle.
if( ( prevTangent != Vector3.zero ) && ( curTangent != Vector3.zero ) )
{
prevTangent.Normalize();
curTangent.Normalize();
float dot = Vector3.Dot ( prevTangent, curTangent );
if( dot > 1.0f ) dot = 1.0f;
else if( dot < -1.0f ) dot = -1.0f;
r = Mathf.Acos(dot);
a = Vector3.Cross( prevTangent, curTangent );
}
if ( ( a != Vector3.zero ) && ( r != 0.0f ) )
{
Matrix4x4 R = CreateRotation(a, r); //Matrix44<T>::createRotation( a, r );
Matrix4x4 Tj = CreateTranslation( curPoint );
Matrix4x4 Ti = CreateTranslation( -prevPoint );
// Original order of operation:
//return prevMatrix * Ti * R * Tj;
//
// Cinder's order of operation
return Tj*R*Ti*prevMatrix;
}
else {
Matrix4x4 Tr = CreateTranslation( curPoint - prevPoint );
// Original order of operation:
//return prevMatrix*Tr;
//
// Cinder's order of operation
return Tr*prevMatrix;
}
}
public static Matrix4x4 LastFrame(
Matrix4x4 prevMatrix,
Vector3 prevPoint,
Vector3 lastPoint )
{
// Original order of operation:
//return prevMatrix * Matrix44<T>::createTranslation( lastPoint - prevPoint );
//
// Cinder's order of operation
return CreateTranslation( lastPoint - prevPoint )*prevMatrix;
}
}
Answer by drudiverse · Jul 25, 2014 at 10:47 AM
instead of matrix, i simply rotated the extruded plane using quaternion lookat relative the the previous version of itself. this prevents any next version of the extruded object from being too much rotated compared to the previous... i found the complete post here:
http://answers.unity3d.com/questions/662944/lookrotation-flipping-180-degrees-through-y-axis.html
Your answer
Follow this Question
Related Questions
Directional booster 1 Answer
Mimic other object's rotation on one axis (with offset) 0 Answers
90 Degree stopping rotation on y-axis issue 0 Answers
Quaternions incorrect? 2 Answers