原本想用兩個圓柱體實現盛滿液體的玻璃容器效果,如實有了如下代碼:
1 var liquid = new THREE.Mesh( 2 new THREE.CylinderGeometry(40, 40, 150, 32, 32), 3 new THREE.MeshPhongMaterial({ 4 color: '#318414', 5 emissive: '#318414', 6 specular: '#22842c', 7 shininess: 10, 8 shading: THREE.FlatShading, 9 transparent: true, 10 opacity: 0.5, 11 }), 12 ); 13 14 var tube = new THREE.Mesh( 15 new THREE.CylinderGeometry(45, 45, 150, 32, 32, true), 16 new THREE.MeshPhongMaterial({ 17 color: '#3d79ff', 18 transparent: true, 19 opacity: 0.4, 20 shininess: 4, 21 }), 22 ); 23 24 SEDU.add( liquid, tube );
效果如下:
what? 效果不太對吧,里面綠色液體哪里去了???是不是透明造成的??修改一下試試看:
var tube = new THREE.Mesh( new THREE.CylinderGeometry(45, 45, 150, 32, 32, true), new THREE.MeshPhongMaterial({ color: '#3d79ff', //transparent: true, opacity: 0.4, shininess: 4, }), );
果然是transparent屬性造成的,但是這樣雖然顯示出來綠色液體的,但液體缺無法體現透明度了。
為什么一個transparent物體內的 另一個transparent物體無法顯示呢?
這是因為Three.js中 WebGLRenderer,會根據對象與攝像機的距離對象進行排序,並按照從最遠到最近的順序渲染透明對象。為了使兩個透明對象正確地呈現,后面的對象-也就是綠色液體-必須首先渲染。否則,由於深度緩沖區,它將根本不會渲染。因為我把他們兩個物體的坐標設為同一個坐標了,沒有了遠近的區別,所以綠色液體沒有被渲染。那么我們把 綠色液體的坐標稍微改動1個px是不是就能顯示出來了呢?
liquid.position.set( 0, 0, -1 );
OK,綠色液體確實渲染出來了,看來這個問題輕松的就被搞定了。嗯,別高興的太早。如果物體是靜態的,那么可以這么處理,但如果是運動的就要各個方向都要看仔細了。
果然旋轉一下問題依然存在,那么怎么能徹底解決這個問題呢?下面提供幾種方案。
第一種 renderOrder
將tube的renderOrder設為1,即可正確渲染兩個物體。
第二種 depthWrite:false
將兩個物體材質的depthWrite屬性都設為 false,也可正確渲染兩個物體。