3D Ray Picking использует координаты мыши, когда мышь не заблокирована
Итак, в основном я создал программу с использованием OpenGL, которая может выполнять 3D-подбор лучей. Если Camera View Direction Ray
касается/пересекает что-либо (что не является воздухом), тогда в точке пересечения/точках будет отображаться немного фиолетового поля.
Если луч пересекается с любым из "красных ящиков", один раз, пересекающийся с лучом, станет зеленым. Земля и стены не изменят цвет или текстуру вообще.
Примеры:
![]()
Текущий способ, которым я занимаюсь 3D Ray Picking, получает луч направления обзора камеры, а затем просто вычисляет для пересечений. Моя функция вычисления пересечений не возвращается как логическая, она возвращается как 3D-вектор (координаты самого пересечения)
Вопрос
То, что я пытаюсь достичь, - это рассчитать Picking Ray, но в соответствии с мышью, когда не заблокирован на экране.
Пример. Итак, вы можете видеть, что фиолетовая коробка находится на перекрестье, хотя если бы я разблокировал мышь и переместил ее (поверх экрана, как обычно) и переместил ее к центру зеленой метки X, которую я рисую, тогда я хочу рассчитать луч от центра камеры к координате мыши сверху экрана.
![]()
Текущие тесты и идеи
Это должна быть математическая проблема. Вот лишь краткий список вещей, которые я сейчас использую для вычисления луча (и пытается рассчитать второй луч)
- Cameara X, Y, Z
- Камера Pitch Yaw Roll (Roll не используется прямо сейчас)
- Камера рядом с дальним (расстояния)
- Камера Fov
- Аспект камеры
- Мышь X, Y (В верхней части экрана)
- Ширина Sceen, Высота
Мышь X и Y origin (0x0) находится в левом нижнем углу окна/кадра.
Вычисление самого самого самого собирающего луча
Vector3D position = new Vector3D(
camera.x,
camera.y,
camera.z);
Vector3D direction = new Vector3D(
Math.cos(Math.toRadians(camera.pitch)) * -Math.sin(Math.toRadians(-camera.yaw)) * camera.far,
Math.cos(Math.toRadians(camera.pitch)) * cameara.far,
Math.cos(Math.toRadians(camera.pitch)) * -Math.sin(Math.toRadians(-camera.yaw)) * camera.far);
direction.normalize();
Ray3D ray = new Ray(position, direction);
Вот как я вычисляю сам основной луч отбора (луч для захвата запертой мыши). Я сам делал классы, хотя они должны иметь смысл (Vector3D
, Ray3D
и т.д.), А методы normalize()
делают именно то, что он говорит, нормализует вектор.
Идея
Итак, когда я попытался вычислить с помощью координат мыши, я вставил следующий код прямо перед тем, как позвонить direction.normalize();
, поэтому сразу после создания Vector3D direction
.
if (!Mouse.isGrabbed())
{
float mx = Mouse.getX() / (float) scene.width - 0.5f;
float my = Mouse.getY() / (float) scene.height - 0.5f;
mx *= camera.far;
my *= camera.far;
line.b.x += mx;
line.b.y += my;
line.b.z += mz;
}
Это дает мне странный результат, когда мышь не заблокирована/схвачена. Это имеет смысл, так как я просто возился и пытался кое-что из того, что было первым в моей голове.
Я предполагаю, что мне нужно перевести координаты мыши в соответствии с шагом, рыскангом и рулоном. Хотя я и не знаю, как бы я это сделал.
Поэтому я надеюсь, что есть кто-то, кто может помочь мне достичь этого и/или дать мне какой-то ресурс, чтобы я мог понять, как делать то, что я пытаюсь сделать.
Extra
Если вам нужна дополнительная информация об этом, просто напишите комментарий, и я сделаю все возможное.
Ответ - благодаря fen
В итоге я использовал fen, так как это было намного проще, чем вычислять все!
FloatBuffer projection = BufferTools.createFloatBuffer(16);
FloatBuffer modelview = BufferTools.createFloatBuffer(16);
IntBuffer viewport = BufferTools.createIntBuffer(16);
glGetFloat(GL_PROJECTION_MATRIX, projection);
glGetFloat(GL_MODELVIEW_MATRIX, modelview);
glGetInteger(GL_VIEWPORT, viewport);
float win_x = Mouse.getX();
float win_y = Mouse.getY();
FloatBuffer position_near = BufferTools.createFloatBuffer(3);
FloatBuffer position_far = BufferTools.createFloatBuffer(3);
gluUnProject(win_x, win_y, 0f, modelview, projection, viewport, position_near);
gluUnProject(win_x, win_y, 1f, modelview, projection, viewport, position_far);
Ray3D ray = new Ray3D(
new Vector3D(
position_near.get(0),
position_near.get(1),
position_near.get(2)),
new Vector3D(
position_far.get(0),
position_far.get(1),
position_far.get(2)));
Ответы
Ответ 1
вот мой код для создания луча мыши:
double matModelView[16], matProjection[16];
int viewport[4];
// get matrix and viewport:
glGetDoublev( GL_MODELVIEW_MATRIX, matModelView );
glGetDoublev( GL_PROJECTION_MATRIX, matProjection );
glGetIntegerv( GL_VIEWPORT, viewport );
// window pos of mouse, Y is inverted on Windows
double winX = (double)mouseX;
double winY = viewport[3] - (double)mouseY;
// get point on the 'near' plane (third param is set to 0.0)
gluUnProject(winX, winY, 0.0, matModelView, matProjection,
viewport, m_start.x, &m_start.y, &m_start.z);
// get point on the 'far' plane (third param is set to 1.0)
gluUnProject(winX, winY, 1.0, matModelView, matProjection,
viewport, m_end.x, &m_end.y, &m_end.z);
// now you can create a ray from m_start to m_end
OpenGL 2.0, но надеюсь, что вы получите эту идею.
Некоторые ссылки: Выбрать + Mouse + OpenGL
Ответ 2
Все, что вам нужно сделать, это снять луч из источника камеры, который проходит через точку пространства экрана (x, y). Проблема заключается в том, что для перехода от источника вашей камеры к точке в пространстве экрана существует ряд преобразований, которые обычно встречаются (на самом деле, 2 матрицы и отображение видового экрана). Другая проблема заключается в том, что это бросает все на голову, обычно вы начинаете с позиции мирового пространства и заканчиваете пространство экрана в конвейере OpenGL - вы хотите пойти другим путем:)
Вы не можете решить эту проблему только с ориентацией камеры. Вам нужно знать, как сцена проецируется на вашу плоскость просмотра, следовательно, нужна матрица проецирования. Вам также необходимо знать размеры видовых экранов и происхождение камеры. Вся проблема может быть решена, если вы знаете размеры видовых экранов, матрицу проекции и матрицу вида.
Я предлагаю вам заглянуть в gluUnProject (...)
, он сделает все, что вам нужно. Быстрый поиск в Google привел к этому, что выглядит довольно полезно: http://myweb.lmu.edu/dondi/share/cg/unproject-explained.pdf