- 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

### Welcome to Unity Answers

The best place to ask and answer questions about development with Unity.

To help users navigate the site we have posted a site navigation guide.

If you are a new user to Unity Answers, check out our FAQ for more information.

Make sure to check out our Knowledge Base for commonly asked Unity questions.

If you are a moderator, see our Moderator Guidelines page.

We are making improvements to UA, see the list of changes.

### Follow this Question

### Related Questions

My rotation keeps resetting 1 Answer

Unity thinks my Quaternion is a Float 2 Answers

Tank urret rotation - Need help. 1 Answer

[2D] Rotations become tighter the further left they are? 1 Answer

Head and body rotate threshold 1 Answer