原本想用两个圆柱体实现盛满液体的玻璃容器效果,如实有了如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
var liquid = new THREE.Mesh( new THREE.CylinderGeometry(40, 40, 150, 32, 32), new THREE.MeshPhongMaterial({ color: '#318414', emissive: '#318414', specular: '#22842c', shininess: 10, shading: THREE.FlatShading, transparent: true, opacity: 0.5, }), ); 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, }), ); SEDU.add( liquid, tube ); |
what? 效果不太对吧,里面绿色液体哪里去了???是不是透明造成的??修改一下试试看:
1 2 3 4 5 6 7 8 9 10 |
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是不是就能显示出来了呢?
1 2 |
liquid.position.set( 0, 0, -1 ); |
OK,绿色液体确实渲染出来了,看来这个问题轻松的就被搞定了。嗯,别高兴的太早。如果物体是静态的,那么可以这么处理,但如果是运动的就要各个方向都要看仔细了。
果然旋转一下问题依然存在,那么怎么能彻底解决这个问题呢?下面提供几种方案。
第一种 renderOrder
将tube的renderOrder设为1,即可正确渲染两个物体。
第二种 depthWrite:false
将两个物体材质的depthWrite属性都设为 false,也可正确渲染两个物体。