2012-10-23 5 views
5

Uso Box2D con WebGL. Box2D richiede una frequenza fotogrammi costante (i passaggi temporali per i suoi aggiornamenti "mondiali").requestAnimFrame non può fornire una frequenza fotogrammi costante, ma il mio motore fisico ne ha bisogno

function update(time) {//update of box2d world 
    world.Step(
      1/60 // 1/frame-rate 
     , 3  //velocity iterations 
     , 8  //position iterations 
    ); 

Ma ho letto che requestAnimFrame definito come sotto è la strada giusta da percorrere.

 requestAnimFrame = (function() { 
    return window.requestAnimationFrame || 
    window.webkitRequestAnimationFrame || 
    window.mozRequestAnimationFrame || 
    window.oRequestAnimationFrame || 
    window.msRequestAnimationFrame || 
    function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) { 
     window.setTimeout(callback, 1000/60); 
    }; 
})(); 

requestAnimFrame non mi dà un frame rate costante e quindi le variabili di mio Box2D stanno andando non sincronizzato.

C'è una soluzione a questo?

Giovanni (Cotch) soluzione [EDIT] quando sembra implementate come questo:

function interpolate(dt) { 
    var t = dt/time_step; 
    body_coordinates = (1-t) * body_coordinates + t * next_body_coordinates; 
} 

var physicsDt = 0; 
function tick() { 
    var time_now = new Date().getTime(); 
    var dt = time_now - last_time; //Note that last_time is initialized priorly 
    last_time = time_now; 
    physicsDt += dt; 
    clear_the_screen(); 
    requestAnimFrame(tick); 
    drawEverything(); 
    if(physicsDt >= time_step) { 
     update(); 
     physicsDt -= time_step; 
    } 
    interpolate(dt); 
} 

Nota che la mia funzione di aggiornamento di fisica si prende cura che siano impostati i next_attribue s. E inoltre, una fisica update è chiamato prima di questo, per mantenere il mondo della fisica avanti di 1 fotogramma.

Il risultato

l'animazione è abbastanza liscia, tranne che per quei tempi, quando riesco a vedere alcuni salti davvero male e casuale apparire micro-movimenti.

ho pensato che i seguenti problemi non sono stati affrontati nella soluzione:

----> 1)dt può diventare più grande di time_step: Questo renderebbe dt/time_step maggiore di 1, che rovinerebbe le equazioni di interpolazione.

Quando dt rimane più grande di time_step in modo coerente, i problemi aumenterebbero. E 'possibile superare il problema del divario temporale che diventa più grande di time_step?

Voglio dire, anche se teniamo il mondo un fotogramma prima del rendering, se intervalli di tempo sempre maggiore di rimanere time_step, non ci sarebbe voluto molto passare che "avanti" frame.

----> 2) Imagine dt essendo minore time_step da 1 ms. Quindi, il mondo non viene aggiornato una volta. Ora l'interpolazione viene eseguita e viene trovata la posizione approssimativa (1 ms dietro dove avrebbe dovuto essere).

Diciamo che la prossima volta non si vedrà alcuna differenza tra dt e time_step.

Ora, nessuna interpolazione viene eseguita considerando che dt e time_step sono uguali. Quindi, la prossima che viene disegnata è la "prima" frame nel mondo, giusto? (Utilizzando quelle equazioni, con t = 1)

Ma con precisione, il mondo reso dovrebbe essere che 1ms dietro la quale era prima. Voglio dire, che 1ms con cui era dietro la cornice del mondo non dovrebbe svanire. Ma con t = 1, disegna la cornice del mondo fisico e dimentica quel millesimo.

Mi sbaglio sul codice o sui 2 punti precedenti?

Vi chiedo di chiarire questi problemi.

[EDIT]

ho chiesto l'autore di this pagina web, di un modo di disegnare in modo efficiente molte forme, nei commenti there.

ho imparato a fare in questo modo: sto risparmiando bufferData chiamate mantenendo buffer separati per ogni forma e chiamando createBuffer, bindBuffer, bufferData solo una volta durante init.

Ogni rinfresco la schermata, devo iterare su tutte le forme e devo chiamare enableVertexAttribArray e vertexAttribPointer dopo tampone di legame della forma desiderata (usando bindBuffer).

Le mie forme non cambiano nel tempo. Ce ne sono solo una varietà (come poligoni, cerchi, triangoli) che rimangono dall'inizio alla fine.

risposta

6

È necessario disaccoppiare i tempi di simulazione della simulazione fisica dal tempo di rendering vsync. La soluzione più semplice è quella di fare questo:

frameCallback(dt) { 
    physicsDt += dt; 
    if (physicsDt > 16) { 
    stepPhysics(); 
    physicsDt -= 16; 
    } 
    renderWorld(); 
    requestAnimFrame(frameCallback); 
} 

Il più grande problema qui è che a volte ti verrà il rendering di un mondo della fisica obsoleto, per esempio, se physicsDt era 15 alcun aggiornamento di simulazione si verificherà, ma gli oggetti non avrebbe spostato quasi un intero fotogramma per quel punto nel tempo. È possibile aggirare il problema mantenendo la fisica 1 davanti al rendering e linearmente interpolando le posizioni dell'oggetto nel renderer. Qualcosa di simile:

var t = dt/16.0; 
framePosition = (1-t) * previousFramePositions + (t) * nextFramePositions; 

questo modo i vostri oggetti si muovono senza problemi anche se si sta rendendo non è sincronizzato con la simulazione della fisica. Fatemi sapere se avete domande.

John

+0

Non sono sicuro di come quel codice disaccoppia la simulazione fisica. Quindi, 'frameCallBack' è la funzione di" aggiornamento "? Ci vuole differenza nel tempo dell'ultima chiamata e la chiamata corrente come argomento, e solo dopo che il frame della fisica corrente è durato per 32 millisecondi, aggiorna il mondo. Ho ragione? – batman

+0

Ma cosa succede se l'aggiornamento del mondo e l'aggiornamento dello schermo devono avvenire dopo intervalli di tempo comparabili? Diciamo che il mio mondo della fisica aspetta 60 ms prima di un aggiornamento. L'aggiornamento della prima schermata avviene a 59 ms. Il mondo della fisica non si aggiornerà poiché non sono passati 60 ms dall'ultimo aggiornamento. La schermata successiva si aggiorna? dopo altri 59 ms. Ora aggiornamenti sul mondo della fisica. Ma quando dovrebbe essere aggiornato dopo 60 ms, ora avviene dopo 118 ms. Non è molto impreciso? – batman

+0

Oh e non capisco quel secondo frammento che hai inserito.Puoi spiegare per favore? – batman

1

requestAnimFrame non è pensato per garantire una frequenza fotogrammi costante: è progettato in modo che il browser esegua solo i calcoli per i frame effettivamente disegnati.

Se si desidera/deve calcolare frame che non sono disegnati, non è la strada da percorrere.

+0

Il browser richiama nel mio caso. Simula la fisica tramite WebGL. – batman