jolt_soft_body_3d.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716
  1. /**************************************************************************/
  2. /* jolt_soft_body_3d.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "jolt_soft_body_3d.h"
  31. #include "../jolt_project_settings.h"
  32. #include "../misc/jolt_type_conversions.h"
  33. #include "../spaces/jolt_broad_phase_layer.h"
  34. #include "../spaces/jolt_space_3d.h"
  35. #include "jolt_area_3d.h"
  36. #include "jolt_body_3d.h"
  37. #include "jolt_group_filter.h"
  38. #include "servers/rendering/rendering_server.h"
  39. #include "Jolt/Physics/SoftBody/SoftBodyMotionProperties.h"
  40. namespace {
  41. template <typename TJoltVertex>
  42. void pin_vertices(const JoltSoftBody3D &p_body, const HashSet<int> &p_pinned_vertices, const LocalVector<int> &p_mesh_to_physics, JPH::Array<TJoltVertex> &r_physics_vertices) {
  43. const int mesh_vertex_count = p_mesh_to_physics.size();
  44. const int physics_vertex_count = (int)r_physics_vertices.size();
  45. for (int mesh_index : p_pinned_vertices) {
  46. ERR_CONTINUE_MSG(mesh_index < 0 || mesh_index >= mesh_vertex_count, vformat("Index %d of pinned vertex in soft body '%s' is out of bounds. There are only %d vertices in the current mesh.", mesh_index, p_body.to_string(), mesh_vertex_count));
  47. const int physics_index = p_mesh_to_physics[mesh_index];
  48. ERR_CONTINUE_MSG(physics_index < 0 || physics_index >= physics_vertex_count, vformat("Index %d of pinned vertex in soft body '%s' is out of bounds. There are only %d vertices in the current mesh. This should not happen. Please report this.", physics_index, p_body.to_string(), physics_vertex_count));
  49. r_physics_vertices[physics_index].mInvMass = 0.0f;
  50. }
  51. }
  52. } // namespace
  53. JPH::BroadPhaseLayer JoltSoftBody3D::_get_broad_phase_layer() const {
  54. return JoltBroadPhaseLayer::BODY_DYNAMIC;
  55. }
  56. JPH::ObjectLayer JoltSoftBody3D::_get_object_layer() const {
  57. ERR_FAIL_NULL_V(space, 0);
  58. return space->map_to_object_layer(_get_broad_phase_layer(), collision_layer, collision_mask);
  59. }
  60. void JoltSoftBody3D::_space_changing() {
  61. JoltObject3D::_space_changing();
  62. if (in_space()) {
  63. jolt_settings = new JPH::SoftBodyCreationSettings(jolt_body->GetSoftBodyCreationSettings());
  64. jolt_settings->mSettings = nullptr;
  65. jolt_settings->mVertexRadius = JoltProjectSettings::soft_body_point_radius;
  66. }
  67. }
  68. void JoltSoftBody3D::_space_changed() {
  69. JoltObject3D::_space_changed();
  70. _update_mass();
  71. _update_pressure();
  72. _update_damping();
  73. _update_simulation_precision();
  74. _update_group_filter();
  75. }
  76. void JoltSoftBody3D::_add_to_space() {
  77. if (unlikely(space == nullptr || !mesh.is_valid())) {
  78. return;
  79. }
  80. JPH::SoftBodySharedSettings *shared_settings = _create_shared_settings();
  81. ERR_FAIL_NULL(shared_settings);
  82. JPH::CollisionGroup::GroupID group_id = 0;
  83. JPH::CollisionGroup::SubGroupID sub_group_id = 0;
  84. JoltGroupFilter::encode_object(this, group_id, sub_group_id);
  85. jolt_settings->mSettings = shared_settings;
  86. jolt_settings->mUserData = reinterpret_cast<JPH::uint64>(this);
  87. jolt_settings->mObjectLayer = _get_object_layer();
  88. jolt_settings->mCollisionGroup = JPH::CollisionGroup(nullptr, group_id, sub_group_id);
  89. jolt_settings->mMaxLinearVelocity = JoltProjectSettings::max_linear_velocity;
  90. JPH::Body *new_jolt_body = space->add_object(*this, *jolt_settings);
  91. if (new_jolt_body == nullptr) {
  92. return;
  93. }
  94. jolt_body = new_jolt_body;
  95. delete jolt_settings;
  96. jolt_settings = nullptr;
  97. }
  98. JPH::SoftBodySharedSettings *JoltSoftBody3D::_create_shared_settings() {
  99. RenderingServer *rendering = RenderingServer::get_singleton();
  100. // TODO: calling RenderingServer::mesh_surface_get_arrays() from the physics thread
  101. // is not safe and can deadlock when physics/3d/run_on_separate_thread is enabled.
  102. // This method blocks on the main thread to return data, but the main thread may be
  103. // blocked waiting on us in PhysicsServer3D::sync().
  104. const Array mesh_data = rendering->mesh_surface_get_arrays(mesh, 0);
  105. ERR_FAIL_COND_V(mesh_data.is_empty(), nullptr);
  106. const PackedInt32Array mesh_indices = mesh_data[RenderingServer::ARRAY_INDEX];
  107. ERR_FAIL_COND_V(mesh_indices.is_empty(), nullptr);
  108. const PackedVector3Array mesh_vertices = mesh_data[RenderingServer::ARRAY_VERTEX];
  109. ERR_FAIL_COND_V(mesh_vertices.is_empty(), nullptr);
  110. JPH::SoftBodySharedSettings *settings = new JPH::SoftBodySharedSettings();
  111. JPH::Array<JPH::SoftBodySharedSettings::Vertex> &physics_vertices = settings->mVertices;
  112. JPH::Array<JPH::SoftBodySharedSettings::Face> &physics_faces = settings->mFaces;
  113. HashMap<Vector3, int> vertex_to_physics;
  114. const int mesh_vertex_count = mesh_vertices.size();
  115. const int mesh_index_count = mesh_indices.size();
  116. mesh_to_physics.resize(mesh_vertex_count);
  117. for (int &index : mesh_to_physics) {
  118. index = -1;
  119. }
  120. physics_vertices.reserve(mesh_vertex_count);
  121. vertex_to_physics.reserve(mesh_vertex_count);
  122. int physics_index_count = 0;
  123. const JPH::RVec3 body_position = jolt_settings->mPosition;
  124. for (int i = 0; i < mesh_index_count; i += 3) {
  125. int physics_face[3];
  126. for (int j = 0; j < 3; ++j) {
  127. const int mesh_index = mesh_indices[i + j];
  128. const Vector3 vertex = mesh_vertices[mesh_index];
  129. HashMap<Vector3, int>::Iterator iter_physics_index = vertex_to_physics.find(vertex);
  130. if (iter_physics_index == vertex_to_physics.end()) {
  131. physics_vertices.emplace_back(JPH::Float3((float)(vertex.x - body_position.GetX()), (float)(vertex.y - body_position.GetY()), (float)(vertex.z - body_position.GetZ())), JPH::Float3(0.0f, 0.0f, 0.0f), 1.0f);
  132. iter_physics_index = vertex_to_physics.insert(vertex, physics_index_count++);
  133. }
  134. physics_face[j] = iter_physics_index->value;
  135. mesh_to_physics[mesh_index] = iter_physics_index->value;
  136. }
  137. if (physics_face[0] == physics_face[1] || physics_face[0] == physics_face[2] || physics_face[1] == physics_face[2]) {
  138. continue; // We skip degenerate faces, since they're problematic, and Jolt will assert about it anyway.
  139. }
  140. // Jolt uses a different winding order, so we swap the indices to account for that.
  141. physics_faces.emplace_back((JPH::uint32)physics_face[2], (JPH::uint32)physics_face[1], (JPH::uint32)physics_face[0]);
  142. }
  143. // Pin whatever pinned vertices we have currently. This is used during the `Optimize` call below to order the
  144. // constraints. Note that it's fine if the pinned vertices change later, but that will reduce the effectiveness
  145. // of the constraints a bit.
  146. pin_vertices(*this, pinned_vertices, mesh_to_physics, physics_vertices);
  147. // Since Godot's stiffness is input as a coefficient between 0 and 1, and Jolt uses actual stiffness for its
  148. // edge constraints, we crudely map one to the other with an arbitrary constant.
  149. const float stiffness = MAX(Math::pow(stiffness_coefficient, 3.0f) * 100000.0f, 0.000001f);
  150. const float inverse_stiffness = 1.0f / stiffness;
  151. JPH::SoftBodySharedSettings::VertexAttributes vertex_attrib;
  152. vertex_attrib.mCompliance = vertex_attrib.mShearCompliance = inverse_stiffness;
  153. settings->CreateConstraints(&vertex_attrib, 1, JPH::SoftBodySharedSettings::EBendType::None);
  154. float multiplier = 1.0f - shrinking_factor;
  155. for (JPH::SoftBodySharedSettings::Edge &e : settings->mEdgeConstraints) {
  156. e.mRestLength *= multiplier;
  157. }
  158. settings->Optimize();
  159. return settings;
  160. }
  161. void JoltSoftBody3D::_update_mass() {
  162. if (!in_space()) {
  163. return;
  164. }
  165. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  166. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  167. const float inverse_vertex_mass = mass == 0.0f ? 1.0f : (float)physics_vertices.size() / mass;
  168. for (JPH::SoftBodyVertex &vertex : physics_vertices) {
  169. vertex.mInvMass = inverse_vertex_mass;
  170. }
  171. pin_vertices(*this, pinned_vertices, mesh_to_physics, physics_vertices);
  172. }
  173. void JoltSoftBody3D::_update_pressure() {
  174. if (!in_space()) {
  175. jolt_settings->mPressure = pressure;
  176. return;
  177. }
  178. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  179. motion_properties.SetPressure(pressure);
  180. }
  181. void JoltSoftBody3D::_update_damping() {
  182. if (!in_space()) {
  183. jolt_settings->mLinearDamping = linear_damping;
  184. return;
  185. }
  186. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  187. motion_properties.SetLinearDamping(linear_damping);
  188. }
  189. void JoltSoftBody3D::_update_simulation_precision() {
  190. if (!in_space()) {
  191. jolt_settings->mNumIterations = (JPH::uint32)simulation_precision;
  192. return;
  193. }
  194. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  195. motion_properties.SetNumIterations((JPH::uint32)simulation_precision);
  196. }
  197. void JoltSoftBody3D::_update_group_filter() {
  198. JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;
  199. if (!in_space()) {
  200. jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);
  201. } else {
  202. jolt_body->GetCollisionGroup().SetGroupFilter(group_filter);
  203. }
  204. }
  205. void JoltSoftBody3D::_try_rebuild() {
  206. if (space != nullptr) {
  207. _reset_space();
  208. }
  209. }
  210. void JoltSoftBody3D::_mesh_changed() {
  211. _try_rebuild();
  212. }
  213. void JoltSoftBody3D::_simulation_precision_changed() {
  214. wake_up();
  215. }
  216. void JoltSoftBody3D::_mass_changed() {
  217. wake_up();
  218. }
  219. void JoltSoftBody3D::_pressure_changed() {
  220. _update_pressure();
  221. wake_up();
  222. }
  223. void JoltSoftBody3D::_damping_changed() {
  224. _update_damping();
  225. wake_up();
  226. }
  227. void JoltSoftBody3D::_pins_changed() {
  228. _update_mass();
  229. wake_up();
  230. }
  231. void JoltSoftBody3D::_vertices_changed() {
  232. wake_up();
  233. }
  234. void JoltSoftBody3D::_exceptions_changed() {
  235. _update_group_filter();
  236. }
  237. void JoltSoftBody3D::_motion_changed() {
  238. wake_up();
  239. }
  240. JoltSoftBody3D::JoltSoftBody3D() :
  241. JoltObject3D(OBJECT_TYPE_SOFT_BODY) {
  242. jolt_settings->mRestitution = 0.0f;
  243. jolt_settings->mFriction = 1.0f;
  244. jolt_settings->mUpdatePosition = true;
  245. jolt_settings->mMakeRotationIdentity = false;
  246. }
  247. JoltSoftBody3D::~JoltSoftBody3D() {
  248. if (jolt_settings != nullptr) {
  249. delete jolt_settings;
  250. jolt_settings = nullptr;
  251. }
  252. }
  253. void JoltSoftBody3D::add_collision_exception(const RID &p_excepted_body) {
  254. exceptions.push_back(p_excepted_body);
  255. _exceptions_changed();
  256. }
  257. void JoltSoftBody3D::remove_collision_exception(const RID &p_excepted_body) {
  258. exceptions.erase(p_excepted_body);
  259. _exceptions_changed();
  260. }
  261. bool JoltSoftBody3D::has_collision_exception(const RID &p_excepted_body) const {
  262. return exceptions.find(p_excepted_body) >= 0;
  263. }
  264. bool JoltSoftBody3D::can_interact_with(const JoltBody3D &p_other) const {
  265. return (can_collide_with(p_other) || p_other.can_collide_with(*this)) && !has_collision_exception(p_other.get_rid()) && !p_other.has_collision_exception(rid);
  266. }
  267. bool JoltSoftBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {
  268. return (can_collide_with(p_other) || p_other.can_collide_with(*this)) && !has_collision_exception(p_other.get_rid()) && !p_other.has_collision_exception(rid);
  269. }
  270. bool JoltSoftBody3D::can_interact_with(const JoltArea3D &p_other) const {
  271. return p_other.can_interact_with(*this);
  272. }
  273. Vector3 JoltSoftBody3D::get_velocity_at_position(const Vector3 &p_position) const {
  274. return Vector3();
  275. }
  276. void JoltSoftBody3D::set_mesh(const RID &p_mesh) {
  277. if (unlikely(mesh == p_mesh)) {
  278. return;
  279. }
  280. mesh = p_mesh;
  281. _mesh_changed();
  282. }
  283. bool JoltSoftBody3D::is_sleeping() const {
  284. if (!in_space()) {
  285. return false;
  286. } else {
  287. return !jolt_body->IsActive();
  288. }
  289. }
  290. void JoltSoftBody3D::apply_vertex_impulse(int p_index, const Vector3 &p_impulse) {
  291. ERR_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()));
  292. ERR_FAIL_INDEX(p_index, (int)mesh_to_physics.size());
  293. const int physics_index = mesh_to_physics[p_index];
  294. ERR_FAIL_COND_MSG(physics_index < 0, vformat("Soft body vertex %d was not used by a face and has been omitted for '%s'. No impulse can be applied.", p_index, to_string()));
  295. ERR_FAIL_COND_MSG(pinned_vertices.has(physics_index), vformat("Failed to apply impulse to point at index %d for '%s'. Point was found to be pinned.", static_cast<int>(physics_index), to_string()));
  296. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  297. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  298. JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
  299. physics_vertex.mVelocity += to_jolt(p_impulse) * physics_vertex.mInvMass;
  300. _motion_changed();
  301. }
  302. void JoltSoftBody3D::apply_vertex_force(int p_index, const Vector3 &p_force) {
  303. ERR_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()));
  304. apply_vertex_impulse(p_index, p_force * space->get_last_step());
  305. }
  306. void JoltSoftBody3D::apply_central_impulse(const Vector3 &p_impulse) {
  307. ERR_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()));
  308. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  309. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  310. const JPH::Vec3 impulse = to_jolt(p_impulse) / physics_vertices.size();
  311. for (JPH::SoftBodyVertex &physics_vertex : physics_vertices) {
  312. if (physics_vertex.mInvMass > 0.0f) {
  313. physics_vertex.mVelocity += impulse * physics_vertex.mInvMass;
  314. }
  315. }
  316. _motion_changed();
  317. }
  318. void JoltSoftBody3D::apply_central_force(const Vector3 &p_force) {
  319. ERR_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()));
  320. jolt_body->AddForce(to_jolt(p_force));
  321. _motion_changed();
  322. }
  323. void JoltSoftBody3D::set_is_sleeping(bool p_enabled) {
  324. if (!in_space()) {
  325. return;
  326. }
  327. space->set_is_object_sleeping(jolt_body->GetID(), p_enabled);
  328. }
  329. bool JoltSoftBody3D::is_sleep_allowed() const {
  330. if (!in_space()) {
  331. return jolt_settings->mAllowSleeping;
  332. } else {
  333. return jolt_body->GetAllowSleeping();
  334. }
  335. }
  336. void JoltSoftBody3D::set_is_sleep_allowed(bool p_enabled) {
  337. if (!in_space()) {
  338. jolt_settings->mAllowSleeping = p_enabled;
  339. } else {
  340. jolt_body->SetAllowSleeping(p_enabled);
  341. }
  342. }
  343. void JoltSoftBody3D::set_simulation_precision(int p_precision) {
  344. if (unlikely(simulation_precision == p_precision)) {
  345. return;
  346. }
  347. simulation_precision = MAX(p_precision, 0);
  348. _simulation_precision_changed();
  349. }
  350. void JoltSoftBody3D::set_mass(float p_mass) {
  351. if (unlikely(mass == p_mass)) {
  352. return;
  353. }
  354. mass = MAX(p_mass, 0.0f);
  355. _mass_changed();
  356. }
  357. float JoltSoftBody3D::get_stiffness_coefficient() const {
  358. return stiffness_coefficient;
  359. }
  360. void JoltSoftBody3D::set_stiffness_coefficient(float p_coefficient) {
  361. stiffness_coefficient = CLAMP(p_coefficient, 0.0f, 1.0f);
  362. }
  363. float JoltSoftBody3D::get_shrinking_factor() const {
  364. return shrinking_factor;
  365. }
  366. void JoltSoftBody3D::set_shrinking_factor(float p_shrinking_factor) {
  367. shrinking_factor = p_shrinking_factor;
  368. }
  369. void JoltSoftBody3D::set_pressure(float p_pressure) {
  370. if (unlikely(pressure == p_pressure)) {
  371. return;
  372. }
  373. pressure = MAX(p_pressure, 0.0f);
  374. _pressure_changed();
  375. }
  376. void JoltSoftBody3D::set_linear_damping(float p_damping) {
  377. if (unlikely(linear_damping == p_damping)) {
  378. return;
  379. }
  380. linear_damping = MAX(p_damping, 0.0f);
  381. _damping_changed();
  382. }
  383. float JoltSoftBody3D::get_drag() const {
  384. // Drag is not a thing in Jolt, and not supported by Godot Physics either.
  385. return 0.0f;
  386. }
  387. void JoltSoftBody3D::set_drag(float p_drag) {
  388. // Drag is not a thing in Jolt, and not supported by Godot Physics either.
  389. }
  390. Variant JoltSoftBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
  391. switch (p_state) {
  392. case PhysicsServer3D::BODY_STATE_TRANSFORM: {
  393. return get_transform();
  394. }
  395. case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
  396. ERR_FAIL_V_MSG(Variant(), "Linear velocity is not supported for soft bodies.");
  397. }
  398. case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
  399. ERR_FAIL_V_MSG(Variant(), "Angular velocity is not supported for soft bodies.");
  400. }
  401. case PhysicsServer3D::BODY_STATE_SLEEPING: {
  402. return is_sleeping();
  403. }
  404. case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
  405. return is_sleep_allowed();
  406. }
  407. default: {
  408. ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
  409. }
  410. }
  411. }
  412. void JoltSoftBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {
  413. switch (p_state) {
  414. case PhysicsServer3D::BODY_STATE_TRANSFORM: {
  415. set_transform(p_value);
  416. } break;
  417. case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
  418. ERR_FAIL_MSG("Linear velocity is not supported for soft bodies.");
  419. } break;
  420. case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
  421. ERR_FAIL_MSG("Angular velocity is not supported for soft bodies.");
  422. } break;
  423. case PhysicsServer3D::BODY_STATE_SLEEPING: {
  424. set_is_sleeping(p_value);
  425. } break;
  426. case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
  427. set_is_sleep_allowed(p_value);
  428. } break;
  429. default: {
  430. ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
  431. } break;
  432. }
  433. }
  434. Transform3D JoltSoftBody3D::get_transform() const {
  435. // Since any transform gets baked into the vertices anyway we can just return identity here.
  436. return Transform3D();
  437. }
  438. void JoltSoftBody3D::set_transform(const Transform3D &p_transform) {
  439. ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to set transform for '%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()));
  440. // For whatever reason this has to be interpreted as a relative global-space transform rather than an absolute one,
  441. // because `SoftBody3D` will immediately upon entering the scene tree set itself to be top-level and also set its
  442. // transform to be identity, while still expecting to stay in its original position.
  443. //
  444. // We also discard any scaling, since we have no way of scaling the actual edge lengths.
  445. const JPH::Mat44 relative_transform = to_jolt(p_transform.orthonormalized());
  446. // The translation delta goes to the body's position to avoid vertices getting too far away from it.
  447. JPH::BodyInterface &body_iface = space->get_body_iface();
  448. body_iface.SetPosition(jolt_body->GetID(), jolt_body->GetPosition() + relative_transform.GetTranslation(), JPH::EActivation::DontActivate);
  449. // The rotation difference goes to the vertices. We also reset the velocity of these vertices.
  450. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  451. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  452. for (JPH::SoftBodyVertex &vertex : physics_vertices) {
  453. vertex.mPosition = vertex.mPreviousPosition = relative_transform.Multiply3x3(vertex.mPosition);
  454. vertex.mVelocity = JPH::Vec3::sZero();
  455. }
  456. wake_up();
  457. }
  458. AABB JoltSoftBody3D::get_bounds() const {
  459. ERR_FAIL_COND_V_MSG(!in_space(), AABB(), vformat("Failed to retrieve world bounds 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()));
  460. return to_godot(jolt_body->GetWorldSpaceBounds());
  461. }
  462. void JoltSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandler *p_rendering_server_handler) {
  463. // Ideally we would emit an actual error here, but that would spam the logs to the point where the actual cause will be drowned out.
  464. if (unlikely(!in_space())) {
  465. return;
  466. }
  467. const JPH::SoftBodyMotionProperties &motion_properties = static_cast<const JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  468. typedef JPH::SoftBodyMotionProperties::Vertex SoftBodyVertex;
  469. typedef JPH::SoftBodyMotionProperties::Face SoftBodyFace;
  470. const JPH::Array<SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  471. const JPH::Array<SoftBodyFace> &physics_faces = motion_properties.GetFaces();
  472. const int physics_vertex_count = (int)physics_vertices.size();
  473. normals.clear();
  474. normals.resize(physics_vertex_count);
  475. // Compute vertex normals using smooth-shading:
  476. // Each vertex should use the average normal of all faces it is a part of.
  477. // Iterate over each face, and add the face normal to each of the face vertices.
  478. // By the end of the loop, each vertex normal will be the sum of all face normals it belongs to.
  479. for (const SoftBodyFace &physics_face : physics_faces) {
  480. // Jolt uses a different winding order, so we swap the indices to account for that.
  481. const uint32_t i0 = physics_face.mVertex[2];
  482. const uint32_t i1 = physics_face.mVertex[1];
  483. const uint32_t i2 = physics_face.mVertex[0];
  484. const Vector3 v0 = to_godot(physics_vertices[i0].mPosition);
  485. const Vector3 v1 = to_godot(physics_vertices[i1].mPosition);
  486. const Vector3 v2 = to_godot(physics_vertices[i2].mPosition);
  487. const Vector3 normal = (v2 - v0).cross(v1 - v0).normalized();
  488. normals[i0] += normal;
  489. normals[i1] += normal;
  490. normals[i2] += normal;
  491. }
  492. // Normalize the vertex normals to have length 1.0
  493. for (Vector3 &n : normals) {
  494. real_t len = n.length();
  495. // Some normals may have length 0 if the face was degenerate,
  496. // so don't divide by zero.
  497. if (len > CMP_EPSILON) {
  498. n /= len;
  499. }
  500. }
  501. const int mesh_vertex_count = mesh_to_physics.size();
  502. const JPH::RVec3 body_position = jolt_body->GetCenterOfMassPosition();
  503. for (int i = 0; i < mesh_vertex_count; ++i) {
  504. const int physics_index = mesh_to_physics[i];
  505. if (physics_index >= 0) {
  506. const Vector3 vertex = to_godot(body_position + physics_vertices[(size_t)physics_index].mPosition);
  507. const Vector3 normal = normals[(uint32_t)physics_index];
  508. p_rendering_server_handler->set_vertex(i, vertex);
  509. p_rendering_server_handler->set_normal(i, normal);
  510. }
  511. }
  512. p_rendering_server_handler->set_aabb(get_bounds());
  513. }
  514. Vector3 JoltSoftBody3D::get_vertex_position(int p_index) {
  515. ERR_FAIL_COND_V_MSG(!in_space(), Vector3(), vformat("Failed to retrieve point position for '%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()));
  516. ERR_FAIL_INDEX_V(p_index, (int)mesh_to_physics.size(), Vector3());
  517. const int physics_index = mesh_to_physics[p_index];
  518. ERR_FAIL_COND_V_MSG(physics_index < 0, Vector3(), vformat("Soft body vertex %d was not used by a face and has been omitted for '%s'. Position cannot be returned.", p_index, to_string()));
  519. const JPH::SoftBodyMotionProperties &motion_properties = static_cast<const JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  520. const JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  521. const JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
  522. return to_godot(jolt_body->GetCenterOfMassPosition() + physics_vertex.mPosition);
  523. }
  524. void JoltSoftBody3D::set_vertex_position(int p_index, const Vector3 &p_position) {
  525. ERR_FAIL_COND_MSG(!in_space(), vformat("Failed to set point position for '%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()));
  526. ERR_FAIL_INDEX(p_index, (int)mesh_to_physics.size());
  527. const int physics_index = mesh_to_physics[p_index];
  528. ERR_FAIL_COND_MSG(physics_index < 0, vformat("Soft body vertex %d was not used by a face and has been omitted for '%s'. Position cannot be set.", p_index, to_string()));
  529. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*jolt_body->GetMotionPropertiesUnchecked());
  530. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  531. JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
  532. const JPH::RVec3 center_of_mass = jolt_body->GetCenterOfMassPosition();
  533. physics_vertex.mPosition = JPH::Vec3(to_jolt_r(p_position) - center_of_mass);
  534. _vertices_changed();
  535. }
  536. void JoltSoftBody3D::pin_vertex(int p_index) {
  537. pinned_vertices.insert(p_index);
  538. _pins_changed();
  539. }
  540. void JoltSoftBody3D::unpin_vertex(int p_index) {
  541. pinned_vertices.erase(p_index);
  542. _pins_changed();
  543. }
  544. void JoltSoftBody3D::unpin_all_vertices() {
  545. pinned_vertices.clear();
  546. _pins_changed();
  547. }
  548. bool JoltSoftBody3D::is_vertex_pinned(int p_index) const {
  549. ERR_FAIL_COND_V_MSG(!in_space(), false, vformat("Failed retrieve pin status of point for '%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()));
  550. ERR_FAIL_INDEX_V(p_index, (int)mesh_to_physics.size(), false);
  551. const int physics_index = mesh_to_physics[p_index];
  552. return pinned_vertices.has(physics_index);
  553. }