Jak się robi screeny

2010-04-20 16:19

W robieniu zrzutów ekranowych (screenshotów) nie ma, wydawałoby się, nic nadzwyczajnego. Wciskamy po prostu klawisz Print Screen i obraz ekranu ląduje nam w systemowym Schowku, po czym możemy go użyć w dowolny sposób. Przynajmniej tego właśnie się spodziewamy zazwyczaj.
W rzeczywistości robienie screenów to dość śliski temat, jeśli mamy do czynienia z czymś więcej niż zwykłymi aplikacjami okienkowymi. Dotyczy to chociażby pełnoekranowych gier, korzystających z bibliotek graficznych typu DirectX i OpenGL. Wykorzystują one mechanizm znany jako hardware overlay, pozwalający – w skrócie – na ominięcie narzutu systemu operacyjnego związanego z zarządzeniem oknami wielu aplikacji na współdzielonym ekranie monitora. Skutkiem ubocznym jest między innymi to, że wbudowany w system mechanizm tworzenia zrzutów ekranu staje się w tej sytuacji bezużyteczny, jeśli chcemy wykonać screenshota tego rodzaju aplikacji.

Skąd w takim razie biorą się screeny, a nawet całe filmy ze współczesnych gier?… Cóż, istnieją oczywiście metody pozwalające na przechwytywanie obrazów generowanych przez aplikację – można bowiem skłonić ją do wywoływania naszej własnej wersji metody IDirect3DDeviceN::Present zamiast tej wbudowanej :) Brzmi to pewnie tajemniczo i nieco hakersko, ale tak mniej więcej działają programy do przechwytywania wideo typu Fraps.

Do zwykłych screenów zazwyczaj jednak przewiduje się odpowiednie rozwiązania w samych grach. Jednym ze sposobów jest, w przypadku wykrycia wciśnięcia klawisza odpowiadającego za screenshoty (czyli zwykle Print Screen), wyrenderowanie sceny najpierw do tekstury, a ją potem na ekran. Rzeczoną teksturę można później zapisać do pliku.


Aliasing (i nie tylko)
w pełnej krasie

Czy to dobre rozwiązanie? Otóż nie, i to aż z trzech powodów. Stosunkowo najmniej ważnym jest to, iż implementacja może być kłopotliwa, bo wymaga dobrania się do początku i do końca potoku renderingu w aplikacji z kolejnym render targetem. Bardziej istotny jest brak multisamplingu (a więc wygładzania krawędzi wielokątów znanego jako anti-aliasing) w powstałym obrazku. Nie będzie on więc wyglądać zbyt ładnie, już nie wspominając o tym, że nie będzie on odpowiadał temu, co widzimy na ekranie.

Jak więc należy robić screeny? Dokładnie tak, jak nam podpowiada intuicja: należy wziąć to, co widać na ekranie – czyli zawartość bufora przedniego (front buffer) i zapisać to do pliku. W DirectX mamy do tego metodę urządzenia o nazwie GetFrontBufferData, która pobiera nam to jako powierzchnię:

  1. IDirect3DSurface9* screen;
  2. dev->CreateOffscreenPlaneSurface(Width, Height, D3DFMT_A8R8G8B8,
  3.     D3DPOOL_SCRATCH, &screen, NULL);
  4. // screenshot i zapis go do pliku
  5. dev->GetFrontBufferData(0, &screen);
  6. D3DXSaveSurfaceToFile(ScreenFile, D3DXIFF_JPG, screen, NULL, NULL);

Ważne jest, by pamiętać o właściwych rozmiarach powierzchni – takich, jakie ma bufor przedni. W trybie pełnoekranowym odpowiada to buforowi tylnemu, ale dla aplikacji okienkowej wcale nie musi, jeśli rozmiar jej okna możemy zmieniać.

W OpenGL podobną rolę spełnia do GetFrontBufferData spełnia funkcja glReadPixels. Z zapisaniem pobranego obrazu może być tylko “nieco” trudniej ;-)

Tags: , , ,
Author: Xion, posted under Programming »


One comment for post “Jak się robi screeny”.
  1. Kos:
    April 20th, 2010 o 17:06

    To, co pokazałeś na obrazku, to nie tylko aliasing, ale jeszcze specjalne optymalizowanie rysowanego tekstu pod monitory LCD :).

Comments are disabled.
 


© 2017 Karol Kuczmarski "Xion". Layout by Urszulka. Powered by WordPress with QuickLaTeX.com.