G'day!

A while back when my old "quaternions" were getting a little more attention I had some requests for examples of how they could be used to rotate an object to align to a wall so that it can walk on whatever surface it wants, no matter what the angle is. I helped a couple of people with it, and have seen another request for such a function, so I thought people might appreciate it.

This does not require my quaternion code. I personally prefer to use my quaternions (albeit a much more updated version than my previous contribution, which will get updated when the next public beta comes out), but this function here has been designed for use with normal A7 Euler angles (pan, tilt and roll).

This is a (very slightly modified) function I wrote for Pappenheimer which other people might like:
Code:
function alignToVec(ANGLE* entAng, VECTOR* vec, VECTOR* axis, var factor) {
	vec_rotate(axis, entAng);
	vec_normalize(axis, 1);
	vec_normalize(vec, 1);
	VECTOR rotAxis;
	vec_cross(rotAxis, vec, axis);
	var angle = -acos((float)vec_dot(axis, vec)) * factor * vec_length(rotAxis);
	ANGLE rotAngle;
	ang_for_axis(rotAngle, rotAxis, angle);
	ang_add(entAng, rotAngle);
}


entAng is the angle that gets modified. This will commonly be "my.pan", but if you're using c_rotate you won't use this function to modify "my.pan" directly.

vec is the vector (in world space) that the angle should get lined-up with (this will commonly be "normal" after doing a c_trace or c_move).

axis is the vector (in local space, relative to the angle) that needs to get aligned to "vec" (for walking on walls, this will commonly be "vector(0, 0, 1)", which is straight up relative to the angle).

factor usually ranges from 0-1 (but there's nothing stopping you from using any other value), and indicates how far to rotate the angle (where 1 = complete alignment, and 0 = no rotation).

TWO IMPORTANT NOTES:

1.
The alignment has been "smoothed out" to prevent stuttering/shaking due to var's finite precision, so calling "alignToVec" with a factor of "1" just once often won't be a complete alignment (it'll get most of the way there). Call "alignToVec(........, 1)" once every frame over several frames to complete the alignment (this will be quite smooth and quite quick), or several times in one frame for a complete alignment in only one frame.

If you would rather deal with the imprecisions yourself, remove the "* vec_length(rotAxis);". If you call "alignToVec" with a factor of 1 every frame you will often come across a stuttering or shaking.

2.
This requires the latest public beta (A7.8), but also relies on a bug in the latest beta. "ang_for_axis" currently uses radians instead of degrees. Apparently this has been fixed and will be solved in the next public release, and so this will require this:
Code:
-acos((float)vec_dot(axis, vec))

to be changed to this:
Code:
-acosv(vec_dot(axis, vec))

when the update comes out.

I hope you find this useful!

Jibb


Formerly known as JulzMighty.
I made KarBOOM!