Hlavní navigace

Modulace normálových vektorů - bump mapping

29. 7. 2008
Doba čtení: 12 minut

Sdílet

V dnešní části našeho seriálu o POV-Rayi si ukážeme, jakým způsobem lze použít procedurální textury pro modulaci normálových vektorů ploch (bump mapping). Jedná se o techniku, pomocí které je možné dosáhnout iluze zvlněného povrchu i v případě, že je povrch vykreslovaného tělesa dokonale rovný.

Obsah

1. Modulace normálových vektorů – bump mapping
2. Princip bump mappingu
3. Použití procedurálních textur při bump mappingu
4. První příklad – procedurální textura „crackle“ jako zdroj pro bump mapping
5. Druhý příklad – procedurální textura „granite“ jako zdroj pro bump mapping
6. Třetí příklad – změna hodnoty turbulence pro procedurální texturu „marble“
7. Čtvrtý příklad – změna hodnoty turbulence pro procedurální texturu „bumps“
8. Obsah další části seriálu

1. Modulace normálových vektorů – bump mapping

Ve třinácté a především pak čtrnácté části tohoto seriálu byly vysvětleny principy Phongova osvětlovacího modelu, který představuje základ pro výpočet osvětlení všech potenciálně viditelných bodů na povrchu těles. Phongův osvětlovací model je mimo vlastní POV-Ray použitý i v mnoha dalších aplikacích zaměřených na vykreslování trojrozměrných scén, protože výpočty světelných poměrů jsou poměrně rychlé a výsledná scéna současně působí přirozeně. Výsledek snah o co nejrychlejší a přesto kvalitní obrázky trojrozměrných scén samozřejmě vyústil v kompromisní model, který se však s úspěchem používá již několik desetiletí, i když je nutné říci, že se vlastně jedná o ad-hoc řešení, které pouze přibližně simuluje skutečné světelné poměry na povrchu těles a některé optické jevy se s jeho využitím nedají přímo vytvořit (například „prasátka“, které jsou v POV-Rayi simulovány pomocí odlišné metody).

povray2201

Obrázek 1: Vodní hladina byla v této scéně vytvořena pomocí modulace normál, ve skutečnosti se však jedná o geometricky zcela rovnou plochu

Osvětlovací model je při vykreslování využit ve chvíli, kdy světelný paprsek dopadne na povrch tělesa, od nějž se následně odrazí (popř. i zlomí směrem dovnitř tělesa, ovšem pouze u těles alespoň částečně průhledných), ale vždy s určitým rozptylem – světlo je tedy teoreticky vyzářeno do všech směrů. Míru vyzáření světla lze vyjádřit funkcí, jejíž výsledek závisí na směru dopadajícího světelného paprsku (vzájemné pozici světelného zdroje a povrchu tělesa), intenzitě a barvě světla (barva světla souvisí s jeho vlnovou délkou), normálovém vektoru v místě dopadu paprsku na povrch objektu atd. Právě orientace normálového vektoru, tj. vektoru, jenž je kolmý na povrch tělesa v místě dopadu paprsku, má velký vliv na výslednou barvu dané části tělesa. I malá změna orientace tohoto vektoru (který pak již vlastně nelze nazývat normálový) může vést ke značné vizuální změně na zobrazeném povrchu. Cílená změna orientace normálových vektorů se nazývá modulace normálových vektorů a v počítačové grafice se pro ni vžil pojem bump mapping, tedy tvorba „hrbolků“.

povray2202

Obrázek 2: I tato vodní hladina byla vytvořena s využitím modulace normálových vektorů

2. Princip bump mappingu

Princip práce bump mappingu je poměrně jednoduchý – ve své podstatě se jedná o rozšíření texturování. Ve chvíli, kdy světelný paprsek dopadne na povrch tělesa, jsou na základě místa dopadu (jedná se o bod ležící v prostoru) vypočteny souřadnice v textuře (podle typu textury se jedná o bod ležící v ploše či prostoru), orientace normálového vektoru a popř. také souřadnice do další textury, která je použita právě při bump mappingu. Na základě hodnoty získané z této textury je načtena hodnota z tabulky nazvané slope_map, ze které se získá informace, jakým způsobem má být změněna orientace normálového vektoru. Normálový vektor je skutečně na základě této informace modifikován (a to velmi jednoduše – k jeho koncovému bodu se přičte hodnota načtená z tabulky slope_map) a následně znovu normalizován. Posléze se již tato nová hodnota normálového vektoru použije při výpočtu osvětlení, který je založen, jak jsme si již řekli ve čtrnácté části tohoto seriálu, na následující rovnici:

I=caIa+cdId(NL)+c­sIs(VR)n

Ve výsledku tento proces vede k tvorbě zdánlivě hrbolatých povrchů, i když se geometrie zobrazovaného tělesa ve skutečnosti nijak nezmění – to bude v demonstračních příkladech patrné při pohledu na hranici mezi tělesem a jeho pozadím, která má původní tvar, i když by (v případě skutečné změny tvaru povrchu) měla kopírovat vystínované hrbolky.

povray2203

Obrázek 3: Klasická scéna ve světě raytracingu – několik reflexních koulí z nichž prostřední má při výpočtu osvětlení modulované normálové vektory svého povrchu

3. Použití procedurálních textur při bump mappingu

Prakticky každý vyspělejší raytracer obsahuje speciální typy procedurálních textur, které jsou určené pro bump mapping (viz historické obrázky 3 a 4). Tak tomu bylo i v případě POV-Raye, který ve verzi 1 i 2 obsahoval například specializovanou texturu nazvanou příznačně bumps nebo dents. Ve třetí verzi však došlo k dlouho očekávanému sloučení procedurálních textur určených pro modulaci normálových vektorů i „normálních“ procedurálních textur určených pro změnu barvy těles, takže nyní je možné pro bump mapping použít prakticky jakoukoli procedurální texturu – my jsme s popisem těchto textur začali v patnácté části tohoto seriálu. V následujících čtyřech demonstračních příkladech budou pro modulaci normálových vektorů použity procedurální textury crackle, granite, marble a bumps. Ve všech příkladech budou použity hodnoty z implicitní tabulky slope_map, způsob její změny si vysvětlíme příště.

povray2204

Obrázek 4: Tatáž scéna, jaká byla zobrazena na třetím obrázku (jen viděná z jiného místa) vykreslená v dávné minulosti v odlišném raytraceru Rayshade (pro POV-Ray bylo nutné původní zdrojový kód scény celý přepsat)

4. První příklad – procedurální textura „crackle“ jako zdroj pro bump mapping

V dnešním prvním demonstračním příkladu je ukázáno, jakým způsobem je možné specifikovat procedurální texturu určenou pro bump mapping spolu s některými jejími základními parametry. V demonstrační scéně je na podkladové rovině umístěno jediné těleso – zelená koule –, na jejímž povrchu dochází při výpočtu světelných podmínek k modulaci normálových vektorů. Jako procedurální textura pro modulaci byla zvolena již dříve popsaná textura crackle, jež tvoří typický vzorek připomínající suchou půdu. Ze zdrojového kódu příkladu je patrné, že do definice textury (texture) byl, kromě již známých poduzlů pigment a finish, přidán nový poduzel nazvaný normal, který obsahuje jak jméno použité procedurální textury, tak i parametr bump_size (míra výšky vytvářených hrbolků) a parametr scale (změna velikosti hrbolků). Následuje výpis zdrojového kódu tohoto demonstračního příkladu:

// ------------------------------------------------------------
// První demonstrační příklad na bump mapping.
//
// Jednoduchá scéna s jedním uzavřeným objektem, jedním nekonečným
// objektem, dvojicí světel a jednou kamerou (pozorovatelem).
//
// Normálové vektory objektu (koule) jsou modulovány - bump mapping.
//
// Založeno na souboru původně vytvořeného Danem Farmerem (leden 2002)
//
// rendering lze spustit příkazem: povray +W1024 +H768 +B100 +FN +D +Iscena.pov +Oscena.png
// (pro náhled postačí zadat povray scena.pov)
// ------------------------------------------------------------

// globální nastavení parametrů scény
global_settings {
    assumed_gamma 2.2
    max_trace_level 5
}

// načtení všech potřebných externích souborů
#include "colors.inc"
#include "stones.inc"                    // zde je textura pro podkladovou rovinu

// nastavení kamery (pozorovatele)
camera {
    location  <1.65, 5.5, -5.0>          // pozice kamery
    up        <0.0,  1.0,  0.0>          // vektor směřující vzhůru
    right     <4/3,  0.0,  0.0>          // vektor směřující doprava
    look_at   <0,    0.5, -1.0>          // bod, na který kamera směřuje
}

// dva světelné zdroje
light_source {
    < 21, 12, -20>                       // pozice světelného zdroje
    color White                          // barva světla (plná bílá)
}

light_source {
    < 32, 11, -20>                       // pozice světelného zdroje
    color LightGray                      // barva světla
}

// jediný uzavřený objekt ve scéně - zelená koule
sphere {
    <0, 0, 0>,                           // souřadnice středu koule
    1.75                                 // poloměr koule
    texture {                            // textura - povrch koule
        pigment {
            color green 0.90             // barva povrchu
        }
        normal {                         // modulace normálových vektorů
            crackle                      // typ procedurální textury
            bump_size 1.5                // relativní velikost zvlnění
            scale 0.4                    // změna měřítka (hustoty zvlnění povrchu)
        }
        finish {                         // optické vlastnosti materiálu
            phong 1                      // velikost a síla odlesků
            phong_size 100
        }
    }
}

// druhý objekt - nekonečná rovina
plane {
    y,                                   // orientace roviny
    -1.5                                 // vzdálenost od počátku
    texture {                            // textura - vlastnosti povrchu
        T_Stone1                         // definováno v externím souboru
        pigment {                        // vlastní vzorek textury
            octaves 3                    // modifikace procedurálního vzorku
            rotate 90*z
        }
        finish {                         // optické vlastnosti materiálu
            reflection 0.10
        }
    }
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2205

Obrázek 5: Výsledek běhu prvního demonstračního příkladu

5. Druhý příklad – procedurální textura „granite“ jako zdroj pro bump mapping

Ve druhém demonstračním příkladu je, možná poněkud netradičně, pro bump mapu použita procedurální textura granite. Tato textura sice při běžném použití vypadá velmi náhodně, což nepřímo značí její nevhodnost pro modulaci normálových vektorů, ovšem při větším zvětšení tato náhodnost do značné míry zmizí a výsledná bump mapa je v mnoha případech velmi dobře použitelná, například při vytváření plechových předmětů, artefaktů vyrobených z roztepaného zlata apod. Druhý demonstrační příklad má tvar:

// ------------------------------------------------------------
// Druhý demonstrační příklad na bump mapping.
//
// Jednoduchá scéna s jedním uzavřeným objektem, jedním nekonečným
// objektem, dvojicí světel a jednou kamerou (pozorovatelem).
//
// Normálové vektory objektu (koule) jsou modulovány - bump mapping.
//
// Založeno na souboru původně vytvořeného Danem Farmerem (leden 2002)
//
// rendering lze spustit příkazem: povray +W1024 +H768 +B100 +FN +D +Iscena.pov +Oscena.png
// (pro náhled postačí zadat povray scena.pov)
// ------------------------------------------------------------


// globální nastavení parametrů scény
global_settings {
    assumed_gamma 2.2
    max_trace_level 5
}

// načtení všech potřebných externích souborů
#include "colors.inc"
#include "stones.inc"                    // zde je textura pro podkladovou rovinu

// nastavení kamery (pozorovatele)
camera {
    location  <1.65, 5.5, -5.0>          // pozice kamery
    up        <0.0,  1.0,  0.0>          // vektor směřující vzhůru
    right     <4/3,  0.0,  0.0>          // vektor směřující doprava
    look_at   <0,    0.5, -1.0>          // bod, na který kamera směřuje
}

// dva světelné zdroje
light_source {
    < 21, 12, -20>                       // pozice světelného zdroje
    color White                          // barva světla (plná bílá)
}

light_source {
    < 32, 11, -20>                       // pozice světelného zdroje
    color LightGray                      // barva světla
}

// jediný uzavřený objekt ve scéně - červená koule
sphere {
    <0, 0, 0>,                           // souřadnice středu koule
    1.75                                 // poloměr koule
    texture {                            // textura - povrch koule
        pigment {
            color red 0.90               // barva povrchu
        }
        normal {                         // modulace normálových vektorů
            granite
            bump_size 1.2                // relativní velikost zvlnění
            scale 8.4                    // změna měřítka (hustoty zvlnění povrchu)
        }
        finish {                         // optické vlastnosti materiálu
            phong 1                      // velikost a síla odlesků
            phong_size 100
        }
    }
}

// druhý objekt - nekonečná rovina
plane {
    y,                                   // orientace roviny
    -1.5                                 // vzdálenost od počátku
    texture {                            // textura - vlastnosti povrchu
        T_Stone1                         // definováno v externím souboru
        pigment {                        // vlastní vzorek textury
            octaves 3                    // modifikace procedurálního vzorku
            rotate 90*z
        }
        finish {                         // optické vlastnosti materiálu
            reflection 0.10
        }
    }
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2206

Obrázek 6: Výsledek běhu druhého demonstračního příkladu

6. Třetí příklad – změna hodnoty turbulence pro procedurální texturu „marble“

Ve třetím demonstračním příkladu je ukázán vliv míry turbulence na tvar bump mapy použité při modulaci normálových vektorů. V modelované scéně se nachází devět naprosto stejných koulí s lesklým jednobarevným povrchem modulovaným pomocí procedurální textury marble. Pokud není tato textura modifikována turbulencí, je výsledkem těleso, na němž jsou vytvořeny pravidelné pásky tvořící reliéf. Kdyby se jednalo o skutečný plastický reliéf, měl by v řezu pilovitý průběh, ovšem bump mapa, jak již víme z předchozích odstavců, ve skutečnosti povrch tělesa nemění. Spolu se zvětšující se mírou turbulence přestává být pravidelný reliéf patrný a naopak se ukazuje struktura vzdáleně připomínající omítku. Výpis třetího demonstračního příkladu má tvar:

// ------------------------------------------------------------
// Třetí demonstrační příklad ukazující práci s procedurálními
// texturami použitými jako zdroj pro modulaci normál.
//
// Postupná změna hodnoty turbulence pro zvolenou procedurální
// texturu marble od hodnoty 0.0 do hodnoty 0.8.
//
// rendering lze spustit příkazem:
//     povray +W1024 +H1024 +B100 +FN +D +Itextures.pov +Otextures.png
//
// !POZOR: scénu je nutné vykreslit se stejným horizontálním
//         i vertikálním rozlišením!
// ------------------------------------------------------------

#version 3.0
global_settings {
    assumed_gamma 2.2
}

#include "colors.inc"

camera {                       // nastavení kamery
    orthographic               // bez perspektivy
    location < 0, 0, -2.1>     // pozice kamery
    right 15*x                 // šířka a výška snímané části scény
    up 15*y
    direction z                // směr pohledu kamery (k počátku)
}

light_source {                 // světelný zdroj
    <200, 200, -500>           // pozice
    color White                // barva
}

#declare COL1=-4.5;            // posuny objektů ve vztahu
#declare COL2= 0.0;            // k pomyslné mřížce
#declare COL3= 4.5;            // o rozměrech 3x3
#declare ROW1= 4.5;
#declare ROW2= 0.0;
#declare ROW3=-4.5;
#declare Z=0.0;

#declare NORMAL=normal {      // testovací procedurální textura
    marble                    // základ pro tvorbu textury mramoru
    bump_size 1.5
}

#declare OBJECT=sphere {
    <0,0,0>, 2
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.0
        }
    }
    translate <COL1, ROW1, Z>
}


object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.1
        }
    }
    translate <COL2, ROW1, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.2
        }
    }
    translate <COL3, ROW1, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.3
        }
    }
    translate <COL1, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.4
        }
    }
    translate <COL2, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.5
        }
    }
    translate <COL3, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.6
        }
    }
    translate <COL1, ROW3, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.7
        }
    }
    translate <COL2, ROW3, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Cyan
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.8
        }
    }
    translate <COL3, ROW3, Z>
}

// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2207

Obrázek 7: Výsledek běhu třetího demonstračního příkladu

7. Čtvrtý příklad – změna hodnoty turbulence pro procedurální texturu „bumps“

Ve čtvrtém demonstračním příkladu je ukázáno použití snad nejtypičtější procedurální textury využívané při modulaci normálových vektorů. Jedná se o texturu bumps. I na tuto procedurální texturu je samozřejmě možné aplikovat turbulenci a měnit tak náhodnost hrbolků opticky vytvořených na povrchu vykreslovaného tělesa. V příkladu je míra turbulence měněna od hodnoty 0,0 (žádná turbulence, používá se nemodifikovaný vzorek generovaný procedurální texturou) až po hodnotu 0,8 (poměrně vysoká míra turbulence a tím také náhodnosti hrbolků). Textura bumps má při modulaci normálových vektorů široké možnosti použití, od tvorby omítek (malá měřítka) přes kamenné povrchy až po zprohýbané plechy či listy.

// ------------------------------------------------------------
// Čtvrtý demonstrační příklad ukazující práci s procedurálními
// texturami použitými jako zdroj pro modulaci normál.
//
// Postupná změna hodnoty turbulence pro zvolenou procedurální
// texturu bumps od hodnoty 0.0 do hodnoty 0.8.
//
// rendering lze spustit příkazem:
//     povray +W1024 +H1024 +B100 +FN +D +Itextures.pov +Otextures.png
//
// !POZOR: scénu je nutné vykreslit se stejným horizontálním
//         i vertikálním rozlišením!
// ------------------------------------------------------------

#version 3.0
global_settings {
    assumed_gamma 2.2
}

#include "colors.inc"

camera {                       // nastavení kamery
    orthographic               // bez perspektivy
    location < 0, 0, -2.1>     // pozice kamery
    right 15*x                 // šířka a výška snímané části scény
    up 15*y
    direction z                // směr pohledu kamery (k počátku)
}

light_source {                 // světelný zdroj
    <0, 0, -500>               // pozice
    color White                // barva
}

#declare COL1=-4.5;            // posuny objektů ve vztahu
#declare COL2= 0.0;            // k pomyslné mřížce
#declare COL3= 4.5;            // o rozměrech 3x3
#declare ROW1= 4.5;
#declare ROW2= 0.0;
#declare ROW3=-4.5;
#declare Z=0.0;

#declare NORMAL=normal {      // testovací procedurální textura
    bumps                     // základ pro tvorbu textury mramoru
    bump_size 1.5
    scale 0.7
}

#declare OBJECT=sphere {
    <0,0,0>, 2
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.0
        }
    }
    translate <COL1, ROW1, Z>
}


object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.1
        }
    }
    translate <COL2, ROW1, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.2
        }
    }
    translate <COL3, ROW1, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.3
        }
    }
    translate <COL1, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.4
        }
    }
    translate <COL2, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.5
        }
    }
    translate <COL3, ROW2, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.6
        }
    }
    translate <COL1, ROW3, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.7
        }
    }
    translate <COL2, ROW3, Z>
}

object {
    OBJECT
    texture {
        pigment {
            color Yellow
        }
        finish {
            phong 1
        }
        normal {
            NORMAL
            turbulence 0.8
        }
    }
    translate <COL3, ROW3, Z>
}

// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2208

Obrázek 8: Výsledek běhu čtvrtého demonstračního příkladu

8. Obsah další části seriálu

V následující části seriálu o aplikaci POV-Ray se (po dokončení vysvětlení modulace normálových vektorů) budeme zabývat nastavením dalších optických vlastností materiálů těles využívaných především při výpočtu průhlednosti, lomu světelných paprsků na povrchu těles a v neposlední řadě také simulaci rozkladu světla při průchodu průhlednými tělesy, s čímž souvisí i simulace vzniku světelných „prasátek“. Uvidíme, že POV-Ray dokáže provádět nejenom klasické zpětné sledování paprsku, tak jako všechny ostatní raytracery, ale také výpočetně mnohem náročnější dopředné sledování paprsku, které se využívá právě při modelování složitějších optických jevů vznikajících na povrchu či uvnitř těles. Jeden takový – běžnými raytracery neprodukovatelný – optický jev je ukázán i na dnešním posledním obrázku:

povray2209

Obrázek 9: Ukázka lomu a částečného rozkladu světelných paprsků na rozhraní dvou různých materiálů

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.