Sign in to follow this  

How To: Using up vector for a FlyPath

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, I'm coding a FlyPath (at least that's what I call it), you know the type where the camera follows a predetermined track using a set of control points. Each control point consists of an eye position, a look-at position and an up vector. To move the camera/eye I use 4 of the control points as input to form a Catmull-Rom Spline and simply interpolate. I want to use the up vector the "roll" the camera/eye. However, how should I interpolate the up vectors as the camera/eye follows the spline?
struct control_point
{
   vec3 position, look_at, up;
};

...

void FlyPath::Animate()
{
   lerp = lerp + MY_CTIME;

   if (lerp > 1.0f)
   {
      lerp = 0.0f;

      if (++index >= count)
      {
         index = 0;
      }
   }

   vec3 p0 = step[(index - 1 + count) % count].position;
   vec3 p1 = step[(index    ) % count].position;
   vec3 p2 = step[(index + 1) % count].position;
   vec3 p3 = step[(index + 2) % count].position;

   current.position = 0.5f * ((2.0f * p1) + 
                              (-p0 + p2) * lerp +
                              (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * pow(lerp, 2.0f) +
                              (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * pow(lerp, 3.0f));

   p0 = step[(index - 1 + count) % count].look_at;
   p1 = step[(index    ) % count].look_at;
   p2 = step[(index + 1) % count].look_at;
   p3 = step[(index + 2) % count].look_at;

   current.look_at = 0.5f * ((2.0f * p1) + 
                             (-p0 + p2) * lerp +
                             (2.0f * p0 - 5.0f * p1 + 4.0f * p2 - p3) * pow(lerp, 2.0f) +
                             (-p0 + 3.0f * p1 - 3.0f * p2 + p3) * pow(lerp, 3.0f));

// current.up = ?????????????????????????????????????????????????????????

   return;
}

void FlyPath::Render()
{
   gluLookAt(current.position[x], current.position[y], current.position[z],
             current.look_at[x], current.look_at[y], current.look_at[z],
             current.up[x], current.up[y], current.up[z]);

   return;
}



Thanks in advance.

Share this post


Link to post
Share on other sites
That would depend on how worried you are about having a constant roll speed. If you don't need a constant roll speed you can interpolate the up vector like everything else and just normalize it before you use it. If that's not good enough you might try looking into quaternions. They're supposed to be good for interpolation.

Share this post


Link to post
Share on other sites
You can interpolate UP vector just like you´re doing with everything else...

But, I don´t think you´re going to get things smooth...

Using quaternion is the way to do it:

Do it interpolating position using splines but interpolate camera rotation using quaternions.

Heres something you can do:

using UP, AT and EYE you can have camera axis at each point:

-zAxis = at - eye
xAxis = -zAxis ^ upAxis
yAxis = xAxis ^ -zAxis

(^ = vectorial product )

Camera rotation matrix is:
m[16] =
[ xAxis.x, xAxis.y, xAxis.z, 0 ]
[ yAxis.x, yAxis.y, yAxis.z, 0 ]
[ zAxis.x, zAxis.y, zAxis.z, 0 ]
[ 0, 0, 0, 1 ]

( In the code below m.m[i] show up, its only because I have
Struct Matrix
{ m[16]; }; )


Then you can build a quaternion from this matrix:

** STRUCT QUATERNION ***

typedef struct
{

real w;

real x;

real y;

real z;
}
Quat;

** QUATERNION FROM MATRIX **

Quat q;
real tr = m.m[0] + m.m[5] + m.m[10]; /* Matrix trace */
real s;

if ( tr > 0 )
{
s = (real) sqrt(tr + 1);

q.w = 0.5f * s;
s = 0.5f / s;
q.x = (m.m[6] - m.m[9]) * s;
q.y = (m.m[8] - m.m[2]) * s;
q.z = (m.m[1] - m.m[4]) * s;
} else
{
/* Find out the bigger element from diagonal */
real max = m.m[0];
max = (m.m[5] > max ? m.m[5] : max);
max = (m.m[10] > max ? m.m[10] : max);

if ( m.m[0] == max )
{
/* Column 0 */
s = (real) sqrt(m.m[0] - m.m[5] - m.m[10] + 1);

q.x = 0.5f * s;
if ( s != 0 ) s = 0.5f / s;

q.w = (m.m[6] - m.m[9] ) * s;
q.y = (m.m[1] + m.m[4] ) * s;
q.z = (m.m[2] + m.m[8] ) * s;
} else if ( m.m[5] == max )
{
/* Column 1 */
s = (real) sqrt(m.m[5] - m.m[0] - m.m[10] + 1);

q.y = 0.5f * s;
if ( s != 0 ) s = 0.5f / s;

q.w = (m.m[8] - m.m[2]) * s;
q.x = (m.m[1] + m.m[4]) * s;
q.z = (m.m[6] + m.m[9]) * s;
} else
{
/* Column 2: m[10] == max */
s = (real) sqrt(m.m[10] - m.m[0] - m.m[5] + 1);

q.z = 0.5f * s;
if ( s != 0 ) s = 0.5f / s;

q.w = (m.m[1] - m.m[4]) * s;
q.x = (m.m[2] + m.m[8]) * s;
q.y = (m.m[6] + m.m[9]) * s;
}
}
return q;

Ok. Now, with that in hands, you can easily interpolate quaternions by using linear interpolation:

q(t) = aq1 + bq2

b = 1-a

t is the linear parameter

When you have the interpolated quaternion, its easy to get the rotation matrix back, you only need to know that a quaternion is actually:
q = (cos(Theta/2), sin(Theta/2)ê)

ê is the unitary rotation axis.

With that you can build the rotation matrix again..
you transitions between cameras rotations will be very smooth..

[Edited by - hugeride on May 18, 2007 1:51:18 PM]

Share this post


Link to post
Share on other sites
To get a matrix again from a quaternion just find out how to built a matrix from an angle and an axis (you gonna get angle and axis from final quaternion )

[Edited by - hugeride on May 18, 2007 1:57:36 PM]

Share this post


Link to post
Share on other sites

This topic is 3863 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this