| | | +--+--+ +-----+ | | | | | +----+ | | | | | | | | | | | | | | | | | +-----+ +----+ | | +----+ | 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ň