Facepunch / sbox-issues

176 stars 12 forks source link

GetInertia() for physics object #1704

Closed S4TURN21 closed 1 year ago

S4TURN21 commented 2 years ago

Method of getting principal moments of inertia of the physics object, exactly like this one: https://wiki.facepunch.com/gmod/PhysObj:GetInertia

Phyksar commented 2 years ago

I am in need of overriding the object's inertia, please consider implementing this too

S4TURN21 commented 1 year ago

@aylaylay, a year later, still not resolved. Just asking if there will be some solution or I can close this issue as "not planned"?

aylaylay commented 1 year ago

@S4TURN21 Sorry, what's your use case? Just don't want to add onto the API until it's something that's going to be used.

S4TURN21 commented 1 year ago

@aylaylay, it is something that I need to account for to apply angular force to an entity, in order to create rigidbody player controller.

aylaylay commented 1 year ago

We already have functions on physics body to apply angular forces, how come these can't be used?

S4TURN21 commented 1 year ago

@aylaylay, I know that there is methods for applying forces, such as ApplyForce, ApplyForceAt and ApplyTorque. But in order to actually use them you need to calculate and provide value for a force, variable depending on actual use case. For that purpose I need angular inertia in order to calculate valid force. ApplyForce methods are not the topic and isn't the issue.

aylaylay commented 1 year ago

Try ApplyAngularImpulse, it uses inertia internally.

Phyksar commented 1 year ago

@aylaylay In my case I need this to be able to solve contacts for vehicle wheel physics, it's something similar to what Forza Horizon or GTA V are doing. I already have a working sample project in Unity which I switched to when I realized that S&box still has no way to access object's inertia. I don't get why you are so against it, this is a common API for many physics engines, it even was in Garry's Mod Lua API.

aylaylay commented 1 year ago

I'm not against it, we just like to avoid adding things to the API until it's shown it's needed. I'm trying to find out first if what you're trying to do isn't already supported and also find out how you want it supported.

In Rubikon, inertia is a matrix, how would you need this to be represented in the API?

Phyksar commented 1 year ago

Well, I have no way to check Rubikon's API since it's private, although I had assumptions that this could be the problem. Generally, real-time physic engines simplify moment of inertia to a tensor (vector representing components for a scale matrix) and it's rotation. If Rubikon doesn't do that, I think it's okay to just expose this in its original form. Anyway the only way I was planning to use this is to convert tensors back to inertia matrices, I doubt they can be used alone in anyway.

Phyksar commented 1 year ago

I just figured out, that breaking inertia matrix down to tensor and rotation allows to compute inverse of inertia by inverting only its tensor, like that:

invertedInertia = inertiaRotation * (1.0f / inertiaTensor) * inertiaRotation.Transposed

In fact, I was using this code in Unity. Could you please make sure that Rubikon stores inertia as a matrix data and not computing it from tensor?

Phyksar commented 1 year ago

@aylaylay did some digging for a while, now I have some thoughts on how it all can be done. I noticed that S&Box API doesn't define a 3-by-3 matrix, nor .NET does, so the best approach I see would be making things like Unity did:

public Vector3 InertiaTensor { get; set; }
public Rotation InertiaTensorRotation { get; set; }

This forms the inertia matrix by formula I = R * T * R^-1, where T is a scale diagonal matrix of InertiaTensor, R is a rotation matrix of InertiaTensorRotation and R^-1 is an inverted or transposed rotation matrix. You need to decompose inertia matrix to these values as well, this process is described here http://answers.unity.com/answers/1716025/view.html. physx::PxDiagonalize(const PxMat33& m, PxQuat& massFrame) will return inertia tensor and inertia tensor rotation as massFrame.

aylaylay commented 1 year ago

Do you need local or global inertia?

Phyksar commented 1 year ago

@aylaylay InertiaTensorRotation should describe transformation from object's local-space to inertia-space where inertia tensor forms a diagonal matrix, thus it would change only when moment of inertia is recomputed. I can easily obtain world-space inertia with that just by combining PhysicsBody.Rotation and InertiaTensorRotation and using it in inertia matrix fomula.

aylaylay commented 1 year ago

That should be easy enough but I assume you want setters for these which aren't as easy

Phyksar commented 1 year ago

Whats wrong with setters? I was thinking Rubikon's inertia matrix will be recomputed by formula every time the setters are called.

aylaylay commented 1 year ago

I didn't write rubikon, I'm not just going to add this to the API until I know how to do it properly.

aylaylay commented 1 year ago

I've added Inertia and InertiaRotation getters, let me know if this does what you're wanting. I'm not adding setters until this is proven it's needed. The inertia matrix is calculated when setting up mass so I don't see why this would be needed yet.

Phyksar commented 1 year ago

@aylaylay to give you some thoughts why someone would need this - moment of inertia is computed from collision model which primary purpose is to handle collisions fast but it would fail to describe angular motion precisely. There are much more details that affect inertia, for example hollow spaces generally increment inertia, but to model this out you would need to make a lot of pointless collision shapes which would be an overkill for physics engine. Racing sims developers often use inertia measurements taken from specific devices like this and apply them directly without coupling moment of inertia with vehicle collision model. It also will be handy being able to tweak inertia for a simple arcade racing game.

Phyksar commented 1 year ago

@aylaylay tried to spawn a custom entity inherited from ModelEntity and its inertia is empty:

// Right after calling SetupPhysicsFromModel(PhysicsMotionType.Dynamic, false);
08:41:53   Server mass: 7046.533; inertia: 0,0,0; inertia rotation: 0,0,0,1
// After setting up custom mass
08:41:53   Server mass: 600; inertia: 0,0,0; inertia rotation: 0,0,0,1

What should I do for it to be the right way? I see that some map spawned props have inertia precomputed but the values are very low, looks like Rubikon's inertia supposed to be scaled by mass or something?

08:45:10   Server entity Prop 75 - mass: 4; inertia: 0.0032,0.0032,0.0048; inertia rotation: 0,-0.00176,0,1
08:45:10   Server entity Prop 76 - mass: 2; inertia: 0.0068,0.0068,0.0081; inertia rotation: 0,0.00291,0,1
08:45:10   Server entity Prop 77 - mass: 0.5; inertia: 0.101,0.101,0.0507; inertia rotation: 0,0,0.17447,0.98466
aylaylay commented 1 year ago

it's probably the inverse inertia. 1.0f/inertia I'll rework it

aylaylay commented 1 year ago

It should now give you sane values