Renegade Vile
Renegade Vile

Reputation: 157

Raytracer, computing viewing rays (Java)

For school, I have recently started creating my own raytracer. However, I've hit a snag with either computing the viewing rays, or checking for an intersection between a triangle and a ray. As far as I can tell, the computations seem to be executed correctly, as I place my camera in the origin and have it face the -z axis towards an object right in front of it, allowing for simple vector maths by hand. Everything seems to check out, but nothing gets painted on the screen.

I will post the code I am using the calculate the viewing rays.

public Ray generateRay(float nX, float nY , Point2f coordinates)
{
    // Compute l, r, b and t.
    Vector3f temp = VectorHelper.multiply(u, nX/2.0f);
    float r = temp.x + Position.x;
    temp = VectorHelper.multiply(u, -nX/2.0f);
    float l = temp.x + Position.x;
    temp = VectorHelper.multiply(v, nY/2.0f);
    float t = temp.y + Position.y;
    temp = VectorHelper.multiply(v, -nY/2.0f);
    float b = temp.y + Position.y;

    // Compute the u and v coordinates.
    float uCo = (l + (r - l) * (coordinates.x + 0.5f)/nX);
    float vCo = (b + (t - b) * (coordinates.y + 0.5f)/nY);

    // Compute the ray's direction.
    Vector3f rayDirection = VectorHelper.multiply(w, -FocalLength);
    temp = VectorHelper.add(VectorHelper.multiply(u, uCo), VectorHelper.multiply(v, vCo));
    rayDirection = VectorHelper.add(rayDirection, temp);
    rayDirection = VectorHelper.add(rayDirection, Position);
    rayDirection = VectorHelper.normalize(VectorHelper.add(rayDirection, temp));

    // Create and return the ray.
    return new Ray(Position, rayDirection);
}

The following code is what I use to calculate an intersection. It uses Cramer's Rule to solve the matrix equation.

public static Point3f rayTriangleIntersection(
        Ray ray, Point3f vertexA, Point3f vertexB, Point3f vertexC)
{
    // Solve the linear system formed by the ray and the parametric surface
    // formed by the points of the triangle.
    // | a d g |   | B |   | j |
    // | b e h | * | Y | = | k |
    // | c f i | * | t | = | l |
    // The following uses Cramer's rule to that effect.
    float a = vertexA.x - vertexB.x; float d = vertexA.x - vertexC.x; float g = ray.getDirection().x;
    float b = vertexA.y - vertexB.y; float e = vertexA.y - vertexC.y; float h = ray.getDirection().y;
    float c = vertexA.z - vertexB.z; float f = vertexA.z - vertexC.z; float i = ray.getDirection().z;

    float j = vertexA.x - ray.getOrigin().x;
    float k = vertexA.y - ray.getOrigin().y;
    float l = vertexA.z - ray.getOrigin().z;

    // Compute some subterms in advance.
    float eihf = (e * i) - (h * f);
    float gfdi = (g * f) - (d * i);
    float dheg = (d * h) - (e * g);
    float akjb = (a * k) - (j * b);
    float jcal = (j * c) - (a * l);
    float blkc = (b * l) - (k * c);
    // Compute common division number.
    float m = (a * eihf) + (b * gfdi) + (c * dheg);

    // Compute unknown t and check whether the point is within the given
    // depth interval.
    float t = -((f * akjb) + (e * jcal) + (d * blkc)) / m;
    if (t < 0)
        return null;

    // Compute unknown gamma and check whether the point intersects the
    // triangle.
    float gamma = ((i * akjb) + (h * jcal) + (g * blkc)) / m;
    if (gamma < 0 || gamma > 1)
        return null;

    // Compute unknown beta and check whether the point intersects the
    // triangle.
    float beta = ((j * eihf) + (k * gfdi) + (l * dheg)) / m;
    if (beta < 0 || beta > (1 - gamma))
        return null;

    // Else, compute the intersection point and return it.
    Point3f result = new Point3f();
    result.x = ray.getOrigin().x + t * ray.getDirection().x;
    result.y = ray.getOrigin().y + t * ray.getDirection().y;
    result.z = ray.getOrigin().z + t * ray.getDirection().z;
    return result;
}

My question is rather simple. What am I doing wrong? I've looked and debugged this code to death and cannot single out the errors, google offers little more than the theory I already have in the book I am using. Also, the code is still rather rough as I'm just focusing on getting it to work before cleaning it up.

Thanks in advance,

Kevin

Upvotes: 3

Views: 1129

Answers (1)

mikera
mikera

Reputation: 106351

Hard to say precisely what is going wrong. Especially since you aren't using descriptive variable names (what are nX, nY etc.??)

Here are some tips:

  • First make sure it's not a bug in your display code. Fake an intersection to prove that you get visible output when you hit something, e.g. make all rays in the bottom right of the screen hit an axis-aligned plane or something similar so that you can easily verify the co-ordinates
  • Try a ray/sphere intersection first. It's easier than a ray/triangle intersection.
  • Consider using vector/matrix operations rather than computing all the components by hand. It's too easy to make a mistake in many lines of jumbled letters.
  • If you have a scale problem (e.g. the object is too small) then double-check your conversions between world and screen co-ordinates. World co-ordinates will be in the range of small double numbers (0.2 ....5.0 for example) while screen co-ordinates should be pixel locations according to your view size (0 .. 1024 for example). You should be doing most of your maths in world co-ordinates, only converting from/to screen co-ordinates at the beginning and the end of your rendering code.
  • Step through the top level raytracing code in a debugger and make sure that you are producing rays in sensible directions for each screen co-ordinate(especially the corners of the screen)
  • Check that your camera direction is pointing towards the target object. It is quite an easy mistake to have it looking in exactly the opposite direction!

Example set-up that should work:

  • Camera position [0 0 4]
  • Object position [0 0 0]
  • Camera DIRECTION [0 0 -1] (note the minus if you want it to look towards the origin!)
  • UP vector [0 0.75 0]
  • RIGHT vector [+/-1 0 0]

Then your ray direction should be something like (for a pixel [screenX, screenY]):

ray = DIRECTION + (2*(screenX / screenWidth)-1)*RIGHT + (1-2*(screenY/screenHeight))*UP

ray = normalize(ray)

Upvotes: 1

Related Questions