Animation Three.js在100立方体动画上崩溃
在我的场景中,我有4个点光源,其中3个连接在相机上,还有大约100到300个立方体。 我有很多种类的立方体,每个都在100-300之间。根据用户菜单选择,“我的场景”中随时只能出现1类立方体 (包含100个立方体的类别)renderer.info:Animation Three.js在100立方体动画上崩溃,animation,3d,three.js,webgl,Animation,3d,Three.js,Webgl,在我的场景中,我有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
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
});
由于每个立方体的纹理不同,因此每次循环中都会显示productMaterial
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 )
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 )
此外,您将注意到helix内部的另一个函数调用,这一个:this.models.reset(category)代码>
这是下面的代码,实际上是重置对象位置,并将其设置为visible=false
,最后将其从场景中移除
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 )
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 )
在个人电脑里,一切都很顺利,我的速度是每秒36帧。我的gpu是一个新的nvidia GTX(我不知道36是否可以接受)
问题是,当我试图用最新的chrome在Nexus5上运行我的应用程序时,我在场景外的立方体和其他进来的立方体之间的转换中得到了巨大的fps损失。大多数情况下,这会导致chrome崩溃。。。除此之外,如果我不改变类别,也没有播放任何动画,它在我的手机中也可以正常工作
PS:我无法合并几何体,因为每个网格都必须在用户选择后自行移动。(如果我至少没有弄错的话)
性能下降/崩溃的原因可能是什么?如果在场景外移动200个立方体,在场景内移动200个立方体,您将如何处理类似的场景?请记住,我对three.js还是新手,有什么建议我应该考虑一下吗
任何其他来源的要求,这可能是原因,请让我知道,我会更新我的问题 首先,36 fps是可以接受的。根据经验,我使用25 fps作为最小值
现在来看问题。Nexus5的gpu比你的电脑慢得多。因为着色器直接传递到gpu,所以速度很重要。当你试图在廉价pc上玩crysis游戏时,gpu的功能还不够强大,无法足够快地处理所有数据
将所有立方体几何体添加到单个网格中可能是一种解决方案,可以使用三个.meshfaceMeterial
将不同的材质应用于每个立方体。具有100个几何体的单个网格的处理速度比具有1个几何体的100个网格快。但正如我所说。也可能这根本解决不了任何问题,更像是一场圣母玛利亚
编辑:在单个网格中添加几何体并检测单击的几何体
我仔细考虑了一下,有可能检测到点击的几何体。这并不漂亮,但它可能会给你一些如何做得漂亮的想法。
只需向几何体的面添加另一个特性
var addGeometry = function(baseGeometry, addedGeometry){
for(i in addedGeometry.faces){
addedGeometry.faces[i].parent = addedGeometry;
}
baseGeometry.add(addedGeometry);
}
然后,在光线投射时,您不调用对象
属性,而是调用面.parent
属性,它应该包含单击的几何体,您可以随意操纵这些几何体
但是,我也不知道这将如何在性能方面发挥作用。不过值得一试
您还可以尝试使用其他功能 我也考虑过这一点,合并几何体,但问题是我需要在单击/用户选择时为每个立方体分别设置动画。因此,我想如果我要合并它们,如果用户单击,我将无法为1个立方体设置动画。动画不会有太大问题,您可以调整几何体相对于网格的位置。单击是另一个故事,您可以获得距离、面、面索引、对象和点,但不幸的是,没有被单击的对象子对象。你可以检查哪个面属于哪个几何体,但我担心这只会导致更多的问题,解决不了。你仍然可以在合并的几何体中设置立方体顶点的动画。是的,就像我说的那样,这不是问题。检测单击合并几何体的哪个子级是一个关键问题。