Hlavní navigace

Výšková pole a úprava normálových vektorů ve VRML

6. 12. 2007
Doba čtení: 9 minut

Sdílet

V dnešní části seriálu o zajímavých grafických formátech a metaformátech si řekneme, jakým způsobem je možné v jazyce VRML 2 nadefinovat tělesa vytvořená pomocí takzvaných výškových polí (height field). Také si ukážeme význam normálových vektorů při specifikaci povrchu tělesa a způsob jejich změny.

Obsah

1. Výšková pole – malé zopakování
2. První demonstrační příklad – použití výškového pole s globálním nastavením barvy
3. Druhý demonstrační příklad – použití výškového pole s explicitním nastavením barvy pro každý jeho vrchol
4. Normálové vektory a jejich význam
5. Nastavení normálových vektorů trojrozměrných objektů
6. Obsah další části seriálu
7. Zdrojové kódy demonstračních příkladů

1. Výšková pole – malé zopakování

V předchozí části tohoto seriálu jsme si řekli, že jazyk VRML 2 podporuje tvorbu těles zapisovaných ve formě takzvaných výškových polí známých také pod původním anglickým názvem height field. Tato pole jsou poměrně úspornou formou uložena v uzlu nazvaném ElevationGrid, ve kterém jsou zapsány jak informace o velikosti (dimenzi) pole, vzhledu materiálu, texturování, barvách atd., tak i y-ové souřadnice vrcholů pole. Ostatní dvě souřadnice, tj. x a z jsou pro každý bod/vrchol dopočítány automaticky z indexu bodu, tj. z jeho pozice v mřížce. Počátek mřížky, tj. její levý dolní roh při pohledu z osy y, leží v počátku souřadného systému na souřadnicích [0, 0, 0] a indexy mřížky se zvětšují ve směru růstu os x a z. Ve VRML je, podobně jako v mnoha dalších nástrojích, použit pravotočivý souřadný systém, ve kterém mají grafici tendenci uvažovat o ose z rostoucí směrem nahoru – ostatně to také odpovídá například implicitnímu nastavení některých 3D editorů. Takto chápané uspořádání trojrozměrné scény je zobrazeno na prvním obrázku:

671

Pravotočivý souřadný systém použitý ve VRML

Ovšem při práci s výškovým polem je lepší si osy souřadného systému mentálně pootočit tak, aby po promítnutí směřovala osa y směrem nahoru a zbývající dvě osy tvořily základní rovinu. Implicitní pozice pozorovatele (kamery) při inicializaci VRML prohlížeče leží v bodě [0, 0, 10], přičemž pozorovatel/kamera je natočen tak, aby se díval na počátek souřadného systému. V této konfiguraci opravdu dochází k tomu, že osa y směřuje na obrazovce, tj. po promítnutí 3D scény na 2D plochu, směrem nahoru, což je pravděpodobně důvod, proč tvůrci VRML navrhli výšková pole, jejichž mřížka leží v rovině X-Z a ne X-Y, jak je tomu například v některých editorech specializovaných na vytváření „3D světů“. Celá konfigurace souřadného systému a mřížky výškového pole je zobrazena na druhém obrázku. Všimněte si, že i po pootočení souřadného systému je stále zachována jeho „pravotočivost“, pouze se změnila pozice pozorovatele (kamery) a směr jeho pohledu:

672

„Pootočený“ pravotočivý souřadný systém s naznačením pozice mřížky výškového pole

2. První demonstrační příklad – použití výškového pole

V dnešním prvním demonstračním příkladu je ukázáno použití výškových polí při vykreslení trojrozměrného grafu jednoduché funkce z=x×y. Graf této funkce tvoří v okolí počátku souřadného systému takzvanou sedlovou plochu, někdy také nazývanou hyperbolický paraboloid (tento název vznikl podle tvaru řezů grafu sedlové plochy rovinou kolmou na některou souřadnou osu nebo rovinou pootočenou o 45° – vznikne buď řez ve tvaru paraboly nebo hyperboly). Výškové pole je určeno poměrně malým počtem bodů, protože je použita mřížka o rozměrech pouze 10×10 vrcholů (v reálných scénách bývají rozměry mnohem větší). Aby bylo možné celým trojrozměrným modelem lehce manipulovat, například ho natáčet, je výškové pole posunuto tak, aby střed mřížky ležel v počátku souřadného systému. U výškového pole sice nemůžeme přímo ovlivnit, kde leží jeho střed ani kterým směrem bude mřížka natočena, pomůžeme si však tím, že celý uzel výškového pole umístíme do uzlu představujícího transformaci.

673

Ve scéně je vytvořen (pokud tedy nepočítáme s objektem představujícím osvětlení) ještě jeden geometrický objekt, který plní pomocnou funkci – slouží k naznačení základní roviny, nad kterou je zkonstruováno výškové pole. Vzhledem k tomu, že nám dostačuje zobrazení jednoduché plošné mřížky (šachovnice) složené z úseček, je použit uzel typu IndexedLineSet. Samotný graf výškového pole má nastavenu částečnou průhlednost, aby byla mřížka vždy viditelná. Specifikací průhlednosti se samozřejmě změní i výsledná barva grafu, protože jím bude prosvítat oranžové pozadí. Dimenze pole, tj. velikost mřížky je nastavena na 10×10 vrcholů, odstup jednotlivých sousedních bodů/vrcholů je 3 metry. Nastavením atributu solid je zaručeno, že se výškové pole zobrazí i při pohledu na jeho spodní povrch. Obsah celého VRML souboru s touto trojrozměrnou scénou je následující:

#VRML V2.0 utf8
# verze 2.0 vyzaduje kodovani UTF-8

# ---------------------------------------------------------
# Prvni demonstracni priklad trojrozmerne sceny
# popsane jazykem VRML 2.0, ktera obsahuje vyskove pole
# a pomocny objekt slozeny z usecek
#
# Priklad je soucasti serialu "Graficke formaty"
# (/serialy/graficke-formaty/)
# vychazejiciho na Root.cz (http://www.root.cz)
# ---------------------------------------------------------

WorldInfo {
    title "Prvni 3D scena s vyskovym polem"
    info ["Autor: Pavel Tisnovsky, 2007"
         "sireno pod licenci GPL "
         "(zde mohou byt dalsi texty"]
}

# nastaveni barevneho prechodu na pozadi sceny
Background {
    skyColor [1 1 0,
              1 0 0]
    skyAngle [3.14]
}

# nastaveni pozice pozorovatele
Viewpoint {
    position     50 50 50
    orientation -0.5989022244467349 0.7614300374339465 0.2480734239012532 0.9964411608712673
}

# nastaveni svetelneho zdroje
PointLight {
    color     1.0 1.0 1.0 # barva svetla
    intensity 1.0         # intenzita bodoveho svetla
    location  0.0 4.0 1.0 # pozice svetelneho zdroje
}

Transform {
    # transformace kvuli posunu vyskoveho pole do stredu sceny
    translation -15 0 -15
    children [

        # pomocne teleso slozene z usecek
        Shape {
            # vzhled objektu - negeometricke informace
            appearance Appearance {
                material Material {
                    emissiveColor 0 0 1
                    transparency  1.0
                }
            }
            # tvar objektu - geometricke informace
            geometry IndexedLineSet {
                # interni poduzel se souradnicemi bodu
                coord Coordinate {
                    point [
                        0   0   0,  # zakladni "ctverec"
                        30  0   0,
                        30  0  30,
                        0   0  30,

                        10  0   0,  # horizontalni casti sachovnice
                        10  0  30,
                        20  0   0,
                        20  0  30,

                         0  0  10,  # vertikalni casti sachovnice
                        30  0  10,
                         0  0  20,
                        30  0  20
                 ]
              }
                # indexy do predchoziho pole
                # (pouze usecky) oddelene
                # indexem s hodnotou -1
                coordIndex [
                     0  1  2  3  0 -1  # zakladna
                     4  5 -1           # vnitrni hrany sachovnice
                     6  7 -1
                     8  9 -1
                    10 11 -1
                ]
            }
        }
        Shape {
            # vzhled objektu - negeometricke informace
            appearance Appearance {
                material Material {
                    emissiveColor 0.0 0.0 0.0
                    diffuseColor  0.8 0.8 0.8
                    specularColor 1.0 1.0 1.0
                    transparency  0.5
                }
            }
            # tvar objektu - geometricke informace
            # vyskoveho pole
            geometry ElevationGrid {
                xDimension 10
                xSpacing   3
                zDimension 10
                zSpacing   3
                solid      FALSE
                height [
                 20.2    15.8    11.2     6.8     2.2   -2.2    -6.8   -11.2   -15.8   -20.2
                 11.2     8.8     6.2     3.8     1.2   -1.2    -3.8    -6.2    -8.8   -11.2
                  6.8     5.2     3.8     2.2     0.8   -0.8    -2.2    -3.8    -5.2    -6.8
                  2.2     1.8     1.2     0.8     0.2   -0.2    -0.8    -1.2    -1.8    -2.2
                 -2.2    -1.8    -1.2    -0.8    -0.2    0.2     0.8     1.2     1.8     2.2
                 -3.4    -2.6    -1.9    -1.1    -0.4    0.4     1.1     1.9     2.6     3.4
                -11.2    -8.8    -6.2    -3.8    -1.2    1.2     3.8     6.2     8.8    11.2
                -15.8   -12.2    -8.8    -5.2    -1.8    1.8     5.2     8.8    12.2    15.8
                -15.8   -12.2    -8.8    -5.2    -1.8    1.8     5.2     8.8    12.2    15.8
                -20.2   -15.8   -11.2    -6.8    -2.2    2.2     6.8    11.2    15.8    20.2
                    ]
            }
        }
    ]
}



# ---------------------------------------------------------
# finito
# --------------------------------------------------------- 
674

3. Druhý demonstrační příklad – použití výškového pole s explicitním nastavením barvy pro každý jeho vrchol

Ve druhém demonstračním příkladu je zobrazen stejný graf, jako v příkladu prvním. Změnil se však způsob specifikace barev plochy grafu. Zatímco v prvním příkladu byl použit uzel Appearance s poduzlem Material, kterým se nastavil způsob zobrazení povrchu celého výškového pole, je ve druhém příkladu použitý jiný způsob. Barva je přiřazena každému vrcholu výškového pole s tím, že se barvy ploch mezi vrcholy automaticky interpolují. V tomto případě je nutné k poli vrcholů reprezentované atributem height přidat ještě pole barev reprezentované atributem color. Toto pole by mělo mít stejnou dimenzi, přičemž každá barva je typicky reprezentována trojicí hodnot představujících barvové složky barvového modelu RGB.

675

Zdrojový kód druhého demonstračního příkladu má následující obsah:

#VRML V2.0 utf8
# verze 2.0 vyzaduje kodovani UTF-8

# ---------------------------------------------------------
# Druhy demonstracni priklad trojrozmerne sceny
# popsane jazykem VRML 2.0, ktera obsahuje vyskove pole
#
# Priklad je soucasti serialu "Graficke formaty"
# (/serialy/graficke-formaty/)
# vychazejiciho na Root.cz (http://www.root.cz)
# ---------------------------------------------------------

WorldInfo {
    title "Druha 3D scena s vyskovym polem"
    info ["Autor: Pavel Tisnovsky, 2007"
         "sireno pod licenci GPL "
         "(zde mohou byt dalsi texty"]
}

# nastaveni barevneho prechodu na pozadi sceny
Background {
    skyColor [1 1 0,
              1 0 0]
    skyAngle [3.14]
}

# nastaveni pozice pozorovatele
Viewpoint {
    position     40 20 40
    orientation -0.5989022244467349 0.7614300374339465 0.2480734239012532 0.9964411608712673
}

# nastaveni svetelneho zdroje
PointLight {
    color     1.0 1.0 1.0 # barva svetla
    intensity 1.0         # intenzita bodoveho svetla
    location  0.0 4.0 1.0 # pozice svetelneho zdroje
}

Transform {
    # transformace kvuli posunu vyskoveho pole do stredu sceny
    translation -15 0 -15
    children [

        # pomocne teleso slozene z usecek
        Shape {
            # vzhled objektu - negeometricke informace
            appearance Appearance {
                material Material {
                    emissiveColor 0 0 1
                    transparency  1.0
                }
            }
            # tvar objektu - geometricke informace
            geometry IndexedLineSet {
                # interni poduzel se souradnicemi bodu
                coord Coordinate {
                    point [
                        0   0   0,  # zakladni "ctverec"
                        30  0   0,
                        30  0  30,
                        0   0  30,

                        10  0   0,  # horizontalni casti sachovnice
                        10  0  30,
                        20  0   0,
                        20  0  30,

                         0  0  10,  # vertikalni casti sachovnice
                        30  0  10,
                         0  0  20,
                        30  0  20
                 ]
              }
                # indexy do predchoziho pole
                # (pouze usecky) oddelene
                # indexem s hodnotou -1
                coordIndex [
                     0  1  2  3  0 -1  # zakladna
                     4  5 -1           # vnitrni hrany sachovnice
                     6  7 -1
                     8  9 -1
                    10 11 -1
                ]
            }
        }
        Shape {
            # tvar objektu - geometricke informace
            # vyskoveho pole
            geometry ElevationGrid {
                xDimension 10
                xSpacing   3
                zDimension 10
                zSpacing   3
                solid      FALSE
                height [
                 20.2    15.8    11.2     6.8     2.2   -2.2    -6.8   -11.2   -15.8   -20.2
                 11.2     8.8     6.2     3.8     1.2   -1.2    -3.8    -6.2    -8.8   -11.2
                  6.8     5.2     3.8     2.2     0.8   -0.8    -2.2    -3.8    -5.2    -6.8
                  2.2     1.8     1.2     0.8     0.2   -0.2    -0.8    -1.2    -1.8    -2.2
                 -2.2    -1.8    -1.2    -0.8    -0.2    0.2     0.8     1.2     1.8     2.2
                 -3.4    -2.6    -1.9    -1.1    -0.4    0.4     1.1     1.9     2.6     3.4
                -11.2    -8.8    -6.2    -3.8    -1.2    1.2     3.8     6.2     8.8    11.2
                -15.8   -12.2    -8.8    -5.2    -1.8    1.8     5.2     8.8    12.2    15.8
                -15.8   -12.2    -8.8    -5.2    -1.8    1.8     5.2     8.8    12.2    15.8
                -20.2   -15.8   -11.2    -6.8    -2.2    2.2     6.8    11.2    15.8    20.2
                    ]
                color Color {
                    color [
                        1 0.2 0  1 0.4 0  0 0.6 0  0 0.8 0  0 0.8 0
                        1 0.4 0  1 0.6 0  0 0.8 0  0 1 0.2  0 1 0.2
                        1 0.6 0  1 0.8 0  0 1 0.2  0 1 0.4  0 1 0.4
                        1 0.8 0  1 1 0.2  0 1 0.4  0 1 0.6  0 1 0.6
                        1 0.2 0  1 0.4 0  0 0.6 0  0 0.8 0  0 0.8 0
                        1 0.4 0  1 0.6 0  0 0.8 0  0 1 0.2  0 1 0.2
                        1 0.6 0  1 0.8 0  0 1 0.2  0 1 0.4  0 1 0.4
                        1 0.8 0  1 1 0.2  0 1 0.4  0 1 0.6  0 1 0.6
                        1 0.6 0  1 0.8 0  0 1 0.2  0 1 0.4  0 1 0.4
                        1 0.8 0  1 1 0.2  0 1 0.4  0 1 0.6  0 1 0.6

                        0 0.2 1  1 0.4 0  0 0.6 0  0 0.8 0  0 0 0.8
                        0 0.4 1  1 0.6 0  0 0.8 0  0 1 0.2  0.2 1 0
                        0 0.6 1  1 0.8 0  0 1 0.2  0 1 0.4  0.4 1 0
                        0 0.8 1  1 1 0.2  0 1 0.4  0 1 0.6  0.6 1 0
                        0 0.2 1  1 0.4 0  0 0.6 0  0 0.8 0  0 0 0.8
                        0 0.4 1  1 0.6 0  0 0.8 0  0 1 0.2  0.2 1 0
                        0 0.6 1  1 0.8 0  0 1 0.2  0 1 0.4  0.4 1 0
                        0 0.8 1  1 1 0.2  0 1 0.4  0 1 0.6  0.6 1 0
                        0 0.6 1  1 0.8 0  0 1 0.2  0 1 0.4  0.4 1 0
                        0 0.8 1  1 1 0.2  0 1 0.4  0 1 0.6  0.6 1 0
                    ]
                }
            }
        }
    ]
}



# ---------------------------------------------------------
# finito
# --------------------------------------------------------- 
676

4. Normálové vektory a jejich význam

Při výpočtu osvětlení je bezpodmínečně nutné nějakým způsobem zjistit u každého vrcholu nebo každé plošky její normálu, jinak by nebylo možné spočítat barvu na povrchu tělesa (viz dříve popsaný Phongův osvětlovací model se složkami ambientního, difúzního a odraženého světla). Pokud není normála nastavena, předpokládá se, že prohlížeč VRML souborů normálový vektor automaticky dopočítá, což však nemusí být v některých případech žádoucí. Na druhou stranu se však vynecháním informací o normálových vektorech zkracuje VRML soubor a zjednodušuje se způsob jeho zápisu.

Pro korektní funkčnost výpočtu osvětlení musí být normálový vektor normalizován, tj. délka tohoto vektoru musí být jednotková. Normalizaci je nutné provést programově při vytváření VRML souborů. Pokud by normálový vektor nebyl normalizovaný, nastanou při výpočtech osvětlení chyby, které sice mohou vést k zajímavým efektům (posunuté odlesky, „černá“ barva odlesků atd.), ale nejsou obecně přenositelné mezi různými prohlížeči nebo i stejnými prohlížeči s jinou grafickou kartou či verzí ovladače.

Programová normalizace spočívá v tom, že se vypočte délka normálového vektoru podle vzorce:
L=sqrt(nx2+n2+nz2)
a touto délkou se vydělí každá složka normálového vektoru:
nx‚=nx / L
ny‘=ny / L
nz'=nz / L

Při vykreslování trojrozměrných objektů uložených ve VRML souborech je možné používat dva typy stínování: konstantní a Gouraudovo. Při použití konstantního stínování je pro každou plošku (tj. například trojúhelník či plošný mnohoúhelník) spočítána jedna barva a celá ploška je při vykreslování touto barvou vykreslena. Výsledkem je, že jsou na zobrazovaném tělese jasně patrné všechny hrany mezi ploškami, což je nepříjemné zvláště u oblých tvarů. Řešení tohoto problému založené na zmenšení plošek a tím i zpřesnění povrchu tělesa není vždy žádoucí, protože vede k mnohdy neúměrnému zvětšení souborů a také k pomalejšímu vykreslování.

Problém viditelnosti hran částečně řeší Gouraudovo stínování, u kterého se spočítají barvy jednotlivých vrcholů (normály jsou zadané pro vrcholy, takže se přímo použijí pro výpočet osvětlení) a vykreslovaná ploška mezi těmito vrcholy je vyplněna přechodem mezi těmito barvami. Výsledkem jsou jemnější hrany, které jsou méně viditelné. Gouraudovo stínování samozřejmě způsobuje také vizuální chyby, protože se osvětlení počítá pouze ve vrcholech a ignorují se světelné podmínky na ploškách. To například znamená, že zejména na velkých plochách jsou jasně patrné absence odlesků.

677

5. Nastavení normálových vektorů trojrozměrných objektů

S možností nastavení normálových vektorů se setkáváme u několika typů objektů. Pravděpodobně nejpoužívanější z těchto objektů je minule popsaný IndexedFaceSet, v jehož uzlu je možné specifikovat atribut normal. Stejně pojmenovaným atributem je možné nastavovat normálové vektory vrcholů i ve výškových polích. Tyto atributy se používají naprosto stejným způsobem, jako příbuzné atributy color. Pravdivostním atributem normalPerVertex je určeno, zda se normálový vektor vztahuje k celé plošce nebo k jednotlivým vrcholům (počet normál se v obou případech samozřejmě liší). Pokud jsou normály vztaženy k celým ploškám, je použito konstantní stínování, v opačném případě sice pomalejší ale zato kvalitnější stínování Gouraudovo.

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

Celou následující část seriálu o grafických formátech a metaformátech se budeme zabývat problematikou šablonování, tj. zejména uzlem typu Extrusion a také způsobem texturování dvourozměrných i trojrozměrných objektů.

CS24_early

7. Zdrojové kódy demonstračních příkladů

Zdrojové kódy obou dnešních demonstračních příkladů si můžete stáhnout ve zkomprimované podobě z této adresy.

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.