[EN/DE] Procedural Terrain - Behind the games (Part 1: Heightmaps)

in #technology7 years ago (edited)

[EN] Heightmaps


Introduction

Many modern games work with procedurally generated terrain. Some use it to make the game more dynamic, some use it to increase development speed. There are multiple ways to create these procedural (or "random") terrains, one of the easiest ones works by using heightmaps.


Heightmaps

Like the name says, a heightmap is used to store the height of our terrain. This is done by using the color value of a certain offset of a grayscale image. Unlike the more or less famous novel, an 8-Bit grayscale image can store up to 256 shades of grey. That means, every pixel defines a certain height from 0 to 256.

There is a nice page called terrain.party, which lets you transform any part of the world into a heightmap. So let's do this!

I've decided to use the island of Malta for our cause. So, how does the heightmap of Malta look like?

As we can see, all the parts with water are black, they have a height of 0. A completely white pixel (256) would represent the biggest height possible. How big that is depends on your implementation.

Note that you are technically not forced to use a grayscale image, you could also use the colour channels of an image. That way, you could also store a much bigger range of heights. Grayscale images are the ones most widely supported though, and you have the advantage of being able to kind of see how the 3D landscape will look like, when the heightmap is applied.

Talking about applying the heightmap, how does it look like in 3D?

Okay, let's face it: Malta-junior looks pretty ugly. But that's not the point of this post. As you can see, the black portion of the image now is a flat area, while the lighter ones form elevated terrain.

It is completely up to us, how we interpret this heightmap data. We could say that one heightmap value (0-256) is 50 meters high or 25 and so on.


Procedurally generated heightmaps

This is all pretty nice, but how do we get a randomly generated landscape now? This is where noise comes in. A widely used noise function is perlin-noise. Noise functions create a pseudo random noise, so you get a repeatable but random (when using a random seed) pattern. An easy way to quickly create such a heightmap is by using Gimp. We can use Gimps "Solid Noise" functionality (which is essentially using Perlin Noise), to create such a random heightmap. How does this look like?

Definitely wilder than our Malta-heightmap! As we can see, it looks quite random, but one is still able to make out some kind of pattern. This is exactly what we want for our terrain, completely random pixels would look rather weird.

Perlin-Noise is not the only noise function. Using different noise functions or by combining multiple noise functions (or by changing some parameters in your noise function), you can get totally different results.

How does our heightmap look like in 3D?

Looks quite nice! We could use special textures, to make our landscape look a bit more realistic, but that's a topic for a different series.


Sooo, we're done, right?

Nope! What if we want caves in our terrain? What if we want our terrain to be fully destructible? Destruction would work, but we could only represent one value per pixel. That means if we have two "layers" in our terrain (like a ladge), we couldn't save it.

We'll need a different solution! More on that in the next post! As always, if you have any questions, feel free to ask in the comments.


References

  1. terrain.party
  2. unagames.com/blog/erika/2010/05/how-make-nebula-few-steps-gimp

[DE] Heightmaps


Einführung

Viele moderne Spiele nutzen prozedural generiertes Terrain. Manche nutzen es, um das Spiel dynamischer zu gestalten, andere um die Entwicklungszeit zu verkürzen. Es gibt verschiedene Wege, um dieses prozedurale (oder "zufällige") Terrain zu erstellen. Einer der einfachsten besteht jedoch aus der Nutzung von Heightmaps.


Heightmaps

Wie der Name schon sagt, speichert eine Heightmap die Höhe von unserem Terrain. Dies geschieht, indem man einfach den Farbwert an dem jeweiligen Offset in einem Graustufen-Bild nutzt. Anders als in dem mehr oder weniger bekannten Roman kann ein 8-Bit Graustufen-Bild per Pixel 256 "shades of grey" speichern. Das bedeutet, dass jeder Pixel eine bestimmte Höhe von 0 bis 256 definiert.

Es gibt eine tolle Seite namens terrain.party, mit welcher man jeden Teil der Welt in eine Heightmap umwandeln kann. Probieren wir das mal!

Ich habe mir für unseren Versuch Malta ausgesucht. Also, wie sieht die Heightmap von Malta aus?

Wie wir sehen können sind alle Teile, die sonst mit Wasser bedeckt sind schwarz. Das heißt sie haben eine Höhe von 0. Ein komplett weißer Pixel (256) würde die größtmögliche Höhe darstellen. Wie groß das ist, hängt von unserer Implementierung ab.

Theoretisch könnten wir statt den Grauwerten auch Farbwerte für unsere Heightmap nutzen. So könnten wir viel mehr Höhenstufen speichern. Graustufenbilder werden allerdings besser unterstützt, und man hat den Vorteil, dass man ungefähr sehen kann, wie die Landschaft am Ende aussehen wird.

Wie sieht unsere Heightmap jetzt eigentlich in 3D aus?

Okay, Hand auf's Herz: Malta-junior sieht relativ hässlich aus. Das ist aber auch nicht der Sinn dieses Posts. Wie man sehen kann, ist der schwarze Teil des Bildes nun eine platte Fläche, während die helleren Teile erhöhtes Terrain formen.

Es hängt völlig von uns ab, wie wir diese Heightmap interpretieren. Wir könnten festlegen, dass ein Wert der Heightmap (0-256) 50 Meter hoch ist, oder auch 25 und so weiter.


Prozedural generierte Heightmaps

Das ist alles schon sehr schön, aber wie bekommen wir nun ein zufällig generiertes Terrain? Das ist der Punkt, an dem Rauschen ins Spiel kommt. Eine oft genutzte Rauschfunktion ist das Perlin-Rauschen (Perlin-Noise). Rauschfunktionen erzeugen ein pseudo-zufälliges Rauschen, das heißt man bekommt ein wiederholbares aber zufälliges (wenn man einen zufälligen Seed nutzt) Muster. Ein einfacher Weg um schnell eine solche Heightmap zu erstellen ist Gimps "Solid Noise" Funktion (welche im Prinzip Perlin-Noise benutzt). Wie sieht das Ergebnis aus?

Defintiv verrückter, als unsere Malta-Heightmap! Wie wir sehen können, sieht das Ganze ziemlich zufällig aus, aber man kann trotzdem ein gewisses Muster ausmachen. Das ist genau, was wir für unser Terrain vollen. Komplett zufällige Pixel würden am Ende recht obskur aussehen.

Perlin-Rauschen ist nicht die einzige Rauschfunktion. Durch die Nutzung bzw. die Kombination verschiedener Rauschfunktionen können wir viele Verschiedene Ergebnisse erzeugen.

Wie würde unsere neue Heightmap also in 3D aussehen?

Sieht doch schon ganz gut aus! Wir könnten nun eine spezielle Textur nutzen, um unsere Landschaft direkt etwas realistischer aussehen zu lassen, aber das ist ein Thema für einen anderen Post.


Das heißt wir sind durch, oder?

Nein! Was, wenn wir in unserem Terrain Höhlen haben wollen? Was, wenn wir unser Terrain vollständig zerstörbar (und speicherbar) machen wollen?

Wir brauchen eine andere Lösung! Mehr dazu im nächsten Post. Wie immer, wenn Fragen aufkommen können diese gerne in den Kommentaren gestellt werden.


Referenzen

  1. terrain.party
  2. unagames.com/blog/erika/2010/05/how-make-nebula-few-steps-gimp
Sort:  

Bin gespannt was noch kommt. Soweit so bekannt aus fast jedem Aufbau oder Wisim-Spiel :P Wie man Tunnel in einer 2D Heightmap unterbringen soll wüsste ich jetzt nicht, außer man nimmt Layer? Aber das wirst du ja zeigen.

Richtig, Heightmaps sind eine ziemlich bekannte Technik. Die Tunnel (u. Ä.) bringt man aber auch nicht in einer Heightmap unter, sondern in einer anderen Datenstruktur. Aber wie du schon sagtest, das zeige ich dann noch. Danke für's Lesen!

Hallo @biw,

danke für diese Simple Erklärung :-). Da ich schon seit vielen Jahren Spiele mit solch einer Form der Kartenerstellung spiele, hab ich mich schon oft gefragt, wie man so etwas geschickt implementieren kann. Ich bin bisher von einer Funktion ausgegangen, die mit Hilfe von 2 Koordinaten den dritten Punkt in der Höhe bestimmt, würde das auch gut gehen oder ist der Bedarf an Rechenleistung dort höher?

Hey! Diese Noise-Funktionen machen im Grunde nicht viel Anderes. Du bekommst zusammenhängende "z"-Werte für jede Koordinate in deinem Bild. Was du natürlich auch nutzen könntest wäre eine 3-Dimensionale Funktion (z.B f(x,y) = x2- y2). Da würdest du dann jeweils einzelne Werte von nehmen, um deinen Mesh zu generieren (dazu kommen wir noch). Das ist aber nicht wirklich flexibel, und du kannst dein Terrain später, solltest du es verändern, auch nicht wieder in Funktionsform abspeichern.

Außerdem kannst du Perlin-Noise und andere auch 3-Dimensional anwenden, wodurch du am Ende praktisch ein Skalarfeld bekommst (dh. jedem Punkt im Raum ist eine Zahl zugeordnet, in dem Fall 0, oder 1, was jeweils Luft oder Erde bedeuten würde). Dazu komme ich aber auch noch in einem späteren Post.

In jedem Fall vielen Dank für deinen Kommentar!

Danke für deine fixe Antwort, jetzt hast du meine Aufmerksamkeit gezogen.

Bin gespannt, wie das mit dem Mesh funktioniert, kann mir gerade gut vorstellen, dass du über die Funktion f(x,y) einzelne Punkte für die erste Festlegung des Geländes holst und anschließend die Zwischenpunkte interpolierst.

Mein follow haste bekommen :-D

Congratulations @biw! You received a personal award!

1 Year on Steemit

Click here to view your Board

Do not miss the last post from @steemitboard:

SteemitBoard - Witness Update

Support SteemitBoard's project! Vote for its witness and get one more award!

Congratulations @biw! You received a personal award!

Happy Birthday! - You are on the Steem blockchain for 2 years!

You can view your badges on your Steem Board and compare to others on the Steem Ranking

Vote for @Steemitboard as a witness to get one more award and increased upvotes!

Coin Marketplace

STEEM 0.27
TRX 0.20
JST 0.038
BTC 96715.05
ETH 3649.48
USDT 1.00
SBD 3.88