Rotate an object to face a target in 3D space

Started by
5 comments, last by justynjj 15 years, 11 months ago
Hi, As usual I've been stressing over the last few days trying to do this "simple" task. I want to rotate a 3d object to face another location in 3d space. I've done lots of searching around and understand the following: 1. When calculating two degrees of rotation i.e pitch and yaw calculate them one at a time then combine them. pitch round X axis yaw around Y axis (I will not be using roll just yet) 2. Use aTan2 instead of cos when calculating the angles as the results are more accurate. To work out the pitch(angleX) and yaw(angleY) I am doing the following:

D3DXVECTOR objLocation, //Location of the fish
objHeading, //Current direction the fish is facing
objVelocity, //Used to translate the objLocation towards the target
targetLocation; //Location of the target
float angleX, angleY;

//Work out the velocity so object can move towards target
//Work out the distance
D3DXVECTOR3 distV = targetLocation - objLocation;
float distance = D3DXVec3Length(&distV);

//Now find the difference and normalise it.
D3DXVECTOR3 diff;
D3DXVec3Subtract(&diff, &targetLocation, &objLocation);
D3DXVECTOR3 diffNorm;
D3DXVec3Normalize(&diffNorm, &diff);
objVelocity = diffNorm;

//Now calculate the angles to rotate the object towards the velocity vector
D3DXVECTOR3 directionV;
D3DXVec3Subtract(&directionV, &objVelocity, &objHeading);
angleX = atan2(directionV.z, directionV.y);
angleY = atan2(directionV.x, directionV.z);

//Now create the translate and rotation matrices
D3DXMATRIX matRotate, matTranslate;
D3DXMatrixRotationYawPitchRoll(&matRotate, angleY, angleX, 0);
D3DXMatrixTranslation(&matTranslate, x, y, z);

//Now apply to the scene
d3ddev->SetTransform(D3DTS_WORLD, &(matRotate * matTranslate));
The velocity works fine and my fish zooms off to the target but it still faces in the wrong direction. I know i'm close. I think i've just got some x and z round the wrong way somewhere. Can you see where I am going wrong? If the above lost you I tried to make the problem simpler below. A break down of the problem: I have an object facing a random direction objHeading = X,Y,Z I then have a target which the object has to rotate to head towards targetLoc = X,Y,Z To rotate my object to face the target I need to work out the angle to turn to face it. rotateAroundX = degree rotateAroundY = degree I am using Direct3D with C++ I need it to satisfy the following scenarios: Sceneario 1: Follow positive X axis objHeading = 0,0,-1 targetLoc = 10,0,0 would result in the following angles:- rotateAroundX = 0 degrees rotateAroundY = -90 degrees Sceneario 2: Follow positive Y axis objHeading = 0,0,-1 targetLoc = 0,10,0 would result in the following angles:- rotateAroundX = 90 degrees rotateAroundY = 0 degrees Sceneario 3: Follow positive Z axis objHeading = 0,0,-1 targetLoc = 0,0,10 would result in the following angles:- rotateAroundX = 0 degrees rotateAroundY = 0 degrees Sceneario 3: Two axis of rotation objHeading = 0,0,-1 targetLoc = 10,10,0 would result in the following angles:- rotateAroundX = 45 degrees rotateAroundY = -90 or 270 degrees Sceneario 3: Two axis of rotation objHeading = 0,0,-1 targetLoc = 10,10,10 would result in the following angles:- rotateAroundX = 45 degrees rotateAroundY = -135 or 225 degrees The program will eventually be a shoal of fish that swarm together. I am rotating the fish object to face the final calculated swarm target location. I guess eventually I will also want the fish to have its up direction always facing up the Y axis.. possibly enabling a slight roll during turns.. but that's for later :D Hope all the above makes sense. Help would be greatly appreciated. Thanks Justyn
Advertisement
I don't know how to do this with angles, but an easy way is to calculate a rotation vector and a rotation angle, and then construct a rotation matrix that rotates around an arbitrary axis. If you want, I can outline the process for you.
yea that would be helpful. I think i'm kind of doing what your saying anyway but just using the Direct3D function:

D3DXMatrixRotationYawPitchRoll(&matRotate, rotateAroundY, rotateAroundX, rotateAroundZ);


to create that rotation matrix.

Please explain your method though as i'm sure it will shed some light onto the situation. :D

Thanks
I can suggest a slightly different way of going about it that will work, I believe. I did something similar about a year ago with a project I had.

The relevant source code is here (though there is an error in my source code in the first post: it should be RotateGlobal rather than RotateLocal):

http://www.gamedev.net/community/forums/topic.asp?topic_id=441234

Essentially, if you find the vector between your current position and the point you wish to be looking at (vDest - vPos), then find the cross product of your current forward position with the previously calculated vector, you find the vector that becomes your axis of rotation. You won't need to muck about finding the pitch/yaw/roll angles at all.
Great thanks, i'll check it out later tonight and post back here with my results.
OK it goes like this (I think CaspianB does the same thing):

Lets P1 be the position of your object, P2 the position of the target, L the normalized look-at vector for your object.

1) Calculate the normalized vector from your object to the target. This is simply normalize(P2 - P1). We'll mark this as T.

2) Take the cross product of T and L (watch the order as the cross product is not commutative). This is the axis of rotation.

3) Calculate arccos(dot(T, L)). This is your angle of rotation.

Using these two pieces of data, you can construct a rotation matrix that rotates the object accordingly. You can use D3DXMatrixRotationAxis() to create the matrix.
Great! It worked :D I followed Gage64's walk through.

The Cpp with Direct3D source that I used to do it was as follows (Let me know if there is a better way/more efficient way of doing this please). I def remember hearing a way of using aTan instead of aCos to do it which reduced an error when using small angle changes... but the following code works fine for me at the moment.

I just need to work on a way to keep the object from turning upside down now.

        D3DXVECTOR3 P1, P2, L, T, tempV, axisOfRotation;	float angle;	P1 = ob->loc; //The D3DXVECTOR3 location of the object	P2 = ob->target //The D3DXVECTOR3 location of the target        //Calculate the normalized vector from the object to the target	D3DXVec3Normalize(&L, &ob->heading);	D3DXVec3Subtract(&tempV, &P2, &P1);	D3DXVec3Normalize(&T, &tempV);        //Take the cross product of T and L to compute the axis rotation	D3DXVec3Cross(&axisOfRotation, &L, &T);        //Calculate the angle of rotation	angle = acosf(D3DXVec3Dot(&T, &L));	        //Now create the rotation matrix        D3DXMATRIX matRotate;	D3DXMatrixRotationAxis(&matRotate, &axisOfRotation, angle);        //Now you can apply the rotation when you place your object in the scene        d3ddev->SetTransform(D3DTS_WORLD, &matRotate);


I've only been doing C++ and direct3D programming for about a month so I wouldn't go using this in your multimillion dollar/pound games! lol ...unless of course someone can verify that this is indeed the best way to do it. Which I doubt highly. hehe

Thanks a lot all for helping out.

Justyn

This topic is closed to new replies.

Advertisement