Подтвердить что ты не робот

Прозрачные объекты в Threejs

Я пытаюсь написать небольшую программу в Three.js, которая отображает две сферы, одну внутри другой. Радиус сферы 2 должен колебаться между 0,5 и 1,5, а радиус сферы 1 всегда равен 1,0. Каждая сфера прозрачна (непрозрачность: 0,5), чтобы можно было видеть меньшую сферу, содержащуюся в большей. Конечно, роли "меньшего" и "большего" изменения изменяются по мере изменения радиуса сферы2.

Теперь проблема заключается в том, что Three.js делает прозрачным первую сферу, которую я определяю в своей программе, но не вторую. Если я определяю первую сферу1, тогда она становится прозрачной, но затем сфера 2 полностью непрозрачна. Если я определяю первую сферу2, то это прозрачная. Порядок добавления их на сцену не играет никакой роли.

Я включаю ниже минимальную программу, которая показывает, что происходит (без анимации). В текущем состоянии видна только сфера1, и она не прозрачна. Если я определяю сферу 1 перед сферой 2, то сфера1 становится прозрачной, но сфера2 уже не прозрачна. Изменение радиуса сферы2 до 1,2 затем скроет сферу.

Есть ли способ сделать оба шара прозрачными?

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

Ответ 1

Обе сферы прозрачны и остаются такими. Что происходит, так это то, что меньшая сфера вообще не отображается.

Прозрачность в WebGL сложна. Вы можете решить эту проблему, чтобы узнать больше об этом.

Но вы наткнулись на проблему, связанную с тем, как three.js, в частности, обрабатывает прозрачность.

WebGLRenderer в three.js сортирует объекты на основе их расстояния от камеры и визуализирует прозрачные объекты в порядке от самого дальнего до ближайшего. (Это важный момент: он сортирует объекты на основе их положения и отображает объекты в отсортированном порядке.)

Итак, для двух прозрачных объектов, которые нужно правильно отобразить, объект, который находится сзади, - меньшая сфера в вашем случае - должен быть отображен первым. В противном случае он не будет отображаться вообще из-за буфера глубины.

Но в вашем случае у вас есть две сферы, которые находятся в одном месте и, следовательно, находятся на равном расстоянии от камеры. В этом и заключается проблема, которую нужно сделать первыми; это бросок.

Таким образом, вам нужно поместить меньшую сферу дальше от камеры, чем большая сфера, чтобы сцена выглядела правильно.

Одним из решений является небольшое перемещение маленькой сферы.

Другим решением является установка renderer.sortObjects = false. Затем объекты будут отображаться в том порядке, в котором они будут добавлены в сцену. В этом случае сначала добавьте меньшую сферу в сцену.

Третье решение - установить material1.depthWrite = false и material2.depthWrite = false.

EDIT:

Объекты, имеющие material.transparent = false (непрозрачные объекты), визуализируются перед объектами, имеющими material.transparent = true (прозрачные объекты).

Итак, четвертое решение состоит в том, чтобы сделать меньшую сферу непрозрачной, чтобы она была сделана первой.

Новая функция для r.71:

Теперь существует свойство Object3D.renderOrder. Внутри каждого класса объекта (непрозрачный или прозрачный) объекты отображаются в порядке, указанном object.renderOrder. Значение по умолчанию renderOrder равно 0. Обратите внимание, что renderOrder не наследуется дочерними объектами; вы должны установить его для каждого рендерируемого объекта.

Объекты с тем же renderOrder (связями) сортируются по глубине, как описано выше.

Итак, пятое решение - установить renderOrder = 1 для большей сферы. Это, скорее всего, лучшее решение в вашем случае.

three.js r.71

Ответ 2

Несколько комментариев.

Во-первых. Если вы зададите вопрос, который ожидает, что люди просмотрят код, поместите его в 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, а затем изменить порядок добавления сфер в сцену. Это было сделано из-за информации в следующих двух ссылках

прозрачные плоскости WebGL Прозрачное поведение текстуры