Having trouble with transform math for RigidBody.ApplyForce(), how do I calculate the thrust vector?


So the concept is you have a parent entity representing a spaceship, and child entities that represent thrusters/engines. The script on the parent entity finds all the child engines, and if they are “firing” it uses RigidBody.ApplyForce(Vector3 thrust, Vector3 localOffset) to add the engine’s force to the spaceship momentum.

Sounded easy enough. Start with a Vector3 with the magnitude of the engine’s power, rotate it by the engine’s world-space rotation quaternion, and there’s your thrust vector. Then the localOffset is just the local translation between the parent ship and the child engine. So when firing the thruster (from the parent entity):

// Start with engine local-space vector with magnitude of engine power.
var forceVector = engine.Entity.Transform.LocalMatrix.Forward * power;

// HOW TO ROTATE??? Things I've tried:

// Attempt 1: Probably not world-space?
engine.Entity.Transform.Rotation.Rotate(ref forceVector); 

// Attempt 2: Trying to get world-space engine quaternion
var rot = engine.Entity.Transform.Rotation;
engine.Entity.Transform.LocalToWorld(..., ref Quaternion rot, ...);
rot.Rotate(ref forceVector);

// Attempt 3: Trying to get world-space engine quaternion another way?
engine.Entity.Transform.WorldMatrix.Decompose(out _, out Quaternion rot, out _);
rot.Rotate(ref forceVector);

// Attempt 4: Maybe get WorldMatrix forward instead?
forceVector = engine.Entity.WorldMatrix.Forward * power

// Finally, apply the force
physics.ApplyForce(forceVector, engine.Entity.Transform.Position);

All of these produce weird results like only moving forward in world-space, or rotating wildly. Clearly I only have a loose grasp on matrix transforms because there’s probably a really simple way of doing this. Can anyone help point out what I’m doing wrong here?

ApplyImpulse() might be what you are looking for? See the sample … stride/samples/Physics/PhysicsSample at master · stride3d/stride (github.com)

You might also try looking at the docs for other physics engines to get the concepts down … here’s one sample … Using A Physics Engine | Babylon.js Documentation

Not sure what Stride is based on.

I do need to switch to using impulse to account for variable frame rates. I’ll make the switch but I don’t think it’s related to the problem.

I’ll go over the sample project though, thanks!

Okay, I figured it out. I was often calculating the force vector correctly, but was thrown off because the offset is in world space, though it’s relative to your position.

// Calc force, factoring in frame rate
var power = engine.CurrentThrottle * engine.Power * (float)time.Elapsed.TotalSeconds;
var forceVector = engine.Entity.Transform.WorldMatrix.Forward * power;

// Calc offset vector in world space. The difference between the ship world space and the engine world space
 var offset = engine.Entity.Transform.WorldMatrix.TranslationVector - 
// Apply force
_physics.Physics.ApplyImpulse(forceVector, offset);