0

I need to make a function that will calculate the degrees necessary to make an NPC look at the center of the player. However, I have not been able to find any results regarding 3 dimensions which is what I need. Only 2 dimensional equations. I'm programming in C++.

Info:

Data Type: Float.

Vertical-Axis: 90 is looking straight up, -90 is looking straight down and 0 is looking straight ahead.

Horizontal-Axis: Positive value between 0 and 360, North is 0, East is 90, South 180, West 270.

John Kugelman
  • 349,597
  • 67
  • 533
  • 578

3 Answers3

1

See these transformation equations from Wikipedia. But note since you want "elevation" or "vertical-axis" to be zero on the xy-plane, you need to make the changes noted after "if theta measures elevation from the reference plane instead of inclination from the zenith".

First, find a vector from the NPC to the player to get the values x, y, z, where x is positive to the East, y is positive to the North, and z is positive upward.

Then you have:

float r = sqrtf(x*x+y*y+z*z);
float theta = asinf(z/r);
float phi = atan2f(x,y);

Or you might get better precision from replacing the first declaration with

float r = hypotf(hypotf(x,y), z);

Note acosf and atan2f return radians, not degrees. If you need degrees, start with:

theta *= 180./M_PI;

and theta is now your "vertical axis" angle.

Also, Wikipedia's phi = arctan(y/x) assumes an azimuth of zero at the positive x-axis and pi/2 at the positive y-axis. Since you want an azimuth of zero at the North direction and 90 at the East direction, I've switched to atan2f(x,y) (instead of the more common atan2f(y,x)). Also, atan2f returns a value from -pi to pi inclusive, but you want strictly positive values. So:

if (phi < 0) {
    phi += 2*M_PI;
}
phi *= 180./M_PI;

and now phi is your desired "horizontal-axis" angle.

aschepler
  • 70,891
  • 9
  • 107
  • 161
0

I'm not too familiar with math which involves rotation and 3d envionments, but couldn't you draw a line from your coordinates to the NPC's coordinates or vise versa and have a function approximate the proper rotation to that line until within a range of accepted +/-? This way it does this is by just increasing and decreasing the vertical and horizontal values until it falls into the range, it's just a matter of what causes to increase or decrease first and you could determine that based on the position state of the NPC. But I feel like this is the really lame way to go about it.

Yetoo
  • 47
  • 1
  • 9
0

use 4x4 homogenous transform matrices instead of Euler angles for this. You create the matrix anyway so why not use it ...

  1. create/use NPC transform matrix M

    my bet is you got it somewhere near your mesh and you are using it for rendering. In case you use Euler angles you are doing a set of rotations and translation and the result is the M.

  2. convert players GCS Cartesian position to NPC LCS Cartesian position

    GCS means global coordinate system and LCS means local coordinate system. So is the position is 3D vector xyz = (x,y,z,1) the transformed position would be one of these (depending on conventions you use)

    xyz'=M*xyz
    xyz'=Inverse(M)*xyz
    xyz'=Transpose(xyz*M)
    xyz'=Transpose(xyz*Inverse(M))
    
  3. either rotate by angle or construct new NPC matrix

    You know your NPC's old coordinate system so you can extract X,Y,Z,O vectors from it. And now you just set the axis that is your viewing direction (usually -Z) to direction to player. That is easy

    -Z = normalize( xyz' - (0,0,0) )
     Z = -xyz' / |xyz'|
    

    Now just exploit cross product and make the other axises perpendicular to Z again so:

    X = cross(Y,Z)
    Y = cross(Z,X)
    

    And feed the vectors back to your NPC's matrix. This way is also much much easier to move the objects. Also to lock the side rotation you can set one of the vectors to Up prior to this.

    If you still want to compute the rotation then it is:

    ang = acos(dot(Z,-xyz')/(|Z|*|xyz'|))
    axis = cross(Z,-xyz')
    

    but to convert that into Euler angles is another story ...

With transform matrices you can easily make cool stuff like camera follow, easy computation between objects coordinate systems, easy physics motion simulations and much more.

Spektre
  • 49,595
  • 11
  • 110
  • 380