Path: blob/master/modules/jolt_physics/objects/jolt_body_3d.cpp
20943 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();181182// Jolt applies damping differently from Godot Physics, where Godot Physics applies damping before integrating183// forces whereas Jolt does it after integrating forces. The way Godot Physics does it seems to yield more184// consistent results across different update frequencies when using high (>1) damping values, so we apply the185// damping ourselves instead, before any force integration happens.186JPH::Vec3 linear_velocity = motion_properties.GetLinearVelocity();187linear_velocity *= MAX(1.0f - total_linear_damp * p_step, 0.0f);188motion_properties.SetLinearVelocity(linear_velocity);189190JPH::Vec3 angular_velocity = motion_properties.GetAngularVelocity();191angular_velocity *= MAX(1.0f - total_angular_damp * p_step, 0.0f);192motion_properties.SetAngularVelocity(angular_velocity);193194p_jolt_body.AddForce(to_jolt(gravity / motion_properties.GetInverseMass() + constant_force));195p_jolt_body.AddTorque(to_jolt(constant_torque));196}197}198199void JoltBody3D::_move_kinematic(float p_step, JPH::Body &p_jolt_body) {200p_jolt_body.SetLinearVelocity(JPH::Vec3::sZero());201p_jolt_body.SetAngularVelocity(JPH::Vec3::sZero());202203const JPH::RVec3 current_position = p_jolt_body.GetPosition();204const JPH::Quat current_rotation = p_jolt_body.GetRotation();205206const JPH::RVec3 new_position = to_jolt_r(kinematic_transform.origin);207const JPH::Quat new_rotation = to_jolt(kinematic_transform.basis);208209if (new_position == current_position && new_rotation == current_rotation) {210return;211}212213p_jolt_body.MoveKinematic(new_position, new_rotation, p_step);214}215216JPH::EAllowedDOFs JoltBody3D::_calculate_allowed_dofs() const {217if (is_static()) {218return JPH::EAllowedDOFs::All;219}220221JPH::EAllowedDOFs allowed_dofs = JPH::EAllowedDOFs::All;222223if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_X)) {224allowed_dofs &= ~JPH::EAllowedDOFs::TranslationX;225}226227if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Y)) {228allowed_dofs &= ~JPH::EAllowedDOFs::TranslationY;229}230231if (is_axis_locked(PhysicsServer3D::BODY_AXIS_LINEAR_Z)) {232allowed_dofs &= ~JPH::EAllowedDOFs::TranslationZ;233}234235if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_X) || is_rigid_linear()) {236allowed_dofs &= ~JPH::EAllowedDOFs::RotationX;237}238239if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Y) || is_rigid_linear()) {240allowed_dofs &= ~JPH::EAllowedDOFs::RotationY;241}242243if (is_axis_locked(PhysicsServer3D::BODY_AXIS_ANGULAR_Z) || is_rigid_linear()) {244allowed_dofs &= ~JPH::EAllowedDOFs::RotationZ;245}246247ERR_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()));248249return allowed_dofs;250}251252JPH::MassProperties JoltBody3D::_calculate_mass_properties(const JPH::Shape &p_shape) const {253const bool calculate_mass = mass <= 0;254const bool calculate_inertia = inertia.x <= 0 || inertia.y <= 0 || inertia.z <= 0;255256JPH::MassProperties mass_properties = p_shape.GetMassProperties();257258if (calculate_mass && calculate_inertia) {259// Use the mass properties calculated by the shape260} else if (calculate_inertia) {261mass_properties.ScaleToMass(mass);262} else {263mass_properties.mMass = mass;264}265266if (inertia.x > 0) {267mass_properties.mInertia(0, 0) = (float)inertia.x;268mass_properties.mInertia(0, 1) = 0;269mass_properties.mInertia(0, 2) = 0;270mass_properties.mInertia(1, 0) = 0;271mass_properties.mInertia(2, 0) = 0;272}273274if (inertia.y > 0) {275mass_properties.mInertia(1, 1) = (float)inertia.y;276mass_properties.mInertia(1, 0) = 0;277mass_properties.mInertia(1, 2) = 0;278mass_properties.mInertia(0, 1) = 0;279mass_properties.mInertia(2, 1) = 0;280}281282if (inertia.z > 0) {283mass_properties.mInertia(2, 2) = (float)inertia.z;284mass_properties.mInertia(2, 0) = 0;285mass_properties.mInertia(2, 1) = 0;286mass_properties.mInertia(0, 2) = 0;287mass_properties.mInertia(1, 2) = 0;288}289290mass_properties.mInertia(3, 3) = 1.0f;291292return mass_properties;293}294295JPH::MassProperties JoltBody3D::_calculate_mass_properties() const {296return _calculate_mass_properties(*jolt_shape);297}298299void JoltBody3D::_on_wake_up() {300// This method will be called from the body activation listener on multiple threads during the simulation step.301302if (_should_call_queries()) {303_enqueue_call_queries();304}305}306307void JoltBody3D::_update_mass_properties() {308if (in_space()) {309jolt_body->GetMotionPropertiesUnchecked()->SetMassProperties(_calculate_allowed_dofs(), _calculate_mass_properties());310}311}312313void JoltBody3D::_update_gravity(JPH::Body &p_jolt_body) {314gravity = Vector3();315316const Vector3 position = to_godot(p_jolt_body.GetPosition());317318bool gravity_done = false;319320for (const JoltArea3D *area : areas) {321gravity_done = integrate(gravity, area->get_gravity_mode(), [&]() {322return area->compute_gravity(position);323});324325if (gravity_done) {326break;327}328}329330if (!gravity_done) {331gravity += space->get_default_area()->compute_gravity(position);332}333334gravity *= gravity_scale;335}336337void JoltBody3D::_update_damp() {338if (!in_space()) {339return;340}341342total_linear_damp = 0.0;343total_angular_damp = 0.0;344345bool linear_damp_done = linear_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;346bool angular_damp_done = angular_damp_mode == PhysicsServer3D::BODY_DAMP_MODE_REPLACE;347348for (const JoltArea3D *area : areas) {349if (!linear_damp_done) {350linear_damp_done = integrate(total_linear_damp, area->get_linear_damp_mode(), [&]() {351return area->get_linear_damp();352});353}354355if (!angular_damp_done) {356angular_damp_done = integrate(total_angular_damp, area->get_angular_damp_mode(), [&]() {357return area->get_angular_damp();358});359}360361if (linear_damp_done && angular_damp_done) {362break;363}364}365366const JoltArea3D *default_area = space->get_default_area();367368if (!linear_damp_done) {369total_linear_damp += default_area->get_linear_damp();370}371372if (!angular_damp_done) {373total_angular_damp += default_area->get_angular_damp();374}375376switch (linear_damp_mode) {377case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {378total_linear_damp += linear_damp;379} break;380case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {381total_linear_damp = linear_damp;382} break;383}384385switch (angular_damp_mode) {386case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: {387total_angular_damp += angular_damp;388} break;389case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: {390total_angular_damp = angular_damp;391} break;392}393394_motion_changed();395}396397void JoltBody3D::_update_kinematic_transform() {398if (is_kinematic()) {399kinematic_transform = get_transform_unscaled();400}401}402403void JoltBody3D::_update_joint_constraints() {404for (JoltJoint3D *joint : joints) {405joint->rebuild();406}407}408409void JoltBody3D::_update_possible_kinematic_contacts() {410const bool value = reports_all_kinematic_contacts();411412if (!in_space()) {413jolt_settings->mCollideKinematicVsNonDynamic = value;414} else {415jolt_body->SetCollideKinematicVsNonDynamic(value);416}417}418419void JoltBody3D::_update_sleep_allowed() {420const bool value = is_sleep_actually_allowed();421422if (!in_space()) {423jolt_settings->mAllowSleeping = value;424} else {425jolt_body->SetAllowSleeping(value);426}427}428429void JoltBody3D::_destroy_joint_constraints() {430for (JoltJoint3D *joint : joints) {431joint->destroy();432}433}434435void JoltBody3D::_exit_all_areas() {436if (!in_space()) {437return;438}439440for (JoltArea3D *area : areas) {441area->body_exited(jolt_body->GetID(), false);442}443444areas.clear();445}446447void JoltBody3D::_update_group_filter() {448JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;449450if (!in_space()) {451jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);452} else {453jolt_body->GetCollisionGroup().SetGroupFilter(group_filter);454}455}456457void JoltBody3D::_mode_changed() {458_update_object_layer();459_update_kinematic_transform();460_update_mass_properties();461_update_sleep_allowed();462wake_up();463}464465void JoltBody3D::_shapes_committed() {466JoltShapedObject3D::_shapes_committed();467468_update_mass_properties();469_update_joint_constraints();470wake_up();471}472473void JoltBody3D::_space_changing() {474JoltShapedObject3D::_space_changing();475476sleep_initially = is_sleeping();477478_destroy_joint_constraints();479_exit_all_areas();480_dequeue_call_queries();481}482483void JoltBody3D::_space_changed() {484JoltShapedObject3D::_space_changed();485486_update_kinematic_transform();487_update_group_filter();488_update_joint_constraints();489_update_sleep_allowed();490_areas_changed();491}492493void JoltBody3D::_areas_changed() {494_update_damp();495wake_up();496}497498void JoltBody3D::_joints_changed() {499wake_up();500}501502void JoltBody3D::_transform_changed() {503wake_up();504}505506void JoltBody3D::_motion_changed() {507wake_up();508}509510void JoltBody3D::_exceptions_changed() {511_update_group_filter();512}513514void JoltBody3D::_axis_lock_changed() {515_update_mass_properties();516wake_up();517}518519void JoltBody3D::_contact_reporting_changed() {520_update_possible_kinematic_contacts();521_update_sleep_allowed();522wake_up();523}524525void JoltBody3D::_sleep_allowed_changed() {526_update_sleep_allowed();527wake_up();528}529530JoltBody3D::JoltBody3D() :531JoltShapedObject3D(OBJECT_TYPE_BODY),532call_queries_element(this) {533}534535JoltBody3D::~JoltBody3D() {536if (direct_state != nullptr) {537memdelete(direct_state);538direct_state = nullptr;539}540}541542void JoltBody3D::set_transform(Transform3D p_transform) {543JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed to physics body '%s'.", to_string()));544545Vector3 new_scale;546JoltMath::decompose(p_transform, new_scale);547548// Ideally we would do an exact comparison here, but due to floating-point precision this would be invalidated very often.549if (!scale.is_equal_approx(new_scale)) {550scale = new_scale;551_shapes_changed();552}553554if (!in_space()) {555jolt_settings->mPosition = to_jolt_r(p_transform.origin);556jolt_settings->mRotation = to_jolt(p_transform.basis);557} else if (is_kinematic()) {558kinematic_transform = p_transform;559} else {560space->get_body_iface().SetPositionAndRotation(jolt_body->GetID(), to_jolt_r(p_transform.origin), to_jolt(p_transform.basis), JPH::EActivation::DontActivate);561}562563_transform_changed();564}565566Variant JoltBody3D::get_state(PhysicsServer3D::BodyState p_state) const {567switch (p_state) {568case PhysicsServer3D::BODY_STATE_TRANSFORM: {569return get_transform_scaled();570}571case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {572return get_linear_velocity();573}574case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {575return get_angular_velocity();576}577case PhysicsServer3D::BODY_STATE_SLEEPING: {578return is_sleeping();579}580case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {581return is_sleep_allowed();582}583default: {584ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));585}586}587}588589void JoltBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {590switch (p_state) {591case PhysicsServer3D::BODY_STATE_TRANSFORM: {592set_transform(p_value);593} break;594case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {595set_linear_velocity(p_value);596} break;597case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {598set_angular_velocity(p_value);599} break;600case PhysicsServer3D::BODY_STATE_SLEEPING: {601set_is_sleeping(p_value);602} break;603case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {604set_is_sleep_allowed(p_value);605} break;606default: {607ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));608} break;609}610}611612Variant JoltBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const {613switch (p_param) {614case PhysicsServer3D::BODY_PARAM_BOUNCE: {615return get_bounce();616}617case PhysicsServer3D::BODY_PARAM_FRICTION: {618return get_friction();619}620case PhysicsServer3D::BODY_PARAM_MASS: {621return get_mass();622}623case PhysicsServer3D::BODY_PARAM_INERTIA: {624return get_inertia();625}626case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {627return get_center_of_mass_custom();628}629case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {630return get_gravity_scale();631}632case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {633return get_linear_damp_mode();634}635case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {636return get_angular_damp_mode();637}638case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {639return get_linear_damp();640}641case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {642return get_angular_damp();643}644default: {645ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));646}647}648}649650void JoltBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) {651switch (p_param) {652case PhysicsServer3D::BODY_PARAM_BOUNCE: {653set_bounce(p_value);654} break;655case PhysicsServer3D::BODY_PARAM_FRICTION: {656set_friction(p_value);657} break;658case PhysicsServer3D::BODY_PARAM_MASS: {659set_mass(p_value);660} break;661case PhysicsServer3D::BODY_PARAM_INERTIA: {662set_inertia(p_value);663} break;664case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: {665set_center_of_mass_custom(p_value);666} break;667case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: {668set_gravity_scale(p_value);669} break;670case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: {671set_linear_damp_mode((DampMode)(int)p_value);672} break;673case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: {674set_angular_damp_mode((DampMode)(int)p_value);675} break;676case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: {677set_linear_damp(p_value);678} break;679case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP: {680set_angular_damp(p_value);681} break;682default: {683ERR_FAIL_MSG(vformat("Unhandled body parameter: '%d'. This should not happen. Please report this.", p_param));684} break;685}686}687688void JoltBody3D::set_custom_integrator(bool p_enabled) {689if (custom_integrator == p_enabled) {690return;691}692693custom_integrator = p_enabled;694695if (in_space()) {696jolt_body->ResetForce();697jolt_body->ResetTorque();698}699700_motion_changed();701}702703bool JoltBody3D::is_sleeping() const {704if (!in_space()) {705return sleep_initially;706} else {707return !jolt_body->IsActive();708}709}710711bool JoltBody3D::is_sleep_actually_allowed() const {712return sleep_allowed && !(is_kinematic() && reports_contacts());713}714715void JoltBody3D::set_is_sleeping(bool p_enabled) {716if (!in_space()) {717sleep_initially = p_enabled;718} else {719space->set_is_object_sleeping(jolt_body->GetID(), p_enabled);720}721}722723void JoltBody3D::set_is_sleep_allowed(bool p_enabled) {724if (sleep_allowed == p_enabled) {725return;726}727728sleep_allowed = p_enabled;729730_sleep_allowed_changed();731}732733Basis JoltBody3D::get_principal_inertia_axes() const {734ERR_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()));735736if (unlikely(is_static() || is_kinematic())) {737return Basis();738}739740return to_godot(jolt_body->GetRotation() * jolt_body->GetMotionPropertiesUnchecked()->GetInertiaRotation());741}742743Vector3 JoltBody3D::get_inverse_inertia() const {744ERR_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()));745746if (unlikely(is_static() || is_kinematic())) {747return Vector3();748}749750return to_godot(jolt_body->GetMotionPropertiesUnchecked()->GetLocalSpaceInverseInertia().GetDiagonal3());751}752753Basis JoltBody3D::get_inverse_inertia_tensor() const {754ERR_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()));755756if (unlikely(is_static() || is_kinematic())) {757return Basis();758}759760return to_godot(jolt_body->GetInverseInertia()).basis;761}762763void JoltBody3D::set_linear_velocity(const Vector3 &p_velocity) {764if (is_static() || is_kinematic()) {765linear_surface_velocity = p_velocity;766} else {767if (!in_space()) {768jolt_settings->mLinearVelocity = to_jolt(p_velocity);769} else {770jolt_body->GetMotionPropertiesUnchecked()->SetLinearVelocityClamped(to_jolt(p_velocity));771}772}773774_motion_changed();775}776777void JoltBody3D::set_angular_velocity(const Vector3 &p_velocity) {778if (is_static() || is_kinematic()) {779angular_surface_velocity = p_velocity;780} else {781if (!in_space()) {782jolt_settings->mAngularVelocity = to_jolt(p_velocity);783} else {784jolt_body->GetMotionPropertiesUnchecked()->SetAngularVelocityClamped(to_jolt(p_velocity));785}786}787788_motion_changed();789}790791void JoltBody3D::set_axis_velocity(const Vector3 &p_axis_velocity) {792const Vector3 axis = p_axis_velocity.normalized();793794if (!in_space()) {795Vector3 linear_velocity = to_godot(jolt_settings->mLinearVelocity);796linear_velocity -= axis * axis.dot(linear_velocity);797linear_velocity += p_axis_velocity;798jolt_settings->mLinearVelocity = to_jolt(linear_velocity);799} else {800Vector3 linear_velocity = get_linear_velocity();801linear_velocity -= axis * axis.dot(linear_velocity);802linear_velocity += p_axis_velocity;803set_linear_velocity(linear_velocity);804}805806_motion_changed();807}808809Vector3 JoltBody3D::get_velocity_at_position(const Vector3 &p_position) const {810if (unlikely(!in_space())) {811return Vector3();812}813814const JPH::MotionProperties &motion_properties = *jolt_body->GetMotionPropertiesUnchecked();815const Vector3 total_linear_velocity = to_godot(motion_properties.GetLinearVelocity()) + linear_surface_velocity;816const Vector3 total_angular_velocity = to_godot(motion_properties.GetAngularVelocity()) + angular_surface_velocity;817const Vector3 com_to_pos = p_position - to_godot(jolt_body->GetCenterOfMassPosition());818819return total_linear_velocity + total_angular_velocity.cross(com_to_pos);820}821822void JoltBody3D::set_center_of_mass_custom(const Vector3 &p_center_of_mass) {823if (custom_center_of_mass && p_center_of_mass == center_of_mass_custom) {824return;825}826827custom_center_of_mass = true;828center_of_mass_custom = p_center_of_mass;829830_shapes_changed();831}832833void JoltBody3D::set_max_contacts_reported(int p_count) {834ERR_FAIL_INDEX(p_count, MAX_CONTACTS_REPORTED_3D_MAX);835836if (unlikely((int)contacts.size() == p_count)) {837return;838}839840contacts.resize(p_count);841contact_count = MIN(contact_count, p_count);842843const bool use_manifold_reduction = !reports_contacts();844845if (!in_space()) {846jolt_settings->mUseManifoldReduction = use_manifold_reduction;847} else {848space->get_body_iface().SetUseManifoldReduction(jolt_body->GetID(), use_manifold_reduction);849}850851_contact_reporting_changed();852}853854bool JoltBody3D::reports_all_kinematic_contacts() const {855return reports_contacts() && JoltProjectSettings::generate_all_kinematic_contacts;856}857858void 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) {859const int max_contacts = get_max_contacts_reported();860861if (max_contacts == 0) {862return;863}864865Contact *contact = nullptr;866867if (contact_count < max_contacts) {868contact = &contacts[contact_count++];869} else {870Contact *shallowest_contact = &contacts[0];871872for (int i = 1; i < (int)contacts.size(); i++) {873Contact &other_contact = contacts[i];874if (other_contact.depth < shallowest_contact->depth) {875shallowest_contact = &other_contact;876}877}878879if (shallowest_contact->depth < p_depth) {880contact = shallowest_contact;881}882}883884if (contact != nullptr) {885contact->normal = p_normal;886contact->position = p_position;887contact->collider_position = p_collider_position;888contact->velocity = p_velocity;889contact->collider_velocity = p_collider_velocity;890contact->impulse = p_impulse;891contact->collider_id = p_collider->get_instance_id();892contact->collider_rid = p_collider->get_rid();893contact->shape_index = p_shape_index;894contact->collider_shape_index = p_collider_shape_index;895}896}897898void JoltBody3D::reset_mass_properties() {899if (custom_center_of_mass) {900custom_center_of_mass = false;901center_of_mass_custom.zero();902903_shapes_changed();904}905906inertia.zero();907908_update_mass_properties();909}910911void JoltBody3D::apply_force(const Vector3 &p_force, const Vector3 &p_position) {912ERR_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()));913914if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {915return;916}917918jolt_body->AddForce(to_jolt(p_force), jolt_body->GetPosition() + to_jolt(p_position));919920_motion_changed();921}922923void JoltBody3D::apply_central_force(const Vector3 &p_force) {924ERR_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()));925926if (unlikely(!is_rigid()) || custom_integrator || p_force == Vector3()) {927return;928}929930jolt_body->AddForce(to_jolt(p_force));931932_motion_changed();933}934935void JoltBody3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) {936ERR_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()));937938if (unlikely(!is_rigid()) || p_impulse == Vector3()) {939return;940}941942jolt_body->AddImpulse(to_jolt(p_impulse), jolt_body->GetPosition() + to_jolt(p_position));943944_motion_changed();945}946947void JoltBody3D::apply_central_impulse(const Vector3 &p_impulse) {948ERR_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()));949950if (unlikely(!is_rigid()) || p_impulse == Vector3()) {951return;952}953954jolt_body->AddImpulse(to_jolt(p_impulse));955956_motion_changed();957}958959void JoltBody3D::apply_torque(const Vector3 &p_torque) {960ERR_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()));961962if (unlikely(!is_rigid()) || custom_integrator || p_torque == Vector3()) {963return;964}965966jolt_body->AddTorque(to_jolt(p_torque));967968_motion_changed();969}970971void JoltBody3D::apply_torque_impulse(const Vector3 &p_impulse) {972ERR_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()));973974if (unlikely(!is_rigid()) || p_impulse == Vector3()) {975return;976}977978jolt_body->AddAngularImpulse(to_jolt(p_impulse));979980_motion_changed();981}982983void JoltBody3D::add_constant_central_force(const Vector3 &p_force) {984if (p_force == Vector3()) {985return;986}987988constant_force += p_force;989990_motion_changed();991}992993void JoltBody3D::add_constant_force(const Vector3 &p_force, const Vector3 &p_position) {994if (p_force == Vector3()) {995return;996}997998constant_force += p_force;999constant_torque += (p_position - get_center_of_mass_relative()).cross(p_force);10001001_motion_changed();1002}10031004void JoltBody3D::add_constant_torque(const Vector3 &p_torque) {1005if (p_torque == Vector3()) {1006return;1007}10081009constant_torque += p_torque;10101011_motion_changed();1012}10131014Vector3 JoltBody3D::get_constant_force() const {1015return constant_force;1016}10171018void JoltBody3D::set_constant_force(const Vector3 &p_force) {1019if (constant_force == p_force) {1020return;1021}10221023constant_force = p_force;10241025_motion_changed();1026}10271028Vector3 JoltBody3D::get_constant_torque() const {1029return constant_torque;1030}10311032void JoltBody3D::set_constant_torque(const Vector3 &p_torque) {1033if (constant_torque == p_torque) {1034return;1035}10361037constant_torque = p_torque;10381039_motion_changed();1040}10411042void JoltBody3D::add_collision_exception(const RID &p_excepted_body) {1043exceptions.push_back(p_excepted_body);10441045_exceptions_changed();1046}10471048void JoltBody3D::remove_collision_exception(const RID &p_excepted_body) {1049exceptions.erase(p_excepted_body);10501051_exceptions_changed();1052}10531054bool JoltBody3D::has_collision_exception(const RID &p_excepted_body) const {1055return exceptions.find(p_excepted_body) >= 0;1056}10571058void JoltBody3D::add_area(JoltArea3D *p_area) {1059int i = 0;1060for (; i < (int)areas.size(); i++) {1061if (p_area->get_priority() > areas[i]->get_priority()) {1062break;1063}1064}10651066areas.insert(i, p_area);10671068_areas_changed();1069}10701071void JoltBody3D::remove_area(JoltArea3D *p_area) {1072areas.erase(p_area);10731074_areas_changed();1075}10761077void JoltBody3D::add_joint(JoltJoint3D *p_joint) {1078joints.push_back(p_joint);10791080_joints_changed();1081}10821083void JoltBody3D::remove_joint(JoltJoint3D *p_joint) {1084joints.erase(p_joint);10851086_joints_changed();1087}10881089void JoltBody3D::call_queries() {1090if (custom_integration_callback.is_valid()) {1091const Variant direct_state_variant = get_direct_state();1092const Variant *args[2] = { &direct_state_variant, &custom_integration_userdata };1093const int argc = custom_integration_userdata.get_type() != Variant::NIL ? 2 : 1;10941095Callable::CallError ce;1096Variant ret;1097custom_integration_callback.callp(args, argc, ret, ce);10981099if (unlikely(ce.error != Callable::CallError::CALL_OK)) {1100ERR_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)));1101}1102}11031104if (state_sync_callback.is_valid()) {1105const Variant direct_state_variant = get_direct_state();1106const Variant *args[1] = { &direct_state_variant };11071108Callable::CallError ce;1109Variant ret;1110state_sync_callback.callp(args, 1, ret, ce);11111112if (unlikely(ce.error != Callable::CallError::CALL_OK)) {1113ERR_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)));1114}1115}1116}11171118void JoltBody3D::pre_step(float p_step, JPH::Body &p_jolt_body) {1119JoltObject3D::pre_step(p_step, p_jolt_body);11201121switch (mode) {1122case PhysicsServer3D::BODY_MODE_STATIC: {1123// Will never happen.1124} break;1125case PhysicsServer3D::BODY_MODE_RIGID:1126case PhysicsServer3D::BODY_MODE_RIGID_LINEAR: {1127_integrate_forces(p_step, p_jolt_body);1128} break;1129case PhysicsServer3D::BODY_MODE_KINEMATIC: {1130_update_gravity(p_jolt_body);1131_move_kinematic(p_step, p_jolt_body);1132} break;1133}11341135if (_should_call_queries()) {1136_enqueue_call_queries();1137}11381139contact_count = 0;1140}11411142JoltPhysicsDirectBodyState3D *JoltBody3D::get_direct_state() {1143if (direct_state == nullptr) {1144direct_state = memnew(JoltPhysicsDirectBodyState3D(this));1145}11461147return direct_state;1148}11491150void JoltBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) {1151if (p_mode == mode) {1152return;1153}11541155mode = p_mode;11561157if (!in_space()) {1158_mode_changed();1159return;1160}11611162const JPH::EMotionType motion_type = _get_motion_type();11631164if (motion_type == JPH::EMotionType::Static) {1165put_to_sleep();1166}11671168jolt_body->SetMotionType(motion_type);11691170if (motion_type != JPH::EMotionType::Static) {1171wake_up();1172}11731174if (motion_type == JPH::EMotionType::Kinematic) {1175jolt_body->SetLinearVelocity(JPH::Vec3::sZero());1176jolt_body->SetAngularVelocity(JPH::Vec3::sZero());1177}11781179linear_surface_velocity = Vector3();1180angular_surface_velocity = Vector3();11811182_mode_changed();1183}11841185bool JoltBody3D::is_ccd_enabled() const {1186if (!in_space()) {1187return jolt_settings->mMotionQuality == JPH::EMotionQuality::LinearCast;1188} else {1189return !is_static() && jolt_body->GetMotionProperties()->GetMotionQuality() == JPH::EMotionQuality::LinearCast;1190}1191}11921193void JoltBody3D::set_ccd_enabled(bool p_enabled) {1194const JPH::EMotionQuality motion_quality = p_enabled ? JPH::EMotionQuality::LinearCast : JPH::EMotionQuality::Discrete;11951196if (!in_space()) {1197jolt_settings->mMotionQuality = motion_quality;1198} else {1199space->get_body_iface().SetMotionQuality(jolt_body->GetID(), motion_quality);1200}1201}12021203void JoltBody3D::set_mass(float p_mass) {1204if (p_mass != mass) {1205mass = p_mass;1206_update_mass_properties();1207}1208}12091210void JoltBody3D::set_inertia(const Vector3 &p_inertia) {1211if (p_inertia != inertia) {1212inertia = p_inertia;1213_update_mass_properties();1214}1215}12161217float JoltBody3D::get_bounce() const {1218if (!in_space()) {1219return jolt_settings->mRestitution;1220} else {1221return jolt_body->GetRestitution();1222}1223}12241225void JoltBody3D::set_bounce(float p_bounce) {1226if (!in_space()) {1227jolt_settings->mRestitution = p_bounce;1228} else {1229jolt_body->SetRestitution(p_bounce);1230}1231}12321233float JoltBody3D::get_friction() const {1234if (!in_space()) {1235return jolt_settings->mFriction;1236} else {1237return jolt_body->GetFriction();1238}1239}12401241void JoltBody3D::set_friction(float p_friction) {1242if (!in_space()) {1243jolt_settings->mFriction = p_friction;1244} else {1245jolt_body->SetFriction(p_friction);1246}1247}12481249void JoltBody3D::set_gravity_scale(float p_scale) {1250if (gravity_scale == p_scale) {1251return;1252}12531254gravity_scale = p_scale;12551256_motion_changed();1257}12581259void JoltBody3D::set_linear_damp(float p_damp) {1260p_damp = MAX(0.0f, p_damp);12611262if (p_damp == linear_damp) {1263return;1264}12651266linear_damp = p_damp;12671268_update_damp();1269}12701271void JoltBody3D::set_angular_damp(float p_damp) {1272p_damp = MAX(0.0f, p_damp);12731274if (p_damp == angular_damp) {1275return;1276}12771278angular_damp = p_damp;12791280_update_damp();1281}12821283void JoltBody3D::set_linear_damp_mode(DampMode p_mode) {1284if (p_mode == linear_damp_mode) {1285return;1286}12871288linear_damp_mode = p_mode;12891290_update_damp();1291}12921293void JoltBody3D::set_angular_damp_mode(DampMode p_mode) {1294if (p_mode == angular_damp_mode) {1295return;1296}12971298angular_damp_mode = p_mode;12991300_update_damp();1301}13021303bool JoltBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const {1304return (locked_axes & (uint32_t)p_axis) != 0;1305}13061307void JoltBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool p_enabled) {1308const uint32_t previous_locked_axes = locked_axes;13091310if (p_enabled) {1311locked_axes |= (uint32_t)p_axis;1312} else {1313locked_axes &= ~(uint32_t)p_axis;1314}13151316if (previous_locked_axes != locked_axes) {1317_axis_lock_changed();1318}1319}13201321bool JoltBody3D::can_interact_with(const JoltBody3D &p_other) const {1322return (can_collide_with(p_other) || p_other.can_collide_with(*this)) && !has_collision_exception(p_other.get_rid()) && !p_other.has_collision_exception(rid);1323}13241325bool JoltBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {1326return p_other.can_interact_with(*this);1327}13281329bool JoltBody3D::can_interact_with(const JoltArea3D &p_other) const {1330return p_other.can_interact_with(*this);1331}133213331334