developer tip

Threejs의 투명한 개체

copycodes 2020. 12. 14. 20:02
반응형

Threejs의 투명한 개체


두 개의 영역을 표시하는 Three.js에 작은 프로그램을 작성하려고합니다. sphere2의 반경은 0.5와 1.5 사이에서 진동하는 반면 sphere1의 반경은 항상 1.0입니다. 각 구는 투명하므로 (불투명도 : 0.5) 더 큰 구에 포함 된 더 작은 구를 볼 수 있습니다. 물론 "작은"및 "큰"의 역할은 sphere2의 반지름이 변함에 따라 변경됩니다.

이제 문제는 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);

두 구체 모두 투명하고 그대로 남아 있습니다. 일어나고있는 것은 더 작은 구가 전혀 렌더링되지 않고 있다는 것입니다.

WebGL의 투명성은 까다 롭습니다. 문제를 Google에 검색하여 더 자세히 알아볼 수 있습니다.

그러나 특히 three.js 가 투명성을 처리 하는 방법과 관련된 문제를 발견했습니다 .

WebGLRendererthree.js를 종류의 카메라로부터의 거리에 따라, 그리고 멀리에서 가장 가까운을 위해 투명한 오브젝트를 렌더링 객체. (이것은 중요한 포인트입니다 : 그것은 정렬 객체를 자신의 기반으로 위치 및 렌더링 오브젝트 정렬 순서를.)

따라서 두 개의 투명 오브젝트가 올바르게 렌더링 되려면 뒤쪽에있는 오브젝트 (귀하의 경우에는 더 작은 구)를 먼저 렌더링해야합니다. 그렇지 않으면 깊이 버퍼로 인해 전혀 렌더링되지 않습니다.

그러나 귀하의 경우에는 동일한 위치에 있으므로 카메라에서 등거리에있는 두 개의 구가 있습니다. 이것이 문제입니다. 어느 것이 먼저 렌더링해야하는지; 던지기입니다.

따라서 장면을 올바르게 렌더링하려면 더 작은 구를 큰 구보다 카메라에서 더 멀리 배치해야합니다.

한 가지 해결책은 작은 구를 조금 뒤로 이동하는 것입니다.

또 다른 해결책은 renderer.sortObjects = false. 그러면 오브젝트가 장면에 추가 된 순서대로 렌더링됩니다. 이 경우 먼저 장면에 더 작은 구를 추가해야합니다.

세 번째 해결책은 material1.depthWrite = falsematerial2.depthWrite = false.

편집하다:

렌더링 가능한 갖는 개체 material.transparent = false(불투명 오브젝트)을 갖는 오브젝트가 렌더링되기 전에 material.transparent = true(투명체).

네 번째 해결책은 더 작은 구를 불투명하게 만들어 먼저 렌더링하는 것입니다.

r.71의 새로운 기능 :

There is now an Object3D.renderOrder property. Within each class of object (opaque or transparent), objects are rendered in the order specified by object.renderOrder. The default value of renderOrder is 0. Note that renderOrder is not inherited by child objects; you must set it for each renderable object.

Objects with the same renderOrder (ties), are sorted by depth, as described above.

So a fifth solution is to set renderOrder = 1 for the larger sphere. This is likely the best solution in your case.

three.js r.71


A couple comments.

First. If you are going to ask a question that expects people to review code, put it in jsfiddle. If you do, you will get more people taking a peek. That having been said, here is a slightly modified version of your code in jsfiddle, please use it as a guide for future questions. jsfiddle example

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

What I've changed in your code is to set sortObjects to false and then changed the order that the spheres were added to the scene. This was done because of the information in the next 2 links

WebGL transparent planes Transparent texture behavior


For what it's worth I could not solve the same problem using the methods above but found that having:

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

in my init() and then adding the frontside mesh to the scene, but the backside mesh to group solved the problem. 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);

then

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

My material map was a transparent .png texture.

I can not explain why other suggested methods did not work for me, but I hope the above might help some one in a similar position.

참고URL : https://stackoverflow.com/questions/15994944/transparent-objects-in-threejs

반응형