Rotating parts of compound body

Discuss any questions about BEPUphysics or problems encountered.
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Rotating parts of compound body

Post by tomweiland »

So I'm currently working on making my ship's sail adjustable, which includes changing its angle relative to the rest of the ship. In order to do this, I need to rotate the top beam that it's attached to. Since players can walk on said beam, I need to rotate its collider along with the visual representation.

Is there a way to rotate a single part of a compound body without affecting the rest of it? If not, I'm guessing the best alternative will be to give the beam its own body and use some sort of constraint to keep it in place?

I also need to be able to rotate colliders for cannons, as well as the rudder.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

You could adjust the relevant CompoundChild's pose (and, if it's a BigCompound, refit or update the Tree) and then update the inertia tensor for the new configuration, but modifying a shape is equivalent to teleportation as far as the solver is concerned. If anything is physically interacting with the shapes when they change, the resulting collisions will be squishy and weird.

If there's any kind of physical interaction going on, I'd recommend just making them separate bodies and connecting them together with constraints.
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

What's the best way of achieving positional behavior like what you get if you make a body part of a compound, but with constraints?

I have a body which I'd like to rotate around its local Y axis only and keep in the same local position (restrict all linear movement compared to the main ship's compound body), but I'm not sure which constraint type (or combo of constraints) would be the best way of making this happen.

I was looking at the AngularHinge and thought that might take care of the rotational aspect of what I'm trying to do, but then I noticed that the parameters are LocalHingeAxes instead of Offsets like I'd initially assumed (probably because the main constraint I've used is the PointOnLineServo, which has offsets).

As always, your help and input is very much appreciated!
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

The Hinge constraint would be the best bet. The AngularHinge handles the same angular degrees of freedom as the Hinge, but doesn't handle the linear degrees of freedom. An AngularHinge combined with a BallSocket would be equivalent to a Hinge in terms of degrees of freedom, but using a Hinge is preferred because it can solve all five degrees of freedom directly for greater robustness.

The Hinge and AngularHinge will try to keep LocalHingeAxisA/B pointing in the same direction in world space. That gives the connected object one remaining angular degree of freedom (around the world hinge axis).
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

So I switched to the Hinge constraint, which I was initializing like so:

Code: Select all

new Hinge()
{
    LocalHingeAxisA = Vector3.UnitY,
    LocalHingeAxisB = Vector3.UnitY,
    LocalOffsetA = transform.localPosition,
    LocalOffsetB = Vector3.Zero,
    SpringSettings = new SpringSettings(10, 1)
};
But after adding it to the simulation's Solver, my ship started to spin quite quickly. Then I switched the values I was assigning to the local offsets, and the ship stopped spinning, but the second collider started orbiting the ship.

I'm not sure if the Hinge constraint is the right thing for my situation after all (unless I'm using it wrong). I need BodyA (the ship) to move like normal, while BodyB should spin around its origin (not BodyA's origin) while also having an offset position from BodyA. BodyA would ideally not receive any forces from the constraint, as I only want to "attach" BodyB to BodyA as if it were part of the compound, while retaining rotational freedom around one axis. I'm not sure if that makes sense, maybe I'll have to draw it out to explain it better, but is this possible with any single constraint?

Is there maybe a way to disable rotation around two of the local axes without a 2-body constraint? Then all I'd need was a constraint that restricts movement along all three linear axes (does that exist?).
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

But after adding it to the simulation's Solver, my ship started to spin quite quickly. Then I switched the values I was assigning to the local offsets, and the ship stopped spinning, but the second collider started orbiting the ship.
It's hard to say exactly what's wrong, but this does sound like a constraint misconfiguration. Is Vector3.UnitY the correct direction for both connected bodies in their respective local spaces? Is transform.localPosition correct in context?
BodyA would ideally not receive any forces from the constraint, as I only want to "attach" BodyB to BodyA as if it were part of the compound, while retaining rotational freedom around one axis.
In order for the constraint-based approach to have similar whole system angular behavior, the constraint needs to apply forces to both bodies. If it didn't, the combined system would behave as though the connected subbody had zero inertia, or an otherwise physically inconsistent inertia tensor. You could reduce the connected body's mass relative to the main body if you want it to have less effect in either case.

I would recommend against any approach that controls the motion of a body without an equal and opposite reaction somewhere, since that's how you get Gordon Freeman flying away on a tiny plank.
I'm not sure if that makes sense, maybe I'll have to draw it out to explain it better, but is this possible with any single constraint?
I may be missing something, but it still sounds like the Hinge is what you want.
Is there maybe a way to disable rotation around two of the local axes without a 2-body constraint? Then all I'd need was a constraint that restricts movement along all three linear axes (does that exist?).
You can set rows of the inverse inertia to zero, but if I understand your goal, that's not going to produce the desired behavior. The BallSocket constrains three linear degrees of freedom.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

Here's a little snippet of what I suspect is close to what you're doing:

Code: Select all

                var shipShape = new Box(4, 3, 10);
                shipShape.ComputeInertia(10, out var shipInertia);
                var spinnyShape = new Box(1, 1, 1);
                spinnyShape.ComputeInertia(0.5f, out var spinnyInertia);
                var a = Simulation.Bodies.Add(BodyDescription.CreateDynamic(new Vector3(0, 3, 10), shipInertia, new CollidableDescription(Simulation.Shapes.Add(shipShape), 0.1f), activity));
                var b = Simulation.Bodies.Add(BodyDescription.CreateDynamic(new Vector3(0, 5, 10 - 3.5f), spinnyInertia, new CollidableDescription(Simulation.Shapes.Add(spinnyShape), 0.1f), activity));
                Simulation.Solver.Add(a, b, new Hinge
                {
                    LocalHingeAxisA = Vector3.UnitY,
                    LocalHingeAxisB = Vector3.UnitY,
                    LocalOffsetA = new Vector3(0, 2f, -3.5f),
                    LocalOffsetB = new Vector3(0, 0, 0),
                    SpringSettings = new SpringSettings(30, 1)
                });
Could the transform.LocalPosition be in the 'design' local space, rather than local to the constructed body's center of mass?
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

Norbo wrote: Sat Jan 11, 2020 6:21 pm Is Vector3.UnitY the correct direction for both connected bodies in their respective local spaces?
UnitY is <0,1,0>, but to be honest I'm not sure what the "correct" direction would/should be...
Norbo wrote: Sat Jan 11, 2020 6:21 pm Is transform.localPosition correct in context?
transform.localPosition is where I want the spinning body to be positioned in the ship's local coordinate system.
Norbo wrote: Sun Jan 12, 2020 6:25 pm Here's a little snippet of what I suspect is close to what you're doing:
That looks about right.
Norbo wrote: Sun Jan 12, 2020 6:25 pm Could the transform.LocalPosition be in the 'design' local space, rather than local to the constructed body's center of mass?
Not entirely sure what you mean by "design local space", but what effect would it have if the center of mass differs from the ship model's origin point? I think the two match up (or are at least very close) because I gave the compound's child body which is at the center of the model the most weight, precisely to accomplish this.
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

UnitY is <0,1,0>, but to be honest I'm not sure what the "correct" direction would/should be...
The LocalHingeAxis is the axis around which the body can rotate in its local space, so supposing you wanted it to rotate around (0,1,0) in design space and the body has an identity orientation, then (0,1,0) would be fine. But if the body's orientation was pitched to the side by 90 degrees, then using (0,1,0) as the local axis would yield a design space rotation of (1,0,0) or some other direction 90 degrees off.

If you have a target axis in a reference frame and you know the body's orientation in that reference frame, you can transform the target axis by the inverse of the body's orientation to get the local axis that matches the target axis.
Not entirely sure what you mean by "design local space", but what effect would it have if the center of mass differs from the ship model's origin point? I think the two match up (or are at least very close) because I gave the compound's child body which is at the center of the model the most weight, precisely to accomplish this.
By "design local space" I mean the reference frame in which the compound was put together. It won't match the final body's local space if recentering is used.

A constraint with a target offset of design origin->attachment point will try to move the attached body so that ship center of mass->connected body anchor is the same as design origin->attachment point. If the design origin and center of mass are not exactly the same, this might result in the connected body floating away from the surface it's supposed to be on, or being shunted forward or back, or in the worst case, shoved into the ship's body. If it's shoved into the ship's body, the resulting contact constraints and hinge will fight. Depending on involved inertia tensors, lever arms, constraint stiffnesses, timestep durations, and solver iterations, the solver might be unable to reach equilibrium and energy could be introduced. Common outcomes for this kind of issue are spinning out of control, shaking violently, or exploding.

Notably, large lever arms relative to the 'size' of the inertia tensor makes things harder to solve. If the child body that was given the bulk of the ship's mass is small and the inertia tensor was constructed from the weighted body contributions, then the ship will have a much smaller inertia than would be expected for the ship's extent. Constraints that are connected to the ship far from its center of mass will have a long lever arm relative to the inertia, making them harder to solve.
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

Norbo wrote: Mon Jan 13, 2020 7:36 pm If the design origin and center of mass are not exactly the same, this might result in the connected body floating away from the surface it's supposed to be on, or being shunted forward or back, or in the worst case, shoved into the ship's body.
Is there a way I can check where the design origin and center of mass are relative to each other?
Norbo wrote: Mon Jan 13, 2020 7:36 pm Common outcomes for this kind of issue are spinning out of control, shaking violently, or exploding.
This doesn't sound like what's happening. I uploaded a devlog video the other day, at 5:49 you can see exactly how the attached object (the capstan, represented by the cyan cube) is moving. At 3:29 you have a good view of the capstan's model (the thing with the 4 handles sticking out) which is where I want the collider to be positioned. The ship model's origin is below deck, in line with the mast on the x and z axes.
Norbo wrote: Mon Jan 13, 2020 7:36 pm If the child body that was given the bulk of the ship's mass is small and the inertia tensor was constructed from the weighted body contributions, then the ship will have a much smaller inertia than would be expected for the ship's extent. Constraints that are connected to the ship far from its center of mass will have a long lever arm relative to the inertia, making them harder to solve.
So would you suggest not giving one part of the compound a much larger mass than is appropriate based on it's proportional size? If I want my ship to have a specific mass (say, 500), what would be the best way to go about distributing that properly without doing a bunch of tedious calculations (or would that be the only way)?
Also, on a slightly different note, how many children warrant the use of a BigCompound? Currently the ship consists of 123 primitive colliders, but I expect that number to increase further (although not too much).
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

Is there a way I can check where the design origin and center of mass are relative to each other?
If using the CompoundHelper, the Build* functions that output a "center" are the ones that do recentering, and that parameter tells you what center it computed.

The overload that does not output a center performs no recentering and leaves the children in exactly the same relative position as they were added in. That original state generally won't be the 'true' center of mass in terms of the input shapes/weights, but sometimes that's desirable.
This doesn't sound like what's happening. I uploaded a devlog video the other day, at 5:49 you can see exactly how the attached object (the capstan, represented by the cyan cube) is moving. At 3:29 you have a good view of the capstan's model (the thing with the 4 handles sticking out) which is where I want the collider to be positioned. The ship model's origin is below deck, in line with the mast on the x and z axes.
The previous part of that video showing the ship spinning wildly is the kind of thing I was talking about. The part at 5:49 swapped the offsets, which resulted in the capstan's local offset being the design origin to the capstan, which means the capstan tries to be below the ship. It's no longer conflicting with the body of the ship and is actually functioning as configured, which here means it's orbiting undersea.
So would you suggest not giving one part of the compound a much larger mass than is appropriate based on it's proportional size? If I want my ship to have a specific mass (say, 500), what would be the best way to go about distributing that properly without doing a bunch of tedious calculations (or would that be the only way)?
The easiest thing to do is just to scale the final resulting inertia. The body weights would then be only meaningful in a relative sense. You could compute the weights based on the shapes' volumes, but I wouldn't worry too much about a perfect distribution- eyeballing it tends to work fine. Many games have used the inertia tensor of complex shapes' bounding boxes and it works out okay. Just need to avoid pathological cases like a tank with the rotational inertia of a shrew.

A change in mass by a factor of X scales the components of the inertia tensor by a factor of X. Suppose you created a compound whose weights added up to a mass of 5 and you instead wanted a mass of 10, you'd scale the mass and inertia tensor by a factor of 2. Since the body inertia stores inverse mass and inertia, you'd scale them by 1/2.

In other words:

Code: Select all

var inverseInertiaScale = 1 / (targetMass * bodyInertia.InverseMass);
bodyInertia.InverseMass *= inverseInertiaScale;
Symmetric3x3.Scale(bodyInertia.InverseInertiaTensor, inverseInertiaScale, out bodyInertia.InverseInertiaTensor);
Also, on a slightly different note, how many children warrant the use of a BigCompound? Currently the ship consists of 123 primitive colliders, but I expect that number to increase further (although not too much).
There is no hard threshold- depends on the kinds and layout of bodies- but 123 is pretty solidly in the realm where I'd expect BigCompound to be a better choice. I'd expect the cutoff to usually be somewhere in the 4 to 16 child range, depending on the context.
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

Norbo wrote: Tue Jan 14, 2020 1:10 am The overload that does not output a center performs no recentering and leaves the children in exactly the same relative position as they were added in. That original state generally won't be the 'true' center of mass in terms of the input shapes/weights, but sometimes that's desirable.
This is what I'm using, so I guess the two should match up.
Norbo wrote: Tue Jan 14, 2020 1:10 am The previous part of that video showing the ship spinning wildly is the kind of thing I was talking about. The part at 5:49 swapped the offsets, which resulted in the capstan's local offset being the design origin to the capstan, which means the capstan tries to be below the ship. It's no longer conflicting with the body of the ship and is actually functioning as configured, which here means it's orbiting undersea.
I'm kind of confused. If it's behaving as intended in the clip, I'm obviously misunderstanding something about how to set it up in a way where it does what I want (which I suspected was the case from the get-go). If for example I wanted the collider to rotate around its local Y axis and to be locked in place at <0,1,1> in the ship's local space, what do I need to set the offsets to?
Norbo wrote: Tue Jan 14, 2020 1:10 am There is no hard threshold- depends on the kinds and layout of bodies- but 123 is pretty solidly in the realm where I'd expect BigCompound to be a better choice. I'd expect the cutoff to usually be somewhere in the 4 to 16 child range, depending on the context.
I just realized I'm already using a BigCompound :lol:
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

If for example I wanted the collider to rotate around its local Y axis and to be locked in place at <0,1,1> in the ship's local space, what do I need to set the offsets to?
Provided you want the anchor of the constraint to be at the capstan's center of mass, and assuming the ship is body A, then LocalOffsetA would be <0, 1, 1> and LocalOffsetB would be <0, 0, 0>.

The snippet I posted earlier shows a complete configuration.

It's worth noting that the Hinge's LocalOffsetA and LocalOffsetB are exactly the same as a BallSocket's LocalOffsetA and LocalOffsetB. Mathematically, the linear degrees of freedom are the same constraint. They can be thought of as rigid rods attached to the body. In the BallSocket and Hinge, the constraint attempts to prevent and recover from any separation between the tips of those rods.
offsets.png
offsets.png (14.08 KiB) Viewed 27332 times
tomweiland
Posts: 99
Joined: Wed May 08, 2019 12:17 am

Re: Rotating parts of compound body

Post by tomweiland »

Norbo wrote: Tue Jan 14, 2020 9:15 pm Provided you want the anchor of the constraint to be at the capstan's center of mass, and assuming the ship is body A, then LocalOffsetA would be <0, 1, 1> and LocalOffsetB would be <0, 0, 0>.
Hmm...so that would mean that initially I had it set it up correctly, but that resulted in the ship spinning around. Does that mean the inertia is the issue (I'll try and fix that now), or might there be something else going on too?
Norbo
Site Admin
Posts: 4929
Joined: Tue Jul 04, 2006 4:45 am

Re: Rotating parts of compound body

Post by Norbo »

A sufficiently small inertia tensor could be at fault, yes. It could also be that the goal position of the capstan is partially embedded in the ship. Stiff constraints fighting each other with a long lever arm relative to inertia could cause tornadoship.
Post Reply