OpenGL Math - Проецирование экранного пространства на мировые космические координаты - PullRequest
15 голосов
/ 08 октября 2011

Время немного математики на конец дня.

Мне нужно спроецировать 4 точки размера окна :

<0,0> <1024,768>

В координаты мирового пространства , поэтому он будет образовывать четырехугольную форму, которая впоследствии будет использоваться для отбора ландшафта - без GluUnproject

Только для теста, я использую координаты мыши - и пытаюсь спроецировать их на мировые координаты

Ответы [ 4 ]

31 голосов
/ 09 октября 2011

РАЗРЕШЕНО

Вот как это сделать точно, шаг за шагом.

  1. Получите координаты мыши в пределах клиентской области
  2. Получите матрицу проекции и матрицу просмотра, если матрица модели не требуется.
  3. Умножение проекции * Просмотр
  4. Инверсия результатов умножения
  5. Построение вектора4, состоящего из

    x = mouseposition.x в пределах диапазона окна x

    • преобразовать в значения между -1 и 1

    y = mouseposition.y в пределах диапазона окна y

    • преобразовать в значения между -1 и 1
    • не забудьте инвертировать mouseposition.y при необходимости

    z = the depth value (это можно получить с помощью glReadPixel)

    • вы можете вручную перейти от -1 к 1 (zNear, zFar)

    w = 1.0

  6. Умножить вектор на обратную матрицу, созданную до

  7. Разделить результатвектор этимW-компонент после умножения матрицы (деление перспективы)

        POINT mousePos;
        GetCursorPos(&mousePos);
        ScreenToClient( this->GetWindowHWND(), &mousePos );         
    
        CMatrix4x4 matProjection = m_pCamera->getViewMatrix() *  m_pCamera->getProjectionMatrix() ;
    
        CMatrix4x4 matInverse =  matProjection.inverse();
    
    
        float in[4];
        float winZ = 1.0;
    
    
        in[0]=(2.0f*((float)(mousePos.x-0)/(this->GetResolution().x-0)))-1.0f,
        in[1]=1.0f-(2.0f*((float)(mousePos.y-0)/(this->GetResolution().y-0)));
        in[2]=2.0* winZ -1.0;
        in[3]=1.0;          
    
        CVector4 vIn = CVector4(in[0],in[1],in[2],in[3]);
        pos = vIn * matInverse;
    
        pos.w = 1.0 / pos.w;
    
        pos.x *= pos.w;
        pos.y *= pos.w;
        pos.z *= pos.w;
    
        sprintf(strTitle,"%f %f %f / %f,%f,%f ",m_pCamera->m_vPosition.x,m_pCamera->m_vPosition.y,m_pCamera->m_vPosition.z,pos.x,pos.y,pos.z);
    
        SetWindowText(this->GetWindowHWND(),strTitle);
    
7 голосов
/ 08 октября 2011

Умножьте все свои матрицы.Затем инвертируйте результат.Точки после проекции всегда находятся в -1,1.Итак, четыре угловые точки экрана: -1, -1;-1,1;1, -1; 1,1.Но вам все равно нужно выбрать значение z z.Если вы находитесь в OpenGL, z находится в диапазоне от -1 до 1. Для directx диапазон составляет от 0 до 1. Наконец, возьмите свои точки и преобразуйте их с помощью матрицы

3 голосов
/ 08 октября 2011

Если у вас есть доступ к библиотекам glu, используйте gluUnProject (winX, winY, winZ, модель, проекция, область просмотра, & objX, & objY, & objZ);

winX иwinY будет углами вашего экрана в пикселях.winZ - это число в [0,1], которое будет указывать, где между zNear и zFar (плоскости отсечения) должны падать точки.objX-Z будет содержать результаты.Средние переменные являются соответствующими матрицами.Они могут быть запрошены при необходимости.

0 голосов
/ 28 мая 2019

Мне пришлось внести некоторые коррективы в ответы, представленные здесь. Но вот код, с которым я закончил (обратите внимание, я использую GLM, это может повлиять на порядок умножения). nearResult - это спроецированная точка на ближней плоскости, а farResult - спроецированная точка на далекой плоскости. Я хочу выполнить приведение лучей, чтобы увидеть, на что наведена моя мышь, поэтому я преобразую их в вектор направления, который будет исходить из положения моей камеры.

vec3 getRayFromScreenSpace(const vec2 & pos)
{
    mat4 invMat= inverse(m_glData.getPerspective()*m_glData.getView());
    vec4 near = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, -1, 1.0);
    vec4 far = vec4((pos.x - Constants::m_halfScreenWidth) / Constants::m_halfScreenWidth, -1*(pos.y - Constants::m_halfScreenHeight) / Constants::m_halfScreenHeight, 1, 1.0);
    vec4 nearResult = invMat*near;
    vec4 farResult = invMat*far;
    nearResult /= nearResult.w;
    farResult /= farResult.w;
    vec3 dir = vec3(farResult - nearResult );
    return normalize(dir);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...