Programowanie Gier -> Wykład: Parallax mapping, Precomputed Radiance Transfer, Shadow Fields

Aka "zaawansowane shadery", bo zarówno parallax mapping i PRT (tzn. obliczenia w PRT per-vertex) implementujemy typowo w shaderach.

1. Parallax Mapping

http://en.wikipedia.org/wiki/Parallax_mapping

Wiele uwag także na http://jerome.jouvie.free.fr/OpenGl/Projects/Shaders.php

1.1. Podstawy

Paralaksa — kiedy przesuwamy się patrząc na statyczne obiekty, elementy w różnej odległości od oka są potrzegane jakby przesuwały się z różną szybkością. "Parallax mapping" to symulowanie powierzchni z wypukłościami tak żeby potrzegane wypukłości były 3D, jednocześnie renderujemy powierzchnię jako normalną 2D. Pomagamy sobie teksturą wysokości (chociaż istnieją metody które wymagają innych tekstur pomocniczych, ale to nie na tym wykładzie), sama implementacja "parallax mapping" jest w shaderze.

Idea: w shaderze możemy przesunąc texture coordinate o jakiś offset. Patrz page 3 z http://www.cs.ualberta.ca/~keith/610/papers/parallax_mapping.pdf. W zasadzie, wystarczy popatrzeć na rysuki i zauważyć że

# pamiętajcie że offset i xxx_tex_coord to wektory 2D
offset := wysokość(w punkcie oryginalny_tex_coord) *
  EyeVector.xy /
  EyeVector.z
nowy_tex_coord = oryginalny_tex_coord + offset

daje nam to co chcemy. Zakładamy że powierzchnia jest "mniej więcej" płaska pomiędzy oryginalnym o nowym tex coord (bo statystycznie tak jest najczęściej), więc jest to "mniej więcej" prawidłowy offset.

1.2. Offset limiting

Parallax mapping with offset limiting (opisuje też dobrze bazowe parallax mapping, w sumie sama modyfikacja "offset limiting" jest trywialniutka):

http://www.cs.ualberta.ca/~keith/610/papers/parallax_mapping.pdf

Idea: problem z klasycznym parallax mapping to że gdy patrzymy na ścianę prawie-równolegle (a to jest sytuacja kiedy parallax mapping ma być najbardziej widoczny i efekciarski) to EyeVector.z daży do zera, a więc przesunięcie tex coord będzie olbrzymie, i zapewne bez sensu.

Prosty pomysł: ogranicz ofsset. Najprościej: ogranicz go do wysokość(w punkcie oryginalny_tex_coord), poza tym nie ograniczaj przez max() tylko przez przeskalowanie (i wiedzę że EyeVector jest znormalizowany, więc EyeVector.x <= 1 i EyeVector.y <= 1). Czyli po prostu... usuń dzielenie przez EyeVector.z !

1.3. Steep parallax mapping (with self-shadowing)

Nieuchronny problem z poprzednimi podejściami do parallax mapping to że robimy trywialny hack, próbując jednym "guessem" dojść do poprawnego wyniku. W praktyce, działa to satysfakcjonująco tylko kiedy powierzchnie są mniej więcej gładkie. Nierówności muszą być możliwie "smoothed", nie gwałtowne.

No i nie mamy cieni od wypukłości.

Jak poprawić?

Zrobić mini-raytracek który "idzie" po wypukłościach w kilku krokach, patrząc gdzie EyeVector po raz pierwszy "wchodzi" w wypukłość.

Bonus: w podobny sposób, tylko idąc w drugą stronę i biorąc LightVector zamiast EyeVector, możemy zrobić self-shadowing. Czyli sprawdź czy jakaś wypukłość blokuje drogę wzdłuż LightVector do naszego punktu.

Za opis metody w sumie wystarcza "extended abstract", 1 strona, http://graphics.cs.brown.edu/games/SteepParallax/mcguire-steepparallax.pdf

Preudo-kod implementacji to kilka linijek.

Patrz http://graphics.cs.brown.edu/games/SteepParallax/index.html

W sieci znajdziecie pełne przykłady implementacji. Na wykładzie szybciutko zobaczymy moją implementację: https://vrmlengine.svn.sourceforge.net/svnroot/vrmlengine/trunk/kambi_vrml_game_engine/src/vrml/opengl/glsl_parallax_bump_mapping.vs https://vrmlengine.svn.sourceforge.net/svnroot/vrmlengine/trunk/kambi_vrml_game_engine/src/vrml/opengl/glsl_parallax_bump_mapping.fs

2. Precomputed Radiance Transfer

https://vrmlengine.svn.sourceforge.net/svnroot/vrmlengine/trunk/kambi_vrml_game_engine/examples/vrml/radiance_transfer/README.txt

Demo: show_sh, radiance_transfer z chinchilla, towers.

http://www.tml.tkk.fi/~tmakipat/prtf_fixed.pdf, strona 8 (3.1.1 Diffuse objects)

3. Shadow Fields

Już nie zdążyliśmy... Możecie poczytać sami, linki i moje komentarze na

https://vrmlengine.svn.sourceforge.net/svnroot/vrmlengine/trunk/kambi_vrml_game_engine/examples/vrml/shadow_fields/README.txt