-
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