0
\$\begingroup\$

I need to make a camera rotation system similar to the one here

http://madebyevan.com/webgl-path-tracing/

To rotate, press the Left mouse button and drag. So far I figured a basic idea of how this could be implemented.

Note that although it looks like the scene is rotating in front of the camera but in my case I want to rotate the camera instead. Since the scene contains hundreds of thousands of triangles and I wouldn't wanna apply a matrix operation to each of them.

I have represented my camera by a 4x4 matrix. The columns from 1 to 4 are side, up, look at and eye respectively.

So here's what I thought so far.

1) Subtract old cursor position from new cursor position. Doing this for X and Y we get a direction vector as to where the mouse is headed.

2) Invert this direction. And translate the camera a little in this direction. So if the mouse is headed right, the camera heads left. This is done by checking the components of the direction vector.

if (dir.x < 0)
    cam.eye += side
if(dir.x > 0)
    cam.eye -= side
if (dir.y < 0)
    cam.eye += up
if(dir.x > 0)
   cam.eye -= up

Note the translations are inverse. If less than zero than add the side vector instead of subtracting it.

3) Now find a vector perpendicular to it. So if the mouse was headed left or right the vector perpendicular to it is the Y axis. I calculate this by taking the cross(vec(0,0,1), direction_vector). Note this is not the inverse but the actual direction vector.

4) Rotate the camera a little along this perpendicular axis a little.

If you imagine these operations for the X axis. This feels like the camera is moving in some sort of circle around the scene. That is, the camera translates a little, then rotates. Next time it translates by adding the side (which was changed when it first rotated) it moves a little diagonally. In this way it feels like it rotates in a circle.

So this works somewhat fine for pure X and Y rotation and upto a certain extent. Fails when i move the mouse diagonally or in Pure X/Y rotation when I go beyond a certain point probably 90 degrees.

Any advice or suggestions? I am not using OpenGL instead doing this with GLFW and GLM. The renderer is a raytracer/pathtracer.

\$\endgroup\$
1
\$\begingroup\$

About the linked Demo

The linked demo uses euler angles, has a locked target on the center of the scene, and you drag left aqnd right to move the first euler angle, or up and down right to move the second one. The third euler angle is not controlled and remains where it starts.

It is geographic coordinates: the first angle is the rotation on the horizontal axis (Longitude), and second angle is the angular elevation from that plane (Latitude). The first angle can do a full rotation, while the second is limited to minus one quarter rotation to plus one quarter rotation. You can confirm on the demo.


To implement it, store the two angles I mention above in varialbes, update them based on the drag gesture, and use them to compute the position of the camera (and the up vector too, given the way you represent your camera).


Camera Representation

A virtual camera has position, orientation and a viewing volume (usually a perspective projection, can be orthogonal, skwed or something else).

At the end a position and orientation becomes a matrix transformation.

I will not be talking about the viewing volume.


What you have is a lookat matrix. It is a valid transformation matrix.

However, I am not a fan of it, because it sticks you to the vectors (side, up, lookat and eye). It gives you the idea of modifying the vectors directly, which is error prone. For instance, you may end up with a combination of side, up and lookat that does not make sense. We always need to move side, up and lookat together.

We can acomplish that by treating them as a matrix instead of treating them as vectors. I am suggesting to forget about side, up, lookat and eye. I am suggesting to not treat those components of the matrix as vector and to not operate on them directly. Use them as a matrix. Or rahter, I should say, just as a matrix.

Addendum: To move the camera, you can create a translation matrix and apply it to the one of the camera. Similarly to rotate it. However to replicate the demo, recompute the the matrix transformation of the camera each time the user drags.

Note: Whatever the vectors are columns or rows is convention. OpenGL (which GLFW uses internally) only cares about the order in memory. This can also be a source of confusion. In fact, I didn't think you had it right, just because last time I was working with them, I was considering them rows.


Camera Control

There are many models for camera control. There is the static camera that does nothing. The fixed camera that does not move but changes orientation to follow the action. There are cameras that follow the action at a fixed distance. There are variants that are controlled by the player. There are scripted sequences where the camera follows a predefined trajectory...

A common idea is to have the camera follow a object that is affected by physics and collisions (that is effectively what you would do in a FPS). However, if this is physic object is on itself separate from the avatar (for example a third person camera), it also means that the camera can bumb or even get stuck due to collisions. And we do not want that... we would use ray cast checks to anticipate and avoid the collisions. And we want this collision avoidance to be smooth and to keep the action in view.

There is then the problem of objects obscuring the view of the avatar. Some games will have those objects appear translucid, or will render silhouettes, etc.

Futhermore, I have been saying "the action", because the camera may not only be following the player's avatar. For instance you may offset it to show points of interest or to keep nearby enemies in frame.

Sorry, I do not have any books to suggest. Hopefully the presentation "50 Game Camera Mistakes" can help you.


Orbit Camera

What we have in the linked demo is an orbit camera. As I said at the start, it is controlled by euler angles. I will be refering to the point around which the camera orbits as the "target".

Start by declaring your first and second euler angles. Then each time the player drags, you increment the euler angles accordingly to the drag distance, horizontally and vertically respectively. Note that you can do both movements in the same drag gesture.

The position of the camera will be an initial position that you rotate by the euler angles... And the orientation of the camara will be dictated by that same rotation.

Note: I am assuming that you pick an starting position and orientation that is at desired distance from the target and looking at it. Then all you need to do is to get the correct rotation from the euler angles.

To get that rotation, your library has an utility to create a rotation transformation over one of the main axis. Use it to create two rotation matrix (one for each angle) and combine them (multiply them together).

Note: Remember that the order matters in matrix multiplication.

Again, forget about side, up, lookat and eye.

\$\endgroup\$
  • \$\begingroup\$ Ok I have a few questions. 1) What other camera representation models are there? You said about using an actual transformation matrix but isn't mine already one? I use it to store the camera basis vectors and transform between camera and world space. 2) What do you mean by adding position of target to rotated position? 3) Any good books which describes common camera representation and some usual ways camera can be rotated like this? for example an FPS camera rotation system, a system similar to this one etc. \$\endgroup\$ – gallickgunner Jul 29 '18 at 7:21
  • \$\begingroup\$ @gallickgunner I rewrote my answer. \$\endgroup\$ – Theraot Jul 29 '18 at 20:22
  • \$\begingroup\$ @Thearot - Ok I know now what you want me to do. You basically want me to either construct a new orientation matrix from incremented euler angle variables or compose the rotations on top of the existing orientation matrix. Both fail for me however. Especially this won't work if camera is at the origin, since then no rotation matrix could change the position. Of the two composing the rotations on top of orientation matrix seems closer to what I want. It moves the camera in a circle of a small radius. \$\endgroup\$ – gallickgunner Jul 30 '18 at 2:38
  • \$\begingroup\$ @Thearot- I've thought a lot about that and I think I want the camera to move on the surface of a sphere, the radius of which is equal to the distance between the camera position and the center of the bounding box of my whole scene. If I'm moving my mouse left/right. I increment the latitude or theta. If im moving up/down I increment the inclination phi. Then I convert these to cartesian coords to find the actual position of the camera. Rotation would be similar to what you said. \$\endgroup\$ – gallickgunner Jul 30 '18 at 2:43
  • \$\begingroup\$ @gallickgunner Yes, correct. As I said, you will have an starting position for the camera respect to the target. That one you rotate (by the rotation given by those angles). If you want to orbit around a target (and not the origin), add the position of the target to that rotated position (I mean, the one you rotated according to the angles, hopefully that makes sense this time around). The result is the camera position. The camera orientation comes from the same rotation (from the same angles). Note that reversing the order of position and rotatation, gives a camera that rotates in place. \$\endgroup\$ – Theraot Jul 30 '18 at 2:56

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.