OpenGL Math - 为世界空间坐标投影屏幕空间

Pee*_*eeS 15 opengl math matrix

是时候进行一些数学计算了...

我需要预测窗口大小的4个点:

<0,0> <1024,768>

进入一个世界空间坐标,它将形成一个四边形的形状,以后将用于地形剔除 - 没有GluUnproject

仅供测试,我使用鼠标坐标 - 并尝试将它们投射到世界坐标上

Pee*_*eeS 31

解决

这是如何准确地,一步一步地做到这一点.

0)在客户区域内获取鼠标坐标

1)如果不需要模型矩阵,请获取投影矩阵和视图矩阵.

2)乘法投影*查看

3)反转乘法的结果

4)构造一个由4组成的vector4

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

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);
Run Code Online (Sandbox Code Playgroud)

  • 为什么要通过viewMatrix*projectMatrix计算投影而不是projectMatrix*viewMatrix? (5认同)

cra*_*jul 7

将所有矩阵相乘.然后反转结果.投影后的点总是在-1,1.所以四角屏幕点是-1,-1; 1,1; 1,-1; 1,1.但是你仍然需要选择z值.如果你在OpenGL中,z介于-1和1之间.对于directx,范围是0到1.最后取点并用矩阵转换它们


小智 6

我不得不对这里提供的答案进行一些调整。但这是我最终得到的代码(注意我使用的是 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);
}
Run Code Online (Sandbox Code Playgroud)