Gradient of Triangle

Hello,

I’m wanting to calculate the gradient(steepness) of a triangle, given the x,y,z coordinates of each point of the triangle. This is so I can use different materials on the triangle in a terrain according to the terrains slope.

Any copy/paste code around for doing this ? Searches so far have not succeeded

thanks
SteveH

I think what you want is the normal… which is the cross product of two the edges but you also may already have it in the mesh. Not sure what your source data is.

The source data is just an 2D array with the array value being the height value

So TerrainGrid(x,y)=height

Well, then you have to figure out how you want to turn that into triangles… then take two of the edges and do cross product. You can easily manufacture edges from the grid. x, y, z where y is height and x, z are grid locations.

Not sure the normal is what I’m after. eg if a triangle is lying flat in the x-z plane, the normal will point straight up which implies a non zero gradient which is what a horizontal surface has.

What I’m after is a scalar indicating the rise in height as a fraction of the horizontal distance it covers. eg 1.0 would be a 45 deg slope in 2D.

Calculate the angle between the normal and it’s projection on the ground plane (X-Z or whatever your ground is). For example: create a vector from the X-Z of the normal (setting Y=0) and take the cross-product between the normal and this vector.
As pspeed said, you need the normal.

Slope like that only works in 2D but you have the y value of the vector which is as close as you will get to a “slope”. It’s the sine of the angle… you should be able to produce whatever you want from that with a little trig. (Note: if you use asin() or similar then you are doing it wrong… no reason to bring angles into it.)

Hint: in cos^2 + sin^2 = 1
sin = normal.y

Ok, it’s starting to be clearer, I’ll go from there. Thank you

I wrote these methods a while back while toying around with terrain:

These were my terrain settings:

public static int BlockSize = 129;
public static int PatchSize = 65;

Useage:

int pos = ((int)z + (GlobalSettings.BlockSize / 2)) * GlobalSettings.BlockSize + ((int)x + (GlobalSettings.BlockSize / 2));
float slope = slopemap[pos];

The code pretty much speaks for itself. Hope it has some kind of use for you.

private float[] generateSlopeMap(float[] heightmap)
{
    float[] map = new float[heightmap.length];

    for (int z = 0; z < GlobalSettings.BlockSize; z++)
    {
        for (int x = 0; x < GlobalSettings.BlockSize; x++)
        {
            int pos = z * GlobalSettings.BlockSize + x;

            float center = heightmap[pos] * GlobalSettings.WorldHeight;
            float top = getAbove(heightmap, x, z);
            float bottom = getBelow(heightmap, x, z);
            float left = getLeft(heightmap, x, z);
            float right = getRight(heightmap, x, z);

            float diff1 = top - center;
            float diff2 = bottom - center;
            float diff3 = left - center;
            float diff4 = right - center;

            float result = diff1 + diff2 + diff3 + diff4;

            float division = result / 4f;

            map[pos] = Math.abs(division);
        }
    }

    return map;
}

private float getAbove(float[] heightmap, int x, int z)
{
    if (z == 0) return 0f;

    int pos = (z - 1) * GlobalSettings.BlockSize + x;
    return heightmap[pos] * GlobalSettings.WorldHeight;
}

private float getBelow(float[] heightmap, int x, int z)
{
    if (z == GlobalSettings.BlockSize - 1) return 0f;

    int pos = (z + 1) * GlobalSettings.BlockSize + x;
    return heightmap[pos] * GlobalSettings.WorldHeight;
}

private float getLeft(float[] heightmap, int x, int z)
{
    if (x == 0) return 0f;

    int pos = z * GlobalSettings.BlockSize + (x - 1);
    return heightmap[pos] * GlobalSettings.WorldHeight;
}

private float getRight(float[] heightmap, int x, int z)
{
    if (x == GlobalSettings.BlockSize - 1) return 0f;

    int pos = z * GlobalSettings.BlockSize + (x + 1);
    return heightmap[pos] * GlobalSettings.WorldHeight;
}

And this method lets you get the height of a specific point.

public final float getHeight(Vector3f location)
    {
        int tqLocX = (int)location.getX() >> this.bitshift;
        int tqLocZ = (int)location.getZ() >> this.bitshift;

        TerrainLocation tLoc = new TerrainLocation(tqLocX, tqLocZ);

        TerrainChunk tq = this.worldTiles.get(tLoc);

        if (tq == null)
            return 0f;

        float tqPosX = location.getX() - (tqLocX * this.blockSize);
        float tqPosZ = location.getZ() - (tqLocZ * this.blockSize);

        float height = tq.getHeightmapHeight(new Vector2f(tqPosX, tqPosZ));

        return height * this.worldHeight;
    }

I’m sure they will be very helpfull, thank you.

Do note that he is effectively averaging the slope for the surrounding grid directions… which is not originally what you asked for.