Attention: Here be dragons
This is the latest
(unstable) version of this documentation, which may document features
not available in or compatible with released stable versions of Godot.
Checking the stable version of the documentation...
Using Jolt Physics
Introduction
The Jolt physics engine was added as an alternative to the existing Godot Physics physics engine in 4.4. Jolt is developed by Jorrit Rouwe with a focus on games and VR applications. Previously it was available as a extension but is now built into Godot.
It is important to note that the built-in Jolt Physics module is considered not finished, experimental, and lacks feature parity with both Godot Physics and the Godot Jolt extension. Behavior may change as it is developed further. Please keep that in mind when choosing what to use for your project.
The existing extension is now considered in maintenance mode. That means bug fixes will be merged, and it will be kept compatible with new versions of Godot until the built-in module has feature parity with the extension. The extension can be found here on GitHub and in Godot's asset library.
To change the 3D physics engine to be Jolt Physics, set
Project Settings > Physics > 3D > Physics Engine
to Jolt Physics
. Once you've done that, click the Save & Restart button.
When the editor opens again, 3D scenes should now be using Jolt for physics.
Notable differences to Godot Physics
There are many differences between the existing Godot Physics engine and Jolt.
Area3D and static bodies
When using Jolt, Area3D will not detect overlaps with StaticBody3D
(nor a RigidBody3D frozen with FREEZE_MODE_STATIC
) by default, for
performance reasons. If you have many/large Area3D overlapping with
complex static geometry, such as ConcavePolygonShape3D or
HeightMapShape3D, you can end up wasting a significant amount of CPU
performance and memory without realizing it.
For this reason this behavior is opt-in through the project setting Physics > Jolt Physics 3D > Simulation > Areas Detect Static Bodies, with the recommendation that you set up your collision layers and masks in such a way that only a few small Area3D are able to detect collisions with static bodies.
Joint properties
The current interfaces for the 3D joint nodes don't quite line up with the interface of Jolt's own joints. As such, there are a number of joint properties that are not supported, mainly ones related to configuring the joint's soft limits.
The unsupported properties are:
PinJoint3D:
bias
,damping
,impulse_clamp
HingeJoint3D:
bias
,softness
,relaxation
SliderJoint3D:
angular_\*
,\*_limit/softness
,\*_limit/restitution
,\*_limit/damping
ConeTwistJoint3D:
bias
,relaxation
,softness
Generic6DOFJoint3D:
*_limit_*/softness
,*_limit_*/restitution
,*_limit_*/damping
,*_limit_*/erp
Currently a warning is emitted if you set these properties to anything but their default values.
Single-body joints
You can, in Godot, omit one of the joint bodies for a two-body joint and effectively
have "the world" be the other body. However, the node path that you assign your body
to (node_a vs node_b)
is ignored. Godot Physics will always behave as if you
assigned it to node_a
, and since node_a
is also what defines the frame of reference
for the joint limits, you end up with inverted limits and a potentially strange
limit shape, especially if your limits allow both linear and angular degrees of
freedom.
Jolt will behave as if you assigned the body to node_b
instead, with node_a
representing "the world". There is a project setting called Physics > Jolt Physics 3D > Joints > World Node
that lets you toggle this behavior, if you need compatibility for an existing project.
Collision margins
Jolt (and other similar physics engines) uses something that Jolt refers to as
"convex radius" to help improve the performance and behavior of the types of
collision detection that Jolt relies on for convex shapes. Other physics engines
(Godot included) might refer to these as "collision margins" instead. Godot exposes
these as the margin
property on every Shape3D-derived class, but Godot Physics
itself does not use them for anything.
What these collision margins sometimes do in other engines (as described in Godot's documentation) is effectively add a "shell" around the shape, slightly increasing its size while also rounding off any edges/corners. In Jolt however, these margins are first used to shrink the shape, and then the "shell" is applied, resulting in edges/corners being similarly rounded off, but without increasing the size of the shape.
To prevent having to tweak this margin property manually, since its default value can be problematic for smaller shapes, the Jolt module exposes a project setting called Physics > Jolt Physics 3D > Collisions > Collision Margin Fraction which is multiplied with the smallest axis of the shape's AABB to calculate the actual margin. The margin property of the shape is then instead used as an upper bound.
These margins should, for most use-cases, be more or less transparent, but can
sometimes result in odd collision normals when performing shape queries. You can
lower the above mentioned project setting to mitigate some of this, including
setting it to 0.0
, but too small of a margin can also cause odd collision results,
so is generally not recommended.
Baumgarte stabilization
Baumgarte stabilization is a method to resolve penetrating bodies and push them to a state where they are just touching. In Godot Physics this works like a spring. This means that bodies can accelerate and may cause the bodies to overshoot and separate completely. With Jolt, the stabilization is only applied to the position and not to the velocity of the body. This means it cannot overshoot but it may take longer to resolve the penetration.
The strength of this stabilization can be tweaked using the project setting
Physics > Jolt Physics 3D > Simulation > Baumgarte Stabilization Factor.
Setting this project setting to 0.0
will turn Baumgarte stabilization off.
Setting it to 1.0
will resolve penetration in 1 simulation step. This is fast
but often also unstable.
Ghost collisions
Jolt employs two techniques to mitigate ghost collisions, meaning collisions with internal edges of shapes/bodies that result in collision normals that oppose the direction of movement.
The first technique, called "active edge detection", marks edges of triangles in ConcavePolygonShape3D or HeightMapShape3D as either "active" or "inactive", based on the angle to the neighboring triangle. When a collision happens with an inactive edge the collision normal will be replaced with the triangle's normal instead, to lessen the effect of ghost collisions.
The angle threshold for this active edge detection is configurable through the project setting Physics >Jolt Physics 3D > Collisions > Active Edge Threshold.
The second technique, called "enhanced internal edge removal", instead adds runtime checks to detect whether an edge is active or inactive, based on the contact points of the two bodies. This has the benefit of applying not only to collisions with ConcavePolygonShape3D and HeightMapShape3D, but also edges between any shapes within the same body.
Enhanced internal edge removal can be toggled on and off for the various contexts to which it's applied, using the Physics >Jolt Physics 3D > Simulation > Use Enhanced Internal Edge Removal, project setting, and the similar settings for queries and motion queries.
Note that neither the active edge detection nor enhanced internal edge removal apply when dealing with ghost collisions between two different bodies.
Memory usage
Jolt uses a stack allocator for temporary allocations within its simulation step. This stack allocator requires allocating a set amount of memory up front, which can be configured using the Physics > Jolt Physics 3D > Limits > Temporary Memory Buffer Size project setting.
Ray-cast face index
The face_index
property returned in the results of intersect_ray()
and RayCast3D will by default always be -1
with Jolt. The project setting Physics > Jolt Physics 3D > Queries > Enable Ray Cast Face Index
will enable them.
Note that enabling this setting will increase the memory requirement of ConcavePolygonShape3D with about 25%.
Kinematic RigidBody3D contacts
When using Jolt, a RigidBody3D frozen with FREEZE_MODE_KINEMATIC will by default not report contacts from collisions with other static/kinematic bodies, for performance reasons, even when setting a non-zero max_contacts_reported. If you have many/large kinematic bodies overlapping with complex static geometry, such as ConcavePolygonShape3D or HeightMapShape3D, you can end up wasting a significant amount of CPU performance and memory without realizing it.
For this reason this behavior is opt-in through the project setting Physics > Jolt Physics 3D > Simulation > Generate All Kinematic Contacts.
Contact impulses
Due to limitations internal to Jolt, the contact impulses provided by PhysicsDirectBodyState3D.get_contact_impulse() are estimated ahead of time based on things like the contact manifold and velocities of the colliding bodies. This means that the reported impulses will only be accurate in cases where the two bodies in question are not colliding with any other bodies.
Area3D and SoftBody3D
Jolt does not currently support any interactions between SoftBody3D and Area3D, such as overlap events, or the wind properties found on Area3D.
WorldBoundaryShape3D
WorldBoundaryShape3D, which is meant to represent an infinite plane, is implemented a bit differently in Jolt compared to Godot Physics. Both engines have an upper limit for how big the effective size of this plane can be, but this size is much smaller when using Jolt, in order to avoid precision issues.
You can configure this size using the Physics > Jolt Physics 3D > Limits > World Boundary Shape Size project setting.
Notable differences to the Godot Jolt extension
While the built-in Jolt module is largely a straight port of the Godot Jolt extension, there are a few things that are different.
Project settings
All project settings have been moved from the physics/jolt_3d
category to
physics/jolt_physics_3d
.
On top of that, there's been some renaming and refactoring of the individual project settings as well. These include:
sleep/enabled
is nowsimulation/allow_sleep.
sleep/velocity_threshold
is nowsimulation/sleep_velocity_threshold.
sleep/time_threshold
is nowsimulation/sleep_time_threshold.
collisions/use_shape_margins
is nowcollisions/collision_margin_fraction
, where a value of 0 is equivalent to disabling it.collisions/use_enhanced_internal_edge_removal
is nowsimulation/use_enhanced_internal_edge_removal.
collisions/areas_detect_static_bodies
is nowsimulation/areas_detect_static_bodies.
collisions/report_all_kinematic_contacts
is nowsimulation/generate_all_kinematic_contacts.
collisions/soft_body_point_margin
is nowsimulation/soft_body_point_radius.
collisions/body_pair_cache_enabled is now simulation/body_pair_contact_cache_enabled.
collisions/body_pair_cache_distance_threshold
isnow simulation/body_pair_contact_cache_distance_threshold.
collisions/body_pair_cache_angle_threshold is now simulation/body_pair_contact_cache_angle_threshold.
continuous_cd/movement_threshold
is nowsimulation/continuous_cd_movement_threshold
, but expressed as a fraction instead of a percentage.continuous_cd/max_penetration
is nowsimulation/continuous_cd_max_penetration
, but expressed as a fraction instead of a percentage.kinematics/use_enhanced_internal_edge_removal
is nowmotion_queries/use_enhanced_internal_edge_removal.
kinematics/recovery_iterations
is nowmotion_queries/recovery_iterations
, but expressed as a fraction instead of a percentage.kinematics/recovery_amount
is nowmotion_queries/recovery_amount.
queries/use_legacy_ray_casting
has been removed.solver/position_iterations
is nowsimulation/position_steps.
solver/velocity_iterations
is nowsimulation/velocity_steps.
solver/position_correction
is nowsimulation/baumgarte_stabilization_factor
, but expressed as a fraction instead of a percentage.solver/active_edge_threshold
is nowcollisions/active_edge_threshold.
solver/bounce_velocity_threshold
is nowsimulation/bounce_velocity_threshold.
solver/contact_speculative_distance
is nowsimulation/speculative_contact_distance.
solver/contact_allowed_penetration
is nowsimulation/penetration_slop.
limits/max_angular_velocity
is now stored as radians instead.limits/max_temporary_memory
is nowlimits/temporary_memory_buffer_size.
Joint nodes
The joint nodes that are exposed in the Godot Jolt extension (JoltPinJoint3D, JoltHingeJoint3D, JoltSliderJoint3D, JoltConeTwistJoint3D, and JoltGeneric6DOFJoint) have not been included in the Jolt module.
Thread safety
Unlike the Godot Jolt extension, the Jolt module does have thread-safety, including support for the Physics > 3D > Run On Separate Thread project setting. However this has not been tested very thoroughly, so it should be considered experimental.