3d rotation matrix

been stuck for about a month on this -

i use "euler angles" (tait-bryan angles) to describe rotation coordinates.

as far as i understand (i would like to be wrong), in order to concatenate two 2d rotations, eg. to rotate around an arbitrary orientation, it is necessary to convert the angles to a matrix, perform the rotations, then convert back to euler.

i have thoroughly failed at this.

i think my stumbling block is that i set out to use a LH/LH coordinate/rotation system (being familiar with LH/LH from years of POVray use). my initial attempts were.. terrible beyond description.. eventually i adopted someone else's LH/RH system and achieved some modicum of performance.

i think it must be that the conversion formulas i've been given must suck, i've tried this so many times. the best performance will perform well for initial simple rotations, then start to develop an inaccuracy which switches back and forth between two wrong places.

i cannot identify what it is about my implementation that does not work, since i have followed the conversions to a tee (both from geometrictools.com and euclideanspace.com).

i do not think it is my matrix implementation, while i've never needed one before it's not that complex and it has been doublechecked and ok'ed by someone else.

i can't post meaningful screenshots of the error, because it is bilocating between two places, so taking a screenshot would only show one of the locations.


my source is here, if anyone is intrepid enough - the matrix implementation is at the end of vectoralg.h and the "game loop" is in game.h. all it does is draw a tetrahedron on the screen which is rotated by the arrow keys.
http://xoxos.net/temp/source.zip

the matrix is arranged
abc
def
ghi

and read from the angles like this:
1
2
3
4
5
6
7
8
9
			paramxc = cos(param.x);	paramxs = sin(param.x);
			paramyc = cos(param.y);	paramys = sin(param.y);
			paramzc = cos(param.z);	paramzs = sin(param.z);

			g = paramys * paramzc;
			h = paramys * paramzs; 		
			a = paramyc * paramzc;	b = paramyc * -paramzs;	c = paramys;
			d = paramxs * g + paramxc * paramzs;	e = -paramxs * h + paramxc * paramzc;	f = -paramxs * paramyc;
			g = -paramxc * g + paramxs * paramzs;	h = paramxc * h + paramxs * paramzc;	i = paramxc * paramyc;


the matrix is converted back to radians here:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
			if (c < .99999f) {
				if (c > -.99999f) {		
					param.x = atan2(-f, i);
					param.y = asin(c);		
					param.z = atan2(-b, a);
				}
				else {
					param.x = -atan2(d, e);
					param.y = -pih;
					param.z = 0.f;
				}
			}
			else {
				param.x = atan2(d, e);
				param.y = pih;
				param.z = 0.f;
			}	


if you use the app you can see the problem - obviously the error is in the matrix-to-euler conversion, but this step is where i have to trust my source...

if some brilliant person can discern the problem, please tell me! otherwise, is there a left handed system *anywhere* that i can really trust? or do i have to go and get nasa's right handed system?

this problem is just lousy.
It's probably a sign error somewhere, such that each frame the same component gets transformed in opposite directions.
There's various solutions you can use:
1. Don't store the current angle. Just precompute the matrix you will use for each keypress and transform the location of the camera each frame.
2. Just use matrices to represent rotations, without going back and forth between representations. Less operations == less chances to mess up.
3. Use quaternions.
in order to identify the error, i removed the matrix operation so that the rotation is converted from angles to matrix, then back to angles. the rotation is incremented naively with radians to test :)

what i found is that the conversions are working perfectly except for crossing past +/- pi/2 on the Y axis... then the result is returned with pi added, or subtracted from x and z..

this is good, as i feel this "error" is something i was warned about :) if you can volunteer a way for testing the matrix and adjusting the outcome, or maybe i'll have some clarity eventually, it looks solveable :)


while i am adjusting to the concept of storing rotations as matrices, i'll try and stick with radians for this project, i mainly think in terms of audio dsp so the parameterisation works well for my ideas.
i have located the source of my woes.. asin() returns +/- pi/2, so any rotation going in that's in the other hemisphere is flipped around.

x and z are shifted by pi in these cases, and y is mirrored back into range..

so (1) that really validates the "use quaternions" response, and

(2) there's gotta be a way to use matrixes with the full sphere or nobody would talk about them..
You can write an asin() function that fixes the problem. But that isn't the real issue.

The reason to use quaternions is that at really tiny angles (at the poles) the floating point representation breaks down and cannot accurately model what is wanted. (That when you start to see the so-called "gimbal lock".)

Use of quaternions removes that restriction by allowing proper scaling toward infinity.
how can i fenangle a full 2pi radian response asin() ?? :)

i do remember this error from playing a flight simulator long ago.. entering the specific heading would ~spiral around until stabler regimes were found or selected..

tbh i'm quite interested in the matrix solution more than quaternions as i'd like to work on the app.
Last edited on
Considering sin() is not bijective, that's not really possible. Just use atan2().
the problem is, i'm just a guy, a simple guy who wants to concatenate 3d rotations. lord of mercy. i'm using the matrix-to-radians conversion as it was handed to me, i don't have the ability to reconceptualise it, so i don't know how do that.
closed account (48T7M4Gy)
@xoxos

With all due respect it seems to me you are bogged down in jargon. There is no such thing as a conversion between matrices and radians and I have never heard of concatenating matrices - somebody might have but it's obviously getting you nowhere.. And you list goes on. My suggestion would be to use matrix algebra instead of expanding the matrix multiplications (manually). It's no slower and far less prone to error especially signs, conventions and variable naming:

So,
1. go back to first principles.

2. learn what a matrix is and particularly how matrix multiplication works.

3. write a matrix class or steal one e.g. matrix11 http://www.trumphurst.com/cpplibs4.html#250 It's free with source code and pretty simple and very adaptable.

4. test your matrix with a few sets of simple data, completely forgetting about rotations etc.

5. then apply rotation technology using something like the article at http://en.wikipedia.org/wiki/Euler_angles and take it in simple, single angle steps.

6. when you are confident with that you will be able to apply multiple rotations in any direction you want ... whatever you like.

7. use quarternions but you still have matrices to deal with.

There are thousands of applications where a matrix class is the only sensible way to maintain your sanity and 3d rotations is one of them! And luckily for you that is at the easier end of the spectrum.

Hope this helps :)
ty for earnesty :) i see the same sentiments expressed across the board and i appreciate what that means.

my development, and my renown if i can say that, has been primarily (and at great length) in 1d audio dsp. i think in radians, and i want to use radian representations of angles for my app.

the reason is not because i am stubborn, but because..

well, consider the preexistent case of blewm (documented here)
http://www.youtube.com/watch?v=PZwg0ba-Xkk

this is a procedural music app with rudimentary graphical animation.

unlike games, the visual content is secondary. if i were to conceive of ideas (and, i do) for graphical representation of sounds, then radians, or if you prefer to say, a single coefficient scheme (would it be better to say scalar or phasor? i'd say phasor), is the preferred method of translating aural coefficients into spacial.

i know what the matrix performance error is like, as mentioned above. i've experienced it. and, considering how banal my animations are, it would probably result in a more interesting result when the error occurs ;) :D

everyone everywhere is telling me, quaternions quaternions.

i've got most of a matrix implementation complete, and i have seen with my own eyes that the gaming industry used them to good effect for a good while.

i know quaternions are the best answer, but i don't need the best answer.

i'm going to hang out for a couple more days and hope someone somewhere will tell me how i can do it the way it was done for a decade. i know quaternions exist and they will be there, waiting for me when i need them or want them.

but i don't, i just want the simple, half ass solution. i just want to get this done so my mind can work with my ideas instead of stagnating spending a month trying to do something. i know what the error is and i'm alright with it. i want to get back to making stuff instead of waiting for information.

about terminology - the conversion is usually called "matrix to euler" although some would correct that and say "matrix to tait-bryan angles" - the conversion returns values in radians, so i call it "matrix to radians" and hope that people will be okay with that understanding of a locally employed reference.

here are some links exhibiting the use of "concatenation" within the pedigreed graphical field -

https://www.opengl.org/discussion_boards/showthread.php/143241-concatenation-of-two-rotations

https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/2dconc.htm

http://msdn.microsoft.com/en-us/library/windows/desktop/bb153310%28v=vs.85%29.aspx
i hope people can understand, this is not for a primarily graphical application. this is for graphical representation of sounds. i've been coding for a long time, and a euler angle/radian solution is definately the best for what i have been wanting to do.

keeping angles in matrix form is great for spacial manipulation. but, this is not what i need. the conversion from and to radians is absolutely necessary.
closed account (48T7M4Gy)
@xoxos

Well I can see that matrices can be concatenated in several ways - either extending or multiplying them - all of which neatly adds to the confusion over something that's very simple.

You'll obviously have the solution when you can find somebody to agree with your half-assed (your words) way of doing things and anyway I suppose spaghetti code has its place. Good luck with your endeavours. :)
eg. NASA still host extensive information on their RH/RH matrix rotation system, so me saying half-assed is a way of winning (or apparently, losing) sympathy.

the issue seems to be that, with only 180 degrees range returned for Y, it is not suitable to use the matrix-to-euler conversion for a naive implementation that uses 360 degrees for each axis.

so, i think that, instead of clarifying my social position, it would be more helpful to help me explore ways that matrices have been traditionally implemented in flight simulators to produce a full field of motion.

i really don't get, how anything can be done with Y only between - and + pi/2.

insight and kindness may even be returned by some universal dynamic. i don't see why you would feel able to assert anything about my coding style based on what i've posted. but we don't always understand each others perspectives and needs do we :)
closed account (48T7M4Gy)
i don't see why you would feel able to assert anything about my coding style based on what i've posted.

Advice is free, as harsh as it might appear, arguments will incur a charge.


Once again, by not understanding the basics of trigonometery, or what is even worse, not bothering but blaming the world, you are making your challenge a misery ( Again, your assessment, not mine. )

Here I mean you blame C++ and perhaps even the asin function, or perhaps even arcsine for not giving you what you want.

The reality is the function only has to give you an answer in the range of pi/2 or -pi/2 to satisfy the equation. This is so basic. If you want more, say 5pi/2 then add 2pi. In terms of the final 'direction' it means nothing because you've spun around twice and in exactly the same position that the equation is telling you. You would only have an argument if the asin function returned pi/4 to -pi/4 or even worse 0-pi/4 which is 'enough'. The developers weren't that dumb.

I wish you luck with changing hands (midstream?). Seems to me you adopt one and stick to it. If you are using library transform functions from GLUT, Boost or wherever then just use their, convention.
Food for thought on a couple of levels: http://stackoverflow.com/questions/21165178/changing-rotation-matrix-from-left-handed-to-right-handed-swap-of-axis
Last edited on
it's not realistic or productive to superimpose a worldview on me.. i'm able to accept inadequate comprehension without blame. if you want a measuring contest, let me know.

instead of trying to help me by "putting me in my place," perhaps you could take a moment to understand my place..

my source is here -
http://xoxos.net/temp/source.zip

you will find a very naive implementation, which exhibits a very real performance deficit.

if you could possibly consider how things look from here, you could save yourself a whole bunch of energy exhorting me to improve,

when i'm actually a celebrated and award winning developer.

there are things i don't know. possibly, there are things i've conceived of poorly.

but telling me my code is "spaghetti" is way off.
closed account (48T7M4Gy)
Is your shift key broken? 😭
ftr i found my solution...

// place0.r is composed of radian angles x y and z

float rzbuf = place0.r.z;

// convert place0.r to matrix form, then return it to radian format

rzbuf -= place0.r.z;
rzbuf = fabs(rzbuf);
if (rzbuf > 2.1f && rzbuf < 4.1f) {
place0.r.x < pi ? place0.r.x += pi : place0.r.x -= pi;
place0.r.y = pi - place0.r.y;
place0.r.z < pi ? place0.r.z += pi : place0.r.z -= pi;
}
Topic archived. No new replies allowed.