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);
Вывод
Поскольку ive никогда не использовал glm :: unproject или gluUnproject, я не знаю, как должен выглядеть нормальный вывод, но получаю такие результаты:
Направление луча: 0,109035 -0,0380502 0,0114562
Мне это не кажется правильным, но, сравнивая свой код с другими источниками (упомянутыми выше), я не вижу ошибок.
Пересечение лучей работает в некоторых особых случаях (вращение камеры), и даже тогда я получаю пересечения, даже если я не нажимаю на пол. То же самое и с выходными данными пересечения, различающимися от попаданий на заднюю поверхность до точек за пределами треугольника.
Все эти ошибки выглядят так, будто основной источник проблемы - это непредсказуемость.
Есть какие-нибудь подсказки в правильном направлении?
unproject
не возвращает направление, а возвращает точку. Когда вы возвращаете некоторую точку на ближней плоскости в мировое пространство с помощью inv (proj * biew), вы получаете координату этой точки в мировом пространстве. Вам нужно вычесть положение камеры в мировом пространстве, чтобы получить направление луча. - person derhass   schedule 30.12.2013UnProject
функции? Если бы вы следовали glm и GLU, вы, вероятно, заметили бы, что они используют матрицу ModelView и дают вам координаты объект-пространство. Вы действительно используете в этом примере только матрицу представления? И ваш расчет координат NDC далек от того, Y инвертирован, а Z неправильно настроен для диапазона глубин. Z должно быть 2 * глубина - 1.0, потому что глубина в NDC колеблется от [-1,1] вместо [0,1] (диапазон глубины по умолчанию) в пространстве окна. - person Andon M. Coleman   schedule 30.12.2013View * Model
(чтение умножения матриц справа налево). - person Andon M. Coleman   schedule 30.12.2013floor
вводится в это обсуждение, это будет матрица преобразования для одного объекта в вашей сцене. Если у вас нет преобразования объекта в мир, который применяется к каждому объекту (это было бы объединено в матрицу ModelView), тогда вы можете просто использовать матрицу просмотра, как и изначально. Учитывая луч (в настоящее время обратный), который вы отбрасываете, вам необходимо добавить его начало координат в точку вашего взгляда (в мировом пространстве) и проверить пересечение с каждым объектом (после применения их матриц объекта-мира). - person Andon M. Coleman   schedule 30.12.2013