PyOpenGL - 获取绘制图像的深度图
PyOpenGL - Get depth map of drawn image
我从一个特定的角度(使用视图和投影矩阵)绘制了一个特定的场景。我使用了三角形的 VBO 等等。
我可以使用以下方法获取图像的 RGB:
data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
data = np.frombuffer(data, dtype=np.uint8).reshape(width, height, 3)[::-1]
cv2.imwrite(r"c:\temp\image1.png", data)
但是获取深度图会得到一些奇怪的结果,主要由 255 组成:
data2 = glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE)
data2 = np.frombuffer(data2, dtype=np.uint8).reshape(width, height)[::-1]
cv2.imwrite(r"c:\temp\image2.png", data2)
我尝试替换 GL_UNSIGNED_BYTE
-> GL_FLOAT
和 uint8
-> float32
但这并没有帮助
深度图由 1.0 初始化,如果读取到 GL_UNSIGNED_BYTE
缓冲区,则为 255。注意,深度图的范围是[0.0, 1.0],如果读取到GL_UNSIGNED_BYTE
,那么这个范围映射到[0, 255].
在透视投影中,z 坐标不会线性映射到深度缓冲区。深度值迅速增加,靠近远平面的几何体将导致值深度值为255。
如果深度值在 [0.0, 1.0] 范围内并且你想计算视图(眼睛)space z 坐标,那么你必须将深度值转换为规范化设备 z 坐标拳头 (z_ndc
):
z_ndc = 2.0 * depth - 1.0;
这个坐标可以转化为眼睛spacez坐标(z_eye
),通过以下公式:
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
其中 n
是近平面,f
是远平面。
请注意,此转换仅适用于透视投影。
在正交投影中,z 坐标线性映射到深度。所以向后转换就简单多了:
z_eye = depth * (f-n) + n;
另见 How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?
我从一个特定的角度(使用视图和投影矩阵)绘制了一个特定的场景。我使用了三角形的 VBO 等等。 我可以使用以下方法获取图像的 RGB:
data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
data = np.frombuffer(data, dtype=np.uint8).reshape(width, height, 3)[::-1]
cv2.imwrite(r"c:\temp\image1.png", data)
但是获取深度图会得到一些奇怪的结果,主要由 255 组成:
data2 = glReadPixels(0, 0, width, height, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE)
data2 = np.frombuffer(data2, dtype=np.uint8).reshape(width, height)[::-1]
cv2.imwrite(r"c:\temp\image2.png", data2)
我尝试替换 GL_UNSIGNED_BYTE
-> GL_FLOAT
和 uint8
-> float32
但这并没有帮助
深度图由 1.0 初始化,如果读取到 GL_UNSIGNED_BYTE
缓冲区,则为 255。注意,深度图的范围是[0.0, 1.0],如果读取到GL_UNSIGNED_BYTE
,那么这个范围映射到[0, 255].
在透视投影中,z 坐标不会线性映射到深度缓冲区。深度值迅速增加,靠近远平面的几何体将导致值深度值为255。
如果深度值在 [0.0, 1.0] 范围内并且你想计算视图(眼睛)space z 坐标,那么你必须将深度值转换为规范化设备 z 坐标拳头 (z_ndc
):
z_ndc = 2.0 * depth - 1.0;
这个坐标可以转化为眼睛spacez坐标(z_eye
),通过以下公式:
z_eye = 2.0 * n * f / (f + n - z_ndc * (f - n));
其中 n
是近平面,f
是远平面。
请注意,此转换仅适用于透视投影。
在正交投影中,z 坐标线性映射到深度。所以向后转换就简单多了:
z_eye = depth * (f-n) + n;
另见 How to render depth linearly in modern OpenGL with gl_FragCoord.z in fragment shader?