3
$\begingroup$

So I have a vector of glm::vec3 containing the triangles for the classic Cornell Box called triangles. The Draw method casts a ray for each pixel on the screen and calls ClosestIntersection which returns true or false and updates a struct containing things like colour and the point of that intersection. Then I simply draw the pixels based on the colours (black for no intersection).

The result is very inconsistent and I can't find the error: enter image description here

void Draw()
{
    if (SDL_MUSTLOCK(screen))
        SDL_LockSurface(screen);

    // Loop through each pixel and cast ray
    for (int y = 0; y<SCREEN_HEIGHT; ++y)
    {
        for (int x = 0; x<SCREEN_WIDTH; ++x)
        {
            vec3 dir(x - SCREEN_WIDTH / 2, y - SCREEN_HEIGHT / 2, focalLength);
            Intersection isect;
            if (ClosestIntersection(cameraPos, dir, triangles, isect))
            {
                vec3 color = triangles[isect.triangleIndex].color;
                PutPixelSDL(screen, x, y, color);
            }
            else
            {
                PutPixelSDL(screen, x, y, vec3(1, 1, 1));
            }
        }
    }

    if (SDL_MUSTLOCK(screen))
        SDL_UnlockSurface(screen);

    SDL_UpdateRect(screen, 0, 0, 0, 0);
}

This is the function called from Draw:

bool ClosestIntersection(vec3 start,
    vec3 dir,
    const vector<Triangle>& triangles,
    Intersection& closestIntersection)
{
    bool foundIntersection = false;

    // Loop through all the triangles and check for intersection with ray
    for (size_t i = 0; i < triangles.size(); i++)
    {
        vec3 v0 = triangles[i].v0;
        vec3 v1 = triangles[i].v1;
        vec3 v2 = triangles[i].v2;
        vec3 e1 = v1 - v0;
        vec3 e2 = v2 - v0;
        vec3 b = start - v0;
        mat3 A(-dir, e1, e2);
        vec3 x = glm::inverse(A) * b;

        // Check that found scalars are within bounds
        if ((x.x >= 0) && (x.y > 0) && (x.z > 0) && (x.y + x.z < 1))
        {
            if (foundIntersection)  // If there's a previvous intersection for this ray check that new one is closer to camera
            {
                if (glm::distance(start, x) < closestIntersection.distance)
                {
                    closestIntersection.distance = glm::distance(start, x);
                    closestIntersection.triangleIndex = i;
                    closestIntersection.position = x;
                }
            }
            else
            {
                foundIntersection = true;
                closestIntersection.distance = glm::distance(start, x);
                closestIntersection.triangleIndex = i;
                closestIntersection.position = x;
            }
        }
    }
    return foundIntersection;
}
$\endgroup$
0

1 Answer 1

4
$\begingroup$

Two symptoms

There appear to be two problems with the image.

  1. The background is showing through along the line between adjacent triangles.
  2. The colour displayed is not always from the closest intersection.

Note that the background colour is white, rather than black, due to the line:

                PutPixelSDL(screen, x, y, vec3(1, 1, 1));

Why this background shows through at the triangle edges I do not know. However, the second problem is identified below, so I recommend you fix that first and then the first problem can be analysed in isolation without the additional distractions.


Cause of the problem with ClosestIntersection

The ClosestIntesection function returns true when an intersection is found, and updates an Intersection object called closestIntersection. However, the intersection stored here is not always the closest to the camera.

The reason for this is here:

                closestIntersection.distance = glm::distance(start, x);

This appears in two places so it will need to be fixed in both.

start is cameraPos, presumably in world coordinates. x appears to be in the local coordinates of the triangle being intersected (one of the triangle vertices being the origin). The distance between two points in different coordinate systems is meaningless, so that in different regions of a triangle it will appear to be behind or in front of another triangle for no immediately apparent reason.

If x is first converted to world coordinates then the distance will be correct and the intersection chosen will be the closest to the camera.

$\endgroup$
1
  • 2
    $\begingroup$ Thanks! You were right, but I should also make note for future readers that I had misunderstood the inverse of the matrix. What I got from that inverse matrix (variable called x) was actually 3 scalars, not a coordinate. Think about that and everything else will click once this is realized. The first value (x.x) is actually the scalar distance from the start vector along the direction vector where the intersection occurs! $\endgroup$ Apr 29, 2016 at 22:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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