2013-04-14 18 views
36

Tôi đang cố gắng viết một chương trình nhỏ trong Three.js hiển thị hai hình cầu, một mặt trong hình kia. Bán kính của sphere2 được cho là dao động giữa 0,5 và 1,5 trong khi bán kính của sphere1 luôn là 1,0. Mỗi hình cầu trong suốt (độ mờ: 0,5) sao cho có thể nhìn thấy quả cầu nhỏ hơn chứa trong hình cầu lớn hơn. Tất nhiên, vai trò của thay đổi "nhỏ hơn" và "lớn hơn" khi bán kính của hình cầu2 thay đổi.Đối tượng trong suốt ở Threejs

Vấn đề bây giờ là Three.js làm cho minh bạch hình cầu đầu tiên tôi xác định trong chương trình của tôi nhưng không phải là hình cầu thứ hai. Nếu tôi định nghĩa hình cầu 1 đầu tiên thì nó trở nên trong suốt nhưng sau đó hình cầu2 hoàn toàn mờ đục. Nếu tôi định nghĩa hình cầu 2 đầu tiên thì đây là hình cầu trong suốt. Thứ tự thêm chúng vào cảnh không có vai trò gì.

Tôi bao gồm bên dưới chương trình tối thiểu cho biết điều gì đang diễn ra (không có hoạt ảnh). Trong trạng thái hiện tại của nó chỉ có hình cầu1 là có thể nhìn thấy và nó không phải là minh bạch. Nếu tôi xác định sphere1 trước sphere2 thì sphere1 trở nên trong suốt nhưng sphere2 không còn trong suốt nữa. Thay đổi bán kính của sphere2 thành 1.2 sẽ ẩn hình cầu1.

Có cách nào để làm cho cả hai hình cầu trong suốt?

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

Trả lời

111

Cả hai lĩnh vực của bạn là minh bạch, và còn lại như vậy. Điều đang xảy ra là quả cầu nhỏ hơn không được kết xuất chút nào.

Tính minh bạch trong WebGL rất khó khăn. Bạn có thể google vấn đề để tìm hiểu thêm về nó.

Nhưng bạn đã tình cờ gặp một vấn đề liên quan đến cách three.js cụ thể là xử lý độ trong suốt.

WebGLRenderer trong ba.js sắp xếp các đối tượng dựa trên khoảng cách của chúng từ máy ảnh và hiển thị đối tượng trong suốt theo thứ tự từ xa đến gần nhất. (Đây là một điểm quan trọng: Nó phân loại đối tượng dựa trên vị trí của họ, và làm cho đối tượng theo thứ tự sắp xếp.)

Vì vậy, cho hai đối tượng trong suốt hiển thị chính xác, các đối tượng đó là ở phía sau - - quả cầu nhỏ hơn trong trường hợp của bạn - phải được trả trước. Nếu không, nó sẽ không được hiển thị ở tất cả, do bộ đệm độ sâu.

Nhưng trong trường hợp của bạn, bạn có hai hình cầu ở cùng một vị trí và do đó cách nhau bằng máy ảnh. Đó là vấn đề - cái nào để làm đầu tiên; nó là một quăng lên.

Vì vậy, bạn cần phải đặt hình cầu nhỏ hơn cách xa máy ảnh hơn hình cầu lớn hơn để cảnh hiển thị chính xác.

Một giải pháp là di chuyển quả cầu nhỏ trở lại một chút.

Một giải pháp khác là đặt renderer.sortObjects = false. Sau đó, các đối tượng sẽ hiển thị theo thứ tự chúng được thêm vào cảnh. Trong trường hợp đó, hãy chắc chắn thêm quả cầu nhỏ hơn vào cảnh đầu tiên.

Giải pháp thứ ba là đặt material1.depthWrite = falsematerial2.depthWrite = false.

EDIT:

đối tượng Renderable có material.transparent = false (đối tượng đục) đều được trả lại trước khi đối tượng có material.transparent = true (đối tượng trong suốt).

Vì vậy, giải pháp thứ tư là làm cho hình cầu nhỏ hơn mờ đục để nó được hiển thị trước.

Tính năng mới cho r.71:

Hiện tại có thuộc tính Object3D.renderOrder. Trong mỗi lớp đối tượng (đục hoặc trong suốt), các đối tượng được hiển thị theo thứ tự được chỉ định bởi object.renderOrder. Giá trị mặc định của renderOrder0. Lưu ý rằng renderOrder không được thừa hưởng bởi các đối tượng con; bạn phải đặt nó cho từng đối tượng có thể hiển thị.

Đối tượng có cùng số renderOrder (quan hệ), được sắp xếp theo chiều sâu, như được mô tả ở trên.

Vì vậy, giải pháp thứ năm là đặt renderOrder = 1 cho hình cầu lớn hơn. Đây có thể là giải pháp tốt nhất trong trường hợp của bạn.

three.js r.71

+0

Đây là một câu trả lời tuyệt vời, cảm ơn dude !!! –

+0

Vì vậy, cảm ơn bạn –

+0

depthWrite làm gì chính xác? Những hạn chế (perfs, bugs mới, ...?) Là gì? –

5

Một vài nhận xét.

Trước tiên. Nếu bạn định đặt một câu hỏi mong đợi mọi người xem lại mã, hãy đặt nó vào jsfiddle. Nếu bạn làm thế, bạn sẽ thu hút nhiều người hơn. Điều đó đã được nói, đây là một phiên bản sửa đổi của mã của bạn trong jsfiddle, hãy sử dụng nó như một hướng dẫn cho các câu hỏi trong tương lai. 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); 

Những gì tôi đã thay đổi trong mã của bạn là để thiết lập sortObjects false và sau đó thay đổi theo thứ tự mà các lĩnh vực đã được thêm vào hiện trường. Điều này đã được thực hiện bởi vì các thông tin trong 2 liên kết tiếp theo

WebGL transparent planes Transparent texture behavior

+1

Cảm ơn bạn đã dành thời gian kiểm tra mã và trả lời. Đặt 'render.sortObjects' thành' false' làm cho kết quả cuối cùng phụ thuộc vào thứ tự tôi thêm các đối tượng vào cảnh, như được giải thích trong câu trả lời sau bởi WestLangley. Vấn đề là tôi muốn tạo hiệu ứng cho cảnh và đối với một số khung hình sẽ tốt hơn nếu có một quả cầu được vẽ đầu tiên và tạo ra một số khung khác hình cầu khác. – cefstat