2016-07-23 7 views
1

Ich versuche, Geländekollision für meine Höhenkarte Terrain zu implementieren, und ich werde this folgen. Das Tutorial ist für Java, aber ich benutze C++, obwohl die Prinzipien die gleichen sind, so sollte es kein Problem sein.Geländekollision Probleme

Zu Beginn benötigen wir eine Funktion, um die Höhe des Geländes anhand der Kameraposition zu ermitteln. WorldX und WorldZ ist die Position der Kamera (x, z) und die Höhe ist ein 2D-Array, das alle Höhen der Ecken enthält.

float HeightMap::getHeightOfTerrain(float worldX, float worldZ, float heights[][256]) 
{ 
    //Image is (256 x 256) 
    float gridLength = 256; 
    float terrainLength = 256; 

    float terrainX = worldX; 
    float terrainZ = worldZ; 
    float gridSquareLength = terrainLength/((float)gridLength - 1); 
    int gridX = (int)std::floor(terrainX/gridSquareLength); 
    int gridZ = (int)std::floor(terrainZ/gridSquareLength); 

    //Check if position is on the terrain 
    if (gridX >= gridLength - 1 || gridZ >= gridLength - 1 || gridX < 0 || gridZ < 0) 
    { 
     return 0; 
    } 

    //Find out where the player is on the grid square 
    float xCoord = std::fmod(terrainX, gridSquareLength)/gridSquareLength; 
    float zCoord = std::fmod(terrainZ, gridSquareLength)/gridSquareLength; 
    float answer = 0.0; 

    //Top triangle of a square else the bottom 
    if (xCoord <= (1 - zCoord)) 
    { 
     answer = barryCentric(glm::vec3(0, heights[gridX][gridZ], 0), 
     glm::vec3(1, heights[gridX + 1][gridZ], 0), glm::vec3(0, heights[gridX][gridZ + 1], 1), 
     glm::vec2(xCoord, zCoord)); 
    } 

    else 
    { 
     answer = barryCentric(glm::vec3(1, heights[gridX + 1][gridZ], 0), 
     glm::vec3(1, heights[gridX + 1][gridZ + 1], 1), glm::vec3(0, heights[gridX][gridZ + 1], 1), 
     glm::vec2(xCoord, zCoord)); 
    } 

    return answer; 
} 

Um die Höhe des Dreiecks finden die Kamera aktuell wir Funktion die baryzentrische Interpolation steht.

float HeightMap::barryCentric(glm::vec3 p1, glm::vec3 p2, glm::vec3 p3, glm::vec2 pos) 
{ 
    float det = (p2.z - p3.z) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.z - p3.z); 
    float l1 = ((p2.z - p3.z) * (pos.x - p3.x) + (p3.x - p2.x) * (pos.y - p3.z))/det; 
    float l2 = ((p3.z - p1.z) * (pos.x - p3.x) + (p1.x - p3.x) * (pos.y - p3.z))/det; 
    float l3 = 1.0f - l1 - l2; 
    return l1 * p1.y + l2 * p2.y + l3 * p3.y; 
} 

Dann müssen wir nur die Höhe verwenden wir berechnet haben für Kollision während des Spiels

float terrainHeight = heightMap.getHeightOfTerrain(camera.Position.x, camera.Position.z, heights); 
    if (camera.Position.y < terrainHeight) 
    { 
     camera.Position.y = terrainHeight; 
    }; 

nun nach dem Tutorial zu überprüfen, sollte dies völlig in Ordnung arbeiten, aber die Höhe ist eher ab und an manchen Orten funktioniert es nicht einmal. Habe ich es etwas haben könnte, mit der Übersetzung und Skalierung Teil des Geländes

glm::mat4 model; 
    model = glm::translate(model, glm::vec3(0.0f, -0.3f, -15.0f)); 
    model = glm::scale(model, glm::vec3(0.1f, 0.1f, 0.1f)); 

und dass ich um 0,1 die Werte der Höhen-Array multiplizieren sollte zu tun, da die Skalierung für das Gelände, dass ein Teil tut auf der GPU Seite, aber das hat den Trick nicht gemacht.

Hinweis

Im Tutorial die ersten Zeilen in der getHeightOfTerrain Funktion sagen

float terrainX = worldX - x; 
float terrainZ = worldZ - z; 

wobei x und z die Weltposition des Geländes ist. Dies wird getan, um die Spielerposition relativ zur Position des Geländes zu erhalten. Ich habe versucht mit den Werten aus dem Übersetzungsteil, aber es funktioniert auch nicht. Ich habe diese Zeilen geändert, weil es nicht notwendig erscheint.

Antwort

1
float terrainX = worldX - x; 
float terrainZ = worldZ - z; 

Diese Linien sind in der Tat sehr notwendig, es sei denn, Ihr Gelände ist immer am Ursprung.

Ihre Code-Ressource (Tutorial) geht davon aus, dass Sie das Terrain in keiner Weise skaliert oder gedreht haben. Die Variablen x und z sind die XZ-Position des Geländes, die sich um Fälle kümmern, in denen das Gelände übersetzt wird.

Idealerweise sollten Sie die Welt Positionsvektor von Weltraumtransformation Raum zum Objekt (unter Verwendung der Inverse der model Matrix Sie für das Gelände verwenden), so etwas wie

vec3 localPosition = inverse(model) * vec4(worldPosition, 1) 

Und dann verwenden localPosition.x und localPosition.z statt von terrainX und terrainZ.

+0

Ich sehe, jetzt weiß ich nicht, ob das albern klingt, aber wie könnte ich den Weltpositionsvektor finden, da ich nur einen Übersetzungsvektor habe, der die lokale Raumposition ausgleicht, aber ich kenne die lokale Raumposition nicht weil es für jede Ecke anders ist und die GPU jede Ecke einzeln mit diesem Übersetzungsvektor ausgleicht?Wenn du verstehst, was ich meine? @Evil Tak – Riggs

+0

Sie benötigen nur die Welt-Raumposition der unteren linken Ecke (vorausgesetzt, die X-, Y- und Z-Achsen zeigen nach rechts, oben bzw. nach vorne) des Geländes. – EvilTak

+0

Welches gefunden werden könnte, indem der erste Index des Vektors mit allen Scheitelpunkten überprüft und dann übersetzt wird: (0.0, 0.89, 0.0) + (0.0, -0.3, -15.0) = (0.0, 0.59, -15.0)? (Wenn ich keine Skalierung mache) @Evil Tak – Riggs