Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/three.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Three.js 3JS中的透明对象_Three.js - Fatal编程技术网

Three.js 3JS中的透明对象

Three.js 3JS中的透明对象,three.js,Three.js,我正在尝试用Three.js编写一个小程序,它显示两个球体,一个在另一个球体内。假设球体2的半径在0.5和1.5之间振荡,而球体1的半径始终为1.0。每个球体都是透明的(不透明度:0.5),因此可以看到较大球体中包含的较小球体。当然,“小”和“大”的作用随着球体2半径的变化而变化 现在的问题是Three.js使我在程序中定义的第一个球体透明,而不是第二个球体。如果我定义了第一个sphere1,那么它将变得透明,但sphere2是完全不透明的。如果我首先定义sphere2,那么这是透明的。将它们添

我正在尝试用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);
一些评论

首先。如果您要问一个期望人们检查代码的问题,请将其放在JSFIDLE中。如果你这样做,你会让更多的人偷看。话虽如此,这里是您在JSFIDLE中代码的一个稍加修改的版本,请将其用作未来问题的指南

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


您的两个球体都是透明的,并且保持透明。发生的情况是,较小的球体根本没有被渲染

WebGL中的透明度很棘手。你可以通过谷歌搜索这个问题来了解更多信息

但是您偶然发现了一个问题,这个问题与three.js如何处理透明度有关

three.js中的
WebGLRenderer
根据对象与摄影机的距离对对象进行排序,并按从最远到最近的顺序渲染透明对象。(这一点很重要:它根据对象的位置对对象进行排序,并按排序顺序渲染对象。)

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

但是在你的例子中,你有两个球体在同一个位置,因此与相机的距离相等。这就是问题所在——首先呈现哪一个;这件事很难决定

因此,为了正确渲染场景,需要将较小的球体放置在距离摄影机较远的位置

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

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

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

编辑:

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

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

r.71的新功能:

现在有一个
Object3D.renderOrder
属性。在每一类对象(不透明或透明)中,对象都按照
object.renderOrder
指定的顺序进行渲染。
renderroder
的默认值为
0
。请注意,
renderOrder
不是由子对象继承的;必须为每个可渲染对象设置它

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

因此,第五种解决方案是为较大的球体设置
renderOrder=1
。这可能是您的最佳解决方案


three.js r.71

值得一提的是,我无法使用上述方法解决相同的问题,但我发现:

scene = new THREE.Scene();
group = new THREE.Group();
scene.add( group );
在my init()中,然后将正面网格添加到场景中,但将背面网格分组解决了问题。i、 e:

var materialfront = new THREE.MeshPhongMaterial({ 
opacity:1, map:texture });
materialfront.transparent = true ;     
materialfront.side = THREE.FrontSide ; 
frontthing = new THREE.Mesh( geometry, materialfront );
frontthing.renderOrder = 2;
scene.add(frontthing);
然后

我的材质贴图是一个透明的.png纹理


我无法解释为什么其他建议的方法对我不起作用,但我希望上述方法可能会对处于类似位置的人有所帮助。

感谢您抽出时间检查我的代码并回复。将
rendered.sortObjects
设置为
false
会使最终结果取决于我将对象添加到场景中的顺序,如WestLangley稍后的回答中所述。问题是,我想为场景设置动画,对于某些帧,最好先绘制一个球体,然后在其他帧之前绘制另一个球体。depthWrite到底做什么?缺点是什么(性能、新错误等等?)?我认为深度写入信号表明对象应该写入自己的深度,这意味着它们根据与摄影机的距离计算出场景中的深度。如果禁用它,可以覆盖新的深度r.71中的
renderOrder
功能为我工作。注意:必须在子对象上设置它。在父对象上设置它不适用于子对象。添加
depthWrite:false
是解决方案,谢谢!所以我现在使用:
var material_plane=new THREE.MeshBasicMaterial({color:drawcol,side:THREE.DoubleSide,opacity:0.5,transparent:true,depthWrite:false})德普斯威特为我修复了它
var materialfront = new THREE.MeshPhongMaterial({ 
opacity:1, map:texture });
materialfront.transparent = true ;     
materialfront.side = THREE.FrontSide ; 
frontthing = new THREE.Mesh( geometry, materialfront );
frontthing.renderOrder = 2;
scene.add(frontthing);
var texture2 = texture.clone();
texture2.needsUpdate = true;
var materialBack = new THREE.MeshPhongMaterial({
opacity:0.1, map: texture2})
materialBack.transparent = true ;
materialBack.side = THREE.BackSide;
backthing = new THREE.Mesh( geometryback, materialBack );
backthing.renderOrder = 1;
group.add(backthing);