Page 3 of 4

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 4:14 am
by snoozbuster
Before I make the video, I had an idea. When I was detailing my troubles to my modeler, he asked if I could "parent" objects, like he does to create the rotation of my blasted machine. I thought for a moment, and proceeded to wonder about CompoundBody. If I joined all my objects into a CompoundBody, could I still access each individual roller and rotate it, or are they merged into one mesh (more or less)? Is there anything supporing such functionality? If I could get all of my models to rotate as one entity, but then still allow access to each roller, that would, in theory, solve my problem.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 4:17 am
by Norbo
A CompoundBody is a single entity rigidly composed of multiple shapes. While you can technically alter the local transforms of the shapes after the fact, it is not efficient and will teleport the shapes rather than move them with velocities. In other words, collision response won't work properly and they won't behave like rollers anymore.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 4:18 am
by snoozbuster
Bother. I guess I'll have to make that video.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 4:22 am
by Norbo
You could, however, create your own 'parenting' scheme. The process isn't fundamentally different from what you're already doing, but it may be conceptually helpful and more intuitive. The idea is just to have a tree of transforms, kind of like in a character animation system. The transforms give you the goal position/orientation each frame. You use an EntityMover/EntityRotator (or do what they do directly) to reach the state goals with velocity.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 5:09 am
by snoozbuster
You said transforms and something came to mind. If I set all the rollers at the center, and then multiplied by WorldTransform to translate them, would that work...? Well, wait. That wouldn't work with the velocity. Never mind.

Tree of transforms? How would that work?

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 5:39 am
by Norbo
Imagine an animated character with bones. Each bone is parented to another bone. When a parent moves, so do all of its children.

This is implemented by every bone having a relative transform. You can change these relative transforms over time to animate the character.

For example, you have a character with a partial bone structure of shoulder -> elbow -> wrist. Ignoring multi-bone weight mesh skinning, assume most vertices in the upper arm are parented to the shoulder transform. Most vertices in the forearm are parented to the elbow transform. Most vertices in the hand are parented to the wrist transform.

To find out where a vertex in the hand ends up:
1) Transform the vertex by the wrist transform.
2) Transform the wrist(vertex) result by the elbow transform.
3) Transform the elbow(wrist(vertex)) result by the shoulder transform.
...N) And so on, to the root of the tree.

At the end of this process, you have the location of that vertex in world space (or perhaps animated character space, if you plan on doing another transform later to position and orient it in the world).

Equivalently, you can create your own hierarchy to control the rollers which emulates an animated character. You probably don't need to create a full-fledged animation system or create a rig in Maya or anything since the tree will be shallow and simple.

Instead of an arm, we have the machine. The rollers are like the hands. They have a relative transform that changes over time to make them roll (a local lengthwise rotation transform). The roller is parented to another bone, perhaps a fixed translation offset. That bone is parented to a root bone whose transform rotates over time.

If we perform all the transformations:
1) Roll the roller around its length in its local space.
2) Translate the roller by (X,0,0) or whatever it needs to be.
3) Rotate the result by the rotating core bone's transformation.

Since we roll first, translate, and then rotate last, the final world space result is the roller spinning around its local axis while swinging around some other origin.

Evaluate this tree of transforms every frame after modifying the relative transforms according to your desired animation (rollers rolling, spinner... spinning). This transformation evaluation procedure results in a position and orientation. This is the goal state. You can tell an EntityMover and EntityRotator to target the goal position and orientation and they will handle the conversion of the goal state into velocities. Or, you can compute and apply the velocities yourself.

Again, this is fundamentally the same as what you were already trying to do, but it may be a more intuitive way of thinking about it.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 6:02 am
by snoozbuster
Norbo wrote: If we perform all the transformations:
1) Roll the roller around its length in its local space.
2) Translate the roller by (X,0,0) or whatever it needs to be.
3) Rotate the result by the rotating core bone's transformation.
I'm terrible with bones and such, but let's see if I can translate your steps into something less generic.
0.5?) Unmultiply WorldTransform by the arbitrary value in step 3.
1) Get a Quaternion representing rotation around the length (something like GetAngularVelocity(Orientation, pi/2, 2 * dt) but returning early with the Quaternion)
2) Multiply WorldTransform by some arbitrary value, then find linear velocity to the next circular point.
3) Concatenate Step 1 with another Quaternion which is the Quaternion of the angular velocity I already have.
4) Get the AngularVelocity from Orientation to the Quaternion in step 3.
5) Set Linear- and AngularVelocity.

I don't think I've got step 2 quite right, but I think I have the idea. Am I close?

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 6:50 am
by Norbo
The approach I laid out isn't actually abstracted; you can apply it directly.

In the following, you're just dealing with pure transformations. You don't need to look at the entity's state- we are computing the entity's goal state directly from the animation.

Start with the desired transform in local space.
Apply the roll transform.
Apply the translation transform.
Apply the spin transform.
(Optionally apply some final transform to position/orient it in the world.)

(**Note, I'm making certain assumptions about the situation here. If something doesn't seem to fit, that could be because I don't know the full situation and just picked something that seemed reasonable with what information was available.)

The result is a goal world transform, a position and orientation. The velocities needed to reach that new state from the current state can be computed by the EntityMover/Rotator. Just tell them the goal state.

There's two main conceptual differences here. The first is that we've split the transforms into an explicit order (the 'tree') that might be easier to handle. The second is that we're animating our transforms and having the entity follow it, rather than incrementally building on the previous entity state.

In a way, it's like following a curve, but instead of a curve, an 'animation' defines the motion. This animation can be of the form "the relative transform of rollers advances 2 radians per second, the spin transform advances 0.5 radians per second." Such procedural animation can be a lot simpler than a curve since you don't need to define keyframes or provide much information.

The advantage of not incrementally building upon previous entity states is that you don't have to worry about position drift or anything like that. The entities go right to their goal states every frame and you have total control over the motion.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 7:11 am
by snoozbuster
Oh, okay... So I'm dealing purely with matrices until I extract the position and orientation from it. That makes more sense. Let's see, now I have to think about how I can do that. It seems like I'll still have to keep track of where I am, if only to build the matrix. And I assume I'd have to start at Identity, apply local rotation (such as the roller's rotation to orient along a different axis) via CreateRotationZ, apply length-wise rotation via CreateRotationX (or Y), apply offset via Matrix.CreateTranslation, apply rotation via CreateRotationZ, apply translation to get to the proper space, decompose, set goals? That makes sense to me, do I have it this time?

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 7:17 am
by Norbo
That sounds about right.

Technically, the transforms can be done on separated position and rotations, but it will probably be easier to just use the unified Matrix and decompose at the end (as you wrote).

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 7:41 am
by snoozbuster
That sounds a whole lot easier for my linear-algebra-deprived mind to handle. Matrices are far easier to think about, at least in XNA terms, than vectors. They have lots of helper functions that do exactly what they say. =D I guess they did matrices in precalc 1, which I tested through... Just out of curiousity, is linear algebra a seperate course, or is it part of calc (or precalc)? I'll test this tomorrow and get back to you. It is time to dream of le code.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 7:59 am
by Norbo
Just out of curiousity, is linear algebra a seperate course, or is it part of calc (or precalc)?
Typically, from what I've heard of and seen in American universities, it's a separate course that comes after a couple of calculus classes in university. Sometimes the later portions of calculus touch on vectors and such, usually in regards to multivariable calculus. Linear algebra doesn't really require calculus, though.

Sometimes, Linear Algebra classes are about a bunch of matrix solving and transformations, and other times you might see a dose of more abstract stuff. The links in this thread go into great depth about it: http://bepu.nfshost.com/forum/viewtopic.php?f=4&t=1442

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 7:17 pm
by snoozbuster
Norbo wrote:Sometimes, Linear Algebra classes are about a bunch of matrix solving and transformations, and other times you might see a dose of more abstract stuff. The links in this thread go into great depth about it: http://bepu.nfshost.com/forum/viewtopic.php?f=4&t=1442
I read that the other day. When I saw the link, I thought "I bet that's that one thread." =p

So, I'm closer, I think. My tubes currently fly off in the direction of the offset, and I'm not sure why. I must be applying the offset twice somehow. Here's what I've got.

EDIT: Fixed that. Using the current position didn't work, I changed newOrientation *= Matrix.CreateTranslation(t.ModelPosition) to newOrientation *= Matrix.CreateTranslation(t.Origin), which is the original position of that roller. However, the offset doesn't seem to be applied correctly, because when the objects rotate they end up on the same axis. I think I'm doing the curve.Evaluate part wrong, or maybe the LinearVelocity?
Also, OriginalOrientation is what aligns the roller to either X or Y, depending. It's either 0 or 90 degrees.

Code: Select all

foreach(Tube t in tubeList)
{
    newOrientation = Matrix.Identity;

    // Makes sense to do this first so as to avoid if testing for axis orientation after.
    if(t.Rotating)
        newOrientation *= Matrix.CreateRotationY(MathHelper.TwoPi * BaseGame.space.TimeStepSettings.TimeStepDuration);

    // rotate to new axis
    newOrientation *= Matrix.CreateFromQuaternion(t.OriginalOrientation);
    // Apply offset (currently m.Ent.OrientationMatrix.Right times a scalar)
    // The offset seems to not apply to the rotation afterwards, because things offset on Y originally
    // that look fine proceed to have a staggered position afterwards, as if the offset was applied after.
    newOrientation *= Matrix.CreateTranslation(t.LocalOffset);

    // Rotate for the spinny machine
    newOrientation *= Matrix.CreateFromQuaternion(curve.Evaluate(pathTime));

    // Move to position
    newOrientation *= Matrix.CreateTranslation(t.Origin);
    newOrientation.Decompose(out scale, out rotation, out translation);

    t.Ent.AngularVelocity = GetAngularVelocity(t.Ent.Orientation, rotation, BaseGame.space.TimeStepSettings.TimeStepDuration);

    // Maybe this is wrong?
    t.Ent.LinearVelocity = Vector3.Cross(t.Ent.AngularVelocity, t.LocalOffset) +         
        ((translation - t.Ent.Position) * 0.2f / (float)BaseGame.space.TimeStepSettings.TimeStepDuration);
}
It must be something fairly simple that I'm missing, but I can't place it. Other that that, it already works and takes a lot less to think about. =p

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 9:23 pm
by Norbo
Just use an EntityMover/EntityRotator, or do what they do internally, rather than trying to create your own linear velocity from cross products and error correction. You already computed the position goal, so all you need to do is compute the velocity needed to reach it from the current position. It's the same idea as getting the angular velocity from two orientations, but much simpler: (goal - currentPosition) / dt.

Re: Rotate with an offset

Posted: Tue Nov 15, 2011 9:32 pm
by snoozbuster
I made a couple of edits while you replied. I have to get on le bus, but I'll see if I can get what you're talking about to work. Using (translation - t.Origin) * dt just causes some position drift and doesn't actually rotate them at all. Maybe I'm doing the translation wrong...?