Таинственная проблема с минимальным трассировщиком лучей в C - PullRequest
0 голосов
/ 10 ноября 2019

Я работаю над минимальным трассировщиком лучей в C, и некоторое время назад я написал лучевой трассировщик, поэтому я понимаю теорию, стоящую за ними, просто хотел переписать для целей очистки.

У меня есть необходимые элементы для трассировки лучей, и ничего более. Я написал пересечение треугольников, преобразовывая координаты пространства пикселей в NDC (с учетом соотношения сторон и FOV), и записывая буфер кадров.

Однако он не работает должным образом. Изображение полностью черное, когда оно должно отображать один треугольник. Я тестировал написание одного тестового пикселя, и он отлично работает, поэтому я знаю, что это не проблема с кодом написания изображений.

Я дважды и трижды проверил код за математикой, и он выглядит хорошо для меня. Код пересечения, по сути, является дубликатом исходного кода в оригинальной статье Moller-Trumbore:

/* 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 и SUB являются просто макросами:

#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];

Код преобразования выглядит следующим образом:

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);

И 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);
}

Буду признателен за любую помощь.

1 Ответ

3 голосов
/ 12 ноября 2019

Попробуйте поменять ориентацию вашего треугольника. Ваш код пересечения луч-треугольник отбраковывает задние грани, потому что он возвращается рано, когда det отрицательно.

...