6 votes

Comment éliminer le déchirement de l'animation ?

Je fais tourner une animation dans une application WinForms à 18.66666... images par seconde (elle est synchronisée avec une musique à 140 BPM, ce qui explique le taux d'images bizarre). Chaque cellule de l'animation est précalculée, et l'animation est pilotée par un minuteur multimédia haute résolution. L'animation elle-même est fluide, mais je constate une quantité importante de "déchirures", c'est-à-dire d'artefacts résultant de la capture de cels à mi-chemin d'un rafraîchissement d'écran.

Lorsque je prends l'ensemble des images rendues par mon programme et que je les écris dans un fichier AVI, puis que je lis ce fichier AVI dans Windows Media Player, je ne vois aucun déchirement. Je suppose que WMP lit le fichier sans problème parce qu'il utilise DirectX (ou autre) et est capable de synchroniser le rendu avec l'activité de rafraîchissement de l'écran. Il ne modifie pas la fréquence d'images, car l'animation reste synchronisée avec l'audio.

Est-ce la raison pour laquelle WMP est capable d'effectuer le rendu de l'animation sans déchirure, ou est-ce que je rate quelque chose ? Existe-t-il un moyen d'utiliser DirectX (ou quelque chose d'autre) pour permettre à mon programme de savoir où se trouve la ligne de balayage actuelle, et si oui, existe-t-il un moyen d'utiliser cette information pour éliminer le déchirement sans utiliser DirectX pour l'affichage des images ? Ou dois-je utiliser pleinement DirectX pour le rendu afin de résoudre ce problème ?

Mise à jour J'ai oublié un détail. Mon application rend chaque cellule sur une PictureBox en utilisant Graphics.DrawImage. Est-ce que cela est beaucoup plus lent que l'utilisation de BitBlt, au point que je pourrais éliminer au moins une partie du déchirement en utilisant BitBlt ?

Mise à jour 2 L'effet que je vois n'est certainement pas du scintillement (qui est différent du déchirement). Mon panneau est à double tampon, il définit les styles de contrôle pour AllPaintingInWmPaint, UserPaint, OptimizedDoubleBuffer, etc. et surcharge onPaintBackGround, etc. Toutes ces mesures sont nécessaires pour éliminer le scintillement, mais le problème du déchirement demeure. Il est particulièrement prononcé lorsque l'animation comporte des objets qui se déplacent très rapidement ou des objets qui passent du clair au foncé très rapidement. Lorsque les objets se déplacent lentement et ne changent pas de couleur rapidement, l'effet de déchirement est beaucoup moins perceptible (parce que les cels consécutifs sont toujours très similaires les uns aux autres).

3voto

Hans Passant Points 475940

Le déchirement se produit lorsque la mise à jour de votre image n'est pas synchronisée avec la fréquence de rafraîchissement du moniteur. Le moniteur affiche une partie de l'image précédente, une partie de la nouvelle image. Lorsque les objets de l'image se déplacent rapidement, l'effet est très visible.

Ce n'est pas réparable dans Windows Forms, vous ne pouvez pas accéder au signal v-sync de l'adaptateur vidéo. Vous pouvez dans un Application DirectX .

2voto

Skizz Points 30682

J'ai essayé l'idée du double tampon sur le projet sur lequel je travaille en ce moment, mais je n'ai pas obtenu de très bons résultats. Au final, j'ai créé ce qui suit :

  1. Un System.Drawing.Bitmap pour mon tampon hors écran. Décodez l'animation dans ce bitmap.
  2. Un UserControl de la même taille que l'image en (1) et où la méthode OnPaintBackground était vide (pas de dessin, pas d'appel à la classe de base) et où le OnPaint faisait un Graphics.DrawImage pour copier l'image hors écran sur l'écran.

Vous avez un taux d'animation bizarre, donc le déchirement est presque certainement dû à un décalage entre le taux de mise à jour et le taux de rafraîchissement de l'écran. Vous mettez à jour l'écran à mi-chemin du rafraîchissement de l'écran, de sorte que l'écran affiche l'ancienne image en haut de l'écran et la nouvelle en bas de l'écran. Si vous pouvez synchroniser la fréquence d'images avec la fréquence de rafraîchissement de l'écran, le déchirement devrait disparaître.

0voto

Andrey Points 36869

Il est préférable d'utiliser directx (ou opengl) pour de telles tâches. Mais si vous voulez utiliser uniquement winforms utilisez DoubleBuffered propriété.

0voto

Chris Points 7877

Doublez le tampon.

Vous pouvez activer la double mise en mémoire tampon à l'aide des styles Windows ou, ce qui est sans doute plus simple, en dessinant une image hors écran, puis en les intervertissant.

Si cela ne fonctionne pas, la meilleure chose à faire est de faire un bitblit et un double tampon.

C'est essentiellement la même chose.

Vous avez une référence à deux bitmaps, l'un représentant l'écran, l'autre le tampon. Vous dessinez d'abord dans le tampon, puis vous transférez le tout à l'écran. De cette façon, vous n'écrivez que des données réelles dans le tampon. L'écran montre simplement quelque chose que vous avez fait plus tôt (style blue peter).

0voto

MikeT Points 1

La déchirure est un artefact résultant de la superposition d'un cadre sur un autre. Les seuls moyens sûrs de l'éviter sont a) d'attendre la vsync ou b) de dessiner derrière le faisceau (ce qui est assez délicat). La double mémoire tampon seule ne garantit pas l'absence de déchirure, car vous pouvez avoir une double mémoire tampon tout en dessinant avec la vsync désactivée. Certaines cartes peuvent également avoir l'option d'attente vsync "forced off". Vous devez vérifier la documentation concernant vsync et comment vérifier où elle se trouve. C'est la seule façon sûre de le faire. Gardez également à l'esprit que cela bloquera votre framerate.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X