0

I do understand how glm::LookAt works and what parameters it requires. I can't understand how to provide right Up vector.

For example, this:

glm::mat4x4 transformation = glm::lookAt(cameraPosition, targetPosition, glm::vec3(0.f, 1.f, 0.f));

If I want to make camera watch straight down:

 mat4x4 transformation = glm::lookAt(vec3(0.f, 1.f, 0.f), vec3(0.f, 0.f, 0.f), vec3(0.f, 1.f, 0.f));

It won't work. Matrix will contain NaNs (Not a Number) values! So how to get right value for Up vector?

genpfault
  • 51,148
  • 11
  • 85
  • 139
overwriter
  • 339
  • 3
  • 14

1 Answers1

3

The reason for the NaN's you get is division by zero.


Quoting this post:

The up vector is basically a vector defining your world's "upwards" direction. In almost all normal cases, this will be the vector (0, 1, 0) i.e. towards positive Y. eye is the position of the camera's viewpoint, and center is where you are looking at (a position).

How does the setup work? The below diagram illustrates:

enter image description here

  • u is the up vector (third argument)
  • p is the target position (second argument)
  • c is the camera position (first argument)
  • d is the direction vector (= p - c)
  • r is the right vector

lookAt returns the view matrix, which has the following format:

enter image description here

(Where the "hats" mean normalized - having length 1)

Since you only supply the up vector and (effectively, because d = p - c) the direction vector, we must compute the right vector using the cross-product:

enter image description here

(Note the above was before normalization)


Now for why your example does not work as expected. The arguments as such:

  • u = (0, 1, 0)
  • p = (0, 0, 0)
  • c = (0, 1, 0)
  • And thus d = (0, -1, 0)

The above gives r = d * u = (0, 0, 0)! This is because the direction and up vectors are anti-parallel, whereas there should be an angle between them for the routine to work (ideally 90 degrees). When r is normalized there is a division by zero, and hence the entire first row of your matrix should be occupied by NaN's.

(As a possible fix, try up = (0, 0, 1) instead.)

meowgoesthedog
  • 14,670
  • 4
  • 27
  • 40
  • Thank you very much for your deployed answer! But what I'm looking for is A way to get right Up vector for any situation, How can I determine right Up-direction for camera automatically? Maybe there is a way to get it taking cross product with glm::vec3(1, 0, 0) (right direction)? Or should I use quaternions maybe? If normally my camera is at (0, 0, 0) looking forward (0, 0, 1) and I place my camera somewhere at _cameraPosition_ and trying to get it look to _targetPosition_ how can I get rotation that doesn't rotate about camera's Z axis to turn to target? – overwriter Nov 09 '17 at 06:48
  • 1
    @overwriter Sure, you can calculate *up* from *right*. But this raises the question how to get *right*. In general, there is no automatic way because there are infinitely many solutions. And there is nothing that makes one solution better than another. So, in the end the programmer or scene designer has to decide. – Nico Schertler Nov 09 '17 at 07:12
  • This is confusing me as well. I ended up just checking the special case of it being straight down and just made it conditional. Feels really inelegant and like a hack, but it works for how my functions are used in practice. – Bradford Medeiros Nov 01 '20 at 05:16