Objets transparents en Threejs

j'essaie d'écrire un petit programme en trois.js qui affiche deux sphères, l'une dans l'autre. Le rayon de sphere2 est censé oscillent entre 0,5 et 1,5, tandis que le rayon de sphere1 est toujours 1.0. Chaque sphère est transparente (opacité: 0.5) de sorte qu'il serait possible de voir la plus petite sphère contenue dans la plus grande. Bien sûr, les rôles de "petites" et "grandes" changer le radius de sphere2 varie.

Le problème maintenant est que Trois.js rend transparente la première sphère que j'ai définie dans mon programme mais pas la seconde. Si je définis d'abord sphére1 alors il devient transparent, mais alors sphére2 est complètement opaque. Si je définis d'abord sphére2 alors celui-ci est le transparent. L'ordre de leur ajout à la scène ne joue aucun rôle.

j'inclus ci-dessous un programme minimal qui montre ce qui se passe (sans animation). Dans son état actuel, seule la sphère 1 est visible et elle n'est pas transparente. Si je définis sphére1 avant la sphére2, la sphére1 devient transparente, mais la sphére2 n'est plus transparente. Changer le rayon de la sphère 2 en 1.2 masquera alors la sphère 1.

est-il possible de rendre les deux sphères transparentes?

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);
44
demandé sur cefstat 2013-04-14 05:58:25

3 réponses

vos deux sphères sont transparentes et le restent. Ce qui se passe, c'est que la sphère plus petite n'est pas rendue du tout.

la transparence dans WebGL est délicate. Vous pouvez google la question pour en savoir plus à ce sujet.

mais vous êtes tombé sur une question liée à la façon dont trois.js en particulier s'occupe de la transparence.

le WebGLRenderer en trois.js trie les objets basés sur leur distance de la caméra, et rend les objets transparents dans l'ordre de plus loin au plus proche. (C'est un point important: il trie objets basé sur leur position , et rend objets dans l'ordre trié.)

donc pour que deux objets transparents rendent correctement, l'objet qui est à l'arrière -- la plus petite sphère dans votre cas -- doit être rendu en premier. Sinon, il ne sera pas rendu à tout, en raison du tampon de profondeur.

mais dans votre cas, vous avez deux sphères qui sont au même endroit, et sont donc équidistantes de la caméra. C'est le problème -- lequel rendre en premier; c'est un lancer.

vous devez donc placer la plus petite sphère plus loin de la caméra que la plus grande sphère afin que la scène pour rendre correctement.

une solution est de déplacer la plus petite sphère en arrière a peu.

une autre solution consiste à régler renderer.sortObjects = false . Ensuite, les objets se rendre dans l'ordre où ils sont ajoutés à la scène. Dans ce cas, assurez-vous d'ajouter de la plus petite sphère de la scène.

une troisième solution consiste à régler material1.depthWrite = false et material2.depthWrite = false .

EDIT:

objets récupérables ayant material.transparent = false (objets opaques) sont rendus avant les objets ayant material.transparent = true (transparent objet.)

ainsi une quatrième solution est de rendre la sphère plus petite opaque afin qu'elle soit rendue en premier.

New feature for R. 71:

il y a maintenant une propriété Object3D.renderOrder . Dans chaque classe d'objet (opaque ou transparent), les objets sont rendus dans l'ordre spécifié par object.renderOrder . La valeur par défaut de renderOrder est 0 . Notez que renderOrder n'est pas hérité par des objets enfant; vous devez le définir pour chaque restituable objet.

Les objets

avec le même renderOrder (liens), sont triés par profondeur, comme décrit ci-dessus.

ainsi une cinquième solution est de mettre renderOrder = 1 pour la plus grande sphère. C'est probablement la meilleure solution dans votre cas.

trois.JSR.71

121
répondu WestLangley 2015-03-26 22:21:24

quelques commentaires.

D'abord. Si vous allez poser une question qui attend des gens qu'ils révisent le code, mettez-la dans jsfiddle. Si vous le faites, vous obtiendrez plus de gens prendre un coup d'oeil. Ceci étant dit, voici une version légèrement modifiée de votre code dans jsfiddle, veuillez l'utiliser comme un guide pour les questions d'avenir. exemple de 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);

ce que j'ai changé dans votre code est de mettre les objets sortObjects à false et ensuite changé l'ordre que les sphères ont été ajoutés à la scène. Cela a été fait en raison de l'information dans les 2 liens

WebGL transparent planes Transparent texture comportement

5
répondu Crossphire Development 2017-05-23 11:54:50

pour ce que cela vaut Je ne pouvais pas résoudre le même problème en utilisant les méthodes ci-dessus, mais a constaté que d'avoir:

scene = new THREE.Scene();
group = new THREE.Group();
scene.add( group );

dans mon init() et en ajoutant ensuite la maille frontale à la scène, mais la maille arrière pour grouper a résolu le problème. c'est à dire:

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);

puis

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);

ma carte matérielle était transparente .texture png.

Je ne peux pas expliquer pourquoi les autres méthodes suggérées n'ont pas travaillez pour moi, mais j'espère que ce qui précède pourrait aider quelqu'un dans une position similaire.

0
répondu Craig Wallace 2018-09-23 18:54:16