Hlavní navigace

Optické vlastnosti uzavřených těles v POV-Rayi

23. 9. 2008
Doba čtení: 13 minut

Sdílet

Klasický raytracing je založen na nalézání průsečíků paprsků s povrchy objektů umístěných ve scéně a výpočtu světelných podmínek v nalezených průsečících. POV-Ray tento výpočetní model dále rozšiřuje o optické vlastnosti vnitřků uzavřených těles, což je téma, kterému se budeme dnes věnovat.

Obsah

1. Koncept otevřených a uzavřených těles
2. Modifikátor clipped_by
3. První demonstrační příklad – použití modifikátoru clipped_by
4. Textura vnitřní strany povrchu těles
5. Druhý demonstrační příklad – objekt s odlišnou vnější a vnitřní texturou
6. Vyplnění uzavřených těles částicemi
7. Třetí demonstrační příklad – tělesa vyplněná částicemi
8. Obsah dalšího pokračování seriálu

1. Koncept otevřených a uzavřených těles

V předchozích částech seriálu o raytraceru POV-Ray jsme si popsali a na mnoha demonstračních příkladech i prakticky ukázali téměř všechny typy těles, které lze použít při vytváření trojrozměrných scén. Všechna základní tělesa nabízená přímo POV-Rayem i tělesa vzniklá pomocí CSG operací (Constructive Solid Geometry) je možné rozdělit do dvou skupin podle toho, zda jejich povrch ohraničuje určitou uzavřenou část prostoru či nikoli. V případě, že nějaké těleso skutečně ohraničuje část prostoru, může být tato ohraničená část považována za vnitřek tělesa (raytracer správně určí, co je vnějšek a co vnitřek), což má vliv zejména v případě, že se jedná o těleso s průhledným či poloprůhledným povrchem a v okolí tělesa se vyskytuje například mlha či jiný materiál, než pouhý prázdný prostor. POV-Ray implicitně považuje všechna uzavřená tělesa za vyplněná, což v některých případech může, jak uvidíme dále, způsobovat nežádoucí vizuální chyby.

povray2901

Obrázek 1: Implicitní plochy jsou v POV-Rayi považovány za uzavřená tělesa s jasně definovaným vnitřkem a vnějškem

Některé typy těles být uzavřené již z principu nemohou – jedná se především o trojúhelníkové plošky (jednoduché trojúhelníky i trojúhelníky se zadanými normálovými vektory – smooth triangles), trojúhelníkové sítě, Bézierovy bikubické plochy, obecné polygony atd. Tato tělesa jsou tvořena nekonečně tenkou plochou, u níž vnitřek a vnějšek nelze jednoznačným způsobem určit (ovšem u nekonečné roviny představované objektem typu plane je to možné, definitoricky se za vnitřek tohoto tělesa považuje poloprostor, do kterého směřuje normálový vektor roviny). Naproti tomu kvádry, koule, válce, kužely, toroidy, superelipsoidy, implicitní plochy, rotační plochy, textové řetězce a další typy objektů jsou v POV-Rayi implicitně považovány za uzavřené, dokonce i v případě, že se těleso například pomocí CSG operací rozdělí na několik menších částí nebo se nějaká jeho část zcela odstraní, typicky operací množinového rozdílu či průniku.

povray2902

Obrázek 2: Často používané typy uzavřených těles, které je možné v POV-Rayi použít při vytváření scény

V případě, že se má vytvořit například nevyplněná koule, lze při jejím zápisu do vytvářené scény použít modifikátor hollow. Pokud je tento modifikátor použit, stane se z původně vyplněného tělesa dutý objekt, jehož povrch je nekonečně tenký, podobně jako je tomu u konceptuálně otevřených těles. V případě, že je těleso otevřené, nemá pro ně modifikátor hollow žádný praktický význam. Ovšem při rozlišování vyplněných a nevyplněných těles je zapotřebí dát pozor na jednu věc – pokud je část povrchu tělesa odříznuta pomocí modifikátoru clipped_by (viz první demonstrační příklad), bude z řezu patrné, že i vyplněné těleso je ve skutečnosti tvořeno pouze svým povrchem (obálkou). Koncept vyplněných a nevyplněných těles totiž paradoxně nijak neovlivňuje způsob, jakým jsou tělesa pomocí raytracingu vykreslována. To, zda je těleso vyplněné či nevyplněné, se projeví až ve chvíli, kdy jeho vnitřek vyplníme nějakým médiem, například mlhou (viz šestá kapitola).

povray2903

Obrázek 3: CSG operace aplikované na uzavřená základní tělesa – výsledkem je opět uzavřené těleso

2. Modifikátor clipped_by

Před vysvětlením metody definice optických vlastností vnitřních částí těles si ukážeme způsob použití modifikátoru clipped_by. Pomocí tohoto modifikátoru je možné odstranit libovolnou část povrchu tělesa, přičemž tvar odstraněné části je určen dalším tělesem (může se jednat i o těleso vzniklé pomocí CSG operací). Ve své podstatě se jedná o analogii k již popsané CSG operaci rozdílu (difference), ovšem s jedním podstatným rozdílem – zatímco u rozdílu dojde ke změně tvaru tělesa, ale povrch je v místě rozdílu zachován (vlastnosti povrchu jsou získané od tělesa, které je „odečítáno“), modifikátor clipped_by v povrchu vytvoří otvor, čímž se otevře průhled do jeho vnitřku. Tato principiální odchylka mezi CSG operací rozdílu a výsledkem použití modifikátoru clipped_by je ukázána na následujících dvou obrázcích:

povray2904

Obrázek 4: Operace rozdílu (difference) aplikovaná na dvě uzavřená tělesa – výsledkem je opět uzavřené těleso, v tomto případě „vykousnutá“ koule A

povray2905

Obrázek 5: Použití modifikátoru clipped_by na kouli A – výsledkem je těleso, v jehož povrchu je vyříznut otvor, kterým mohou procházet světelné paprsky

3. První demonstrační příklad – použití modifikátoru clipped_by

V dnešním prvním demonstračním příkladu je ukázán jeden z možných způsobů aplikace modifikátoru clipped_by na poměrně složitý model představovaný ventilem. Jedná se o těleso vytvořené pomocí mnoha CSG operací. V případě, že je zapotřebí prohlédnout si i vnitřní části takto složitého tělesa, není z rychlostního hlediska vhodné použít ani CSG operaci rozdílu (difference) ani průniku (intersection), ale spíše modifikátor clipped_by, při jehož použití dokonce může dojít k urychlení vykreslení celé scény. V případě, že by byla použita CSG operace rozdílu, muselo by být druhé těleso zcela průhledné se zákazem jakéhokoli lomu či odrazu paprsků.

povray2906

Obrázek 6: Ventil vykreslený bez modifikátoru clipped_by

povray2907

Obrázek 7: Ventil vykreslený s použitím modifikátoru clipped_by

Následuje výpis zdrojového kódu prvního demonstračního příkladu. Modifikátor clipped_by je aplikován až na výsledný objekt po provedení všech potřebných CSG operací, vyskytuje se tedy až na samém konci definice objektu.

// ------------------------------------------------------------
// První demonstrační příklad - použití modifikátoru clipped_by
//
// Autor: siegfriedfeterowsky@web.de
//
// rendering lze spustit příkazem:
//     povray +W800 +H600 +B100 +FN +D +Iscena1.pov +Oscena1.png
//
// (pro náhled postačí zadat povray scena1.pov)
// ------------------------------------------------------------

#declare winkel = 1/10*360*3;
#declare rotall = 1/10*360;
#declare winkel = 45;

// globální nastavení parametrů scény
global_settings
{
    assumed_gamma 1.0
    number_of_waves 1
}

// načtení všech potřebných externích souborů
#include "colors.inc"
#include "shapes.inc"
#include "textures.inc"
#include "metals.inc"

// nastavení kamery (pozorovatele)
camera
{
    location <-20.0, 30.0,-75>
    direction z * 3
    up y
    right x*4/3
    look_at < -2, 0, 0>
}

// dva světelné zdroje
light_source
{
    <10.0, 50.0, 35.0>
    color White
}

light_source
{
    <-35.0, 30.0, -150.0>
    color White
}

// podkladová rovina
plane
{
    y, -10
    pigment
    {
        Navy * .1
    }
}

// část ventilu
#declare loch =difference
{
    cylinder
    {
        <0,-4,0>, <0,-5,0>, 1
        texture
        {
            T_Chrome_5D
        }
    }
    cylinder
    {
        <0,-3.9,0>, <0,-5.1,0>,.5
        texture
        {
            T_Chrome_1A
        }
    }
}

// samotný ventil
object
{
    union
    {
        cone
        {
            <-7,0,0>, 2.6, <-6.2,0,0>, 3.2
            texture
            {
                T_Chrome_5D
            }
        }

        cylinder
        {
            <-6.2,0,0>, <-4.4,0,0>, 3.2
            texture
            {
                T_Chrome_5D
            }
        }

        difference
        {
            union
            {
                object
                {
                    loch
                    translate <-5,9,-3.2>
                }
                object
                {
                    loch
                    translate <4.5,9,-2.4>
                }
                object
                {
                    loch
                    translate <-0.7,9,5.3>
                }
                cylinder
                {
                    <-.4,-4,0>, <-.4,5,0>, 5
                    texture
                    {
                        T_Chrome_5D
                    }
                }
            }
            cylinder
            {
                <-.4,-4.1,0>, <-.4,5.1,0>, 4
                texture
                {
                    T_Chrome_5D
                }
            }
            plane
            {
                <0,0,1>,-3.2
                texture
                {
                    T_Chrome_5D
                }
            }
        }

        difference
        {
            cylinder
            {
                <-.4,-4,0>, <-.4,-5,0>, 5
                texture
                {
                    T_Chrome_5D
                }
            }
            cylinder
            {
                <-.4,-3.9,0>, <-.4,-5.1,0>, 4
                texture
                {
                    T_Chrome_5D
                }
            }
        }

        cylinder
        {
            <3.6 0,0>, <5.6,0,0> ,1.8
            texture
            {
                T_Chrome_5D
            }
        }

        // Mountings

        object
        {
            loch
            translate <-5,0,-3.2>
        }
        object
        {
            loch
            translate <4.5,0,-2.4>
        }
        object
        {
            loch
            translate <-0.7,0,5.3>
        }

#declare welle = union
        {
            cylinder
            {
                <-9.2,0,0> , <5.8,0,0>, .6
                texture
                {
                    T_Copper_5A
                }
                finish
                {
                    metallic
                }
            }
            cylinder
            {
                <-.4,0,-.2>, <-.4,0,.2>, 4
                texture
                {
                    T_Copper_5A
                }
                finish
                {
                    metallic
                }
            }
            cylinder
            {
                <-9.,0,0>, <-7.,0,0>, 1.8
                texture
                {
                    T_Copper_5E
                }
            }
            cylinder
            {
                <-9.1,-1,0>, <-9.1,1,0>, .1
                texture
                {
                    T_Copper_5E
                }
            }
            box
            {
                <-8.5, -1.8, 0>
                <-7.5,  1.8,  -10>
                texture
                {
                    T_Copper_5E
                }
            }
            difference
            {
                cylinder
                {
                    <-9.,0,-10>, <-7,0,-10>, 1.8
                    texture
                    {
                        T_Copper_5E
                    }
                }
                cylinder
                {
                    <-9.1,0,-10>, <-6.9,0,-10>, .9
                    texture
                    {
                        T_Copper_5E
                    }
                }
            }
        }

        object
        {
            welle
            rotate <winkel,0,0>
        }
        rotate rotall*y
    }
    scale 1.5

    // aplikace modifikátoru clipped_by
    clipped_by
    {
        // jedná se o rovinu bez specifikace textury
        plane
        {
            -z,0
        }
        rotate <40,0,0>
    }
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2908

Obrázek 8: Pohled na ventil z odlišného úhlu

4. Textura vnitřní strany povrchu těles

Poměrně specifickou vlastností POV-Raye, která nebývá v jiných raytracerech k dispozici, je možnost pokrýt vnitřní část plochy povrchu tělesa texturou, která je odlišná od textury nanesené na vnější část plochy povrchu tělesa. Nejenom to – je možné nastavit i odlišné optické vlastnosti materiálu, takže například modelovaná koule či jiné uzavřené těleso může mít z vnější strany maximální odrazivost (ideální zrcadlo), zatímco ze strany vnitřní může být zcela černá, bez jakýchkoli odlesků či odrazů světelných paprsků (připomeňme, že vnitřní část tělesa je možné zobrazit buď umístěním kamery i světelných zdrojů dovnitř tělesa nebo použitím výše uvedeného modifikátoru clipped_by s uvedením vhodného ořezového tvaru). Dokonce je možné, aby vnitřní část povrchu měla jinou průhlednost než část vnější, což může vést k tvorbě těles se značně neobvyklými optickými vlastnostmi. Ve většině případů se však setkáváme pouze s potřebou změnit barvu vnitřní strany povrchu tělesa.

V případě, že je u modelovaného tělesa uvedena pouze jedna textura (pomocí nám již známého a do podrobností popsaného uzlu texture), je tato textura platná současně jak pro vnější, tak i pro vnitřní povrch tělesa. Ve chvíli, kdy má být vnitřní povrch tělesa pokrytý odlišnou texturou či má mít jiné optické vlastnosti, lze použít uzel nazvaný interior_texture. Tento uzel může obsahovat stejné parametry a poduzly, jako texture, ovšem s tím rozdílem, že hodnoty jsou platné pouze pro vnitřní stranu povrchu těles. Uzel interior_texture lze použít i u některých „otevřených“ těles, například pro Bézierův bikubický plát – v tomto případě je texture použito pro přední stranu povrchu a interior_texture pro stranu zadní. Přední a zadní strana je rozeznána podle orientace normálových vektorů. Syntaxe zápisu obecného objektu používajícího jak uzel texture, tak i uzel interior_texture, je následující:

object
{
  texture
  {
      ...
      atributy textury
      ...
  }
  interior_texture
  {
      ...
      atributy textury
      ...
  }
} 
povray2909

Obrázek 9: Bez použití uzlu interior_texture jsou obě dvě strany povrchu tělesa pokryté stejnou texturou a povrch má i stejné optické vlastnosti

5. Druhý demonstrační příklad – objekt s odlišnou vnější a vnitřní texturou

V dnešním druhém demonstračním příkladu je ukázáno, jakým způsobem je možné vykreslit těleso, jehož vnější povrch má texturu odlišnou od povrchu vnitřního. Testovacím objektem je obyčejná koule. Vnější povrch koule je modrý, vnitřní povrch červený. Aby byl jak vnější, tak i vnitřní povrch viditelný, je na kouli aplikován výše popsaný operátor clipped_by s ořezovým tělesem ve tvaru krychle, která má střed totožný se středem koule a délku hran zvolenou tak, aby jednotlivé stěny krychle protínaly povrch koule a vytvořily v něm tak šest kruhových otvorů (podobný tvar, i když uzavřený, mívají například hrací kostky).

povray2910

Obrázek 10: Obrázek vzniklý vykreslením druhého demonstračního příkladu

Zdrojový kód dnešního druhého demonstračního příklad vypadá následovně:

// ------------------------------------------------------------
// Druhý demonstrační příklad - vnější a vnitřní textura
//
// Založeno na souboru původně vytvořeném Danem Farmerem (leden 2002)
//
// rendering lze spustit příkazem:
//     povray +W800 +H600 +B100 +FN +D +Iscena2.pov +Oscena2.png
//
// (pro náhled postačí zadat povray scena2.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"

// 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
}

// tři světelné zdroje
light_source
{
    <-30, 11,  20>                       // pozice světelného zdroje
    color White                          // barva světla
}

light_source
{
    < 31, 12, -20>                       // pozice světelného zdroje
    color White                          // barva světla
}

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

#declare VEL=1.4;                        // velikost krychle

sphere
{
    <0, 0, 0>,                           // souřadnice středu koule
    1.8                                  // poloměr koule
    texture
    {                                    // textura - povrch koule
        pigment
        {
            color <0,0,1>
        }
        finish
        {                                // optické vlastnosti materiálu
            phong 1                      // velikost a síla odlesků
            phong_size 300
            reflection 0.15              // odrazivost
        }
    }
    interior_texture                     // vnitřní textura
    {
        pigment
        {
            color <1,0,0>
        }
        finish
        {                                // optické vlastnosti materiálu
            phong 1                      // velikost a síla odlesků
            phong_size 300
            reflection 0.15              // odrazivost
        }
    }
    clipped_by                           // část koule je odříznuta
    {
        box
        {
            <-VEL, -VEL, -VEL>           // jeden z vrcholů krychle na tělesové úhlopříčce
            < VEL,  VEL,  VEL>           // druhý z vrcholů krychle na tělesové úhlopříčce
        }
    }
    translate <0.5, 0.5, -0.4>           // posun a změna měřítka
    scale 1.3
    rotate <0,40,0>                      // rotace výsledného "dvojtělesa"
}

// druhý objekt - nekonečná rovina
plane
{
    y,                                   // orientace roviny
    -1.5                                 // vzdálenost od počátku
    texture
        {                                // textura - vlastnosti povrchu
        pigment
        {
            crackle
        }
        finish
        {                                // optické vlastnosti materiálu
            reflection 0.10
        }
    }
}



// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 

6. Vyplnění uzavřených těles částicemi

Pozorný čtenář, který si přečetl první kapitolu tohoto článku, se může oprávněně ptát, proč jsme si vlastně popisovali rozdíly mezi uzavřenými a otevřenými tělesy a z jakého důvodu je do jazyka POV-Raye přidáno slovo hollow. Vždyť jak vyplněná, tak i prázdná uzavřená tělesa se vykreslují stejně, jejich povrch je v obou případech nekonečně tenký a vnitřní část prázdná. Skutečně tomu tak je, ovšem s jednou zásadní výjimkou – POV-Ray totiž umožňuje, aby se vnitřek uzavřených a současně prázdných těles vyplnil částicemi s různými optickými vlastnostmi. Může se jednat například o částice, které emitují žluté světlo – výsledkem je model slunce či v mnoha hrách populárního fireballu –, částice pohlcující světlo (mlha, kouř) atd. Statistické parametry částic jsou specifikovány v uzlu typu media, který bude podrobně popsán v následující části tohoto seriálu. Dnes si na jednom demonstračním příkladu ukážeme, jak se uzel používá a pro jaká tělesa je vhodné ho použít.

povray2911

Obrázek 11: Optické jevy, které je možné vytvořit korektním použitím uzlu media

7. Třetí demonstrační příklad – tělesa vyplněná částicemi

Ve třetím demonstračním příkladu je ukázáno použití uzlu typu media. Pomocí tohoto uzlu jsou jediná dvě uzavřená tělesa ve scéně – koule – vyplněna částicemi, které emitují světlo. Hustota částic a tím i intenzita světla v daném bodě objemu tělesa je vypočtena na základě procedurálních textur, které, jak již víme, pro každý bod v prostoru vrací reálnou hodnotu (procedurální textury jsou tedy definovány v objemu, nikoli pouze v ploše). Použitá procedurální textura je velmi jednoduchá – její hustota je nejvyšší ve středu koulí a se zvyšující se vzdáleností od středu postupně klesá. Díky aplikaci turbulence se průběh hustoty stane více náhodný. Všimněte si, že povrch koulí je zcela průhledný a že obě koule jsou prázdné – u obou je použito klíčové slovo hollow. V tomto případě je nutné, aby tělesa byla prázdná, jinak by docházelo k vizuálním chybám při výpočtu (především ve chvíli, kdy by povrch těles již nebyl zcela průhledný). Následuje výpis zdrojového kódu třetího demonstračního příkladu:

// ------------------------------------------------------------
// Třetí demonstrační příklad - použití uzlu typu "media"
//
// Založeno na souboru dodávaném společně s POV-Rayem verze 3.5
// Autor: Dieter Bayer
//
// rendering lze spustit příkazem:
//     povray +W800 +H600 +B100 +FN +D +Iscena3.pov +Oscena3.png
//
// (pro náhled postačí zadat povray scena3.pov)
// ------------------------------------------------------------

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

// načtení všech potřebných externích souborů
#include "colors.inc"

// nastavení kamery (pozorovatele)
camera
{
    location  <0, 20,-100>               // pozice kamery
    direction <0, 0, 1>                  // orientace kamery
}

// světelné zdroje
light_source
{
    <500, 600, -200>                     // pozice světelného zdroje
    color White                          // barva světla
}

// nekonečná rovina - podklad (podlaha)
plane
{
    y, -10
    pigment
    {                                    // textura se vzorkem šachovnice
        checker White, Black
        scale 20
    }
    finish
    {
        ambient 0.2
        diffuse 0.8
    }
    hollow
}

// nekonečná rovina - zadní stěna
plane
{
    z, 50
    pigment
    {                                    // textura se vzorkem šachovnice
        checker White, Black
        scale 20
    }
    finish
    {
        ambient 0.2
        diffuse 0.8
    }
    hollow
}

// medium použité pro výplň levé koule
#declare Media1 =
media {
    emission 0.05
    intervals 1
    samples 5
    method 3
    density {
        spherical
        ramp_wave
        turbulence 0.8
        color_map {
            [0.0 color rgb <0, 0, 0>]
            [0.2 color rgb <1, 0, 0>]
            [1.0 color rgb <1, 1, 0>]
        }
    }
}

// medium použité pro výplň pravé koule
#declare Media2 =
media {
    emission 0.25
    intervals 1
    samples 5
    method 3
    density {
        spherical
        sine_wave
        turbulence 1.0
        color_map {
            [0.0 color rgb <0, 0, 0>]
            [0.9 color rgb <0, 0, 1>]
            [1.0 color rgb <1, 0.8, 0>]
        }
    }
}

// vyplněné objekty
sphere
{
    < 0, 0, 0>, 1
    pigment
    {
        color rgbf <1, 1, 1, 1>          // povrch je neviditelný
    }
    finish
    {
        ambient 0                        // také odlesky jsou zakázané
        diffuse 0
    }
    interior                             // výplň tělesa - částice
    {
        media
        {
            Media1
        }
    }
    scale 28
    translate <-29, 20, 0>
    hollow                               // důležité - zákaz automatické výplně tělesa
}

sphere
{
    < 0, 0, 0>, 1
    pigment
    {
        color rgbf <1, 1, 1, 1>          // povrch je neviditelný
    }
    finish
    {
        ambient 0                        // také odlesky jsou zakázané
        diffuse 0
    }
    interior                             // výplň tělesa - částice
    {
        media
        {
            Media2
        }
    }
    scale 28
    translate <29, 20, 0>
    hollow                               // důležité - zákaz automatické výplně tělesa
}


// ------------------------------------------------------------
// finito
// ------------------------------------------------------------ 
povray2912

Obrázek 12: Obrázek vzniklý vykreslením třetího demonstračního příkladu (tento obrázek je vhodné si prohlédnout v původní velikosti, aby vynikly detaily)

CS24_early

8. Obsah dalšího pokračování seriálu

I v následující části seriálu o raytraceru POV-Ray se budeme zabývat nastavením uzlu typu media, pomocí kterého je možné vyplňovat uzavřená tělesa. Podrobně si popíšeme a na demonstračních příkladech i ukážeme nejdůležitější atributy, které je možné v tomto uzlu nastavit.

Byl pro vás článek přínosný?

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.