Path: blob/master/modules/godot_physics_3d/godot_soft_body_3d.cpp
10277 views
/**************************************************************************/1/* godot_soft_body_3d.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "godot_soft_body_3d.h"3132#include "godot_space_3d.h"3334#include "core/math/geometry_3d.h"35#include "servers/rendering_server.h"3637// Based on Bullet soft body.3839/*40Bullet Continuous Collision Detection and Physics Library41Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/4243This software is provided 'as-is', without any express or implied warranty.44In no event will the authors be held liable for any damages arising from the use of this software.45Permission is granted to anyone to use this software for any purpose,46including commercial applications, and to alter it and redistribute it freely,47subject to the following restrictions:48491. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.502. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.513. This notice may not be removed or altered from any source distribution.52*/53///btSoftBody implementation by Nathanael Presson5455GodotSoftBody3D::GodotSoftBody3D() :56GodotCollisionObject3D(TYPE_SOFT_BODY),57active_list(this) {58_set_static(false);59}6061void GodotSoftBody3D::_shapes_changed() {62}6364void GodotSoftBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) {65switch (p_state) {66case PhysicsServer3D::BODY_STATE_TRANSFORM: {67_set_transform(p_variant);68_set_inv_transform(get_transform().inverse());6970apply_nodes_transform(get_transform());7172} break;73case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {74// Not supported.75ERR_FAIL_MSG("Linear velocity is not supported for Soft bodies.");76} break;77case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {78ERR_FAIL_MSG("Angular velocity is not supported for Soft bodies.");79} break;80case PhysicsServer3D::BODY_STATE_SLEEPING: {81ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");82} break;83case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {84ERR_FAIL_MSG("Sleeping state is not supported for Soft bodies.");85} break;86}87}8889Variant GodotSoftBody3D::get_state(PhysicsServer3D::BodyState p_state) const {90switch (p_state) {91case PhysicsServer3D::BODY_STATE_TRANSFORM: {92return get_transform();93} break;94case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: {95ERR_FAIL_V_MSG(Vector3(), "Linear velocity is not supported for Soft bodies.");96} break;97case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: {98ERR_FAIL_V_MSG(Vector3(), "Angular velocity is not supported for Soft bodies.");99} break;100case PhysicsServer3D::BODY_STATE_SLEEPING: {101ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");102} break;103case PhysicsServer3D::BODY_STATE_CAN_SLEEP: {104ERR_FAIL_V_MSG(false, "Sleeping state is not supported for Soft bodies.");105} break;106}107108return Variant();109}110111void GodotSoftBody3D::set_space(GodotSpace3D *p_space) {112if (get_space()) {113get_space()->soft_body_remove_from_active_list(&active_list);114115deinitialize_shape();116}117118_set_space(p_space);119120if (get_space()) {121get_space()->soft_body_add_to_active_list(&active_list);122123if (bounds != AABB()) {124initialize_shape(true);125}126}127}128129void GodotSoftBody3D::set_mesh(RID p_mesh) {130destroy();131132soft_mesh = p_mesh;133134if (soft_mesh.is_null()) {135return;136}137138// TODO: calling RenderingServer::mesh_surface_get_arrays() from the physics thread139// is not safe and can deadlock when physics/3d/run_on_separate_thread is enabled.140// This method blocks on the main thread to return data, but the main thread may be141// blocked waiting on us in PhysicsServer3D::sync().142Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0);143ERR_FAIL_COND(arrays.is_empty());144145const Vector<int> &indices = arrays[RenderingServer::ARRAY_INDEX];146const Vector<Vector3> &vertices = arrays[RenderingServer::ARRAY_VERTEX];147ERR_FAIL_COND_MSG(indices.is_empty(), "Soft body's mesh needs to have indices");148ERR_FAIL_COND_MSG(vertices.is_empty(), "Soft body's mesh needs to have vertices");149150bool success = create_from_trimesh(indices, vertices);151if (!success) {152destroy();153}154}155156void GodotSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHandler *p_rendering_server_handler) {157if (soft_mesh.is_null()) {158return;159}160161const uint32_t vertex_count = map_visual_to_physics.size();162for (uint32_t i = 0; i < vertex_count; ++i) {163const uint32_t node_index = map_visual_to_physics[i];164const Node &node = nodes[node_index];165166p_rendering_server_handler->set_vertex(i, node.x);167p_rendering_server_handler->set_normal(i, node.n);168}169170p_rendering_server_handler->set_aabb(bounds);171}172173void GodotSoftBody3D::update_normals_and_centroids() {174for (Node &node : nodes) {175node.n = Vector3();176}177178for (Face &face : faces) {179const Vector3 n = vec3_cross(face.n[0]->x - face.n[2]->x, face.n[0]->x - face.n[1]->x);180face.n[0]->n += n;181face.n[1]->n += n;182face.n[2]->n += n;183face.normal = n;184face.normal.normalize();185face.centroid = 0.33333333333 * (face.n[0]->x + face.n[1]->x + face.n[2]->x);186}187188for (Node &node : nodes) {189real_t len = node.n.length();190if (len > CMP_EPSILON) {191node.n /= len;192}193}194}195196void GodotSoftBody3D::update_bounds() {197AABB prev_bounds = bounds;198prev_bounds.grow_by(collision_margin);199200bounds = AABB();201202const uint32_t nodes_count = nodes.size();203if (nodes_count == 0) {204deinitialize_shape();205return;206}207208bool first = true;209bool moved = false;210for (uint32_t node_index = 0; node_index < nodes_count; ++node_index) {211const Node &node = nodes[node_index];212if (!prev_bounds.has_point(node.x)) {213moved = true;214}215if (first) {216bounds.position = node.x;217first = false;218} else {219bounds.expand_to(node.x);220}221}222223if (get_space()) {224initialize_shape(moved);225}226}227228void GodotSoftBody3D::update_constants() {229reset_link_rest_lengths();230update_link_constants();231update_area();232}233234void GodotSoftBody3D::update_area() {235int i, ni;236237// Face area.238for (Face &face : faces) {239const Vector3 &x0 = face.n[0]->x;240const Vector3 &x1 = face.n[1]->x;241const Vector3 &x2 = face.n[2]->x;242243const Vector3 a = x1 - x0;244const Vector3 b = x2 - x0;245const Vector3 cr = vec3_cross(a, b);246face.ra = cr.length() * 0.5;247}248249// Node area.250LocalVector<int> counts;251if (nodes.size() > 0) {252counts.resize(nodes.size());253memset(counts.ptr(), 0, counts.size() * sizeof(int));254}255256for (Node &node : nodes) {257node.area = 0.0;258}259260for (const Face &face : faces) {261for (int j = 0; j < 3; ++j) {262const int index = (int)(face.n[j] - &nodes[0]);263counts[index]++;264face.n[j]->area += Math::abs(face.ra);265}266}267268for (i = 0, ni = nodes.size(); i < ni; ++i) {269if (counts[i] > 0) {270nodes[i].area /= (real_t)counts[i];271} else {272nodes[i].area = 0.0;273}274}275}276277void GodotSoftBody3D::reset_link_rest_lengths() {278float multiplier = 1.0 - shrinking_factor;279for (Link &link : links) {280link.rl = (link.n[0]->x - link.n[1]->x).length();281link.rl *= multiplier;282link.c1 = link.rl * link.rl;283}284}285286void GodotSoftBody3D::update_link_constants() {287real_t inv_linear_stiffness = 1.0 / linear_stiffness;288for (Link &link : links) {289link.c0 = (link.n[0]->im + link.n[1]->im) * inv_linear_stiffness;290}291}292293void GodotSoftBody3D::apply_nodes_transform(const Transform3D &p_transform) {294if (soft_mesh.is_null()) {295return;296}297298uint32_t node_count = nodes.size();299Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;300for (uint32_t node_index = 0; node_index < node_count; ++node_index) {301Node &node = nodes[node_index];302303node.x = p_transform.xform(node.x);304node.q = node.x;305node.v = Vector3();306node.bv = Vector3();307308AABB node_aabb(node.x, leaf_size);309node_tree.update(node.leaf, node_aabb);310}311312face_tree.clear();313314update_normals_and_centroids();315update_bounds();316update_constants();317}318319Vector3 GodotSoftBody3D::get_vertex_position(int p_index) const {320ERR_FAIL_COND_V(p_index < 0, Vector3());321322if (soft_mesh.is_null()) {323return Vector3();324}325326ERR_FAIL_COND_V(p_index >= (int)map_visual_to_physics.size(), Vector3());327uint32_t node_index = map_visual_to_physics[p_index];328329ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3());330return nodes[node_index].x;331}332333void GodotSoftBody3D::set_vertex_position(int p_index, const Vector3 &p_position) {334ERR_FAIL_COND(p_index < 0);335336if (soft_mesh.is_null()) {337return;338}339340ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());341uint32_t node_index = map_visual_to_physics[p_index];342343ERR_FAIL_COND(node_index >= nodes.size());344Node &node = nodes[node_index];345node.q = node.x;346node.x = p_position;347}348349void GodotSoftBody3D::pin_vertex(int p_index) {350ERR_FAIL_COND(p_index < 0);351352if (is_vertex_pinned(p_index)) {353return;354}355356pinned_vertices.push_back(p_index);357358if (!soft_mesh.is_null()) {359ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());360uint32_t node_index = map_visual_to_physics[p_index];361362ERR_FAIL_COND(node_index >= nodes.size());363Node &node = nodes[node_index];364node.im = 0.0;365}366}367368void GodotSoftBody3D::unpin_vertex(int p_index) {369ERR_FAIL_COND(p_index < 0);370371uint32_t pinned_count = pinned_vertices.size();372for (uint32_t i = 0; i < pinned_count; ++i) {373if (p_index == pinned_vertices[i]) {374pinned_vertices.remove_at(i);375376if (!soft_mesh.is_null()) {377ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size());378uint32_t node_index = map_visual_to_physics[p_index];379380ERR_FAIL_COND(node_index >= nodes.size());381real_t inv_node_mass = nodes.size() * inv_total_mass;382383Node &node = nodes[node_index];384node.im = inv_node_mass;385}386387return;388}389}390}391392void GodotSoftBody3D::unpin_all_vertices() {393if (!soft_mesh.is_null()) {394real_t inv_node_mass = nodes.size() * inv_total_mass;395uint32_t pinned_count = pinned_vertices.size();396for (uint32_t i = 0; i < pinned_count; ++i) {397int pinned_vertex = pinned_vertices[i];398399ERR_CONTINUE(pinned_vertex >= (int)map_visual_to_physics.size());400uint32_t node_index = map_visual_to_physics[pinned_vertex];401402ERR_CONTINUE(node_index >= nodes.size());403Node &node = nodes[node_index];404node.im = inv_node_mass;405}406}407408pinned_vertices.clear();409}410411bool GodotSoftBody3D::is_vertex_pinned(int p_index) const {412ERR_FAIL_COND_V(p_index < 0, false);413414uint32_t pinned_count = pinned_vertices.size();415for (uint32_t i = 0; i < pinned_count; ++i) {416if (p_index == pinned_vertices[i]) {417return true;418}419}420421return false;422}423424uint32_t GodotSoftBody3D::get_node_count() const {425return nodes.size();426}427428real_t GodotSoftBody3D::get_node_inv_mass(uint32_t p_node_index) const {429ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), 0.0);430return nodes[p_node_index].im;431}432433Vector3 GodotSoftBody3D::get_node_position(uint32_t p_node_index) const {434ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());435return nodes[p_node_index].x;436}437438Vector3 GodotSoftBody3D::get_node_velocity(uint32_t p_node_index) const {439ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());440return nodes[p_node_index].v;441}442443Vector3 GodotSoftBody3D::get_node_biased_velocity(uint32_t p_node_index) const {444ERR_FAIL_UNSIGNED_INDEX_V(p_node_index, nodes.size(), Vector3());445return nodes[p_node_index].bv;446}447448void GodotSoftBody3D::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {449ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());450Node &node = nodes[p_node_index];451node.v += p_impulse * node.im;452}453454void GodotSoftBody3D::apply_node_force(uint32_t p_node_index, const Vector3 &p_force) {455ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());456Node &node = nodes[p_node_index];457node.f += p_force;458}459460void GodotSoftBody3D::apply_central_impulse(const Vector3 &p_impulse) {461const Vector3 impulse = p_impulse / nodes.size();462for (Node &node : nodes) {463if (node.im > 0) {464node.v += impulse * node.im;465}466}467}468469void GodotSoftBody3D::apply_central_force(const Vector3 &p_force) {470const Vector3 force = p_force / nodes.size();471for (Node &node : nodes) {472if (node.im > 0) {473node.f += force;474}475}476}477478void GodotSoftBody3D::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) {479ERR_FAIL_UNSIGNED_INDEX(p_node_index, nodes.size());480Node &node = nodes[p_node_index];481node.bv += p_impulse * node.im;482}483484uint32_t GodotSoftBody3D::get_face_count() const {485return faces.size();486}487488void GodotSoftBody3D::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const {489ERR_FAIL_UNSIGNED_INDEX(p_face_index, faces.size());490const Face &face = faces[p_face_index];491r_point_1 = face.n[0]->x;492r_point_2 = face.n[1]->x;493r_point_3 = face.n[2]->x;494}495496Vector3 GodotSoftBody3D::get_face_normal(uint32_t p_face_index) const {497ERR_FAIL_UNSIGNED_INDEX_V(p_face_index, faces.size(), Vector3());498return faces[p_face_index].normal;499}500501bool GodotSoftBody3D::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) {502ERR_FAIL_COND_V(p_indices.is_empty(), false);503ERR_FAIL_COND_V(p_vertices.is_empty(), false);504505uint32_t node_count = 0;506LocalVector<Vector3> vertices;507const int visual_vertex_count(p_vertices.size());508509LocalVector<int> triangles;510const uint32_t triangle_count(p_indices.size() / 3);511triangles.resize(triangle_count * 3);512513// Merge all overlapping vertices and create a map of physical vertices to visual vertices.514{515// Process vertices.516{517uint32_t vertex_count = 0;518HashMap<Vector3, uint32_t> unique_vertices;519520vertices.resize(visual_vertex_count);521map_visual_to_physics.resize(visual_vertex_count);522523for (int visual_vertex_index = 0; visual_vertex_index < visual_vertex_count; ++visual_vertex_index) {524const Vector3 &vertex = p_vertices[visual_vertex_index];525526HashMap<Vector3, uint32_t>::Iterator e = unique_vertices.find(vertex);527uint32_t vertex_id;528if (e) {529// Already existing.530vertex_id = e->value;531} else {532// Create new one.533vertex_id = vertex_count++;534unique_vertices[vertex] = vertex_id;535vertices[vertex_id] = vertex;536}537538map_visual_to_physics[visual_vertex_index] = vertex_id;539}540541vertices.resize(vertex_count);542}543544// Process triangles.545{546for (uint32_t triangle_index = 0; triangle_index < triangle_count; ++triangle_index) {547for (int i = 0; i < 3; ++i) {548int visual_index = 3 * triangle_index + i;549int physics_index = map_visual_to_physics[p_indices[visual_index]];550triangles[visual_index] = physics_index;551node_count = MAX((int)node_count, physics_index);552}553}554}555}556557++node_count;558559// Create nodes from vertices.560nodes.resize(node_count);561real_t inv_node_mass = node_count * inv_total_mass;562Vector3 leaf_size = Vector3(collision_margin, collision_margin, collision_margin) * 2.0;563for (uint32_t i = 0; i < node_count; ++i) {564Node &node = nodes[i];565node.s = vertices[i];566node.x = node.s;567node.q = node.s;568node.im = inv_node_mass;569570AABB node_aabb(node.x, leaf_size);571node.leaf = node_tree.insert(node_aabb, &node);572573node.index = i;574}575576// Create links and faces from triangles.577LocalVector<bool> chks;578chks.resize(node_count * node_count);579memset(chks.ptr(), 0, chks.size() * sizeof(bool));580581for (uint32_t i = 0; i < triangle_count * 3; i += 3) {582const int idx[] = { triangles[i], triangles[i + 1], triangles[i + 2] };583584for (int j = 2, k = 0; k < 3; j = k++) {585int chk = idx[k] * node_count + idx[j];586if (!chks[chk]) {587chks[chk] = true;588int inv_chk = idx[j] * node_count + idx[k];589chks[inv_chk] = true;590591append_link(idx[j], idx[k]);592}593}594595append_face(idx[0], idx[1], idx[2]);596}597598// Set pinned nodes.599uint32_t pinned_count = pinned_vertices.size();600for (uint32_t i = 0; i < pinned_count; ++i) {601int pinned_vertex = pinned_vertices[i];602603ERR_CONTINUE(pinned_vertex >= visual_vertex_count);604uint32_t node_index = map_visual_to_physics[pinned_vertex];605606ERR_CONTINUE(node_index >= node_count);607Node &node = nodes[node_index];608node.im = 0.0;609}610611generate_bending_constraints(2);612reoptimize_link_order();613614update_constants();615update_normals_and_centroids();616update_bounds();617618return true;619}620621void GodotSoftBody3D::generate_bending_constraints(int p_distance) {622uint32_t i, j;623624if (p_distance > 1) {625// Build graph.626const uint32_t n = nodes.size();627const unsigned inf = (~(unsigned)0) >> 1;628const uint32_t adj_size = n * n;629unsigned *adj = memnew_arr(unsigned, adj_size);630631#define IDX(_x_, _y_) ((_y_) * n + (_x_))632for (j = 0; j < n; ++j) {633for (i = 0; i < n; ++i) {634int idx_ij = j * n + i;635int idx_ji = i * n + j;636if (i != j) {637adj[idx_ij] = adj[idx_ji] = inf;638} else {639adj[idx_ij] = adj[idx_ji] = 0;640}641}642}643for (Link &link : links) {644const int ia = (int)(link.n[0] - &nodes[0]);645const int ib = (int)(link.n[1] - &nodes[0]);646int idx = ib * n + ia;647int idx_inv = ia * n + ib;648adj[idx] = 1;649adj[idx_inv] = 1;650}651652// Special optimized case for distance == 2.653if (p_distance == 2) {654LocalVector<LocalVector<int>> node_links;655656// Build node links.657node_links.resize(nodes.size());658659for (Link &link : links) {660const int ia = (int)(link.n[0] - &nodes[0]);661const int ib = (int)(link.n[1] - &nodes[0]);662if (!node_links[ia].has(ib)) {663node_links[ia].push_back(ib);664}665666if (!node_links[ib].has(ia)) {667node_links[ib].push_back(ia);668}669}670for (uint32_t ii = 0; ii < node_links.size(); ii++) {671for (uint32_t jj = 0; jj < node_links[ii].size(); jj++) {672int k = node_links[ii][jj];673for (const int &l : node_links[k]) {674if ((int)ii != l) {675int idx_ik = k * n + ii;676int idx_kj = l * n + k;677const unsigned sum = adj[idx_ik] + adj[idx_kj];678ERR_FAIL_COND(sum != 2);679int idx_ij = l * n + ii;680if (adj[idx_ij] > sum) {681int idx_ji = l * n + ii;682adj[idx_ij] = adj[idx_ji] = sum;683}684}685}686}687}688} else {689// Generic Floyd's algorithm.690for (uint32_t k = 0; k < n; ++k) {691for (j = 0; j < n; ++j) {692for (i = j + 1; i < n; ++i) {693int idx_ik = k * n + i;694int idx_kj = j * n + k;695const unsigned sum = adj[idx_ik] + adj[idx_kj];696int idx_ij = j * n + i;697if (adj[idx_ij] > sum) {698int idx_ji = j * n + i;699adj[idx_ij] = adj[idx_ji] = sum;700}701}702}703}704}705706// Build links.707for (j = 0; j < n; ++j) {708for (i = j + 1; i < n; ++i) {709int idx_ij = j * n + i;710if (adj[idx_ij] == (unsigned)p_distance) {711append_link(i, j);712}713}714}715memdelete_arr(adj);716}717}718719//===================================================================720//721//722// This function takes in a list of interdependent Links and tries723// to maximize the distance between calculation724// of dependent links. This increases the amount of parallelism that can725// be exploited by out-of-order instruction processors with large but726// (inevitably) finite instruction windows.727//728//===================================================================729730// A small structure to track lists of dependent link calculations.731class LinkDeps {732public:733// A link calculation that is dependent on this one.734// Positive values = "input A" while negative values = "input B".735int value;736// Next dependence in the list.737LinkDeps *next;738};739typedef LinkDeps *LinkDepsPtr;740741void GodotSoftBody3D::reoptimize_link_order() {742const int reop_not_dependent = -1;743const int reop_node_complete = -2;744745uint32_t link_count = links.size();746uint32_t node_count = nodes.size();747748if (link_count < 1 || node_count < 2) {749return;750}751752uint32_t i;753Link *lr;754int ar, br;755Node *node0 = &(nodes[0]);756Node *node1 = &(nodes[1]);757LinkDepsPtr link_dep;758int ready_list_head, ready_list_tail, link_num, link_dep_frees, dep_link;759760// Allocate temporary buffers.761int *node_written_at = memnew_arr(int, node_count + 1); // What link calculation produced this node's current values?762int *link_dep_A = memnew_arr(int, link_count); // Link calculation input is dependent upon prior calculation #N763int *link_dep_B = memnew_arr(int, link_count);764int *ready_list = memnew_arr(int, link_count); // List of ready-to-process link calculations (# of links, maximum)765LinkDeps *link_dep_free_list = memnew_arr(LinkDeps, 2 * link_count); // Dependent-on-me list elements (2x# of links, maximum)766LinkDepsPtr *link_dep_list_starts = memnew_arr(LinkDepsPtr, link_count); // Start nodes of dependent-on-me lists, one for each link767768// Copy the original, unsorted links to a side buffer.769Link *link_buffer = memnew_arr(Link, link_count);770memcpy(link_buffer, &(links[0]), sizeof(Link) * link_count);771772// Clear out the node setup and ready list.773for (i = 0; i < node_count + 1; i++) {774node_written_at[i] = reop_not_dependent;775}776for (i = 0; i < link_count; i++) {777link_dep_list_starts[i] = nullptr;778}779ready_list_head = ready_list_tail = link_dep_frees = 0;780781// Initial link analysis to set up data structures.782for (i = 0; i < link_count; i++) {783// Note which prior link calculations we are dependent upon & build up dependence lists.784lr = &(links[i]);785ar = (lr->n[0] - node0) / (node1 - node0);786br = (lr->n[1] - node0) / (node1 - node0);787if (node_written_at[ar] > reop_not_dependent) {788link_dep_A[i] = node_written_at[ar];789link_dep = &link_dep_free_list[link_dep_frees++];790link_dep->value = i;791link_dep->next = link_dep_list_starts[node_written_at[ar]];792link_dep_list_starts[node_written_at[ar]] = link_dep;793} else {794link_dep_A[i] = reop_not_dependent;795}796if (node_written_at[br] > reop_not_dependent) {797link_dep_B[i] = node_written_at[br];798link_dep = &link_dep_free_list[link_dep_frees++];799link_dep->value = -(int)(i + 1);800link_dep->next = link_dep_list_starts[node_written_at[br]];801link_dep_list_starts[node_written_at[br]] = link_dep;802} else {803link_dep_B[i] = reop_not_dependent;804}805806// Add this link to the initial ready list, if it is not dependent on any other links.807if ((link_dep_A[i] == reop_not_dependent) && (link_dep_B[i] == reop_not_dependent)) {808ready_list[ready_list_tail++] = i;809link_dep_A[i] = link_dep_B[i] = reop_node_complete; // Probably not needed now.810}811812// Update the nodes to mark which ones are calculated by this link.813node_written_at[ar] = node_written_at[br] = i;814}815816// Process the ready list and create the sorted list of links:817// -- By treating the ready list as a queue, we maximize the distance between any818// inter-dependent node calculations.819// -- All other (non-related) nodes in the ready list will automatically be inserted820// in between each set of inter-dependent link calculations by this loop.821i = 0;822while (ready_list_head != ready_list_tail) {823// Use ready list to select the next link to process.824link_num = ready_list[ready_list_head++];825// Copy the next-to-calculate link back into the original link array.826links[i++] = link_buffer[link_num];827828// Free up any link inputs that are dependent on this one.829link_dep = link_dep_list_starts[link_num];830while (link_dep) {831dep_link = link_dep->value;832if (dep_link >= 0) {833link_dep_A[dep_link] = reop_not_dependent;834} else {835dep_link = -dep_link - 1;836link_dep_B[dep_link] = reop_not_dependent;837}838// Add this dependent link calculation to the ready list if *both* inputs are clear.839if ((link_dep_A[dep_link] == reop_not_dependent) && (link_dep_B[dep_link] == reop_not_dependent)) {840ready_list[ready_list_tail++] = dep_link;841link_dep_A[dep_link] = link_dep_B[dep_link] = reop_node_complete; // Probably not needed now.842}843link_dep = link_dep->next;844}845}846847// Delete the temporary buffers.848memdelete_arr(node_written_at);849memdelete_arr(link_dep_A);850memdelete_arr(link_dep_B);851memdelete_arr(ready_list);852memdelete_arr(link_dep_free_list);853memdelete_arr(link_dep_list_starts);854memdelete_arr(link_buffer);855}856857void GodotSoftBody3D::append_link(uint32_t p_node1, uint32_t p_node2) {858if (p_node1 == p_node2) {859return;860}861862Node *node1 = &nodes[p_node1];863Node *node2 = &nodes[p_node2];864865Link link;866link.n[0] = node1;867link.n[1] = node2;868link.rl = (node1->x - node2->x).length();869link.rl *= 1.0 - shrinking_factor;870871links.push_back(link);872}873874void GodotSoftBody3D::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) {875if (p_node1 == p_node2) {876return;877}878if (p_node1 == p_node3) {879return;880}881if (p_node2 == p_node3) {882return;883}884885Node *node1 = &nodes[p_node1];886Node *node2 = &nodes[p_node2];887Node *node3 = &nodes[p_node3];888889Face face;890face.n[0] = node1;891face.n[1] = node2;892face.n[2] = node3;893894face.index = faces.size();895896faces.push_back(face);897}898899void GodotSoftBody3D::set_iteration_count(int p_val) {900iteration_count = p_val;901}902903void GodotSoftBody3D::set_total_mass(real_t p_val) {904ERR_FAIL_COND(p_val < 0.0);905906inv_total_mass = 1.0 / p_val;907real_t mass_factor = total_mass * inv_total_mass;908total_mass = p_val;909910uint32_t node_count = nodes.size();911for (uint32_t node_index = 0; node_index < node_count; ++node_index) {912Node &node = nodes[node_index];913node.im *= mass_factor;914}915916update_constants();917}918919void GodotSoftBody3D::set_collision_margin(real_t p_val) {920collision_margin = p_val;921}922923void GodotSoftBody3D::set_linear_stiffness(real_t p_val) {924linear_stiffness = p_val;925}926927void GodotSoftBody3D::set_shrinking_factor(real_t p_val) {928shrinking_factor = p_val;929}930931void GodotSoftBody3D::set_pressure_coefficient(real_t p_val) {932pressure_coefficient = p_val;933}934935void GodotSoftBody3D::set_damping_coefficient(real_t p_val) {936damping_coefficient = p_val;937}938939void GodotSoftBody3D::set_drag_coefficient(real_t p_val) {940drag_coefficient = p_val;941}942943void GodotSoftBody3D::add_velocity(const Vector3 &p_velocity) {944for (Node &node : nodes) {945if (node.im > 0) {946node.v += p_velocity;947}948}949}950951void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_areas) {952if (nodes.is_empty()) {953return;954}955956int32_t j;957958real_t volume = 0.0;959const Vector3 &org = nodes[0].x;960961// Iterate over faces (try not to iterate elsewhere if possible).962for (const Face &face : faces) {963Vector3 wind_force(0, 0, 0);964965// Compute volume.966volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org));967968// Compute nodal forces from area winds.969if (!p_wind_areas.is_empty()) {970for (const GodotArea3D *area : p_wind_areas) {971wind_force += _compute_area_windforce(area, &face);972}973974for (j = 0; j < 3; j++) {975Node *current_node = face.n[j];976current_node->f += wind_force;977}978}979}980volume /= 6.0;981982// Apply nodal pressure forces.983if (pressure_coefficient > CMP_EPSILON) {984real_t ivolumetp = 1.0 / Math::abs(volume) * pressure_coefficient;985for (Node &node : nodes) {986if (node.im > 0) {987node.f += node.n * (node.area * ivolumetp);988}989}990}991}992993Vector3 GodotSoftBody3D::_compute_area_windforce(const GodotArea3D *p_area, const Face *p_face) {994real_t wfm = p_area->get_wind_force_magnitude();995real_t waf = p_area->get_wind_attenuation_factor();996const Vector3 &wd = p_area->get_wind_direction();997const Vector3 &ws = p_area->get_wind_source();998real_t projection_on_tri_normal = vec3_dot(p_face->normal, wd);999real_t projection_toward_centroid = vec3_dot(p_face->centroid - ws, wd);1000real_t attenuation_over_distance = std::pow(projection_toward_centroid, -waf);1001real_t nodal_force_magnitude = wfm * 0.33333333333 * p_face->ra * projection_on_tri_normal * attenuation_over_distance;1002return nodal_force_magnitude * p_face->normal;1003}10041005void GodotSoftBody3D::predict_motion(real_t p_delta) {1006const real_t inv_delta = 1.0 / p_delta;10071008ERR_FAIL_NULL(get_space());10091010bool gravity_done = false;1011Vector3 gravity;10121013LocalVector<GodotArea3D *> wind_areas;10141015int ac = areas.size();1016if (ac) {1017areas.sort();1018const AreaCMP *aa = &areas[0];1019for (int i = ac - 1; i >= 0; i--) {1020if (!gravity_done) {1021PhysicsServer3D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE);1022if (area_gravity_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) {1023Vector3 area_gravity;1024aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity);1025switch (area_gravity_mode) {1026case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE:1027case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: {1028gravity += area_gravity;1029gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE;1030} break;1031case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE:1032case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: {1033gravity = area_gravity;1034gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE;1035} break;1036default: {1037}1038}1039}1040}10411042if (aa[i].area->get_wind_force_magnitude() > CMP_EPSILON) {1043wind_areas.push_back(aa[i].area);1044}1045}1046}10471048// Add default gravity and damping from space area.1049if (!gravity_done) {1050GodotArea3D *default_area = get_space()->get_default_area();1051ERR_FAIL_NULL(default_area);10521053Vector3 default_gravity;1054default_area->compute_gravity(get_transform().get_origin(), default_gravity);1055gravity += default_gravity;1056}10571058// Apply forces.1059add_velocity(gravity * p_delta);1060if (pressure_coefficient > CMP_EPSILON || !wind_areas.is_empty()) {1061apply_forces(wind_areas);1062}10631064// Avoid soft body from 'exploding' so use some upper threshold of maximum motion1065// that a node can travel per frame.1066const real_t max_displacement = 1000.0;1067real_t clamp_delta_v = max_displacement * inv_delta;10681069// Integrate.1070for (Node &node : nodes) {1071node.q = node.x;1072Vector3 delta_v = node.f * node.im * p_delta;1073for (int c = 0; c < 3; c++) {1074delta_v[c] = CLAMP(delta_v[c], -clamp_delta_v, clamp_delta_v);1075}1076node.v += delta_v;1077node.x += node.v * p_delta;1078node.f = Vector3();1079}10801081// Bounds and tree update.1082update_bounds();10831084// Node tree update.1085for (const Node &node : nodes) {1086AABB node_aabb(node.x, Vector3());1087node_aabb.expand_to(node.x + node.v * p_delta);1088node_aabb.grow_by(collision_margin);10891090node_tree.update(node.leaf, node_aabb);1091}10921093// Face tree update.1094if (!face_tree.is_empty()) {1095update_face_tree(p_delta);1096}10971098// Optimize node tree.1099node_tree.optimize_incremental(1);1100face_tree.optimize_incremental(1);1101}11021103void GodotSoftBody3D::solve_constraints(real_t p_delta) {1104const real_t inv_delta = 1.0 / p_delta;11051106for (Link &link : links) {1107link.c3 = link.n[1]->q - link.n[0]->q;1108link.c2 = 1 / (link.c3.length_squared() * link.c0);1109}11101111// Solve velocities.1112for (Node &node : nodes) {1113node.x = node.q + node.v * p_delta;1114}11151116// Solve positions.1117for (int isolve = 0; isolve < iteration_count; ++isolve) {1118const real_t ti = isolve / (real_t)iteration_count;1119solve_links(1.0, ti);1120}1121const real_t vc = (1.0 - damping_coefficient) * inv_delta;1122for (Node &node : nodes) {1123node.x += node.bv * p_delta;1124node.bv = Vector3();11251126node.v = (node.x - node.q) * vc;11271128node.q = node.x;1129}11301131update_normals_and_centroids();1132}11331134void GodotSoftBody3D::solve_links(real_t kst, real_t ti) {1135for (Link &link : links) {1136if (link.c0 > 0) {1137Node &node_a = *link.n[0];1138Node &node_b = *link.n[1];1139const Vector3 del = node_b.x - node_a.x;1140const real_t len = del.length_squared();1141if (link.c1 + len > CMP_EPSILON) {1142const real_t k = ((link.c1 - len) / (link.c0 * (link.c1 + len))) * kst;1143node_a.x -= del * (k * node_a.im);1144node_b.x += del * (k * node_b.im);1145}1146}1147}1148}11491150struct AABBQueryResult {1151const GodotSoftBody3D *soft_body = nullptr;1152void *userdata = nullptr;1153GodotSoftBody3D::QueryResultCallback result_callback = nullptr;11541155_FORCE_INLINE_ bool operator()(void *p_data) {1156return result_callback(soft_body->get_node_index(p_data), userdata);1157}1158};11591160void GodotSoftBody3D::query_aabb(const AABB &p_aabb, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) {1161AABBQueryResult query_result;1162query_result.soft_body = this;1163query_result.result_callback = p_result_callback;1164query_result.userdata = p_userdata;11651166node_tree.aabb_query(p_aabb, query_result);1167}11681169struct RayQueryResult {1170const GodotSoftBody3D *soft_body = nullptr;1171void *userdata = nullptr;1172GodotSoftBody3D::QueryResultCallback result_callback = nullptr;11731174_FORCE_INLINE_ bool operator()(void *p_data) {1175return result_callback(soft_body->get_face_index(p_data), userdata);1176}1177};11781179void GodotSoftBody3D::query_ray(const Vector3 &p_from, const Vector3 &p_to, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) {1180if (face_tree.is_empty()) {1181initialize_face_tree();1182}11831184RayQueryResult query_result;1185query_result.soft_body = this;1186query_result.result_callback = p_result_callback;1187query_result.userdata = p_userdata;11881189face_tree.ray_query(p_from, p_to, query_result);1190}11911192void GodotSoftBody3D::initialize_face_tree() {1193face_tree.clear();1194for (Face &face : faces) {1195AABB face_aabb;11961197face_aabb.position = face.n[0]->x;1198face_aabb.expand_to(face.n[1]->x);1199face_aabb.expand_to(face.n[2]->x);12001201face_aabb.grow_by(collision_margin);12021203face.leaf = face_tree.insert(face_aabb, &face);1204}1205}12061207void GodotSoftBody3D::update_face_tree(real_t p_delta) {1208for (const Face &face : faces) {1209AABB face_aabb;12101211const Node *node0 = face.n[0];1212face_aabb.position = node0->x;1213face_aabb.expand_to(node0->x + node0->v * p_delta);12141215const Node *node1 = face.n[1];1216face_aabb.expand_to(node1->x);1217face_aabb.expand_to(node1->x + node1->v * p_delta);12181219const Node *node2 = face.n[2];1220face_aabb.expand_to(node2->x);1221face_aabb.expand_to(node2->x + node2->v * p_delta);12221223face_aabb.grow_by(collision_margin);12241225face_tree.update(face.leaf, face_aabb);1226}1227}12281229void GodotSoftBody3D::initialize_shape(bool p_force_move) {1230if (get_shape_count() == 0) {1231GodotSoftBodyShape3D *soft_body_shape = memnew(GodotSoftBodyShape3D(this));1232add_shape(soft_body_shape);1233} else if (p_force_move) {1234GodotSoftBodyShape3D *soft_body_shape = static_cast<GodotSoftBodyShape3D *>(get_shape(0));1235soft_body_shape->update_bounds();1236}1237}12381239void GodotSoftBody3D::deinitialize_shape() {1240if (get_shape_count() > 0) {1241GodotShape3D *shape = get_shape(0);1242remove_shape(shape);1243memdelete(shape);1244}1245}12461247void GodotSoftBody3D::destroy() {1248soft_mesh = RID();12491250map_visual_to_physics.clear();12511252node_tree.clear();1253face_tree.clear();12541255nodes.clear();1256links.clear();1257faces.clear();12581259bounds = AABB();1260deinitialize_shape();1261}12621263void GodotSoftBodyShape3D::update_bounds() {1264ERR_FAIL_NULL(soft_body);12651266AABB collision_aabb = soft_body->get_bounds();1267collision_aabb.grow_by(soft_body->get_collision_margin());1268configure(collision_aabb);1269}12701271GodotSoftBodyShape3D::GodotSoftBodyShape3D(GodotSoftBody3D *p_soft_body) {1272soft_body = p_soft_body;1273update_bounds();1274}12751276struct _SoftBodyIntersectSegmentInfo {1277const GodotSoftBody3D *soft_body = nullptr;1278Vector3 from;1279Vector3 dir;1280Vector3 hit_position;1281uint32_t hit_face_index = -1;1282real_t hit_dist_sq = Math::INF;12831284static bool process_hit(uint32_t p_face_index, void *p_userdata) {1285_SoftBodyIntersectSegmentInfo &query_info = *(static_cast<_SoftBodyIntersectSegmentInfo *>(p_userdata));12861287Vector3 points[3];1288query_info.soft_body->get_face_points(p_face_index, points[0], points[1], points[2]);12891290Vector3 result;1291if (Geometry3D::ray_intersects_triangle(query_info.from, query_info.dir, points[0], points[1], points[2], &result)) {1292real_t dist_sq = query_info.from.distance_squared_to(result);1293if (dist_sq < query_info.hit_dist_sq) {1294query_info.hit_dist_sq = dist_sq;1295query_info.hit_position = result;1296query_info.hit_face_index = p_face_index;1297}1298}12991300// Continue with the query.1301return false;1302}1303};13041305bool GodotSoftBodyShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, int &r_face_index, bool p_hit_back_faces) const {1306_SoftBodyIntersectSegmentInfo query_info;1307query_info.soft_body = soft_body;1308query_info.from = p_begin;1309query_info.dir = (p_end - p_begin).normalized();13101311soft_body->query_ray(p_begin, p_end, _SoftBodyIntersectSegmentInfo::process_hit, &query_info);13121313if (query_info.hit_dist_sq != Math::INF) {1314r_result = query_info.hit_position;1315r_normal = soft_body->get_face_normal(query_info.hit_face_index);1316return true;1317}13181319return false;1320}13211322bool GodotSoftBodyShape3D::intersect_point(const Vector3 &p_point) const {1323return false;1324}13251326Vector3 GodotSoftBodyShape3D::get_closest_point_to(const Vector3 &p_point) const {1327ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies.");1328}132913301331