I need to calculate the slope/angle of a triangle, for my terrain engine.

Is this the right way to do it:

n = calcFaceNormal(v0, v1, v2);
angle = acos(worldYAxis.dot(n))

It seems to give me the correct results however I don't get any sign information, so I don't know if the face is sloping down or up :/ I guess I can get that information by checking the vertices, but is there another way? A more math correct way err..?

I think what you want is: sqrt(n.x*n.x + n.z*n.z) / n.y Assuming the Y axis is up, this number will be 0 if the triangle is perfectly horizontal, increasing to 1 where the triangle is at a 45 degree angle with horizontal, increasing to infinity where the triangle is perfectly vertical. If you want an angle instead, try atan2(n.y, sqrt(n.x*n.x + n.z*n.z)). This angle will be 0 when the triangle is horizontal, to pi/2 when it is vertical.

Regarding "sloping down or up"...assuming your triangle are all facing upwards (as they should be for terrain triangles), this question has no meaning. It'll be up if you move along the triangle one way, down if you move the other way. The triangle by itself has no intrinsic upness or downness.

Now, if some triangles face up and some face down, the above expressions will give you negative results for the down-facing ones. But I don't think that's quite what you want.

I think what you want is: sqrt(n.x*n.x + n.z*n.z) / n.y Assuming the Y axis is up, this number will be 0 if the triangle is perfectly horizontal, increasing to 1 where the triangle is at a 45 degree angle with horizontal, increasing to infinity where the triangle is perfectly vertical. If you want an angle instead, try atan2(n.y, sqrt(n.x*n.x + n.z*n.z)). This angle will be 0 when the triangle is horizontal, to pi/2 when it is vertical.

Hm.. I tried the atan2() and it gives the same result as 90 minus my acos() function. So the angle actually gets bigger when it should get smaller and gets smaller when it should get biggger, at least imo. So: atan2(n.y, sqrt(n.x*n.x+n.z*n.z)) == 90.0 - acos(worldYAxis.dot(n))

Of course, converting to degrees before that, I just excluded that from that piece. So is that atan2 thing really right?

I have setup a window with a view of a single triangle where I do my testing. And there I have a triangle with these coordinates: v0[-1, 10, -1] v1[-1, 0, 1] v2[1, 0, 1]. And these are the results:

my acos = 78.69007 your atan2 = 11.309933

If i change v0 to v0 [-1, 2, -1] both give me 45 degrees. And if I change to v0 [-1, 0, -1] I get 90 from your atan2 and 0 from my acos. So to me it looks like my way is the right way :/

Regarding "sloping down or up"...assuming your triangle are all facing upwards (as they should be for terrain triangles), this question has no meaning. It'll be up if you move along the triangle one way, down if you move the other way. The triangle by itself has no intrinsic upness or downness.

Instead of using acos(worldYAxis.dot(n)), use just worldYAxis.dot(n) and adjust all depending formulas accordingly. Chances are that the next thing you do with the angle as take the cosine, making the whole conversion pointless...

On road signs they also typically indicate the slope in percentage instead of an angle. For example at 5% you know that after a kilometer you've climed 50 meters.

It's just another way of thinking about slope. You almost never need trigonometric functions in any game code.

Do you actually want the gradient in one axis ? - I usually find that the vector with maximum gradient ('grad') is more useful, mathematically this is the vector whose components are the individual gradients in the respective axes. This gives a good direction for things 'sliding' off the plane, etc.