【问题标题】:Return floats from fragmentshader从碎片着色器返回浮点数
【发布时间】:2016-07-25 15:00:06
【问题描述】:

对于一个应用程序,我需要创建一个网格的深度图像。基本上我想要一个图像,其中每个像素都告诉相机中心和交点之间的距离。我选择使用 OpenGL 来完成这项任务,这样大部分计算都可以在 GPU 而不是 CPU 上完成。

这是我的顶点着色器代码。它计算交点的真实坐标并将坐标存储在varying vec4 中,以便我可以在片段着色器中访问它。

varying vec4 verpos;
void main(void)
{
    gl_Position = ftransform();
    verpos = gl_ModelViewMatrix*gl_Vertex;
}

这里是片段着色器的代码。在片段着色器中,我使用这些坐标来使用毕达哥拉斯计算到原点 (0,0,0) 的欧式距离。为了访问 CPU 上的计算值,我的计划是使用 gl_FragColor 将距离存储为颜色,并使用 glReadPixels(0, 0, width, height, GL_RED, GL_FLOAT, &distances[0]); 提取颜色值

varying vec4 verpos;
void main() 
{ 
    float x = verpos.x;
    float y = verpos.y;
    float z = verpos.z;

    float depth = sqrt(x*x + y*y + z*z) / 5000.0;
    gl_FragColor = vec4(depth, depth, depth, 1.0);
}

问题是,我只收到0.003921569 (=1/255) 精度的结果。 结果值包含例如0.364705890, 0.364705890, 0.364705890, 0.364705890, 0.368627459, 0.368627459, 0.368627459。一行中的大部分值是完全一样的,然后有1/255的跳跃。 所以介于gl_FragColorglReadPixels 之间的某个地方,OpenGL 将浮点数转换为 8 位,然后将它们转换回浮点数。

如何在不丢失精度的情况下将距离值提取为浮点数?

【问题讨论】:

  • 您正在写入 8 位 RGBA 的后缓冲区,如果您想写入浮点值,您需要渲染到带有 HALF_FLOATFLOAT 纹理的 FrameBufferObject 附加到它,然后从该纹理中读取。
  • 为什么深度是 1/5000?为什么不使用现成的length 内置函数,即length(verpos)。从技术上讲,您甚至可以省去将深度写入片段颜色的步骤(并一起禁用颜色写入),只需读取深度缓冲区的内容并线性化其中深度值的 1/x 映射。深度缓冲区至少有 16 位,更可能是 24 位。从技术上讲,您甚至可以将线性深度写入深度缓冲区,但这会影响性能。
  • @datenwolf 我除以 5000,所以值在[0, 1] 的范围内。
  • 而且我不使用深度缓冲区,因为您收到的不是中心的深度,而是查看平面的深度。
  • @user38034:在 OpenGL 中,没有“中心”之类的东西,只有“一些”空间 OpenGL 对此一无所知,并且有剪辑和 NDC 空间,这是 OpenGL 操作的空间。而且顶点着色器从这个“一些”空间映射到剪辑空间(并从那里进行一些硬连线转换到 NDC 空间)。深度缓冲区在 NDC 空间中运行,仅此而已。值得一提的是,到查看平面的距离与到原点的距离没有实际差异;它归结为一个恒定的偏移量。

标签: c++ opengl glsl shader fragment-shader


【解决方案1】:

将 R32F 或 R16F 纹理附加到 FBO 并对其进行渲染。然后使用glGetTexImage2D() 提取像素,就像使用glReadPixels() 一样。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-15
    • 2021-03-31
    • 2011-05-27
    • 1970-01-01
    • 2011-05-24
    相关资源
    最近更新 更多