|
|
| +--+--+
+-----+ | | | | | +----+
| | | | | | | | |
| | | | | | | |
+-----+ +----+ | | +----+
|
mapping
V minulém čísle jsem vám nastínil možnosti geniálního
environment mappingu, jehož výhodně využijeme při implementaci
časově náročnějšího bump mappingu, který dává opravdu vynikající
výsledky co do vizuální věrnosti výsledného produktu. Předem
upozorňuji ty z vás, kteří do texturovacích technik příliš
nevidíte, že po přečtení tohoto článku by se vám možná mohla
stát jedna nepříjemná věc. Je to podobné jako u texturovacích
metod. Když nezasvěcený pozorovatel zhlédne scénu s lineárním
texturemappingem a potom s perspektivní korekcí, netuší v čem je
rozdíl a zkonstatuje, že ten první průlet byl asi dvakrát
plynulejší. Ale jakmile mu celou problematiky vysvětlíte a on se
začne pozorněji dívat, po nějakém čase zaregistruje spoustu
optických chyb, které mu před tím unikaly. Neuplyne dlouhá doba a
bývalý laik bezpečně pozná rozdíl mez lineární interpolací a
perspektivní korekcí. Zvláště pro programátory, kteří vyvíjí
nějaké engine je tento fakt velmi destruktivní, jelikož věci,
které se jim kdysi líbily najednou ztrácejí svojí optickou krásu.
Tato profesionální deformace se projevuje také u environment a
bump mappingu. Takže pokud máte rádi některé scény a nechcete si
nechat zkazit dobrý dojem, dívejte se raději stále svým laickým
okem a nepokoušejte se proniknout do tajů těchto metod. Bump
mapping je pro laiky opravdu značně realistický, zvláště pokud
je objekt ve vzdálenosti "zlatého řezu", tedy tam, kde se poměr
mezi rastrem obrazovky a textury blíží jedné. K jeho implementaci
potřebujeme celkem tři textury. Jedna reprezentuje vlastní
materiál objektu, druhá jeho nerovnosti a třetí phong environment
mapu. Poslední dvě si popíšeme podrobněji.
Bump mapa je textura, která by měla mít stejné rozměry jako
textura materiálová. Její paleta není samozřejmě důležitá, závisí
pouze na indexech jednotlivých barev. Nejlépe je si zvolit jako 0
největší prohlubeň a 127 jako největší výstupek. Proč právě 127
si objasníme později. Phong mapa je jednoduchá environment mapa s
předpočítaným hotspotem světla, tak, jak jsem ji popisoval a na
obrázku ukazoval v minulém čísle. Zde zase nezáleží na paletě,
ale pouze na indexech barev, takže je logické si zvolit 0 jako
minimální a 63 maximální intenzitu. Rozsah 0 až 255 je v praxi
zbytečně veliký, protože lidské oko je schopné rozlišit přibližně
64 odstínů jedné barvy.
Další tabulku hodnot, kterou budeme potřebovat, pokud
pracujeme v 256 barevných režimech, je jednoduchá lookup tabulka
pro převod intenzity na konečnou barvu. Na její vytvoření
existuje spousta metod, asi nejjednodušší je hledání nebližší
barvy dané intenzity pomocí vzdálenosti v RGB krychli. Případné
zájemce odkazuji na Liborův článek v tomto čísle. Rozsah této
tabulky závisí na zvoleném indexování Phong mapy. Je výhodné
zvolit 64 odstínů, takže výsledná velikost bude 256*64=16384
bajtů.
Poslední paměť musíme alokovat pro velice důležitou bump
tabulku, která sice není úplně nezbytná, ale výrazně urychluje
vykreslování bump mapovaného polygonu. Bude mít stejný počet bodů
jako bump mapa, kterou budeme moci po provedení jistých
inicializačních kalkulací uvolnit z paměti. Jediný rozdíl bude v
tom, že bude moci obsahovat i záporná čísla v rozsahu paměťové
velikosti textury tedy například od -32767 do +32767. Abychom
pochopili její význam, musíme si nejdřív objasnit vlastní
podstatu bump mappingu.
Samotná teorie prostorových textur je poměrně komplikovaná
a její podstata tkví na stejném základě jako například Phongův
osvětlovací model. Abychom docílili opravdové přesnosti, měli
bychom počítat úhel, který svírá normála nerovné plochy s
vektorem světla. Implementace nerovnosti povrchu zvýšením počtu
polygonů je zajisté možná, ale jak už asi všichni tušíte, není ta
nejlepší. Její realističnost je sice zachována i při relativně
velkém přiblížení k objektu, ale optimalizace s cílem redukce
časově náročných operací v plovoucí čárce je i pro výkonné
procesory stále aktuální. Ve světě počítačů s procesory firmy
Intel se jakékoli zvýšení počtu polygonů nad nutnou mez stává
fatálním. Veškeré low-level optimalizace vykreslování polygonů
jdou automaticky stranou, pokud je scéna složena z velkého
množství relativně malých polygonů. Tento problém lze poměrně
elegantně vyřešit následujícím způsobem. Spočteme gradient v
každém bodě textury, která reprezentuje nerovnost materiálu a
pomocí velice rychlé rutiny, která se nijak výrazně neliší od
phong texture mappingu pokryjeme nesrovnatelně větší polygony.
Tato simulace má ovšem jedno úskalí. Pokud se přiblížíme k
objektu na vzdálenost, kdy se rastr textury značně liší od rastru
obrazovky, výsledný efekt nenávratně vymizí a objekt ztratí
původní plastičnost. Tato skutečnost se v mnohých profesionálních
systémech řeší dynamickou náhradou polygonového detailu povrchu.
Výpočet gradientu je velice jednoduchá záležitost, pokud
využijeme zjednodušené implementace bump mappingu pomocí
prostorových textur s pevnou velikostí.
....+---+....
: | c | :
+---+-+-+---+
| a |x|y| b |
+---+-+-+---+
: | d | :
....+---+....
grad[x] = b-a = bump_mapa[x-1][y]-bump_mapa[x+1][y]
grad[y] = d-c = bump_mapa[x][y-1]-bump_mapa[x][y+1]
Ve své podstatě nám obě hodnotu udávají sklon elementární plošky
ve směru dané osy. Pro jednoduchost zvolíme vektor světla kolmý
na počítaný povrch a z této podmínky je už snadné odvodit
intenzitu odráženého světla na elementární plošce:
intenzita[x][y] = max-(grad[x]+grad[y])
Jak je vidět, maximální intenzitu bude mít odražené světlo na
plošce, jejíž gradient bude nulový ve směru osy X respektive osy
Y. Tento fakt využijeme při samotném vykreslování polygonu. Nyní
se vraťme k bump tabulce. Právě do ní budeme ukládat jednotlivé
gradienty, kterými v konečné fázi vychýlíme UV vektor ukazující
do envirnoment textury. Doufám, že je zřejmé, že tím snížíme nebo
naopak zvýšíme intenzitu ve vykreslovaném bodě. Pochopit tento
fakt je poněkud složitější, takže jsem pro vás připravil
ilustrační obrázek .Pokud si představíte, že levé bílé políčko má
hloubku 0 a pravé 127, potom je obrázek reálný. Je z něj vidět,
že čím větší je rozdíl mezi hloubkami okolních bodů, tím více se
odchýlí UV vektor a ukazuje na tím menší intenzitu. Proč je
maximální hloubka 127, je už snad jasné. Bump textura o velikosti
256x256 má střed právě v bodě [127,127]. Hodnoty, které budeme
ukládat do bump tabulky získáme zřejmě následovně:
bump_tab[x][y] = bump_mapa[x-1][y]-bump_mapa[x+1][y]+
(bump_mapa[x][y-1]-bump_mapa[x][y+1])*256
Proč je tam to násobení 256 ? Je to jednoduché. Jak jistě víte,
intenzita bodu se pomocí phong textury spočítá následovně:
intenzita[u][v] = phong_mapa[u+v*256],
takže když bychom to rozepsali pro bump mapping pomocí gradientů:
intenzita[tU][tV] = phong_mapa[(pU-grad[tU])+(pV-grad[tV])*256],
kde pU a pV jsou souřadnice bodu v phong textuře a tU, tV v
materiálové textuře. Když to upravíme pomocí předpočítané bump
tabulky, získáme výsledný vztah pro intenzitu v daném bodě:
intenzita[tU][tV] = phong_mapa[pU+pV*256-bump_tab[tU][tV]]
Pokud to stále nechápete, zkuste si to sami odvodit. Je to
myslím poměrně jednoduché a pochopitelné. V praxi by se daly
použít následující rutiny (předpočítání bump tabulky a
vykreslovací smyčka) napsané v C, které GNU C kompilátory
spolehlivě zoptimalizují:
for (i=1;i<255;i++)
for (j=1;j<255;j++) {
ofs=i+j*256;
bump_tab[ofs]=bump_mapa[ofs-1]-bump_mapa[ofs+1]+
((bump_mapa[ofs-256]-bump_mapa[ofs+256])<<8);
}
while (output<=end) {
int tUV=tU+(tV<<8);
int pUV=pU+(pV<<8)-bump_tab[tUV];
*output++=shadow_tab[(textura[tUV]<<6)+phong_mapa[pUV]];
tU+=dtU;
tV+=dtV;
pU+=dpU;
pV+=dpV;
}
Na závěr podotýkám, že nejvíce bump mapping vynikne, pokud
je objekt v pohybu, protože právě malá změna pozice objektu
vyvolá mnohdy relativně velkou změny intenzity různě vystouplých
bodů, podobně jako je tomu v reálném světě, kterému se stále
snažíme přiblížit. Někdy se ptám, proč tak vlastně činíme, když
stačí vypnout počítač a vyrazit do přírody, kde to všechno
funguje nekonečně plynule a přesně. :-]
ReDox
výheň