如何在 WebGL 中的片段着色器中获取单击点的 3D 坐标?

问题描述 投票:0回答:1

我绘制一个由物体(星星、精灵等)组成的单位球体,这些物体在该球体的“表面”上都有 3D 坐标。相机位于它的中心,我使用透视投影来显示生成的天空图。这是从球体中心看到的视图(我的应用程序将如何向用户显示): enter image description here

从侧面看(为了让你更好地理解我所说的物体球体的意思): enter image description here

我读过很多关于非投影和光线投射的文章,但最终

  • 使用一些库,如 Three.js(除了
    gl-matrix
    之外,我不使用任何库,只是裸露的 WebGL2)
  • 使用对象的绘图 ID 进行 WebGL 拾取(图表上有很多空白区域,所以我不能这样做)
  • 说不可能进行这样的转换,因为也需要深度(我有一个单位球体并且想要其表面上的坐标,所以在我的情况下深度或向量长度总是
    1
  • 讨论的不是 WebGL2 和 JavaScript,而是 OpenGL 和类似 C 的语言,它们恰好有解决此问题的便捷方法。

由于我没有模型,除了旋转之外没有相机移动,所以我有超级简单的矩阵代码:

const projectionMatrix = mat4.create()

mat4.perspective(projectionMatrix,
  degreesToRad(fov),
  viewport.x / viewport.y,
  0,
  100)

const panningMatrix = mat4.create()
// in place of this comment, rotations are applied to it as the user pans the map
mat4.invert(panningMatrix, panningMatrix)

const groundViewMatrix = mat4.create()
mat4.multiply(groundViewMatrix, panningMatrix, groundViewMatrix)

// some-shader.vert; u_modelViewMatrix is groundViewMatrix in this case
gl_Position = u_projectionMatrix * u_modelViewMatrix * a_position;

那么,如何获取这个单位球体上的 3D 坐标:

  1. 在 JavaScript 端点击我点击的点(以便我可以将它们转换为 RA/Dec 并显示给用户)?
  2. 在当前绘制像素的片段着色器中(我想绘制四边形以真实的方式对天空进行着色,为此我想计算像素距太阳的角距离、像素在地平线以上的高度等,所有这些都在着色器代码中)?
javascript 3d webgl projection gl-matrix
1个回答
0
投票

为了解决这个问题,我们想要反转变换链: OpenGL Transformation Pipeline

所以步骤是:

将像素坐标转换回 NDC(标准化设备坐标)

标准化设备坐标空间是一个 3D 单位立方体,因此要将屏幕像素坐标取消投影到该立方体中,我们可以简单地执行以下操作:

ndcX = (screenX / screenWidth) * 2 - 1
ndcY = (screenY / screenHeight) * 2 - 1
ndcZ = ???

在矩阵中,这将表示为:

reverse viewport transform matrix

注意:与浏览器相比,WebGL Y 像素坐标是反转的,这意味着如果您使用

ClickEvent
s
clientY
/
offsetY
属性,您想要反转它。

将 NDC 坐标取消投影到相机空间坐标

通过上一步,我们计算了 NDC 空间内深度未知的 2D 平面上的 NDC 坐标。为了回到 3D,我们需要认识到 2D 点是 3D 空间中射线的折叠表示(投影),为此我们需要射线上至少两个点(一条线段)来表示它。对于常用的投影矩阵(例如通过 glMatrix

perspective
ortho
生成的矩阵),我们可以简单地选择体积的范围,从而给我们两个坐标集:

ndc1 = [ndcX, ndcY, -1]
ndc2 = [ndcX, ndcY,  1]

使用投影矩阵的逆来变换这些点将为我们提供相机空间中近剪裁平面和远剪裁平面上的点。

near = ndc1 * inverseProjectionMatrix
far = ndc2 * inverseProjectionMatrix

注意:你想在这里使用gl-matrix'es

vec3.transformMat4

从相机空间到世界空间

要撤消相机变换,我们只需使用逆视图矩阵变换我们的两个点。

worldNear = near * inverseViewMatrix
worldFar = far * inverseViewMatrix

注意:同样,你想在这里使用 gl-matrix'es

vec3.transformMat4

从线段到射线

为了获取单位球体上的点,我们只需将线段转换为射线表示形式,通常表示为射线原点和标准化射线方向,后者是您要查找的单位球体上的点。为此,我们只需从远处减去近处并标准化所得向量。

rayOrigin = near
rayDirection = normalize(far-near)

请注意,如果您在世界空间中指定相机位置,或者您不以任何方式平移场景(相机位置为 0,0,0),您只需要为

far
执行所有这些操作,如下所示
rayOrigin
只是
cameraPosition

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.