To store or not to store (matrices & vectors)

Started by
4 comments, last by Zipster 15 years, 8 months ago
Dev'rs: How are others storing data like Position, Direction vs a matrix within an entity? Another words, do ppl tend to... 1) store a world matrix and pull position/rotation from that and calculate the direction? 2) store vectors of pos/dir and calculate a world matrix on render? Or... another way? P.S. I'm fully aware you're probably using an object/user matrix rather than a world matrix, but lets just simplify things for now. Thanks Jeff.
Advertisement
A Frame (co-ordinate frame) stores a position in a ModelSpace::Point3 vector instance and an orientation in a ModelSpace::Rotation3 (implementing a quaternion) instance; in fact, it is a bit more complex than said, but in principle it is sufficient for the understanding. The said parameters are given w.r.t the next super-ordinated co-ordinate frame, so they are called "local" in the following. A const Frame::GLOBAL instance denotes the world frame.

A Frame furthur holds 2 AffineMap instances, 1 as localMap and 1 as globalMap. AffineMap is a homogeneous 4x4 matrix under the hood, but is aware of the special properties of translation and rotation w.r.t. a matrix. So it can compose and decompose matrices in a (more-or-less) efficient way.

The localMap is given in local co-ordinates, the globalMap in global co-ordinates. A Frame refers to its super-ordinated Frame, and also to its sub-ordinated Frames. When a Frame's (local) parameters are changed, then both its localMap and its globalMap are marked being dirty. Furthurmore, the "dirtyness" is propagated to all sub-ordinated Frames. This models a parenting geometry dependency graph.

When e.g. a Frame's globalMap is requested, perhaps due to set-up of a rendering, then the globalMap is returned if it isn't dirty. Otherwise the globalMap is computed first: The localMap is composed from the local position and orientation if needed, so that the dirtyness of the localMap is cleaned. Then the globalMap of the super-ordinated frame is requested, multiplied with the localMap, yielding in the own new globalMap with a clean state. Notice please that requesting the super-ordinated Frame's globalMap means actually a recursion.

Hence, there is both elemental and composed storage, also both in local and global spaces. A dependency graph allows to propagate the dirty state, and to clean the state later on. Notice that the one mechanism is a push, and the other is a pull. This minimizes state changes.
haegarr,

Thanks for your reply.

I understand what you're saying about the matrices and it makes sense. However, you are then implying your vectors (pos/rotation/scale) are always up-to-date... is this correct? So your matricies will always be updating (if dirty). So you never manipulate the local/global matrix for any given "Frame". Is this correct?

Do you maintain a direction vector as well?

Thanks
BTW: Although I don't deal with scaling at this level, it can be handled like the other properties as well.

The position and orientation define where the Frame is located and how it is orientated w.r.t. its super-ordinated Frame. They are fields that of course can be altered. E.g. things that I call Modifiers (and Animation is one of them, namely a time based Modifier) actually alter such things. Modifies are "active" in this sense, and the position and orientation are "passive". So yes, they can be understood as always being in a clean state.

An exception is if the localMap and/or globalMap are allowed to be altered directly. I actually allow this, but I neglected this detail since it makes things even more complex. Since animation and such stuff are normally altering only the elemental parts of a frame, I think that it may suffice for most purposes if the maps are only altered internally by Frame itself.
haegarr,

Very interesting. So, let me ask you this. Do you have ways to place a "Frame" anywhere in the world regardless of parent orientation? Another words, do you have something like SetGlobalPos() & SetLocalPos() where SetGlobalPos would calculate it's frame's position from a subtraction of the parent frame - new global pos = local pos?

Thanks again
To answer your original question, our engine stores both the source data (what haegarr refers to as elemental data) such as position and orientation, as well as the composed matrices. We use a "dirty hierarchy" similar to what haegarr described in order to determine when the matrices should be updated based on the changing elemental values. This solution provides the best of both worlds -- up-to-date transformation matrices that are only generated when they have to be, plus easy manipulation of source data such as position, orientation, scale, etc.

To answer your last question, if an object is attached to a [non-world] parent then it doesn't make as much sense to set its global position/orientation, since it's implied that it should really only care about its position/orientation relative to the parent object to which it's attached. However, for the sake the generality and flexibility you could certainly have such a method. All you need to do is transform the world position/orientation into local position/orientation by going down the hierarchy. So let's say you have object hierarchy A->B->C->D where A is in world-space and B is a child of A, C is a child of B, etc., and you want to set the world position of D. To take a world vector 'P' from world-space to A's space, you multiply it by the inverse of A's local-to-world transform (which would be a world-to-local transform), MA-1. To go from A's space to B's space, you then multiply by the inverse of B's transform. You keep going until you've transformed into C's space. The final transform should look like MC-1MB-1MA-1P.

This topic is closed to new replies.

Advertisement