feat: modules moved and engine moved to submodule

This commit is contained in:
Jan van der Weide 2025-04-12 18:40:44 +02:00
parent dfb5e645cd
commit c33d2130cc
5136 changed files with 225275 additions and 64485 deletions

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef ANIMATABLE_BODY_3D_H
#define ANIMATABLE_BODY_3D_H
#pragma once
#include "scene/3d/physics/static_body_3d.h"
@ -63,5 +62,3 @@ private:
void set_sync_to_physics(bool p_enable);
bool is_sync_to_physics_enabled() const;
};
#endif // ANIMATABLE_BODY_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef AREA_3D_H
#define AREA_3D_H
#pragma once
#include "core/templates/vset.h"
#include "scene/3d/physics/collision_object_3d.h"
@ -231,5 +230,3 @@ public:
};
VARIANT_ENUM_CAST(Area3D::SpaceOverride);
#endif // AREA_3D_H

View file

@ -219,7 +219,7 @@ void CharacterBody3D::_move_and_slide_grounded(double p_delta, bool p_was_on_flo
// Avoid to move forward on a wall if floor_block_on_wall is true.
// Applies only when the motion angle is under 90 degrees,
// in order to avoid blocking lateral motion along a wall.
if (motion_angle < .5 * Math_PI) {
if (motion_angle < .5 * Math::PI) {
apply_default_sliding = false;
if (p_was_on_floor && !vel_dir_facing_up) {
// Cancel the motion.
@ -569,7 +569,7 @@ void CharacterBody3D::_set_collision_direction(const PhysicsServer3D::MotionResu
wall_normal = collision.normal;
// Don't apply wall velocity when the collider is a CharacterBody3D.
if (Object::cast_to<CharacterBody3D>(ObjectDB::get_instance(collision.collider_id)) == nullptr) {
if (ObjectDB::get_instance<CharacterBody3D>(collision.collider_id) == nullptr) {
_set_platform_data(collision);
}
}
@ -717,7 +717,7 @@ Ref<KinematicCollision3D> CharacterBody3D::_get_slide_collision(int p_bounce) {
}
Ref<KinematicCollision3D> CharacterBody3D::_get_last_slide_collision() {
if (motion_results.size() == 0) {
if (motion_results.is_empty()) {
return Ref<KinematicCollision3D>();
}
return _get_slide_collision(motion_results.size() - 1);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CHARACTER_BODY_3D_H
#define CHARACTER_BODY_3D_H
#pragma once
#include "scene/3d/physics/kinematic_collision_3d.h"
#include "scene/3d/physics/physics_body_3d.h"
@ -185,5 +184,3 @@ protected:
VARIANT_ENUM_CAST(CharacterBody3D::MotionMode);
VARIANT_ENUM_CAST(CharacterBody3D::PlatformOnLeave);
#endif // CHARACTER_BODY_3D_H

View file

@ -519,7 +519,7 @@ uint32_t CollisionObject3D::create_shape_owner(Object *p_owner) {
ShapeData sd;
uint32_t id;
if (shapes.size() == 0) {
if (shapes.is_empty()) {
id = 0;
} else {
id = shapes.back()->key() + 1;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef COLLISION_OBJECT_3D_H
#define COLLISION_OBJECT_3D_H
#pragma once
#include "scene/3d/camera_3d.h"
#include "scene/3d/node_3d.h"
@ -180,5 +179,3 @@ public:
};
VARIANT_ENUM_CAST(CollisionObject3D::DisableMode);
#endif // COLLISION_OBJECT_3D_H

View file

@ -41,12 +41,12 @@ void CollisionPolygon3D::_build_polygon() {
collision_object->shape_owner_clear_shapes(owner_id);
if (polygon.size() == 0) {
if (polygon.is_empty()) {
return;
}
Vector<Vector<Vector2>> decomp = Geometry2D::decompose_polygon_in_convex(polygon);
if (decomp.size() == 0) {
if (decomp.is_empty()) {
return;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef COLLISION_POLYGON_3D_H
#define COLLISION_POLYGON_3D_H
#pragma once
#include "scene/3d/node_3d.h"
@ -94,5 +93,3 @@ public:
CollisionPolygon3D();
};
#endif // COLLISION_POLYGON_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef COLLISION_SHAPE_3D_H
#define COLLISION_SHAPE_3D_H
#pragma once
#include "scene/3d/node_3d.h"
#include "scene/resources/3d/shape_3d.h"
@ -90,5 +89,3 @@ public:
CollisionShape3D();
~CollisionShape3D();
};
#endif // COLLISION_SHAPE_3D_H

View file

@ -87,8 +87,8 @@ void ConeTwistJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, Phys
}
ConeTwistJoint3D::ConeTwistJoint3D() {
params[PARAM_SWING_SPAN] = Math_PI * 0.25;
params[PARAM_TWIST_SPAN] = Math_PI;
params[PARAM_SWING_SPAN] = Math::PI * 0.25;
params[PARAM_TWIST_SPAN] = Math::PI;
params[PARAM_BIAS] = 0.3;
params[PARAM_SOFTNESS] = 0.8;
params[PARAM_RELAXATION] = 1.0;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef CONE_TWIST_JOINT_3D_H
#define CONE_TWIST_JOINT_3D_H
#pragma once
#include "scene/3d/physics/joints/joint_3d.h"
@ -59,5 +58,3 @@ public:
};
VARIANT_ENUM_CAST(ConeTwistJoint3D::Param);
#endif // CONE_TWIST_JOINT_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef GENERIC_6DOF_JOINT_3D_H
#define GENERIC_6DOF_JOINT_3D_H
#pragma once
#include "scene/3d/physics/joints/joint_3d.h"
@ -108,5 +107,3 @@ public:
VARIANT_ENUM_CAST(Generic6DOFJoint3D::Param);
VARIANT_ENUM_CAST(Generic6DOFJoint3D::Flag);
#endif // GENERIC_6DOF_JOINT_3D_H

View file

@ -122,8 +122,8 @@ void HingeJoint3D::_configure_joint(RID p_joint, PhysicsBody3D *body_a, PhysicsB
HingeJoint3D::HingeJoint3D() {
params[PARAM_BIAS] = 0.3;
params[PARAM_LIMIT_UPPER] = Math_PI * 0.5;
params[PARAM_LIMIT_LOWER] = -Math_PI * 0.5;
params[PARAM_LIMIT_UPPER] = Math::PI * 0.5;
params[PARAM_LIMIT_LOWER] = -Math::PI * 0.5;
params[PARAM_LIMIT_BIAS] = 0.3;
params[PARAM_LIMIT_SOFTNESS] = 0.9;
params[PARAM_LIMIT_RELAXATION] = 1.0;

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef HINGE_JOINT_3D_H
#define HINGE_JOINT_3D_H
#pragma once
#include "scene/3d/physics/joints/joint_3d.h"
@ -73,5 +72,3 @@ public:
VARIANT_ENUM_CAST(HingeJoint3D::Param);
VARIANT_ENUM_CAST(HingeJoint3D::Flag);
#endif // HINGE_JOINT_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef JOINT_3D_H
#define JOINT_3D_H
#pragma once
#include "scene/3d/node_3d.h"
#include "scene/3d/physics/physics_body_3d.h"
@ -81,5 +80,3 @@ public:
Joint3D();
~Joint3D();
};
#endif // JOINT_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PIN_JOINT_3D_H
#define PIN_JOINT_3D_H
#pragma once
#include "scene/3d/physics/joints/joint_3d.h"
@ -56,5 +55,3 @@ public:
};
VARIANT_ENUM_CAST(PinJoint3D::Param);
#endif // PIN_JOINT_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SLIDER_JOINT_3D_H
#define SLIDER_JOINT_3D_H
#pragma once
#include "scene/3d/physics/joints/joint_3d.h"
@ -78,5 +77,3 @@ public:
};
VARIANT_ENUM_CAST(SliderJoint3D::Param);
#endif // SLIDER_JOINT_3D_H

View file

@ -66,7 +66,7 @@ real_t KinematicCollision3D::get_angle(int p_collision_index, const Vector3 &p_u
Object *KinematicCollision3D::get_local_shape(int p_collision_index) const {
ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr);
PhysicsBody3D *owner = Object::cast_to<PhysicsBody3D>(ObjectDB::get_instance(owner_id));
PhysicsBody3D *owner = ObjectDB::get_instance<PhysicsBody3D>(owner_id);
if (!owner) {
return nullptr;
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef KINEMATIC_COLLISION_3D_H
#define KINEMATIC_COLLISION_3D_H
#pragma once
#include "core/object/ref_counted.h"
#include "servers/physics_server_3d.h"
@ -61,5 +60,3 @@ public:
int get_collider_shape_index(int p_collision_index = 0) const;
Vector3 get_collider_velocity(int p_collision_index = 0) const;
};
#endif // KINEMATIC_COLLISION_3D_H

View file

@ -30,7 +30,7 @@
#include "physical_bone_3d.h"
#include "scene/3d/physical_bone_simulator_3d.h"
#include "scene/3d/physics/physical_bone_simulator_3d.h"
#ifndef DISABLE_DEPRECATED
#include "scene/3d/skeleton_3d.h"
#endif //_DISABLE_DEPRECATED
@ -752,8 +752,9 @@ void PhysicalBone3D::_get_property_list(List<PropertyInfo> *p_list) const {
void PhysicalBone3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_PARENTED:
// We need to wait until the bone has finished being added to the tree
// or none of the global transform calls will work correctly.
case NOTIFICATION_POST_ENTER_TREE:
_update_simulator_path();
update_bone_id();
reset_to_rest_position();
@ -763,6 +764,9 @@ void PhysicalBone3D::_notification(int p_what) {
}
break;
// If we're detached from the skeleton we need to
// clear our references to it.
case NOTIFICATION_UNPARENTED:
case NOTIFICATION_EXIT_TREE: {
PhysicalBoneSimulator3D *simulator = get_simulator();
if (simulator) {
@ -1052,7 +1056,7 @@ void PhysicalBone3D::_update_simulator_path() {
}
PhysicalBoneSimulator3D *PhysicalBone3D::get_simulator() const {
return Object::cast_to<PhysicalBoneSimulator3D>(ObjectDB::get_instance(simulator_id));
return ObjectDB::get_instance<PhysicalBoneSimulator3D>(simulator_id);
}
Skeleton3D *PhysicalBone3D::get_skeleton() const {

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PHYSICAL_BONE_3D_H
#define PHYSICAL_BONE_3D_H
#pragma once
#include "scene/3d/physics/physics_body_3d.h"
#include "scene/3d/skeleton_3d.h"
@ -84,8 +83,8 @@ public:
virtual bool _get(const StringName &p_name, Variant &r_ret) const;
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
real_t swing_span = Math_PI * 0.25;
real_t twist_span = Math_PI;
real_t swing_span = Math::PI * 0.25;
real_t twist_span = Math::PI;
real_t bias = 0.3;
real_t softness = 0.8;
real_t relaxation = 1.;
@ -99,8 +98,8 @@ public:
virtual void _get_property_list(List<PropertyInfo> *p_list) const;
bool angular_limit_enabled = false;
real_t angular_limit_upper = Math_PI * 0.5;
real_t angular_limit_lower = -Math_PI * 0.5;
real_t angular_limit_upper = Math::PI * 0.5;
real_t angular_limit_lower = -Math::PI * 0.5;
real_t angular_limit_bias = 0.3;
real_t angular_limit_softness = 0.9;
real_t angular_limit_relaxation = 1.;
@ -307,5 +306,3 @@ private:
VARIANT_ENUM_CAST(PhysicalBone3D::JointType);
VARIANT_ENUM_CAST(PhysicalBone3D::DampMode);
#endif // PHYSICAL_BONE_3D_H

View file

@ -0,0 +1,396 @@
/**************************************************************************/
/* physical_bone_simulator_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "physical_bone_simulator_3d.h"
#include "scene/3d/physics/physical_bone_3d.h"
void PhysicalBoneSimulator3D::_skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) {
if (p_old) {
if (p_old->is_connected(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed))) {
p_old->disconnect(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed));
}
if (p_old->is_connected(SceneStringName(pose_updated), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated))) {
p_old->disconnect(SceneStringName(pose_updated), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated));
}
}
if (p_new) {
if (!p_new->is_connected(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed))) {
p_new->connect(SNAME("bone_list_changed"), callable_mp(this, &PhysicalBoneSimulator3D::_bone_list_changed));
}
if (!p_new->is_connected(SceneStringName(pose_updated), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated))) {
p_new->connect(SceneStringName(pose_updated), callable_mp(this, &PhysicalBoneSimulator3D::_pose_updated));
}
}
_bone_list_changed();
}
void PhysicalBoneSimulator3D::_bone_list_changed() {
bones.clear();
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return;
}
for (int i = 0; i < skeleton->get_bone_count(); i++) {
SimulatedBone sb;
sb.parent = skeleton->get_bone_parent(i);
sb.child_bones = skeleton->get_bone_children(i);
bones.push_back(sb);
}
_rebuild_physical_bones_cache();
_pose_updated();
}
void PhysicalBoneSimulator3D::_pose_updated() {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton || simulating) {
return;
}
// If this triggers that means that we likely haven't rebuilt the bone list yet.
if (skeleton->get_bone_count() != bones.size()) {
// NOTE: this is re-entrant and will call _pose_updated again.
_bone_list_changed();
} else {
for (int i = 0; i < skeleton->get_bone_count(); i++) {
_bone_pose_updated(skeleton, i);
}
}
}
void PhysicalBoneSimulator3D::_bone_pose_updated(Skeleton3D *p_skeleton, int p_bone_id) {
ERR_FAIL_INDEX(p_bone_id, bones.size());
bones.write[p_bone_id].global_pose = p_skeleton->get_bone_global_pose(p_bone_id);
}
void PhysicalBoneSimulator3D::_set_active(bool p_active) {
if (!Engine::get_singleton()->is_editor_hint()) {
_reset_physical_bones_state();
}
}
void PhysicalBoneSimulator3D::_reset_physical_bones_state() {
for (int i = 0; i < bones.size(); i += 1) {
if (bones[i].physical_bone) {
bones[i].physical_bone->reset_physics_simulation_state();
}
}
}
bool PhysicalBoneSimulator3D::is_simulating_physics() const {
return simulating;
}
int PhysicalBoneSimulator3D::find_bone(const String &p_name) const {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return -1;
}
return skeleton->find_bone(p_name);
}
String PhysicalBoneSimulator3D::get_bone_name(int p_bone) const {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return String();
}
return skeleton->get_bone_name(p_bone);
}
int PhysicalBoneSimulator3D::get_bone_count() const {
return bones.size();
}
bool PhysicalBoneSimulator3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return false;
}
return skeleton->is_bone_parent_of(p_bone, p_parent_bone_id);
}
void PhysicalBoneSimulator3D::bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
ERR_FAIL_COND(bones[p_bone].physical_bone);
ERR_FAIL_NULL(p_physical_bone);
bones.write[p_bone].physical_bone = p_physical_bone;
_rebuild_physical_bones_cache();
}
void PhysicalBoneSimulator3D::unbind_physical_bone_from_bone(int p_bone) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].physical_bone = nullptr;
_rebuild_physical_bones_cache();
}
PhysicalBone3D *PhysicalBoneSimulator3D::get_physical_bone(int p_bone) {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
return bones[p_bone].physical_bone;
}
PhysicalBone3D *PhysicalBoneSimulator3D::get_physical_bone_parent(int p_bone) {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
if (bones[p_bone].cache_parent_physical_bone) {
return bones[p_bone].cache_parent_physical_bone;
}
return _get_physical_bone_parent(p_bone);
}
PhysicalBone3D *PhysicalBoneSimulator3D::_get_physical_bone_parent(int p_bone) {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, nullptr);
const int parent_bone = bones[p_bone].parent;
if (parent_bone < 0) {
return nullptr;
}
PhysicalBone3D *pb = bones[parent_bone].physical_bone;
if (pb) {
return pb;
} else {
return get_physical_bone_parent(parent_bone);
}
}
void PhysicalBoneSimulator3D::_rebuild_physical_bones_cache() {
const int b_size = bones.size();
for (int i = 0; i < b_size; ++i) {
PhysicalBone3D *parent_pb = _get_physical_bone_parent(i);
if (parent_pb != bones[i].cache_parent_physical_bone) {
bones.write[i].cache_parent_physical_bone = parent_pb;
if (bones[i].physical_bone) {
bones[i].physical_bone->_on_bone_parent_changed();
}
}
}
}
#ifndef DISABLE_DEPRECATED
void _pb_stop_simulation_compat(Node *p_node) {
PhysicalBoneSimulator3D *ps = Object::cast_to<PhysicalBoneSimulator3D>(p_node);
if (ps) {
return; // Prevent conflict.
}
for (int i = p_node->get_child_count() - 1; i >= 0; --i) {
_pb_stop_simulation_compat(p_node->get_child(i));
}
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
pb->set_simulate_physics(false);
}
}
#endif // _DISABLE_DEPRECATED
void _pb_stop_simulation(Node *p_node) {
for (int i = p_node->get_child_count() - 1; i >= 0; --i) {
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node->get_child(i));
if (!pb) {
continue;
}
_pb_stop_simulation(pb);
}
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
pb->set_simulate_physics(false);
}
}
void PhysicalBoneSimulator3D::physical_bones_stop_simulation() {
simulating = false;
_reset_physical_bones_state();
#ifndef DISABLE_DEPRECATED
if (is_compat) {
Skeleton3D *sk = get_skeleton();
if (sk) {
_pb_stop_simulation_compat(sk);
}
} else {
_pb_stop_simulation(this);
}
#else
_pb_stop_simulation(this);
#endif // _DISABLE_DEPRECATED
}
#ifndef DISABLE_DEPRECATED
void _pb_start_simulation_compat(const PhysicalBoneSimulator3D *p_simulator, Node *p_node, const Vector<int> &p_sim_bones) {
PhysicalBoneSimulator3D *ps = Object::cast_to<PhysicalBoneSimulator3D>(p_node);
if (ps) {
return; // Prevent conflict.
}
for (int i = p_node->get_child_count() - 1; i >= 0; --i) {
_pb_start_simulation_compat(p_simulator, p_node->get_child(i), p_sim_bones);
}
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
if (p_sim_bones.is_empty()) { // If no bones are specified, activate ragdoll on full body.
pb->set_simulate_physics(true);
} else {
for (int i = p_sim_bones.size() - 1; i >= 0; --i) {
if (p_sim_bones[i] == pb->get_bone_id() || p_simulator->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
pb->set_simulate_physics(true);
break;
}
}
}
}
}
#endif // _DISABLE_DEPRECATED
void _pb_start_simulation(const PhysicalBoneSimulator3D *p_simulator, Node *p_node, const Vector<int> &p_sim_bones) {
for (int i = p_node->get_child_count() - 1; i >= 0; --i) {
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node->get_child(i));
if (!pb) {
continue;
}
_pb_start_simulation(p_simulator, pb, p_sim_bones);
}
PhysicalBone3D *pb = Object::cast_to<PhysicalBone3D>(p_node);
if (pb) {
if (p_sim_bones.is_empty()) { // If no bones are specified, activate ragdoll on full body.
pb->set_simulate_physics(true);
} else {
for (int i = p_sim_bones.size() - 1; i >= 0; --i) {
if (p_sim_bones[i] == pb->get_bone_id() || p_simulator->is_bone_parent_of(pb->get_bone_id(), p_sim_bones[i])) {
pb->set_simulate_physics(true);
break;
}
}
}
}
}
void PhysicalBoneSimulator3D::physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones) {
_pose_updated();
simulating = true;
_reset_physical_bones_state();
Vector<int> sim_bones;
if (p_bones.size() > 0) {
sim_bones.resize(p_bones.size());
int c = 0;
for (int i = sim_bones.size() - 1; i >= 0; --i) {
int bone_id = find_bone(p_bones[i]);
if (bone_id != -1) {
sim_bones.write[c++] = bone_id;
}
}
sim_bones.resize(c);
}
#ifndef DISABLE_DEPRECATED
if (is_compat) {
Skeleton3D *sk = get_skeleton();
if (sk) {
_pb_start_simulation_compat(this, sk, sim_bones);
}
} else {
_pb_start_simulation(this, this, sim_bones);
}
#else
_pb_start_simulation(this, this, sim_bones);
#endif // _DISABLE_DEPRECATED
}
void _physical_bones_add_remove_collision_exception(bool p_add, Node *p_node, RID p_exception) {
for (int i = p_node->get_child_count() - 1; i >= 0; --i) {
_physical_bones_add_remove_collision_exception(p_add, p_node->get_child(i), p_exception);
}
CollisionObject3D *co = Object::cast_to<CollisionObject3D>(p_node);
if (co) {
if (p_add) {
PhysicsServer3D::get_singleton()->body_add_collision_exception(co->get_rid(), p_exception);
} else {
PhysicsServer3D::get_singleton()->body_remove_collision_exception(co->get_rid(), p_exception);
}
}
}
void PhysicalBoneSimulator3D::physical_bones_add_collision_exception(RID p_exception) {
_physical_bones_add_remove_collision_exception(true, this, p_exception);
}
void PhysicalBoneSimulator3D::physical_bones_remove_collision_exception(RID p_exception) {
_physical_bones_add_remove_collision_exception(false, this, p_exception);
}
Transform3D PhysicalBoneSimulator3D::get_bone_global_pose(int p_bone) const {
const int bone_size = bones.size();
ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
return bones[p_bone].global_pose;
}
void PhysicalBoneSimulator3D::set_bone_global_pose(int p_bone, const Transform3D &p_pose) {
const int bone_size = bones.size();
ERR_FAIL_INDEX(p_bone, bone_size);
bones.write[p_bone].global_pose = p_pose;
}
void PhysicalBoneSimulator3D::_process_modification(double p_delta) {
Skeleton3D *skeleton = get_skeleton();
if (!skeleton) {
return;
}
ERR_FAIL_COND(skeleton->get_bone_count() != bones.size());
for (int i = 0; i < skeleton->get_bone_count(); i++) {
if (!bones[i].physical_bone) {
continue;
}
if (bones[i].physical_bone->is_simulating_physics() == false) {
_bone_pose_updated(skeleton, i);
bones[i].physical_bone->reset_to_rest_position();
} else if (simulating) {
skeleton->set_bone_global_pose(i, bones[i].global_pose);
}
}
}
void PhysicalBoneSimulator3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_simulating_physics"), &PhysicalBoneSimulator3D::is_simulating_physics);
ClassDB::bind_method(D_METHOD("physical_bones_stop_simulation"), &PhysicalBoneSimulator3D::physical_bones_stop_simulation);
ClassDB::bind_method(D_METHOD("physical_bones_start_simulation", "bones"), &PhysicalBoneSimulator3D::physical_bones_start_simulation_on, DEFVAL(Array()));
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &PhysicalBoneSimulator3D::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &PhysicalBoneSimulator3D::physical_bones_remove_collision_exception);
}
PhysicalBoneSimulator3D::PhysicalBoneSimulator3D() {
}

View file

@ -0,0 +1,105 @@
/**************************************************************************/
/* physical_bone_simulator_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/3d/skeleton_modifier_3d.h"
class PhysicalBone3D;
class PhysicalBoneSimulator3D : public SkeletonModifier3D {
GDCLASS(PhysicalBoneSimulator3D, SkeletonModifier3D);
bool simulating = false;
struct SimulatedBone {
int parent;
Vector<int> child_bones;
Transform3D global_pose;
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
SimulatedBone() {
parent = -1;
global_pose = Transform3D();
physical_bone = nullptr;
cache_parent_physical_bone = nullptr;
}
};
Vector<SimulatedBone> bones;
/// This is a slow API, so it's cached
PhysicalBone3D *_get_physical_bone_parent(int p_bone);
void _rebuild_physical_bones_cache();
void _reset_physical_bones_state();
protected:
static void _bind_methods();
virtual void _set_active(bool p_active) override;
void _bone_list_changed();
void _pose_updated();
void _bone_pose_updated(Skeleton3D *skeleton, int p_bone_id);
virtual void _process_modification(double p_delta) override;
virtual void _skeleton_changed(Skeleton3D *p_old, Skeleton3D *p_new) override;
public:
#ifndef DISABLE_DEPRECATED
bool is_compat = false;
#endif // _DISABLE_DEPRECATED
bool is_simulating_physics() const;
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
int get_bone_count() const;
bool is_bone_parent_of(int p_bone_id, int p_parent_bone_id) const;
Transform3D get_bone_global_pose(int p_bone) const;
void set_bone_global_pose(int p_bone, const Transform3D &p_pose);
void bind_physical_bone_to_bone(int p_bone, PhysicalBone3D *p_physical_bone);
void unbind_physical_bone_from_bone(int p_bone);
PhysicalBone3D *get_physical_bone(int p_bone);
PhysicalBone3D *get_physical_bone_parent(int p_bone);
void physical_bones_stop_simulation();
void physical_bones_start_simulation_on(const TypedArray<StringName> &p_bones);
void physical_bones_add_collision_exception(RID p_exception);
void physical_bones_remove_collision_exception(RID p_exception);
PhysicalBoneSimulator3D();
};

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef PHYSICS_BODY_3D_H
#define PHYSICS_BODY_3D_H
#pragma once
#include "scene/3d/physics/collision_object_3d.h"
#include "scene/3d/physics/kinematic_collision_3d.h"
@ -65,5 +64,3 @@ public:
void add_collision_exception_with(Node *p_node); //must be physicsbody
void remove_collision_exception_with(Node *p_node);
};
#endif // PHYSICS_BODY_3D_H

View file

@ -413,7 +413,7 @@ void RayCast3D::_update_debug_shape_vertices() {
int vertices_strip_order[14] = { 4, 5, 0, 1, 2, 5, 6, 4, 7, 0, 3, 2, 7, 6 };
for (int v = 0; v < 14; v++) {
Vector3 vertex = vertices_strip_order[v] < 4 ? normal : normal / 3.0 + target_position;
debug_shape_vertices.push_back(vertex.rotated(dir, Math_PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25)));
debug_shape_vertices.push_back(vertex.rotated(dir, Math::PI * (0.5 * (vertices_strip_order[v] % 4) + 0.25)));
}
}
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef RAY_CAST_3D_H
#define RAY_CAST_3D_H
#pragma once
#include "scene/3d/node_3d.h"
@ -135,5 +134,3 @@ public:
RayCast3D();
};
#endif // RAY_CAST_3D_H

View file

@ -521,6 +521,7 @@ bool RigidBody3D::is_sleeping() const {
}
void RigidBody3D::set_max_contacts_reported(int p_amount) {
ERR_FAIL_INDEX_MSG(p_amount, MAX_CONTACTS_REPORTED_3D_MAX, "Max contacts reported allocates memory (about 80 bytes each), and therefore must not be set too high.");
max_contacts_reported = p_amount;
PhysicsServer3D::get_singleton()->body_set_max_contacts_reported(get_rid(), p_amount);
}
@ -662,7 +663,7 @@ PackedStringArray RigidBody3D::get_configuration_warnings() const {
PackedStringArray warnings = PhysicsBody3D::get_configuration_warnings();
Vector3 scale = get_transform().get_basis().get_scale();
if (ABS(scale.x - 1.0) > 0.05 || ABS(scale.y - 1.0) > 0.05 || ABS(scale.z - 1.0) > 0.05) {
if (Math::abs(scale.x - 1.0) > 0.05 || Math::abs(scale.y - 1.0) > 0.05 || Math::abs(scale.z - 1.0) > 0.05) {
warnings.push_back(RTR("Scale changes to RigidBody3D will be overridden by the physics engine when running.\nPlease change the size in children collision shapes instead."));
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef RIGID_BODY_3D_H
#define RIGID_BODY_3D_H
#pragma once
#include "core/templates/vset.h"
#include "scene/3d/physics/physics_body_3d.h"
@ -245,5 +244,3 @@ private:
VARIANT_ENUM_CAST(RigidBody3D::FreezeMode);
VARIANT_ENUM_CAST(RigidBody3D::CenterOfMassMode);
VARIANT_ENUM_CAST(RigidBody3D::DampMode);
#endif // RIGID_BODY_3D_H

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SHAPE_CAST_3D_H
#define SHAPE_CAST_3D_H
#pragma once
#include "scene/3d/node_3d.h"
#include "scene/resources/3d/shape_3d.h"
@ -143,5 +142,3 @@ public:
virtual PackedStringArray get_configuration_warnings() const override;
};
#endif // SHAPE_CAST_3D_H

View file

@ -0,0 +1,41 @@
/**************************************************************************/
/* soft_body_3d.compat.inc */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef DISABLE_DEPRECATED
void SoftBody3D::_pin_point_bind_compat_94684(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path) {
pin_point(p_point_index, pin, p_spatial_attachment_path, -1);
}
void SoftBody3D::_bind_compatibility_methods() {
ClassDB::bind_compatibility_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path"), &SoftBody3D::_pin_point_bind_compat_94684, DEFVAL(NodePath()));
}
#endif // DISABLE_DEPRECATED

View file

@ -0,0 +1,823 @@
/**************************************************************************/
/* soft_body_3d.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#include "soft_body_3d.h"
#include "soft_body_3d.compat.inc"
#include "scene/3d/physics/physics_body_3d.h"
SoftBodyRenderingServerHandler::SoftBodyRenderingServerHandler() {}
void SoftBodyRenderingServerHandler::prepare(RID p_mesh, int p_surface) {
clear();
ERR_FAIL_COND(!p_mesh.is_valid());
mesh = p_mesh;
surface = p_surface;
RS::SurfaceData surface_data = RS::get_singleton()->mesh_get_surface(mesh, surface);
uint32_t surface_offsets[RS::ARRAY_MAX];
uint32_t vertex_stride;
uint32_t normal_tangent_stride;
uint32_t attrib_stride;
uint32_t skin_stride;
RS::get_singleton()->mesh_surface_make_offsets_from_format(surface_data.format, surface_data.vertex_count, surface_data.index_count, surface_offsets, vertex_stride, normal_tangent_stride, attrib_stride, skin_stride);
buffer = surface_data.vertex_data;
stride = vertex_stride;
normal_stride = normal_tangent_stride;
offset_vertices = surface_offsets[RS::ARRAY_VERTEX];
offset_normal = surface_offsets[RS::ARRAY_NORMAL];
}
void SoftBodyRenderingServerHandler::clear() {
buffer.resize(0);
stride = 0;
normal_stride = 0;
offset_vertices = 0;
offset_normal = 0;
surface = 0;
mesh = RID();
}
void SoftBodyRenderingServerHandler::open() {
write_buffer = buffer.ptrw();
}
void SoftBodyRenderingServerHandler::close() {
write_buffer = nullptr;
}
void SoftBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
}
void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
float *vertex_buffer = reinterpret_cast<float *>(write_buffer + p_vertex_id * stride + offset_vertices);
*vertex_buffer++ = (float)p_vertex.x;
*vertex_buffer++ = (float)p_vertex.y;
*vertex_buffer++ = (float)p_vertex.z;
}
void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &p_normal) {
Vector2 res = p_normal.octahedron_encode();
uint32_t value = 0;
value |= (uint16_t)CLAMP(res.x * 65535, 0, 65535);
value |= (uint16_t)CLAMP(res.y * 65535, 0, 65535) << 16;
memcpy(&write_buffer[p_vertex_id * normal_stride + offset_normal], &value, sizeof(uint32_t));
}
void SoftBodyRenderingServerHandler::set_aabb(const AABB &p_aabb) {
RS::get_singleton()->mesh_set_custom_aabb(mesh, p_aabb);
}
SoftBody3D::PinnedPoint::PinnedPoint() {
}
SoftBody3D::PinnedPoint::PinnedPoint(const PinnedPoint &obj_tocopy) {
point_index = obj_tocopy.point_index;
spatial_attachment_path = obj_tocopy.spatial_attachment_path;
spatial_attachment = obj_tocopy.spatial_attachment;
offset = obj_tocopy.offset;
}
void SoftBody3D::PinnedPoint::operator=(const PinnedPoint &obj) {
point_index = obj.point_index;
spatial_attachment_path = obj.spatial_attachment_path;
spatial_attachment = obj.spatial_attachment;
offset = obj.offset;
}
void SoftBody3D::_update_pickable() {
if (!is_inside_tree()) {
return;
}
bool pickable = ray_pickable && is_visible_in_tree();
PhysicsServer3D::get_singleton()->soft_body_set_ray_pickable(physics_rid, pickable);
}
bool SoftBody3D::_set(const StringName &p_name, const Variant &p_value) {
String name = p_name;
String which = name.get_slicec('/', 0);
if ("pinned_points" == which) {
return _set_property_pinned_points_indices(p_value);
} else if ("attachments" == which) {
int idx = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
return _set_property_pinned_points_attachment(idx, what, p_value);
}
return false;
}
bool SoftBody3D::_get(const StringName &p_name, Variant &r_ret) const {
String name = p_name;
String which = name.get_slicec('/', 0);
if ("pinned_points" == which) {
Array arr_ret;
const int pinned_points_indices_size = pinned_points.size();
const PinnedPoint *r = pinned_points.ptr();
arr_ret.resize(pinned_points_indices_size);
for (int i = 0; i < pinned_points_indices_size; ++i) {
arr_ret[i] = r[i].point_index;
}
r_ret = arr_ret;
return true;
} else if ("attachments" == which) {
int idx = name.get_slicec('/', 1).to_int();
String what = name.get_slicec('/', 2);
return _get_property_pinned_points(idx, what, r_ret);
}
return false;
}
void SoftBody3D::_get_property_list(List<PropertyInfo> *p_list) const {
const int pinned_points_indices_size = pinned_points.size();
p_list->push_back(PropertyInfo(Variant::PACKED_INT32_ARRAY, PNAME("pinned_points")));
for (int i = 0; i < pinned_points_indices_size; ++i) {
const String prefix = vformat("%s/%d/", PNAME("attachments"), i);
p_list->push_back(PropertyInfo(Variant::INT, prefix + PNAME("point_index")));
p_list->push_back(PropertyInfo(Variant::NODE_PATH, prefix + PNAME("spatial_attachment_path")));
p_list->push_back(PropertyInfo(Variant::VECTOR3, prefix + PNAME("offset")));
}
}
bool SoftBody3D::_set_property_pinned_points_indices(const Array &p_indices) {
const int p_indices_size = p_indices.size();
{ // Remove the pined points on physics server that will be removed by resize
const PinnedPoint *r = pinned_points.ptr();
if (p_indices_size < pinned_points.size()) {
for (int i = pinned_points.size() - 1; i >= p_indices_size; --i) {
pin_point(r[i].point_index, false);
}
}
}
pinned_points.resize(p_indices_size);
PinnedPoint *w = pinned_points.ptrw();
int point_index;
for (int i = 0; i < p_indices_size; ++i) {
point_index = p_indices.get(i);
if (w[i].point_index != point_index || pinned_points.size() < p_indices_size) {
bool insert = false;
if (w[i].point_index != -1 && p_indices.find(w[i].point_index) == -1) {
pin_point(w[i].point_index, false);
insert = true;
}
w[i].point_index = point_index;
if (insert) {
pin_point(w[i].point_index, true, NodePath(), i);
} else {
pin_point(w[i].point_index, true);
}
}
}
return true;
}
bool SoftBody3D::_set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value) {
if (pinned_points.size() <= p_item) {
return false;
}
if ("spatial_attachment_path" == p_what) {
PinnedPoint *w = pinned_points.ptrw();
if (is_inside_tree()) {
callable_mp(this, &SoftBody3D::_pin_point_deferred).call_deferred(Variant(w[p_item].point_index), true, p_value);
} else {
pin_point(w[p_item].point_index, true, p_value);
_make_cache_dirty();
}
} else if ("offset" == p_what) {
PinnedPoint *w = pinned_points.ptrw();
w[p_item].offset = p_value;
} else {
return false;
}
return true;
}
bool SoftBody3D::_get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const {
if (pinned_points.size() <= p_item) {
return false;
}
const PinnedPoint *r = pinned_points.ptr();
if ("point_index" == p_what) {
r_ret = r[p_item].point_index;
} else if ("spatial_attachment_path" == p_what) {
r_ret = r[p_item].spatial_attachment_path;
} else if ("offset" == p_what) {
r_ret = r[p_item].offset;
} else {
return false;
}
return true;
}
void SoftBody3D::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_WORLD: {
if (Engine::get_singleton()->is_editor_hint()) {
// I have no idea what this is supposed to do, it's really weird
// leaving for upcoming PK work on physics
//add_change_receptor(this);
}
RID space = get_world_3d()->get_space();
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, space);
_prepare_physics_server();
} break;
case NOTIFICATION_READY: {
if (!parent_collision_ignore.is_empty()) {
add_collision_exception_with(get_node(parent_collision_ignore));
}
} break;
case NOTIFICATION_TRANSFORM_CHANGED: {
if (Engine::get_singleton()->is_editor_hint()) {
_reset_points_offsets();
return;
}
PhysicsServer3D::get_singleton()->soft_body_set_transform(physics_rid, get_global_transform());
set_notify_transform(false);
// Required to be top level with Transform at center of world in order to modify RenderingServer only to support custom Transform
set_as_top_level(true);
set_transform(Transform3D());
set_notify_transform(true);
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
_update_pickable();
} break;
case NOTIFICATION_EXIT_WORLD: {
PhysicsServer3D::get_singleton()->soft_body_set_space(physics_rid, RID());
} break;
case NOTIFICATION_DISABLED: {
if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
_prepare_physics_server();
}
} break;
case NOTIFICATION_ENABLED: {
if (is_inside_tree() && (disable_mode == DISABLE_MODE_REMOVE)) {
_prepare_physics_server();
}
} break;
}
}
void SoftBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_physics_rid"), &SoftBody3D::get_physics_rid);
ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &SoftBody3D::set_collision_mask);
ClassDB::bind_method(D_METHOD("get_collision_mask"), &SoftBody3D::get_collision_mask);
ClassDB::bind_method(D_METHOD("set_collision_layer", "collision_layer"), &SoftBody3D::set_collision_layer);
ClassDB::bind_method(D_METHOD("get_collision_layer"), &SoftBody3D::get_collision_layer);
ClassDB::bind_method(D_METHOD("set_collision_mask_value", "layer_number", "value"), &SoftBody3D::set_collision_mask_value);
ClassDB::bind_method(D_METHOD("get_collision_mask_value", "layer_number"), &SoftBody3D::get_collision_mask_value);
ClassDB::bind_method(D_METHOD("set_collision_layer_value", "layer_number", "value"), &SoftBody3D::set_collision_layer_value);
ClassDB::bind_method(D_METHOD("get_collision_layer_value", "layer_number"), &SoftBody3D::get_collision_layer_value);
ClassDB::bind_method(D_METHOD("set_parent_collision_ignore", "parent_collision_ignore"), &SoftBody3D::set_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("get_parent_collision_ignore"), &SoftBody3D::get_parent_collision_ignore);
ClassDB::bind_method(D_METHOD("set_disable_mode", "mode"), &SoftBody3D::set_disable_mode);
ClassDB::bind_method(D_METHOD("get_disable_mode"), &SoftBody3D::get_disable_mode);
ClassDB::bind_method(D_METHOD("get_collision_exceptions"), &SoftBody3D::get_collision_exceptions);
ClassDB::bind_method(D_METHOD("add_collision_exception_with", "body"), &SoftBody3D::add_collision_exception_with);
ClassDB::bind_method(D_METHOD("remove_collision_exception_with", "body"), &SoftBody3D::remove_collision_exception_with);
ClassDB::bind_method(D_METHOD("set_simulation_precision", "simulation_precision"), &SoftBody3D::set_simulation_precision);
ClassDB::bind_method(D_METHOD("get_simulation_precision"), &SoftBody3D::get_simulation_precision);
ClassDB::bind_method(D_METHOD("set_total_mass", "mass"), &SoftBody3D::set_total_mass);
ClassDB::bind_method(D_METHOD("get_total_mass"), &SoftBody3D::get_total_mass);
ClassDB::bind_method(D_METHOD("set_linear_stiffness", "linear_stiffness"), &SoftBody3D::set_linear_stiffness);
ClassDB::bind_method(D_METHOD("get_linear_stiffness"), &SoftBody3D::get_linear_stiffness);
ClassDB::bind_method(D_METHOD("set_pressure_coefficient", "pressure_coefficient"), &SoftBody3D::set_pressure_coefficient);
ClassDB::bind_method(D_METHOD("get_pressure_coefficient"), &SoftBody3D::get_pressure_coefficient);
ClassDB::bind_method(D_METHOD("set_damping_coefficient", "damping_coefficient"), &SoftBody3D::set_damping_coefficient);
ClassDB::bind_method(D_METHOD("get_damping_coefficient"), &SoftBody3D::get_damping_coefficient);
ClassDB::bind_method(D_METHOD("set_drag_coefficient", "drag_coefficient"), &SoftBody3D::set_drag_coefficient);
ClassDB::bind_method(D_METHOD("get_drag_coefficient"), &SoftBody3D::get_drag_coefficient);
ClassDB::bind_method(D_METHOD("get_point_transform", "point_index"), &SoftBody3D::get_point_transform);
ClassDB::bind_method(D_METHOD("set_point_pinned", "point_index", "pinned", "attachment_path", "insert_at"), &SoftBody3D::pin_point, DEFVAL(NodePath()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("is_point_pinned", "point_index"), &SoftBody3D::is_point_pinned);
ClassDB::bind_method(D_METHOD("set_ray_pickable", "ray_pickable"), &SoftBody3D::set_ray_pickable);
ClassDB::bind_method(D_METHOD("is_ray_pickable"), &SoftBody3D::is_ray_pickable);
ADD_GROUP("Collision", "collision_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_layer", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_layer", "get_collision_layer");
ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "parent_collision_ignore", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "CollisionObject3D"), "set_parent_collision_ignore", "get_parent_collision_ignore");
ADD_PROPERTY(PropertyInfo(Variant::INT, "simulation_precision", PROPERTY_HINT_RANGE, "1,100,1"), "set_simulation_precision", "get_simulation_precision");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_mass", PROPERTY_HINT_RANGE, "0.01,10000,1"), "set_total_mass", "get_total_mass");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "linear_stiffness", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_linear_stiffness", "get_linear_stiffness");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pressure_coefficient"), "set_pressure_coefficient", "get_pressure_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_damping_coefficient", "get_damping_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "drag_coefficient", PROPERTY_HINT_RANGE, "0,1,0.01"), "set_drag_coefficient", "get_drag_coefficient");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ray_pickable"), "set_ray_pickable", "is_ray_pickable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "disable_mode", PROPERTY_HINT_ENUM, "Remove,KeepActive"), "set_disable_mode", "get_disable_mode");
BIND_ENUM_CONSTANT(DISABLE_MODE_REMOVE);
BIND_ENUM_CONSTANT(DISABLE_MODE_KEEP_ACTIVE);
}
PackedStringArray SoftBody3D::get_configuration_warnings() const {
PackedStringArray warnings = MeshInstance3D::get_configuration_warnings();
if (mesh.is_null()) {
warnings.push_back(RTR("This body will be ignored until you set a mesh."));
}
return warnings;
}
void SoftBody3D::_update_physics_server() {
if (!simulation_started) {
return;
}
_update_cache_pin_points_datas();
// Submit bone attachment
const int pinned_points_indices_size = pinned_points.size();
const PinnedPoint *r = pinned_points.ptr();
for (int i = 0; i < pinned_points_indices_size; ++i) {
if (r[i].spatial_attachment) {
PhysicsServer3D::get_singleton()->soft_body_move_point(physics_rid, r[i].point_index, r[i].spatial_attachment->get_global_transform().xform(r[i].offset));
}
}
}
void SoftBody3D::_draw_soft_mesh() {
if (mesh.is_null()) {
return;
}
RID mesh_rid = mesh->get_rid();
if (owned_mesh != mesh_rid) {
_become_mesh_owner();
mesh_rid = mesh->get_rid();
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
}
if (!rendering_server_handler->is_ready(mesh_rid)) {
rendering_server_handler->prepare(mesh_rid, 0);
/// Necessary in order to render the mesh correctly (Soft body nodes are in global space)
simulation_started = true;
callable_mp((Node3D *)this, &Node3D::set_as_top_level).call_deferred(true);
callable_mp((Node3D *)this, &Node3D::set_transform).call_deferred(Transform3D());
}
_update_physics_server();
rendering_server_handler->open();
PhysicsServer3D::get_singleton()->soft_body_update_rendering_server(physics_rid, rendering_server_handler);
rendering_server_handler->close();
rendering_server_handler->commit_changes();
}
void SoftBody3D::_prepare_physics_server() {
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint()) {
if (mesh.is_valid()) {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh->get_rid());
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
}
return;
}
#endif
if (mesh.is_valid() && (is_enabled() || (disable_mode != DISABLE_MODE_REMOVE))) {
RID mesh_rid = mesh->get_rid();
if (owned_mesh != mesh_rid) {
_become_mesh_owner();
mesh_rid = mesh->get_rid();
}
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, mesh_rid);
RS::get_singleton()->connect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
} else {
PhysicsServer3D::get_singleton()->soft_body_set_mesh(physics_rid, RID());
if (RS::get_singleton()->is_connected("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh))) {
RS::get_singleton()->disconnect("frame_pre_draw", callable_mp(this, &SoftBody3D::_draw_soft_mesh));
}
}
}
void SoftBody3D::_become_mesh_owner() {
Vector<Ref<Material>> copy_materials;
copy_materials.append_array(surface_override_materials);
ERR_FAIL_COND(!mesh->get_surface_count());
// Get current mesh array and create new mesh array with necessary flag for SoftBody
Array surface_arrays = mesh->surface_get_arrays(0);
Array surface_blend_arrays = mesh->surface_get_blend_shape_arrays(0);
Dictionary surface_lods = mesh->surface_get_lods(0);
uint32_t surface_format = mesh->surface_get_format(0);
surface_format |= Mesh::ARRAY_FLAG_USE_DYNAMIC_UPDATE;
surface_format &= ~Mesh::ARRAY_FLAG_COMPRESS_ATTRIBUTES;
Ref<ArrayMesh> soft_mesh;
soft_mesh.instantiate();
soft_mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface_arrays, surface_blend_arrays, surface_lods, surface_format);
soft_mesh->surface_set_material(0, mesh->surface_get_material(0));
set_mesh(soft_mesh);
for (int i = copy_materials.size() - 1; 0 <= i; --i) {
set_surface_override_material(i, copy_materials[i]);
}
owned_mesh = soft_mesh->get_rid();
}
void SoftBody3D::set_collision_mask(uint32_t p_mask) {
collision_mask = p_mask;
PhysicsServer3D::get_singleton()->soft_body_set_collision_mask(physics_rid, p_mask);
}
uint32_t SoftBody3D::get_collision_mask() const {
return collision_mask;
}
void SoftBody3D::set_collision_layer(uint32_t p_layer) {
collision_layer = p_layer;
PhysicsServer3D::get_singleton()->soft_body_set_collision_layer(physics_rid, p_layer);
}
uint32_t SoftBody3D::get_collision_layer() const {
return collision_layer;
}
void SoftBody3D::set_collision_layer_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t collision_layer_new = get_collision_layer();
if (p_value) {
collision_layer_new |= 1 << (p_layer_number - 1);
} else {
collision_layer_new &= ~(1 << (p_layer_number - 1));
}
set_collision_layer(collision_layer_new);
}
bool SoftBody3D::get_collision_layer_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_layer() & (1 << (p_layer_number - 1));
}
void SoftBody3D::set_collision_mask_value(int p_layer_number, bool p_value) {
ERR_FAIL_COND_MSG(p_layer_number < 1, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_MSG(p_layer_number > 32, "Collision layer number must be between 1 and 32 inclusive.");
uint32_t mask = get_collision_mask();
if (p_value) {
mask |= 1 << (p_layer_number - 1);
} else {
mask &= ~(1 << (p_layer_number - 1));
}
set_collision_mask(mask);
}
bool SoftBody3D::get_collision_mask_value(int p_layer_number) const {
ERR_FAIL_COND_V_MSG(p_layer_number < 1, false, "Collision layer number must be between 1 and 32 inclusive.");
ERR_FAIL_COND_V_MSG(p_layer_number > 32, false, "Collision layer number must be between 1 and 32 inclusive.");
return get_collision_mask() & (1 << (p_layer_number - 1));
}
void SoftBody3D::set_disable_mode(DisableMode p_mode) {
if (disable_mode == p_mode) {
return;
}
disable_mode = p_mode;
if (mesh.is_valid() && is_inside_tree() && !is_enabled()) {
_prepare_physics_server();
}
}
SoftBody3D::DisableMode SoftBody3D::get_disable_mode() const {
return disable_mode;
}
void SoftBody3D::set_parent_collision_ignore(const NodePath &p_parent_collision_ignore) {
parent_collision_ignore = p_parent_collision_ignore;
}
const NodePath &SoftBody3D::get_parent_collision_ignore() const {
return parent_collision_ignore;
}
void SoftBody3D::set_pinned_points_indices(Vector<SoftBody3D::PinnedPoint> p_pinned_points_indices) {
pinned_points = p_pinned_points_indices;
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
pin_point(p_pinned_points_indices[i].point_index, true);
}
}
Vector<SoftBody3D::PinnedPoint> SoftBody3D::get_pinned_points_indices() {
return pinned_points;
}
TypedArray<PhysicsBody3D> SoftBody3D::get_collision_exceptions() {
List<RID> exceptions;
PhysicsServer3D::get_singleton()->soft_body_get_collision_exceptions(physics_rid, &exceptions);
TypedArray<PhysicsBody3D> ret;
for (const RID &body : exceptions) {
ObjectID instance_id = PhysicsServer3D::get_singleton()->body_get_object_instance_id(body);
Object *obj = ObjectDB::get_instance(instance_id);
PhysicsBody3D *physics_body = Object::cast_to<PhysicsBody3D>(obj);
ret.append(physics_body);
}
return ret;
}
void SoftBody3D::add_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->soft_body_add_collision_exception(physics_rid, collision_object->get_rid());
}
void SoftBody3D::remove_collision_exception_with(Node *p_node) {
ERR_FAIL_NULL(p_node);
CollisionObject3D *collision_object = Object::cast_to<CollisionObject3D>(p_node);
ERR_FAIL_NULL_MSG(collision_object, "Collision exception only works between two nodes that inherit from CollisionObject3D (such as Area3D or PhysicsBody3D).");
PhysicsServer3D::get_singleton()->soft_body_remove_collision_exception(physics_rid, collision_object->get_rid());
}
int SoftBody3D::get_simulation_precision() {
return PhysicsServer3D::get_singleton()->soft_body_get_simulation_precision(physics_rid);
}
void SoftBody3D::set_simulation_precision(int p_simulation_precision) {
PhysicsServer3D::get_singleton()->soft_body_set_simulation_precision(physics_rid, p_simulation_precision);
}
real_t SoftBody3D::get_total_mass() {
return PhysicsServer3D::get_singleton()->soft_body_get_total_mass(physics_rid);
}
void SoftBody3D::set_total_mass(real_t p_total_mass) {
PhysicsServer3D::get_singleton()->soft_body_set_total_mass(physics_rid, p_total_mass);
}
void SoftBody3D::set_linear_stiffness(real_t p_linear_stiffness) {
PhysicsServer3D::get_singleton()->soft_body_set_linear_stiffness(physics_rid, p_linear_stiffness);
}
real_t SoftBody3D::get_linear_stiffness() {
return PhysicsServer3D::get_singleton()->soft_body_get_linear_stiffness(physics_rid);
}
real_t SoftBody3D::get_pressure_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_pressure_coefficient(physics_rid);
}
void SoftBody3D::set_pressure_coefficient(real_t p_pressure_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_pressure_coefficient(physics_rid, p_pressure_coefficient);
}
real_t SoftBody3D::get_damping_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_damping_coefficient(physics_rid);
}
void SoftBody3D::set_damping_coefficient(real_t p_damping_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_damping_coefficient(physics_rid, p_damping_coefficient);
}
real_t SoftBody3D::get_drag_coefficient() {
return PhysicsServer3D::get_singleton()->soft_body_get_drag_coefficient(physics_rid);
}
void SoftBody3D::set_drag_coefficient(real_t p_drag_coefficient) {
PhysicsServer3D::get_singleton()->soft_body_set_drag_coefficient(physics_rid, p_drag_coefficient);
}
Vector3 SoftBody3D::get_point_transform(int p_point_index) {
return PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, p_point_index);
}
void SoftBody3D::pin_point_toggle(int p_point_index) {
pin_point(p_point_index, !(-1 != _has_pinned_point(p_point_index)));
}
void SoftBody3D::pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path, int p_insert_at) {
ERR_FAIL_COND_MSG(p_insert_at < -1 || p_insert_at >= pinned_points.size(), "Invalid index for pin point insertion position.");
_pin_point_on_physics_server(p_point_index, pin);
if (pin) {
_add_pinned_point(p_point_index, p_spatial_attachment_path, p_insert_at);
} else {
_remove_pinned_point(p_point_index);
}
}
void SoftBody3D::_pin_point_deferred(int p_point_index, bool pin, const NodePath p_spatial_attachment_path) {
pin_point(p_point_index, pin, p_spatial_attachment_path);
_make_cache_dirty();
}
bool SoftBody3D::is_point_pinned(int p_point_index) const {
return -1 != _has_pinned_point(p_point_index);
}
void SoftBody3D::set_ray_pickable(bool p_ray_pickable) {
ray_pickable = p_ray_pickable;
_update_pickable();
}
bool SoftBody3D::is_ray_pickable() const {
return ray_pickable;
}
SoftBody3D::SoftBody3D() :
physics_rid(PhysicsServer3D::get_singleton()->soft_body_create()) {
rendering_server_handler = memnew(SoftBodyRenderingServerHandler);
PhysicsServer3D::get_singleton()->body_attach_object_instance_id(physics_rid, get_instance_id());
}
SoftBody3D::~SoftBody3D() {
memdelete(rendering_server_handler);
ERR_FAIL_NULL(PhysicsServer3D::get_singleton());
PhysicsServer3D::get_singleton()->free(physics_rid);
}
void SoftBody3D::_make_cache_dirty() {
pinned_points_cache_dirty = true;
}
void SoftBody3D::_update_cache_pin_points_datas() {
if (!pinned_points_cache_dirty) {
return;
}
pinned_points_cache_dirty = false;
PinnedPoint *w = pinned_points.ptrw();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!w[i].spatial_attachment_path.is_empty()) {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(w[i].spatial_attachment_path));
}
}
}
void SoftBody3D::_pin_point_on_physics_server(int p_point_index, bool pin) {
PhysicsServer3D::get_singleton()->soft_body_pin_point(physics_rid, p_point_index, pin);
}
void SoftBody3D::_add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path, int p_insert_at) {
SoftBody3D::PinnedPoint *pinned_point;
if (-1 == _get_pinned_point(p_point_index, pinned_point)) {
// Create new
PinnedPoint pp;
pp.point_index = p_point_index;
pp.spatial_attachment_path = p_spatial_attachment_path;
if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
pp.spatial_attachment = Object::cast_to<Node3D>(get_node(p_spatial_attachment_path));
pp.offset = (pp.spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, pp.point_index));
}
if (p_insert_at != -1) {
pinned_points.insert(p_insert_at, pp);
} else {
pinned_points.push_back(pp);
}
} else {
pinned_point->point_index = p_point_index;
pinned_point->spatial_attachment_path = p_spatial_attachment_path;
if (!p_spatial_attachment_path.is_empty() && has_node(p_spatial_attachment_path)) {
Node3D *attachment_node = Object::cast_to<Node3D>(get_node(p_spatial_attachment_path));
ERR_FAIL_NULL_MSG(attachment_node, "Attachment node path is invalid.");
pinned_point->spatial_attachment = attachment_node;
pinned_point->offset = (pinned_point->spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, pinned_point->point_index));
}
}
}
void SoftBody3D::_reset_points_offsets() {
if (!Engine::get_singleton()->is_editor_hint()) {
return;
}
const PinnedPoint *r = pinned_points.ptr();
PinnedPoint *w = pinned_points.ptrw();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (!r[i].spatial_attachment) {
if (!r[i].spatial_attachment_path.is_empty() && has_node(r[i].spatial_attachment_path)) {
w[i].spatial_attachment = Object::cast_to<Node3D>(get_node(r[i].spatial_attachment_path));
}
}
if (!r[i].spatial_attachment) {
continue;
}
w[i].offset = (r[i].spatial_attachment->get_global_transform().affine_inverse() * get_global_transform()).xform(PhysicsServer3D::get_singleton()->soft_body_get_point_global_position(physics_rid, r[i].point_index));
}
}
void SoftBody3D::_remove_pinned_point(int p_point_index) {
const int id(_has_pinned_point(p_point_index));
if (-1 != id) {
pinned_points.remove_at(id);
}
}
int SoftBody3D::_get_pinned_point(int p_point_index, SoftBody3D::PinnedPoint *&r_point) const {
const int id = _has_pinned_point(p_point_index);
if (-1 == id) {
r_point = nullptr;
return -1;
} else {
r_point = const_cast<SoftBody3D::PinnedPoint *>(&pinned_points.ptr()[id]);
return id;
}
}
int SoftBody3D::_has_pinned_point(int p_point_index) const {
const PinnedPoint *r = pinned_points.ptr();
for (int i = pinned_points.size() - 1; 0 <= i; --i) {
if (p_point_index == r[i].point_index) {
return i;
}
}
return -1;
}

View file

@ -0,0 +1,207 @@
/**************************************************************************/
/* soft_body_3d.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#pragma once
#include "scene/3d/mesh_instance_3d.h"
#include "servers/physics_server_3d.h"
class PhysicsBody3D;
class SoftBodyRenderingServerHandler : public PhysicsServer3DRenderingServerHandler {
friend class SoftBody3D;
RID mesh;
int surface = 0;
Vector<uint8_t> buffer;
uint32_t stride = 0;
uint32_t normal_stride = 0;
uint32_t offset_vertices = 0;
uint32_t offset_normal = 0;
uint8_t *write_buffer = nullptr;
private:
SoftBodyRenderingServerHandler();
bool is_ready(RID p_mesh_rid) const { return mesh.is_valid() && mesh == p_mesh_rid; }
void prepare(RID p_mesh_rid, int p_surface);
void clear();
void open();
void close();
void commit_changes();
public:
void set_vertex(int p_vertex_id, const Vector3 &p_vertex) override;
void set_normal(int p_vertex_id, const Vector3 &p_normal) override;
void set_aabb(const AABB &p_aabb) override;
};
class SoftBody3D : public MeshInstance3D {
GDCLASS(SoftBody3D, MeshInstance3D);
public:
enum DisableMode {
DISABLE_MODE_REMOVE,
DISABLE_MODE_KEEP_ACTIVE,
};
struct PinnedPoint {
int point_index = -1;
NodePath spatial_attachment_path;
Node3D *spatial_attachment = nullptr; // Cache
Vector3 offset;
PinnedPoint();
PinnedPoint(const PinnedPoint &obj_tocopy);
void operator=(const PinnedPoint &obj);
};
private:
SoftBodyRenderingServerHandler *rendering_server_handler = nullptr;
RID physics_rid;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
RID owned_mesh;
uint32_t collision_mask = 1;
uint32_t collision_layer = 1;
NodePath parent_collision_ignore;
Vector<PinnedPoint> pinned_points;
bool simulation_started = false;
bool pinned_points_cache_dirty = true;
Ref<ArrayMesh> debug_mesh_cache;
class MeshInstance3D *debug_mesh = nullptr;
bool capture_input_on_drag = false;
bool ray_pickable = true;
void _update_pickable();
void _update_physics_server();
void _draw_soft_mesh();
void _prepare_physics_server();
void _become_mesh_owner();
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
bool _set_property_pinned_points_indices(const Array &p_indices);
bool _set_property_pinned_points_attachment(int p_item, const String &p_what, const Variant &p_value);
bool _get_property_pinned_points(int p_item, const String &p_what, Variant &r_ret) const;
void _notification(int p_what);
static void _bind_methods();
#ifndef DISABLE_DEPRECATED
void _pin_point_bind_compat_94684(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath());
static void _bind_compatibility_methods();
#endif
PackedStringArray get_configuration_warnings() const override;
public:
RID get_physics_rid() const { return physics_rid; }
void set_collision_mask(uint32_t p_mask);
uint32_t get_collision_mask() const;
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
void set_collision_layer_value(int p_layer_number, bool p_value);
bool get_collision_layer_value(int p_layer_number) const;
void set_collision_mask_value(int p_layer_number, bool p_value);
bool get_collision_mask_value(int p_layer_number) const;
void set_disable_mode(DisableMode p_mode);
DisableMode get_disable_mode() const;
void set_parent_collision_ignore(const NodePath &p_parent_collision_ignore);
const NodePath &get_parent_collision_ignore() const;
void set_pinned_points_indices(Vector<PinnedPoint> p_pinned_points_indices);
Vector<PinnedPoint> get_pinned_points_indices();
void set_simulation_precision(int p_simulation_precision);
int get_simulation_precision();
void set_total_mass(real_t p_total_mass);
real_t get_total_mass();
void set_linear_stiffness(real_t p_linear_stiffness);
real_t get_linear_stiffness();
void set_pressure_coefficient(real_t p_pressure_coefficient);
real_t get_pressure_coefficient();
void set_damping_coefficient(real_t p_damping_coefficient);
real_t get_damping_coefficient();
void set_drag_coefficient(real_t p_drag_coefficient);
real_t get_drag_coefficient();
TypedArray<PhysicsBody3D> get_collision_exceptions();
void add_collision_exception_with(Node *p_node);
void remove_collision_exception_with(Node *p_node);
Vector3 get_point_transform(int p_point_index);
void pin_point_toggle(int p_point_index);
void pin_point(int p_point_index, bool pin, const NodePath &p_spatial_attachment_path = NodePath(), int p_insert_at = -1);
bool is_point_pinned(int p_point_index) const;
void _pin_point_deferred(int p_point_index, bool pin, const NodePath p_spatial_attachment_path);
void set_ray_pickable(bool p_ray_pickable);
bool is_ray_pickable() const;
SoftBody3D();
~SoftBody3D();
private:
void _make_cache_dirty();
void _update_cache_pin_points_datas();
void _pin_point_on_physics_server(int p_point_index, bool pin);
void _add_pinned_point(int p_point_index, const NodePath &p_spatial_attachment_path, int p_insert_at = -1);
void _reset_points_offsets();
void _remove_pinned_point(int p_point_index);
int _get_pinned_point(int p_point_index, PinnedPoint *&r_point) const;
int _has_pinned_point(int p_point_index) const;
};
VARIANT_ENUM_CAST(SoftBody3D::DisableMode);

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef SPRING_ARM_3D_H
#define SPRING_ARM_3D_H
#pragma once
#include "scene/3d/node_3d.h"
@ -67,5 +66,3 @@ public:
private:
void process_spring();
};
#endif // SPRING_ARM_3D_H

View file

@ -30,6 +30,7 @@
#include "static_body_3d.h"
#ifndef NAVIGATION_3D_DISABLED
#include "core/math/convex_hull.h"
#include "scene/resources/3d/box_shape_3d.h"
#include "scene/resources/3d/capsule_shape_3d.h"
@ -47,6 +48,7 @@
Callable StaticBody3D::_navmesh_source_geometry_parsing_callback;
RID StaticBody3D::_navmesh_source_geometry_parser;
#endif // NAVIGATION_3D_DISABLED
void StaticBody3D::set_physics_material_override(const Ref<PhysicsMaterial> &p_physics_material_override) {
if (physics_material_override.is_valid()) {
@ -95,6 +97,7 @@ void StaticBody3D::_reload_physics_characteristics() {
}
}
#ifndef NAVIGATION_3D_DISABLED
void StaticBody3D::navmesh_parse_init() {
ERR_FAIL_NULL(NavigationServer3D::get_singleton());
if (!_navmesh_source_geometry_parser.is_valid()) {
@ -226,6 +229,7 @@ void StaticBody3D::navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_na
}
}
}
#endif // NAVIGATION_3D_DISABLED
void StaticBody3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_constant_linear_velocity", "vel"), &StaticBody3D::set_constant_linear_velocity);

View file

@ -28,13 +28,14 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef STATIC_BODY_3D_H
#define STATIC_BODY_3D_H
#pragma once
#include "scene/3d/physics/physics_body_3d.h"
#ifndef NAVIGATION_3D_DISABLED
class NavigationMesh;
class NavigationMeshSourceGeometryData3D;
#endif // NAVIGATION_3D_DISABLED
class StaticBody3D : public PhysicsBody3D {
GDCLASS(StaticBody3D, PhysicsBody3D);
@ -63,12 +64,12 @@ public:
private:
void _reload_physics_characteristics();
#ifndef NAVIGATION_3D_DISABLED
static Callable _navmesh_source_geometry_parsing_callback;
static RID _navmesh_source_geometry_parser;
public:
static void navmesh_parse_init();
static void navmesh_parse_source_geometry(const Ref<NavigationMesh> &p_navigation_mesh, Ref<NavigationMeshSourceGeometryData3D> p_source_geometry_data, Node *p_node);
#endif // NAVIGATION_3D_DISABLED
};
#endif // STATIC_BODY_3D_H

View file

@ -852,18 +852,26 @@ void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
for (int i = 0; i < wheels.size(); i++) {
VehicleWheel3D &wheel = *wheels[i];
Vector3 relpos = wheel.m_raycastInfo.m_hardPointWS - p_state->get_transform().origin;
Vector3 vel = p_state->get_linear_velocity() + (p_state->get_angular_velocity()).cross(relpos); // * mPos);
Vector3 vel = p_state->get_linear_velocity() + (p_state->get_angular_velocity()).cross(relpos);
if (wheel.m_raycastInfo.m_isInContact) {
const Transform3D &chassisWorldTransform = p_state->get_transform();
// Get forward vector.
Vector3 fwd(
chassisWorldTransform.basis[0][Vector3::AXIS_Z],
chassisWorldTransform.basis[1][Vector3::AXIS_Z],
chassisWorldTransform.basis[2][Vector3::AXIS_Z]);
// Apply steering rotation to forward vector for steerable wheels.
if (wheel.steers) {
Basis steering_mat(Vector3(0, 1, 0), wheel.m_steering);
fwd = steering_mat.xform(fwd);
}
real_t proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS);
fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj;
fwd.normalize();
real_t proj2 = fwd.dot(vel);
@ -871,7 +879,7 @@ void VehicleBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
}
wheel.m_rotation += wheel.m_deltaRotation;
wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math_TAU;
wheel.m_rpm = ((wheel.m_deltaRotation / step) * 60) / Math::TAU;
wheel.m_deltaRotation *= real_t(0.99); //damping of rotation when not in contact
}

View file

@ -28,8 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
#ifndef VEHICLE_BODY_3D_H
#define VEHICLE_BODY_3D_H
#pragma once
#include "scene/3d/physics/physics_body_3d.h"
#include "scene/3d/physics/rigid_body_3d.h"
@ -214,5 +213,3 @@ public:
VehicleBody3D();
};
#endif // VEHICLE_BODY_3D_H