Attaching two objects and changing their world matrices accordingly

I'm having a hard time wrapping my head around the transformations required to bind two objects together in either a two-way or one-way relationship. I will need to implement both types.

For the first case, I want to be able to 'couple' two ships together in space. The ships have different mass, of course. Forces applied to either ship will use combined mass and moment of inertia to calculate and move both ships. The trick is, being sure that the point at which they are coupled remains the same, and they don't move at all relative to each other.

The second case is similar: I want a ship to be able to enter the atmosphere of a planet and move relative to the planet. The planet will be orbiting the sun, which is fixed at 0,0,0. Essentially, when the ship is sitting still outside of the atmosphere, the planet will move past it on its course-- but when the ship is sitting still inside the atmosphere, it moves and rotates with the planet, so that it is always relative to the horizon. Essentially, the vertices which make up the ship are now transformed just like the ones that make up the planet, except that the ship can move itself around relative to the planet.

I get the feeling I can implement both of these with the same code. Essentially, I am thinking of giving each object (which I call Fixtures) a list of "slave" Fixtures onto which that Fixture's world matrix is imposed. So, this would be the planet imposing its world on any contained ships. In the case of coupling, I would simply make each ship a slave of the other, somehow.

Obviously I can't just multiply the ship's world matrix by the planet's, or each ship by the others. What I'd like some help with is what calculations to make in order to get a nice, seamless relative world to the other object. I was thinking maybe I could just multiply the world of the slave by the inverse of the master, but then when you couple two ships you would lose all that world data. So, perhaps I need an intermediate "world" which is the absolute world, but use a secondary "final world" to actually transform the objects?

-

In a typical hierarchy situation, the child transform offers relative rotation & translational differences from the parent transform. In your case, a ship may be a child to another ship, or it may be a child to a planet. So for 1st case, let's say shipB is joining shipA. They are positioned correctly where they will be joined. Prior to joining, they both have their own independent transforms. After joining, shipB becomes a child of shipA.

``````    //this occurs at joining:
Vector3 offset = shipB.transform.Translation - shipA.transform.Translation;//creates a global space offset
offset = Vector3.Transform(offset, Matrix.Invect(shipA.transform)); // converts offset to shipA's local space.

shipB.transform = Matrix.Identity; // shipB offers no rotation relative to shipA.
shipB.Translation = offset;

//when drawing shipA:
effect.World = shipA.transform;

//when drawing shipB:
effect.World = shipA.transform * shipB.transform; //typical parent/child concatenation in a row major transform API like Xna.
/*
since shipB's transform's rotational section (the 3x3 rotation section) is the identity matrix, it will not rotate B relative to A,
but will offset translation per shipA's local rotation
*/
``````

When removing the joint to allow both ships to fly freely on their own:

``````shipB.transform = shipA.transform;
Vector3 currentOffset = (shipA.transform.Right    * offset.X) +
(shipA.transform.Up       * offset.Y) +
(shipA.transform.Backward * offset.Z);
shipB.transform.Translation += currentOffset;

//draw shipA
effect.Worls = shipA.transform;

//draw shipB
effect.World = shipB.transform; // no longer a child.
``````

For planet to ship relationship, it is similar to joining shipB to shipA but each frame, the ship can maneuver.

``````//this occurs at joining:
Vector3 offset = ship.transform.Translation - planet.transform.Translation;//creates a global space offset
offset = Vector3.Transform(offset, Matrix.Invect(planet.transform)); // converts offset to planet's local space.

ship.transform = Matrix.Identity;
ship.Translation = offset;

//each frame you would manipulate the ship's matrix thusly:
ship.transform.Translation += ship.transform.Forward * velocity * elapsedTime; // or whatever

//then when drawing planet:
effect.World = planet.transform;

//when drawing ship:
effect.World = planet.transform * ship.transform; //back to a parent/child concatenation here
``````
-
Thank you, this is very informative! In this case, the ship-ship joining would be a child-parent relationship, which might not be ideal, but will work. I intend to allow both joined ships to use their thrusters to move the joined mass, will this be possible? I am intending to allow the player to attach his ship to a set of generators, thrusters, weapons, or a combination of them to boost the power of his ship by controlling them. Would this be doable with a child/parent relationship, and would it be as simple as applying objects' forces on both objects? Anyways, I'll begin implementing this. – A-Type Jun 26 '12 at 14:09
Yes, it is possible. Forces such as thrust act on the CG of the ship. The CG is not always in alignment with the matrix's position value anyway so often you must have offsets. When the ships join, determine CG offset from shipA. While it used to be in the center of A (probably), it is now probably somewhere in between A & B depending on mass differences. Any force (A or B thrusters) acts upon that CG and causes linear/rotational affects on shipA's matrix only. ShipB inherits that affect during concatenation. – Steve H Jun 26 '12 at 14:48
Ah, the inheritance was something I didn't think of. I imagine I will have to recalculate the inertia tensor as well if I want to keep things realistic, but since as you said the rotation is inherited and the same for both fixtures, I won't have to worry about one rotating differently than the other even if I don't (the new coupled group just won't 'feel' as bulky as it looks). I think my CG calculations are already ready for this change. You've done a good job making this understandable, thank you. Accepted and +1 :) – A-Type Jun 26 '12 at 17:33