Проблемы с простым raytracer в C++
В основном он проверяет наличие столкновений с массивом треугольников и рисует изображение, основываясь на цвете треугольника, в который он попадает. Я думаю, что моя проблема заключается в обнаружении столкновений. Код здесь:
for (int 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;
if (x.x > 0 && x.y > 0 && (x.x + x.y < 1) && (x.z - start.z>= 0)){
return true;
}
}
... где "dir" - это направление луча, исходящего из камеры, вычисляемое как "x - SCREEN_WIDTH / 2, y - SCREEN_HEIGHT / 2, focalLength". SCREEN_WIDTH, SCREEN_HEIGHT и focalLength являются константами. Старт - это положение камеры, установленное на 0,0,0.
То, в чем я не уверен, так это то, что на самом деле х и что я должен проверить, прежде чем возвращать true. Предполагается, что "xx > 0 && xy > 0 && (xx + xy <1)" проверяет, попадает ли луч не только в ту же плоскость, но и внутри треугольника, и в последнюю часть ("xz - start.z>=" 0", тот, в котором я менее всего уверен), если столкновение произошло перед камерой.
Я получаю изображения, но как бы я ни старался, это никогда не правильно. Предполагается, что это классическая модель TestModel для комнаты с разноцветными стенами и двумя формами. Я думаю, что ближе всего я получаю четыре из пяти правильных стен, при этом отсутствует одна дальняя и часть одной из фигур на другой стороне.
1 ответ
Я не знаком с формулировкой матрицы для пересечения треугольника - это звучит довольно дорого.
Мой собственный код ниже, где мой e1
а также e2
эквивалентны вашим - то есть они представляют векторы ребер из v0
в v1
а также v2
соответственно:
// NB: triangles are assumed to be in world space
vector3 pvec = vector3::cross(ray.direction(), e2);
double det = e1.dot(pvec);
if (::fabs(det) < math::epsilon) return 0;
double invDet = 1.0 / det;
vector3 tvec(p0, ray.origin());
double u = tvec.dot(pvec) * invDet;
if (u < 0 || u > 1) return 0;
vector3 qvec = vector3::cross(tvec, e1);
double v = ray.direction().dot(qvec) * invDet;
if (v < 0 || u + v > 1) return 0;
double t = e2.dot(qvec) * invDet;
if (t > math::epsilon) { // avoid self intersection
// hit found at distance "t"
}
Я подозреваю, что проблема в вашем расчете вектора луча, который должен быть нормализован.