在 Three.js 中使用透明纹理管理 z 缓冲 [英] Managing z-buffering with transparent textures in Three.js

查看:24
本文介绍了在 Three.js 中使用透明纹理管理 z 缓冲的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 THREE.js 在 WebGL 中创建一个简单的地图,其中带有扁平的纸状树木.我无法理解库如何处理 z 缓冲.我试过使用 renderer.sortObjects 参数以及 material.depthWrite 和 object.renderDepth,但似乎没有任何组合有效 - 我要么让库以正确的顺序显示树(远离相机的那些树被挡住了)靠近相机的那些),但是有奇怪的透明度故障,或者我设法获得了正确的透明度,但是离屏幕较远的树出现在较近的树的顶部.经过几个小时的努力,这就是我的结果:

I am trying to create a simple map with flat, paper-like trees sticking out of it in WebGL with THREE.js. I cannot grasp how the library handles z-buffering. I've tried playing with renderer.sortObjects parameter as well as with material.depthWrite and object.renderDepth, but no combination seems to be working - I either get the library to display the trees in proper order (those further from the camera are obstructed by those closer to the camera), but with weird transparency glitches, OR I manage to get the transparency right, but the trees further from the screen appear on top on those that are closer. After hours of trying to get this right, this is what I ended up with:

如您所见,更靠右侧的树木呈现在左侧的顶部.

As you can see, the trees that are more to the right are rendered on top on those to the left.

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

Please help me before I go completely nuts :)

这是我的代码: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();
                }
            );

推荐答案

一般情况下,这个问题不能通过打开/关闭深度测试/写入来解决.这在这个答案中有很好的解释:WebGL 中的透明纹理行为

Generally, this problem cannot be solved by turning depth testing/writing on/off. This is well explained in this answer: Transparent textures behaviour in WebGL

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

Therefore it can only be solved by drawing the transparent objects in the correct order. The solution is (mostly the default three.js behavior!):

  • 保持启用深度测试/写入(无论如何你很少禁用它).
  • 启用对象排序:app.renderer.sortObjects = true; 尽管我在您的代码中没有看到它被禁用的位置.
  • 仅当您看到伪影时才手动设置 renderDepth.
  • Keep depth testing/writing enabled (you rarely disable this anyway).
  • Enable sorting of objects: app.renderer.sortObjects = true; although i don't see where in your code it is disabled.
  • Set renderDepth manually only if you see artifacts.

但是,就您而言,结果表明您的three.js 版本在重新排序方面做得很差(可能是一些不稳定的排序,我不会深入研究),因此您会得到看似随机的工件.更新到最新版本修复了这个问题.

However, in your case, it turns out that your three.js version does a bad job at reordering (maybe some unstable sorting, I won't dig into that) so you get seemingly random artifacts. Updating to the latest build fixes that.

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

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

As a sidenote: Try reducing your code examples/fiddles next time, and also the number of dependencies. There's a lot of unrelated code in there.

这篇关于在 Three.js 中使用透明纹理管理 z 缓冲的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆