我正在考虑我认为的the first paper for depth peeling (the simplest algorithm?),我想用webgl实现它,使用three.js
我想我理解这个概念并能够制作几个皮,其中一些逻辑看起来像这样:
render(scene, camera) {
const oldAutoClear = this._renderer.autoClear
this._renderer.autoClear = false
setDepthPeelActive(true) //sets a global injected uniform in a singleton elsewhere, every material in the scene has onBeforeRender injected with additional logic and uniforms
let ping
let pong
for (let i = 0; i < this._numPasses; i++) {
const pingPong = i % 2 === 0
ping = pingPong ? 1 : 0
pong = pingPong ? 0 : 1
const writeRGBA = this._screenRGBA[i]
const writeDepth = this._screenDepth[ping]
setDepthPeelPassNumber(i) //was going to try increasing the polygonOffsetUnits here globally,
if (i > 0) {
//all but first pass write to depth
const readDepth = this._screenDepth[pong]
setDepthPeelFirstPass(false)
setDepthPeelPrevDepthTexture(readDepth)
this._depthMaterial.uniforms.uFirstPass.value = 0
this._depthMaterial.uniforms.uPrevDepthTex.value = readDepth
} else {
//first pass just renders to depth
setDepthPeelFirstPass(true)
setDepthPeelPrevDepthTexture(null)
this._depthMaterial.uniforms.uFirstPass.value = 1
this._depthMaterial.uniforms.uPrevDepthTex.value = null
}
scene.overrideMaterial = this._depthMaterial
this._renderer.render(scene, camera, writeDepth, true)
scene.overrideMaterial = null
this._renderer.render(scene, camera, writeRGBA, true)
}
this._quad.material = this._blitMaterial
// this._blitMaterial.uniforms.uTexture.value = this._screenDepth[ping]
this._blitMaterial.uniforms.uTexture.value = this._screenRGBA[
this._currentBlitTex
]
console.log(this._currentBlitTex)
this._renderer.render(this._scene, this._camera)
this._renderer.autoClear = oldAutoClear
}
我使用gl_FragCoord.z
进行测试,并将深度打包成8位RGBA纹理,其着色器如下所示:
float depth = gl_FragCoord.z;
vec4 pp = packDepthToRGBA( depth );
if( uFirstPass == 0 ){
float prevDepth = unpackRGBAToDepth( texture2D( uPrevDepthTex , vSS));
if( depth <= prevDepth + 0.0001) {
discard;
}
}
gl_FragColor = pp;
在投影之后,在顶点着色器中计算变化vSS
:
vSS.xy = gl_Position.xy * .5 + .5;
基本的想法似乎有效,我得到皮肤,但只有我使用软糖因素。看起来它失败了,因为角度变得更加钝(这就是为什么polygonOffset
需要因子和单位来计算斜率?)。
我根本不了解不变性是如何解决的。我不明白所提到的扩展是如何被使用的,除了它似乎压倒片段深度,但是用什么?
我必须承认,由于每个像素都是对齐的,我甚至不确定这里引用的是哪个插值,我只是使用最近的滤波。
我确实看到了一些关于深度缓冲精度的提示,但并没有真正理解这个问题,我想尝试将深度只包含在三个通道中,看看会发生什么。
拥有如此小的软糖因素使它有点工作告诉我,所有这些采样和计算深度似乎确实存在于同一空间。但这似乎与使用gl.EQUAL进行深度测试的问题相同?对于粪便和咯咯笑声,我试图在打包后立即用深度打开深度覆盖深度,但它似乎没有做任何事情。
修改
每次剥离增加多边形偏移似乎已经成功了。虽然我用线条进行了一些战斗,但我认为这是因为我已经使用偏移来绘制它们,我需要将其包含在剥离偏移中。我仍然希望更多地了解这个问题。
答案 0 :(得分:2)
深度缓冲区存储深度:)根据“远”和“近”平面,透视投影倾向于将“堆叠”点的深度设置在缓冲区的一小部分中。它在z中不是线性的。您可以根据深度在自己的设置上看到不同的颜色,并渲染一些占据近远距离的三角形。
阴影贴图存储投影后计算的深度(光照距离)。之后,在第二个或后一个过程中,您将比较那些“堆叠”的深度,这使得一些比较失败,因为它们是非常相似的值:危险差异。
您可以使用更精细的深度缓冲区,24位而不是16位或8位。这可以解决部分问题。
还有另一个问题:透视划分或z / w,需要获得规范化设备坐标(NDC)。它出现在顶点着色器之后,因此gl_FragDepth = gl_FragCoord.z会受到影响。
另一种方法是存储在某些空间中计算的深度,该深度不会遭受“堆叠”或透视划分。相机空间是一个。换句话说,您可以在顶点着色器中计算深度撤消投影。
您链接的文章适用于旧的固定管道,没有着色器。它显示了一个NVIDIA扩展来处理这些差异。