【ThreeJs 】利⽤DepthPeel 技术,解决模型半透明出现的碎三⾓⾯问题
在ThreeJS中,模型半透明设置只需要很简单的两⾏代码
留学的好处然⽽.....
我们的模型有时候出现这种情况,正⾯看半透明效果似乎正常,
正⾯看半透明效果似乎正常
⼀旦旋转到侧⾯,就会发现⼤量的碎三⾓⾯⽚(我的妈呀,这是什么⿁)
侧⾯看出现⼤量的碎三⾓⾯开始以为是模型数据问题,经过排查发现并⾮如此,这个半透明不是材质本⾝问题,⽽是绘制顺序。在OpenGL渲染中的解决⽅案是开启depth peeling,但素(41's tone),threejs中并没有这个选项,需要⾃⼰实现。
实现基本原理是芥末解释的
The idea is straight forward as shown by the name: we draw the objects multiple times. For each pas
采购职责
s, we peel one layer from front and one layer from back (front or back is purely depending on their depth, not if it’s from front face or back face).
主要实现函数如下:
1. depthOnbeforeCompile
1
curMat.opacity = 0.5 // 50%透明度ansparent = curMat.opacity < 1 // transparent 属性必须为True 才能半透明
孙权的儿子
2
3 shader.uniforms.uScreenSize = this.globalPeelUniforms.uScreenSize
4 shader.uniforms.uPrevDepthTexture = this.globalPeelUniforms.uPrevDepthTexture
5 shader.uniforms.uLayer = this.globalPeelUniforms.uLayer
6 shader.uniforms.uDepthOfft = this.globalPeelUniforms.uDepthOfft
癞蛤蟆吃什么
7 shader.uniforms.uDepthPeel = this.globalPeelUniforms.uDepthPeel
8
9 shader.fragmentShader = `
10 uniform vec2 uScreenSize;
11 uniform sampler2D uPrevDepthTexture;
12 uniform int uLayer;
13 uniform int uDepthPeel;
14 uniform float uDepthOfft;
15
16 ${shader.fragmentShader}
所以用英语怎么说
17 `
18 //peel depth
19 shader.fragmentShader = place(
20 /}$/gm,
21 `
22 if(uDepthPeel == 0) return;
23
24 if(uLayer != 0 ){
25
26 vec2 screenPos = * uScreenSize;
27
28 float prevDepth = unpackRGBAToDepth(texture2D(uPrevDepthTexture,screenPos));
29
30 if(prevDepth + uDepthOfft - gl_FragCoord.z >= 0. ){
31 discard;
32 }
33 }
34 }
35 `
36 )
37}
该函数在深度材质shader编译前(THREE.MeshDepthMaterial)和原始材质shader编译前中调⽤
1this.depthMaterial = new THREE.MeshDepthMaterial()
2this.depthMaterial.side = Side()
3this.depthMaterial.depthPacking = THREE.RGBADepthPacking
BeforeCompile = this.depthOnbeforeCompile.bind(this)
2. colorOnBeforeCompile
2 shader.fragmentShader = place('#include <packing>','')
3 shader.fragmentShader = `
4 #include <packing>
5 uniform sampler2D uPrevColorTexture;
6
7 ${shader.fragmentShader}
8 `海市蜃楼歌词
9 //this has early return
10 this.depthOnbeforeCompile(shader)
11
12 shader.fragmentShader = place(
13 /}$/gm,
14 `
15 *= gl_FragColor.a;
16 }
17 `
18 )
19}
该函数在原始材质shader编译前调⽤treat
1attach(node){
2 if (node.isMesh) {
3
4 derOrder = 1
5
6 ansparentObjects.push(node) // 索引,⽅便快速调⽤
7
8 BeforeCompile = lorOnBeforeCompile.bind(this);
9 }
10}
3.全局参数设置
1this.globalPeelUniforms = {
2 uLayer: { value: 0 },
3 uPrevDepthTexture: { value: null },
4 uPrevColorTexture: { value: null },
5 uScreenSize: { value: new THREE.Vector2(1,1) },
6 uDepthPeel: { value: Number(abled) },
7 uDepthOfft: { value: 0 },
8}
值得注意的是,this.globalPeelUniforms.uDepthPeel.value 作为是否开启半透明开关,⽽不是⽤threejs 默认的ansparent 属性。并且,ansparent 必须设置为fal,透明度依然由curMat.opacity控制。
4. 最后使⽤depth peel的render 替换threejs默认的der()
1
2render(renderer, scene, camera){
3
4 //clear main frame
5 renderer.tClearColor(0x000,1)
6 renderer.clear()
7
8 this.globalPeelUniforms.uLayer.value = 0
9
10 //render first depth
11 scene.overrideMaterial = this.depthMaterial
12 renderer.tClearColor(0xffffff,1)
13 der( scene, camera, this.targets[0], true)
14
15 //first color
16 scene.overrideMaterial = null
17 renderer.tClearColor(0x000,0)
18 der( scene, camera, this.targets[2], true)
19
20 for( let i = 0 ; i < this.options.layers ; i ++ ){
21
22 const a = i % 3 //shift the around
23 const b = (i+1) % 3
24 const c = (i+2) % 3
25 const d = 3 //peel into this
26
27 this.globalPeelUniforms.uPrevDepthTexture.value = this.targets[a]
28 this.globalPeelUniforms.uLayer.value = i + 1
29
30 //render next depth
31 scene.overrideMaterial = this.depthMaterial
32 renderer.tClearColor(0xffffff,1)
33 der( scene, camera, this.targets[b], true)
34
35 //peel
36 scene.overrideMaterial = null
环城37 renderer.tClearColor(0x000,0)
38 der( scene, camera, this.targets[d], true)
39
40 //combine
41 positeMaterial.uniforms.uTextureA.value = this.targets[c]
42 positeMaterial.uniforms.uTextureB.value = this.targets[d]
43 der( positeScene, camera, this.targets[a], true) 44
45 }
46
47 //render final result over opaque objects
48 this.globalPeelUniforms.uPrevDepthTexture.value = null
49
50 this. transparentObjects.forEach(o=>o.visible = fal)
51
52 der( scene, camera )
53 der( positeScene, camera )
54
55 ansparentObjects.forEach(o=>o.visible = true)
56
57
58 //der( this.debugScene , this.debugCamera )
59}
⼤功告成!最后效果如下:
在线