• FEATURED

View more

View more

View more

### Image of the Day Submit

IOTD | Top Screenshots

### The latest, straight to your Inbox.

Subscribe to GameDev.net Direct to receive the latest updates and exclusive content.

# Adding or Concatenating Transforms (Scale, Rotation, Translation)

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

22 replies to this topic

### #1Kwizatz  Members

Posted 08 January 2013 - 05:18 PM

I keep my transformations as a scale vector, a rotation quaternion and a translation vector (SRT) rather than a single matrix, when I need a matrix I do some conversion and get a 4x4 matrix out of the 2 vectors and quaternion.

To add or concatenate 2 transforms what I do is generate the matrices from the 2 SRT transforms and multiply them together, which is fine since I rarely require to convert back from Matrix to SRT.

In the long run I think there are some matrix multiplications that can be shaved off if I could "add transforms", so I am trying to do that, but I ran into some issues.

My basic approach is as follows:

I have 2 SRT structures which I want to concatenate.

I do a element wise multiplication of the scale vector (S = S1[0] * S2[0],S1[1] * S2[1],S1[2] * S2[2]), this seems to work, but for now I have no scaling, so all values are 1, I just need to know if this is correct or if there is something wrong there.

I do a simple quaternion multiplication with R1 * R2, again this works as expected as the 3x3 sub-matrix is the same as when I convert to matrix and multiply matrices.

I to an element wise addition of the translation vectors so T = T1[0]+T2[0],T1[1]+T2[1],T1[2]+T2[2], and this is where it all goes wrong, the values on the matrices are different, and now that I think of it, this may have to do with the last element in the matrix, the 4th element of a position vector....

TL;DR version:

So anyway, long story short I want to concatenate/add transforms in Scale, Rotation, Translation format and then convert the result to a 4x4 matrix rather than convert the SRT's to matrices and then multiply the matrices, but the translation vector addition is giving me trouble.

Any ideas?

Posted 08 January 2013 - 05:24 PM

You don't add translations when they are 4x4 homogeneous matrices, you (matrix) multiply them, that's the whole point of homogeneous matrices (all affine transforms can be multiplied). Just make sure the rest of the translation matrix is the identity (i.e. the upper 3x3 part).

Edited by Paradigm Shifter, 08 January 2013 - 05:26 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

### #3Kwizatz  Members

Posted 08 January 2013 - 05:35 PM

Hey, thanks! that makes perfect sense, I though of something like that, but for some reason I kept thinking the 3x3 upper part had to already be populated with rotation and translation data instead of the identity... I am glad I posted.

Would scale work the way I am doing it though? I would like confirmation on that.

Thanks again!

Posted 08 January 2013 - 05:39 PM

Yeah, scale works the same way, just make sure the 4th row and column is (0 0 0 1). (So it's diagonal with zeros everywhere except leading diagonal which is (scalex scaley scalez 1).

EDIT: There is always a 1 in the bottom right corner of homogeneous transform matrices.

Edited by Paradigm Shifter, 08 January 2013 - 05:41 PM.

"Most people think, great God will come from the sky, take away everything, and make everybody feel high" - Bob Marley

### #5Kwizatz  Members

Posted 08 January 2013 - 07:37 PM

Hmmmm no, that didn't work, I get the same values.

With identity matrices for the SR part the T part becomes the sum I am already doing, but inverted (IE: T2 + T1 instead of T1 + T2).

The bottom right value does remain as 1, so no real change.

Edited by Kwizatz, 08 January 2013 - 07:38 PM.

### #6HappyCoder  Members

Posted 08 January 2013 - 08:03 PM

You will only be able to keep the pieces of the transformation separate if you only allow uniform scaling. This is because by appending transforms that don't enforce uniform scaling you can end up with a matrix that skews vertices. Being that you cannot skew vertices with a scale, rotation, then translation. You will not be able to concatenate transformations and keep them in the split representation.
My current game project Platform RPG

### #7yckx  Prime Members

Posted 08 January 2013 - 09:04 PM

I don't think this is going to work. IIRC, if you have a transform matrix that has scaling and/or rotation info as well as translation, the scale and rotation are applied first. So the translation components can't be combined independently, unless the scale and rotation of both SRTs are identical. Matrix multiplication isn't commutative, so you can't really expect to get an accurate result if you change the order inl which you combine the component transforms.

### #8Kwizatz  Members

Posted 08 January 2013 - 11:15 PM

I don't think this is going to work. IIRC, if you have a transform matrix that has scaling and/or rotation info as well as translation, the scale and rotation are applied first. So the translation components can't be combined independently, unless the scale and rotation of both SRTs are identical. Matrix multiplication isn't commutative, so you can't really expect to get an accurate result if you change the order inl which you combine the component transforms.

Yeah, you're right, I found out that if I apply the rotation of the first SRT to the translation of the second SRT before adding the 2 vectors, I do get the same vector as the matrix multiplications, give or take 0.000001 due to floating point error (scale is 1,1,1 so its mute at the moment, but I am sure I would have to take it into account as well).

My "rotate_vector_by_quaternion" packs quite a lot of operations, so now I am just pondering whether its worth it or not. In the end what I may be saving is a temp array of matrices since what OpenGL (and I suspect Direct3D) expects is matrices as well anyway.

Edited by Kwizatz, 08 January 2013 - 11:19 PM.

### #9yckx  Prime Members

Posted 09 January 2013 - 01:33 AM

I wouldn't worry too much about trying to devise a more efficient way to concatenate transforms unless you've determined empirically through profiling that this bit of code is your bottleneck. Your first priority should be code that you can read and understand after not looking at it for six months. Multiplying matrices is a standard approach to transform concatenation, so let it be your first choice. Otherwise you run the risk of wondering what the hell you were trying to do, how it was supposed to work, and why you were doing it in the first place.

### #10Morphex  Members

Posted 09 January 2013 - 04:36 AM

Yckx you just resumed my coding life!

I have been looking for a piece of code I wrote about 8 years ago, and I am still trying to figure out what the hell was I thinking when doing that.

Don't do the same mistakes, if you do change, comment through fully, you never know when you will need to revisit your old code. And believe me, sometimes when I am really sleepy or tired I code extraordinary things that work, do what is supposed, but I have no idea why.

So unless this really is your bottleneck (which I doubt), don't really bother trying to optimize the code.

Check out my new blog: Morphexe

### #11Kwizatz  Members

Posted 09 January 2013 - 10:55 AM

You're right, and I agree, my matrix code works, but to give some more context to this, I'll explain how this idea came to be.

My skeleton file format stores transforms as SRT, as I explained, my animation file format stores a "channel" per vector element, so animations are applied to the SRT vectors as well, this works great, BUT at runtime I need to generate a temp array of matrices (that is, an array of arrays) for the bind pose skeleton pose, a temp array of matrices for the animated joints which gets multiplied by the bind pose array and a final array for the result of the previous multiplication.

I cache the bind pose array since it never changes, but keeping duplicate data on memory kind of bothers me, and having a temp array with the SRT's converted to matrices provokes the same nagging annoyance in me.

So I though that if I could do the operations with the SRT's directly I could do without the auxiliary arrays, so no duplication of data in memory, and at the time avoid a runtime pre-computation (I am trying to do all preprocessing offline so my file formats are ready to use as soon as they're loaded into memory and some pointers are set), and some matrix multiplications here and there.

To me, it is an interesting topic, I have not dumped my matrix code yet, and I won't, but I'd like to know what could I get away with.

### #12RobTheBloke  Members

Posted 17 January 2013 - 01:06 PM

You can do everything with SRT (and upload them to the GPU and process the verts with them directly if you wish). Doing so has a number of problems. Firstly, SRT * Vertex is an exceptionally slow operation (well, it's not that bad, but it is much slower than matrix * Vertex). Secondly, SRT * SRT is also fairly slow when compared to matrix * matrix. Really the only time SRT makes any practical sense, is when you are performing lots of interpolations (which is quicker with SRT than with matrices). Most people store the bind pose as matrices because, well, it's efficient as is possible (assuming you have SIMD optimised your matrix operations. If you haven't, then you *may* be able to squeeze a tiny advantage with SRT).

### #13Kwizatz  Members

Posted 21 January 2013 - 07:12 PM

In the end I did manage to get it working, I am doing this for animation interpolation, so it does seem justified. I convert to matrix before feeding the transforms to the gpu.
I do think this way is more efficient at least as long as it stays on the CPU, many multiplications can be avoided for example because one of the multiplicands being zero for the translation part and the scale part (what I did was convert the vectors to matrices and assume constants for the non variable elements in the matrix, then simplify the matrix multiplications),
the most expensive operation then becomes rotating the translation vector using the quaternion, since it implies a quaternion to 3x3 matrix conversion and a matrix vector multiplication but still not as many operations as the regular matrix multiplication.
You only need to apply rotation and scale to the translation, I think, because of the nature of translation, a skew in 4D, rather than being a linear transform in 3D, and in any case it makes sense when you think of the translation vector as being in the space of the rotated and scaled axes.

I am leaving SIMD viability as an exercise for later.

### #14Dmytry  Members

Posted 22 January 2013 - 12:04 PM

You could have a transformation that rotates by 45 degrees, then scales the x axis by a half, then rotates back. This transformation can not be represented with scaling vector, it happens along an axis that is at 45 degrees.

For the rotation and translation, your transform is like

V'=rotation*V+translation

and for two transforms, it is

V'=rotation2*(rotation1*V+translation1)+translation2

or

V'=rotation2*rotation1*V + rotation2 * translation1 + translation2

so you multiply your rotations and you add translations after multiplying the earlier translation by the later rotation.

The multiplication by rotation here means rotating by a quaternion, i.e. represents Q*a*~Q where ~ is inverse.

### #15Kwizatz  Members

Posted 24 January 2013 - 06:02 PM

Hi Dmytry,

I am not sure I follow, what do you mean? in the end what my SRT operations do is a simplified matrix multiplication, so if you take S,R,and T as matrices with scale, rotation and translation respectively, and I as identity the operation you describe would be something along these lines:

( I * R * I ) * (S * I * I) * ( I * *R * I ),

which is the same as RSR, wouldn't the scale vector (diagonal) on the second matrix be doing the scale on world axes rather than object axes as well?

I think I see where you're going, but I haven't had time to think more about it.

The second part of your post, I am not sure if you're pointing out a (another?) problem or providing me with an optimization

### #16RobTheBloke  Members

Posted 27 January 2013 - 02:34 PM

He seems to be saying that you should always use matrices because RSR cannot be represented by SRT, which is simply not true. SRT * SRT * SRT can represent RSR just fine, not to mention the fact that your DCC package is going to be authoring data in SRT anyway, so why bother worrying about an edge case that will never happen?

### #17Kwizatz  Members

Posted 28 January 2013 - 10:47 AM

I see, that's what I though, I am still in need of some time to reassess non uniform scaling, but with uniform scaling it seems fine to just multiply the scaling factors, since scale would be the same in all directions.

And yes, this is going to handle mostly DCC'ed meshes and animations, the 'optimization' in fact came about because of how I was doing animation interpolation.

Thanks again!

### #18Álvaro  Members

Posted 28 January 2013 - 10:53 AM

Just drop non-uniform scaling: The notion of what constitutes a non-uniform scaling is not an intrinsic feature of the transform (in other words, it depends on the coordinate system used), which is the root of a lot of problems. I don't know what people use non-uniform scalings for anyway.

### #19RobTheBloke  Members

Posted 28 January 2013 - 01:02 PM

If you want to take account of non-uniform scaling, you can simply do the following:

transform = [S] * [R] * [IS] * [T]

Where IS is the inverse parent scale, which is pretty much all that most dcc packages do....

Certainly maya applies that transformation for all joint nodes, but geometry leaf transforms usually just use a plain SRT.

I don't know what people use non-uniform scalings for anyway.

Speak to an animator, and they usually find a million reasons to support it. A common trick is to apply non-uniform scale on leaf transforms within a skinned mesh to prevent collapsing elbows, or to simulate the effect of muscles bulging. I've even seen rigs that have made use of excessive amounts of animated scaling for classic-cartoon-like squash and stretch. It does have its uses, which is why animators make so much use of it in maya et-al. A seasoned animator in the games industry may not use it at all, but that's usually due to them having been pre-conditioned to not use scaling on pain of death, not because it has no use.

Edited by RobTheBloke, 28 January 2013 - 01:11 PM.

### #20Álvaro  Members

Posted 28 January 2013 - 03:13 PM

I bet animators could also make use of shearing transformations, which just means that they should be given access to general affine transformations, not just movements (rotation + translation) or a combination of movements and uniform scalings. The only problem with that is what to do about interpolations.

Old topic!

Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.