ThreeJS OIT Depth Peel

blog.csdn.net/kaimw2007/a…

image.png

  • OpenGL渲染中的解决方案是开启 depth peeling

  • depthOnbeforeCompile

depthOnbeforeCompile(shader) {
 
    shader.uniforms.uScreenSize = this.globalPeelUniforms.uScreenSize
    shader.uniforms.uPrevDepthTexture = this.globalPeelUniforms.uPrevDepthTexture
    shader.uniforms.uLayer = this.globalPeelUniforms.uLayer
    shader.uniforms.uDepthOffset = this.globalPeelUniforms.uDepthOffset
     shader.uniforms.uDepthPeel = this.globalPeelUniforms.uDepthPeel
 
    shader.fragmentShader = `
                uniform vec2 uScreenSize;
                uniform sampler2D uPrevDepthTexture;
                uniform int uLayer;
                uniform int uDepthPeel;
                uniform float uDepthOffset;
                ${shader.fragmentShader}
            `
    //peel depth
    shader.fragmentShader = shader.fragmentShader.replace(
        /}$/gm,
        `
                    if(uDepthPeel == 0) return;
                    if(uLayer != 0 ){
                        vec2 screenPos = gl_FragCoord.xy * uScreenSize;
                        float prevDepth = unpackRGBAToDepth(texture2D(uPrevDepthTexture,screenPos));
                        if(prevDepth + uDepthOffset - gl_FragCoord.z >= 0. ){
                            discard;
                        }
                    }
                }
                `
    )
}
复制代码
  • 该函数在深度材质shader编译前(THREE.MeshDepthMaterial)和原始材质shader编译前中调用
this.depthMaterial = new THREE.MeshDepthMaterial()
this.depthMaterial.side = this.getSide()
this.depthMaterial.depthPacking = THREE.RGBADepthPacking
this.depthMaterial.onBeforeCompile = this.depthOnbeforeCompile.bind(this)
复制代码
  • colorOnBeforeCompile
colorOnBeforeCompile(shader){
    shader.fragmentShader = shader.fragmentShader.replace('#include <packing>','')
    shader.fragmentShader = `
			#include <packing>
			uniform sampler2D uPrevColorTexture;
			${shader.fragmentShader}
		`
    //this has early return
    this.depthOnbeforeCompile(shader)
 
    shader.fragmentShader = shader.fragmentShader.replace(
        /}$/gm,
        `
				gl_FragColor.xyz *= gl_FragColor.a;
			}
			`
    )
}
复制代码
  • 该函数在原始材质shader编译前调用
attach(node){
    if (node.isMesh) {
        node.renderOrder = 1
        this.transparentObjects.push(node) // 索引,方便快速调用
        node.material.onBeforeCompile = this.colorOnBeforeCompile.bind(this);
    }
}
复制代码
  • 全局参数设置
  • this.globalPeelUniforms.uDepthPeel.value 作为是否开启半透明开关
  • curMat.transparent 必须设置为false,透明度依然由curMat.opacity控制。
this.globalPeelUniforms = {
    uLayer: { value: 0 },
    uPrevDepthTexture: { value: null },
    uPrevColorTexture: { value: null },
    uScreenSize: { value: new THREE.Vector2(1,1) },
    uDepthPeel: { value: Number(this.options.enabled) },
    uDepthOffset: { value: 0 },
}
复制代码
  • 最后使用depth peel的render 替换threejs默认的renderer.render()
 
render(renderer, scene, camera){
 
    //clear main frame
    renderer.setClearColor(0x000,1)
    renderer.clear()
 
    this.globalPeelUniforms.uLayer.value = 0
 
    //render first depth
    scene.overrideMaterial = this.depthMaterial
    renderer.setClearColor(0xffffff,1)
    renderer.render( scene, camera, this.targets[0], true)
 
    //first color
    scene.overrideMaterial = null
    renderer.setClearColor(0x000,0)
    renderer.render( scene, camera, this.targets[2], true)
 
    for( let i = 0 ; i < this.options.layers ; i ++ ){
 
        const a = i % 3 //shift these around
        const b = (i+1) % 3
        const c = (i+2) % 3
        const d = 3 //peel into this
 
        this.globalPeelUniforms.uPrevDepthTexture.value = this.targets[a]
        this.globalPeelUniforms.uLayer.value = i + 1
 
        //render next depth
        scene.overrideMaterial = this.depthMaterial
        renderer.setClearColor(0xffffff,1)
        renderer.render( scene, camera, this.targets[b], true)
 
        //peel
        scene.overrideMaterial = null
        renderer.setClearColor(0x000,0)
        renderer.render( scene, camera, this.targets[d], true)
 
        //combine
        this.compositeMaterial.uniforms.uTextureA.value = this.targets[c]
        this.compositeMaterial.uniforms.uTextureB.value = this.targets[d]
        renderer.render( this.compositeScene, camera, this.targets[a], true)
 
    }
 
    //render final result over opaque objects
    this.globalPeelUniforms.uPrevDepthTexture.value = null
 
    this.transparentObjects.forEach(o=>o.visible = false)
 
    renderer.render( scene, camera )
    renderer.render( this.compositeScene, camera )
 
    this.transparentObjects.forEach(o=>o.visible = true)
 
 
     //renderer.render( this.debugScene , this.debugCamera )
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享