【问题标题】:3d Math : screen space to world space3d 数学:屏幕空间到世界空间
【发布时间】:2016-02-25 01:27:41
【问题描述】:

在过去的 6 个小时里,我一直在尝试在我的 webgl 应用程序中实现点击,但我找不到任何关于这个主题的足够清楚的信息。

到目前为止,我想出的是伪代码:

screenSpace = mousePosition;
normalizedScreenSpace = (screenSpace.x/screen.width, screenSpace.y/screen.height);

camSpace = invertProjectionMatrix * normalizedScreenSpace;

worldSpace = invertViewMatrix * camSpace;

打印出世界空间坐标,不对应场景中的其他物体。我做错了什么?

【问题讨论】:

  • @LJ 这个问题的答案并不令人满意。一个链接到他的实现与非常糟糕的命名和评论,如果你还不理解它,这将毫无意义。或者对该主题进行非常高水平的评论的论文。还有一个 Three.js 版本,根本不回答这个问题。
  • 接受的答案链接到the glu unproject implementation,恕我直言,它具有描述性。您的归一化在 0-1 范围内,而它应该是 -1,+1,此外您似乎没有应用透视划分。

标签: javascript math 3d webgl clicking


【解决方案1】:

viewProjection 矩阵将 vec3 从世界空间带到剪辑空间,因此它的逆矩阵将剪辑空间反转到世界空间。缺少的是 gpu 在后台为您处理的透视划分,因此您也必须考虑到这一点。加上屏幕的宽度和高度,你就拥有了你的屏幕:

screenToWorld: function(invViewProjection, screenWidth, screenHeight){
    // expects this[2] (z value) to be -1 if want position at zNear and +1 at zFar

    var x = 2*this[0]/screenWidth - 1.0;
    var y = 1.0 - (2*this[1]/screenHeight); // note: Y axis oriented top -> down in screen space
    var z = this[2];
    this.setXYZ(x,y,z);
    this.applyMat4(invViewProjection);
    var m = invViewProjection;
    var w = m[3] * x + m[7] * y + m[11] * z + m[15]; // required for perspective divide
    if (w !== 0){
        var invW = 1.0/w;
        this[0] *= invW;
        this[1] *= invW;
        this[2] *= invW;
    }

    return this;
},

以及逆向计算:

worldToScreen: function(viewProjectionMatrix, screenWidth, screenHeight){
    var m = viewProjectionMatrix;
    var w = m[3] * this[0] + m[7] * this[1] + m[11] * this[2] + m[15]; // required for perspective divide
    this.applyMat4(viewProjectionMatrix);
    if (w!==0){ // do perspective divide and NDC -> screen conversion
        var invW = 1.0/w;
        this[0] = (this[0]*invW + 1) / 2 * screenWidth;
        this[1] = (1-this[1]*invW) / 2 * screenHeight; // screen space Y goes from top to bottom
        this[2] *= invW;
    } 
    return this;
},

【讨论】:

  • 现在这是一个高质量的答案。我还有两个问题:当您将初始 XYZ 与倒置视图投影矩阵相乘时,W 的值是多少?是否假定为 0?
  • 我的第二个问题是,如果我想像着色器一样获得屏幕坐标的世界坐标,但在 CPU 中,我想我会做 modelViewProjMatrix * vec4(vector,1)。但是,透视划分是如何计算的呢? (我尝试除以结果向量的 w 部分,但我的数字是关闭的)
  • 假设 W 为 1。应该发生的是我先转换为 Vec4(x,y,z,1) 然后在 vec4 上执行 applyMat4。请注意,var w = m[3] * x + m[7] * y + m[11] * z + m[15] 应该是 +W*m[15],但 W 被隐式假定为 1。我更新了世界屏幕的答案。
  • 我有一个关于 screenToWorld 光线投射的问题。我需要来自 znear 和 zfar 的点来投射光线并针对场景中的三角形进行测试,但是如果我所有的三角形都在 z = 0 处呢?是否可以调用 screenToWorld 一次以获取 z = 0 处的世界空间中的位置,或者我是否必须获取一条射线并将该射线转换为 z = 0 以获得坐标?谢谢
  • 我认为你混淆了一些事情。您想要做的是在世界位置获得光线段的 2 个点。这可以通过将 vec3 设置为 (mouse.x, mouse.y, 1) 然后将 pt A 设置为 screenToWorld 并将 pt B 设置为 (mouse.x, mouse.y, -1) 来完成。现在你在世界中有射线段 AB位置。然后将你的三角形和射线带入同一个坐标空间并运行射线三角形测试。
猜你喜欢
  • 2021-04-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多