2010-03-15 6 views
6

Sto eseguendo un'animazione in un'app WinForms a 18.66666 ... fotogrammi al secondo (è sincronizzato con la musica a 140 BPM, motivo per cui il frame rate è strano). Ogni cel dell'animazione è precalcolata e l'animazione è gestita da un timer multimediale ad alta risoluzione. L'animazione è liscia, ma sto vedendo una quantità significativa di "strappi", o artefatti che derivano da celle che vengono catturate in parte attraverso un aggiornamento dello schermo.Come eliminare lo strappo dall'animazione?

Quando prendo l'insieme di cels resi dal mio programma e li scrivo in un file AVI, e poi riproduco il file AVI in Windows Media Player, non vedo alcuno strappo. Presumo che WMP riproduca il file senza problemi perché utilizza DirectX (o qualcos'altro) ed è in grado di sincronizzare il rendering con l'attività di aggiornamento dello schermo. Non sta cambiando la frequenza dei fotogrammi, poiché l'animazione rimane sincronizzata con l'audio.

È per questo che WMP è in grado di eseguire il rendering dell'animazione senza strappi o mi manca qualcosa? C'è un modo in cui posso usare DirectX (o qualcos'altro) per consentire al mio programma di essere a conoscenza di dove si trova la linea di scansione corrente, e se è così, c'è un modo in cui posso usare quella informazione per eliminare la lacerazione senza usare effettivamente DirectX per la visualizzazione dei Cels? O devo usare completamente DirectX per il rendering per far fronte a questo problema?

Aggiornamento: dimenticato un dettaglio. La mia app esegue il rendering di ogni cella su una PictureBox utilizzando Graphics.DrawImage. È molto più lento dell'utilizzo di BitBlt, in modo tale da eliminare almeno parte del problema con BitBlt?

Aggiornamento 2: l'effetto che sto vedendo non è sicuramente sfarfallio (che è diverso dallo strappo). Il mio pannello è a doppio buffer, imposta gli stili di controllo per AllPaintingInWmPaint, UserPaint, OptimizedDoubleBuffer ecc., Sovrascrive onPaintBackGround e così via. Tutti questi sono necessari per eliminare lo sfarfallio, ma il problema dello strappo rimane. È particolarmente pronunciato quando l'animazione ha oggetti o oggetti molto veloci che cambiano molto rapidamente dalla luce allo scuro. Quando gli oggetti si muovono lentamente e non cambiano rapidamente colore, l'effetto di strappo è molto meno evidente (perché i cicli consecutivi sono sempre molto simili tra loro).

+0

Stai eseguendo il rendering su un thread separato? –

+0

@Ardman: sì, il rendering viene eseguito su un thread separato (separato dal thread dell'interfaccia utente). – MusiGenesis

risposta

3

Lo strappo si verifica quando l'aggiornamento dell'immagine non è sincronizzato con la frequenza di aggiornamento del monitor. Il monitor mostra parte dell'immagine precedente, parte della nuova immagine. Quando gli oggetti nell'immagine si muovono velocemente, l'effetto è abbastanza evidente.

Non è risolvibile in Windows Form, non è possibile accedere al segnale di v-sync della scheda video. È possibile in un DirectX app.

0

È preferibile utilizzare directx (o opengl) per tali attività. Ma se vuoi usare solo winform usa la proprietà DoubleBuffered.

+1

Uso DoubleBuffered per eliminare lo sfarfallio, ma non aiuta a strappare. – MusiGenesis

+0

Inoltre, sto cercando di rendere la mia app multi-piattaforma con Mono, quindi voglio evitare cose specifiche della piattaforma come DirectX, se possibile. – MusiGenesis

+0

quindi usa opengl! è analogico multipiattaforma di directx. beh, pensavo che le winforms non fossero cross-pl. – Andrey

0

Doppio buffer.

È possibile abilitare il doppio buffering utilizzando gli stili di Windows o, cosa che probabilmente è più facile, è disegnare un'immagine da fuori schermo e quindi scambiarli.

Se ciò non funziona, la cosa migliore da fare è bitblit e doppio buffer.

Essenzialmente è lo stesso.

Avere un riferimento a due bitmap, uno è lo schermo, l'altro è il buffer. Prima si disegna sul buffer, quindi si confonde tutta la cosa sullo schermo. In questo modo si scrivono sempre solo dati in tempo reale nel buffer. Lo sceen mostra semplicemente qualcosa che hai fatto prima (stile blu peter)

+2

Scusa, avrei dovuto essere più chiaro nella mia domanda. Il doppio buffering (che sto già utilizzando) non aiuta con gli effetti di strappi. – MusiGenesis

+0

Ah ok non preoccuparti. Non usare la casella immagine e scrivere direttamente sullo schermo (con doppio buffering) – Chris

2

Ho provato l'idea del doppio buffer sul progetto al quale sto lavorando al momento, ma con questo non ho ottenuto risultati molto buoni. Alla fine, ho creato il seguente:

  1. Un System.Drawing.Bitmap per il mio buffer fuori schermo. Decodifica l'animazione in questa bitmap.
  2. Un controllo utente ha le stesse dimensioni dell'immagine in (1) e il metodo OnPaintBackground era vuoto (nessun disegno, nessuna chiamata alla classe base) e OnPaint ha creato un'immagine Graphics.Draw per copiare l'immagine fuori schermo sullo schermo.

Ora, hai una strana velocità di animazione, quindi lo strappo ha quasi certamente a che fare con una mancata corrispondenza tra la frequenza di aggiornamento dello schermo e la frequenza di aggiornamento dello schermo. Si sta aggiornando lo schermo a metà della schermata di aggiornamento in modo che lo schermo stia disegnando il vecchio frame nella parte superiore dello schermo e il nuovo frame nella parte inferiore dello schermo. Se è possibile sincronizzare la frequenza dei fotogrammi con la frequenza di aggiornamento del display, lo strappo dovrebbe scomparire.

+1

Ciò che descrivi è essenzialmente ciò che sto facendo, sebbene io usi due bitmap come buffer fuori schermo, in modo che possa aggiornarne uno mentre l'altro è disegnato sullo schermo. Ho intenzione di provare a sincronizzare la mia animazione con la mia frequenza di aggiornamento (60Hz) e vedere cosa fa per me. – MusiGenesis

0

Lo strappo è un artefatto da una cornice disegnata sopra un'altra. L'unico modo sicuro per evitarlo è a) attendere da vsync o b) disegnare dietro il raggio (questo è piuttosto complicato). Il doppio tampone da solo non garantisce contro lo strappo poiché si può avere un doppio buffer ma si disegna ancora avendo spento il vsync. Alcune carte potrebbero anche avere l'opzione di attesa vsync "forzata". È necessario controllare la documentazione relativa a vsync e come verificare dove si trova. Questo è l'unico modo sicuro per farlo. Inoltre, tieni presente che questo bloccherà il tuo framerate.

+1

Ci deve essere un modo per animare ciò senza strappare usando il mio framerate scelto (il framerate è vincolato perché l'animazione deve essere sincronizzata con la musica), perché WMP è in grado di renderlo bene senza strappi. Forse WMP fa una specie di interpolazione tra frame? – MusiGenesis