0

I'm working on a minimal ray tracer in C, and I've written a ray tracer a little while ago so I understand the theory behind them, just wanted to do a rewrite for cleanup purposes.

I have the necessary elements for a ray tracer, and nothing more. I've written triangle intersection, transforming pixel space coordinates to NDC (with aspect ratio and FOV accounted for), and writing out the frame buffer.

However, it does not work as expected. The image is entirely black when it should be rendering a single triangle. I've tested writing a single test pixel, and it works fine so I know it isn't an issue with the image writing code.

I've double and triple-checked the code behind the math, and it looks fine to me. Intersection code is basically a duplicate of the source code in the original Moller-Trumbore paper:

/* ray triangle intersection */
bool ray_triangle_intersect(double orig[3], double dir[3], double vert0[3],
    double vert1[3], double vert2[3], double* t, double* u, double* v) {
    double edge1[3], edge2[3];
    double tvec[3], pvec[3], qvec[3];
    double det, inv_det;

    /* edges */
    SUB(edge1, vert1, vert0);
    SUB(edge2, vert2, vert0);

    /* determinant */
    CROSS(pvec, dir, edge2);

    /* ray in plane of triangle if near zero */
    det = DOT(edge1, pvec);

    if(det < EPSILON)
        return 0;

    SUB(tvec, orig, vert0);

    inv_det = 1.0 / det;

    /* calculate, check bounds */
    *u = DOT(tvec, pvec) * inv_det;
    if(*u < 0.0 || *u > 1.0)
        return 0;

    CROSS(qvec, tvec, edge1);

    /* calculate, check bounds */
    *v = DOT(dir, qvec) * inv_det;
    if(*v < 0.0 || *u + *v > 1.0)
        return 0;

    *t = DOT(edge2, qvec) * inv_det;

    return 1;
}

CROSS, DOT, and SUB are just macros:

#define CROSS(v,v0,v1) \
    v[0] = v0[1] * v1[2] - v0[2] * v1[1]; \
    v[1] = v0[2] * v1[0] - v0[0] * v1[2]; \
    v[2] = v0[0] * v1[1] - v0[1] * v1[0];

#define DOT(v0,v1) (v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2])

/* v = v0 - v1 */
#define SUB(v,v0,v1) \
    v[0] = v0[0] - v1[0]; \
    v[1] = v0[1] - v1[1]; \
    v[2] = v0[2] - v1[2];

Transformation code is as follows:

double ndc[2];
screen_to_ndc(x, y, &ndc[0], &ndc[1]);

double dir[3];

dir[0] = ndc[0] * ar * tfov;
dir[1] = ndc[1] * tfov;
dir[2] = -1;

norm(dir);

And screen_to_ndc:

void screen_to_ndc(unsigned int x, unsigned int y, double* ndcx, double* ndcy) {
    *ndcx = 2 * (((double) x + (1.0 / 2.0)) / (double) WIDTH) - 1;
    *ndcy = 1 - 2 * (((double) y + (1.0 / 2.0)) / (double) HEIGHT);
}

Any help would be appreciated.

reeeee
  • 139
  • 10
  • Try to debug it with a debugger tool. – Serge Nov 10 '19 at 12:23
  • If you could site a part of my code where a system error might occur that would be helpful. I don't believe the error would be anything a debugger could detect, as it doesn't segfault or anything like that. – reeeee Nov 10 '19 at 12:26
  • 1
    Debuggers aren’t limited to segfaults. You can step through to a call you expect to return true, then go line by line and look at the values of variables and how control flows to find out what the difference is from your expectation. – Ry- Nov 10 '19 at 13:02
  • 2
    `v0[2] + v1[2]` in `DOT` doesn’t look right, though. – Ry- Nov 10 '19 at 13:05
  • 1
    @reeeee debuggers are for examining values of variables step by step and for checking execution flow of your program. You can also use print statements for similar purposes. Without mastering debugging techniques you will never master programming. – Serge Nov 10 '19 at 14:49
  • Thanks for the help. I fixed ```DOT```, no immediate change. I'll step through with a debugger and see if I can find anything. – reeeee Nov 10 '19 at 20:02
  • @reeeee add `{ }` to your multi-line macros !!! it will spare you headaches latter on ... Is your triangle in view of your camera? do any rays intersect? You can extract the intersection code from here [Reflection and refraction impossible without recursive ray tracing?](https://stackoverflow.com/a/45140313/2521214) and compare against working code (however its GLSL based and iterative instead of recursive) – Spektre Nov 11 '19 at 08:53
  • also your NDC are `<-1,+1>` or `<0,+1>` or what? – Spektre Nov 11 '19 at 09:33
  • Yes, NDC are <-1, +1>. The issue was with culling backfacing triangles. – reeeee Nov 11 '19 at 22:40

1 Answers1

4

Try reversing the orientation of your triangle. Your ray-triangle intersection code culls backfaces because it returns early when det is negative.

prideout
  • 2,895
  • 1
  • 23
  • 25