2014-12-23 12 views
6

Nella mia scena ho 4 punti luce 3 di quelli collegati sulla fotocamera e circa 100 a 300 cubi. Ho molte categorie di cubi, ognuno compreso tra 100 e 300. Solo una categoria di cubi può apparire nella mia scena in qualsiasi momento in base alla selezione del menu utente.Three.js che si blocca su animazione 100 cubi

(categoria con 100 cubetti) renderer.info:

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

In un ciclo genero miei cubi per ogni categoria come questo:

var materials = [ 
    backgroundMaterial, 
    backgroundMaterial, 
    backgroundMaterial, 
    backgroundMaterial, 
    productMaterial, 
    backgroundMaterial 
]; 

var cubeMaterial = new THREE.MeshFaceMaterial(materials); 

var object3D = new THREE.Mesh(geometryBox, cubeMaterial); 

Il materiale backgroundMaterial è definito fuori dal giro una volta;

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 
}); 

e il prodottoMateriale ogni volta all'interno del ciclo poiché la trama è diversa per ogni cubo.

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 
}); 

Inoltre non aggiungo le maglie in scena a questo punto, e sono impostati visible = false

dopo che spingono le cubetti in un oggetto di array, ogni array dentro quell'oggetto è un categoria di cubi con lunghezza compresa tra 100 e 300.

All'avvio dell'applicazione eseguo un'animazione simile a quella del muggito che introduce una categoria di cubi nella scena.

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) 

Inoltre si noterà un'altra chiamata di funzione all'interno dell'elica, questo: this.models.reset(category);

Qual è il codice qui sotto ed è essenzialmente reseting la posizione degli oggetti e li mette a visible = false e, infine, la loro rimozione dalla scena.

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) 

In un pc funziona tutto liscio e sono in esecuzione con 36 fps. La mia gpu è una nuova nvidia GTX (non so se 36 sia accettabile).

Il problema è che quando provo a eseguire la mia applicazione sul mio nexus 5 con l'ultimo chrome, ho una perdita enorme di fps tra la transizione di cubi fuori dalla scena e gli altri cubi che entrano. Il più delle volte questo risultato in un crash di cromo ... A parte questo, se non cambio categoria e non si riproducono animazioni, funziona bene sul mio cellulare.

PS:. Non posso unire le geometrie dal momento che ogni rete deve muoversi su ogni proprio su selezione utente (se non mi sbaglio atleast)

Quale potrebbe essere la ragione di questo calo/crash prestazioni, e come ti avvicineresti ad uno scenario simile in cui muovi 200 cubetti fuori dalla scena e altri 200 all'interno della scena? Ci sono dei consigli che dovrei prendere in considerazione, tenendo presente che sono ancora nuovo su three.js.

Qualsiasi altra fonte richiesta potrebbe essere la ragione, fatemelo sapere e aggiornerò la mia domanda.

risposta

2

prima di tutto, 36 fps sono accettabili. Come regola generale uso 25 fps per essere il minimo indispensabile.

ora per il problema. un nesso 5 ha una gpu molto più lenta del tuo pc.poiché gli shader vengono passati direttamente alla gpu, la velocità conta. è lo stesso problema quando si prova a giocare a Crysis su un PC economico, la GPU non è abbastanza potente da gestire tutti i dati abbastanza velocemente.

it MAGGIO essere una soluzione per aggiungere tutte le geometrie del cubo a una singola mesh, magari con un THREE.MeshFaceMaterial per applicare i diversi materiali a ciascun cubo. una singola mesh con 100 geometrie viene elaborata più rapidamente di 100 mesh con 1 geometria. ma come ho detto potrebbe anche essere questo non risolve affatto, è più di un grandino.

MODIFICA: aggiunta delle geometrie in una singola mesh e rilevamento di quale geometria è stata selezionata.

Ci ho pensato un po 'di più, ed è possibile rilevare la geometria cliccata. non è carino ma potrebbe darti qualche idea su come farlo bene. semplicemente aggiungi un'altra proprietà alle facce della geometria.

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

poi, quando raycasting, non si chiama la proprietà object, ma la proprietà face.parent, dovrebbe contenere la geometria cliccato, che è possibile manipolare a piacimento.

ma, ancora una volta, non so come funzionerà in termini di prestazioni. Vale la pena provare.

qualcos'altro che potresti provare utilizzando webworkers.

+0

Ho pensato anche a questo, per unire le geometrie, ma il fatto è che ho bisogno di animazioni separate per ogni cubo al clic/selezione dell'utente. Quindi suppongo che se dovessi unirli non sarei in grado di animare 1 cubo se l'utente fa clic su di esso. – Syd

+0

L'animazione non sarà un gran problema, puoi semplicemente regolare la posizione della geometria rispetto alla mesh. il clic è un'altra storia, puoi ottenere la distanza, faccia, facciaIndex, oggetto e punto, ma sfortunatamente non il bambino oggetto che è stato cliccato. Puoi controllare quale faccia appartiene a quale geometria, ma temo che ciò causerebbe solo più problemi di quanti ne risolva. –

+0

è ancora possibile animare i vertici del cubo nella geometria unita. – makc