Edit3: мои проблемы были в совершенно других функциях, чем я ожидал. пусть код останется, может быть, это кому-нибудь поможет 🙂 (и не забудьте отладить!).
Я пытаюсь найти вектор, где линия пересекается с треугольником.
Текущее состояние: случайные пересечения, даже если мышь не находится на полу и вид с камеры зависит (матрица обзора)
меры
Отпроектировать координаты мыши
Я проверил источник 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.
Пересечение лучей работает в некоторых особых случаях (вращение камеры), и даже тогда я получаю пересечения, даже если я не нажимаю на пол.
То же самое относится и к выходным данным пересечения, варьирующимся от попаданий на заднюю поверхность за пределы треугольника.
Все эти ошибки выглядят так, будто основным источником проблемы является непроекция.
Любые намеки в правильном направлении?
Это нигде не близко к ответу на этот вопрос, но это слишком сложно объяснить в комментариях или чате.
Прежде всего:
// 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
это будет хорошо работать для этой цели), прежде чем попробовать этот тест.
Я выследил проблему и исправил ошибки. у меня были неправильные матрицы * матрица и матрица * операторы умножения вектора.