Path: blob/master/modules/jolt_physics/objects/jolt_shaped_object_3d.cpp
10278 views
/**************************************************************************/1/* jolt_shaped_object_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_shaped_object_3d.h"3132#include "../misc/jolt_math_funcs.h"33#include "../misc/jolt_type_conversions.h"34#include "../shapes/jolt_custom_double_sided_shape.h"35#include "../shapes/jolt_shape_3d.h"36#include "../spaces/jolt_space_3d.h"3738#include "Jolt/Physics/Collision/Shape/EmptyShape.h"39#include "Jolt/Physics/Collision/Shape/MutableCompoundShape.h"40#include "Jolt/Physics/Collision/Shape/StaticCompoundShape.h"4142bool JoltShapedObject3D::_is_big() const {43// This number is completely arbitrary, and mostly just needs to capture `WorldBoundaryShape3D`, which needs to be kept out of the normal broadphase layers.44return get_aabb().get_longest_axis_size() >= 1000.0f;45}4647JPH::ShapeRefC JoltShapedObject3D::_try_build_shape(bool p_optimize_compound) {48int built_shapes = 0;4950for (JoltShapeInstance3D &shape : shapes) {51if (shape.is_enabled() && shape.try_build()) {52built_shapes += 1;53}54}5556if (unlikely(built_shapes == 0)) {57return nullptr;58}5960JPH::ShapeRefC result = built_shapes == 1 ? _try_build_single_shape() : _try_build_compound_shape(p_optimize_compound);61if (unlikely(result == nullptr)) {62return nullptr;63}6465if (has_custom_center_of_mass()) {66result = JoltShape3D::with_center_of_mass(result, get_center_of_mass_custom());67}6869if (scale != Vector3(1, 1, 1)) {70Vector3 actual_scale = scale;71JOLT_ENSURE_SCALE_VALID(result, actual_scale, vformat("Failed to correctly scale body '%s'.", to_string()));72result = JoltShape3D::with_scale(result, actual_scale);73}7475if (is_area()) {76result = JoltShape3D::with_double_sided(result, true);77}7879return result;80}8182JPH::ShapeRefC JoltShapedObject3D::_try_build_single_shape() {83for (int shape_index = 0; shape_index < (int)shapes.size(); ++shape_index) {84const JoltShapeInstance3D &sub_shape = shapes[shape_index];8586if (!sub_shape.is_enabled() || !sub_shape.is_built()) {87continue;88}8990JPH::ShapeRefC jolt_sub_shape = sub_shape.get_jolt_ref();9192Vector3 sub_shape_scale = sub_shape.get_scale();93const Transform3D sub_shape_transform = sub_shape.get_transform_unscaled();9495if (sub_shape_scale != Vector3(1, 1, 1)) {96JOLT_ENSURE_SCALE_VALID(jolt_sub_shape, sub_shape_scale, vformat("Failed to correctly scale shape at index %d in body '%s'.", shape_index, to_string()));97jolt_sub_shape = JoltShape3D::with_scale(jolt_sub_shape, sub_shape_scale);98}99100if (sub_shape_transform != Transform3D()) {101jolt_sub_shape = JoltShape3D::with_basis_origin(jolt_sub_shape, sub_shape_transform.basis, sub_shape_transform.origin);102}103104return jolt_sub_shape;105}106107return nullptr;108}109110JPH::ShapeRefC JoltShapedObject3D::_try_build_compound_shape(bool p_optimize) {111JPH::StaticCompoundShapeSettings static_compound_shape_settings;112JPH::MutableCompoundShapeSettings mutable_compound_shape_settings;113JPH::CompoundShapeSettings *compound_shape_settings = p_optimize ? static_cast<JPH::CompoundShapeSettings *>(&static_compound_shape_settings) : static_cast<JPH::CompoundShapeSettings *>(&mutable_compound_shape_settings);114115compound_shape_settings->mSubShapes.reserve((size_t)shapes.size());116117for (int shape_index = 0; shape_index < (int)shapes.size(); ++shape_index) {118const JoltShapeInstance3D &sub_shape = shapes[shape_index];119120if (!sub_shape.is_enabled() || !sub_shape.is_built()) {121continue;122}123124JPH::ShapeRefC jolt_sub_shape = sub_shape.get_jolt_ref();125126Vector3 sub_shape_scale = sub_shape.get_scale();127const Transform3D sub_shape_transform = sub_shape.get_transform_unscaled();128129if (sub_shape_scale != Vector3(1, 1, 1)) {130JOLT_ENSURE_SCALE_VALID(jolt_sub_shape, sub_shape_scale, vformat("Failed to correctly scale shape at index %d for body '%s'.", shape_index, to_string()));131jolt_sub_shape = JoltShape3D::with_scale(jolt_sub_shape, sub_shape_scale);132}133134compound_shape_settings->AddShape(to_jolt(sub_shape_transform.origin), to_jolt(sub_shape_transform.basis), jolt_sub_shape);135}136137const JPH::ShapeSettings::ShapeResult shape_result = p_optimize ? static_compound_shape_settings.Create(space->get_temp_allocator()) : mutable_compound_shape_settings.Create();138ERR_FAIL_COND_V_MSG(shape_result.HasError(), nullptr, vformat("Failed to create compound shape for body '%s'. It returned the following error: '%s'.", to_string(), to_godot(shape_result.GetError())));139140return shape_result.Get();141}142143void JoltShapedObject3D::_enqueue_shapes_changed() {144if (space != nullptr) {145space->enqueue_shapes_changed(&shapes_changed_element);146}147}148149void JoltShapedObject3D::_dequeue_shapes_changed() {150if (space != nullptr) {151space->dequeue_shapes_changed(&shapes_changed_element);152}153}154155void JoltShapedObject3D::_enqueue_needs_optimization() {156if (space != nullptr) {157space->enqueue_needs_optimization(&needs_optimization_element);158}159}160161void JoltShapedObject3D::_dequeue_needs_optimization() {162if (space != nullptr) {163space->dequeue_needs_optimization(&needs_optimization_element);164}165}166167void JoltShapedObject3D::_shapes_changed() {168commit_shapes(false);169}170171void JoltShapedObject3D::_shapes_committed() {172_update_object_layer();173}174175void JoltShapedObject3D::_space_changing() {176JoltObject3D::_space_changing();177178_dequeue_shapes_changed();179_dequeue_needs_optimization();180181previous_jolt_shape = nullptr;182183if (in_space()) {184jolt_settings = new JPH::BodyCreationSettings(jolt_body->GetBodyCreationSettings());185}186}187188JoltShapedObject3D::JoltShapedObject3D(ObjectType p_object_type) :189JoltObject3D(p_object_type),190shapes_changed_element(this),191needs_optimization_element(this) {192jolt_settings->mAllowSleeping = true;193jolt_settings->mFriction = 1.0f;194jolt_settings->mRestitution = 0.0f;195jolt_settings->mLinearDamping = 0.0f;196jolt_settings->mAngularDamping = 0.0f;197jolt_settings->mGravityFactor = 0.0f;198}199200JoltShapedObject3D::~JoltShapedObject3D() {201if (jolt_settings != nullptr) {202delete jolt_settings;203jolt_settings = nullptr;204}205}206207Transform3D JoltShapedObject3D::get_transform_unscaled() const {208if (!in_space()) {209return Transform3D(to_godot(jolt_settings->mRotation), to_godot(jolt_settings->mPosition));210} else {211return Transform3D(to_godot(jolt_body->GetRotation()), to_godot(jolt_body->GetPosition()));212}213}214215Transform3D JoltShapedObject3D::get_transform_scaled() const {216return get_transform_unscaled().scaled_local(scale);217}218219Basis JoltShapedObject3D::get_basis() const {220if (!in_space()) {221return to_godot(jolt_settings->mRotation);222} else {223return to_godot(jolt_body->GetRotation());224}225}226227Vector3 JoltShapedObject3D::get_position() const {228if (!in_space()) {229return to_godot(jolt_settings->mPosition);230} else {231return to_godot(jolt_body->GetPosition());232}233}234235Vector3 JoltShapedObject3D::get_center_of_mass() const {236ERR_FAIL_COND_V_MSG(!in_space(), Vector3(), vformat("Failed to retrieve center-of-mass 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()));237return to_godot(jolt_body->GetCenterOfMassPosition());238}239240Vector3 JoltShapedObject3D::get_center_of_mass_relative() const {241return get_center_of_mass() - get_position();242}243244Vector3 JoltShapedObject3D::get_center_of_mass_local() const {245ERR_FAIL_NULL_V_MSG(space, Vector3(), vformat("Failed to retrieve local center-of-mass 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()));246247return get_transform_scaled().xform_inv(get_center_of_mass());248}249250Vector3 JoltShapedObject3D::get_linear_velocity() const {251if (!in_space()) {252return to_godot(jolt_settings->mLinearVelocity);253} else {254return to_godot(jolt_body->GetLinearVelocity());255}256}257258Vector3 JoltShapedObject3D::get_angular_velocity() const {259if (!in_space()) {260return to_godot(jolt_settings->mAngularVelocity);261} else {262return to_godot(jolt_body->GetAngularVelocity());263}264}265266AABB JoltShapedObject3D::get_aabb() const {267AABB result;268269for (const JoltShapeInstance3D &shape : shapes) {270if (shape.is_disabled()) {271continue;272}273274if (result == AABB()) {275result = shape.get_aabb();276} else {277result.merge_with(shape.get_aabb());278}279}280281return get_transform_scaled().xform(result);282}283284JPH::ShapeRefC JoltShapedObject3D::build_shapes(bool p_optimize_compound) {285JPH::ShapeRefC new_shape = _try_build_shape(p_optimize_compound);286287if (new_shape == nullptr) {288if (has_custom_center_of_mass()) {289new_shape = JPH::EmptyShapeSettings(to_jolt(get_center_of_mass_custom())).Create().Get();290} else {291new_shape = new JPH::EmptyShape();292}293}294295return new_shape;296}297298void JoltShapedObject3D::commit_shapes(bool p_optimize_compound) {299if (!in_space()) {300_shapes_committed();301return;302}303304JPH::ShapeRefC new_shape = build_shapes(p_optimize_compound);305if (new_shape == jolt_shape) {306return;307}308309if (previous_jolt_shape == nullptr) {310previous_jolt_shape = jolt_shape;311}312313jolt_shape = new_shape;314315space->get_body_iface().SetShape(jolt_body->GetID(), jolt_shape, false, JPH::EActivation::DontActivate);316317_enqueue_shapes_changed();318319if (!p_optimize_compound && jolt_shape->GetType() == JPH::EShapeType::Compound) {320_enqueue_needs_optimization();321} else {322_dequeue_needs_optimization();323}324325_shapes_committed();326}327328void JoltShapedObject3D::add_shape(JoltShape3D *p_shape, Transform3D p_transform, bool p_disabled) {329JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, vformat("An invalid transform was passed when adding shape at index %d to physics body '%s'.", shapes.size(), to_string()));330331Vector3 shape_scale;332JoltMath::decompose(p_transform, shape_scale);333334shapes.push_back(JoltShapeInstance3D(this, p_shape, p_transform, shape_scale, p_disabled));335336_shapes_changed();337}338339void JoltShapedObject3D::remove_shape(const JoltShape3D *p_shape) {340for (int i = shapes.size() - 1; i >= 0; i--) {341if (shapes[i].get_shape() == p_shape) {342shapes.remove_at(i);343}344}345346_shapes_changed();347}348349void JoltShapedObject3D::remove_shape(int p_index) {350ERR_FAIL_INDEX(p_index, (int)shapes.size());351shapes.remove_at(p_index);352353_shapes_changed();354}355356JoltShape3D *JoltShapedObject3D::get_shape(int p_index) const {357ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), nullptr);358return shapes[p_index].get_shape();359}360361void JoltShapedObject3D::set_shape(int p_index, JoltShape3D *p_shape) {362ERR_FAIL_INDEX(p_index, (int)shapes.size());363shapes[p_index] = JoltShapeInstance3D(this, p_shape);364365_shapes_changed();366}367368void JoltShapedObject3D::clear_shapes() {369shapes.clear();370371_shapes_changed();372}373374void JoltShapedObject3D::clear_previous_shape() {375previous_jolt_shape = nullptr;376}377378int JoltShapedObject3D::find_shape_index(uint32_t p_shape_instance_id) const {379for (int i = 0; i < (int)shapes.size(); ++i) {380if (shapes[i].get_id() == p_shape_instance_id) {381return i;382}383}384385return -1;386}387388int JoltShapedObject3D::find_shape_index(const JPH::SubShapeID &p_sub_shape_id) const {389ERR_FAIL_NULL_V(jolt_shape, -1);390return find_shape_index((uint32_t)jolt_shape->GetSubShapeUserData(p_sub_shape_id));391}392393JoltShape3D *JoltShapedObject3D::find_shape(uint32_t p_shape_instance_id) const {394const int shape_index = find_shape_index(p_shape_instance_id);395return shape_index != -1 ? shapes[shape_index].get_shape() : nullptr;396}397398JoltShape3D *JoltShapedObject3D::find_shape(const JPH::SubShapeID &p_sub_shape_id) const {399const int shape_index = find_shape_index(p_sub_shape_id);400return shape_index != -1 ? shapes[shape_index].get_shape() : nullptr;401}402403Transform3D JoltShapedObject3D::get_shape_transform_unscaled(int p_index) const {404ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Transform3D());405return shapes[p_index].get_transform_unscaled();406}407408Transform3D JoltShapedObject3D::get_shape_transform_scaled(int p_index) const {409ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Transform3D());410return shapes[p_index].get_transform_scaled();411}412413void JoltShapedObject3D::set_shape_transform(int p_index, Transform3D p_transform) {414ERR_FAIL_INDEX(p_index, (int)shapes.size());415JOLT_ENSURE_SCALE_NOT_ZERO(p_transform, "Failed to correctly set transform for shape at index %d in body '%s'.");416417Vector3 new_scale;418JoltMath::decompose(p_transform, new_scale);419420JoltShapeInstance3D &shape = shapes[p_index];421422if (shape.get_transform_unscaled() == p_transform && shape.get_scale() == new_scale) {423return;424}425426shape.set_transform(p_transform);427shape.set_scale(new_scale);428429_shapes_changed();430}431432Vector3 JoltShapedObject3D::get_shape_scale(int p_index) const {433ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), Vector3());434return shapes[p_index].get_scale();435}436437bool JoltShapedObject3D::is_shape_disabled(int p_index) const {438ERR_FAIL_INDEX_V(p_index, (int)shapes.size(), false);439return shapes[p_index].is_disabled();440}441442void JoltShapedObject3D::set_shape_disabled(int p_index, bool p_disabled) {443ERR_FAIL_INDEX(p_index, (int)shapes.size());444445JoltShapeInstance3D &shape = shapes[p_index];446447if (shape.is_disabled() == p_disabled) {448return;449}450451if (p_disabled) {452shape.disable();453} else {454shape.enable();455}456457_shapes_changed();458}459460461