2010-03-15 12 views
6

Używam animacji w aplikacji WinForms o wartości 18.66666 ... klatek na sekundę (jest zsynchronizowana z muzyką przy 140 BPM, dlatego częstotliwość klatek jest dziwna). Każda cel animacji jest wstępnie obliczana, a animacja jest sterowana za pomocą timera multimedialnego o wysokiej rozdzielczości. Animacja sama w sobie jest płynna, ale widzę znaczną część "łzawienia" lub artefaktów, które wynikają z tego, że celowniki zostały częściowo przechwycone podczas odświeżania ekranu.Jak wyeliminować łzy z animacji?

Po pobraniu zestawu obiektów renderowanych przez mój program i zapisaniu ich do pliku AVI, a następnie odtworzeniu pliku AVI w programie Windows Media Player, nie widzę żadnego rozerwania. Zakładam, że WMP odtwarza plik płynnie, ponieważ używa DirectX (lub czegoś innego) i jest w stanie zsynchronizować rendering z działaniem odświeżania ekranu. Nie zmienia to liczby klatek na sekundę, ponieważ animacja pozostaje zsynchronizowana z dźwiękiem.

Czy to jest powód, dla którego WMP potrafi renderować animację bez łez, czy też czegoś brakuje? Czy istnieje sposób, w jaki mogę korzystać z DirectX (lub czegoś innego) w celu umożliwienia mojemu programowi zorientowanie się, gdzie znajduje się aktualna linia skanowania, a jeśli tak, to w jaki sposób mogę wykorzystać te informacje, aby wyeliminować rozdarcie bez korzystania z DirectX do wyświetlania cels? Czy muszę w pełni korzystać z DirectX do renderowania, aby poradzić sobie z tym problemem?

Aktualizacja: zapomniałem o szczegółach. Moja aplikacja renderuje każdą komórkę na PictureBox za pomocą Graphics.DrawImage. Czy jest to znacznie wolniejsze niż przy użyciu BitBlt, tak, że mogę wyeliminować przynajmniej część łez używając BitBlt?

Aktualizacja 2: efekt, który widzę, zdecydowanie nie jest migotaniem (co różni się od łzawienia). Mój panel jest podwójnie buforowany, ustawia style kontrolne dla AllPaintingInWmPaint, UserPaint, OptimizedDoubleBuffer itd., Zastępuje on PaintBackGround i tak dalej. Wszystko to jest konieczne, aby wyeliminować migotanie, ale problem z łzawieniem pozostaje. Jest to szczególnie widoczne, gdy animacja zawiera bardzo szybko poruszające się obiekty lub obiekty, które bardzo szybko zmieniają się z jasnego na ciemne. Kiedy obiekty poruszają się wolno i nie zmieniają kolorów szybko, efekt łzawienia jest znacznie mniej zauważalny (ponieważ kolejne celowniki są zawsze bardzo podobne do siebie).

+0

Czy renderujesz na osobnym wątku? –

+0

@Ardman: tak, renderowanie odbywa się w oddzielnym wątku (oddzielnym od wątku UI). – MusiGenesis

Odpowiedz

3

Rozerwanie występuje, gdy aktualizacja obrazu nie jest zsynchronizowana z częstotliwością odświeżania monitora. Monitor pokazuje część poprzedniego obrazu, część nowego obrazu. Gdy obiekty na obrazie poruszają się szybko, efekt jest dość zauważalny.

Nie można go naprawić w Windows Forms, nie można uzyskać sygnału v-sync adaptera wideo. Możesz w DirectX app.

0

Do takich zadań lepiej użyć directx (lub opengl). Ale jeśli chcesz używać tylko winformów, użyj właściwości DoubleBuffered.

+1

Używam DoubleBuffered, aby wyeliminować migotanie, ale nie pomaga to w rozdarciu. – MusiGenesis

+0

Staram się również, aby moja aplikacja była międzyplatformowa z Mono, więc chcę, jeśli to możliwe, unikać specyficznych dla platformy rzeczy, takich jak DirectX. – MusiGenesis

+0

więc użyj opengl! jest to cross-platformowy odpowiednik directx. Cóż, myślałem, że WinForm nie są cross-pl. – Andrey

0

Podwójny bufor to.

Możesz włączyć podwójne buforowanie za pomocą stylów okien lub, co chyba łatwiejsze, narysować obraz poza ekranem, a następnie zamienić je.

Jeśli to nie działa, najlepszą rzeczą do zrobienia jest bitblit i podwójny bufor.

Zasadniczo jest taki sam.

Mieć odniesienie do dwóch bitmap, jeden to ekran, a drugi to bufor. Najpierw narysujesz do bufora, a następnie przeklejesz całą rzecz na ekran. W ten sposób zapisujesz na żywo tylko dane do bufora. Sceen pokazuje po prostu coś, co zrobiłeś wcześniej (niebieski styl)

+2

Przepraszam, powinienem być bardziej przejrzysty w moim pytaniu. Podwójne buforowanie (które już używam) nie pomaga w efektach rozdarcia. – MusiGenesis

+0

Ah ok nie martwi się. Nie używaj wtedy pudełka z obrazkami i napisz bezpośrednio na ekran (z podwójnym buforowaniem). – Chris

2

Wypróbowałem pomysł podwójnego buforowania w projekcie, nad którym pracuję w tej chwili, ale nie osiągnąłem z nim bardzo dobrych rezultatów. W końcu stworzył następujące:

  1. A System.Drawing.Bitmap dla mojego bufora offscreen. Odkoduj animację w tej bitmapie.
  2. Kontrolka UserControl o tym samym rozmiarze jak obraz w (1) i gdzie metoda OnPaintBackground była pusta (bez rysowania, bez wywołania do klasy bazowej) i OnPaint wykonał Graphics.DrawImage, aby skopiować obraz poza ekranem na ekran.

Teraz masz dziwny współczynnik animacji, więc zerwanie jest prawie na pewno związane z niedopasowaniem między szybkością aktualizacji ekranu a szybkością odświeżania ekranu. Aktualizujesz ekran w trakcie odświeżania ekranu, tak aby ekran rysował starą ramkę u góry ekranu i nową ramkę u dołu ekranu. Jeśli możesz zsynchronizować liczbę klatek na sekundę z częstotliwością odświeżania wyświetlacza, rozrywanie powinno zniknąć.

+1

To, co opisujesz, jest w zasadzie tym, co robię, chociaż używam dwóch bitmap jako buforów offscreenowych, dzięki czemu mogę zaktualizować jeden podczas gdy drugi jest rysowany na ekranie. Spróbuję zsynchronizować moją animację z moją częstotliwością odświeżania (60 Hz) i zobaczyć, co to dla mnie zrobi. – MusiGenesis

0

Łzawienie jest artefaktem z ramy narysowanej na drugiej. Jedynymi bezpiecznymi sposobami uniknięcia tego są: a) wyczekiwanie z vsync lub b) przeciągnięcie za belką (jest to dość trudne). Sam podwójny bufor nie gwarantuje odporności na rozdarcie, ponieważ możesz mieć podwójny bufor, ale nadal możesz korzystać z funkcji wyłączania. Niektóre karty mogą również mieć opcję oczekiwania "wymuszone". Musisz sprawdzić dokumentację dotyczącą vsync i jak sprawdzić, gdzie ona jest. To jedyny bezpieczny sposób na zrobienie tego. Pamiętaj też, że zablokuje to twoją framerate.

+1

Musi istnieć jakikolwiek sposób animowania tego bez łez z wykorzystaniem wybranej przeze mnie klatek na sekundę (liczba klatek na sekundę jest ograniczona, ponieważ animacja musi być zsynchronizowana z muzyką), ponieważ WMP jest w stanie renderować ją dobrze bez łez. Może WMP robi jakąś interpolację między klatkami? – MusiGenesis

Powiązane problemy