参考: http://math.hws.edu/graphicsbook/c7/s4.html
参考: https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/framebufferTexture2D
参考: https://stackoverflow.com/questions/27535727/opengl-create-a-depth-stencil-texture-for-reading
参考: https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_frag_depth.txt
参考: https://stackoverflow.com/questions/13171036/visualizing-the-stencil-buffer-to-a-texture/13171346#13171346
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)
在某个场景下, 我们期望在渲染时, 保存当前的深度缓冲区, 然后再开始下一步渲染, 之后再把深度缓冲区还原, 还原后进行下一步.
时序是:
如果做到该步骤呢?
通常我们会考虑把深度模板通过渲染方式,保存到一份新的颜色纹理中;
还原时, 把这份颜色纹理作为输入, 对深度值进行还原.
当然, 前提需要我们把深度缓冲区绑定到了纹理上, 这样子我们就可以把深度模板纹理作为输入向新的颜色纹理中写入.
(下面的样例使用的js+webgl)
保存的前提部分, 是我们需要Render to Target, 需要让深度写入到纹理中, 便于我们后续的操作.
新建colorTexture与depthStencilTexture:
var colorTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,colorTexture);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,512, 512,
0,gl.RGBA,gl.UNSIGNED_BYTE,null);
var depthStencilTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,depthStencilTexture);
gl.texImage2D(gl.TEXTURE_2D,0,gl.DEPTH_STENCIL,512, 512,
0,gl.UNSIGNED_INT_24_8,gl.UNSIGNED_BYTE,null);
我们新建一个frameBuffer, 把深度纹理depthStencilTexture绑定给它.
var frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
...
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTexture, 0);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTexture, 0);
保存深度缓冲区内容, 我们需要注意depthStencil的纹理特点, 读取时的要求.
参考: https://stackoverflow.com/questions/27535727/opengl-create-a-depth-stencil-texture-for-reading
读取深度与模板缓冲是需要分开来读取的:
// Texture Image Unit 0 will treat it as a depth texture
gl.glActiveTexture (GL_TEXTURE0);
gl.glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
// 下面这句话可选,缺省使用了GL_DEPTH_COMPONENT
gl.glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_DEPTH_COMPONENT);
// Texture Image Unit 1 will treat the stencil view of depth_stencil_tex accordingly
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, depthStencilTexture);
// 注意模板采样出的值是整数
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
Fragment Shader中,注意读取到值在第一个分量中存储:
// 读取depth
float depth = texture(depthtexture, uv).r;
gl_FragColor = encodeDepth(depth); // encodeDepth把一个float打包到rgba四个分量中
注意: 考虑到精度, fragment精度建议使用高精度, 这样获取到的depth值能够精度高一些. 还原时可以稍微精确一定.
还原深度缓冲区, 是保存的逆过程, 把保存的colorTexture作为输入纹理, 然后在shader中,
置位深度缓冲区的值.
Fragment Shader中
vec4 color = texture(colorTexture, uv);
gl_FragDepthEXT = decodeDepth(color); // decodeDepth把一个rgba四个分量还原到float中
注意: 同样考虑到精度, 建议使用高精度, 这样还原出的gl_FragDepthEXT可以稍微精确高一点.
(Owed by: 春夜喜雨 http://blog.csdn.net/chunyexiyu)