webgl(和threejs)

时间:2017-09-28 18:04:08

标签: algorithm three.js webgl

我正在考虑我认为的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进行深度测试的问题相同?对于粪便和咯咯笑声,我试图在打包后立即用深度打开深度覆盖深度,但它似乎没有做任何事情。

修改

每次剥离增加多边形偏移似乎已经成功了。虽然我用线条进行了一些战斗,但我认为这是因为我已经使用偏移来绘制它们,我需要将其包含在剥离偏移中。我仍然希望更多地了解这个问题。

1 个答案:

答案 0 :(得分:2)

深度缓冲区存储深度:)根据“远”和“近”平面,透视投影倾向于将“堆叠”点的深度设置在缓冲区的一小部分中。它在z中不是线性的。您可以根据深度在自己的设置上看到不同的颜色,并渲染一些占据近远距离的三角形。

阴影贴图存储投影后计算的深度(光照距离)。之后,在第二个或后一个过程中,您将比较那些“堆叠”的深度,这使得一些比较失败,因为它们是非常相似的值:危险差异。

您可以使用更精细的深度缓冲区,24位而不是16位或8位。这可以解决部分问题。

还有另一个问题:透视划分或z / w,需要获得规范化设备坐标(NDC)。它出现在顶点着色器之后,因此gl_FragDepth = gl_FragCoord.z会受到影响。

另一种方法是存储在某些空间中计算的深度,该深度不会遭受“堆叠”或透视划分。相机空间是一个。换句话说,您可以在顶点着色器中计算深度撤消投影。

您链接的文章适用于旧的固定管道,没有着色器。它显示了一个NVIDIA扩展来处理这些差异。