我正在尝试使用THREE.js创建一个简单的地图,其中的平面纸状树木在WebGL中伸出.我无法理解库如何处理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(); } );
morris4.. 6
通常,通过打开/关闭深度测试/写入不能解决该问题.这个答案很好地解释了:WebGL中的透明纹理行为
因此,只能通过以正确的顺序绘制透明对象来解决.解决方案是(主要是默认的three.js行为!):
保持深度测试/写入(无论如何你很少禁用它).
启用对象排序:app.renderer.sortObjects = true;
虽然我没有看到代码中的哪个位置被禁用.
仅在看到工件时手动设置renderDepth.
但是,在你的情况下,事实证明你的three.js版本在重新排序时做得不好(可能是一些不稳定的排序,我不会深入研究),所以你会得到看似随机的文物.更新到最新的构建修复.
工作小提琴:http://jsfiddle.net/UgZxc/12/
作为旁注:尝试下次减少代码示例/小提琴,以及依赖项的数量.那里有很多不相关的代码.
通常,通过打开/关闭深度测试/写入不能解决该问题.这个答案很好地解释了:WebGL中的透明纹理行为
因此,只能通过以正确的顺序绘制透明对象来解决.解决方案是(主要是默认的three.js行为!):
保持深度测试/写入(无论如何你很少禁用它).
启用对象排序:app.renderer.sortObjects = true;
虽然我没有看到代码中的哪个位置被禁用.
仅在看到工件时手动设置renderDepth.
但是,在你的情况下,事实证明你的three.js版本在重新排序时做得不好(可能是一些不稳定的排序,我不会深入研究),所以你会得到看似随机的文物.更新到最新的构建修复.
工作小提琴:http://jsfiddle.net/UgZxc/12/
作为旁注:尝试下次减少代码示例/小提琴,以及依赖项的数量.那里有很多不相关的代码.