Path: blob/master/modules/godot_physics_3d/godot_step_3d.cpp
10277 views
/**************************************************************************/1/* godot_step_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_step_3d.h"3132#include "godot_joint_3d.h"3334#include "core/object/worker_thread_pool.h"35#include "core/os/os.h"3637#define BODY_ISLAND_COUNT_RESERVE 12838#define BODY_ISLAND_SIZE_RESERVE 51239#define ISLAND_COUNT_RESERVE 12840#define ISLAND_SIZE_RESERVE 51241#define CONSTRAINT_COUNT_RESERVE 10244243void GodotStep3D::_populate_island(GodotBody3D *p_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island) {44p_body->set_island_step(_step);4546if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) {47// Only rigid bodies are tested for activation.48p_body_island.push_back(p_body);49}5051for (const KeyValue<GodotConstraint3D *, int> &E : p_body->get_constraint_map()) {52GodotConstraint3D *constraint = E.key;53if (constraint->get_island_step() == _step) {54continue; // Already processed.55}56constraint->set_island_step(_step);57p_constraint_island.push_back(constraint);5859all_constraints.push_back(constraint);6061// Find connected rigid bodies.62for (int i = 0; i < constraint->get_body_count(); i++) {63if (i == E.value) {64continue;65}66GodotBody3D *other_body = constraint->get_body_ptr()[i];67if (other_body->get_island_step() == _step) {68continue; // Already processed.69}70if (other_body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {71continue; // Static bodies don't connect islands.72}73_populate_island(other_body, p_body_island, p_constraint_island);74}7576// Find connected soft bodies.77for (int i = 0; i < constraint->get_soft_body_count(); i++) {78GodotSoftBody3D *soft_body = constraint->get_soft_body_ptr(i);79if (soft_body->get_island_step() == _step) {80continue; // Already processed.81}82_populate_island_soft_body(soft_body, p_body_island, p_constraint_island);83}84}85}8687void GodotStep3D::_populate_island_soft_body(GodotSoftBody3D *p_soft_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island) {88p_soft_body->set_island_step(_step);8990for (GodotConstraint3D *E : p_soft_body->get_constraints()) {91GodotConstraint3D *constraint = E;92if (constraint->get_island_step() == _step) {93continue; // Already processed.94}95constraint->set_island_step(_step);96p_constraint_island.push_back(constraint);9798all_constraints.push_back(constraint);99100// Find connected rigid bodies.101for (int i = 0; i < constraint->get_body_count(); i++) {102GodotBody3D *body = constraint->get_body_ptr()[i];103if (body->get_island_step() == _step) {104continue; // Already processed.105}106if (body->get_mode() == PhysicsServer3D::BODY_MODE_STATIC) {107continue; // Static bodies don't connect islands.108}109_populate_island(body, p_body_island, p_constraint_island);110}111}112}113114void GodotStep3D::_setup_constraint(uint32_t p_constraint_index, void *p_userdata) {115GodotConstraint3D *constraint = all_constraints[p_constraint_index];116constraint->setup(delta);117}118119void GodotStep3D::_pre_solve_island(LocalVector<GodotConstraint3D *> &p_constraint_island) const {120uint32_t constraint_count = p_constraint_island.size();121uint32_t valid_constraint_count = 0;122for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {123GodotConstraint3D *constraint = p_constraint_island[constraint_index];124if (p_constraint_island[constraint_index]->pre_solve(delta)) {125// Keep this constraint for solving.126p_constraint_island[valid_constraint_count++] = constraint;127}128}129p_constraint_island.resize(valid_constraint_count);130}131132void GodotStep3D::_solve_island(uint32_t p_island_index, void *p_userdata) {133LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[p_island_index];134135int current_priority = 1;136137uint32_t constraint_count = constraint_island.size();138while (constraint_count > 0) {139for (int i = 0; i < iterations; i++) {140// Go through all iterations.141for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {142constraint_island[constraint_index]->solve(delta);143}144}145146// Check priority to keep only higher priority constraints.147uint32_t priority_constraint_count = 0;148++current_priority;149for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) {150GodotConstraint3D *constraint = constraint_island[constraint_index];151if (constraint->get_priority() >= current_priority) {152// Keep this constraint for the next iteration.153constraint_island[priority_constraint_count++] = constraint;154}155}156constraint_count = priority_constraint_count;157}158}159160void GodotStep3D::_check_suspend(const LocalVector<GodotBody3D *> &p_body_island) const {161bool can_sleep = true;162163uint32_t body_count = p_body_island.size();164for (uint32_t body_index = 0; body_index < body_count; ++body_index) {165GodotBody3D *body = p_body_island[body_index];166167if (!body->sleep_test(delta)) {168can_sleep = false;169}170}171172// Put all to sleep or wake up everyone.173for (uint32_t body_index = 0; body_index < body_count; ++body_index) {174GodotBody3D *body = p_body_island[body_index];175176bool active = body->is_active();177178if (active == can_sleep) {179body->set_active(!can_sleep);180}181}182}183184void GodotStep3D::step(GodotSpace3D *p_space, real_t p_delta) {185p_space->lock(); // can't access space during this186187p_space->setup(); //update inertias, etc188189p_space->set_last_step(p_delta);190191iterations = p_space->get_solver_iterations();192delta = p_delta;193194const SelfList<GodotBody3D>::List *body_list = &p_space->get_active_body_list();195196const SelfList<GodotSoftBody3D>::List *soft_body_list = &p_space->get_active_soft_body_list();197198/* INTEGRATE FORCES */199200uint64_t profile_begtime = OS::get_singleton()->get_ticks_usec();201uint64_t profile_endtime = 0;202203int active_count = 0;204205const SelfList<GodotBody3D> *b = body_list->first();206while (b) {207b->self()->integrate_forces(p_delta);208b = b->next();209active_count++;210}211212/* UPDATE SOFT BODY MOTION */213214const SelfList<GodotSoftBody3D> *sb = soft_body_list->first();215while (sb) {216sb->self()->predict_motion(p_delta);217sb = sb->next();218active_count++;219}220221p_space->set_active_objects(active_count);222223// Update the broadphase to register collision pairs.224p_space->update();225226{ //profile227profile_endtime = OS::get_singleton()->get_ticks_usec();228p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime);229profile_begtime = profile_endtime;230}231232/* GENERATE CONSTRAINT ISLANDS FOR MOVING AREAS */233234uint32_t island_count = 0;235236const SelfList<GodotArea3D>::List &aml = p_space->get_moved_area_list();237238while (aml.first()) {239for (GodotConstraint3D *E : aml.first()->self()->get_constraints()) {240GodotConstraint3D *constraint = E;241if (constraint->get_island_step() == _step) {242continue;243}244constraint->set_island_step(_step);245246// Each constraint can be on a separate island for areas as there's no solving phase.247++island_count;248if (constraint_islands.size() < island_count) {249constraint_islands.resize(island_count);250}251LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1];252constraint_island.clear();253254all_constraints.push_back(constraint);255constraint_island.push_back(constraint);256}257p_space->area_remove_from_moved_list((SelfList<GodotArea3D> *)aml.first()); //faster to remove here258}259260/* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */261262b = body_list->first();263264uint32_t body_island_count = 0;265266while (b) {267GodotBody3D *body = b->self();268269if (body->get_island_step() != _step) {270++body_island_count;271if (body_islands.size() < body_island_count) {272body_islands.resize(body_island_count);273}274LocalVector<GodotBody3D *> &body_island = body_islands[body_island_count - 1];275body_island.clear();276body_island.reserve(BODY_ISLAND_SIZE_RESERVE);277278++island_count;279if (constraint_islands.size() < island_count) {280constraint_islands.resize(island_count);281}282LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1];283constraint_island.clear();284constraint_island.reserve(ISLAND_SIZE_RESERVE);285286_populate_island(body, body_island, constraint_island);287288if (body_island.is_empty()) {289--body_island_count;290}291292if (constraint_island.is_empty()) {293--island_count;294}295}296b = b->next();297}298299/* GENERATE CONSTRAINT ISLANDS FOR ACTIVE SOFT BODIES */300301sb = soft_body_list->first();302while (sb) {303GodotSoftBody3D *soft_body = sb->self();304305if (soft_body->get_island_step() != _step) {306++body_island_count;307if (body_islands.size() < body_island_count) {308body_islands.resize(body_island_count);309}310LocalVector<GodotBody3D *> &body_island = body_islands[body_island_count - 1];311body_island.clear();312body_island.reserve(BODY_ISLAND_SIZE_RESERVE);313314++island_count;315if (constraint_islands.size() < island_count) {316constraint_islands.resize(island_count);317}318LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1];319constraint_island.clear();320constraint_island.reserve(ISLAND_SIZE_RESERVE);321322_populate_island_soft_body(soft_body, body_island, constraint_island);323324if (body_island.is_empty()) {325--body_island_count;326}327328if (constraint_island.is_empty()) {329--island_count;330}331}332sb = sb->next();333}334335p_space->set_island_count((int)island_count);336337{ //profile338profile_endtime = OS::get_singleton()->get_ticks_usec();339p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime);340profile_begtime = profile_endtime;341}342343/* SETUP CONSTRAINTS / PROCESS COLLISIONS */344345uint32_t total_constraint_count = all_constraints.size();346WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep3D::_setup_constraint, nullptr, total_constraint_count, -1, true, SNAME("Physics3DConstraintSetup"));347WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);348349{ //profile350profile_endtime = OS::get_singleton()->get_ticks_usec();351p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime);352profile_begtime = profile_endtime;353}354355/* PRE-SOLVE CONSTRAINT ISLANDS */356357// WARNING: This doesn't run on threads, because it involves thread-unsafe processing.358for (uint32_t island_index = 0; island_index < island_count; ++island_index) {359_pre_solve_island(constraint_islands[island_index]);360}361362/* SOLVE CONSTRAINT ISLANDS */363364// WARNING: `_solve_island` modifies the constraint islands for optimization purpose,365// their content is not reliable after these calls and shouldn't be used anymore.366group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &GodotStep3D::_solve_island, nullptr, island_count, -1, true, SNAME("Physics3DConstraintSolveIslands"));367WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);368369{ //profile370profile_endtime = OS::get_singleton()->get_ticks_usec();371p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime);372profile_begtime = profile_endtime;373}374375/* INTEGRATE VELOCITIES */376377b = body_list->first();378while (b) {379const SelfList<GodotBody3D> *n = b->next();380b->self()->integrate_velocities(p_delta);381b = n;382}383384/* SLEEP / WAKE UP ISLANDS */385386for (uint32_t island_index = 0; island_index < body_island_count; ++island_index) {387_check_suspend(body_islands[island_index]);388}389390/* UPDATE SOFT BODY CONSTRAINTS */391392sb = soft_body_list->first();393while (sb) {394sb->self()->solve_constraints(p_delta);395sb = sb->next();396}397398{ //profile399profile_endtime = OS::get_singleton()->get_ticks_usec();400p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime);401profile_begtime = profile_endtime;402}403404all_constraints.clear();405406p_space->unlock();407_step++;408}409410GodotStep3D::GodotStep3D() {411body_islands.reserve(BODY_ISLAND_COUNT_RESERVE);412constraint_islands.reserve(ISLAND_COUNT_RESERVE);413all_constraints.reserve(CONSTRAINT_COUNT_RESERVE);414}415416GodotStep3D::~GodotStep3D() {417}418419420