Hlavní navigace

Open Inventor: Terrain Generator (1)

Jan Pečiva 19. 5. 2004

V počítačové grafice existuje několik základních metod pro generování virtuální krajiny. My si ukážeme dvě z nich.

V minulých dílech jsme se pohybovali ve vesmíru. Nyní se dostáváme zpět na zem a budeme zkoušet generovat krajinu. Krajinou zde budeme nazývat to, co se skrývá za anglickým slovem „landscape“, tedy zemský povrch, nikoliv lesy, louky, háje a pasoucí se ovce.

V následujících dvou dílech bychom si měli ukázat dvě nejzákladnější metody pro generování krajiny:

  • Mid-point displacement (zkráceně midpoint) – metoda přesouvání prostředního bodu
  • Fault formation algoritmus – metoda zlomů

V tomto dílu se budeme soustředit na základy z generování krajiny, takže nečekejte nějaké super výsledky. Ty se možná dostaví příště, kdy vše dotáhneme do konce. Dnes nás tedy čekají tyto dva příklady:

Tabulka č. 562
3.1 – Simple Terrain Nejjednodušší krajina vytvořená ze statické výškové mapy
3.2 – Midpoint Terrain Krajina generovaná midpoint algoritmem

Příklad 3.1: Simple Terrain

Zdrojáky si můžete stáhnout zde. Novinka je, že jsou společné pro Linux i pro Windows. Všechen problematicky přenosný kód byl přesunut do souborů Main-Linux.cpp a Main-Windows.cpp. Z těchto souborů se pak volá především funkce createScene(), která je už umístěna v našem SimpleTerrain.cpp spolu s množstvím dalšího kódu tohoto příkladu.

Abychom věděli, k čemu směřujeme, ukažme si screenshot:

Vidíme plát krajiny osvětlený jedním světlem. Jak vytvořit takovýto plát? K tomu se v počítačové grafice často používá výšková mapa – anglicky „height map“. Ve zdrojovém souboru SimpleTerrain.cpp můžeme tuto výškovou mapu najít jakožto pole floatů 16×16 udávající výšku krajiny v jejích jednotlivých bodech. V tomto příkladě je výšková mapa zadána staticky, ale v dalších příkladech si ji budeme generovat sami.

Máme-li výškovou mapu, je druhou otázkou, jak ji zobrazit. Na následujícím obrázku vidíme, že krajina je složená z čtverců, jejichž vrcholy mají různou výšku. A právě tuto výšku nám udává naše výšková mapa.

Nejvhodnější třídou pro rendrování čtverců je SoQuadMesh, ač ji použijeme jen tentokrát a v následujících příkladech už to bude jen tradiční So(Indexed)Tri­angleStripSet.

Pojďme tedy zabrouzdat do zdrojových kódů. Naším nejdůležitějším úkolem je výpočet souřadnic bodů (neboli vertexů) naší krajiny a jejich předání do nodu SoCoordinate3:

// Vytvoř objekt nesoucí souřadnice modelu krajiny
SoCoordinate3 *coords = new SoCoordinate3;

// Nejprve nastavíme počet souřadnic, které budeme generovat.
// (šablona SbSqr počítá druhou mocninu)
coords->point.setNum(SbSqr(TERRAIN_SIZE));
SbVec3f *c = coords->point.startEditing();

// Nyní generujeme souřadnice bodů do paměti
int ci = 0;
int x,y;
for (y=0; y<TERRAIN_SIZE; y++) {
  for (x=0; x<TERRAIN_SIZE; x++) {
    c[ci++] = SbVec3f(float(x), hmap[y][x]/15.f, float(y));
  }
}
coords->point.finishEditing();
root->addChild(coords); 

Nód SoQuadMesh pak provádí už samotné vykreslení. Stačí mu říci, kolik vertexů máme v řádcích a kolik v sloupcích:

// Vytvoříme objekt "čtvercové mřížky" a nastavíme počet
// řádků a sloupců.
SoQuadMesh *mesh = new SoQuadMesh;
mesh->verticesPerColumn.setValue(TERRAIN_SIZE);
mesh->verticesPerRow.setValue(TERRAIN_SIZE);
root->addChild(mesh); 

Za krátkou zmínku stojí i osvětlení scény. Terén je osvětlen směrovým světlem, a jak čteme z jeho směrového vektoru (0.35f, –1.0f, 0.25f), svítí podle y-ové osy směrem dolů, podle x-ové trochu doprava a podle z trochu ke kameře. Dále je vypnuto defaultní světlo u kamery a ambientní světlo u SoEnvironment je nastaveno na 0.5, aby se nám krajina na odvrácených stranách od světla příliš nezatmívala.

Tímto jsme dokončili jednoduchý příklad provádějící zobrazování výškové mapy a můžeme přejít ke generovacím algoritmům.

Příklad 3.2: Midpoint Terrain

V tomto příkladu si zkusíme vygenerovat výškovou mapu sami. Podíváme-li se do zdrojáků, které jsou ke stažení zde, uvidíme v souboru Midpoint1.cpp dvě funkce: generateMap() a createModel(). První z nich je samotný midpoint algoritmus, který vygeneruje výškovou mapu, druhá pak z této výškové mapy vytvoří odpovídající vertexy v SoCoordinate3 a naplní SoTriangleStripSet. Sama vrátí kořen grafu scény, který zkonstruovala.

My se v prvé řadě podíváme na generovací algoritmus. Ten pracuje iteračně a v každém kroku zvyšuje dvojnásobně úroveň detailu. A každý krok se skládá ze dvou podkroků. Podívejme se tedy na celou situaci na obrázcích.

Na začátku máme čtverec, který reprezentuje celou naši výškovou mapu. Do jeho rohů je přiřazena počáteční výška:

V prvním podkroku si vezme algoritmus prostřední bod čtverce, spočítá průměrnou výšku ze čtyř rohových bodů, připočte nebo odečte nějakou náhodnou hodnotu a výsledek uloží to tohoto prostředního bodu. Aktuální situaci demonstruje obrázek:

Ve druhém podkroku pootočíme naši hlavu o 45 stupňů a vidíme čtyři půlky čtverců, kterým však byla uříznuta jedna polovina. V dalších krocích už nebudeme mít tolik „půlek“, ale i tam musíme tento stav ošetřit. Takže vezmeme prostřední body těchto rádoby čtverců, spočítáme aritmetický průměr výšky okolních třech bodů, modifikujeme výšku nějakou náhodnou hodnotou a výsledek uložíme. Stav ukazuje následující obrázek:

Vidíme tedy, že jsme z jednoho čtverce výškové mapy vygenerovali čtyři další, jinak řečeno, zdvojnásobili jsme rozlišení výškové mapy dvakrát. Při další iteraci vše probíhá podobně pro všechny čtyři nově vygenerované čtverce. Nejprve generujeme prostřední body:

A ve druhém kroku opět pootočíme hlavu o 45 stupňů, ale tentokrát už mnoha čtvercům nechybí druhá polovina. Vygenerujeme tedy opět prostřední body:

Tímto rekurzivním způsobem pokračujeme, až je celá výšková mapa vyplněna hodnotami.

Máme-li výškovou mapu, potřebujeme z ní zkonstruovat zobrazitelný graf scény. To provádíme ve funkci createModel(). Nejprve naplníme nód SoCoordinate3 souřadnicemi bodů. Místo slova bod budeme používat odbornější výraz v počítačové grafice: vertex (a množné číslo: vertices). Pro každou dlaždici v krajině vygenerujeme vždy všechny čtyři rohové body – levý spodní, pravý spodní, levý horní a pravý horní, přičemž pořadí vrcholů má svůj význam. Následující SoTriangleStripSet pak vše zobrazí. Hodnota čtyři v jeho fieldu numVertices říká, že každá dlaždice terénu je triangle strip složený ze čtyřech vertexů, což odpovídá dvěma vyrendrovaným trojúhelníkům.

Nebudeme si uvádět kód, neboť je velmi jednoduchý. Místo toho si ukážeme výsledný screen shot. Jen upozorňuji – nelekněte se. Výsledek se může zdát jako velmi „bídný“.

A vcelku oprávněně se ptáme: Proč naše vylepšená krajina vypadá mnohem hůře než v minulém příkladu? Důvod je v normálách a v použití SoTriangleStripSet místo SoQuadMesh. Celý vizuální nedostatek spravíme a ještě dalece předčíme původní výsledek v dalším pokračování.

Teď ale k důvodu: Při osvětlování krajiny potřebuje znát OpenGL normály povrchu. My jsme nikde třídu SoNormal nepoužili, a proto nejsou normály specifikované. Ale aby celé rendrování neskončilo fiaskem, vychází nám Open Inventor vstříc a vygeneruje normály za nás. To je vcelku triviální věc pro SoQuadMesh, kde na mřížce známe sousední vrcholy pro každý bod, a tak je vizuální výsledek perfektní. SoTriangleStripSet ale reprezentuje obecnou síť trojúhelníků, proto se normály nepodařilo tak dobře vygenerovat a výsledek je „bídný“. Můžeme však být vděční i za to, neboť bez normál by to dopadlo ještě mnohem hůře.

Tímto dnes končíme tento příklad, abychom mohli příště navázat a podstatně vylepšit vizuální výsledek naší aplikace.

Závěr

Dnes jsme se zabořili do problematiky vytváření virtuální krajiny. Ukázali jsme si, jak vyrendrovat výškovou mapu a jak ji vygenerovat midpoint algoritmem. Příště jej budeme nejen vylepšovat, aby byl použitelný v nějaké hře, ale ukážeme si i druhý algoritmus – fault formation – a porovnáme charaktery obou vygenerovaných krajin.

Našli jste v článku chybu?

26. 5. 2004 11:16

PCJohn (neregistrovaný)

Tak výsledek další analýzy:
- na VC6 to vubec neotevírá konzoli, to znamená, že .NET asi není plně zpětně kompatibilní (ale na to jsme si už u MS skoro zvykli)
- bylo by dobre spojit se mailem a spolecne bychom to zkusili najit chybu (v diskuznim foru email nebyl), pro zacatek by se dalo zkusit nahradit v Main-Windows.cpp radek
#pragma comment(linker, "/entry:\"mainCRTStartup\"") za
#pragma comment(linker, "/subsystem"windows\" /entry"mainCRTStartup\"")
Vysledek prosim na muj mail.





19. 5. 2004 21:18

Honza (neregistrovaný)

No vypada to fakt suprove, tak sem si to nainstaloval, ale dela mi to divnou vec. Mam Win2000 a kdyz jakykoliv Example ukoncim, tak mi po nem zustane otevrena konzole, ktera nejde ukoncit. To same to dela v MSVC .NET 2003, kde aplikaci ukoncim ale zustane porad spustena. Ukonci ji az zastaveni debugeru...Nevite nekdo co s tim. Rady jako "smaz Win a instni Linux neberu". Linux mam taky.

Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: Česká televize mění schéma ČT :D

Česká televize mění schéma ČT :D

Podnikatel.cz: Prodává přes internet. Kdy platí zdravotko?

Prodává přes internet. Kdy platí zdravotko?

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí

Lupa.cz: Není sleva jako sleva. Jak obchodům nenaletět?

Není sleva jako sleva. Jak obchodům nenaletět?

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

Vitalia.cz: Tesco: Chudá rodina si koupí levné polské kuře

Tesco: Chudá rodina si koupí levné polské kuře

Vitalia.cz: Baletky propagují zdravotní superpostel

Baletky propagují zdravotní superpostel

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

Vitalia.cz: Chtějí si léčit kvasinky. Lék je jen v Německu

Chtějí si léčit kvasinky. Lék je jen v Německu

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

120na80.cz: Jak oddálit Alzheimera?

Jak oddálit Alzheimera?

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET