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

时间:2011-10-07 21:22:20

标签: math opengl matrix

在一天结束时进行一些数学运算的时间..

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

< 0,0> < 1024,768>

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

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

4 个答案:

答案 0 :(得分:32)

<强>分辨

以下是如何准确地执行此操作。

  1. 在客户区域内获取鼠标坐标
  2. 如果不需要模型矩阵,请获取投影矩阵和视图矩阵。
  3. Multiply Projection *查看
  4. 反转乘法结果
  5. 构造一个由

    组成的vector4 窗口x

    范围内的

    x = mouseposition.x

    • 转换为介于-1和1之间的值
    窗口y范围内的

    y = mouseposition.y

    • 转换为介于-1和1之间的值
    • 记得在需要的时候反转mouseposition.y

    z = the depth value(这可以通过glReadPixel获得)

    • 您可以手动从-1到1(zNear,zFar)

    w = 1.0

  6. 将矢量乘以在

  7. 之前创建的反转矩阵
  8. 在矩阵乘法(透视除法)

    之后将结果向量除以它的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);
    

答案 1 :(得分:7)

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

答案 2 :(得分:2)

如果您可以访问glu库,请使用gluUnProject(winX,winY,winZ,model,projection,viewport,&amp; objX,&amp; objY,&amp; objZ);

winXwinY将成为屏幕的一角(以像素为单位)。 winZ是[0,1]中的数字,用于指定点落入的zNearzFar(剪裁平面)之间的位置。 objX-Z将保留结果。中间变量是相关矩阵。如果需要,可以查询它们。

答案 3 :(得分:0)

我必须对此处提供的答案进行一些调整。但是,这是我最终得到的代码(请注意,我使用的是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);
}