Jump to content
  • Advertisement
Sign in to follow this  
Stowelly

rotating a NPC so it is facing an NPC at any given location

This topic is 4163 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

ok bare with me on this one, i seem to have got myself quite confused and the code is producing some VERY strange results for a start the cross product never equals a negative number, therefore it only rotates across 2 of the quadrants but also it only seems to rotate at 90 degree angles and not directly at the point where it is supposed to, anyone have an idea what could be wrong with this code?

 bool npcHandler::npcFindPlayer(CXFileEntity* e1, CXFileEntity* e2 )
 {
D3DXVECTOR3 velocity;
D3DXVECTOR3 x = D3DXVECTOR3(1.0f,0.0f,0.0f);
D3DXVec3Normalize(&x,&x);



//initialise variables (bounding volume used to determine how close NPC should be)
float dist;float minDist;
	D3DXVECTOR3 e1p;
	D3DXVECTOR3 e2p;
	e1->getPosition(&e1p);
	e2->getPosition(&e2p);
	D3DXVECTOR3 oldPos = e1p;
	D3DXVECTOR3 relPos =  e1p - e2p;
   dist = relPos.x * relPos.x + relPos.y * relPos.y + relPos.z * relPos.z;
   minDist = e1->boundRadius + e2->boundRadius;


//calc gradient of the line
   double m;
   m=((e1p.z-e2p.z)/(e1p.x-e2p.x));

 //work out c
double c;
   c= e1p.z-(m*e1p.x);
double sqrtDist = sqrt(dist);



//if not a certain distance from player move npc along a straight line to player
if (sqrtDist >= minDist *1.5)
 {
	 double amm = -4.0f;

//if negative x
	if (e1p.x <= e2p.x)
	{
	e1p.x = e1p.x -amm;    //calculates new x value
	}
	//if positive
	if (e1p.x > e2p.x)
	{
	e1p.x = e1p.x +amm;    //calculates new x value
	}

	
	e1p.z = (e1p.x*m) + c;;    //calculates new z value
	relPos =  e1p - e2p;
   dist = relPos.x * relPos.x + relPos.y * relPos.y + relPos.z * relPos.z;
 e1->setPosition(&e1p);
 e1->walk(0);



 //work out the velocity of NPC
   D3DXVec3Subtract(&velocity ,&oldPos,&e1p) ; 
//calculate the dot product of the angle
float angleThetax = D3DXVec3Dot( &velocity, &x);

D3DXVec3Normalize(&velocity,&velocity);

//calculate the cross product to see if which quandrant we are in
D3DXVECTOR3 cross;
D3DXVec3Cross(&cross,&oldPos,&e1p);
//D3DXVec3Normalize(&cross,&cross);
D3DXVECTOR3 Rot = e1->getRotation(); 
if (cross < D3DXVECTOR3(0.0f,0.0f,0.0f))
{

	Rot =  D3DXVECTOR3(Rot.x,angleThetax,Rot.z);
	
}
else
{

	Rot =  D3DXVECTOR3(Rot.x,-angleThetax,Rot.z);
	
}
//D3DXVec3Normalize(&Rot,&Rot);
e1->SetRotation(&Rot);


 }
else
{
	return true;
}



 return false;
 }

Share this post


Link to post
Share on other sites
Advertisement
small update i have changed it from using the x axis to using the z axis and it seems to be rotating as it should, apart from i cant find a decent way to pick which quandrant it should be in to offset it from, thanks alot

Share this post


Link to post
Share on other sites
Quote:

ok bare with me on this one

You meant bear.

Quote:

for a start the cross product never equals a negative number

The cross product of two vectors is itself a vector, and can never "equal a negative number."

Quote:

anyone have an idea what could be wrong with this code?

Not really, because it is next to unreadable, and you have not done a particularly great job explaining what you want it to actually do (nor what it really does, but I think that's largely because what it does is needless obtuse and relying on poor geometric assumptions).

From the thread title, I can only assume you have two NPCs, both with position and orientation vectors (specifying where those NPCs are and which direction they are facing), and you'd like to calculate a rotation matrix that will rotate NPC B to face NPC A. This is quite simple, and you can do away with all this "quadrant" stuff, which is crude.

Given the initial (normalized) orientation vector of NPC B (Bf), and the positions of NPCs A and B (Ap, Bp), then:
1) The destination orientation vector Df is (normalize(Ap - Bp)), the normalized vector from Bp to Ap.
2) The desired axis of rotation is cross(Bf,Df).
3) The desired angle of rotation is acos(dot(Bf,Df) / |Bf||Df|).
4) There is a D3DX function (D3DXVec3RotationAxisAngle, or something) that builds a rotation matrix from an axis-angle representation.

This works in general, unlike your solution which seems to be tailored to specific assumptions. If you don't want to rotate the object immediately to the desired direction, you can smoothly interpolate the rotation angle over time.

The solution may not be workable for you because you might not support axis-angle rotations, but I suggest you consider adopting them because they are much more powerful than Euler angle or YPR representations, which is seems you might be using.

If this doesn't help you're going to have to explain your problem and your code in more detail, and clean up the formatting because its rather uncomfortable to read.

Share this post


Link to post
Share on other sites
I dont know what your doing exactly but to make one object face another simply use the atan2f() function.


NPC1.yRotation = atan2f(NPC1.position.x - NPC2.position.x,NPC1.position.z - NPC2.position.z);

Im nowhere near my code at the moment but thats the general idea.

Share this post


Link to post
Share on other sites
yeah sorry about the code being so unreadable.... you know how it is when your trying loads of things at once, it comes abit unmanagable etc

thanks to both of you i now understand both methods

would there be any reason to use jpetrie's method over treeway's methods at all? the second seems like it was a little too easy if anything.


ill be sure to restructure my code and posts abit clearer in future, thanks both of you

Share this post


Link to post
Share on other sites
Hi,

Have you tried this?

* Transform target pos to local pos
* Transform targetLocal pos to spherical

now you have elevation and bearing, that's what I use and it works like a charm.... your bearing will be 0 when looking right at the target....

let me know if you need a snippet...

EDIT: Might not be the most effeciant, but it works.

Share this post


Link to post
Share on other sites
cheers, ill have a look into how that works

any idea what the best method out of all of these are? would like to optimise my code as soon as possible...... i suppose it may be worth my while coding all three and then profiling them maybe?

Share this post


Link to post
Share on other sites
Quote:
Given the initial (normalized) orientation vector of NPC B (Bf), and the positions of NPCs A and B (Ap, Bp), then:
1) The destination orientation vector Df is (normalize(Ap - Bp)), the normalized vector from Bp to Ap.
2) The desired axis of rotation is cross(Bf,Df).
3) The desired angle of rotation is acos(dot(Bf,Df) / |Bf||Df|).
4) There is a D3DX function (D3DXVec3RotationAxisAngle, or something) that builds a rotation matrix from an axis-angle representation.


Well here is the actual code from the algorithm you just posted, I just wrote this code based on what you had said here:

<code>

///////////////////////////////////////////////////////////////////
//Rotations
///////////////////////////////////////////////////////////////////

D3DXVECTOR3 findNearest = D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 crossProd = D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 unitTrigData = D3DXVECTOR3(0.0f,0.0f,0.0f);
D3DXVECTOR3 axisRotation = D3DXVECTOR3(0.0f,0.0f,0.0f);

//this locates the nearest targets position
findNearest = FindNearest(m_Position);

//normalise the orientation vector to target
D3DXVec3Normalize(&unitTrigData,&(findNearest-m_Position));
//get the rotation axis? m_Orientation is current heading
D3DXVec3Cross(&axisRotation,&m_Orientation,&unitTrigData);
//inverse cos of the angle between the current direction and new direction
float top = D3DXVec3Dot(&m_Orientation,&unitTrigData);
//dunno what the hell this is ment to be but you put it as |Bf||Df|
float bot =D3DXVec3Length(&m_Orientation)*D3DXVec3Length(&unitTrigData);
//then we get the inverse cosign of the inverse cosign / whatever that was ^
float angleTheta = acos( top / bot);
//build a rotational matrix based on the axis and angle
D3DXMatrixRotationAxis(&m_Rotation, &axisRotation, angleTheta);

</code>

PLease can you explain a few things about the above method jpetrie because you seem quite vague about it, why are you multiplying to gether the legnths of two unit vectors? surly the length of a unit vector is always 1, therefor 1*1 = 1 always :D

Please can anyone explain what jpetrie was failing to achieve?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
bump

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!