我试图在Android上使用OpenGL ES实现类似DepthBuffer的功能。
换句话说,我试图在用户设备上的点[x,y]上渲染的表面上获取3D点。为了使我能够在给定点读取片段的距离。
在不同情况下回答:
使用普通OpenGL时,您可以通过创建FrameBuffer
来实现此目的,然后将RenderBuffer
或Texture
附加深度组件。
这两种方法都使用glReadPixels,内部格式为GL_DEPTH_COMPONENT
,以从缓冲区/纹理中检索数据。不幸的是,OpenGL ES仅支持GL_ALPHA
,GL_RGB
和GL_RGBA
作为回读格式,因此无法直接访问帧缓冲区的深度数据。< / p>
我能想到的唯一可行方法(以及我在互联网上发现的建议)是为深度缓冲创建不同的着色器。仅用于深度渲染的着色器应在gl_FragCoord.z
上写入gl_FragColor
值(=我们想要读取的距离值。)。但是:
实际问题:
当我在gl_FragCoord.z
上写gl_FragColor = new Vec4(vec3(gl_FragCoord.z), 1.0);
值并稍后使用glReadPixels
来回读rgb值时,这些读取值不会与输入匹配。
我尝试了什么:
我意识到只有24位(r,g,b * 8位)表示深度数据,所以我尝试将返回值移位8 - 得到32位,但它没有&#39;似乎工作。我还尝试在将它应用于红色,绿色和蓝色时移动距离,但这似乎没有按预期工作。我一直试图通过观察底部的结果来弄清楚错误是什么。
fragmentShader.glsl(候选人#3):
void main() {
highp float distance = 1.0; //currently just 1.0 to test the results with different values.
lowp float red = distance / exp2(16.0);
lowp float green = distance / exp2(8.0);
lowp float blue = distance / exp2(0.0);
gl_FragColor = vec4(red, green, blue, 1.0);
}
读取值的方法(= glReadPixels
)
private float getDepth(int x, int y){
FloatBuffer buffer = GeneralSettings.getFloatBuffer(1); //just creates FloatBuffer with capacity of 1 float value.
terrainDepthBuffer.bindFrameBuffer(); //bind the framebuffer before read back.
GLES20.glReadPixels(x, y, 1, 1, GLES20.GL_RGB, GLES20.GL_UNSIGNED_BYTE, buffer); //read the values from previously bind framebuffer.
GeneralSettings.checkGlError("glReadPixels"); //Make sure there is no gl related errors.
terrainDepthBuffer.unbindCurrentFrameBuffer(); //Remember to unbind the buffer after reading/writing.
System.out.println(buffer.get(0)); //Print the value.
}
使用着色器和放大器进行比特观察上面的方法:
Value | Shader input | ReadPixels output
1.0f | 111111100000000000000000000000 | 111111110000000100000000
0.0f | 0 | 0
0.5f | 111111000000000000000000000000 | 100000000000000100000000