1. 程式人生 > 實用技巧 >Three.js Material transparent 兩個透明物體的渲染問題

Three.js Material transparent 兩個透明物體的渲染問題

原本想用兩個圓柱體實現盛滿液體的玻璃容器效果,如實有了如下程式碼:

 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,也可正確渲染兩個物體。