Threejs中的透明对象

我正在尝试在Three.js中写一个小程序,显示两个球体,一个在另一个的内部。 球体2的半径应该在0.5到1.5之间摆动,而球体1的半径总是为1.0。 每个球体都是透明的(不透明度:0.5),这样就可以看到较大球体中包含的较小球体。 当然,“更小”和“更大”的angular色随着球体半径的变化而变化。

现在的问题是,Three.js使我在程序中定义的第一个球体透明,而不是第二个球体。 如果我定义第一个sphere1,那么它变成透明的,但是sphere2是完全不透明的。 如果我定义第一个sphere2,那么这是透明的。 将它们添加到场景中的顺序不起作用。

我在下面包含一个显示正在进行的最小程序(没有animation)。 在当前状态下,sphere1是可见的,并且不透明。 如果我在sphere2之前定义sphere1,那么sphere1变成透明,但sphere2不再透明。 然后将sphere2的半径改为1.2将隐藏sphere1。

有没有什么办法使两个球体都是透明的?

var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); camera.position.set(0, 0, 3); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); var ambient = new THREE.AmbientLight( 0x555555 ); scene.add(ambient); var light = new THREE.DirectionalLight( 0xffffff ); light.position = camera.position; scene.add(light); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); // Definition 2 var geometry2 = new THREE.SphereGeometry(0.8,32,24); var material2 = new THREE.MeshLambertMaterial({color: 0x0000ff, transparent: true, opacity: 0.5}); var sphere2 = new THREE.Mesh(geometry2, material2); // Definition 1 var geometry1 = new THREE.SphereGeometry(1.0,32,24); var material1 = new THREE.MeshLambertMaterial({color: 0x00ff00, transparent: true, opacity: 0.5}); var sphere1 = new THREE.Mesh(geometry1, material1); scene.add(sphere1); scene.add(sphere2); renderer.render(scene, camera); 

你们的领域都是透明的,而且依然如此。 发生的事情是,更小的球体根本没有被渲染。

WebGL的透明度很棘手。 你可以谷歌问题了解更多。

但是你已经偶然发现了一个与three.js如何处理透明度有关的问题。

WebGLRenderer中的WebGLRenderer根据它们与相机的距离对对象进行sorting,并按从最远到最近的顺序呈现透明对象。 (这是一个重要的观点:它根据对象位置对象进行sorting,并按照sorting顺序呈现对象 。)

因此,要正确渲染两个透明对象,必须首先渲染位于后面的对象 – 在您的案例中较小的球体。 否则,由于深度缓冲,它将不会被渲染。

但在你的情况下,你有两个领域是在同一个位置,因此是距离相机等距离。 那就是问题 – 哪一个先呈现? 这是一个折腾。

因此,为了使场景正确呈现,您需要将较小的球体放置在距离相机较远的地方。

一种解决方法是稍稍移动较小的球体。

另一个解决scheme是设置renderer.sortObjects = false 。 然后,对象将按照它们添加到场景的顺序进行渲染。 在这种情况下,请务必首先将较小的球体添加到场景中。

第三个解决scheme是设置material1.depthWrite = falsematerial2.depthWrite = false

编辑:

material.transparent = false (不透明对象)的可渲染对象在具有material.transparent = true (透明对象)的对象之前被渲染。

所以第四个解决scheme是使小球体不透明,以便首先渲染。

r.71的新function:

现在有一个Object3D.renderOrder属性。 在每个对象类(不透明或透明)中,对象按object.renderOrder指定的顺序呈现。 renderOrder的默认值是0 。 请注意, renderOrder不会renderOrder对象inheritance; 您必须为每个可渲染的对象设置它。

renderOrder具有相同renderOrder (tie)的对象按深度sorting。

所以第五个解决scheme是为更大的球体设置renderOrder = 1 。 这可能是你的情况最好的解决scheme。

three.js r.71

几个意见。

第一。 如果你打算提出一个问题,期望人们审查代码,把它放在jsfiddle。 如果你这样做,你会得到更多的人偷看。 刚才已经说过了,这是在jsfiddle中稍微修改一下你的代码的版本,请把它用作未来问题的指南。 jsfiddle的例子

 var scene = new THREE.Scene(); var camera = new THREE.PerspectiveCamera(75, window.innerWidth/window.innerHeight, 0.1, 1000); camera.position.set(0, 0, 3); camera.lookAt(new THREE.Vector3(0, 0, 0)); scene.add(camera); var ambient = new THREE.AmbientLight( 0x555555 ); scene.add(ambient); var light = new THREE.DirectionalLight( 0xffffff ); light.position = camera.position; scene.add(light); var renderer = new THREE.WebGLRenderer(); renderer.setSize(window.innerWidth, window.innerHeight); document.body.appendChild(renderer.domElement); renderer.sortObjects = false; // Definition 2 var geometry2 = new THREE.SphereGeometry(0.8,32,24); var material2 = new THREE.MeshLambertMaterial({color: 0x0000ff, transparent: true, opacity: 0.5}); var sphere2 = new THREE.Mesh(geometry2, material2); // Definition 1 var geometry1 = new THREE.SphereGeometry(1.0,32,24); var material1 = new THREE.MeshLambertMaterial({color: 0xff0000, transparent: true, opacity: 0.5}); var sphere1 = new THREE.Mesh(geometry1, material1); scene.add(sphere2); scene.add(sphere1); renderer.render(scene, camera); 

我在你的代码中改变了什么,把sortObjects设置为false,然后改变球体添加到场景的顺序。 这是因为在接下来的2个链接中的信息

WebGL透明平面 透明纹理行为