jolt_soft_body_3d.cpp 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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_server.h"
  39. #include "Jolt/Physics/SoftBody/SoftBodyMotionProperties.h"
  40. namespace {
  41. bool is_face_degenerate(const int p_face[3]) {
  42. return p_face[0] == p_face[1] || p_face[0] == p_face[2] || p_face[1] == p_face[2];
  43. }
  44. template <typename TJoltVertex>
  45. 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) {
  46. const int mesh_vertex_count = p_mesh_to_physics.size();
  47. const int physics_vertex_count = (int)r_physics_vertices.size();
  48. for (int mesh_index : p_pinned_vertices) {
  49. 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));
  50. const int physics_index = p_mesh_to_physics[mesh_index];
  51. 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));
  52. r_physics_vertices[physics_index].mInvMass = 0.0f;
  53. }
  54. }
  55. } // namespace
  56. JPH::BroadPhaseLayer JoltSoftBody3D::_get_broad_phase_layer() const {
  57. return JoltBroadPhaseLayer::BODY_DYNAMIC;
  58. }
  59. JPH::ObjectLayer JoltSoftBody3D::_get_object_layer() const {
  60. ERR_FAIL_NULL_V(space, 0);
  61. return space->map_to_object_layer(_get_broad_phase_layer(), collision_layer, collision_mask);
  62. }
  63. void JoltSoftBody3D::_space_changing() {
  64. JoltObject3D::_space_changing();
  65. _deref_shared_data();
  66. if (space != nullptr && !jolt_id.IsInvalid()) {
  67. const JoltReadableBody3D body = space->read_body(jolt_id);
  68. ERR_FAIL_COND(body.is_invalid());
  69. jolt_settings = new JPH::SoftBodyCreationSettings(body->GetSoftBodyCreationSettings());
  70. jolt_settings->mSettings = nullptr;
  71. }
  72. }
  73. void JoltSoftBody3D::_space_changed() {
  74. JoltObject3D::_space_changed();
  75. _update_mass();
  76. _update_pressure();
  77. _update_damping();
  78. _update_simulation_precision();
  79. _update_group_filter();
  80. }
  81. void JoltSoftBody3D::_add_to_space() {
  82. if (unlikely(space == nullptr || !mesh.is_valid())) {
  83. return;
  84. }
  85. const bool has_valid_shared = _ref_shared_data();
  86. ERR_FAIL_COND(!has_valid_shared);
  87. JPH::CollisionGroup::GroupID group_id = 0;
  88. JPH::CollisionGroup::SubGroupID sub_group_id = 0;
  89. JoltGroupFilter::encode_object(this, group_id, sub_group_id);
  90. jolt_settings->mSettings = shared->settings;
  91. jolt_settings->mUserData = reinterpret_cast<JPH::uint64>(this);
  92. jolt_settings->mObjectLayer = _get_object_layer();
  93. jolt_settings->mCollisionGroup = JPH::CollisionGroup(nullptr, group_id, sub_group_id);
  94. jolt_settings->mMaxLinearVelocity = JoltProjectSettings::get_max_linear_velocity();
  95. const JPH::BodyID new_jolt_id = space->add_soft_body(*this, *jolt_settings);
  96. if (new_jolt_id.IsInvalid()) {
  97. return;
  98. }
  99. jolt_id = new_jolt_id;
  100. delete jolt_settings;
  101. jolt_settings = nullptr;
  102. }
  103. bool JoltSoftBody3D::_ref_shared_data() {
  104. HashMap<RID, Shared>::Iterator iter_shared_data = mesh_to_shared.find(mesh);
  105. if (iter_shared_data == mesh_to_shared.end()) {
  106. RenderingServer *rendering = RenderingServer::get_singleton();
  107. const Array mesh_data = rendering->mesh_surface_get_arrays(mesh, 0);
  108. ERR_FAIL_COND_V(mesh_data.is_empty(), false);
  109. const PackedInt32Array mesh_indices = mesh_data[RenderingServer::ARRAY_INDEX];
  110. ERR_FAIL_COND_V(mesh_indices.is_empty(), false);
  111. const PackedVector3Array mesh_vertices = mesh_data[RenderingServer::ARRAY_VERTEX];
  112. ERR_FAIL_COND_V(mesh_vertices.is_empty(), false);
  113. iter_shared_data = mesh_to_shared.insert(mesh, Shared());
  114. LocalVector<int> &mesh_to_physics = iter_shared_data->value.mesh_to_physics;
  115. JPH::SoftBodySharedSettings &settings = *iter_shared_data->value.settings;
  116. settings.mVertexRadius = JoltProjectSettings::get_soft_body_point_radius();
  117. JPH::Array<JPH::SoftBodySharedSettings::Vertex> &physics_vertices = settings.mVertices;
  118. JPH::Array<JPH::SoftBodySharedSettings::Face> &physics_faces = settings.mFaces;
  119. HashMap<Vector3, int> vertex_to_physics;
  120. const int mesh_vertex_count = mesh_vertices.size();
  121. const int mesh_index_count = mesh_indices.size();
  122. mesh_to_physics.resize(mesh_vertex_count);
  123. physics_vertices.reserve(mesh_vertex_count);
  124. vertex_to_physics.reserve(mesh_vertex_count);
  125. int physics_index_count = 0;
  126. for (int i = 0; i < mesh_index_count; i += 3) {
  127. int physics_face[3];
  128. int mesh_face[3];
  129. for (int j = 0; j < 3; ++j) {
  130. const int mesh_index = mesh_indices[i + j];
  131. const Vector3 vertex = mesh_vertices[mesh_index];
  132. HashMap<Vector3, int>::Iterator iter_physics_index = vertex_to_physics.find(vertex);
  133. if (iter_physics_index == vertex_to_physics.end()) {
  134. physics_vertices.emplace_back(JPH::Float3((float)vertex.x, (float)vertex.y, (float)vertex.z), JPH::Float3(0.0f, 0.0f, 0.0f), 1.0f);
  135. iter_physics_index = vertex_to_physics.insert(vertex, physics_index_count++);
  136. }
  137. mesh_face[j] = mesh_index;
  138. physics_face[j] = iter_physics_index->value;
  139. mesh_to_physics[mesh_index] = iter_physics_index->value;
  140. }
  141. ERR_CONTINUE_MSG(is_face_degenerate(physics_face), vformat("Failed to append face to soft body '%s'. Face was found to be degenerate. Face consist of indices %d, %d and %d.", to_string(), mesh_face[0], mesh_face[1], mesh_face[2]));
  142. // Jolt uses a different winding order, so we swap the indices to account for that.
  143. physics_faces.emplace_back((JPH::uint32)physics_face[2], (JPH::uint32)physics_face[1], (JPH::uint32)physics_face[0]);
  144. }
  145. // Pin whatever pinned vertices we have currently. This is used during the `Optimize` call below to order the
  146. // constraints. Note that it's fine if the pinned vertices change later, but that will reduce the effectiveness
  147. // of the constraints a bit.
  148. pin_vertices(*this, pinned_vertices, mesh_to_physics, physics_vertices);
  149. // Since Godot's stiffness is input as a coefficient between 0 and 1, and Jolt uses actual stiffness for its
  150. // edge constraints, we crudely map one to the other with an arbitrary constant.
  151. const float stiffness = MAX(Math::pow(stiffness_coefficient, 3.0f) * 100000.0f, 0.000001f);
  152. const float inverse_stiffness = 1.0f / stiffness;
  153. JPH::SoftBodySharedSettings::VertexAttributes vertex_attrib;
  154. vertex_attrib.mCompliance = vertex_attrib.mShearCompliance = inverse_stiffness;
  155. settings.CreateConstraints(&vertex_attrib, 1, JPH::SoftBodySharedSettings::EBendType::None);
  156. settings.Optimize();
  157. } else {
  158. iter_shared_data->value.ref_count++;
  159. }
  160. shared = &iter_shared_data->value;
  161. return true;
  162. }
  163. void JoltSoftBody3D::_deref_shared_data() {
  164. if (unlikely(shared == nullptr)) {
  165. return;
  166. }
  167. HashMap<RID, Shared>::Iterator iter = mesh_to_shared.find(mesh);
  168. if (unlikely(iter == mesh_to_shared.end())) {
  169. return;
  170. }
  171. if (--iter->value.ref_count == 0) {
  172. mesh_to_shared.remove(iter);
  173. }
  174. shared = nullptr;
  175. }
  176. void JoltSoftBody3D::_update_mass() {
  177. if (!in_space()) {
  178. return;
  179. }
  180. JoltWritableBody3D body = space->write_body(jolt_id);
  181. ERR_FAIL_COND(body.is_invalid());
  182. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  183. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  184. const float inverse_vertex_mass = mass == 0.0f ? 1.0f : (float)physics_vertices.size() / mass;
  185. for (JPH::SoftBodyVertex &vertex : physics_vertices) {
  186. vertex.mInvMass = inverse_vertex_mass;
  187. }
  188. pin_vertices(*this, pinned_vertices, shared->mesh_to_physics, physics_vertices);
  189. }
  190. void JoltSoftBody3D::_update_pressure() {
  191. if (!in_space()) {
  192. jolt_settings->mPressure = pressure;
  193. return;
  194. }
  195. JoltWritableBody3D body = space->write_body(jolt_id);
  196. ERR_FAIL_COND(body.is_invalid());
  197. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  198. motion_properties.SetPressure(pressure);
  199. }
  200. void JoltSoftBody3D::_update_damping() {
  201. if (!in_space()) {
  202. jolt_settings->mLinearDamping = linear_damping;
  203. return;
  204. }
  205. JoltWritableBody3D body = space->write_body(jolt_id);
  206. ERR_FAIL_COND(body.is_invalid());
  207. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  208. motion_properties.SetLinearDamping(linear_damping);
  209. }
  210. void JoltSoftBody3D::_update_simulation_precision() {
  211. if (!in_space()) {
  212. jolt_settings->mNumIterations = (JPH::uint32)simulation_precision;
  213. return;
  214. }
  215. JoltWritableBody3D body = space->write_body(jolt_id);
  216. ERR_FAIL_COND(body.is_invalid());
  217. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  218. motion_properties.SetNumIterations((JPH::uint32)simulation_precision);
  219. }
  220. void JoltSoftBody3D::_update_group_filter() {
  221. JPH::GroupFilter *group_filter = !exceptions.is_empty() ? JoltGroupFilter::instance : nullptr;
  222. if (!in_space()) {
  223. jolt_settings->mCollisionGroup.SetGroupFilter(group_filter);
  224. return;
  225. }
  226. const JoltWritableBody3D body = space->write_body(jolt_id);
  227. ERR_FAIL_COND(body.is_invalid());
  228. body->GetCollisionGroup().SetGroupFilter(group_filter);
  229. }
  230. void JoltSoftBody3D::_try_rebuild() {
  231. if (space != nullptr) {
  232. _reset_space();
  233. }
  234. }
  235. void JoltSoftBody3D::_mesh_changed() {
  236. _try_rebuild();
  237. }
  238. void JoltSoftBody3D::_simulation_precision_changed() {
  239. wake_up();
  240. }
  241. void JoltSoftBody3D::_mass_changed() {
  242. wake_up();
  243. }
  244. void JoltSoftBody3D::_pressure_changed() {
  245. _update_pressure();
  246. wake_up();
  247. }
  248. void JoltSoftBody3D::_damping_changed() {
  249. _update_damping();
  250. wake_up();
  251. }
  252. void JoltSoftBody3D::_pins_changed() {
  253. _update_mass();
  254. wake_up();
  255. }
  256. void JoltSoftBody3D::_vertices_changed() {
  257. wake_up();
  258. }
  259. void JoltSoftBody3D::_exceptions_changed() {
  260. _update_group_filter();
  261. }
  262. JoltSoftBody3D::JoltSoftBody3D() :
  263. JoltObject3D(OBJECT_TYPE_SOFT_BODY) {
  264. jolt_settings->mRestitution = 0.0f;
  265. jolt_settings->mFriction = 1.0f;
  266. jolt_settings->mUpdatePosition = false;
  267. jolt_settings->mMakeRotationIdentity = false;
  268. }
  269. JoltSoftBody3D::~JoltSoftBody3D() {
  270. if (jolt_settings != nullptr) {
  271. delete jolt_settings;
  272. jolt_settings = nullptr;
  273. }
  274. }
  275. bool JoltSoftBody3D::in_space() const {
  276. return JoltObject3D::in_space() && shared != nullptr;
  277. }
  278. void JoltSoftBody3D::add_collision_exception(const RID &p_excepted_body) {
  279. exceptions.push_back(p_excepted_body);
  280. _exceptions_changed();
  281. }
  282. void JoltSoftBody3D::remove_collision_exception(const RID &p_excepted_body) {
  283. exceptions.erase(p_excepted_body);
  284. _exceptions_changed();
  285. }
  286. bool JoltSoftBody3D::has_collision_exception(const RID &p_excepted_body) const {
  287. return exceptions.find(p_excepted_body) >= 0;
  288. }
  289. bool JoltSoftBody3D::can_interact_with(const JoltBody3D &p_other) const {
  290. 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);
  291. }
  292. bool JoltSoftBody3D::can_interact_with(const JoltSoftBody3D &p_other) const {
  293. 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);
  294. }
  295. bool JoltSoftBody3D::can_interact_with(const JoltArea3D &p_other) const {
  296. return p_other.can_interact_with(*this);
  297. }
  298. Vector3 JoltSoftBody3D::get_velocity_at_position(const Vector3 &p_position) const {
  299. return Vector3();
  300. }
  301. void JoltSoftBody3D::set_mesh(const RID &p_mesh) {
  302. if (unlikely(mesh == p_mesh)) {
  303. return;
  304. }
  305. _deref_shared_data();
  306. mesh = p_mesh;
  307. _mesh_changed();
  308. }
  309. bool JoltSoftBody3D::is_sleeping() const {
  310. if (!in_space()) {
  311. return false;
  312. }
  313. const JoltReadableBody3D body = space->read_body(jolt_id);
  314. ERR_FAIL_COND_V(body.is_invalid(), false);
  315. return !body->IsActive();
  316. }
  317. void JoltSoftBody3D::set_is_sleeping(bool p_enabled) {
  318. if (!in_space()) {
  319. return;
  320. }
  321. JPH::BodyInterface &body_iface = space->get_body_iface();
  322. if (p_enabled) {
  323. body_iface.DeactivateBody(jolt_id);
  324. } else {
  325. body_iface.ActivateBody(jolt_id);
  326. }
  327. }
  328. bool JoltSoftBody3D::is_sleep_allowed() const {
  329. if (!in_space()) {
  330. return true;
  331. }
  332. const JoltReadableBody3D body = space->read_body(jolt_id);
  333. ERR_FAIL_COND_V(body.is_invalid(), false);
  334. return body->GetAllowSleeping();
  335. }
  336. void JoltSoftBody3D::set_is_sleep_allowed(bool p_enabled) {
  337. if (!in_space()) {
  338. return;
  339. }
  340. const JoltWritableBody3D body = space->write_body(jolt_id);
  341. ERR_FAIL_COND(body.is_invalid());
  342. body->SetAllowSleeping(p_enabled);
  343. }
  344. void JoltSoftBody3D::set_simulation_precision(int p_precision) {
  345. if (unlikely(simulation_precision == p_precision)) {
  346. return;
  347. }
  348. simulation_precision = MAX(p_precision, 0);
  349. _simulation_precision_changed();
  350. }
  351. void JoltSoftBody3D::set_mass(float p_mass) {
  352. if (unlikely(mass == p_mass)) {
  353. return;
  354. }
  355. mass = MAX(p_mass, 0.0f);
  356. _mass_changed();
  357. }
  358. float JoltSoftBody3D::get_stiffness_coefficient() const {
  359. return stiffness_coefficient;
  360. }
  361. void JoltSoftBody3D::set_stiffness_coefficient(float p_coefficient) {
  362. stiffness_coefficient = CLAMP(p_coefficient, 0.0f, 1.0f);
  363. }
  364. void JoltSoftBody3D::set_pressure(float p_pressure) {
  365. if (unlikely(pressure == p_pressure)) {
  366. return;
  367. }
  368. pressure = MAX(p_pressure, 0.0f);
  369. _pressure_changed();
  370. }
  371. void JoltSoftBody3D::set_linear_damping(float p_damping) {
  372. if (unlikely(linear_damping == p_damping)) {
  373. return;
  374. }
  375. linear_damping = MAX(p_damping, 0.0f);
  376. _damping_changed();
  377. }
  378. float JoltSoftBody3D::get_drag() const {
  379. // Drag is not a thing in Jolt, and not supported by Godot Physics either.
  380. return 0.0f;
  381. }
  382. void JoltSoftBody3D::set_drag(float p_drag) {
  383. // Drag is not a thing in Jolt, and not supported by Godot Physics either.
  384. }
  385. Variant JoltSoftBody3D::get_state(PhysicsServer3D::BodyState p_state) const {
  386. switch (p_state) {
  387. case PhysicsServer3D::BODY_STATE_TRANSFORM: {
  388. return get_transform();
  389. }
  390. case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
  391. ERR_FAIL_V_MSG(Variant(), "Linear velocity is not supported for soft bodies.");
  392. }
  393. case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
  394. ERR_FAIL_V_MSG(Variant(), "Angular velocity is not supported for soft bodies.");
  395. }
  396. case PhysicsServer3D::BODY_STATE_SLEEPING: {
  397. return is_sleeping();
  398. }
  399. case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
  400. return is_sleep_allowed();
  401. }
  402. default: {
  403. ERR_FAIL_V_MSG(Variant(), vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
  404. }
  405. }
  406. }
  407. void JoltSoftBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_value) {
  408. switch (p_state) {
  409. case PhysicsServer3D::BODY_STATE_TRANSFORM: {
  410. set_transform(p_value);
  411. } break;
  412. case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {
  413. ERR_FAIL_MSG("Linear velocity is not supported for soft bodies.");
  414. } break;
  415. case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {
  416. ERR_FAIL_MSG("Angular velocity is not supported for soft bodies.");
  417. } break;
  418. case PhysicsServer3D::BODY_STATE_SLEEPING: {
  419. set_is_sleeping(p_value);
  420. } break;
  421. case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {
  422. set_is_sleep_allowed(p_value);
  423. } break;
  424. default: {
  425. ERR_FAIL_MSG(vformat("Unhandled body state: '%d'. This should not happen. Please report this.", p_state));
  426. } break;
  427. }
  428. }
  429. Transform3D JoltSoftBody3D::get_transform() const {
  430. // Since any transform gets baked into the vertices anyway we can just return identity here.
  431. return Transform3D();
  432. }
  433. void JoltSoftBody3D::set_transform(const Transform3D &p_transform) {
  434. 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()));
  435. JoltWritableBody3D body = space->write_body(jolt_id);
  436. ERR_FAIL_COND(body.is_invalid());
  437. // For whatever reason this has to be interpreted as a relative global-space transform rather than an absolute one,
  438. // because `SoftBody3D` will immediately upon entering the scene tree set itself to be top-level and also set its
  439. // transform to be identity, while still expecting to stay in its original position.
  440. //
  441. // We also discard any scaling, since we have no way of scaling the actual edge lengths.
  442. const JPH::Mat44 relative_transform = to_jolt(p_transform.orthonormalized());
  443. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  444. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  445. for (JPH::SoftBodyVertex &vertex : physics_vertices) {
  446. vertex.mPosition = vertex.mPreviousPosition = relative_transform * vertex.mPosition;
  447. vertex.mVelocity = JPH::Vec3::sZero();
  448. }
  449. }
  450. AABB JoltSoftBody3D::get_bounds() const {
  451. 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()));
  452. const JoltReadableBody3D body = space->read_body(jolt_id);
  453. ERR_FAIL_COND_V(body.is_invalid(), AABB());
  454. return to_godot(body->GetWorldSpaceBounds());
  455. }
  456. void JoltSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandler *p_rendering_server_handler) {
  457. // 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.
  458. if (unlikely(!in_space())) {
  459. return;
  460. }
  461. const JoltReadableBody3D body = space->read_body(jolt_id);
  462. ERR_FAIL_COND(body.is_invalid());
  463. const JPH::SoftBodyMotionProperties &motion_properties = static_cast<const JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  464. typedef JPH::SoftBodyMotionProperties::Vertex SoftBodyVertex;
  465. typedef JPH::SoftBodyMotionProperties::Face SoftBodyFace;
  466. const JPH::Array<SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  467. const JPH::Array<SoftBodyFace> &physics_faces = motion_properties.GetFaces();
  468. const int physics_vertex_count = (int)physics_vertices.size();
  469. normals.resize(physics_vertex_count);
  470. for (const SoftBodyFace &physics_face : physics_faces) {
  471. // Jolt uses a different winding order, so we swap the indices to account for that.
  472. const uint32_t i0 = physics_face.mVertex[2];
  473. const uint32_t i1 = physics_face.mVertex[1];
  474. const uint32_t i2 = physics_face.mVertex[0];
  475. const Vector3 v0 = to_godot(physics_vertices[i0].mPosition);
  476. const Vector3 v1 = to_godot(physics_vertices[i1].mPosition);
  477. const Vector3 v2 = to_godot(physics_vertices[i2].mPosition);
  478. const Vector3 normal = (v2 - v0).cross(v1 - v0).normalized();
  479. normals[i0] = normal;
  480. normals[i1] = normal;
  481. normals[i2] = normal;
  482. }
  483. const int mesh_vertex_count = shared->mesh_to_physics.size();
  484. for (int i = 0; i < mesh_vertex_count; ++i) {
  485. const int physics_index = shared->mesh_to_physics[i];
  486. const Vector3 vertex = to_godot(physics_vertices[(size_t)physics_index].mPosition);
  487. const Vector3 normal = normals[(uint32_t)physics_index];
  488. p_rendering_server_handler->set_vertex(i, vertex);
  489. p_rendering_server_handler->set_normal(i, normal);
  490. }
  491. p_rendering_server_handler->set_aabb(get_bounds());
  492. }
  493. Vector3 JoltSoftBody3D::get_vertex_position(int p_index) {
  494. 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()));
  495. ERR_FAIL_NULL_V(shared, Vector3());
  496. ERR_FAIL_INDEX_V(p_index, (int)shared->mesh_to_physics.size(), Vector3());
  497. const size_t physics_index = (size_t)shared->mesh_to_physics[p_index];
  498. const JoltReadableBody3D body = space->read_body(jolt_id);
  499. ERR_FAIL_COND_V(body.is_invalid(), Vector3());
  500. const JPH::SoftBodyMotionProperties &motion_properties = static_cast<const JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  501. const JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  502. const JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
  503. return to_godot(body->GetCenterOfMassPosition() + physics_vertex.mPosition);
  504. }
  505. void JoltSoftBody3D::set_vertex_position(int p_index, const Vector3 &p_position) {
  506. 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()));
  507. ERR_FAIL_NULL(shared);
  508. ERR_FAIL_INDEX(p_index, (int)shared->mesh_to_physics.size());
  509. const size_t physics_index = (size_t)shared->mesh_to_physics[p_index];
  510. const float last_step = space->get_last_step();
  511. if (unlikely(last_step == 0.0f)) {
  512. return;
  513. }
  514. JoltWritableBody3D body = space->write_body(jolt_id);
  515. ERR_FAIL_COND(body.is_invalid());
  516. JPH::SoftBodyMotionProperties &motion_properties = static_cast<JPH::SoftBodyMotionProperties &>(*body->GetMotionPropertiesUnchecked());
  517. JPH::Array<JPH::SoftBodyVertex> &physics_vertices = motion_properties.GetVertices();
  518. JPH::SoftBodyVertex &physics_vertex = physics_vertices[physics_index];
  519. const JPH::RVec3 center_of_mass = body->GetCenterOfMassPosition();
  520. const JPH::Vec3 local_position = JPH::Vec3(to_jolt_r(p_position) - center_of_mass);
  521. const JPH::Vec3 displacement = local_position - physics_vertex.mPosition;
  522. const JPH::Vec3 velocity = displacement / last_step;
  523. physics_vertex.mVelocity = velocity;
  524. _vertices_changed();
  525. }
  526. void JoltSoftBody3D::pin_vertex(int p_index) {
  527. pinned_vertices.insert(p_index);
  528. _pins_changed();
  529. }
  530. void JoltSoftBody3D::unpin_vertex(int p_index) {
  531. pinned_vertices.erase(p_index);
  532. _pins_changed();
  533. }
  534. void JoltSoftBody3D::unpin_all_vertices() {
  535. pinned_vertices.clear();
  536. _pins_changed();
  537. }
  538. bool JoltSoftBody3D::is_vertex_pinned(int p_index) const {
  539. 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()));
  540. ERR_FAIL_NULL_V(shared, false);
  541. ERR_FAIL_INDEX_V(p_index, (int)shared->mesh_to_physics.size(), false);
  542. const int physics_index = shared->mesh_to_physics[p_index];
  543. return pinned_vertices.has(physics_index);
  544. }