OpenGL Math - Проецирование экранного пространства на мировые космические координаты

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

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

<0,0> <1024,768>

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

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

3 ответа

Решение

ПОСТАНОВИЛИ

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

0) Получите ваши координаты мыши в клиентской области

1) Получите матрицу проекции и матрицу просмотра, если матрица модели не требуется.

2) Multiply Projection * Просмотр

3) Инвертировать результаты умножения

4) Построить вектор4, состоящий из

х = mouseposition.x в пределах диапазона окна x - преобразование в значения между -1 и 1

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

z = the depth value (это можно получить с помощью glReadPixel) - вы можете вручную перейти от -1 к 1 ( zNear, zFar)

W = 1.0

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

6) Разделите вектор результата на его 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);

Мне пришлось внести некоторые коррективы в приведенные здесь ответы. Но вот код, который у меня получился (обратите внимание, я использую 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);
}

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

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

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

Другие вопросы по тегам