Calculating relative transforms from absolute ones

Started by
9 comments, last by Sneftel 15 years, 1 month ago
I'm in the middle of a project in which I have a number of hierarchically defined objects that are loaded by parsing a file which contains position, rotation, and scale data for the objects in either absolute or relative coordinates. What I need to do is convert the absolute coordinates into relative ones before I store the data. This used to work fine because I only treated the position and rotation elements as hierarchical, but I've since decided to make scale hierarchical also. The information available consists of the transformation matrix for the parent and position, rotation, and scale data for its child each in either relative or absolute format. Relative data is simply stored, but how do I go about converting the absolute data properly, taking into account the arbitrary translation, rotation, and scale of the parent? I'm assuming I'll need to pull out the parent's data by decomposing the matrix, but I'm getting confused by the order of the individual transformations which means I can't simply calculate relative position, for example, as absolute position minus parent's decomposed position, because scales will mess this up. I'd appreciate a simple explanation of any solutions given. I'd really like to get a better understanding of the problem. Thanks, Andy
Advertisement
If you have transformations T1 and T2, the relative transformation Tr from T1 to T2:

T1 * Tr = T2
T1-1 * T1 * Tr = T1-1 * T2
Tr = T1-1 * T2
First, the composition of a matrix from the 3 particular transformations is usually something like (using column vectors here)
Mi := T * R * S
where T denotes the translation, R the rotation, and S the scaling. (It is perhaps more complex like the transformation stuff of X3D, but from the OP it seems that the above is all.) You're right when you assume that computing the particular transformations from the composite matrix requires a decomposition.

Now, If you have given a "absolute" transformation at level N, it is originally computed as
M := M0 * M1 * ... * MN
The transformation another level below is then obviously
M' := MN * MN+1
and hence
MN-1 * M'
= MN-1 * MN * MN+1
= MN+1
so that the relative matrix at level N+1 is
MN+1 = MN-1 * M'
computed as the product of the inverse absolute matrix of the parental level with the own absolute matrix.


EDIT: Ah, again too late ;)
But I don't have access to T2 (or M'), do I?

I have T1, the parent's transform. I also have data for position, rotation, and scale, but some of this data is relative, and some is absolute. For instance a relative scale and rotation, but an absolute position. Can I calculate T2 from this? If not, how do I derive Tr?
It's hard to tell from your description... you don't make clear what exactly it is you're trying to do, or what is relative to what. For instance, it would be very strange to have relative rotations and scales but absolute translations, because there's little of use one could get out of performing a bunch of concatenated rotations and scales at the origin. What are the EXACT rules of the data you're getting in, and what are the EXACT rules of the data you need to produce?
Okay, I'm reading in data for each object which is stored in an xml file and, as its human editable, can contain absolute or relative translations, rotations, and scales at each stage of the hierarchy. I'd like to make it possible for people to provide data in both formats and mix them arbitrarily because that seems like it would be easier to work with like that.

When I say "relative" I mean "relative to my parent object" of which all objects can have only one. When I say "absolute" I mean "absolute within the hierarchy's space". This is only a problem while parsing hierarchies in. At run time each object contains a relative translation, rotation, and scale that are used to build a transformation matrix for the object hierarchically on a frame by frame basis, much as described by haegarr. The problem is with converting the parsed data into something I can use at run time.

As each object in the hierarchy is read in I calculate its parent's transformation by taking the position, rotation, and scale of each ancestor object, building a transformation matrix from it, and then passing that down to its direct descendent which builds its own relative transform and applies that to the passed transform. When I've calculated all the way down the tree to the parent of the object I'm currently parsing I've therefore got a valid (parse time) absolute transformation matrix for that parent object.

I read in the current object's TRS data and would like to store it as relative values from the parent's transform, so it can used at run time to recalculate object states from frame to frame. Because I'm allowing the person editing the file to provide some of the values as absolutes, however, I need to change any data that's been flagged as absolute to relative before it can be stored. That's the bit I'm stuck on.

Thanks for the help,
Andy
Okeydoke. So to clarify, specifying an absolute transformation component at some node in the hierarchy will discard the contributions to that component from all that node's ancestors?

It sounds, then, like the only real issue is calculating the absolute transformations for each node. Tossing out translation and replacing it with a new translation is trivial (just overwrite the fourth column), but teasing apart scale and rotation can be difficult. It's also an area in which you may not have fully considered the ramifications of the design, if nonuniform scalings are allowed. Consider a hierarchy which applies, in order from the root to the leaf, a rotation of +45 around the Z axis, followed by a nonuniform scaling of 2 in the X axis only, followed by a rotation of -45 around the Z axis. The result is an object which appears skewed along the Y axis. If you create a child which has an absolute scaling of 1, is it still skewed? If you create a child which has an absolute rotation of 0, is it still skewed?
Your clarification is correct.

Your raise an excellent point with the example you gave as non-uniform scaling is certainly valid (I'm actually only working in 2D here, so all rotations are always around the z axis only). I think I'm after a result that would be unskewed, as that would work best with sprites. If an absolute scale of (1, 1) was given, the result should ignore all previous scaling data, so I suppose it could be calculated by rebuilding the parent transformation ignoring all scales and applying the absolute scale to the resulting matrix? Is there a more efficient way?

Edit: Ah, no that didn't work at all :( And it wouldn't thinking about it. If I had an object rotated to 90 degrees and a child object with a relative translation of (10, 0) and relative rotation of 0 I'd expect the child to be drawn at 0, 10 and rotated 90 degrees (child translation is relative to parent rotation). If the child had a child with a relative translation of 0 and an absolute rotation of 0 I'd expect it to be drawn at the same place as the origin child but unrotated, not at (10, 0) unrotated as it would be if I ignored the original rotation, so what exactly am I after?

[Edited by - Stumpeh on March 11, 2009 7:00:07 PM]
Quote:Original post by Stumpeh
If an absolute scale of (1, 1) was given, the result should ignore all previous scaling data, so I suppose it could be calculated by rebuilding the parent transformation ignoring all scales and applying the absolute scale to the resulting matrix?

No. Consider a node with a scaling of 2, with a child with a relative translation of 5,0, with a child with an absolute scaling of 1 and a relative translation of 0. Ignoring all scaling would cause the object to appear at 5,0 instead of 10,0 (which is where its parent would be). Your edit is another example of how simply ignoring that component in the ancestry isn't sufficient.

Anyways, ignoring all scaling, replacing the rotation is easy: just replace the upper-left 3x3 (or 2x2 in the 2D case) submatrix. The resultant translation will be left alone, since it will be safely in the last column at that point.

Adding in uniform scaling, things are still pretty simple. You can extract the scaling factor as the norm of any of the first columns, and divide the upper-left submatrix by that number in order to cancel it out (then multiply by any other scaling factor you'd want). Replacing the rotation while maintaining the scaling is similar: Find the scaling factor, replace with new unscaled rotation, apply scaling to submatrix only.

Nonuniform scaling: You're on your own. You may want to disallow nonuniform scaling except at leaves... in real life it is very strange to see it anywhere else.
I was afraid you'd say that :) So does anyone know if what I'm trying to do with the non-uniform scales is mathematically viable, or am I barking up completely the wrong tree? I suspect I'm going to have to fall back to hierarchical transformations and rotations with absolute scaling factors applied after the hierarchy has been calculated at every level. Not the end of the world by any means.

Thanks very much for your time, both of you. Much appreciated and it's given me a bit of a deeper understanding of what I'm trying to do.

This topic is closed to new replies.

Advertisement