Настройка луча (начало координат, направление) и пересечения треугольника (без glm)

Edit3: мои проблемы были в совершенно других функциях, чем я ожидал. пусть код останется, может быть, это кому-нибудь поможет 🙂 (и не забудьте отладить!).

Я пытаюсь найти вектор, где линия пересекается с треугольником.

Текущее состояние: случайные пересечения, даже если мышь не находится на полу и вид с камеры зависит (матрица обзора)

меры

  1. Отпроектировать координаты мыши
  2. Проверьте пересечение линии / треугольника

Отпроектировать координаты мыши

Я проверил источник glm :: unproject и gluUnproject и создал эту функцию.

   pixel::CVector3 pixel::CVector::unproject(
CVector2 inPosition,
pixel::CShape window,
pixel::matrix4 projectionMatrix,
pixel::matrix4 modelViewMatrix,
float depth
)
{
// transformation of normalized coordinates
CVector4 inVector;
inVector.x = (2.0f * inPosition.x) / window.width - 1.0f;
inVector.y = (2.0f * inPosition.y) / window.height - 1.0f;
inVector.z = 2.0f * depth - 1.0f;
inVector.w = 1.0f;

// multiply inverted matrix with vector
CVector4 rayWorld = pixel::CVector::multMat4Vec4(pixel::CMatrix::invertMatrix(projectionMatrix * modelViewMatrix), inVector);

CVector3 result;
result.x = rayWorld.x / rayWorld.w;
result.y = rayWorld.y / rayWorld.w;
result.z = rayWorld.z / rayWorld.w;return result;
}

Проверка пересечения

pixel::CVector3 pixel::Ray::intersection(
Ray ray,
pixel::CVector3 v0,
pixel::CVector3 v1,
pixel::CVector3 v2
)
{
// compute normal
CVector3 a, b, n;
a = v1 - v0;
b = v2 - v0;

n = ray.direction.cross(b);

// find determinant
float det = a.dot(n);

if (det < 0.000001f)
{
std::cout << "Ray intersecting with backface triangles \n";
return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
}
det = 1.0f / det;

// calculate distance from vertex0 to ray origin
CVector3 s = ray.origin - v0;
float u = det * s.dot(n);

if (u < -0.000001f || u > 1.f + 0.000001f)
{
std::cout << "U: Intersection outside of the triangle!\n";
return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
}

CVector3 r = s.cross(a);
float v = det * ray.direction.dot(r);
if (v < -0.000001f || u + v > 1.f + 0.000001f)
{
std::cout << "V/U: Intersection outside of triangle!\n";
return pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
}

// distance from ray to triangle
det = det *  b.dot(r);

std::cout << "T: " << det << "\n";

CVector3 endPosition;
endPosition.x = ray.origin.x + (ray.direction.x * det);
endPosition.y = ray.origin.y + (ray.direction.y * det);
endPosition.z = ray.origin.z + (ray.direction.z * det);

return endPosition;
}

использование

    if (event.button.button == SDL_BUTTON_RIGHT)
{

camera->setCameraActive();
float mx = event.motion.x;
float my = window->info.height - event.motion.y;
// ray casting
pixel::Ray ray;

std::cout << "\n\n";

// near
pixel::CVector3 rayNear = pixel::CVector::unproject(
pixel::CVector::vector2(mx, my),
pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
camera->camInfo.currentProjection,
camera->camInfo.currentView,
1.0f
);
// far
pixel::CVector3 rayFar = pixel::CVector::unproject(
pixel::CVector::vector2(mx, my),
pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
camera->camInfo.currentProjection,
camera->camInfo.currentView,
0.0f
);// normalized direction results in the same behavior
ray.origin = cameraPosition;

ray.direction = pixel::CVector::normalize(rayFar- rayNear);

std::cout << "Raycast \n";
std::cout << "Mouse Position: " << mx << " - " << my << "\n";
std::cout << "Camera Position: " << ray.origin.x << " - " << ray.origin.y << " - " << ray.origin.z << "\n";
std::cout << "Ray direction: " << ray.direction.x << " - " << ray.direction.y << " - " << ray.direction.z << "\n";pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);pixel::CVector3 rayHit = pixel::Ray::intersection(ray, vertOne, vertTwo, vertThree);
pixel::CVector3 rayHit2 = pixel::Ray::intersection(ray, vertThree, vertFour, vertOne);
std::cout << "Ray hit: " << rayHit.x << " - " << rayHit.y << " - " << rayHit.z << "\n";
std::cout << "Ray hit: " << rayHit2.x << " - " << rayHit2.y << " - " << rayHit2.z << "\n";
std::cout << "--------------------\n";
towerHouse->modelMatrix = pixel::CMatrix::translateMatrix(rayHit);

Выход

Поскольку я никогда не использовал glm :: unproject или gluUnproject, я не знаю, как должен выглядеть нормальный вывод, но я получаю такие результаты:

Направление луча: 0.109035 -0.0380502 0.0114562

Не выглядит правильным для меня, но проверяя мой код по другим источникам (упомянутым выше), я не вижу ошибки / s.

Пересечение лучей работает в некоторых особых случаях (вращение камеры), и даже тогда я получаю пересечения, даже если я не нажимаю на пол.
То же самое относится и к выходным данным пересечения, варьирующимся от попаданий на заднюю поверхность за пределы треугольника.

Все эти ошибки выглядят так, будто основным источником проблемы является непроекция.

Любые намеки в правильном направлении?

3

Решение

Это нигде не близко к ответу на этот вопрос, но это слишком сложно объяснить в комментариях или чате.

Прежде всего:

            // near
pixel::CVector3 rayNear = pixel::CVector::raycast(
pixel::CVector::vector2(mx, my),
pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
camera->camInfo.currentProjection,
camera->camInfo.currentView,
1.0f // WRONG
);
// far
pixel::CVector3 rayFar = pixel::CVector::raycast(
pixel::CVector::vector2(mx, my),
pixel::CVector::shape2(window->info.internalWidth, window->info.internalHeight),
camera->camInfo.currentProjection,
camera->camInfo.currentView,
0.0f // WRONG
);

Рядом находится 0.0 в окне-пространстве, и далеко 1,0 (зависит от диапазона глубины, но если вы изменили диапазон глубины, вы должны это знать).

В вашей функции приведения лучей у вас есть:

CVector3 result;
result.x = rayWorld.x / rayWorld.w;
result.y = rayWorld.y / rayWorld.w;
result.z = rayWorld.z / rayWorld.w;

Есть шанс, что w == 0.0и результат еще не луч в это время … это позиция в Объект-пространство (не мир). Как правило, вы всегда будете работать с матрицами с хорошим поведением, но если вы когда-нибудь посмотрите на формальную реализацию UnProject (...) вы заметите, что они обрабатывают случай, когда w == 0.0 со специальным возвращаемым значением или установив флаг состояния.

            pixel::CVector3 vertOne = pixel::CVector::vector3(0.0f, 0.0f, -300.0f);
pixel::CVector3 vertTwo = pixel::CVector::vector3(0.0f, 0.0f, 0.0f);
pixel::CVector3 vertThree = pixel::CVector::vector3(300.0f, 0.0f, 0.0f);
pixel::CVector3 vertFour = pixel::CVector::vector3(300.0f, 0.0f, -300.0f);

В каком координатном пространстве находятся эти вершины? Предположительно объект-пространство, что означает, что если вы отбрасываете луч из точки глаза вашей камеры (определенной в мировом пространстве), которая проходит через точку на вашей дальней плоскости, и пытаетесь чаще проверять пересечение с треугольником в объектном пространстве чем не скучаешь. Это потому, что начало, масштаб и поворот для каждого из этих пространств могут отличаться. Вам нужно преобразовать эти точки в мировое пространство (ваш исходный код имел floor->modelMatrix это будет хорошо работать для этой цели), прежде чем попробовать этот тест.

1

Другие решения

Я выследил проблему и исправил ошибки. у меня были неправильные матрицы * матрица и матрица * операторы умножения вектора.

1

По вопросам рекламы [email protected]