Setting the up vector in the camera setup in a ray

2019-06-01 05:11发布

问题:

I'm reading fundamentals of computer graphics and trying to set up my own ray tracer. the book says "The most common way to construct the camera frame is from the viewpoint, which becomes e, the view direction, which is−w, and the up vector, which is used to construct a basis that has v and w in the plane defined by the view direction and the up direction"

but then I came across How to move a camera using in a ray-tracer? which says that we need to correct the up vector for the (slope?) by performing a cross product with the camera direction (w). Why is that?

I'm calling my camera setup with lookAt(0,0,0) and up(0,1,0)

// a camera can be constructed using a position, direction and an up vector
Camera::Camera(Vector position, Vector lookAt, Vector up) {
    this->position = position;
    this->lookAt = lookAt;

    // the difference between camera position and where we want
    // to look at is the direction of the camera
    Vector direction = lookAt.diff(position);

    // camera frame
    w = direction.normalize();
    v = up.cross(w).normalize(); // right vector


    // which is the correct up?
    u = up.normalize();
    printf("%.2f %.2f %.2f\n", u.getX(), u.getY(), u.getZ()); // prints 0 1 0

    u = v.cross(w).normalize(); // the up vector
    printf("%.2f %.2f %.2f\n", u.getX(), u.getY(), u.getZ()); // prints 0.31 -0.86 -0.41
}

回答1:

What you need in the end is a pair of vectors that forms an orthonormal basis for the image plane. One of those is going to point to the right relative to the orientation of the camera. The other is going to point up relative to the orientation of the camera.

If the up vector is a general "the sky is that way," and if your camera is not level, then the up vector and the camera-up vector will be slightly different. The up vector is a hint as to the orientation you want, but it's not exactly the right vector. In this case, you can cross the right vector with the direction vector, and that'll give you a vector that lies in the image plane and is perpendicular to the right vector. That's what you want.

If the up vector is a general "the sky is that way," and if your camera is level, then the up vector and the camera_up vector will be exactly the same. The extra cross product would be unnecessary, but there's no harm in it if you want the code to be general enough to handle the first case.

Perhaps some ASCII art can help clarify...

^                                        * look-at point
| "up"        "camera up"
|                  \ 
|       image plane \
                     \
                 "camera down"

The up vector is straight up. The look-at point is higher than the camera, so the camera must tilt back a little bit. In the diagram, we see the edge of the image plane. The "right" vector is in that plane and pointed out of the diagram. The direction vector (which your code called w) is perpendicular to the image and points directly at the look-at point.

The camera-up vector (u in your code) must lie in the image plane, so we can't just use "up". And it must be perpendicular to the "right" vector. The easiest way to get that is to cross those two vectors.

Since we generated the "right" vector in terms of the original up vector, that gives us the orientation.