原本想用两个圆柱体实现盛满液体的玻璃容器效果,如实有了如下代码:
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,也可正确渲染两个物体。