Archived

This topic is now archived and is closed to further replies.

calico210

orienting a vector to another another vector in 3d space

Recommended Posts

I am trying orient a model of a head in the direction of a vector. I have a model of a head which is facing in the direction of the vector (1,0,0) I want to rotate the vector to a new vector in 3d space. I first take the cross product to determine an axis of rotation. Then I find the angle between the two vectors, by taking the dot product of the two vectors and then taking the acos of the dot product. Using that angle I rotate about the axis to have the head look in the direction of the new vector. glRotatef(rot_ang,rot_axis[0],rot_axis[1],rot_axis[2]); This seems to work if the original vector and the new vector point in the same hemisphere, but if the new vector is looking back the other way it behaves very odd. Please help.

Share this post


Link to post
Share on other sites
Make sure everything is normalized That''s always a good start! And what behavior do you mean exactly by "very odd"? The range of acos is 0 to PI, so there aren''t any negative results. Is the head just turning in the wrong direction?

Share this post


Link to post
Share on other sites
You will have problems when the direction is straight forward or straight behind. In this case the cross product is zero, so it cannot use it as an axis. What will probably happen is you will get either a divide by zero error or undefined behavior as it tries to normalise the vector before using it. And close to this you may also get odd results as the closer the result of the cross product is to zero the more rounding errors get magnified when it is normalised.

The solution is to check the magnitude of the cross product and if it is too close to zero use a fixed axis such as straight up instead. How close is "too close" depends on the accuracy of your FP calculations and is easiest to determine by experiment.

Share this post


Link to post
Share on other sites
Everything is normalized. The dot product and crossproduct functions are

crossproduct(vfinal, v1, v2)
{
vfinal->x = v1->unity*v2->unitz-v2->unity*v1->unitz;
vfinal->y = v2->unitx*v1->unitz-v1->unitx*v2->unitz;
vfinal->z = v1->unitx*v2->unity-v2->unitx*v1->unity;

vfinal->magnitude=sqrt(vfinal->x*vfinal->x+vfinal->y*vfinal->y+vfinal->z*vfinal->z)
vfinal->unitx=vfinal->x/vfinal->magnitude;
vfinal->unity=vfinal->y/vfinal->magnitude;
vfinal->unitz=vfinal->z/vfinal->magnitude;
}

double dotproduct(v1, v2)
{
return(v1->unitx*v2->unitx+v1->unity*v2->unity+v1->unitz*v2->unitz);
}

I don''t seem to have problems looking straight ahead, but I do have all sorts of problems when looking back. Watching the axis of rotation it looks like I should also have problems looking forward too though.
The vector will point in the correct direction for all angles, but the head is rotated about the new vector''s axis. I taped a picture of a face to a pen to see what might be going on, and it seems like the bahavior is close to what the axis is supposed to be doing, but the axis seems to have orientation problems closer to straight back. johnb you are probably right about the rounding errors. I had already taken into account the possible divide by zero and the undef behavior. Using a fixed axis would work, but will be much trial and error, are there any other ways? Perhaps a different approach to solving this?

Thanks for the help

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Did you remember to convert radians to degress? acos returns radians, glRotatef expects a degree.

Share this post


Link to post
Share on other sites
This is version I made from Matrix&Quat FAQ: (http://www.flipcode.com/documents/matrfaq.html)


  
// creates a rotation matrix that maps v1 to v2

void mat4::rotation2V(const vec3& v1,const vec3& v2)
{
vec3 axis,vv1,vv2;
float angle,xx,xy,xz,xw,yy,yz,yw,zz,zw;
quat q;

axis = vec3::crossProduct(v1,v2);
vv1=v1; vv1.normalize();
vv2=v2; vv2.normalize();
angle = (float)acos( vec3::dotProduct(vv1,vv2) );

q.fromAxisAngle(axis,angle);

xx = q.x * q.x;
xy = q.x * q.y;
xz = q.x * q.z;
xw = q.x * q.w;
yy = q.y * q.y;
yz = q.y * q.z;
yw = q.y * q.w;
zz = q.z * q.z;
zw = q.z * q.w;

m[0] = 1 - 2 * ( yy + zz );
m[1] = 2 * ( xy - zw );
m[2] = 2 * ( xz + yw );
m[4] = 2 * ( xy + zw );
m[5] = 1 - 2 * ( xx + zz );
m[6] = 2 * ( yz - xw );
m[8] = 2 * ( xz - yw );
m[9] = 2 * ( yz + xw );
m[10] = 1 - 2 * ( xx + yy );
m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f;
m[15] = 1.0f;

}

void quat::fromAxisAngle(vec3& _axis,float _angle)
{
float sin_a,cos_a,mag;
vec3 a;

sin_a = (float)sin( _angle / 2.0f );
cos_a = (float)cos( _angle / 2.0f );
mag = _axis.length();
if (mag <= 1.0e-4) {
/* generate an identity quat */
this->setIdentity();
return;
}
a = _axis / mag;

x = a.x * sin_a;
y = a.y * sin_a;
z = a.z * sin_a;
w = cos_a;
this->normalize();

// quat = (x,y,z,w)

}


// This is part in model animation code that uses it (it is originally from Hasm AM SDK, I''m modified it to use STL and my math lib instead of MFC and Hash math dll)

  
void Bone::ComputeBoneToStandard(vec3 *pivotpos, vec3 *endpos, vec3 *rollpos)
{
// TOIMII OK!!!


mat4 bts;

vec3 pivot_to_end = (*endpos) - (*pivotpos);
vec3 pivot_to_roll = (*rollpos) - (*pivotpos);
vec3 rollvec;

bts.rotation2V(pivot_to_end,vec3(0,0,1));
rollvec = bts.transformCoord(pivot_to_roll);

float roll = (float)atan2( -rollvec.x, rollvec.y );
if ( roll )
{
mat4 zrot;
zrot.rotationZ(-roll);
mat4::multiply(bts,zrot,bts);
}

vec3 tr = - (*pivotpos);
tr = bts.transformCoord(tr);
bts.setTranslate(tr);

m_bonetostandard=bts;
}



Hope you can find some help here, I couldn''t otherwise help you

Share this post


Link to post
Share on other sites
> Using a fixed axis would work, but will be much trial and
> error, are there any other ways? Perhaps a different approach
> to solving this?

At some point for some cases you cannot rely on the cross product as it produces zero an so unnormaliseable results.

One explaination of this is that for vectors facin opposite directions there isn''t a single ''best'' axis. You can rotate through 180 degress about any axis perpendicular to the two vectors to move between them. Mathematically no axis is ''the right one''.

So you have to choose one yourself. Often there''s an obvious choice because there''s an obvious way to turn, because of the constrants of the system.

If there''s no obvious choice, so the choice doesn''t matter, make an arbitrary one. E.g. for horizontal vectors you can choose straight up, as the human head turns through 180 degrees about only the up axis so it''s the most natural to choose. There''s no ''trial and error'' required, just a choice based on simple criteria once taking the cross product fails.

Share this post


Link to post
Share on other sites