2

I'm rusty a bit here.

I have a vector (camDirectionX, camDirectionY, camDirectionZ) that represents my camera direction of view. I have a (camX, camY, camZ) that is my camera position.

Then, I have an object placed at (objectX, objectY, objectZ)

How can I calculate, from the camera point of view, the azimut & elevation of my object ??

gluon
  • 662
  • 1
  • 10
  • 18

1 Answers1

4

The first thing I would do, to simplify the problem, is transform the coordinate space so the camera is at (0, 0, 0) and pointing straight down one of the axes (so the direction is say (0, 0, 1)). Translating so the camera is at (0, 0, 0) is pretty trivial, so I won't go into that. Rotating so that the camera direction is (0, 0, 1) is a little trickier...

One way of doing it is to construct the full orthonormal basis of the camera, then stick that in a rotation matrix and apply it. The "orthonormal basis" of the camera is a fancy way of saying the three vectors that point forward, up, and right from the camera. They should all be at 90 degrees to each other (which is what the ortho bit means), and they should all be of length 1 (which is what the normal bit means).

You can get these vectors with a bit of cross-product trickery: the cross product of two vectors is perpendicular (at 90 degrees) to both.

To get the right-facing vector, we can just cross-product the camera direction vector with (0, 1, 0) (a vector pointing straight up). You'll need to normalise the vector you get out of the cross-product.

To get the up vector of the camera, we can cross product the camera direction vector with the right-facing vector we just calculated. Assuming both input vectors are normalised, this shouldn't need normalising.

We now have the orthonormal basis of the camera. If we stick these vectors into the rows of a 3x3 matrix, we get a rotation matrix that will transform our coordinate space so the camera is pointing straight down one of the axes (which one depends on the order you stick the vectors in).

It's now fairly easy to calculate the azimuth and elevation of the object.

To get the azimuth, just do an atan2 on the x/z coordinates of the object.

To get the elevation, project the object coordinates onto the x/z plane (just set the y coordinate to 0), then do:

acos(dot(normalise(object coordinates), normalise(projected coordinates)))

This will always give a positive angle -- you probably want to negate it if the object's y coordinate is less than 0.

The code for all of this will look something like:

fwd = vec3(camDirectionX, camDirectionY, camDirectionZ)
cam = vec3(camX, camY, camZ)
obj = vec3(objectX, objectY, objectZ)

# if fwd is already normalised you can skip this
fwd = normalise(fwd)

# translate so the camera is at (0, 0, 0)
obj -= cam

# calculate the orthonormal basis of the camera
right = normalise(cross(fwd, (0, 1, 0)))
up = cross(right, fwd)

# rotate so the camera is pointing straight down the z axis
# (this is essentially a matrix multiplication)
obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))

azimuth = atan2(obj.x, obj.z)

proj = vec3(obj.x, 0, obj.z)
elevation = acos(dot(normalise(obj), normalise(proj)))
if obj.y < 0:
    elevation = -elevation

One thing to watch out for is that the cross-product of your original camera vector with (0, 1, 0) will return a zero-length vector when your camera is facing straight up or straight down. To fully define the orientation of the camera, I've assumed that it's always "straight", but that doesn't mean anything when it's facing straight up or down -- you need another rule.

dave
  • 12,634
  • 3
  • 20
  • 12
  • thanks a lot for your answer. I have some difficulties to implement it. I got the first part about simplifying by translating & rotating. But I'm lost after that. Indeed, "we now have the orthonormal basis" means I have to use it for the reference of the object ? how can I do that? because x/z in the azimuth calculation are the x, z into the new basic, right ..? – gluon Jun 17 '12 at 20:51
  • @gluon I've updated the answer with some pseudo-code. Hopefully that will make things clearer – dave Jun 18 '12 at 02:02
  • I guess the key is ... quaternion. I guess I would have to have a total new approach for using quaternions. – gluon Jun 18 '12 at 14:07
  • the facing up & down case is the gimbal lock right? what would I need to provide more to the azimuth & elevation calculation in order to avoid this? I guess quaternions. what would be the calculation in that case ? (any leads would be amazing) – gluon Jun 19 '12 at 21:01
  • @gluon I think you just need some way of deciding which way is up for the camera in the looking straight up/down case. What other information are you storing for the camera? Or is it just position and vec3 direction? What else are you doing with the camera? If you're eg rendering the camera's view, you must already have a way of deciding which way is up for the camera in all cases? – dave Jun 19 '12 at 22:49
  • @gluon If your camera rotation is stored as a quaternion, there are standard ways to convert it to a rotation matrix. See eg http://stackoverflow.com/questions/1556260/convert-quaternion-rotation-to-rotation-matrix. You would just do that instead of calculating the rotation matrix with cross products like I've done – dave Jun 19 '12 at 22:56
  • Hi Dave and thanks for your precious help. I'm okay to convert. my main difficulty is understanding how can I use the resulting matrix. All my needs are: relative position calculation of objects to my camera, but all in the plane defined by the lookat vector of my cam (I guess you just understood that already,btw) then, with the zimuth, I can know the position of object from "left to right" ; just found this : http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToEuler/index.htm I guess I can use that test and be okay to avoid coordinates singularities, right ? – gluon Jun 20 '12 at 07:41
  • @gluon If you have a rotation matrix, the line `obj = vec3(dot(obj, right), dot(obj, up), dot(obj, fwd))` just becomes `obj = possibly_transpose(rot_matrix) * obj` (and you don't need `fwd`/`right`/`up` at all). There's no need to mess around with Euler angles – dave Jun 20 '12 at 22:04
  • thanks a lot for your involvement in my (probably) newbie questions. my maths are very rusty sometimes. if you are interested, here is a very early prototype : http://www.youtube.com/watch?v=ZCexHD297O0 – gluon Jun 21 '12 at 09:19
  • @gluon No problem. Neat video :) – dave Jun 22 '12 at 02:11
  • I didn't succeed yet. Because I have the quaternion, I thought about multiply it would be simpler using sandwich double product of the vector. I used this : http://fr.wikipedia.org/wiki/Quaternions_et_rotation_dans_l'espace#M.C3.A9thodes_utilis.C3.A9es Whatever the position & rotation of my cam, if I keep the object in the center of my window, the azimuth should be the same, right ?? It doesn't seem to be the case here :-/ Where am I doing wrong ...? I totally don't know. Just popped out a message on Max6 forum : http://cycling74.com/forums/topic.php?id=40633&replies=10#post-197409 – gluon Jun 23 '12 at 00:32
  • I posted that to make things clearer probably http://stackoverflow.com/questions/11165863/how-to-calculate-azimuth-elevation-of-objects-relative-to-camera-using-cam-qua – gluon Jun 23 '12 at 00:52