Warsztat.GDCompo!ProjektyMediaArtykułyQ&AForumOferty pracyPobieranie

Opisz napotkaną sytuację, a redakcja niezwłocznie znajdzie rozwiązanie!

wyślij anuluj

Fake HDR

Tekst został importowany z Warsztatowych artykułów. Jego oryginalnym autorem jest Krzysiek K.. Jeżeli został importowany poprawnie, usuń ten szablon!

Oto kolejny efekt - Fake HDR pozwalający nieco 'ulepszyć' wygląd sceny znacznie mniejszym kosztem, niż przy stosowaniu prawdziwego HDR. :)

Screen 1 bez HDR Screen 1 z HDR

Screen 1 bez HDR Screen 1 z HDR

Po lewej obraz wyjściowy, po prawej obraz po zastosowaniu efektu z załączonego kodu. :)

1. HDR

HDR (High Dynamic Range) jest techniką używaną przy renderowaniu fotorealistycznych obrazów. Ideą jest możliwość oddania zarówno bardzo dużych (większych od jedności), jak i bardzo małych (mniejszych niż 1/256) natężeń oświetlenia i kolorów. W przeciwieństwie do standardowego zapisu kolorów z precyzją jednego bajta na składową RGB, używa się liczb zmienno przecinkowych (z precyzją 16 lub 32 bitów).

Typowy rendering HDR polega na:

  • wyrenderowaniu sceny do zmiennoprzecinkowego bufora
  • zrobieniu kopii sceny pomniejszonego dwukrotnie
  • rozmazaniu (blur) sceny (dzięki pomniejszeniu można to zrobić szybciej nie tracąć zbytnio dokładności)
  • połączeniu obrazu zwykłego z rozmazanym
  • mapowanie kolorów i przekształcenie na RGB z precyzją 8 bitów na komponent w celu wyświetlenia)

Wszystkie operacje odbywają się na kolorze zapisanym jako liczby zmiennoprzecinkowe, z czego wynika parę ciekawych właściwości:

  • mały bardzo jasny obiekt może wygenerować dużą poświatę (po rozmyciu może mieć wpływ na jasność nawet odległych pikseli)
  • można tak samo jak w fotografii dobierać czas naświetlania odpowienio skalując wartości podczas konwersji na 24-bitowy kolor RGB - ponieważ wszystkie operacje dotychczas były zmiennoprzecinkowe, słabo oświetlone obiekty nie tracją precyzji koloru)
  • korzystając z powyższego można symulować fizykę oka ludzkiego: adaptacja do warunków oświetlenia, czy nawet brak widzenia barw przy słabym oświetleniu
  • no i ogólnie wygląda to fajnie :)

Po więcej informacji i przykładowe screeny odsyłam do poniższego linka: :) http://www.gamedev.net/columns/hardcore/hdrrendering/

2. Fake HDR

Niestety, jak widać HDR jest dosyć wymagającą techniką i stwarze trochę problemów:

  • starsze karty graficzne nie obsługują formatów koloru o precyzjach większych niż 8-bitów na komponent
  • uzywanie wszędzie arytmetyki zmiennoprzecinkowej jest wolniejsze
  • trzeba zapewnić oddzielne sposoby renderowania z HDR i bez
  • dobrze by było, żeby tekstury też były precyzji większej niż 8-bitów na komponent RGB

Wobec powyższych problemów, programiści zaczęli się uciekać do pewnych sztuczek mających na celu 'udawanie HDR' dużo mniejszym nakładem pracy i środków, co jest tematem tego foo'sa. :)

Fake HDR ('udawany HDR') to nic innego, jak zastosowanie kroków robionych w prawdziwym HDR'rze, ale ze standardową precyzją 8-bitów na komponent RGB. Postępowanie po tej modyfikacji wygląda tak:

  • wyrenderowanie sceny ze zwykłą precyzją
  • zmniejszenie obrazu
  • przefiltrowanie zmniejszeonego obrazu w celu wykrycia jaśniejszych regionów (zazwyczaj to jest operacja x = 2max(0, y-0.5), lub x = y*y na kolorze)
  • blur przefiltrowanego obrazu
  • połączenie wyniku powyższych operacji z obrazem wyjściowym

3. Przykładowy kod

W załączniku znajduje się gotowy do użycia kod OpenGL, który można zastosować we własnych aplikacjach OpenGL. Parę uwag:

  • kod działa poprawnie dla rozdzielczości mniejszych niż 1024x768 (wykorzystana jest tekstura 1024x1024)
  • glCopyTexSubImage2D nie jest może najszczęśliwszym rozwiązaniem - pbuffer, czy nawet zwykłe użycie więcej niż jednego quada i paru tekstur powinno być lepsze, no i słyszałem, że sterowniki ATI drivers nie zawsze wspierają tą funkcję poprawnie
  • zdecydowanie jakość i wydajność tego kodu może być jeszcze poprawiona
  • to add it to your project, simply call init_postprocess() before you are going to use it (but after you have set up OpenGL context) and call do_postprocess() after you are done with drawing your scene (but before drawing GUI)

Żeby uruchomić ten efekt wystarczy:

  • dodać portprocess.cpp do swojego projektu
  • zmienić #include "allstuff.h" na odpowiednie nagłówki
  • zdefiniować SCREEN_W i SCREEN_H tak, żeby odwzorowywały aktualną rozdzielczość ekranu
  • załadować funkcje rozszerzenia glActiveTextureARB() i glMultiTexCoord2fARB()
  • wywołać init_postprocess() podczas inicjalizacji
  • wywołać do_postprocess() po zakończeniu renderowania sceny, a przed wyrenderowaniem GUI

4. Szczegóły implementacyjne

- wyrenderowanie sceny ze zwykłą precyzją

Podpunkt napisany dla kompletności. To jest działka należąca do Was. :)

- zmniejszenie obrazu

Cały obraz jest kopiowany do tekstury 1024x1024 przy użyciu glCopyTexSubImage2D (nie cała tekstura zostanie wypełniona), po czym zrzut ekranu jest renderowany do viewport'u zmniejszonego do 256x256, który jest skolei kopiowany do drugiej tekstury.

- przefiltrowanie zmniejszeonego obrazu w celu wykrycia jaśniejszych regionów

Filtrowanie wykonywane jest przy uzyciu funkcji x=y*y, co można osiągnąć w prosty sposób poprzez multitexturing. Ten krok jest wykonywany podczas zmniejszania tekstury.

- blur przefiltrowanego obrazu

Blur jest dosyć czasochłonną operacją, gdyż należy nałożyć na siebie wiele przesuniętych obrazów, lecz można zoptymalizować to nieco wykonując blur dwa razy w różnych osiach. W moim przypadku wygląda to tak:

  • zsumowanie kilku kopii przesuniętych w osi X z różną jasnością
  • pobranie wyniku do tekstury
  • wykonanie identycznej operacji w osi Y na wyniku poprzedniego blur'a

Ustawione parametry blur'a dają dosyć słabą jakość, ale nie widać tego zbytnio po zsumowaniu efektu z obrazem wyjściowym. Mimo wszystko, da się sporo poprawić, zwłaszcza, że ten etap nie korzysta z multitexturingu (a powinien). :)

- 'posprzątanie' po sobie

Ten punkt jest wynikiem mojej implementacji i nieużywania pbuffer'ów. Jako że cały czas wykorzystywany był fragment 256x256 w rogu ekranu, należy go 'zalepić' spowrotem obrazem wyjściowym (który został zachowany na teksturze po pierwszym kroku).

- połączenie wyniku powyższych operacji z obrazem wyjściowym

W moim przypadku jest to zwykłe dodanie połowy jasności przetworzonego obrazu.

Wszelkie komentarze i uwagi mile widziane. :) Błędy ortograficzne, gramatyczne, językowe i dotyczące terminilogii proszę zgłaszać na PM, żeby nie zaśmiecać wątku, a mimo wszystko trzymać poziom - pozostałe, w wątku. :) W razie błędów/nieścisłości/nowych wersji kodu będę edytować. :)

Pozdrawiam, :)

Krzysiek

Załącznik: fakehdr.cpp

Tekst dodał:
Adam Sawicki
13.04.2006 18:21

Ostatnia edycja:
Adam Sawicki
13.04.2006 18:21

Kategorie:

Aby edytować tekst, musisz się zalogować.

# Edytuj Porównaj Czas Autor Rozmiar
#1 edytuj 13.04.2006 18:21 Adam Sawicki 7.95 KB
Zwykły
Do sprawdzenia
Do akceptacji
  • Dawid Kurek (@skaarj1989) 20 września 2007 21:41
    To by było zbyt piękne żeby działało ;/ błąd przy do_postprocess (włączam multitexturing prawidłowo) ... eh
  • ~cezary 11 sierpnia 2008 10:46
    A jak mam tryb okienkowy a nie fullscreen to mi powieksza obraz i nie widze tego co chce tylko pewien wycinek obrazu
  • ~Misioslaw 26 marca 2009 20:40
    Z HDR to ma niewiele wspólnego, wygląda jak rozmycie chrominacji.
  • Napisz komentarz:
    Aby dodać swój komentarz, musisz się zalogować.
Licencja Creative Commons

Warsztat używa plików cookies. | Copyright © 2006-2017 Warsztat · Kontakt · Regulamin i polityka prywatności
build #ff080b4740 (Tue Mar 25 11:39:28 CET 2014)