Path: blob/master/modules/jolt_physics/objects/jolt_body_3d.cpp
10278 views
/**************************************************************************/1/* jolt_body_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "jolt_body_3d.h"3132#include "../joints/jolt_joint_3d.h"33#include "../jolt_project_settings.h"34#include "../misc/jolt_math_funcs.h"35#include "../misc/jolt_type_conversions.h"36#include "../shapes/jolt_shape_3d.h"37#include "../spaces/jolt_broad_phase_layer.h"38#include "../spaces/jolt_space_3d.h"39#include "jolt_area_3d.h"40#include "jolt_group_filter.h"41#include "jolt_physics_direct_body_state_3d.h"42#include "jolt_soft_body_3d.h"4344namespace {4546template <typename TValue, typename TGetter>47bool integrate(TValue &p_value, PhysicsServer3D::AreaSpaceOverrideMode p_mode, TGetter &&p_getter) {48switch (p_mode) {49case PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED: {50return false;51}52case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: {53p_value += p_getter();54return false;55}56case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {57p_value += p_getter();58return true;59}60case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: {61p_value = p_getter();62return true;63}64case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {65p_value = p_getter();66return false;67}68default: {69ERR_FAIL_V_MSG(false, vformat("Unhandled override mode: '%d'. This should not happen. Please report this.", p_mode));70}71}72}7374} // namespace7576JPH::BroadPhaseLayer JoltBody3D::_get_broad_phase_layer() const {77switch (mode) {78case PhysicsServer3D::BODY_MODE_STATIC: {79return _is_big() ? JoltBroadPhaseLayer::BODY_STATIC_BIG : JoltBroadPhaseLayer::BODY_STATIC;80}81case PhysicsServer3D::BODY_MODE_KINEMATIC:82case PhysicsServer3D::BODY_MODE_RIGID:83case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {84return JoltBroadPhaseLayer::BODY_DYNAMIC;85}86default: {87ERR_FAIL_V_MSG(JoltBroadPhaseLayer::BODY_STATIC, vformat("Unhandled body mode: '%d'. This should not happen. Please report this.", mode));88}89}90}9192JPH::ObjectLayer JoltBody3D::_get_object_layer() const {93ERR_FAIL_NULL_V(space, 0);9495if (jolt_shape == nullptr || jolt_shape->GetType() == JPH::EShapeType::Empty) {96// No point doing collision checks against a shapeless object.97return space->map_to_object_layer(_get_broad_phase_layer(), 0, 0);98}99100return space->map_to_object_layer(_get_broad_phase_layer(), collision_layer, collision_mask);101}102103JPH::EMotionType JoltBody3D::_get_motion_type() const {104switch (mode) {105case PhysicsServer3D::BODY_MODE_STATIC: {106return JPH::EMotionType::Static;107}108case PhysicsServer3D::BODY_MODE_KINEMATIC: {109return JPH::EMotionType::Kinematic;110}111case PhysicsServer3D::BODY_MODE_RIGID:112case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {113return JPH::EMotionType::Dynamic;114}115default: {116ERR_FAIL_V_MSG(JPH::EMotionType::Static, vformat("Unhandled body mode: '%d'. This should not happen. Please report this.", mode));117}118}119}120121void JoltBody3D::_add_to_space() {122jolt_shape = build_shapes(true);123124JPH::CollisionGroup::GroupID group_id = 0;125JPH::CollisionGroup::SubGroupID sub_group_id = 0;126JoltGroupFilter::encode_object(this, group_id, sub_group_id);127128jolt_settings->mUserData = reinterpret_cast<JPH::uint64>(this);129jolt_settings->mObjectLayer = _get_object_layer();130jolt_settings->mCollisionGroup = JPH::CollisionGroup(nullptr, group_id, sub_group_id);131jolt_settings->mMotionType = _get_motion_type();132jolt_settings->mAllowedDOFs = _calculate_allowed_dofs();133jolt_settings->mAllowDynamicOrKinematic = true;134jolt_settings->mCollideKinematicVsNonDynamic = reports_all_kinematic_contacts();135jolt_settings->mUseManifoldReduction = !reports_contacts();136jolt_settings->mAllowSleeping = is_sleep_actually_allowed();137jolt_settings->mLinearDamping = 0.0f;138jolt_settings->mAngularDamping = 0.0f;139jolt_settings->mMaxLinearVelocity = JoltProjectSettings::max_linear_velocity;140jolt_settings->mMaxAngularVelocity = JoltProjectSettings::max_angular_velocity;141142if (JoltProjectSettings::use_enhanced_internal_edge_removal_for_bodies) {143jolt_settings->mEnhancedInternalEdgeRemoval = true;144}145146jolt_settings->mOverrideMassProperties = JPH::EOverrideMassProperties::MassAndInertiaProvided;147jolt_settings->mMassPropertiesOverride = _calculate_mass_properties();148149jolt_settings->SetShape(jolt_shape);150151JPH::Body *new_jolt_body = space->add_object(*this, *jolt_settings, sleep_initially);152if (new_jolt_body == nullptr) {153return;154}155156jolt_body = new_jolt_body;157158delete jolt_settings;159jolt_settings = nullptr;160}161162void JoltBody3D::_enqueue_call_queries() {163// This method will be called from the body activation listener on multiple threads during the simulation step.164165if (space != nullptr) {166space->enqueue_call_queries(&call_queries_element);167}168}169170void JoltBody3D::_dequeue_call_queries() {171if (space != nullptr) {172space->dequeue_call_queries(&call_queries_element);173}174}175176void JoltBody3D::_integrate_forces(float p_step, JPH::Body &p_jolt_body) {177_update_gravity(p_jolt_body);178179if (!custom_integrator) {180JPH::MotionProperties &motion_properties = *p_jolt_body.GetMotionPropertiesUnchecked();181182JPH::Vec3 linear_velocity = motion_properties.GetLinearVelocity();183JPH::Vec3 angular_velocity = motion_properties.GetAngularVelocity();184185// Jolt applies damping differently from Godot Physics, where Godot Physics applies damping before integrating186// forces whereas Jolt does it after integrating forces. The way Godot Physics does it seems to yield more187// consistent results across different update frequencies when using high (>1) damping values, so we apply the188// damping ourselves instead, before any force integration happens.189190linear_velocity *= MAX(1.0f - total_linear_damp * p_step, 0.0f);191angular_velocity *= MAX(1.0f - total_angular_damp * p_step, 0.0f);192193linear_velocity += to_jolt(gravity) * p_step;194195motion_properties.SetLinearVelocityClamped(linear_velocity);196motion_properties.SetAngularVelocityClamped(angular_velocity);197198p_jolt_body.AddForce(to_jolt(constant_force));199p_jolt_body.AddTorque(to_jolt(constant_torque));200}201}202203void JoltBody3D::_move_kinematic(float p_step, JPH::Body &p_jolt_body) {204p_jolt_body.SetLinearVelocity(JPH::Vec3::sZero());205p_jolt_body.SetAngularVelocity(JPH::Vec3::sZero());206207const JPH::RVec3 current_position = p_jolt_body.GetPosition();208const JPH::Quat current_rotation = p_jolt_body.GetRotation();209210const JPH::RVec3 new_position = to_jolt_r(kinematic_transform.origin);211const JPH::Quat new_rotation = to_jolt(kinematic_transform.basis);212213if (new_position == current_position && new_rotation == current_rotation) {214return;215}216217p_jolt_body.MoveKinematic(new_position, new_rotation, p_step);218}219220JPH::EAllowedDOFs JoltBody3D::_calculate_allowed_dofs() const {221if (is_static()) {222return JPH::EAllowedDOFs::All;223}224225JPH::EAllowedDOFs allowed_dofs = JPH::EAllowedDOFs::All;226227if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)) {228allowed_dofs &= ~JPH::EAllowedDOFs::TranslationX;229}230231if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)) {232allowed_dofs &= ~JPH::EAllowedDOFs::TranslationY;233}234235if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)) {236allowed_dofs &= ~JPH::EAllowedDOFs::TranslationZ;237}238239if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X) || is_rigid_linear()) {240allowed_dofs &= ~JPH::EAllowedDOFs::RotationX;241}242243if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y) || is_rigid_linear()) {244allowed_dofs &= ~JPH::EAllowedDOFs::RotationY;245}246247if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z) || is_rigid_linear()) {248allowed_dofs &= ~JPH::EAllowedDOFs::RotationZ;249}250251ERR_FAIL_COND_V_MSG(allowed_dofs == JPH::EAllowedDOFs::None, JPH::EAllowedDOFs::All, vformat("Invalid axis locks for '%s'. Locking all axes is not supported when using Jolt Physics. All axes will be unlocked. Considering freezing the body instead.", to_string()));252253return allowed_dofs;254}255256JPH::MassProperties JoltBody3D::_calculate_mass_properties(const JPH::Shape &p_shape) const {257const bool calculate_mass = mass <= 0;258const bool calculate_inertia = inertia.x <= 0 || inertia.y <= 0 || inertia.z <= 0;259260JPH::MassProperties mass_properties = p_shape.GetMassProperties();261262if (calculate_mass && calculate_inertia) {263// Use the mass properties calculated by the shape264} else if (calculate_inertia) {265mass_properties.ScaleToMass(mass);266} else {267mass_properties.mMass = mass;268}269270if (inertia.x > 0) {271mass_properties.mInertia(0, 0) = (float)inertia.x;272mass_properties.mInertia(0, 1) = 0;273mass_properties.mInertia(0, 2) = 0;274mass_properties.mInertia(1, 0) = 0;275mass_properties.mInertia(2, 0) = 0;276}277278if (inertia.y > 0) {279mass_properties.mInertia(1, 1) = (float)inertia.y;280mass_properties.mInertia(1, 0) = 0;281mass_properties.mInertia(1, 2) = 0;282mass_properties.mInertia(0, 1) = 0;283mass_properties.mInertia(2, 1) = 0;284}285286if (inertia.z > 0) {287mass_properties.mInertia(2, 2) = (float)inertia.z;288mass_properties.mInertia(2, 0) = 0;289mass_properties.mInertia(2, 1) = 0;290mass_properties.mInertia(0, 2) = 0;291mass_properties.mInertia(1, 2) = 0;292}293294mass_properties.mInertia(3, 3) = 1.0f;295296return mass_properties;297}298299JPH::MassProperties JoltBody3D::_calculate_mass_properties() const {300return _calculate_mass_properties(*jolt_shape);301}302303void JoltBody3D::_on_wake_up() {304// This method will be called from the body activation listener on multiple threads during the simulation step.305306if (_should_call_queries()) {307_enqueue_call_queries();308}309}310311void JoltBody3D::_update_mass_properties() {312if (in_space()) {313jolt_body->GetMotionPropertiesUnchecked()->SetMassProperties(_calculate_allowed_dofs(), _calculate_mass_properties());314}315}316317void JoltBody3D::_update_gravity(JPH::Body &p_jolt_body) {318gravity = Vector3();319320const Vector3 position = to_godot(p_jolt_body.GetPosition());321322bool gravity_done = false;323324for (const JoltArea3D *area : areas) {325gravity_done = integrate(gravity, area->get_gravity_mode(), [&]() {326return area->compute_gravity(position);327});328329if (gravity_done) {330break;331}332}333334if (!gravity_done) {335gravity += space->get_default_area()->compute_gravity(position);336}337338gravity *= gravity_scale;339}340341void JoltBody3D::_update_damp() {342if (!in_space()) {343return;344}345346total_linear_damp = 0.0;347total_angular_damp = 0.0;348349bool linear_damp_done = linear_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;350bool angular_damp_done = angular_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;351352for (const JoltArea3D *area : areas) {353if (!linear_damp_done) {354linear_damp_done = integrate(total_linear_damp, area->get_linear_damp_mode(), [&]() {355return area->get_linear_damp();356});357}358359if (!angular_damp_done) {360angular_damp_done = integrate(total_angular_damp, area->get_angular_damp_mode(), [&]() {361return area->get_angular_damp();362});363}364365if (linear_damp_done && angular_damp_done) {366break;367}368}369370const JoltArea3D *default_area = space->get_default_area();371372if (!linear_damp_done) {373total_linear_damp += default_area->get_linear_damp();374}375376if (!angular_damp_done) {377total_angular_damp += default_area->get_angular_damp();378}379380switch (linear_damp_mode) {381case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {382total_linear_damp += linear_damp;383} break;384case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {385total_linear_damp = linear_damp;386} break;387}388389switch (angular_damp_mode) {390case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {391total_angular_damp += angular_damp;392} break;393case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {394total_angular_damp = angular_damp;395} break;396}397398_motion_changed();399}400401void JoltBody3D::_update_kinematic_transform() {402if (is_kinematic()) {403kinematic_transform = get_transform_unscaled();404}405}406407void JoltBody3D::_update_joint_constraints() {408for (JoltJoint3D *joint : joints) {409joint->rebuild();410}411}412413void JoltBody3D::_update_possible_kinematic_contacts() {414const bool value = reports_all_kinematic_contacts();415416if (!in_space()) {417jolt_settings->mCollideKinematicVsNonDynamic = value;418} else {419jolt_body->SetCollideKinematicVsNonDynamic(value);420}421}422423void JoltBody3D::_update_sleep_allowed() {424const bool value = is_sleep_actually_allowed();425426if (!in_space()) {427jolt_settings->mAllowSleeping = value;428} else {429jolt_body->SetAllowSleeping(value);430}431}432433void JoltBody3D::_destroy_joint_constraints() {434for (JoltJoint3D *joint : joints) {435joint->destroy();436}437}438439void JoltBody3D::_exit_all_areas() {440if (!in_space()) {441return;442}443444for (JoltArea3D *area : areas) {445area->body_exited(jolt_body->GetID(), false);446}447448areas.clear();449}450451void JoltBody3D::_update_group_filter() {452JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;453454if (!in_space()) {455jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);456} else {457jolt_body->GetCollisionGroup().SetGroupFilter(group_filter);458}459}460461void JoltBody3D::_mode_changed() {462_update_object_layer();463_update_kinematic_transform();464_update_mass_properties();465_update_sleep_allowed();466wake_up();467}468469void JoltBody3D::_shapes_committed() {470JoltShapedObject3D::_shapes_committed();471472_update_mass_properties();473_update_joint_constraints();474wake_up();475}476477void JoltBody3D::_space_changing() {478JoltShapedObject3D::_space_changing();479480sleep_initially = is_sleeping();481482_destroy_joint_constraints();483_exit_all_areas();484_dequeue_call_queries();485}486487void JoltBody3D::_space_changed() {488JoltShapedObject3D::_space_changed();489490_update_kinematic_transform();491_update_group_filter();492_update_joint_constraints();493_update_sleep_allowed();494_areas_changed();495}496497void JoltBody3D::_areas_changed() {498_update_damp();499wake_up();500}501502void JoltBody3D::_joints_changed() {503wake_up();504}505506void JoltBody3D::_transform_changed() {507wake_up();508}509510void JoltBody3D::_motion_changed() {511wake_up();512}513514void JoltBody3D::_exceptions_changed() {515_update_group_filter();516}517518void JoltBody3D::_axis_lock_changed() {519_update_mass_properties();520wake_up();521}522523void JoltBody3D::_contact_reporting_changed() {524_update_possible_kinematic_contacts();525_update_sleep_allowed();526wake_up();527}528529void JoltBody3D::_sleep_allowed_changed() {530_update_sleep_allowed();531wake_up();532}533534JoltBody3D::JoltBody3D() :535JoltShapedObject3D(OBJECT_TYPE_BODY),536call_queries_element(this) {537}538539JoltBody3D::~JoltBody3D() {540if (direct_state != nullptr) {541memdelete(direct_state);542direct_state = nullptr;543}544}545546void JoltBody3D::set_transform(Transform3D p_transform) {547JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed to physics body '%s'.", to_string()));548549Vector3 new_scale;550JoltMath::decompose(p_transform, new_scale);551552// Ideally we would do an exact comparison here, but due to floating-point precision this would be invalidated very often.553if (!scale.is_equal_approx(new_scale)) {554scale = new_scale;555_shapes_changed();556}557558if (!in_space()) {559jolt_settings->mPosition = to_jolt_r(p_transform.origin);560jolt_settings->mRotation = to_jolt(p_transform.basis);561} else if (is_kinematic()) {562kinematic_transform = p_transform;563} else {564space->get_body_iface().SetPositionAndRotation(jolt_body->GetID(), to_jolt_r(p_transform.origin), to_jolt(p_transform.basis), JPH::EActivation::DontActivate);565}566567_transform_changed();568}569570Variant JoltBody3D::get_state(PhysicsServer3D::BodyState p_state) const {571switch (p_state) {572case PhysicsServer3D::BODY_STATE_TRANSFORM: {573return get_transform_scaled();574}575case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {576return get_linear_velocity();577}578case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {579return get_angular_velocity();580}581case PhysicsServer3D::BODY_STATE_SLEEPING: {582return is_sleeping();583}584case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {585return is_sleep_allowed();586}587default: {588ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));589}590}591}592593void JoltBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {594switch (p_state) {595case PhysicsServer3D::BODY_STATE_TRANSFORM: {596set_transform(p_value);597} break;598case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {599set_linear_velocity(p_value);600} break;601case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {602set_angular_velocity(p_value);603} break;604case PhysicsServer3D::BODY_STATE_SLEEPING: {605set_is_sleeping(p_value);606} break;607case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {608set_is_sleep_allowed(p_value);609} break;610default: {611ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));612} break;613}614}615616Variant JoltBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {617switch (p_param) {618case PhysicsServer3D::BODY_PARAM_BOUNCE: {619return get_bounce();620}621case PhysicsServer3D::BODY_PARAM_FRICTION: {622return get_friction();623}624case PhysicsServer3D::BODY_PARAM_MASS: {625return get_mass();626}627case PhysicsServer3D::BODY_PARAM_INERTIA: {628return get_inertia();629}630case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {631return get_center_of_mass_custom();632}633case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {634return get_gravity_scale();635}636case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {637return get_linear_damp_mode();638}639case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {640return get_angular_damp_mode();641}642case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {643return get_linear_damp();644}645case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {646return get_angular_damp();647}648default: {649ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));650}651}652}653654void JoltBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {655switch (p_param) {656case PhysicsServer3D::BODY_PARAM_BOUNCE: {657set_bounce(p_value);658} break;659case PhysicsServer3D::BODY_PARAM_FRICTION: {660set_friction(p_value);661} break;662case PhysicsServer3D::BODY_PARAM_MASS: {663set_mass(p_value);664} break;665case PhysicsServer3D::BODY_PARAM_INERTIA: {666set_inertia(p_value);667} break;668case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {669set_center_of_mass_custom(p_value);670} break;671case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {672set_gravity_scale(p_value);673} break;674case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {675set_linear_damp_mode((DampMode)(int)p_value);676} break;677case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {678set_angular_damp_mode((DampMode)(int)p_value);679} break;680case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {681set_linear_damp(p_value);682} break;683case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {684set_angular_damp(p_value);685} break;686default: {687ERR_FAIL_MSG(vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));688} break;689}690}691692void JoltBody3D::set_custom_integrator(bool p_enabled) {693if (custom_integrator == p_enabled) {694return;695}696697custom_integrator = p_enabled;698699if (in_space()) {700jolt_body->ResetForce();701jolt_body->ResetTorque();702}703704_motion_changed();705}706707bool JoltBody3D::is_sleeping() const {708if (!in_space()) {709return sleep_initially;710} else {711return !jolt_body->IsActive();712}713}714715bool JoltBody3D::is_sleep_actually_allowed() const {716return sleep_allowed && !(is_kinematic() && reports_contacts());717}718719void JoltBody3D::set_is_sleeping(bool p_enabled) {720if (!in_space()) {721sleep_initially = p_enabled;722} else {723space->set_is_object_sleeping(jolt_body->GetID(), p_enabled);724}725}726727void JoltBody3D::set_is_sleep_allowed(bool p_enabled) {728if (sleep_allowed == p_enabled) {729return;730}731732sleep_allowed = p_enabled;733734_sleep_allowed_changed();735}736737Basis JoltBody3D::get_principal_inertia_axes() const {738ERR_FAIL_COND_V_MSG(!in_space(), Basis(), vformat("Failed to retrieve principal inertia axes of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));739740if (unlikely(is_static() || is_kinematic())) {741return Basis();742}743744return to_godot(jolt_body->GetRotation() * jolt_body->GetMotionPropertiesUnchecked()->GetInertiaRotation());745}746747Vector3 JoltBody3D::get_inverse_inertia() const {748ERR_FAIL_COND_V_MSG(!in_space(), Vector3(), vformat("Failed to retrieve inverse inertia of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));749750if (unlikely(is_static() || is_kinematic())) {751return Vector3();752}753754return to_godot(jolt_body->GetMotionPropertiesUnchecked()->GetLocalSpaceInverseInertia().GetDiagonal3());755}756757Basis JoltBody3D::get_inverse_inertia_tensor() const {758ERR_FAIL_COND_V_MSG(!in_space(), Basis(), vformat("Failed to retrieve inverse inertia tensor of '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));759760if (unlikely(is_static() || is_kinematic())) {761return Basis();762}763764return to_godot(jolt_body->GetInverseInertia()).basis;765}766767void JoltBody3D::set_linear_velocity(const Vector3 &p_velocity) {768if (is_static() || is_kinematic()) {769linear_surface_velocity = p_velocity;770} else {771if (!in_space()) {772jolt_settings->mLinearVelocity = to_jolt(p_velocity);773} else {774jolt_body->GetMotionPropertiesUnchecked()->SetLinearVelocityClamped(to_jolt(p_velocity));775}776}777778_motion_changed();779}780781void JoltBody3D::set_angular_velocity(const Vector3 &p_velocity) {782if (is_static() || is_kinematic()) {783angular_surface_velocity = p_velocity;784} else {785if (!in_space()) {786jolt_settings->mAngularVelocity = to_jolt(p_velocity);787} else {788jolt_body->GetMotionPropertiesUnchecked()->SetAngularVelocityClamped(to_jolt(p_velocity));789}790}791792_motion_changed();793}794795void JoltBody3D::set_axis_velocity(const Vector3 &p_axis_velocity) {796const Vector3 axis = p_axis_velocity.normalized();797798if (!in_space()) {799Vector3 linear_velocity = to_godot(jolt_settings->mLinearVelocity);800linear_velocity -= axis * axis.dot(linear_velocity);801linear_velocity += p_axis_velocity;802jolt_settings->mLinearVelocity = to_jolt(linear_velocity);803} else {804Vector3 linear_velocity = get_linear_velocity();805linear_velocity -= axis * axis.dot(linear_velocity);806linear_velocity += p_axis_velocity;807set_linear_velocity(linear_velocity);808}809810_motion_changed();811}812813Vector3 JoltBody3D::get_velocity_at_position(const Vector3 &p_position) const {814if (unlikely(!in_space())) {815return Vector3();816}817818const JPH::MotionProperties &motion_properties = *jolt_body->GetMotionPropertiesUnchecked();819const Vector3 total_linear_velocity = to_godot(motion_properties.GetLinearVelocity()) + linear_surface_velocity;820const Vector3 total_angular_velocity = to_godot(motion_properties.GetAngularVelocity()) + angular_surface_velocity;821const Vector3 com_to_pos = p_position - to_godot(jolt_body->GetCenterOfMassPosition());822823return total_linear_velocity + total_angular_velocity.cross(com_to_pos);824}825826void JoltBody3D::set_center_of_mass_custom(const Vector3 &p_center_of_mass) {827if (custom_center_of_mass && p_center_of_mass == center_of_mass_custom) {828return;829}830831custom_center_of_mass = true;832center_of_mass_custom = p_center_of_mass;833834_shapes_changed();835}836837void JoltBody3D::set_max_contacts_reported(int p_count) {838ERR_FAIL_INDEX(p_count, MAX_CONTACTS_REPORTED_3D_MAX);839840if (unlikely((int)contacts.size() == p_count)) {841return;842}843844contacts.resize(p_count);845contact_count = MIN(contact_count, p_count);846847const bool use_manifold_reduction = !reports_contacts();848849if (!in_space()) {850jolt_settings->mUseManifoldReduction = use_manifold_reduction;851} else {852space->get_body_iface().SetUseManifoldReduction(jolt_body->GetID(), use_manifold_reduction);853}854855_contact_reporting_changed();856}857858bool JoltBody3D::reports_all_kinematic_contacts() const {859return reports_contacts() && JoltProjectSettings::generate_all_kinematic_contacts;860}861862void JoltBody3D::add_contact(const JoltBody3D *p_collider, float p_depth, int p_shape_index, int p_collider_shape_index, const Vector3 &p_normal, const Vector3 &p_position, const Vector3 &p_collider_position, const Vector3 &p_velocity, const Vector3 &p_collider_velocity, const Vector3 &p_impulse) {863const int max_contacts = get_max_contacts_reported();864865if (max_contacts == 0) {866return;867}868869Contact *contact = nullptr;870871if (contact_count < max_contacts) {872contact = &contacts[contact_count++];873} else {874Contact *shallowest_contact = &contacts[0];875876for (int i = 1; i < (int)contacts.size(); i++) {877Contact &other_contact = contacts[i];878if (other_contact.depth < shallowest_contact->depth) {879shallowest_contact = &other_contact;880}881}882883if (shallowest_contact->depth < p_depth) {884contact = shallowest_contact;885}886}887888if (contact != nullptr) {889contact->normal = p_normal;890contact->position = p_position;891contact->collider_position = p_collider_position;892contact->velocity = p_velocity;893contact->collider_velocity = p_collider_velocity;894contact->impulse = p_impulse;895contact->collider_id = p_collider->get_instance_id();896contact->collider_rid = p_collider->get_rid();897contact->shape_index = p_shape_index;898contact->collider_shape_index = p_collider_shape_index;899}900}901902void JoltBody3D::reset_mass_properties() {903if (custom_center_of_mass) {904custom_center_of_mass = false;905center_of_mass_custom.zero();906907_shapes_changed();908}909910inertia.zero();911912_update_mass_properties();913}914915void JoltBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {916ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply force to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));917918if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {919return;920}921922jolt_body->AddForce(to_jolt(p_force), jolt_body->GetPosition() + to_jolt(p_position));923924_motion_changed();925}926927void JoltBody3D::apply_central_force(const Vector3 &p_force) {928ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central force to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));929930if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {931return;932}933934jolt_body->AddForce(to_jolt(p_force));935936_motion_changed();937}938939void JoltBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {940ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));941942if (unlikely(!is_rigid()) || p_impulse == Vector3()) {943return;944}945946jolt_body->AddImpulse(to_jolt(p_impulse), jolt_body->GetPosition() + to_jolt(p_position));947948_motion_changed();949}950951void JoltBody3D::apply_central_impulse(const Vector3 &p_impulse) {952ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply central impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));953954if (unlikely(!is_rigid()) || p_impulse == Vector3()) {955return;956}957958jolt_body->AddImpulse(to_jolt(p_impulse));959960_motion_changed();961}962963void JoltBody3D::apply_torque(const Vector3 &p_torque) {964ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply torque to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));965966if (unlikely(!is_rigid()) || custom_integrator || p_torque == Vector3()) {967return;968}969970jolt_body->AddTorque(to_jolt(p_torque));971972_motion_changed();973}974975void JoltBody3D::apply_torque_impulse(const Vector3 &p_impulse) {976ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to apply torque impulse to '%s'. Doing so without a physics space is not supported when using Jolt Physics. If this relates to a node, try adding the node to a scene tree first.", to_string()));977978if (unlikely(!is_rigid()) || p_impulse == Vector3()) {979return;980}981982jolt_body->AddAngularImpulse(to_jolt(p_impulse));983984_motion_changed();985}986987void JoltBody3D::add_constant_central_force(const Vector3 &p_force) {988if (p_force == Vector3()) {989return;990}991992constant_force += p_force;993994_motion_changed();995}996997void JoltBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {998if (p_force == Vector3()) {999return;1000}10011002constant_force += p_force;1003constant_torque += (p_position - get_center_of_mass_relative()).cross(p_force);10041005_motion_changed();1006}10071008void JoltBody3D::add_constant_torque(const Vector3 &p_torque) {1009if (p_torque == Vector3()) {1010return;1011}10121013constant_torque += p_torque;10141015_motion_changed();1016}10171018Vector3 JoltBody3D::get_constant_force() const {1019return constant_force;1020}10211022void JoltBody3D::set_constant_force(const Vector3 &p_force) {1023if (constant_force == p_force) {1024return;1025}10261027constant_force = p_force;10281029_motion_changed();1030}10311032Vector3 JoltBody3D::get_constant_torque() const {1033return constant_torque;1034}10351036void JoltBody3D::set_constant_torque(const Vector3 &p_torque) {1037if (constant_torque == p_torque) {1038return;1039}10401041constant_torque = p_torque;10421043_motion_changed();1044}10451046void JoltBody3D::add_collision_exception(const RID &p_excepted_body) {1047exceptions.push_back(p_excepted_body);10481049_exceptions_changed();1050}10511052void JoltBody3D::remove_collision_exception(const RID &p_excepted_body) {1053exceptions.erase(p_excepted_body);10541055_exceptions_changed();1056}10571058bool JoltBody3D::has_collision_exception(const RID &p_excepted_body) const {1059return exceptions.find(p_excepted_body) >= 0;1060}10611062void JoltBody3D::add_area(JoltArea3D *p_area) {1063int i = 0;1064for (; i < (int)areas.size(); i++) {1065if (p_area->get_priority() > areas[i]->get_priority()) {1066break;1067}1068}10691070areas.insert(i, p_area);10711072_areas_changed();1073}10741075void JoltBody3D::remove_area(JoltArea3D *p_area) {1076areas.erase(p_area);10771078_areas_changed();1079}10801081void JoltBody3D::add_joint(JoltJoint3D *p_joint) {1082joints.push_back(p_joint);10831084_joints_changed();1085}10861087void JoltBody3D::remove_joint(JoltJoint3D *p_joint) {1088joints.erase(p_joint);10891090_joints_changed();1091}10921093void JoltBody3D::call_queries() {1094if (custom_integration_callback.is_valid()) {1095const Variant direct_state_variant = get_direct_state();1096const Variant *args[2] = { &direct_state_variant, &custom_integration_userdata };1097const int argc = custom_integration_userdata.get_type() != Variant::NIL ? 2 : 1;10981099Callable::CallError ce;1100Variant ret;1101custom_integration_callback.callp(args, argc, ret, ce);11021103if (unlikely(ce.error != Callable::CallError::CALL_OK)) {1104ERR_PRINT_ONCE(vformat("Failed to call force integration callback for '%s'. It returned the following error: '%s'.", to_string(), Variant::get_callable_error_text(custom_integration_callback, args, argc, ce)));1105}1106}11071108if (state_sync_callback.is_valid()) {1109const Variant direct_state_variant = get_direct_state();1110const Variant *args[1] = { &direct_state_variant };11111112Callable::CallError ce;1113Variant ret;1114state_sync_callback.callp(args, 1, ret, ce);11151116if (unlikely(ce.error != Callable::CallError::CALL_OK)) {1117ERR_PRINT_ONCE(vformat("Failed to call state synchronization callback for '%s'. It returned the following error: '%s'.", to_string(), Variant::get_callable_error_text(state_sync_callback, args, 1, ce)));1118}1119}1120}11211122void JoltBody3D::pre_step(float p_step, JPH::Body &p_jolt_body) {1123JoltObject3D::pre_step(p_step, p_jolt_body);11241125switch (mode) {1126case PhysicsServer3D::BODY_MODE_STATIC: {1127// Will never happen.1128} break;1129case PhysicsServer3D::BODY_MODE_RIGID:1130case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {1131_integrate_forces(p_step, p_jolt_body);1132} break;1133case PhysicsServer3D::BODY_MODE_KINEMATIC: {1134_update_gravity(p_jolt_body);1135_move_kinematic(p_step, p_jolt_body);1136} break;1137}11381139if (_should_call_queries()) {1140_enqueue_call_queries();1141}11421143contact_count = 0;1144}11451146JoltPhysicsDirectBodyState3D *JoltBody3D::get_direct_state() {1147if (direct_state == nullptr) {1148direct_state = memnew(JoltPhysicsDirectBodyState3D(this));1149}11501151return direct_state;1152}11531154void JoltBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {1155if (p_mode == mode) {1156return;1157}11581159mode = p_mode;11601161if (!in_space()) {1162_mode_changed();1163return;1164}11651166const JPH::EMotionType motion_type = _get_motion_type();11671168if (motion_type == JPH::EMotionType::Static) {1169put_to_sleep();1170}11711172jolt_body->SetMotionType(motion_type);11731174if (motion_type != JPH::EMotionType::Static) {1175wake_up();1176}11771178if (motion_type == JPH::EMotionType::Kinematic) {1179jolt_body->SetLinearVelocity(JPH::Vec3::sZero());1180jolt_body->SetAngularVelocity(JPH::Vec3::sZero());1181}11821183linear_surface_velocity = Vector3();1184angular_surface_velocity = Vector3();11851186_mode_changed();1187}11881189bool JoltBody3D::is_ccd_enabled() const {1190if (!in_space()) {1191return jolt_settings->mMotionQuality == JPH::EMotionQuality::LinearCast;1192} else {1193return !is_static() && jolt_body->GetMotionProperties()->GetMotionQuality() == JPH::EMotionQuality::LinearCast;1194}1195}11961197void JoltBody3D::set_ccd_enabled(bool p_enabled) {1198const JPH::EMotionQuality motion_quality = p_enabled ? JPH::EMotionQuality::LinearCast : JPH::EMotionQuality::Discrete;11991200if (!in_space()) {1201jolt_settings->mMotionQuality = motion_quality;1202} else {1203space->get_body_iface().SetMotionQuality(jolt_body->GetID(), motion_quality);1204}1205}12061207void JoltBody3D::set_mass(float p_mass) {1208if (p_mass != mass) {1209mass = p_mass;1210_update_mass_properties();1211}1212}12131214void JoltBody3D::set_inertia(const Vector3 &p_inertia) {1215if (p_inertia != inertia) {1216inertia = p_inertia;1217_update_mass_properties();1218}1219}12201221float JoltBody3D::get_bounce() const {1222if (!in_space()) {1223return jolt_settings->mRestitution;1224} else {1225return jolt_body->GetRestitution();1226}1227}12281229void JoltBody3D::set_bounce(float p_bounce) {1230if (!in_space()) {1231jolt_settings->mRestitution = p_bounce;1232} else {1233jolt_body->SetRestitution(p_bounce);1234}1235}12361237float JoltBody3D::get_friction() const {1238if (!in_space()) {1239return jolt_settings->mFriction;1240} else {1241return jolt_body->GetFriction();1242}1243}12441245void JoltBody3D::set_friction(float p_friction) {1246if (!in_space()) {1247jolt_settings->mFriction = p_friction;1248} else {1249jolt_body->SetFriction(p_friction);1250}1251}12521253void JoltBody3D::set_gravity_scale(float p_scale) {1254if (gravity_scale == p_scale) {1255return;1256}12571258gravity_scale = p_scale;12591260_motion_changed();1261}12621263void JoltBody3D::set_linear_damp(float p_damp) {1264p_damp = MAX(0.0f, p_damp);12651266if (p_damp == linear_damp) {1267return;1268}12691270linear_damp = p_damp;12711272_update_damp();1273}12741275void JoltBody3D::set_angular_damp(float p_damp) {1276p_damp = MAX(0.0f, p_damp);12771278if (p_damp == angular_damp) {1279return;1280}12811282angular_damp = p_damp;12831284_update_damp();1285}12861287void JoltBody3D::set_linear_damp_mode(DampMode p_mode) {1288if (p_mode == linear_damp_mode) {1289return;1290}12911292linear_damp_mode = p_mode;12931294_update_damp();1295}12961297void JoltBody3D::set_angular_damp_mode(DampMode p_mode) {1298if (p_mode == angular_damp_mode) {1299return;1300}13011302angular_damp_mode = p_mode;13031304_update_damp();1305}13061307bool JoltBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {1308return (locked_axes & (uint32_t)p_axis) != 0;1309}13101311void JoltBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_enabled) {1312const uint32_t previous_locked_axes = locked_axes;13131314if (p_enabled) {1315locked_axes |= (uint32_t)p_axis;1316} else {1317locked_axes &= ~(uint32_t)p_axis;1318}13191320if (previous_locked_axes != locked_axes) {1321_axis_lock_changed();1322}1323}13241325bool JoltBody3D::can_interact_with(const JoltBody3D &p_other) const {1326return (can_collide_with(p_other) || p_other.can_collide_with(*this)) && !has_collision_exception(p_other.get_rid()) && !p_other.has_collision_exception(rid);1327}13281329bool JoltBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {1330return p_other.can_interact_with(*this);1331}13321333bool JoltBody3D::can_interact_with(const JoltArea3D &p_other) const {1334return p_other.can_interact_with(*this);1335}133613371338