3D triangle: get hill steepness

Started by
18 comments, last by Gage64 15 years, 8 months ago
I have no idea how it's called in english, but I want to know how steep the hill of a 3D triangle is on the x and y axis. I have 3 vertexes of the triangle with XYZ values, and I need the ammount of height increase for the x axis and the y axis...I hope you get what I mean. I'm really bad at 3D math...never had it in school, will have it in the university I guess :D [Edited by - Decrius on August 16, 2008 12:42:01 PM]
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Advertisement
I assume you mean that the ground is the XY plane, and Z is the height direction, and you want the steepness of a triangle, i.e., the angle to the ground?

I've never tried this, but after some thought, how about this:
Take the dot-product of the height-direction (0,0,1) and the normal of the triangle ABC (cross-product of AC and AB). Since (the absolute of) the dot-product of two vectors represents the cosine of the angle between those two vectors, take the inverse cosine to get the angle between the triangle normal and +Z, which is the same as the angle between the triangle and the XY plane.

Or in code:
steepness = acos(abs(dot(cross(C-A, B-A), Vector3(0,0,1)))
Note that the steepness is now in radians.

If you need help visualizing this, imagine the triangle flat on the ground, normal sticking straight up. The dot-product with +Z is 1, acos(1) = 0 degrees.
If the triangle is perpendicular to the ground plane, then the normal is parallel to the ground plane, the dot-product with +Z is 0, and acos(0) = 90 degrees.
Million-to-one chances occur nine times out of ten!
I see, so you take C as the base point and take the difference between C and the other 2 (separately) points. But what is a cross-product and a dot-product?

Also, once you know the steepness, you can calculate the steepness along the X and Y axis separately I suppose? Because what I ultimately want to do, is getting known of 3 angles: x, y and z angles. The z angle (rotation around the z-axis) is no problem, I have that, the other 2 most correspond with the triangles angles. I need to place a model on a face and it should really have the same angles (a chest on a hill doesn't stand flat, does it? ;-)).

Thanks though!
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
I think to get what you want you should just do

steepnessX = abs(dot(cross(C-A, B-A), Vector3(1,0,0))

and

steepnessY = abs(dot(cross(C-A, B-A), Vector3(0,1,0))

This should give you how much your normal is pointing in the x or y axis.
Quote:Original post by Decrius
I see, so you take C as the base point and take the difference between C and the other 2 (separately) points. But what is a cross-product and a dot-product?

Also, once you know the steepness, you can calculate the steepness along the X and Y axis separately I suppose? Because what I ultimately want to do, is getting known of 3 angles: x, y and z angles. The z angle (rotation around the z-axis) is no problem, I have that, the other 2 most correspond with the triangles angles. I need to place a model on a face and it should really have the same angles (a chest on a hill doesn't stand flat, does it? ;-)).

Thanks though!
Google will tell you about the dot and cross products (just Google those terms - you could also try e.g. 'vector math tutorial').

There are methods for aligning an object to a surface that don't require getting the 'x, y, and z angles' (I assume you're referring to Euler angles here). One method is to compute an orientation from scratch using the triangle normal and a reference vector. Another method is to make a relative adjustment to an existing orientation that aligns the object to the surface.

For a non-moving item, the first of the two methods described above would probably be adequate. (All of these methods will require at least some basic vector math and/or trig, so post back if you need help with that.)
Like jyk said, no need for complicated things here. What you want is a transformation matrix that aligns the object's Z axis with the normal of the face (I'll assume Z is 'up' in object space).

The only problem is that there's still a degree of freedom. That is, you can rotate the object around the normal and it'll still be placed properly on the terrain. Or, in other words, what should the object's X axis be aligned to? And only you can answer that, since you're making it :)

A suggestion though: it could be stored in the map, i.e., the map designer determines it.
Million-to-one chances occur nine times out of ten!
Thanks for the replies guys, I'm pretty good at maths, but we only did 2D stuff till now (which can be complicated as well) so I'm fairly new to what the 3rd dimension involves and all those new terms that ship with it.

I'll explain what I want to achieve:
I build maps (area's you play in) for Call of Duty 4. Mapping is quite time consuming, and I'd love some ways to limit 'troll' work. One of the troll jobs with mapping, is placing grass. Imagine a map with a lot of grass textured terrain, some tree's...bushes...houses...what is missing is the grass model, which gives an incredible more realistic view, where the terrain is no longer consisting of flat, triangle pieces, but actually 'lives'.

To do this, you have multiple (~20) grass models which you have to place on the terrain triangles. While the map editor is quite nice (you place the grass above the terrain, then press a button and it randomly resizes and rotates the model, and makes it go along the steepness of a hill. This requires me to copy paste a lot (really a lot, to make it realistic, the grass models almost have to touch each other) of models, and press that button. Small maps...okay, but big maps, no way. So I'd love to make the computer do the troll work (and it's meant for that! hehe xD).

So, what I did, is building a interpreter of the map file format. It reads in the terrain triangles the map has. Whenever the texture is grass, it will randomly pick a few positions on the triangle (see my previous thread), and place grass models at those positions. Then it appends the data for the model placements to the map file, and I have grass models in my map :).

So, for each triangle I have 3 vertexes in a 3D space. I have a position on the triangle, but that's not important...if you look straight down at the triangle, it's always flat, so it has only one steepness level on the whole triangle.

This is how the model data looks like in a map:
...// grass entity{"origin" "-87.04 -97.28 -46.08""modelscale" "1.45697""angles" "0 232 0""model" "foliage_grass_flowerplants_squareclump""classname" "misc_model"}...


origin is done, it's the XYZ values I calculate with Mike's formula in my previous thread. Model scale is purely random, so is the model and the second angle...which is the rotation around Z...which doesn't matter whenever it's flat (X and Y rotations are 0), but whenever that's not the case, the Z rotation might make the model not attach to the ground (place a model with X rotation 45 degree, and turn it around the Z axis 180 degree, it's now at right angles to the terrain, seen from the X axis).

So, what I want to figure out, is what the first and last angles should be, where it can also compensates the rotation around the Z axis...

Well, I find it quite hard to imagine this situation in my head, and I still ponder on how the origin (previous thread) can ever be calculated this way.

Anyways, I hope this cleared up the matter, I will look into the product terms tomorrow, getting late now...

Previous thread
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
Okay, I believe the dot product is not correct, since it should somewhere do something with an angle as well...but I don't know how to calculate it and with what :S. Anyways, this is the code, should these be correct?

struct Vertex{    float x;    float y;    float z;    Vertex(float x = 0.0f, float y = 0.0f, float z = 0.0f) : x(x), y(y), z(z) {}    Vertex operator- (Vertex &vertex)    {        return Vertex(x - vertex.x, y - vertex.y, z - vertex.z);    }};Vertex cross(Vertex &vertex1, Vertex &vertex2){    return Vertex((vertex1.y * vertex2.z) - (vertex1.z * vertex2.y), (vertex1.z * vertex2.x) - (vertex1.x * vertex2.z), (vertex1.x * vertex2.y) - (vertex1.y * vertex2.x));}Vertex dot(Vertex &vertex1, Vertex &vertex2){    return Vertex((vertex1.x * vertex2.x), (vertex1.y * vertex2.y), (vertex1.z * vertex2.z));}


Thanks!
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora
No, the cross is correct, but the dot-product is:
float dot(const Vertex &vertex1, const Vertex &vertex2){    return (vertex1.x * vertex2.x) + (vertex1.y * vertex2.y) + (vertex1.z * vertex2.z);}

Finally, angle = acos(dot(v1, v2))
Then, angle is the angle between the two vectors.

However, to use this to get the angles which you seek is a different matter. You can try to take the dot product w.r.t. +X and +Y, but I have no idea if that's how CoD4 does it. And another problem with Euler angles is that the order in which they're applied matters. And I really don't know how CoD4 does that either. So you'll have to try some stuff.
Million-to-one chances occur nine times out of ten!
Thank for your reply, but how can the dot-product ever be a value between -1 and 1? It gets to 16384 and 65536 for me (the triangles are from -128 to -128 x and y, and 0 to 64 z), so the result of acos is never right. What have I forgot? How can the dot-product ever result in a value between -1 and 1?
[size="2"]SignatureShuffle: [size="2"]Random signature images on fora

This topic is closed to new replies.

Advertisement