使用Three.js中的透明纹理管理z缓冲

 喋血梦_600 发布于 2023-02-13 16:57

我正在尝试使用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/

作为旁注:尝试下次减少代码示例/小提琴,以及依赖项的数量.那里有很多不相关的代码.

1 个回答
  • 通常,通过打开/关闭深度测试/写入不能解决该问题.这个答案很好地解释了:WebGL中的透明纹理行为

    因此,只能通过以正确的顺序绘制透明对象来解决.解决方案是(主要是默认的three.js行为!):

    保持深度测试/写入(无论如何你很少禁用它).

    启用对象排序:app.renderer.sortObjects = true;虽然我没有看到代码中的哪个位置被禁用.

    仅在看到工件时手动设置renderDepth.

    但是,在你的情况下,事实证明你的three.js版本在重新排序时做得不好(可能是一些不稳定的排序,我不会深入研究),所以你会得到看似随机的文物.更新到最新的构建修复.

    工作小提琴:http://jsfiddle.net/UgZxc/12/

    作为旁注:尝试下次减少代码示例/小提琴,以及依赖项的数量.那里有很多不相关的代码.

    2023-02-13 17:01 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有