Search code examples
javaopenglcollisionsmoothingterrain

Smooth Terrain Collision - 3D


I would like to have smooth terrain collision in my game engine, when i say smooth I mean the player's height isn't determined by one vertex. I belive barycentric coordinates are the way to go. And I've spent a good 7 hours researching this, but none of the code I've seen actually works and it doesn't explain it in plain-english either.

This is all I have so far. :(

public float getHeightAt(float xPos, float zPos) {
        Vector3f one = new Vector3f((float)xPos, ((float)new Color(heightMap.getRGB((int)xPos, (int)zPos)).getRed())/255f*exaggeration*scale, (float)zPos);
        Vector3f two = new Vector3f((float)xPos+1, ((float)new Color(heightMap.getRGB((int)xPos+1, (int)zPos)).getRed())/255f*exaggeration*scale, (float)zPos);
        Vector3f three = new Vector3f((float)xPos, ((float)new Color(heightMap.getRGB((int)xPos, (int)zPos+1)).getRed())/255f*exaggeration*scale, (float)zPos+1);

        float height = mid(one, two, three, new Vector3f(xPos, 0f, zPos));
        System.out.println(height);
        return height + 0.25f;
    }

    private float mid(Vector3f a, Vector3f b, Vector3f c, Vector3f p) {
        Vector3f AB = a.mul(b);
        Vector3f BC = b.mul(c);

        Vector3f norm = AB.cross(BC);
        float n0 = norm.getX();
        float n1 = norm.getY();
        float n2 = norm.getZ();

        return (n0*a.getX() + n1*a.getY() + n2*a.getZ() - n0*p.getX() - n2*p.getZ()) / n1;
    }

It works but it isn't smooth and I don't even know ifit is barycentric.

Here is an example of what I want: https://www.youtube.com/watch?v=ngJ6ISfXG3I


Solution

  • To get the smoothed height, there are two main steps:

    I - Create a function to get the height from position

    Create the function public float getHeightAt(float xPos, float zPos) following these instructions:

    1. Check if the camera/player is inside the ground square

      if(xPos > 0 && xPos < nbVerticesX && zPos > 0 && zPos < nbVerticesZ) 
      
    2. Get the point P nearest xPos and zPos

    3. Get the normal N or compute it

    4. Compute constant d of the plane equation

      double d = -(P.x * N.x + P.y * N.y + P.z * N.z);
      
    5. Return compute height

      return -(d + N.z * zPos + N.x * xPos)/N.y;
      

    II - Compute approximate height

    Use this function to get the smoothed height:

    public float getHeightApprox(float x, float z)
    {
        return ( (getHeightAt(x,z)
                + getHeightAt(x + 1, z)
                + getHeightAt(x - 1, z)
                + getHeightAt(x, z + 1)
                + getHeightAt(x, z - 1)) / 5);
    }
    

    Maybe you will have to adapt your code, but these pieces of code works fine for me. Hope this would help you.