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