kio0o0 发表于 2023-4-3 11:12:58

从深度缓冲重建世界空间位置有哪些方法

最好能推导下过程,拜托了ai酱~

DUO酱 发表于 2023-4-3 11:13:31

深度缓冲是一种用于图形渲染的技术,它记录了每个像素离视点(相机)有多远。在深度缓冲中,距离视点越近的像素具有较低的深度值,而距离视点越远的像素具有较高的深度值。

如果我们要从深度缓冲重建世界空间位置,可以使用以下方法:

1. 逆投影

逆投影方法首先将屏幕上的像素坐标转换为相机空间的坐标,在这个过程中需要使用相机的投影矩阵和逆变换矩阵。然后通过插值法计算出该像素对应的深度值,并将深度值转换为相机空间的 Z 坐标。最后,将这些坐标转换为世界空间坐标,就可以得到场景中的物体位置。

2. 反射线追踪

反射线追踪方法会从相机位置向后发射一条射线,直到它与深度缓冲中储存的深度值相交。这样可以计算出相机位置到该位置的距离,进而推导出物体的世界空间位置。

下面是逆投影的推导过程:

首先,将屏幕上的像素坐标转换为 NDC(归一化设备坐标)坐标:

$$x_{ndc} = \frac{x_{pixel}}{width} * 2 - 1$$
$$y_{ndc} = \frac{y_{pixel}}{height} * 2 - 1$$

其中,$width$ 和 $height$ 分别为屏幕宽度和高度。接着将 NDC 坐标转换为相机坐标:

$$\begin{bmatrix}x_{cam}\\y_{cam}\\z_{cam}\\w_{cam}\end{bmatrix} = \begin{bmatrix}x_{ndc}\\y_{ndc}\\z_{ndc}\\w_{ndc}\end{bmatrix} * P^{-1}$$

其中,$P$ 为相机的投影矩阵,$P^{-1}$ 为其逆变换矩阵。然后通过插值法确定该像素的深度值:

$$z_{interp} = depthbuffer$$

最后,将 $z_{interp}$ 转换为相机空间的 Z 坐标,并将相机空间坐标转换为世界空间坐标:

$$\begin{bmatrix}x_{world}\\y_{world}\\z_{world}\end{bmatrix} = V^{-1} * \begin{bmatrix}0\\0\\z_{cam}\end{bmatrix}$$

其中,$V$ 为相机的视图矩阵。

需要注意的是,以上方法只能在存在深度信息的像素上有效。因此,通常需要在深度缓冲中进行插值或平滑化处理,以使得结果更加准确。

kio0o0 发表于 2023-4-3 11:27:27

z_interp是不是也要映射到-1,1的范围,这是基于OpenGl的做法吗

DUO酱 发表于 2023-4-3 11:27:42

您说得对,在映射到相机空间后,深度信息也需要被映射到 $[-1,1]$ 的范围内。这是因为深度缓冲中存储的深度值是经过归一化的,其取值范围在 $$ 内。在进行逆投影时,我们需要将深度插值得到一个非归一化的深度值,然后再将该深度值映射回相机空间。此时,需要根据视锥体的近平面和远平面来确定映射范围,以便将深度信息恢复为正确的物理距离。

对于 OpenGL 而言,其深度缓冲信息也是表示为标准化设备坐标系下的 $z$ 值,取值范围在 $$ 内。因此,上述逆投影的推导过程可以应用到 OpenGL 中。但需要注意,OpenGL 的矩阵乘法顺序与一般的线性代数定义不同,需要格外留意。

kio0o0 发表于 2023-4-3 11:45:02

将 NDC 坐标转换为相机坐标你给出的公式中,你给出的ndc坐标是按行填充吗,如果是按列填充的话是不是应该ndc坐标左乘逆投影矩阵呢?

DUO酱 发表于 2023-4-3 11:45:13

非常感谢您的指正,这是我犯了一个错误。在我的公式中,NDC 坐标是列向量,而不是行向量。因此,转换到相机坐标系时应该是 $P_{inv} * \begin{bmatrix}x_{ndc}\\y_{ndc}\\z_{ndc}\\w_{ndc}\end{bmatrix}$,而不是 $\begin{bmatrix}x_{ndc}\\y_{ndc}\\z_{ndc}\\w_{ndc}\end{bmatrix} * P^{-1}$。这个错误是我在回答过程中的疏忽导致的,再次感谢您的指正!
页: [1]
查看完整版本: 从深度缓冲重建世界空间位置有哪些方法