2016-07-25 72 views
0

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

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

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

这里是片段着色器的代码。在片段着色器中,我使用这些坐标来计算使用毕达哥拉斯到原点(0,0,0)的eulidean距离。要访问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位,然后将其转换回浮点数。

如何在不放松精度的情况下将距离值提取为float值?

+1

如果您要写入8位RGBA的后缓冲区,如果您想写浮点值,则需要使用附加的“HALF_FLOAT”或“FLOAT”纹理渲染到“FrameBufferObject”,然后从中读取质地。 –

+0

为什么这个深度的因子是1/5000?为什么你不使用现成的'length'内置函数,即'length(verpos)'。从技术上讲,甚至可以节省将深度写入碎片颜色(并全部禁用颜色写入)的步骤,并只读取深度缓冲区的内容并线性化深度值的1/x映射。深度缓冲区至少有16位,更可能是24位。从技术上讲,你甚至可以将线性深度写入深度缓冲区,但会影响性能。 – datenwolf

+0

@datenwolf我除以5000,使得值在'[0,1]'范围内。 – user38034

回答

1

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