Sign in to follow this  
josiah7

Getting A Vector To Look At Another Vector?

Recommended Posts

josiah7    122
This is driving me nuts! I hope someone here can please help me. I am using eular angles with two vectors. The z is the up axis (or pan), the x is the forward facing axis (roll), and the y is the tilt axis. I want to increment the pan and tilt (z and y) by degrees to point at the "camera" vector. I am kind of confused by all the (apparently) different methods, but I gather I need to first normalize each vector to a length of 1, then find the dot product. Then use the result with ACOS. This will give me the angle between the two vectors (right?) I have this so far; //=========================================================== vec_normalize(vec1,1); //normalize the vectors vec_normalize(vec2,1); angle =(acos(vec_dot(vec1,vec2))); //============================================================ Is this much correct? How can I convert this "angle" into degrees of pan and degrees of tilt I need to rotate the vector to get it to face the camera vector? Or am I way off with this approach? Thanks for any help with this!

Share this post


Link to post
Share on other sites
haegarr    7372
Take a look at these recent threads
http://www.gamedev.net/community/forums/topic.asp?topic_id=359774
http://www.gamedev.net/community/forums/topic.asp?topic_id=359332
which discusses the same problem.

I personally suggest you to avoid calculation of the yaw, pitch, and roll angles; IMHO using the standard look-at vector and the wanted look-at vector and computing a rotation matrix by using the pivot/angle pair would be a much better way.

Share this post


Link to post
Share on other sites
dragongame    538
Why rotate around two vectors (which is the same as rotating around one vector).

so lets say you have vec1 and want it to rotate to vec2.

angle = acos( dot(vec1,vec2) );
rotVect = cross( vec1, vec2 );

and now rotate around the rotVector with the given angle.

Hope this helps.

Share this post


Link to post
Share on other sites
someusername    427
hi dude,
I have two approaches in mind.
First of all, this acos( dot_product() ) scheme returns the angle of two vectors *on the plane they form*, so it probably isn't what you want atm, since you want to derive two angles.

Now, two vectors are looking at each other if and only if one is v1=(x1,y1,z1) and the other is v2=(-x1,-y1,-z1), so why not directly set the vector you want to change, into the negative of the other one?

If you need the angles, however, the above won't help much. (though it'll do the job) I'd suggest you use the following formulas to switch into spherical coordinates and then reproject to cartesian after you got what you wanted...
In short, if you want vec1 to point to vec2, express vec2 in spherical coordinates. this way you can get its longitude 'phi'/latitude 'theta' with respect to its head. You obviously need to turn vec1 so that it would have longitude (-phi) and latitude (-theta). Given these angles you create the new vec1 in cartesian coordinates. I hope you see what I mean...
The equation for switching between cartesian-spherical are:

'mag' is the magnitude (length) of the vector

cartesian -> spherical
-----------------------
mag = sqrt( sqr(x)+sqr(y)+sqr(z) )
phi = atan(y/x)
theta = atan( z/sqrt(sqr(x)+sqr(y))

spherical -> cartesian
-----------------------
x = mag*cos(phi)*cos(theta)
y = mag*sin(phi)*cos(theta)
z = mag*sin(theta)

I suppose these will get the job done... :)

Share this post


Link to post
Share on other sites
josiah7    122
Thanks everyone! I really appreciate the answers. All the different approaches
make it a little confusing. I should have stated at the onset that I know very
little about vector math. I thought that it would be simpiler to get these
two angles! Man this is frustrating! I will try to work out some of these ideas,

Thanks again for your time in helping me!

Share this post


Link to post
Share on other sites
someusername    427
Quote:
Original post by someusername
You obviously need to turn vec1 so that it would have longitude (-phi) and latitude (-theta)


oops, I made a mistake there, vec1's longitude should be phi+PI, not -phi.


Share this post


Link to post
Share on other sites
josiah7    122
Quick question, I think mybe I have a problem with either my normalize function
or acos. When I use this on two vectors which are on a even plane and facing
each other directly, the angle returned is 110! as I make a flat orbit 360 on
this plane,(yaw or pan plane), the angle changes from high of 116 to a low of
58! and the high and low numbers dont seem to align with any axis. I would
expect 0 - 360.

Also if I use the SAME normalized vector like this;
//=============================================================
angle = acos(vec_dot(vec1,vec1));
//=============================================================

The angle returned is non zero! This dosent seem correct?
For instance, the angle I get for:
vec1 = 4,0,4;
vec2 = 4,0,4;
is 2.532!

This is what I am doing;
//=============================================================
vec_normalize(vec1,1);
vec_normalize(vec2,1);
angle = acos(vec_dot(vec1,vec2));
//=============================================================

Does this sound right?

Share this post


Link to post
Share on other sites
someusername    427
I haven't taken a look at your code, but...
... 58 sounds like an angle of 1 rad expressed in degrees.
... and 116 sounds like its double!

if you were expecting something like 360 (2pi rad), you probably forgot to multiply with PI somewhere...

Share this post


Link to post
Share on other sites
someusername    427
The problem is that you don't divide the dot product by the product of the vectors' lengths.

acos() expects arguments in the range {-1,...,1} (the range for cosine)
the dot product i.e. of (4.,0.,4.)dot(4.,0.,4.) is 32.
acos(32) won't work even if you're trying for a month. (actually it should return a complex number, but that's another story!)

anyway, the formula angle = acos( dot(v1,v2) ), works only for unit vectors and returns their *angle on the plane they form*, in the range (-PI/2,PI/2)
For arbitrary vectors you should divide the dot product by the product of their lengths. The actual formula for the dot product is

dot(v1,v2) = |v1|*|v2|*cos(angle)

, where |v| = sqrt(x*x +y*y + z*z), the length of vector v

Share this post


Link to post
Share on other sites
josiah7    122
Thanks Someusername, I got it working. The angle provided is the angle
between the vectors tails at the world origin (0,0,0).

I am trying to create spherical billboarding with left hand eulers.

Heres where I am;
//=============================================================

vec_normalize(vec1,1);
vec_normalize(vec2,1);

angle = acos(vec_dot(vec1,vec2));

cross1.x = v1_temp.y*v2_temp.z - v2_temp.y*v1_temp.z;
cross1.y = v1_temp.z*v2_temp.x - v2_temp.z*v1_temp.x;
cross1.z = v1_temp.x*v2_temp.y - v2_temp.x*v1_temp.y;

//=============================================================

~I make the two vectors "unit vectors" with a length of 1.

~Use acos on the dot of these two vectors to get the angle between
them through the world center.

~Get the "left hand" cross product of the two unit vectors to
help determine rotation direction.

Now how can I use these numbers to make one object face another?
I can set an objects yaw and pitch directly, but how to determine
the angles I need from these results?

Thanks for any help on this problem!

Share this post


Link to post
Share on other sites
jyk    2094
Getting one object to face another using an Euler angle pair (such as yaw-pitch) is basically a Cartesian-to-spherical coordinate conversion problem, which can be solved with a few lines of code and atan2(). Google might be able to help with this, or just ask here if you need further details. Also, I'm curious - what's the '1' argument to your normalize function for?

Share this post


Link to post
Share on other sites
someusername    427
I suppose vec1 is the 'look at direction' for your camera, and vec2 is the billboard's local z+, and you want to turn v2, so that it faces the camera directly...

First way: find the inverse of your view matrix. Set it's 4th row to the vector (0,0,0,1). Use that matrix as a world transform for your billboard. No need for extra angles.

Second way: Project both the camera's and billboard's local z+ vectors into spherical coordinates. Get the longitude 'phi'/latitude 'theta' for the first one.
Unproject the spherical coordinates vector with components (1, phi+PI, -theta) back into cartesian coordinates. This must be the billboard's local z axis and furthermore (phi+PI) will be its new pitch and (-theta) its yaw angle.

Cross it with your world up vector to find the billboard's local x axis:
local_x = (World_up)x(local_z)
Cross z with x to get your local_y for the billboard.
local_y = (local_z)x(local_x)

Construct the matrix:

local_x.x local_y.x local_z.x 0
local_x.y local_y.y local_z.y 0
local_x.z local_y.z local_z.z 0
p.x p.y p.z 1

[edit: if that doesn't seem to work, try taking its transpose]

and set it as a world tranform for your billboard. Vector p is the world position of the billboard.

The equations for converting spherical<->cartesian are in one of my replies in this thread...

[Edited by - someusername on November 29, 2005 2:20:41 PM]

Share this post


Link to post
Share on other sites
someusername    427
oops, my bad! ignore the second way in my previous reply, it just keeps the billboard parallel to the camera's local XY plane, it doesn't actually force it to look at the position where the camera actually is:

Here we go again:
Find the vector from the billboard to the camera's eye point, v = v2-v1.
Normalize it and call it local_z
Cross the local_z with the WorldUp vector to get local-x
local_x = (WorldUp)x(local_z)
Cross local_z with local_x to get local_y
local_y = (local_z)x(local_x)

Again construct the matrix like I showed in the previous reply and apply it as the billboard's world transform.

If you also need to find the pitch/yaw angles by which you would have to rotate the billboard to come to this orientation, project the camera's local_z into spherical coordinates. You'll get this (r=cam_dist_from_origin, phi = cam_pitch, theta = cam_yaw )
Do the same for your billboard's local_z and subtract the respective rho/phi coordinates.

Honestly, I don't know why you insist on the dot product formula. The angle you'll derive from it can only be used if you can construct a matrix that rotates around any arbitrary axis that passes through any arbitrary point, by any angle. It's is the most tedious approach. (imo)

I hope these will do the job.

[Edited by - someusername on November 29, 2005 2:34:49 PM]

Share this post


Link to post
Share on other sites

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