How To: Using up vector for a FlyPath

Started by
3 comments, last by hugeride 16 years, 11 months ago
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.
Advertisement
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.
OK, so how should I proceed if I wanted a constant roll speed?
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 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]
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]

This topic is closed to new replies.

Advertisement