Skip to content

Conversation

@erikscott128
Copy link

Current Situation

Currently users can only define custom inertia parallel to the body axes of a RigidBody3D node. That is, the inertia's principle axes are assumed to be aligned with the body axes, and only the principle moments of inertia (Ixx, Iyy, Izz) can be defined.

Improvements Made

This branch adds the ability to set the off diagonal products of inertia (Iyz, Ixz, Ixy) such that the entire local inertia tensor can be defined without the ability for the user to accidentally define an invalid, non-symmetrical matrix. The functionality is implemented for both the GodotPhysics3D and Jolt Physics engines. Behavior in each engine has been shown to be identical. The products of inertia are ordered (Iyz, Ixz, Ixy). If combined with the on-axis inertia value, the 6-element array is consistent with Voigt notation for representing symmetric tensors.

Benefits

Bodies with non-zero products of inertia will respond differently to external moments. For instance, applying a pure x-axis moment to a body with non-zero Ixz and/or Ixy values will result in rotation not purely about the x-axis. This allows for realistic behavior of physics objects, such as vehicles, with one or more off-axis inertia terms.

Implementation Details

The products of inertia are passed to GodotBody3D or JoltBody3D in the same way as the on-axis inertia. In the Jolt engine, a full local inertia tensor is already provided as part of the Mass Properties object, and the inertia values need only be set to the correct elements. In the Godot physics engine, this functionality had to be added. A local inertia tensor object now exists within the GodotBody3D class and the inertia values are assigned to the proper elements. This matrix is then decomposed into its eigenvalues (principle moments of inertia) and eigenvectors (principle axes of inertia) for use within the existing Godot implementation. The algorithm for this was copied from the Jolt physics engine library but modified to use Godot's Vector3 and Basis classes. The algorithm is an implementation of the Jacobi eigenvalue algorithm, which only works for real-symmetric matrices.

The appropriate doc .xml files have been updated to reflect the new product_of_inertia field, and the addition of BODY_PARAM_PROD_INERTIA to the BodyParam enum.

Anticipated Discussion Points

  • I chose to implement the "alternate" convention, where the products of inertia are negated before being inserted into the tensor. This may be controversial. See https://en.wikipedia.org/wiki/Moment_of_inertia#Inertia_tensor for more info.
  • The eigen_value_symmetric function is currently implemented in a new, separate file. This should probably be moved to either the Basis class as a method, or to the math_funcs.h/.cpp files. I defer this decision to someone more familiar with how Godot is and should be laid out. It duplicates the diagonalize method already present in the Basis class, except that it also returns the eigenvalues, which are necessary.

Added UI inputs for product of inertia
Initial jolt implementation of products of inertia
Products of inertia have been added and implemented for both GodotPhysics3D and JoltPhysics engines.
Added documentation for the Product of Inertia parameter in RigidBody3D
Remove unused `use_products_of_inertia` flag. Added enum to doc.
Updated the file header for eigen_value_symmetric.h to the proper Godot format.
Vector3 principal_inertia = Vector3();

// Compute the principal axes and moments of inertia.
eigen_value_symmetric(inertia_tensor_local, principal_inertia_axes_local, principal_inertia);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function can fail. Better check the return value and decide what to do. Use a fallback inertia of some sorts, e.g. set the principal_inertia_axis_local to identity and use _inv_inertia = inertia.inverse().

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good idea. I'd like to have it throw a warning when that happens so that the user is aware of it. What's the proper way to do that?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see people use WARN_PRINT (there are more similar macros in the file where that comes from)

Cleanup of code using clang-format
Added protection to the eigenvalue/vector calculation such that, if it fails, the principal axes revert to the body-aligned frame, and the on-axis moments of inertia are used.
Added warning if unable to find principle axes. Updated #define name to GODOT_EVS_ROTATE. Included math_funcs library and added Math namespace to abs functions.
Added `BIND_ENUM_CONSTANT(BODY_PARAM_PROD_INERTIA);` to `PhysicsServer3D`. Updated RigidBody3D.xml to put product_of_inertia in proper alphabetical order.
@erikscott128
Copy link
Author

Could someone help me understand the remaining error I seem to be having the the automatic checks?

New enum must be added to end of list (but before max). Doc updated.
@erikscott128
Copy link
Author

Thanks for the feedback and help so far guys (and I apologize for my ignorance. This really is my first time formally contributing to an open project like this).

There are some remaining things I want to actually discuss regarding final implementation:

  1. I chose to use the "alternate" convention for expressing the products of inertia in which the values are calculated as positive integrals and then negated when placed in the inertia tensor. I'm willing to be overruled here and, in fact, I'm beginning to question if I made the right decision. I'd like others' feedback here.
  2. For my application, I will likely be modifying the mass properties every time step as fuel is burned. It is inefficient to set the inertia vector, and then the products of inertia vector separately as the eigen decomposition calculation will have to be performed twice. Ideally, I'd like a "set_all_mass_properties" function exposed to GDScript in which I can enter the mass, center of mass, and full inertia in one step to eliminate redundant calculations. It would probably be enough to just have a "set_full_inertia" function, but setting the inertia and center of mass separately will still result in redundant calls to _update_transform_dependent. How do people feel about adding such functions?
  3. Does anyone have any strong opinions on where the eigen_value_symmetric function belongs? Should it remain in its own header file, or be moved to math_funcs.

Finally, I recently happened across issue #80703. This is something I hope to address in a future pull request once I'm finished with this one, but it's something I wanted to bring to people's attention. Should we chose to properly implement Euler's rigid body equations (something I will very much push for) I believe there's performance that could be gained by not computing the principle axes of inertia at all and instead only relying on the local inertia tensor. The entire scope of work would have to be identified, but I understand this would not be a trivial change. However, this pull request would lay the groundwork for that effort.

Changed the order in which the enum entries are bound to reflect new order.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants