Skip to main content
GameDev.net gamedev.net
🔒 Locked

Store transformations

Started by schupf Jul 4, 2009 at 5:05 AM 7 replies 1.1k views
Original Post
schupf
schupf
Hello! I have a screen graph and I need to store a local and world transformation at each node. I want to write a class Transformation, which stores a transformation in a certain way. The only transformations I need is Scaling, Rotation and Translation. There is one additional requirement: Since I want to "animate" the objects I need a system which allows me to easily modify any of the transformations (scaling or rotation or translation). So I guess I can't just store the final composition matrix M in class Transformation, because there is no way to extract one transformation type. For example: Assume M = Rotation1 * Scaling * Rotation2 * Translation * Rotation3; I think its generally impossible to modify each single transformation if I just have M (for example I can't extract the scaling in every case to modify it). My second idea was to store the transformations in a list: std::list transforms. This way I could store arbitrary transformations AND could access each of them seperately. For example if I want to modify the scaling I would just modify transforms[1]. But the problem is: its tedious to remember where which matrix is stored. Now my last idea and basically the reason for this thread: I saw an engine which stores a composition of transformation in this way: R*S*T. So it just stores 3 matrices (rotate, scale, translate) and the order is always rotation, then scaling, then translation. This is easy and I can access every transformation easily but I think I can't express every transformation with this fixed order. Assume I want to do this: I want to rotate a box around the world y-axis and the box has to rotate around its own axis. This would basically lead to this transformation: Scale * Rotate1 * Translate * Rotate2, where Rotate1 express the rotation around the box axis and Rotate2 the rotation about the world y-Axis. Now I wonder if I can express EVERY possible transformation (composed of scale,rotate,translate) with this fixed matrix order: S * R_2 * T * R_2 (scale, rotation1, translation, rotation2) ? Thanks for any help!
Zakwayda
Zakwayda
Hm, I'm a little confused by your question, but here are a few comments:

1. It actually is possible to extract from a matrix the scale, rotation, and translation transforms that were used to build the transform, provided you know how the transform was built. (Usually it's best just to store the different transforms separately though.)

2. I'm used to seeing transforms combined in the order S->R->T, but R->S->T seems a little unusual. Are you sure the engine you mentioned uses exactly this order?

3. Two or more rotations in sequence (e.g. R1->R2) can always be combined into a single rotation.

It's fairly common for a transform class to store scaling (a vector or set of floats), rotation (usually a quaternion or 3x3 matrix), and translation (a vector) separately, and then build a 4x4 matrix from the transforms when needed. It sounds like you want to do something else though - store a more or less arbitrary sequence of transforms, and then be able to modify any one of the transforms in the sequence (changing the overall transform).

Can you by any chance give an example of how this feature would be used? What sorts of objects are these? And what type of animation are you wanting to achieve?
schupf
schupf
Thanks for your fast reply jyk!

Quote:
1. It actually is possible to extract from a matrix the scale, rotation, and translation transforms that were used to build the transform, provided you know how the transform was built. (Usually it's best just to store the different transforms separately though.)

Oh ok, I didn't know that. But you only can always extract the indivdual parts if you know the exact order of multiplications, don't you?
For example: If I give you a matrix M and tell you it contains a scale, rotate and translation (but I don't tell you the order, if it is S*R*T or T*S*R etc.), you can't extract the indivdual operations, can you? But if I tell you M is composed of a S*R*T, then you always can extract S,R,T, cant you?

2. Yes, the engine uses the order R*S*T. To be more precise it uses: v' = v*R*S +T. This is also kinda strange to me and I definitely would use the order S*R*T

3. Yes, I knew that. One could say: R_X(alpha) * R_X(beta) = R_X(alpha+beta) (same for all other axis)

Quote:
It sounds like you want to do something else though - store a more or less arbitrary sequence of transforms, and then be able to modify any one of the transforms in the sequence (changing the overall transform).

Exactly! I basically want two things: Store a "more or less arbitrary" transformation composed of scaling, rotation and translation AND allow to easily modify any of these individual operators (for example just the translation).

Quote:
Can you by any chance give an example of how this feature would be used? What sorts of objects are these?

Sure. I guess I didn't explain my problem very well (might be due to my limited english skills:/ )
My key question is: Can I express EVERY possible transformation (composed of scalings, rotations and translations) in this form:
v' = v * S * R_1 * T * R_2
Now you may wonder whats the use of the second roations matrix R_2. I'm trying to explain it: First I have seen how the mentioned engine stores a transformation as R*S*T. I was surprised that I can express every transformation with a fixed order of just 3 matrices. So I tried to think about a case which is NOT expressible in this form. I think I have found an example (the box scenario, mentioned in my first posting). Im trying to explain it better: Lets say you have a box and you want to make it bigger, rotate it a little bit and place it in the world. This is perfectly expressible in this form: v' = v * S * R * T.
But now think about this case: I want to make the box bigger, rotate the box around its own local axis AND rotate the box around the world y-axis (its kinda like the earth rotating around the sun and the earth also rotates about its own axis). I would express this transformation in this form:
v' = v * S * R_1 * T * R_1. S makes it bigger, R_1 performs the rotation about the local box axis, T translates the box and R_2 performs the rotation about the world y-Axis.
My two questions are: Can I express this box transformation ( v' = v * S * R_1 * T * R_1 ) also in this form: v' = v*S*R*T ?
If yes: Can ALL transformations (crazy spinning boxes etc) be expressed in the form S*R*T?
If not: Can ALL transformtions be expressed by my idea of S * R_1 * T * R_2?

Quote:
And what type of animation are you wanting to achieve?

Well, don't think about animation in terms of "skinning" or something complicated. I need it more for object movement and morphing.

I want to make something like this: I have a scene graph full of nodes and meshes. Each node has its own local transformation (but as you can see I am not sure how to store these). Assume I have a scene with 2 boxes. Box1 stands on the ground and box2 is placed onto box1. The local transformation of Box1 places Box1 in the world and the local transformation of box2 places it realtive to box1. To move box1 I change its local transform and the world matrix for box2 is automatically updated (box2.worldMatrix = box2.localMatrix * box1.WorldMatrix). To implement this movement in a simple way I want to use different controlers and attach them to objects. Lets assume I want to move box1 permanently along the x-axis to the right. So I write a Controller which has a method like update(float time); and this method modifes the translation matrix of the box (according to the passed time). Maybe my little system is total crap but I hope you got an idea now what I am doing :)

Thanks for any help!

[Edited by - schupf on July 4, 2009 8:56:06 AM]
Zakwayda
Zakwayda
Quote:
Oh ok, I didn't know that. But you only can always extract the indivdual parts if you know the exact order of multiplications, don't you?
For example: If I give you a matrix M and tell you it contains a scale, rotate and translation (but I don't tell you the order, if it is S*R*T or T*S*R etc.), you can't extract the indivdual operations, can you? But if I tell you M is composed of a S*R*T, then you always can extract S,R,T, cant you?
If you know the order, you can definitely do it. If the order is unknown, there are other decomposition methods you can use, but in the general case, I don't think you can guarantee that you'll get the original input transforms back.

I understand your example of an 'orbiting object', I think: such an object might be scaled, rotated (to represent its own local rotation), translated, and then rotated again (to represent orbit around another object).

Leaving out scale for the moment, if you concatenate an arbitrary sequence of rotations and translations, you'll end up with a transform containing a rotation and a translation. So in this sense, yes, any sequence of rotations and translations can be expressed as a single rotation followed by a single translation (unless I'm confusing myself, that is).

I will offer one thought that might be helpful. I have an entity system in my current project that supports the kinds of things you're describing (e.g. entities rotating independently but also 'orbiting' around other entities). Each entity has a simple S->R->T transform. Rather than creating more complex transforms by making the transform class itself more complex (which seems to be the approach you're taking), these effects are instead achieved through parenting.

In the case of a rotating and orbiting object, for example, this is achieved as follows. There is a single parent entity (the object being orbited around). This entity has a single child entity which has no physical presence (e.g. no visual representation, and no collision detection proxy) that simply rotates at a fixed rate. Finally, the 'orbiting' object is made a child object of the virtual 'rotator' entity. The end result is the same as if you combined transforms in an arbitrary manner (e.g. S->R1->T->R2), but the transform class itself can be kept simple (that is, it only need support the transform order S->R->T).

I don't know how applicable that is to your situation, but maybe it'll at least help you to look at the problem in a different way.
schupf
schupf
Quote:
Leaving out scale for the moment, if you concatenate an arbitrary sequence of rotations and translations, you'll end up with a transform containing a rotation and a translation. So in this sense, yes, any sequence of rotations and translations can be expressed as a single rotation followed by a single translation (unless I'm confusing myself, that is).

Yes, you can compose an arbitrary number of rotations and translations into one matrix. But I still think you CAN'T express my "orbiting transformation" in the form of S->R->T. Finally R ist just ONE rotation and T is just ONE rotation (even though they might be composed of many indivdual rotations/translations) and you can't express the orbiting example with one rotation and then one translation.

Your example with the parenting and "virtual entity" is really interesting. But there is one part I don't understand. All your nodes have a fixed S->R->T Transformation. So the sun would use S=I (identity), R = Rotation, T=I. Now you add a child node ("virtual rotator entity") to the sun. But in order to let this entity rotate AROUND the parent (=sun) you need something like this: T->R (for example move the rotator 10 units along the x-axis and THEN rotate). But your system only supports S->R->T. I have no idea how I could express the rotation around the sun if I have to apply the rotation before the translation.

Regardless of whether I implement such a system I still would love to know if I can express absolutely EVERY transformation (composed of Scalings, rotations, translastions) with S->R1->T->R2 (just because of mathematical curiosity;)
Zakwayda
Zakwayda
Quote:
Your example with the parenting and "virtual entity" is really interesting. But there is one part I don't understand. All your nodes have a fixed S->R->T Transformation. So the sun would use S=I (identity), R = Rotation, T=I. Now you add a child node ("virtual rotator entity") to the sun. But in order to let this entity rotate AROUND the parent (=sun) you need something like this: T->R (for example move the rotator 10 units along the x-axis and THEN rotate). But your system only supports S->R->T. I have no idea how I could express the rotation around the sun if I have to apply the rotation before the translation.
Good question. The trick is to set up the transforms and parent-child relationships so that only transforms in S->R->T form are required.

For simplicity's sake, let's set aside scale for the moment. Let's also assume that the 'root' object in our hierarchy is not itself rotating (we could set things up so that it could rotate without affecting the orbit of the orbiting object, but this would require a slightly more complex hierarchy).

The second object in the hierarchy (the 'virtual rotator') actually has a local translation of (0, 0, 0); in other words, its position relative to its parent object is fixed.

The third object in the hierarchy (the 'orbiter'), has a fixed translation - say, (10, 0, 0). This means that its position relative to its parent (the 'virtual rotator') is fixed. However, since its parent object is rotating, the end effect is that the orbiter appears to orbit around the root object. Again, this is all achieved using transforms of the form R->T.

(Disclaimer: I think the above example is sound, but it's possible I messed something up somewhere.)

Again, I don't know how relevant this is to the problem you're trying to solve, but generally speaking, using transform hierarchies in this way, you should be able to set up fairly complex relationships between multiple moving objects.
haegarr
haegarr
It is correct that R * T is sufficient to express each possible orientation and position in space. As such it must be (and is) also sufficient to express a transformation resulting from orbiting.

Look at the sequence R1 * T * R2. It describes an orbiting in the sense of the OP. It first gives the object an orientation due to R1, then locates the object due to T, and then does the actual orbiting due to R2. Unfortunately, the multiplication with R2 has an influence on both the rotational as well as the translational sub-matrices so far, so R2 will influence both the effect of T as well as the effect of R1. It models a self rotating earth that is orbiting around the sun. Nevertheless, the resulting orientation and position can be expressed by a composition of a single rotation and translation.

For simplicity we will use the minimal sufficient form in the following:
S * R * T

Now one can argue that s/he doesn't only want to rotate/scale w.r.t. the center of the object but w.r.t. an arbitrary center. For this purpose one needs 2 dependent translations like so:
C-1 * S * R * C * T

Moreover, scaling should not only work along the principal axes but along arbitrary axes, so that the scaling must be surrounded by some extra rotation:
C-1 * A-1 * S * A * R * C * T

BTW, this beast of transformation is (more or less) used by X3D in its transformation nodes.

However, also it is flexible enough to express nearly all tranformation results one may want, it is not able to express all the possible ways to come to a specific result. E.g. it isn't able to express the aforementioned orbiting. And one can imagine dozens of other ways that can't be modelled. On the other hand, due to the graph node concept it is possible to simply put 2 or more transformation nodes in a row and hence extend the transformation to an arbitrary complexity.

Now thinking furthur about that, it is possible to define a node type for all 3 basic transformations and let the designer compose the overall transformation. It would be the most efficient way, but requires the designer to know enough matrix math to understand the above concept. Say, it is presumbly easier for a designer to know a "center of rotation" instead of a translation C before and after rotation, once in its normal form and once in its inverse form.

Hence there are 2 extremes: At the one end there is the overkill transformation node, and on the other end there are simple nodes but the requirement of mathematical skills of the designer. I personally prefer some compromise in-between. E.g. a translation is just a translation, and a rotation may be equipped with a reference point. But both exist for themselfes. Hence the designer can choose
( C-1 * R * C ) * T
or
T * ( C-1 * R * C )
where the parantheses are shown to indicate the part of the rotation node.
Zakwayda
Zakwayda
Quote:
On the other hand, due to the graph node concept it is possible to simply put 2 or more transformation nodes in a row and hence extend the transformation to an arbitrary complexity.
@The OP: Just to clarify, this is more or less what I was getting at in my previous post. (haegarr's post was much better than mine though - 'hopefully you'll be able to get the info you need from it :)
haegarr
haegarr
Quote:
Original post by jyk
Quote:
On the other hand, due to the graph node concept it is possible to simply put 2 or more transformation nodes in a row and hence extend the transformation to an arbitrary complexity.
@The OP: Just to clarify, this is more or less what I was getting at in my previous post.

Correct! Unfortunately I'm so slow with writing such lengthy posts. If I had seen your other answer earlier, I would had referred to it :)

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.