我正在尝试使用 THREE.js 在 WebGL 中创建一个简单的 map ,其中包含平坦的纸状树木。我无法理解库如何处理 z 缓冲。我试过使用 renderer.sortObjects 参数以及 material.depthWrite 和 object.renderDepth,但似乎没有任何组合起作用——我要么让库以正确的顺序显示树(那些离相机较远的树被遮挡了离相机较近的人),但有奇怪的透明度故障,或者我设法使透明度正确,但离屏幕较远的树木出现在距离较近的树木的顶部。 经过几个小时的努力,我最终得到了:
如您所见,右侧的树渲染在左侧树的顶部。
请在我完全发疯之前帮助我 :)
这是我的代码:http://jsfiddle.net/UgZxc/
var map_size = 80;
var MapModel = {};
var types_amount = 2;
var floorMap = [];
for(var i=1; i<=map_size; i++){
floorMap[i]=[];
for(var j=1; j<=map_size; j++){
var ran = Math.ceil(Math.random()*types_amount);
switch(ran){
case 1:
floorMap[i][j]='grass';
break;
case 2:
floorMap[i][j]='water';
break;
}
}
}
MapModel.floorMap = floorMap;
var objectMap = [];
for(var i = map_size; i>=1; i--){
objectMap[i] = [];
for(var j=1; j<=map_size; j++){
objectMap[i][j] = [];
var rand = Math.ceil(Math.random()*2);
switch(rand){
case 1:
objectMap[i][j].push('tree');
break;
}
}
}
MapModel.objectMap = objectMap;
block_size=100;
// Constructor
MapApp = function()
{
Sim.App.call(this);
}
// Subclass Sim.App
MapApp.prototype = new Sim.App();
// Our custom initializer
MapApp.prototype.init = function(param)
{
Sim.App.prototype.init.call(this, param);
// Create the Earth and add it to our sim
for(var i=1; i<=map_size; i++){
for(var j=map_size; j>=1; j--){
var square = new Square();
square.init(i, j);
this.addObject(square);
var arr = MapModel.objectMap[i][j];
for(var k in arr){
var obj = new MapObject();
obj.init(i, j, arr[k]);
this.addObject(obj);
}
}
}
// Let there be light!
var sun = new Sun();
sun.init();
this.addObject(sun);
this.camera.position.x = 3*block_size;
this.camera.position.y = 3*block_size;
this.camera.position.z=5*block_size;
this.camera.rotation.x = Math.round(45* 100* Math.PI/180)/100;
this.selfUpdate = function(){
this.camera.position.x += 0.125 * block_size/10;
this.camera.position.x += 0.050 * block_size/10;
}
}
Square = function()
{
Sim.Object.call(this);
this.size = block_size;
}
Square.prototype = new Sim.Object();
wrote2 = false;
Square.prototype.init = function(x, y){
var type=MapModel.floorMap[x][y];
var reflectivity = 0;
switch(type){
case "grass":
var earthmap = "http://dl.dropboxusercontent.com/u/1142760/static/html/webgl/tiles/samatrawa.png";
break;
case "water":
var earthmap = "http://dl.dropboxusercontent.com/u/1142760/static/html/webgl/tiles/samawoda.png";
reflectivity = 1;
break;
}
//console.log(earthmap);
var geometry = new THREE.CubeGeometry(this.size, this.size, this.size );
var texture = THREE.ImageUtils.loadTexture(earthmap);
var material = new THREE.MeshPhongMaterial( { map: texture, color: 0xffffff, reflectivity: reflectivity } );
material.depthWrite = true;
var mesh = new THREE.Mesh( geometry, material );
mesh.translateX(x*this.size);
mesh.translateY(y*this.size);
mesh.renderDepth = y*block_size;
if(!wrote2){
wrote2=true;
console.log('square renderDepth:', mesh.renderDepth, 'square mesh.position.y:', mesh.position.y);
console.log('square material.depthWrite', material.depthWrite);
}
this.setObject3D(mesh);
}
Square.prototype.update = function()
{
// "I feel the Earth move..."
//this.object3D.rotation.y += 0.1;
//Sim.Object.prototype.update.call(this);
}
// Custom Sun class
Sun = function()
{
Sim.Object.call(this);
}
Sun.prototype = new Sim.Object();
Sun.prototype.init = function()
{
// Create a point light to show off the earth - set the light out back and to left a bit
var light = new THREE.DirectionalLight( 0xC5BC98, 2);
light.position.set(-10, 0, 20);
// Tell the framework about our object
this.setObject3D(light);
}
MapObject = function(){
Sim.Object.call(this);
}
MapObject.prototype = new Sim.Object();
wrote=false
MapObject.prototype.init = function(x, y, type){
switch(type){
case "tree":
var textureURL = "http://dl.dropboxusercontent.com/u/1142760/static/html/webgl/tiles/samodrzewo.png";
break;
case "water":
var textureURL = "http://dl.dropboxusercontent.com/u/1142760/static/html/webgl/tiles/samawoda.png";
break;
}
//console.log(textureURL);
var geometry = new THREE.PlaneGeometry(1*block_size, 2*block_size);
var texture = THREE.ImageUtils.loadTexture(textureURL);
var material = new THREE.MeshPhongMaterial( { map: texture, transparent:true } );
material.depthWrite = false;
var mesh = new THREE.Mesh( geometry, material );
mesh.position.x=x*block_size;
mesh.position.y=y*block_size;
mesh.translateZ(2*block_size);
mesh.rotation.x = Math.round(45 * 100 * Math.PI /180)/100;
//mesh.renderDepth = y*block_size;
mesh.renderDepth = -y*1000 ;
if(!wrote){
console.log('object renderDepth:', mesh.renderDepth, 'object mesh.position.y:', mesh.position.y);
console.log('object material.depthWrite', material.depthWrite);
wrote = true;
}
//console.log(mesh.rotation.x);
this.setObject3D(mesh);
}
var renderer = null;
var scene = null;
var camera = null;
var mesh = null;
$(document).ready(
function() {
var container = document.getElementById("container");
var app = new MapApp();
app.init({ container: container });
app.run();
}
);
最佳答案
这个问题一般不能通过开启/关闭深度测试/写入来解决。这个答案对此有很好的解释:Transparent textures behaviour in WebGL
因此只能通过按正确顺序绘制透明对象来解决。解决方案是(主要是默认的 three.js 行为!):
- 保持深度测试/写入启用(无论如何你很少禁用它)。
- 启用对象排序:
app.renderer.sortObjects = true;
虽然我没有看到它在您的代码中的什么地方被禁用了。 - 仅当您看到伪像时才手动设置 renderDepth。
但是,在您的情况下,事实证明您的 three.js 版本在重新排序方面做得不好(可能是一些不稳定的排序,我不会深入研究)所以您会得到看似随机的工件。更新到最新版本可以解决这个问题。
工作 fiddle :http://jsfiddle.net/UgZxc/12/
作为旁注:下次尝试减少代码示例/ fiddle ,以及依赖项的数量。里面有很多不相关的代码。
关于html - 在 Three.js 中使用透明纹理管理 z 缓冲,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20305439/