Generování terénu

3. díl - Generování terénu

Tomáš Herceg       20.02.2008       VB.NET, XNA, Algoritmy       13900 zobrazení

V minulém díle jsme si vysvětlili základy 3D zobrazení, takže dnes si ukážeme, jak vytvořit v XNA pěkně vypadající terén. Přitom si názorně vysvětlíme a povíme, co je to vertex buffer a index buffer.

V minulých dvou dílech jsme se postupně seznámili s XNA a základy 3D. Dnes si naše znalosti prohloubíme a ukážeme si, jak je vlastně takový 3D model reprezentován uvnitř. Vysvětlíme si, co je to vertex buffer a index buffer a pak si v praxi napíšeme třídu Landscape, která bude umět vykreslit obdélníkovou část terénu s horami a vrcholky.

Základem všeho není kruh, ale trojúhelník

V jednom českém seriálu (už si nevzpomínám na název) se tvrdilo, že základem všeho je kruh. Pokud jde o 3D grafiku tak, jak ji známe dnes, rozhodně toto tvrzení neplatí. Jistě jste si v mnoha hrách všimli, že některé objekty, které by měly být kulaté, kulatými rozhodně nejsou (například kola aut ve starších hrách vypadají jako mnohostěny, jsou zkrátka hranaté).

Prakticky ve všech implementacích počítačové 3D grafiky se vychází z toho, že každý trojrozměrný objekt můžeme rozložit na spoustu trojúhelníků. Je jasné, že to nikdy nebude naprosto přesné zobrazení, i kdyby trojúhelníčků bylo strašně moc, ale zkreslení a nepřesnosti nejsou tak velké, takže to nevadí. Když se podíváte na grafiku dnešních her, jistě je jasné, že to funguje, grafika vypadá velmi realisticky a když se objekty rozloží na optimální počet trojúhelníků (aby jich nebylo málo, protože pak to je hranaté, ale nesmí jich být zase moc, aby to stihla grafická karta vykreslit), výsledek vypadá dobře. Grafické karty samozřejmě počítají s tím, že vše se vykresluje pomocí trojúhelníků, jsou přesně pro tento způsob navrženy a zoptimalizovány.

 Terén rozložený na trojúhelníčky

Na tomto obrázku vidíte to, čeho se dnes budeme snažit dosáhnout. Zvrásněný terén rozložíme na mnoho trojúhelníčků a pak necháme grafickou kartu, aby nám je vykreslila. Jednorožec z minulého dílu byl také poskládán z trojúhelníčků, ty se akorát "vybarvily" nějakou texturou, aby to vypadalo realisticky.

Výšková mapa - heightmap

V souvislosti s terénem se používá často zažitý termín heightmap, česky bychom asi řekli výšková mapa. Je to obrázek, který popisuje "nadmořskou" výšku určité části terénu. Výšková mapa vypadá nějak takhle, čím světlejší je barva na daném místě, tím větší je v tomto terénu nadmořská výška:

Výšková mapa

Všimněte si, že terén zobrazený nahoře odpovídá přesně této výškové mapě - světlá místa jsou vyzvednutá.

Sestavujeme trojúhelníky

Nyní si tedy naši oblast terénu můžeme rozložit na čtvercovou síť, která bude mít stejně sloupců, jako je šířka obrázku v pixelech, a stejně řádků, jako je výška naší mapy. Pak ke každému bodu, kde se protíná vodorovná čára se svislou, můžeme podle světlosti příslušného pixelu zjistit jeho výšku (nemusí to být nadmořská výška, je na nás, jak si ji budeme interpretovat). Pak již není problém určit přesně souřadnice každého bodu mřížky v 3D prostoru.

Vytvoření 3D souřadnic

Výšku nad povrchem máme v souřadnici Y, takže zelené výšky bodů přihodíme mezi původní souřadnice X,Y bodů v mřížce. Tím dostaneme souřadnice X,Y,Z těchto bodů v 3D prostoru. Nyní musíme tyto vrcholy seskupit po trojicích tak, aby nám vznikly požadované trojúhelníky. Jak to uděláme? Použijeme tzv. vertex buffer, což je vlastně seznam vrcholů. Stačí, když stanovíme, že prvky 0, 1 a 2 tvoří první trojúhelník, prvky 3, 4, 5 jsou druhý atd.

Způsob vytvoření trojúhelníků

Jak tedy nějak systematicky vytvořit seznam trojúhelníků? Tak třeba každý čtverec rozdělíme na 2 trojúhelníky podle obrázku a trojúhelníky do bufferu zapíšeme podle jejich čísel. Jako první vrchol vždy vezmene levý horní a dále postupujeme po směru hodinových ručiček. Naše malá mřížka z obrázku by vypadala nějak takto (na každém řádku je jeden trojúhelník):

 [0,3,0], [1,4,0], [1,4,1]
[0,3,0], [1,4,1], [0,4,1]
[1,4,0], [2,5,0], [2,5,1]
[1,4,0], [2,5,1], [1,4,1]
[0,4,1], [1,4,1], [1,5,2]
[0,4,1], [1,5,2], [0,4,2]
[1,4,1], [2,5,1], [2,5,2]
[1,4,1], [2,5,2], [1,5,2]

Má to ale jeden háček - data se nám často opakují. Pokud bychom chtěli změnit výšku jednoho vrcholu, musíme ji změnit na více místech. Vertex buffer bude zbytečně velký, protože každý vrchol je tam několikrát. U vrcholů si nemusíme navíc pamatovat jen jejich pozice, ale třeba navíc jejich barvu či souřadnice mapování textur (o tom později). Celý buffer by tedy mohl zabírat zbytečně moc místa.

Proto v praxi používáme ještě tzv. index buffer. Funguje to jednoduše, vrcholy si nějak očíslujeme a do vertex bufferu uložíme pouze jejich seznam (kde je každý jen jednou). A do index bufferu uložíme trojúhelníky, ale místo celých dat vrcholu tam uložíme jen jeho pořadí ve vertex bufferu.

Očíslování vrcholů

Index buffer by tedy při pořadí vrcholů ve vertex bufferu na obrázku vypadal nějak takto:

 0, 1, 4
0, 4, 3
1, 2, 5
1, 5, 4
3, 4, 7
3, 7, 6
4, 5, 8
4, 8, 7

Já jsem zde sice jak vertex buffer, tak i index buffer vypsal na několik řádků, abychom mohli vidět jednotlivé trojúhelníky, ale v praxi se vše zapíše za sebe, oba dva buffery jsou vlastně jednorozměrná pole.

A na závěr ještě jedna věc - máme mřížku širokou W vrcholů a vysokou H vrcholů. Zajímá nás, kolik bude celkem vrcholů, kolik trojúhelníků a kolik bude položek v index bufferu.

  1. Počet vrcholů je jasný, pokud je šířka W a výška H, pak vrcholů bude W * H.
  2. Počet trojúhelníků je o něco zajímavější. Když se podíváme na to jak trojúhelníky tvoříme, tak v každém vrcholu začínají dva trojúhelníky. Výjimkou jsou vrcholy v posledním sloupci a posledním řádku, tam žádné trojúhelníky nezačínají. Vrcholů, ve kterých trojúhelníky začínají, je tedy (W - 1) * (H - 1), a z každého vrcholu máme 2 trojúhelníky. Takže v mřížce W x H je (W - 1) * (H - 1) * 2 trojúhelníků.
  3. A počet položek v index bufferu je již jednoduchý. Musíme v něm uvést všechny trojúhelníky (víme, kolik jich je, z předchozího bodu) a každý trojúhelník má 3 vrcholy, což jsou 3 položky. Dohromady je tedy (W - 1) * (H - 1) * 6 položek index bufferu.

Pokud jste následující výpočty nepochopili, zkuste si znovu přečíst způsob, jakým trojúhelníky sestavujeme, pořádně si prostudujte uvedené výčty hodnot, které bychom dávali do bufferů, a zkuste si je ukazovat na obrázku. Nebo si to zkuste nakreslit.

Nyní tedy již chápeme princip, jak rozložit terén na trojúhelníky. Pojďme to nyní naprogramovat.

Začínáme

Vytvořte si nový projekt Windows Game z naší šablony a pravým tlačítkem klikněte v podokně Solution Explorer na název projektu a vyberte položku Add / Class podle obrázku.

Přidání třídy do projektu

Třídu pojmenujte Landscape.vb a přidejte do ní tyto deklarace:

     Private heights(,) As Single                    ' výšky terénu v jednotlivých vrcholech
Private verticesCount, indicesCount As Integer ' počty vertexů a indexů
Private width, height As Integer ' šířka a výška oblasti

Private device As GraphicsDevice ' odkaz na objekt GraphicsDevice
Private vb As VertexBuffer, ib As IndexBuffer ' vertex a index buffer
Private effect As BasicEffect ' výchozí efekt

Public Sub New(ByVal graphics As GraphicsDevice)
'schovat si objekt GraphicsDevice
device = graphics

'připravit efekt
effect = New BasicEffect(device, Nothing)
End Sub

heights je dvourozměrné pole, které udává výšky jednotlivých bodů mřížky. Ty načteme z předané heightmapy a podle nich pak určíme 3D souřadnice jednotlivých vertexů. Proměnné verticesCount a indicesCount budou obsahovat počty vertexů a indexů, proměnné width a height budou obsahovat šířku a výšku mřížky.

device reprezentuje objekt GraphicsDevice (grafická karta), který dostane naše třída v konstruktoru a protože jej bude používat často, uloží si jej k sobě, abychom jej nemuseli předávat při každém volání jakékoliv metody. Proměnné vb a ib budou reprezentovat vertex buffer, respektive index buffer a uvnitř proměnné effect bude efekt, který budeme potřebovat k renderování terénu.

Jako malou odbočku trochu angličtiny: vertex = vrchol, množné číslo od vertex je vertices. index = pořadí, množné číslo od index je indices. Proto máme vertex buffer, ale proměnnou verticesCount (počet vrcholů) a indicesCount (počet indexů).

Dále jsme do třídy přidali konstruktor, který uloží odkaz na předaný objekt GraphicsDevice, který budeme potřebovat, a dále nám zinicializuje náš BasicEffect, o tom ale až později.

Načtení výšek z heightmapy

Možná si říkáte, jestli byste tohle nezvládli sami. Já myslím, že ano - znáte namespace System.Drawing (tedy alespoň doufám, pokud ne, naučte se alespoň základy, než se pustíte do 3D). Stačilo by tedy načíst obrázek pomocí metody Image.FromFile, uložit jej do objektu Bitmap a pomocí GetPixel získat barvy jednotlivých pixelů. Má to ovšem dva problémy - zaprvé metoda GetPixel je poměrně pomalá a zmapování velkého obrázku by trvalo dlouho (jsou sice postupy, jak bitmapu "odemknout" a přes Marshal.Copy z ní vytáhnout přímo pole bajtů s hodnotami jednotlivých barevných složek, ale to je jiná kapitola) a zadruhé pokud bychom chtěli spustit naši hru na konzoli XBox 360 (což sice z VB.NET nemůžeme, ale pokud píšete v C#, tak pokud do tohoto jazyka přeložíte kód z těchto článků, bude vám fungovat naprosto stejně), tak by to nefungovalo, protože XBox nemá mimo jiné knihovnu System.Drawing.

Použijeme tedy jiný postup, takový, který umí přímo XNA. Dovnitř naší třídy přidáme metodu LoadContent, které předáme texturu s výškovou mapou a koeficient, kterým určíme, jak moc se má světlost pixelu projevit na výšce terénu. Do třídy Landscape tedy přidejte tuto metodu:

     Public Sub LoadTerrain(ByVal tex As Texture2D, ByVal heightScale As Double)
' zjistit rozměry terénu
width = tex.Width : height = tex.Height
ReDim heights(width - 1, height - 1)

' získat jednotlivé pixely textury
Dim b(Width * Height - 1) As Color
tex.GetData(
Of Color)(b)

' zjistit výšky v jednotlivých bodech
For y As Integer = 0 To Height - 1
For x As Integer = 0 To Width - 1
With b(x + y * Width)
heights(x, y) = heightScale / 255 * (
CDbl(.R) + CDbl(.G) + CDbl(.B)) / 3
End With
Next
Next

' připravit vertex a index buffer
PrepareVertexBuffer()
PrepareIndexBuffer()
End Sub

Nejprve podle šířky a výšky textury nastavíme naše proměnné width a height, které jsme si v této třídě nadeklarovali. Dále pak nastavíme rozměry pole heights na příslušné velikosti - první rozměr bude od 0 do width - 1, druhý bude od 0 do height - 1.

Na dalších dvou řádcích si vytvoříme pole b typu Color od 0 do width * height - 1 a na dalším řádku do tohoto pole nahrajeme metodou GetData po všechny pixely textury po řádcích zleva doprava a odshora dolů.

Dále následují dva cykly v sobě, které nedělají nic jiného, než že nám procházejí po řádcích pole heights. With blok pracuje s výrazem b(x + y * width), což je vlastně pixel v textuře na pozici x, y (pole je ale jednorozměrné, takže musíme pozici pixelu spočítat - pozice na y-tém řádku v textuře je x a před tímto řádkem bylo ještě celých y řádků, kde každý měl width položek). Převod ze souřadnic ve dvojrozměrném poli na index v jednorozměrném poli je patrný z obrázku (jen je nutno říci, že souřadnice musí být číslovány od nuly, což my ale máme !)

 image

Do pole heights(x, y) uložíme výslednou výšku daného bodu, kterou spočítáme takto: (CDbl(.R) + CDbl(.G) + CDbl(.B)) / 3 je aritmetický průměr z hodnot červené, zelené a modré složky našeho pixelu. Musíme použít CDbl, protože operátor + mezi dvěma hodnotami typu Byte předpokládá výsledek také typu Byte a třeba číslo 400 se do bajtu už nevejde, přestože vznikout součtem dvou bajtů může. Proto tedy hodnoty převedeme na Double, sečteme a vydělíme třemi. Vzhledem k tomu, že hodnoty jednotlivých barevných složek jsou v rozsahu od 0 do 255, vydělíme náš spočítaný průměr (který je také z tohoto rozsahu) číslem 255, abychom získali hodnoty od 0 do 1. Ty pak vynásobíme naším parametrem heightScale, který udává výšku nejvyššího možného bodu - pokud tato hodnota bude třeba 5, náš terén bude mít Y souřadnici (výšku) v rozsahu od 0 do 5.

Nakonec naše metoda zavolá metody PrepareVertexBuffer a PrepareIndexBuffer, které nyní napíšeme, takže se nelekejte, že vám Visual Studio vyhazuje chybu.

Vytvoření a naplnění VertexBufferu

Do naší třídy přidejte tuto metodu, která nám připraví VertexBuffer.

     Private Sub PrepareVertexBuffer()
' nastavit vertex buffer
verticesCount = width * height
vb =
New VertexBuffer(device, GetType(VertexPositionTexture), verticesCount, BufferUsage.WriteOnly)

' vytvořit pole vertexů
Dim verts(verticesCount - 1) As VertexPositionTexture
For y As Integer = 0 To height - 1
For x As Integer = 0 To width - 1
With verts(x + y * width)
.Position =
New Vector3(x, heights(x, y), y)
End With
Next
Next

' nahrát vertexy do bufferu
vb.SetData(Of VertexPositionTexture)(verts)
End Sub

V první části nastavíme do proměnné verticesCount počet vertexů a na dalším řádku vytvoříme nový objekt VertexBuffer. Musíme mu předat objekt GraphicsDevice (grafickou kartu) a typ VertexPositionTexture, aby karta věděla, jaké informace budou naše vertexy obsahovat (v tomto případě pozici a mapování textury, to je až pro příští díl). Dále předáváme počet vertexů a nakonec říkáme, že do bufferu budeme jen zapisovat, takže jej XNA může nahrát přímo do paměti grafické karty, aby se s ním rychleji pracovalo.

Ve druhé části musíme připravit data, která do tohoto bufferu "nalijeme". Vytvoříme si tedy jednorozměrné pole všech vertexů (typu VertexPositionTexture; typů vertexů je více, můžeme si dokonce vytvořit vlastní) a v cyklu nastavíme jednotlivým prvkům správnou pozici. Souřadnice x a y, které máme k dispozici uvnitř cyklů, budou souřadnicemi x a z našeho vrcholu (x je v prostoru zleva doprava a z je zezadu dopředu). Jako souřadnici y vertexu dáme výšku, kterou máme již spočítanou v poli heights na pozici x, y. To je vše.

Jako poslední musíme naše pole "natlačit" do bufferu, k čemuž použijeme metodu SetData a ještě jednou jí zopakujeme, jakého typu data jsou (to ne, že by měla třída VertexBuffer sklerózu; je to opět napsáno genericky, typ píšeme, aby kompilátor věděl, jaký datový typ má v parametru očekávat a nemuselo se pořád přetypovávat z obecného typu Object). Tím je náš vertex buffer připraven, to byla ovšem ta jednodušší část.

Vytvoření a naplnění IndexBufferu

Metoda pro přípravu IndexBufferu bude podobná, akorát uvnitř cyklu to bude drobátko hnusnější. Kód této metody je zde:

     Private Sub PrepareIndexBuffer()
' nastavit index buffer
indicesCount = (width - 1) * (height - 1) * 6
ib =
New IndexBuffer(device, GetType(Integer), indicesCount, BufferUsage.WriteOnly)

' vytvořit pole indexů
Dim indices(indicesCount - 1) As Integer
Dim k As Integer = 0
For y As Integer = 0 To height - 2
For x As Integer = 0 To width - 2
Dim b As Integer = x + y * width
indices(k) = b
indices(k + 1) = b + 1
indices(k + 2) = b + 1 + width
indices(k + 3) = b
indices(k + 4) = b + 1 + width
indices(k + 5) = b + width
k += 6
Next
Next

' nahrát indexy do bufferu
ib.SetData(Of Integer)(indices)
End Sub

Nahoře opět spočítáme počet položek v bufferu a vytvoříme nový IndexBuffer. I tady mu jako minule předáme GraphicsDevice a oznámíme, že má čekat hodnoty typu Integer, že jich bude tolik a tolik a opět do něj budeme jen psát.

Před cyklem si vytvoříme opět jednorozměrné pole indexů potřebné velikosti a uděláme si proměnnou k, která si bude pamatovat, kolik položek již máme v poli indices zapsaných, abychom indexy pořád nemuseli vypočítávat ze souřadnic x a y. Všimněte si, že nám nyní cykly běží od 0 do height - 2, resp. width - 2, při vytváření trojúhelníků vynecháváme ten poslední řádek a sloupec, jak jsme si již vysvětlili výše, protože z vrcholů v posledním sloupci a řádku již žádné trojúhelníky vytvářet nebudeme.

Uvnitř cyklu si v každém kroku uložíme do proměnné b index levého horního vrcholu, kde naše dva trojúhelníky budou začínat. Do pole indices uložíme tedy indexy vrcholů našich dvou trojúhelníků. Pro jistotu zde máte obrázek, v jakém pořadí vrcholy trojúhelníků zadáváme:

Pořadí vrcholů v trojúhelnících

Jak vidíme v kódu, první a čtvrtý vrchol je b, tam trojúhelníky začínáme. Druhý vrchol je b + 1, je totiž hned vedle b. Třetí a pátý vrchol je b + 1 + width, je totiž o jednu vedle a o řádek níž (a řádek má width políček). Šestý vrchol ze skupiny je b + width, protože je o jeden řádek níž než b. Jakmile nastavíme příslušné indexy na příslušná místa, zvětšíme k o 6, abychom příští skupinu zapisovali na další políčka a nepřepsali si již spočítané indexy.

Jakmile jsme s touto "opičárnou" hotovi, můžeme stejně jako v předchozí metodě nahrát data do index bufferu a jsme hotovi. Teď přijde již jen vykreslování.

Vykreslení terénu

V konstruktoru třídy Landscape jsme zinicializovali objekt effect typu BasicEffect a já jsem zamlčel, na co jej přesně použijeme. V XNA nemůžeme vykreslovat ve 3D nic, pokud nemáme nastavený žádný efekt. Efektů je víc druhů, nám zatím bude stačit BasicEffect. Ten je mimo jiné zodpovědný za přepočítání souřadnic v 3D prostoru na souřadnice na obrazovce, kromě toho umí mapovat textury a pracovat se světly. Protože jsme ve 3D, musíme samozřejmě mít nachystané naše známé matice world, view a projection. Ty si necháme předat v parametru metody Draw, která se bude starat o vykreslování, a kterou teď napíšeme. Přidejte tedy tento kód do třídy Landscape:

     Public Sub Draw(ByVal world As Matrix, ByVal view As Matrix, ByVal proj As Matrix)
' nastavit projekční matice
effect.World = world
effect.View = view
effect.Projection = proj

' vykreslit jen mřížku
device.RenderState.FillMode = FillMode.WireFrame

' použít efekt na vykreslování
effect.Begin(SaveStateMode.None)
For Each pass As EffectPass In effect.CurrentTechnique.Passes ' všechny průchody
pass.Begin()

' nastavit formát vertexu
device.VertexDeclaration = New VertexDeclaration(device, VertexPositionTexture.VertexElements)
' nastavit vertex a index buffer
device.Vertices(0).SetSource(vb, 0, VertexPositionTexture.SizeInBytes)
device.Indices = ib
' vykreslit vertexy
device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, verticesCount, 0, indicesCount / 3)

pass.End()
Next
effect.End()
End Sub

Hned na začátku přiřadíme našemu efektu všechny tři matice, aby se nám terén zobrazil tak, jak má. Dále objektu grafické karty nastavíme RenderState.FillMode na hodnotu FillMode.WireFrame, čímž způsobíme, že se zobrazí jen trojúhelníková mřížka, přesně ta, kterou jste mohli vidět na začátku tohoto článku.

Pak již budeme vykreslovat, takže musíme nejprve připravit efekt. Vykreslovat ve 3D můžeme pouze mezi voláním effect.Begin a effect.End, stejně jako je to při vykreslování ve 2D. Každý efekt může mít více průchodů (náš efekt ne, ale chceme to napsat obecně, takže musíme počítat s tím, že jiný efekt víc průchodů mít může), v každém průchodu musíme vykreslit celou scénu. Vytvoříme tedy For Each cyklus a projdeme každý průchod pass typu EffectPass. Opět můžeme vykreslovat jen mezi voláními pass.Begin a pass.End, takže vykreslování musíme vložit dovnitř.

A nyní čtyři řádky uprostřed bohatě proložené komentáři, které mohou za celé vykreslení terénu. V prvním řádku grafické kartě oznámíme, jak že přesně vypadá náš vertex v bufferu (vytvoříme tedy nový objekt VertexDeclaration a předáme mu pole všech elementů, které v sobě obsahuje typ VertexPositionTexture). Dále musíme grafické kartě říci, který vertex buffer a index buffer má použít. Vertex bufferů může mít GraphicsDevice několik, takže na první z nich zavoláme SetSource a předáme náš vb, sdělíme navíc, že začíná od 0 a velikost jednoho vertexu je rovna hodnotě VertexPositionTexture.SizeInBytes). Nastavení index bufferu je již jednodušší, stačí jej přiřadit do vlastnosti Indices.

Poslední řádek je ten nejdůležitější, provede samotné vykreslení. DrawIndexedPrimitives vyžaduje typ geometrických obrazců (v našem případě TriangleList, seznam trojúhelníků), dále index prvního vertexu ve vertex bufferu a minimální index, pak následuje počet vertexů, index začátku v index bufferu a počet trojúhelníků (což je tedy indicesCount / 3).

A to je celá třída Landscape. Neumí toho zatím moc, pro pořádné použití ve hře ji budeme muset příště naučit spoustu dalších věcí, jako třeba otexturování (a možná i více různými texturami, na každém místě jinou, tedy tzv. multitexturing atd.), zjištění výšky v konkrétním bodě (s neceločíselnými souřadnicemi), protnutí přímky a terénu atd.

Použití třídy Lanscape

Třídu máme hotovou, ale když spustíte projekt, pochopitelně se nic nestane. Nevoláme totiž žádnou z jejích metod. Přepněte se tedy nyní do třídy Game a do deklarací přidejte tyto čtyři řádky (vysvětlovat je již nebudu, 3 znáte z minula a čtvrtý je jasný).

     Private land As Landscape       ' náš terén

Private world As Matrix = Matrix.Identity
Private view As Matrix = Matrix.CreateLookAt(New Vector3(32, 80, 64), New Vector3(32, 0, 32), Vector3.Up)
Private proj As Matrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, 4 / 3, 1, 1000)

Stáhněte a uložte si tuto výškovou mapu (pravým tlačítkem na ni klikněte a zvolte Uložit obrázek jako). Pak ji přidejte do projektu do složky Content.

Výšková mapa - stáhněte ji a přidejte do projektu

Dovnitř metody LoadContent v třídě Game přidejte tyto dva řádky - zinicializujeme náš Landscape a nahrajeme do něj naši výškovou mapu (načtenou jako Texture2D):

         land = New Landscape(Me.GraphicsDevice)
land.LoadTerrain(Content.Load(
Of Texture2D)("Content\heightmap"), 25)

A samotné vykreslení terénu je již jednoduché, měli byste jej být schopni vymyslet sami. Ale taková potvora nebudu, abych jej sem nenapsal, takže toto přidejte dovnitř metody Draw:

         land.Draw(world, view, proj)

A to je vše, v tomto díle video nebude, protože se nám nic nehýbe. Příště se podíváme na textury, aby náš terén vypadal skutečně a ne jako drátěný model.

 

hodnocení článku

0       Hodnotit mohou jen registrované uživatelé.

 

Všechny díly tohoto seriálu

6. Trocha matematiky pro 3D 11.07.2008
5. Klávesnice a myš v XNA 30.03.2008
4. Textury a světla v XNA 24.02.2008
3. Generování terénu 20.02.2008
2. Vykreslujeme 3D model v XNA 17.02.2008
1. Seznámení s XNA frameworkem 14.02.2008

 

Mohlo by vás také zajímat

Tipy a triky pro ASP.NET - díl 5.: Komponenta pro zadávání data a času

V tomto díle se podíváme na to, jak s využitím komponenty CalendarExtender z knihovny AjaxControlToolkit napsat komponentu pro snadné zadávání data, která podporuje validaci a datové zdroje.

Práce s časovými pásmy a letním časem v aplikaci a databázi - díl 1.: Úvod do časových pásem a letního času

Ve článku se snažím popsat úskalí, která přináší konverze času přes více časových pásem a pravidel pro počítání letního času.

Co je to .NET Framework 4.5?

V tomto článku se snažím nastínit rozdíl mezi .NET 4 a .NET 4.5 z pohledu zpětné kompatibility.

 

 

Nový příspěvek

 

Mr.

1'

csharp|

xml|

css|


'

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Generování terénu

Musim uznat, ze Vam ty clanky jdou pekne od ruky. Za tak malou chvili uz treti pokracovani. To je vykon.

nahlásit spamnahlásit spam 0 / 2 odpovědětodpovědět

Tyto tři články mám napsané již týden, ale publikoval jsem je postupně, abych čtenáře nezahltil a pak 14 dní nečekali na pokračování. Teď ale budu muset už nějaký další díl napsat, připraven již žádný nemám. Problémem je již opět jenom ten volný čas.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Na začátku (velmi podnětného) článku vzpomínáte seriál, kde základem všeho je kruh. Seriál se jmenuje Návštěvníci a stojí za shlédnutí ... už jen proto, že by bylo asi krásné převést Dádu do 3D ... XD

Jinak moc hezky jste to napsal ... jen tak dál

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Nefunkčnost v vb.net 2013

Dobrý den,

je nějaká šance, že by mi někdo mohl vysvětlit, jaký je rozdíl mezi verzí vs. 2010 a vs. 2013? (Myšleno v použití XNA). Zvládnu vykreslit 3D model, povedlo se mi kod upravit, ale jakmile začnu psát třídu Landscape, téměř nic nefunguje. Vs. píše že něco nezná, něco není součástí XNA...atd. Předem děkuji.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Generování terénu

Ahoj!

V řádku:

 ib = New IndexBuffer(device, GetType(Integer), indicesCount, BufferUsage.WriteOnly)

mi debug hlásí

"InvalidOperationException was unhandled" s poznámkou:

"This device does not support 32-bit indices. Use IndexElementSize.SixteenBits or a type that has a size of two bytes." Nemohu se toho zbavit. Poradí mi, prosím, někdo? (VB Express 2008)

nahlásit spamnahlásit spam 0 / 2 odpovědětodpovědět

Jo, s tím jsem se už taky náhodou setkal. Některé slabší (většinou integrované) grafické karty neumí 32bitové indexy. Musíte indexy v IndexBufferu změnit z datového typu Integer na Short. To bude fungovat všude.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Generování terénu

device.DrawIndexedPrimitives(PrimitiveType.TriangleList, 0, 0, verticesCount, 0, indicesCount / 3)

Právě při spuštení mi píše že indicesCount je a nemá být nula. mám visual studio 2008 a Windows vista Bussines.

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

uz to funguje

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Generování terénu

chybí mi odkaz na stažení

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět

Diskuse: Generování terénu

Měl bych dotaz ohledně exportu tohoto vytvořeného terénu do formátu pro 3Ds max 7. Je to možné to nějak vyexportovat? Nevěděl by ste někdo nějaké odkazy?

nahlásit spamnahlásit spam -1 / 1 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback