三.js在 100 个立方体动画上崩溃



在我的场景中,我有 4 个点光源,其中 3 个安装在相机上,大约 100 到 300 个立方体。我有很多类别的立方体,每个类别都在 100 - 300 之间。根据用户菜单选择,我的场景中任何时候只能出现 1 类立方体。

(包含 100 个立方体的类别(renderer.info:

memory: 
  Objectgeometries: 2
  programs: 3
  textures: 100
render: 
  calls: 203
  faces: 1360
  points: 0
  vertices: 4080

在一个循环中,我为每个类别生成我的多维数据集,如下所示:

var materials = [   
    backgroundMaterial,
    backgroundMaterial,
    backgroundMaterial,
    backgroundMaterial,
    productMaterial,
    backgroundMaterial
];
var cubeMaterial = new THREE.MeshFaceMaterial( materials );
var object3D = new THREE.Mesh( geometryBox, cubeMaterial );

材料backgroundMaterial在循环外定义一次;

var backgroundMaterial = new THREE.MeshPhongMaterial({
    color: this.options.models.boxColor,
    specular: this.options.models.boxSpecular,
    //emissive : 0xefefef,
    //side: THREE.DoubleSide,
    overdraw: false,
    transparent: false,
    metal:true,
    shininess: this.options.models.boxShininess,
    reflectivity: this.options.models.boxReflectivity,
    fog:false
});

和产品材料每次在循环内,因为每个立方体的纹理都不同。

var productMaterial = new THREE.MeshBasicMaterial({
    map: productModelTexture,
    color: that.options.models.boxColor,
    specular: that.options.models.boxSpecular,
    //emissive : 0xefefef, 
    side: THREE.FrontSide,
    overdraw: false,
    transparent: false,
    metal:true,
    shininess: that.options.models.textureShininess,
    reflectivity: that.options.models.textureReflectivity,
    opacity: 1,
    fog:false
});

此外,我此时没有将网格添加到场景中,它们设置为visible = false

之后,我将我的立方体推入数组对象中,该对象中的每个数组都是一类长度在 100 - 300 之间的立方体。

当我的应用程序启动时,我运行一个动画,如波纹管,它将一类立方体带入场景。

helix : function( category ) {
    if ( this.models[category] && this.models[category].length > 0 ) {              
        TWEEN.removeAll();
        new TWEEN.Tween( this.camera.position ).to( {x:0,y:0,z:90000}, 1000 ).easing( TWEEN.Easing.Exponential.InOut ).start(); 
        new TWEEN.Tween( this.camera.rotation ).to( {x:0,y:0,z:0}, 1000 ).easing( TWEEN.Easing.Exponential.InOut ).start();             
        this.models.reset( category );
        for ( var i in this.models[category] ) {
            var model = this.models[category][i];
                model.visible = true;
                this.scene.add( model );
            new TWEEN.Tween( model.position ).to({
                x: model.helix.position.x,
                y: model.helix.position.y,
                z: model.helix.position.z
            }, randBtwn( 1000, 3000 ) ).easing( TWEEN.Easing.Exponential.InOut ).delay( 1001 ).start();
            new TWEEN.Tween( model.rotation ).to( {
                x: model.helix.rotation.x,
                y: model.helix.rotation.y,
                z: model.helix.rotation.z
            }, randBtwn( 1000, 3000 ) ).easing( TWEEN.Easing.Exponential.InOut ).delay( 1001 ).onComplete(function(){
            }).start();
        }
    }
}.bind( that )

此外,您会注意到螺旋系统中的另一个函数调用,这个:this.models.reset( category );

这是下面的代码,本质上是重置对象位置并将它们设置为visible = false,最后将它们从场景中删除。

reset : function( category, callback ) {
    for ( var j in this.models ) {
        if ( this.models[j] instanceof Array && this.models[j].length > 0 && category !== j ) {
            for ( var i in this.models[j] ) {
                var model = this.models[j][i];
                    model.visible = true;
                new TWEEN.Tween( model.position ).to({
                    x: model.outside.position.x,
                    y: model.outside.position.y,
                    z: model.outside.position.z
                }, 1000 ).easing( TWEEN.Easing.Exponential.InOut ).start();
                new TWEEN.Tween( model.rotation ).to( {
                    x: model.outside.rotation.x,
                    y: model.outside.rotation.y,
                    z: model.outside.rotation.z
                }, 1000 ).easing( TWEEN.Easing.Exponential.InOut ).onComplete(function ( m ){
                    m.visible = false;
                    this.scene.remove( m );
                    if ( callback ) {
                        callback();
                    }
                }.bind( that, model )).start();
            }
        }
    }
}.bind( that )  

在 PC 中一切顺利,我以 36 fps 的速度运行。我的GPU是一个新的nvidia GTX(我不知道36是否可以接受(。

问题是,当我尝试使用最新的chrome在nexus 5上运行我的应用程序时,我在场景外的立方体和其他立方体进入之间的过渡之间得到了巨大的fps损失。大多数情况下,这会导致铬崩溃...除此之外,如果我不更改类别并且没有播放动画,它在我的手机中工作正常。

PS:我无法合并几何形状,因为每个网格都必须在用户选择时自行移动。(如果我至少没记错的话(

这种性能下降/崩溃的原因可能是什么,您将如何处理类似的场景,即在场景外移动 200 个立方体,在场景内移动另外 200 个立方体?有什么提示我应该考虑吗,请记住,我仍然是三.js的新手。

任何其他来源可能是原因,请告诉我,我会更新我的问题。

首先,36 fps 是可以接受的。根据经验,我使用 25 fps 作为最低要求。

现在来谈谈问题。 Nexus 5的GPU比你的PC慢得多。 由于着色器直接传递给 GPU,因此速度很重要。 当您尝试在预算PC上玩孤岛危机时,这是同样的问题,GPU的功能不足以足够快地处理所有数据。

将所有立

方体几何形状添加到一个网格中可能是一种解决方案,也许可以THREE.MeshFaceMaterial将不同的材料应用于每个立方体。 具有 100 个几何形状的单个网格的处理速度比具有 1 个几何体的 100 个网格的处理速度更快。 但正如我所说。 也可能这根本解决不了任何问题, 这更像是冰雹玛丽。

编辑:在单个网格中添加几何图形并检测单击的几何图形。

我想了一下,可以检测到点击的几何形状。 它并不漂亮,但它可能会给你一些关于如何做得漂亮的想法。只需将另一个属性添加到几何图形的面上即可。

var addGeometry = function(baseGeometry, addedGeometry){
    for(i in addedGeometry.faces){
        addedGeometry.faces[i].parent = addedGeometry;
    }
    baseGeometry.add(addedGeometry);
}

然后,在进行光线投射时,您不调用 object 属性,而是调用 face.parent 属性,它应该包含单击的几何图形,您可以根据需要进行操作。

但同样,我不知道这将如何工作性能明智。不过值得一试。

您可以尝试的其他方法是使用WebWorkers。

最新更新