Convert a 3D vector into a vertical angle

Miscellaneous Forums/General Discussion/Convert a 3D vector into a vertical angle

I am working with player maximum slope angles.

If I have a normalized 3D vector that gives the normal of the slope, how do I turn that into an angle? Assume y is the up direction. If I only consider the x and y vector components, it's easy. But when you add a z component, you can no longer determine the angle from y alone.

If the normal is [1,1,1], the normalized normal will be [0.577350259,0.577350259,0.577350259] and the angle will be 45.0. If the normal is [1,1,0] the normalize normal will be [0.70710681,0.70710681,0.0], and the angle will still be 45.0.

SohCahToa

Sine = Opposite / Hypoteneuse
Cosine = Adjacent / Hypoteneuse
Tangent = Opposite / Adjacent

The opposite is the length of the line opposite the angle we want to know. That would be the Y of the normal.

The hypoteneuse is the length of the line opposite the right angle in our triangle.

The adjacent is the remaining line which is not the hypoteneuse and which connects to the point at which we are looking for the angle.

So...

./|
/_|

This is our triangle. If you imagine the normal is in a plane, and this triangle is in that plane, the normal is the hypoteneuse. We know the length of it is 1.

Now, the Y component of the normal should tell us the length of the opposite, and thus what the angle is, using ArcSin.

I can't figure out right now why that doesn't work though.

But maybe using ArcCos will work out for you. The adjacent is the length of the X and Z component of the normal. So just square those, add them and square root to get the length and use that.

I'm not sure, but I think I've read somewhere that you should do this in 2 steps. First, rotate the vector to face the front. (atan2 x,z) That is the first angle. Then get the second angle (atan x,y)
Inversed you can so something similair to this:
x# = cos(ang1) * cos(ang2)
y# = cos(ang1) * sin(ang2)
z# = sin(ang1)

Do you mean the angle between the 3d vector and the y-axis (vertical vector)?

If so a simple playing around with the dot product and arccos will do it:

a.b = |a||b|cos(Theta)

where a is your unit 3d normal, b is the unit normal pointing up (0,1,0) and |a| is the magnitude of a (ie 1) and same goes for |b|.

So arccos(a.b)=Theta.

Although I'm not sure that is what you are after.

If we take just the horizontal component x and z, the magnitude of that is:

m=Sqr(x*x+z*z)
m=Sqr(0.577350259^2.0+0.577350259^2.0)
m=Sqr(0.333333333+0.333333333)
m=Sqr(0.66666666)
m=0.8165

Now normalize just the horizontal vector:
x=0.5774/0.8165
x=0.7072
z=0.5774/0.8165
z=0.7072

So now we have a triangle with 0.8165 as the base, the hypotonuse is 1, and the height is 0.5774? Why does this seem so hard?

Oh, I see. I was thinking that a normal [1,1,1] would give a 45 degree vertical slope, when it is really more like 35.

Pfft!

I thought something was up there, but, I thought about a line going to the corner of a cube from the center which is what 1,1,1 would be and I thought that must be a 45 degree angle. And you seemed to confirm it so...

It's not?

Draw it out on paper and you'll see why. Start with a cube with one corner at the origin, and the sides are the vector components. For a 45 degree vertical angle, you need x and z to both be a little shorter than Sqr(3.0).

Prolly not understanding this, and my math is pretty crap, but you basically want to find the pitch of the vector? Mark has this function defined in his C++ geom code as:
float pitch()const{
  return -atan2f( y,sqrtf( x*x+z*z ) );
}


Or have the arguments the other way round, if you're working with normals

... I think.

I'm not quite sure what angle is desired here.

For a normalized ( length 1 ) vector the components are the "direction cosines", i.e. the cosines of the angles which the vector makes with the positive coordinate axes.

So if the normalized vector is ( something, 0.5, something ) then the angle between the vector and the Y+ axis is ACos( 0.5 ).

Not sure exactly which angle your after, but here's how to find the angle of a vector relative to the XZ plane. (Blitz Max code)
atan2(y,sqr(x*x+z*z))


normalized vectors and normal vectors are different things. A normalized vector is, as you said, of length 1, but a normal vector is a vector perpendicular to a particular face or edge. Oddball and big10p have the right function for a general vector, but if you want to find the pitch of a face given its normal, I think you'll need to swap the arguments round.