OpenGL 数学 - 将屏幕空间投影到世界空间坐标

发布于 2024-12-09 01:06:35 字数 240 浏览 0 评论 0原文

是时候在一天结束时进行一些数学运算了。

我需要投影窗口大小的 4 个点

<0,0> <1024,768>

进入世界空间坐标,因此它将形成一个四边形形状,稍后将用于地形剔除 - 不使用 GluUnproject

仅用于测试,我使用鼠标坐标 - 并尝试投影他们到世界坐标上

Time for a little bit of math for the end of the day..

I need to project 4 points of the window size:

<0,0> <1024,768>

Into a world space coordinates so it will form a quadrilateral shape that will later be used for terrain culling - without GluUnproject

For test only, I use mouse coordinates - and try to project them onto the world coords

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

风筝有风,海豚有海 2024-12-16 01:06:35

已解决

以下是具体的步骤。

  1. 获取客户区域内的鼠标坐标
  2. 如果不需要模型矩阵,则获取投影矩阵和视图矩阵。
  3. 乘法投影 * 查看
  4. 乘法结果的逆
  5. 构造一个由以下组成的向量4

    x = mouseposition.x 在窗口 x 范围内

    • 转换为 -1 到 1 之间的值

    y = mouseposition.y 在窗口 y 范围内

    • 转换为 -1 到 1 之间的值
    • 如果需要,请记住反转 mouseposition.y

    z = 深度值(可以使用 glReadPixel 获得)

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

    w = 1.0

  6. < p>将向量乘以之前创建的逆矩阵

  7. 将结果向量除以矩阵相乘后的 w 分量(透视除法)

     POINT mousePos;
        GetCursorPos(&mousePos);
        ScreenToClient( this->GetWindowHWND(), &mousePos );         
    
        CMatrix4x4 matProjection = m_pCamera->getViewMatrix() * m_pCamera->getProjectionMatrix() ;
    
        CMatrix4x4 matInverse = matProjection.inverse();
    
    
        漂浮在[4]中;
        浮动 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;
        在[3]=1.0;          
    
        CVector4 vIn = CVector4(in[0],in[1],in[2],in[3]);
        pos = vIn * matInverse;
    
        位置 w = 1.0 / 位置 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,位置y,位置z);
    
        SetWindowText(this->GetWindowHWND(),strTitle);
    

RESOLVED

Here's how to do it exactly, step by step.

  1. Obtain your mouse coordinates within the client area
  2. Get your Projection matrix and View matrix if no Model matrix required.
  3. Multiply Projection * View
  4. Inverse the results of multiplication
  5. Construct a vector4 consisting of

    x = mouseposition.x within a range of window x

    • transform to values between -1 and 1

    y = mouseposition.y within a range of window y

    • transform to values between -1 and 1
    • remember to invert mouseposition.y if needed

    z = the depth value ( this can be obtained with glReadPixel)

    • you can manually go from -1 to 1 ( zNear, zFar )

    w = 1.0

  6. Multiply the vector by inversed matrix created before

  7. Divide result vector by it's w component after matrix multiplication ( perspective division )

        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);
    
彡翼 2024-12-16 01:06:35

我必须对此处提供的答案进行一些调整。但这是我最终得到的代码(注意我正在使用 GLM,这可能会影响乘法顺序)。 closeResult 是近平面上的投影点,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);
}

I had to make some adjustments to the answers provided here. But here's the code I ended up with (Note I'm using GLM, that could affect multiplication order). nearResult is the projected point on the near plane and farResult is the projected point on the far plane. I want to perform a ray cast to see what my mouse is hovering over so I convert them to a direction vector which will then originate from my camera's position.

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);
}
感性 2024-12-16 01:06:35

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

Multiply all your matrices. Then invert the result. Point after projection are always in the -1,1. So the four corner screen points are -1,-1; -1,1; 1,-1;1,1. But you still need to choose th z value. If you are in OpenGL, z is between -1 and 1. For directx, the range is 0 to 1. Finally take your points and transform them with the matrix

眼藏柔 2024-12-16 01:06:35

如果您有权访问 glu 库,请使用 gluUnProject(winX 、winY、winZ、模型、投影、视口、&objX、&objY、&objZ);

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

If you have access to the glu libraries, use gluUnProject(winX, winY, winZ, model, projection, viewport, &objX, &objY, &objZ);

winX and winY will be the corners of your screen in pixels. winZ is a number in [0,1] which will specify where between zNear and zFar (clipping planes) the points should fall. objX-Z will hold the results. The middle variables are the relevant matrices. They can be queried if needed.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文