views:

223

answers:

2

I'm trying to learn a little more on vectormath through writing a simple ray tracer and I've been doing some reading on it, but what I haven't been able to find is how to determine the direction of the primary rays. This sounds like a simple problem and probably is, but with my current knowledge I haven't been able to figure it out.

I figured that I need a camera (nothing more than a location and a direction as vectors) and from the camera I fire the primary rays onto a screen in front of the camera which represents the final image. What I can't figure out are the corner coordinates of the screen. If I know the screen, finding the direction the primary rays is easy.

I'm hoping the screen can be figured out using nothing but simple math that doesn't require any rotation matrices. My best guess is this:

I have the direction of the camera as a vector, this direction is equal to the normal of the plane of the projection screen. So I have the normal of the screen, and from there I can easily calculate the center of the screen which is:

camera_location + (normal * distance)

Where distance is the distance between the screen and the camera. However, that's where I get lost and I can't find a way to figure out the corner coordinates of the plane for any arbitrary direction of the camera.

Can any of you help me out here? And if my method can't possibly work, what does?

A: 

EDIT: Here's some code, which is substantially reduced from that originally posted because it omits the creation of a viewMatrix. That was only needed for some some scanline rendering and wasn't used for ray-tracing.

The hard work is the lookat() function, particularly the creation of the 'up' and 'right' vectors. These have to be perpendicular to each other, and also to the vector running between the eye and the center of the picture. Creation of those vectors relies on the cross-product vector function.

The actual function for casting rays assumes that the screen viewport runs from -0.5 to +0.5 in the Y direction. That function is pretty simple, and just consists of adding the correct proportions of the 'view', 'up' and 'right' vectors together.

public class Camera {

    protected Point3d       eye;
    protected Point3d       center;

    protected Vector3d      up;
    protected Vector3d      right;
    protected Vector3d      view;

    protected double        fovy;           // half FoV in radians
    protected double        tanf;
    protected double        aspect;

    public Ray castRay(double x, double y) {

        Vector3d dir = new Vector3d(view);
        Vector3d t = new Vector3d();
        t.scale(tanf * x * aspect, right);
        dir.add(t);
        t.scale(tanf * y, up);

        dir.add(t);
        dir.normalize();

        return new Ray(eye, dir);
    }

    /* algorithm taken from gluLookAt */
    public void lookAt(Point3d _eye, Point3d _center, Vector3d _up) {

        eye = new Point3d(_eye);
        center = new Point3d(_center);
        Vector3d u = new Vector3d(_up);

        Vector3d f = new Vector3d(center);
        f.sub(eye);
        f.normalize();

        Vector3d s = new Vector3d();
        u.normalize();
        s.cross(f, u);
        s.normalize();
        u.cross(s, f);

        view = new Vector3d(f);
        right = new Vector3d(s);
        up = new Vector3d(u);
    }

    /* algorithm taken from gluPerspective */
    public void setfov(double _fovy, double _aspect)
    {
        fovy = Math.toRadians(_fovy) / 2.0;
        tanf = Math.tan(fovy);
        aspect = _aspect;
    }
}
Alnitak
Thanks. I can work with this. I assume that initializing a vector with another vector as the argument simply set the value of the new vector to the values of the argument vector?
Yes, that's right. These classes are all from the Java 3D API.
Alnitak
A: 

Thank you for the information. Personally, I'm not too comfortable with matrix transformations and would like to avoid them as much as possible. However, from your post I understand that transformations are the only way to do what I want to do? That would too bad, since I thought I was pretty close (I got the normal and centerpoint of the screen) and would've liked a pure vector math solution.

I'll try to adopt your code, but unfortunately I don't know exactly what is going on internally in your objects at some points, mainly in the Matrix4d objects.

PS: If you want to reply to an answer on StackOverflow as the creator of the question, are you supposed to make a comment to that answer, or is it OK to create a new 'answer'?

ok, forget about the perspective() function for now. You can also remove all of the code in lookat() for making the viewMatrix object. Strip it down to making the 'eye', 'view', 'right', and 'up' vectors. That said, you pretty much can't do ray-tracing without _some_ matrix math.
Alnitak
I've shortened the code myself - you should find it easier to understand now.
Alnitak
To answer the PS, don't make a new answer. Comment on the existing one.
Oddthinking
You can also edit your question and insert additional comments, if appropriate.
ShreevatsaR