Game Engine Math

KWEngine, Teil 18: Unebenes Terrain

Ein Terrain-Modell ist ein 3D-Modell wie jedes andere. Man muss es aber zunächst generieren lassen. Dazu braucht man eine Height-Map.

Beispiel für eine Height-Map (128×128 Pixel)

Eine Height-Map ist ein Graustufenbild, in dem die hellen Pixel die Höhe des Terrains angeben. Dunkle Pixel bedeuten hingegen, dass das Terrain an diesen Stellen wenig oder gar keine Höhe aufweist.

Das Terrain-Modell sollte zu Beginn der Prepare()-Methode der gewünschten Welt-Klasse generiert werden:

public override void Prepare()
{
    KWEngine.BuildTerrainModel(
                "MyTerrainName",        // Name, unter dem das Terrain-Modell in der Engine verfügbar sein soll
                "./heightmap.png",      // Name der Height-Map-Datei (Schwarzweiß-Bild als jpg/png) 
                 5                      // Höchster Punkt des Terrains (z.B. 5m über dem Meeresspiegel)
                );
}

Breite und Höhe des Terrains richten sich exakt nach der Auflösung in der Height-Map-Textur. Hat die Textur eine Auflösung von z.B. 256 x 128 Pixeln, ist auch das Terrain 256 Einheiten breit und 128 Einheiten tief.

Legen Sie nun ein Objekt der Klasse TerrainObject in der Prepare()-Methode der Welt-Klasse an:

// Erzeuge Objekt der Klasse Terrain und nenne es t:
TerrainObject t = new TerrainObject("MyTerrainName");

// Optional: Markiere das Objekt als Kollisionsobjekt und als schattenwerfend
t.IsCollisionObject = true; 
t.IsShadowCaster = true;

// Optional: Textur und deren Wiederholungen setzen
t.SetTexture("./myTexture.jpg");
t.SetTextureRepeat(5f, 5f);

AddTerrainObject(t);

Einschränkungen

  • Ein Terrain kann je Dimension maximal 1024 Einheiten breit bzw. tief sein und muss mindestens 16 Einheiten breit sowie tief sein.
  • Sowohl Breite als auch Höhe der Height-Map-Textur muss durch 16 teilbar sein. Die maximale Auflösung der Height-Map beträgt 1024×1024 Pixel.
Beispiel für ein erzeugtes Terrain-Objekt mit Bodentextur

Auf Kollision mit Terrain prüfen

Die Kollisionsprüfung von GameObject-Instanzen in Verbindung mit TerrainObject-Instanzen ist eingeschränkt. Aktuell ist es nicht möglich, die gesamte Hitbox einer GameObject-Instanz mit dem Terrain kollidieren zu lassen.

Aber:
GameObject-Instanzen können stattdessen mithilfe eines Strahlentests prüfen, wie weit sie vom Terrainboden entfernt sind. Dabei erhalten sie als Ergebnisse…

  • …den gemessenen Abstand zum Terrainboden (ausgehend vom Fuß der GameObject-Instanz),
  • den Schnittpunkt des Messstrahls mit dem Terrainboden und
  • den Ebenenvektor des Terrainbodens an diesem Schnittpunkt.

Mithilfe dieser drei Informationen können GameObject-Instanzen entscheiden, wann sie tatsächlich auf dem Terrain „stehen“ oder eben nicht.

Es folgt ein Minimalbeispiel für eine „Ein-Punkt-Messung“:

using KWEngine3;
using KWEngine3.GameObjects;
using OpenTK.Mathematics;

class Player : GameObject
{
    public override void Act()
    {
        // Schieße einen Teststrahl von der angegebenen Position nach unten
        // und erhalte das Ergebnis dieses Tests in der Variable 'result':
        // (GetOBBBottom() berechnet dabei die untere Y-Position des Objekts)
        RayTerrainIntersection result = RaytraceTerrainBelowPosition(
            GetOBBBottom()
        );

        // Wenn der nach unten gerichtete Teststrahl einen Terrainboden 
        // getroffen hat, ist das Ergebnis "valide":
        if(result.IsValid)
        {
            // Ist die Distanz vom Start des Teststrahls zum gefundenen Boden
            // kleiner als z.B. 0,05 Meter, dann betrachte das Objekt als
            // 'nah genug' am Boden. 
            if (result.Distance < 0.05f)
            {
                // Das Objekt ist nah genug am Terrainboden, also wird es
                // in seiner Höhe auf die Höhe des Schnittpunkts gesetzt:
                SetPositionY(
                    result.IntersectionPoint.Y,     // Y-Koordinate des Schnittpunkts
                    PositionMode.BottomOfAABBHitbox // SetPositionY bezieht sich auf die Fußposition der Instanz
                );
            }
        }
    }
}


Beitrag veröffentlicht

in

von

Schlagwörter:

Kommentare

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

This site uses Akismet to reduce spam. Learn how your comment data is processed.