html - 在 Three.js 中使用透明纹理管理 z 缓冲

标签 html canvas 3d three.js

我正在尝试使用 THREE.js 在 WebGL 中创建一个简单的 map ,其中包含平坦的纸状树木。我无法理解库如何处理 z 缓冲。我试过使用 renderer.sortObjects 参数以及 material.depthWrite 和 object.renderDepth,但似乎没有任何组合起作用——我要么让库以正确的顺序显示树(那些离相机较远的树被遮挡了离相机较近的人),但有奇怪的透明度故障,或者我设法使透明度正确,但离屏幕较远的树木出现在距离较近的树木的顶部。 经过几个小时的努力,我最终得到了: screenshot

如您所见,右侧的树渲染在左侧树的顶部。

请在我完全发疯之前帮助我 :)

这是我的代码: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/

相关文章:

python - Python 中的 3D 网格图

animation - 3D动画翻页的算法?

html - 将左浮动项和右浮动项之间的内容居中,以便它们位于页面的中心

iphone - 开发 iphone 应用程序 - GUI 是 HTML 吗?

JavaScript 使用 3 轴鼠标 Canvas 绘制

javascript - 如何使用渐变重新在 HTML5 Canvas 中绘制一条线

从驻点到任意点的 3D 三角变换

html - CSS Thumbnail no subtitle - 只有在显示放大的缩略图时才有字幕

php - 在 php 中显示图像

javascript - HTML5 渐变 : changing color of gradient changes color of triangle on a canvas