Threejs中的透明对象

cef*_*tat 58 three.js

我试图在Three.js中编写一个小程序,显示两个球体,一个在另一个内部.球2的半径应该在0.5和1.5之间振荡,而球1的半径总是1.0.每个球体都是透明的(不透明度:0.5),因此可以看到较大球体中包含的较小球体.当然,随着球体2的半径变化,"较小"和"较大"的作用会发生变化.

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

我在下面包含一个显示正在发生的事情的最小程序(没有动画).在当前状态下,只有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);
Run Code Online (Sandbox Code Playgroud)

Wes*_*ley 147

你的球体都是透明的,并且仍然是如此.发生的事情是较小的球体根本没有被渲染.

WebGL的透明度很棘手.您可以谷歌该问题,以了解更多相关信息.

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

WebGLRenderer在three.js所排序基于来自摄影机的距离的物体,并呈现从最远为了透明物体最接近.(这是一个重点:它根据对象位置对象进行排序,并按排序顺序呈现对象.)

因此,要正确渲染两个透明对象,必须先渲染后面的对象(在您的情况下为较小的球体).否则,由于深度缓冲区,它根本不会被渲染.

但在您的情况下,您有两个位于相同位置的球体,因此与相机等距.这就是问题 - 首先要渲染的问题; 这是一个折腾.

因此,您需要将较小的球体放置在比较大的球体更远离相机的位置,以便场景正确渲染.

一种解决方案是将较小的球体向后移动一点.

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

第三种解决方案是设置material1.depthWrite = falsematerial2.depthWrite = false.

编辑:

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

因此,第四种解决方案是使较小的球体不透明,以便首先渲染.

r.71的新功能:

现在有一处Object3D.renderOrder房产.在每个对象类(不透明或透明)中,对象按指定的顺序呈现object.renderOrder.默认值renderOrder0.注意,renderOrder子对象不会继承它; 您必须为每个可渲染对象设置它.

具有相同renderOrder(关系)的对象按深度排序,如上所述.

所以第五个解决方案是设置renderOrder = 1更大的球体.这可能是您案例中的最佳解决方案.

three.js r.71

  • r.71中的`renderOrder`功能对我有用.注意:您必须在子对象上设置它.在父对象上设置它不适用于子对象. (4认同)
  • 添加`depthWrite:false`是解决方案,谢谢!所以我现在正在使用:`var material_plane = new THREE.MeshBasicMaterial({color:drawcol,side:THREE.DoubleSide,opacity:0.5,transparent:true,depthWrite:false});` (4认同)

小智 8

几个评论.

第一.如果您要问一个希望人们审核代码的问题,请将其放在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);
Run Code Online (Sandbox Code Playgroud)

我在代码中更改的是将sortObjects设置为false,然后更改球体添加到场景中的顺序.这是因为接下来的2个链接中的信息

WebGL透明平面 透明纹理行为