6#include <math/transform.hpp>
20#define BT_USE_SSE_IN_API
21#include <BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h>
22#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
23#include <BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h>
24#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h>
26#include <btBulletCollisionCommon.h>
27#include <btBulletDynamicsCommon.h>
28#include <BulletDynamics/Character/btKinematicCharacterController.h>
29#include <BulletCollision/CollisionDispatch/btGhostObject.h>
31#include <hpp/flat_map.hpp>
43#include "LinearMath/btThreads.h"
52 bool operator<(contact_key
const& o)
const
54 return a < o.a || (
a == o.a &&
b < o.b);
56 bool operator==(contact_key
const& o)
const
58 return a == o.a &&
b == o.b;
65struct hash<contact_key>
70 return (uint64_t)k.a.entity() * 0x9e3779b97f4a7c15ULL ^ ((uint64_t)k.b.entity() << 1);
79bool enable_logging =
false;
81enum class manifold_type
94struct contact_manifold
104const btVector3 gravity_sun(btScalar(0), btScalar(-274), btScalar(0));
105const btVector3 gravity_mercury(btScalar(0), btScalar(-3.7), btScalar(0));
106const btVector3 gravity_venus(btScalar(0), btScalar(-8.87), btScalar(0));
107const btVector3 gravity_earth(btScalar(0), btScalar(-9.8), btScalar(0));
108const btVector3 gravity_mars(btScalar(0), btScalar(-3.72), btScalar(0));
109const btVector3 gravity_jupiter(btScalar(0), btScalar(-24.79), btScalar(0));
110const btVector3 gravity_saturn(btScalar(0), btScalar(-10.44), btScalar(0));
111const btVector3 gravity_uranus(btScalar(0), btScalar(-8.69), btScalar(0));
112const btVector3 gravity_neptune(btScalar(0), btScalar(-11.15), btScalar(0));
113const btVector3 gravity_pluto(btScalar(0), btScalar(-0.62), btScalar(0));
114const btVector3 gravity_moon(btScalar(0), btScalar(-1.625), btScalar(0));
116auto to_bullet(
const math::vec3&
v) -> btVector3
118 return {
v.x,
v.y,
v.z};
121auto from_bullet(
const btVector3&
v) -> math::vec3
123 return {
v.getX(),
v.getY(),
v.getZ()};
126auto to_bullet(
const math::quat& q) -> btQuaternion
128 return {
q.x,
q.y,
q.z,
q.w};
131auto from_bullet(
const btQuaternion& q) -> math::quat
141auto to_bx(
const btVector3& data) -> bx::Vec3
143 return {data.getX(), data.getY(), data.getZ()};
146auto to_bx_color(
const btVector3& in) -> uint32_t
148#define COL32_R_SHIFT 0
149#define COL32_G_SHIFT 8
150#define COL32_B_SHIFT 16
151#define COL32_A_SHIFT 24
152#define COL32_A_MASK 0xFF000000
161class debugdraw :
public btIDebugDraw
163 int debug_mode_ = btIDebugDraw::DBG_DrawContactPoints;
164 DefaultColors our_colors_;
166 std::unique_ptr<DebugDrawEncoderScopePush> scope_;
177 scope_ = std::make_unique<DebugDrawEncoderScopePush>(dd_.
encoder);
181 auto getDefaultColors() const -> DefaultColors
override
187 void setDefaultColors(
const DefaultColors& colors)
override
189 our_colors_ = colors;
192 void drawLine(
const btVector3& from1,
const btVector3& to1,
const btVector3& color1)
override
201 void drawContactPoint(
const btVector3& point_on_b,
202 const btVector3& normal_on_b,
205 const btVector3&
color)
override
207 drawLine(point_on_b, point_on_b + normal_on_b * distance,
color);
208 btVector3 ncolor(0, 0, 0);
209 drawLine(point_on_b, point_on_b + normal_on_b * 0.1, ncolor);
212 void setDebugMode(
int debugMode)
override
214 debug_mode_ = debugMode;
217 auto getDebugMode() const ->
int override
222 void flushLines()
override
227 void reportErrorWarning(
const char* warningString)
override
231 void draw3dText(
const btVector3& location,
const char* textString)
override
236static constexpr int COMBINE_BITS = 2;
237static constexpr int COMBINE_MASK = (1 << COMBINE_BITS) - 1;
238static constexpr int FRICTION_SHIFT = COMBINE_BITS;
239static constexpr int RESTITUTION_SHIFT = 0;
243 int f = (
static_cast<int>(friction) & COMBINE_MASK) << FRICTION_SHIFT;
244 int b = (
static_cast<int>(bounce) & COMBINE_MASK) << RESTITUTION_SHIFT;
279static btScalar per_body_combine(
const btCollisionObject* body0,
280 const btCollisionObject* body1,
287 auto mode = pick_combine_mode(mode0, mode1);
298 combined = (e0 + e1) * btScalar(0.5);
302 combined = btMin(e0, e1);
306 combined = btMax(e0, e1);
322static btScalar combined_restitution_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
324 int raw_mode0 = body0->getUserIndex2();
325 int raw_mode1 = body1->getUserIndex2();
326 auto mode0 = decode_restitution_combine(raw_mode0);
327 auto mode1 = decode_restitution_combine(raw_mode1);
329 return per_body_combine(body0, body1, body0->getRestitution(), body1->getRestitution(), mode0, mode1);
332static btScalar combined_friction_callback(
const btCollisionObject* body0,
333 const btCollisionObject* body1,
337 int raw_mode0 = body0->getUserIndex2();
338 int raw_mode1 = body1->getUserIndex2();
339 auto mode0 = decode_restitution_combine(raw_mode0);
340 auto mode1 = decode_restitution_combine(raw_mode1);
342 auto friction = per_body_combine(body0, body1, f0, f1, mode0, mode1);
343 const btScalar MAX_FRICTION = btScalar(10.);
344 if(friction < -MAX_FRICTION)
345 friction = -MAX_FRICTION;
346 if(friction > MAX_FRICTION)
347 friction = MAX_FRICTION;
351static btScalar combined_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
353 auto f0 = body0->getFriction();
354 auto f1 = body1->getFriction();
355 return combined_friction_callback(body0, body1, f0, f1);
358static btScalar combined_rolling_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
360 auto f0 = body0->getFriction() * body0->getRollingFriction();
361 auto f1 = body1->getFriction() * body1->getRollingFriction();
362 return combined_friction_callback(body0, body1, f0, f1);
365static btScalar combined_spinning_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
367 auto f0 = body0->getFriction() * body0->getSpinningFriction();
368 auto f1 = body1->getFriction() * body1->getSpinningFriction();
369 return combined_friction_callback(body0, body1, f0, f1);
372void override_combine_callbacks()
375 gCalculateCombinedRestitutionCallback = combined_restitution_callback;
378 gCalculateCombinedFrictionCallback = combined_friction_callback;
379 gCalculateCombinedRollingFrictionCallback = combined_rolling_friction_callback;
380 gCalculateCombinedSpinningFrictionCallback = combined_spinning_friction_callback;
383void setup_task_scheduler()
387 btITaskScheduler* scheduler = btGetTaskScheduler();
389 scheduler = btCreateDefaultTaskScheduler();
392 scheduler = btGetSequentialTaskScheduler();
397 btSetTaskScheduler(scheduler);
402void cleanup_task_scheduler()
406 btITaskScheduler* scheduler = btGetTaskScheduler();
409 btSetTaskScheduler(
nullptr);
418 auto id =
static_cast<entt::entity
>(
index);
420 return ec.get_scene().create_handle(
id);
423auto get_entity_id_from_user_index(
int index) -> entt::entity
427 auto id =
static_cast<entt::entity
>(
index);
432auto has_scripting(entt::handle
a) ->
bool
440 return a_has_scripting;
443auto should_record_collision_event(entt::handle
a, entt::handle
b) ->
bool
457auto should_record_sensor_event(entt::handle
a, entt::handle
b) ->
bool
467template<
typename Callback>
468class filter_ray_callback :
public Callback
474 filter_ray_callback(
const btVector3& from,
const btVector3& to,
int mask,
bool sensors)
482 auto needsCollision(btBroadphaseProxy* proxy0)
const ->
bool override
484 if(!Callback::needsCollision(proxy0))
490 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
495 const auto* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
497 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
507using filter_closest_ray_callback = filter_ray_callback<btCollisionWorld::ClosestRayResultCallback>;
508using filter_all_hits_ray_callback = filter_ray_callback<btCollisionWorld::AllHitsRayResultCallback>;
511class sphere_closest_convex_result_callback :
public btCollisionWorld::ClosestConvexResultCallback
517 sphere_closest_convex_result_callback(
const btVector3& from,
const btVector3& to,
int layerMask,
bool sensors)
518 : btCollisionWorld::ClosestConvexResultCallback(from, to)
525 bool needsCollision(btBroadphaseProxy* proxy0)
const override
528 if(!btCollisionWorld::ClosestConvexResultCallback::needsCollision(proxy0))
531 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
537 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
540 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
550class sphere_all_convex_result_callback :
public btCollisionWorld::ConvexResultCallback
558 const btCollisionObject*
object =
nullptr;
566 m_closestHitFraction = btScalar(1.f);
570 btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,
bool normalInWorldSpace)
override
574 hi.object = convexResult.m_hitCollisionObject;
575 hi.fraction = convexResult.m_hitFraction;
577 if(normalInWorldSpace)
578 hi.normal = convexResult.m_hitNormalLocal;
583 convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal;
589 return m_closestHitFraction;
592 bool needsCollision(btBroadphaseProxy* proxy0)
const override
594 if(!ConvexResultCallback::needsCollision(proxy0))
598 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
603 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
605 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
614struct sphere_overlap_callback : btCollisionWorld::ContactResultCallback
616 btCollisionObject*
me{};
623 sphere_overlap_callback(btCollisionObject* obj,
int layerMask,
bool sensors)
628 m_closestDistanceThreshold = btScalar(1.f);
631 bool needsCollision(btBroadphaseProxy* proxy0)
const override
633 if(!btCollisionWorld::ContactResultCallback::needsCollision(proxy0))
637 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
642 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
644 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
652 btScalar addSingleResult(btManifoldPoint&,
653 const btCollisionObjectWrapper* w0,
656 const btCollisionObjectWrapper* w1,
660 const btCollisionObject* other =
661 (w0->getCollisionObject() == me ? w1->getCollisionObject() : w0->getCollisionObject());
662 hits.push_back(
const_cast<btCollisionObject*
>(other));
675struct character_controller
677 std::shared_ptr<btPairCachingGhostObject>
ghost{};
678 std::shared_ptr<btCapsuleShape>
shape{};
679 std::shared_ptr<btKinematicCharacterController>
controller{};
688 std::shared_ptr<btConstraintSolver>
solver;
693 struct contact_record
698 cm.contacts.reserve(4);
711 void add_rigidbody(
const rigidbody& body)
713 if(body.internal->isInWorld())
718 btAssert(in_simulate ==
false);
720 dynamics_world->addRigidBody(body.internal.get(), body.collision_filter_group, body.collision_filter_mask);
723 void remove_rigidbody(
const rigidbody& body)
725 if(!body.internal->isInWorld())
729 btAssert(in_simulate ==
false);
733 void add_character_controller(
const character_controller& cc)
735 btAssert(in_simulate ==
false);
737 cc.collision_filter_group,
738 cc.collision_filter_mask);
742 void remove_character_controller(
const character_controller& cc)
744 btAssert(in_simulate ==
false);
751 switch(manifold.type)
753 case manifold_type::sensor:
755 if(manifold.event == event_type::enter)
761 scripting.
on_sensor_exit(manifold.a, manifold.b, manifold.contacts);
767 case manifold_type::collision:
769 if(manifold.event == event_type::enter)
787 void process_manifolds()
798 for(
auto& kv : contacts_cache)
799 kv.second.active_this_frame =
false;
807 for(
int i = 0;
i < nm; ++
i)
809 auto*
m =
dispatcher->getManifoldByIndexInternal(i);
810 if(
m->getNumContacts() == 0)
814 auto* objA =
m->getBody0();
815 auto* objB =
m->getBody1();
816 bool isSensorA = objA->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE;
817 bool isSensorB = objB->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE;
818 auto eA = get_entity_from_user_index(ec, objA->getUserIndex());
819 auto eB = get_entity_from_user_index(ec, objB->getUserIndex());
822 if(isSensorA || isSensorB)
827 contact_key
key{eA, eB};
831 it->second.active_this_frame =
true;
836 cm.type = manifold_type::sensor;
837 cm.event = event_type::enter;
840 cm.contacts.reserve(
m->getNumContacts());
841 for(
int j = 0;
j <
m->getNumContacts(); ++
j)
843 auto const&
p =
m->getContactPoint(j);
845 mp.
a = from_bullet(
p.getPositionWorldOnA());
846 mp.
b = from_bullet(
p.getPositionWorldOnB());
851 cm.contacts.push_back(mp);
854 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
856 rec.active_this_frame =
true;
862 contact_key
key{eB, eA};
866 it->second.active_this_frame =
true;
871 cm.type = manifold_type::sensor;
872 cm.event = event_type::enter;
875 cm.contacts.reserve(
m->getNumContacts());
876 for(
int j = 0;
j <
m->getNumContacts(); ++
j)
878 auto const&
p =
m->getContactPoint(j);
880 mp.
a = from_bullet(
p.getPositionWorldOnB());
881 mp.
b = from_bullet(
p.getPositionWorldOnA());
886 cm.contacts.push_back(mp);
889 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
891 rec.active_this_frame =
true;
898 contact_key
key{eA, eB};
903 it->second.active_this_frame =
true;
909 cm.type = manifold_type::collision;
910 cm.event = event_type::enter;
913 cm.contacts.reserve(
m->getNumContacts());
914 for(
int j = 0;
j <
m->getNumContacts(); ++
j)
916 auto const&
p =
m->getContactPoint(j);
918 mp.
a = from_bullet(
p.getPositionWorldOnA());
919 mp.
b = from_bullet(
p.getPositionWorldOnB());
924 cm.contacts.push_back(mp);
927 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
929 rec.active_this_frame =
true;
936 if(!it->second.active_this_frame)
938 auto cm = it->second.cm;
939 cm.event = event_type::exit;
950 for(
auto&
cm : to_enter)
952 process_manifold(scripting,
cm);
954 for(
auto&
cm : to_exit)
956 process_manifold(scripting,
cm);
960 void simulate(btScalar dt, btScalar fixed_time_step = 1.0 / 60.0,
int max_subs_steps = 10)
965 dynamics_world->stepSimulation(dt, max_subs_steps, fixed_time_step);
970 auto ray_cast_closest(
const math::vec3& origin,
971 const math::vec3& direction,
981 auto ray_origin = to_bullet(origin);
982 auto ray_end = to_bullet(origin + direction * max_distance);
986 ray_callback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
988 if(ray_callback.hasHit())
990 const btRigidBody* body = btRigidBody::upcast(ray_callback.m_collisionObject);
994 hit.
entity = get_entity_id_from_user_index(body->getUserIndex());
995 hit.point = from_bullet(ray_callback.m_hitPointWorld);
996 hit.normal = from_bullet(ray_callback.m_hitNormalWorld);
997 hit.distance = math::distance(origin,
hit.point);
1005 auto ray_cast_all(
const math::vec3& origin,
1006 const math::vec3& direction,
1016 auto ray_origin = to_bullet(origin);
1017 auto ray_end = to_bullet(origin + direction * max_distance);
1021 ray_callback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
1024 if(!ray_callback.hasHit())
1032 hits.reserve(ray_callback.m_hitPointWorld.size());
1033 for(
int i = 0;
i < ray_callback.m_hitPointWorld.size(); ++
i)
1035 const btCollisionObject* collision_object = ray_callback.m_collisionObjects[
i];
1036 const btRigidBody* body = btRigidBody::upcast(collision_object);
1040 auto&
hit =
hits.emplace_back();
1042 hit.entity = get_entity_id_from_user_index(body->getUserIndex());
1043 hit.point = from_bullet(ray_callback.m_hitPointWorld[i]);
1044 hit.normal = from_bullet(ray_callback.m_hitNormalWorld[i]);
1045 hit.distance = math::distance(origin,
hit.point);
1052 auto sphere_cast_closest(
const math::vec3& origin,
1053 const math::vec3& direction,
1065 btVector3 btOrigin = to_bullet(origin);
1066 btVector3 btEnd = to_bullet(origin + direction * max_distance);
1070 btSphereShape
shape(radius);
1075 start.setIdentity();
1077 start.setOrigin(btOrigin);
1078 end.setOrigin(btEnd);
1093 const btCollisionObject* obj = cb.m_hitCollisionObject;
1095 float fraction = cb.m_closestHitFraction;
1096 btVector3 hitPoint = btOrigin.lerp(btEnd,
fraction);
1097 btVector3
normal = cb.m_hitNormalWorld;
1100 const btRigidBody* body = btRigidBody::upcast(obj);
1104 hit.entity = get_entity_id_from_user_index(body->getUserIndex());
1109 hit.entity = entt::null;
1112 hit.point = from_bullet(hitPoint);
1113 hit.normal = from_bullet(
normal.normalized());
1119 auto sphere_cast_all(
const math::vec3& origin,
1120 const math::vec3& direction,
1131 btVector3 btOrigin = to_bullet(origin);
1132 btVector3 btEnd = to_bullet(origin + direction * max_distance);
1135 start.setIdentity();
1137 start.setOrigin(btOrigin);
1138 end.setOrigin(btEnd);
1141 btSphereShape
shape(radius);
1150 std::sort(cb.hits.begin(),
1152 [](
auto&
a,
auto&
b)
1154 return a.fraction < b.fraction;
1159 hits.reserve(cb.hits.size());
1161 for(
const auto& hi : cb.hits)
1163 auto&
hit =
hits.emplace_back();
1165 const btRigidBody* body = btRigidBody::upcast(hi.object);
1168 hit.entity = get_entity_id_from_user_index(body->getUserIndex());
1172 hit.entity = entt::null;
1175 btVector3 hitPoint = btOrigin.lerp(btEnd, hi.fraction);
1176 hit.point = from_bullet(hitPoint);
1177 hit.normal = from_bullet(hi.normal.normalized());
1178 hit.distance = hi.fraction * max_distance;
1187 btSphereShape
sphere(radius);
1188 btCollisionObject tempObj;
1189 tempObj.setCollisionShape(&sphere);
1190 tempObj.setWorldTransform(btTransform(btQuaternion::getIdentity(), to_bullet(origin)));
1197 hits.reserve(cb.hits.size());
1199 for(
const auto& hi : cb.hits)
1201 auto&
hit =
hits.emplace_back();
1203 const btRigidBody* body = btRigidBody::upcast(hi);
1206 hit = get_entity_id_from_user_index(body->getUserIndex());
1218auto get_world_from_user_pointer(
void* pointer) ->
world&
1220 auto world =
reinterpret_cast<bullet::world*
>(pointer);
1224auto create_dynamics_world() -> bullet::world
1226 bullet::world
world{};
1228 auto collision_config = std::make_shared<btDefaultCollisionConfiguration>();
1231 auto broadphase = std::make_shared<btDbvtBroadphase>();
1235 auto solver_pool = std::make_shared<btConstraintSolverPoolMt>(std::thread::hardware_concurrency() - 1);
1236 auto solver = std::make_shared<btSequentialImpulseConstraintSolverMt>();
1237 world.dynamics_world = std::make_shared<btDiscreteDynamicsWorldMt>(
dispatcher.get(),
1246 auto solver = std::make_shared<btSequentialImpulseConstraintSolver>();
1247 world.dynamics_world = std::make_shared<btDiscreteDynamicsWorld>(
dispatcher.get(),
1256 world.dynamics_world->setGravity(gravity_earth);
1257 world.dynamics_world->setForceUpdateAllAabbs(
false);
1258 world.dynamics_world->getPairCache()->setInternalGhostPairCallback(
new btGhostPairCallback());
1262ATTRIBUTE_ALIGNED16(
class)
1263btCompoundShapeOwning : public btCompoundShape
1266 BT_DECLARE_ALIGNED_ALLOCATOR();
1268 ~btCompoundShapeOwning()
override
1271 for(
int i = 0;
i < m_children.size();
i++)
1273 delete m_children[
i].m_childShape;
1287void wake_up(bullet::rigidbody& body)
1291 body.internal->activate(
true);
1299auto create_bullet_mesh_shapes(
const physics_mesh_shape&
shape)
1300 -> std::vector<std::pair<btCollisionShape*, btTransform>>
1302 std::vector<std::pair<btCollisionShape*, btTransform>> result;
1303 const auto& mesh_ref =
shape.mesh_asset.get();
1306 auto* vertex_data = mesh_ref->get_system_vb();
1307 auto* index_data = mesh_ref->get_system_ib();
1308 auto vertex_count = mesh_ref->get_vertex_count();
1309 auto face_count = mesh_ref->get_face_count();
1310 const auto& vertex_format = mesh_ref->get_vertex_format();
1312 if(!vertex_data || !index_data || vertex_count == 0 || face_count == 0)
1318 auto position_offset = vertex_format.getOffset(bgfx::Attrib::Position);
1320 if(position_offset == UINT16_MAX)
1325 const auto& submeshes = mesh_ref->get_submeshes();
1326 const auto node_transforms = mesh_ref->get_submesh_node_transforms();
1327 result.reserve(submeshes.size());
1329 for(
size_t s = 0;
s < submeshes.size(); ++
s)
1331 const auto* submesh = submeshes[
s];
1332 if(!submesh || submesh->face_start < 0 || submesh->face_count == 0)
1336 const auto face_begin =
static_cast<uint32_t
>(submesh->face_start);
1337 if(face_begin >= face_count)
1343 auto* triangle_mesh =
new btTriangleMesh(
true,
false);
1344 const auto face_end = std::min(face_begin + submesh->face_count, face_count);
1345 for(uint32_t f = face_begin;
f < face_end; ++
f)
1347 uint32_t i0 = index_data[
f * 3 + 0];
1348 uint32_t i1 = index_data[
f * 3 + 1];
1349 uint32_t i2 = index_data[
f * 3 + 2];
1358 btVector3 vertex0(v0[0], v0[1], v0[2]);
1359 btVector3 vertex1(v1[0], v1[1], v1[2]);
1360 btVector3 vertex2(v2[0], v2[1], v2[2]);
1361 triangle_mesh->addTriangle(vertex0, vertex1, vertex2);
1365 btCollisionShape* collision_shape =
nullptr;
1369 collision_shape =
new btConvexTriangleMeshShape(triangle_mesh);
1374 collision_shape =
new btBvhTriangleMeshShape(triangle_mesh,
true);
1379 btTransform child_transform = btTransform::getIdentity();
1380 if(s < node_transforms.size())
1382 const auto& node_transform = node_transforms[
s];
1383 child_transform.setRotation(bullet::to_bullet(node_transform.get_rotation()));
1384 child_transform.setOrigin(bullet::to_bullet(node_transform.get_position()));
1385 collision_shape->setLocalScaling(bullet::to_bullet(node_transform.get_scale()));
1388 result.emplace_back(collision_shape, child_transform);
1394auto make_rigidbody_shape(physics_component& comp) -> std::shared_ptr<btCompoundShape>
1397 auto cp = std::make_shared<bullet::btCompoundShapeOwning>();
1399 auto compound_shapes = comp.get_shapes();
1400 if(compound_shapes.empty())
1405 for(
const auto& s : compound_shapes)
1407 if(hpp::holds_alternative<physics_box_shape>(
s.shape))
1409 const auto&
shape = hpp::get<physics_box_shape>(
s.shape);
1410 auto half_extends =
shape.extends * 0.5f;
1412 btBoxShape* box_shape =
new btBoxShape({half_extends.x, half_extends.y, half_extends.z});
1414 btTransform local_transform = btTransform::getIdentity();
1415 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1416 cp->addChildShape(local_transform, box_shape);
1418 else if(hpp::holds_alternative<physics_sphere_shape>(
s.shape))
1420 const auto&
shape = hpp::get<physics_sphere_shape>(
s.shape);
1422 btSphereShape* sphere_shape =
new btSphereShape(
shape.radius);
1424 btTransform local_transform = btTransform::getIdentity();
1425 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1426 cp->addChildShape(local_transform, sphere_shape);
1428 else if(hpp::holds_alternative<physics_capsule_shape>(
s.shape))
1430 const auto&
shape = hpp::get<physics_capsule_shape>(
s.shape);
1432 btCapsuleShape* capsule_shape =
new btCapsuleShape(
shape.radius,
shape.length);
1434 btTransform local_transform = btTransform::getIdentity();
1435 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1436 cp->addChildShape(local_transform, capsule_shape);
1438 else if(hpp::holds_alternative<physics_cylinder_shape>(
s.shape))
1440 const auto&
shape = hpp::get<physics_cylinder_shape>(
s.shape);
1442 btVector3 half_extends(
shape.radius,
shape.length * 0.5f,
shape.radius);
1443 btCylinderShape* cylinder_shape =
new btCylinderShape(half_extends);
1445 btTransform local_transform = btTransform::getIdentity();
1446 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1447 cp->addChildShape(local_transform, cylinder_shape);
1449 else if(hpp::holds_alternative<physics_mesh_shape>(
s.shape))
1451 const auto&
shape = hpp::get<physics_mesh_shape>(
s.shape);
1454 if(
shape.mesh_asset &&
shape.mesh_asset.is_ready())
1457 auto mesh_shapes = create_bullet_mesh_shapes(
shape);
1458 for(
auto& [mesh_shape, node_transform] : mesh_shapes)
1465 btTransform local_transform = node_transform;
1466 local_transform.setOrigin(local_transform.getOrigin() + bullet::to_bullet(
shape.center));
1467 cp->addChildShape(local_transform, mesh_shape);
1476void update_rigidbody_shape(bullet::rigidbody& body, physics_component& comp)
1478 auto shape = make_rigidbody_shape(comp);
1480 body.internal->setCollisionShape(
shape.get());
1481 body.internal_shape =
shape;
1484void update_rigidbody_shape_scale(bullet::world& world, bullet::rigidbody& body,
const math::vec3& s)
1486 auto bt_scale = body.internal_shape->getLocalScaling();
1487 auto scale = bullet::from_bullet(bt_scale);
1489 if(math::any(math::epsilonNotEqual(
scale, s, math::epsilon<float>())))
1491 bt_scale = bullet::to_bullet(s);
1492 body.internal_shape->setLocalScaling(bt_scale);
1493 world.dynamics_world->updateSingleAabb(body.internal.get());
1498void update_rigidbody_kind(bullet::rigidbody& body, physics_component& comp)
1501 auto flags = body.internal->getCollisionFlags();
1502 auto rbFlags = body.internal->getFlags();
1504 if(comp.is_kinematic())
1507 flags |= btCollisionObject::CF_KINEMATIC_OBJECT;
1508 flags &= ~btCollisionObject::CF_DYNAMIC_OBJECT;
1510 body.internal->setCollisionFlags(flags);
1515 flags &= ~btCollisionObject::CF_KINEMATIC_OBJECT;
1516 flags |= btCollisionObject::CF_DYNAMIC_OBJECT;
1517 body.internal->setCollisionFlags(flags);
1521void update_rigidbody_constraints(bullet::rigidbody& body, physics_component& comp)
1524 auto freeze_position = comp.get_freeze_position();
1525 btVector3 linear_factor(
float(!freeze_position.x),
float(!freeze_position.y),
float(!freeze_position.z));
1526 body.internal->setLinearFactor(linear_factor);
1529 auto velocity = body.internal->getLinearVelocity();
1531 body.internal->setLinearVelocity(
velocity);
1534 auto freeze_rotation = comp.get_freeze_rotation();
1535 btVector3 angular_factor(
float(!freeze_rotation.x),
float(!freeze_rotation.y),
float(!freeze_rotation.z));
1536 body.internal->setAngularFactor(angular_factor);
1547void update_rigidbody_velocity(bullet::rigidbody& body, physics_component& comp)
1549 body.internal->setLinearVelocity(bullet::to_bullet(comp.get_velocity()));
1554void update_rigidbody_angular_velocity(bullet::rigidbody& body, physics_component& comp)
1556 body.internal->setAngularVelocity(bullet::to_bullet(comp.get_angular_velocity()));
1561void update_rigidbody_collision_layer(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1563 int filter_group = comp.get_owner().get<layer_component>().layers.mask;
1564 int filter_mask = comp.get_collision_mask().mask;
1565 body.collision_filter_group = filter_group;
1566 body.collision_filter_mask = filter_mask;
1574 btBroadphaseProxy* proxy = body.internal->getBroadphaseHandle();
1580 if(body.collision_filter_group != proxy->m_collisionFilterGroup ||
1581 body.collision_filter_mask != proxy->m_collisionFilterMask)
1584 world.dynamics_world->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(
1586 world.dynamics_world->getDispatcher());
1589 proxy->m_collisionFilterGroup = body.collision_filter_group;
1590 proxy->m_collisionFilterMask = body.collision_filter_mask;
1593 world.dynamics_world->refreshBroadphaseProxy(body.internal.get());
1598void update_rigidbody_mass_and_inertia(bullet::rigidbody& body, physics_component& comp)
1601 btVector3 local_inertia(0, 0, 0);
1602 if(!comp.is_kinematic())
1604 auto shape = body.internal->getCollisionShape();
1607 mass = comp.get_mass();
1608 shape->calculateLocalInertia(
mass, local_inertia);
1611 body.internal->setMassProps(
mass, local_inertia);
1614void update_rigidbody_gravity(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1616 if(comp.is_using_gravity())
1618 body.internal->setGravity(
world.dynamics_world->getGravity());
1622 body.internal->setGravity(btVector3{0, 0, 0});
1623 body.internal->setLinearVelocity(btVector3(0, 0, 0));
1627void update_rigidbody_material(bullet::rigidbody& body, physics_component& comp)
1629 auto mat = comp.get_material().get();
1631 int packed = bullet::encode_combine_modes(mat->friction_combine, mat->restitution_combine);
1632 if(body.internal->getUserIndex2() != packed)
1634 body.internal->setUserIndex2(packed);
1637 if(math::epsilonNotEqual(body.internal->getRestitution(), mat->restitution, math::epsilon<float>()))
1639 body.internal->setRestitution(mat->restitution);
1641 if(math::epsilonNotEqual(body.internal->getFriction(), mat->friction, math::epsilon<float>()))
1643 body.internal->setFriction(mat->friction);
1646 auto stiffness = mat->get_stiffness();
1647 if(math::epsilonNotEqual(body.internal->getContactStiffness(), stiffness, math::epsilon<float>()) ||
1648 math::epsilonNotEqual(body.internal->getContactDamping(), mat->damping, math::epsilon<float>()))
1650 body.internal->setContactStiffnessAndDamping(stiffness, mat->damping);
1654void update_rigidbody_sensor(bullet::rigidbody& body, physics_component& comp)
1656 auto flags = body.internal->getCollisionFlags();
1657 if(comp.is_sensor())
1659 body.internal->setCollisionFlags(flags | btCollisionObject::CF_NO_CONTACT_RESPONSE);
1663 body.internal->setCollisionFlags(flags & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
1667void set_rigidbody_active(bullet::world& world, bullet::rigidbody& body,
bool enabled)
1671 world.add_rigidbody(body);
1675 world.remove_rigidbody(body);
1679void update_rigidbody_full(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1681 update_rigidbody_kind(body, comp);
1682 update_rigidbody_shape(body, comp);
1683 update_rigidbody_mass_and_inertia(body, comp);
1684 update_rigidbody_material(body, comp);
1685 update_rigidbody_sensor(body, comp);
1686 update_rigidbody_constraints(body, comp);
1687 update_rigidbody_velocity(body, comp);
1688 update_rigidbody_angular_velocity(body, comp);
1689 update_rigidbody_gravity(world, body, comp);
1690 update_rigidbody_collision_layer(world, body, comp);
1693void make_rigidbody(bullet::world& world, entt::handle
entity, physics_component& comp)
1695 auto& body =
entity.emplace<bullet::rigidbody>();
1697 body.internal = std::make_shared<btRigidBody>(comp.get_mass(),
nullptr,
nullptr);
1698 body.internal->setUserIndex(
int(
entity.entity()));
1699 body.internal->setUserPointer(&world);
1700 body.internal->setFlags(BT_DISABLE_WORLD_GRAVITY);
1702 update_rigidbody_full(world, body, comp);
1704 if(
entity.all_of<active_component>())
1706 world.add_rigidbody(body);
1710void destroy_phyisics_body(bullet::world& world, entt::handle
entity,
bool from_physics_component)
1712 auto body =
entity.try_get<bullet::rigidbody>();
1714 if(body && body->internal)
1716 world.remove_rigidbody(*body);
1719 if(from_physics_component)
1721 entity.remove<bullet::rigidbody>();
1725void sync_physics_body(bullet::world& world, physics_component& comp,
bool force =
false)
1727 auto owner = comp.get_owner();
1731 destroy_phyisics_body(world, comp.get_owner(),
true);
1732 make_rigidbody(world,
owner, comp);
1736 auto& body =
owner.get<bullet::rigidbody>();
1740 set_rigidbody_active(world, body,
false);
1741 update_rigidbody_full(world, body, comp);
1742 set_rigidbody_active(world, body,
true);
1749 update_rigidbody_shape(body, comp);
1750 world.dynamics_world->updateSingleAabb(body.internal.get());
1754 update_rigidbody_mass_and_inertia(body, comp);
1759 update_rigidbody_sensor(body, comp);
1764 update_rigidbody_constraints(body, comp);
1769 update_rigidbody_velocity(body, comp);
1773 update_rigidbody_angular_velocity(body, comp);
1778 update_rigidbody_gravity(world, body, comp);
1782 update_rigidbody_material(body, comp);
1783 update_rigidbody_collision_layer(world, body, comp);
1786 if(!comp.is_kinematic())
1788 if(comp.are_any_properties_dirty())
1795 comp.set_dirty(system_id,
false);
1798auto sync_transforms(bullet::world& world, physics_component& comp,
const transform_component& transform) ->
bool
1800 auto owner = comp.get_owner();
1801 auto& body =
owner.get<bullet::rigidbody>();
1808 const auto&
p =
transform.get_position_global();
1809 const auto&
q =
transform.get_rotation_global();
1810 const auto&
s =
transform.get_scale_global();
1812 auto bt_pos = bullet::to_bullet(p);
1813 auto bt_rot = bullet::to_bullet(q);
1814 btTransform bt_trans(bt_rot, bt_pos);
1815 body.internal->setWorldTransform(bt_trans);
1817 if(body.internal_shape && comp.is_autoscaled())
1819 update_rigidbody_shape_scale(world, body, s);
1827auto sync_state(physics_component& comp) ->
bool
1829 auto owner = comp.get_owner();
1830 auto body =
owner.try_get<bullet::rigidbody>();
1832 if(!body || !body->internal)
1837 if(!body->internal->isActive())
1842 comp.set_velocity(bullet::from_bullet(body->internal->getLinearVelocity()));
1843 comp.set_angular_velocity(bullet::from_bullet(body->internal->getAngularVelocity()));
1848auto sync_transforms(physics_component& comp, transform_component& transform) ->
bool
1850 auto owner = comp.get_owner();
1851 auto body =
owner.try_get<bullet::rigidbody>();
1853 if(!body || !body->internal)
1858 if(!body->internal->isActive())
1863 const auto& bt_trans = body->internal->getWorldTransform();
1864 auto p = bullet::from_bullet(bt_trans.getOrigin());
1865 auto q = bullet::from_bullet(bt_trans.getRotation());
1869 float epsilon = 0.009f;
1870 return transform.set_position_and_rotation_global(p, q, epsilon);
1873auto to_physics(bullet::world& world, transform_component& transform, physics_component& comp) ->
bool
1875 bool transform_dirty =
transform.is_dirty(system_id);
1876 bool rigidbody_dirty = comp.is_dirty(system_id);
1880 sync_physics_body(world, comp);
1883 if(transform_dirty || rigidbody_dirty)
1885 return sync_transforms(world, comp, transform);
1891auto from_physics(bullet::world& world, transform_component& transform, physics_component& comp) ->
bool
1895 bool result = sync_transforms(comp, transform);
1898 comp.set_dirty(system_id,
false);
1903void make_character_controller_body(bullet::world& world,
1905 character_controller_component& comp)
1907 auto& cc =
entity.emplace<bullet::character_controller>();
1908 float capsule_half_height = (comp.get_height() - 2.0f * comp.get_radius()) * 0.5f;
1909 if(capsule_half_height < 0.0f)
1911 capsule_half_height = 0.0f;
1913 cc.shape = std::make_shared<btCapsuleShape>(comp.get_radius(), capsule_half_height * 2.0f);
1914 cc.ghost = std::make_shared<btPairCachingGhostObject>();
1915 cc.ghost->setCollisionShape(cc.shape.get());
1916 cc.ghost->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT | btCollisionObject::CF_KINEMATIC_OBJECT);
1917 cc.ghost->setUserIndex(
int(
entity.entity()));
1918 cc.ghost->setUserPointer(&world);
1919 cc.collision_filter_group =
entity.get<layer_component>().layers.mask;
1920 cc.collision_filter_mask = comp.get_collision_mask().mask;
1921 cc.controller = std::make_shared<btKinematicCharacterController>(
1922 cc.ghost.get(), cc.shape.get(), comp.get_step_height());
1923 cc.controller->setMaxSlope(math::radians(comp.get_slope_limit()));
1924 cc.controller->setGravity(
world.dynamics_world->getGravity() * comp.get_gravity_scale());
1925 cc.controller->setFallSpeed(comp.get_terminal_velocity());
1926 cc.controller->setLinearDamping(comp.get_linear_damping());
1928 const auto&
p =
transform.get_position_global();
1929 const auto&
q =
transform.get_rotation_global();
1930 btTransform bt_trans(bullet::to_bullet(q), bullet::to_bullet(p + comp.get_center()));
1931 cc.ghost->setWorldTransform(bt_trans);
1932 if(
entity.all_of<active_component>())
1934 world.add_character_controller(cc);
1938void destroy_character_controller_body(bullet::world& world,
1940 bool from_cc_component)
1942 auto cc =
entity.try_get<bullet::character_controller>();
1943 if(cc && cc->controller)
1945 world.remove_character_controller(*cc);
1947 if(from_cc_component)
1949 entity.remove<bullet::character_controller>();
1953void sync_character_controller_body(bullet::world& world,
1954 character_controller_component& comp,
1957 auto owner = comp.get_owner();
1960 destroy_character_controller_body(world,
owner,
true);
1961 make_character_controller_body(world,
owner, comp);
1965 auto* cc =
owner.try_get<bullet::character_controller>();
1966 if(!cc || !cc->controller)
1973 destroy_character_controller_body(world,
owner,
true);
1974 make_character_controller_body(world,
owner, comp);
1975 comp.set_dirty(system_id,
false);
1980 cc->controller->setStepHeight(comp.get_step_height());
1984 cc->controller->setMaxSlope(math::radians(comp.get_slope_limit()));
1988 cc->controller->setGravity(
world.dynamics_world->getGravity() * comp.get_gravity_scale());
1992 destroy_character_controller_body(world,
owner,
true);
1993 make_character_controller_body(world,
owner, comp);
1994 comp.set_dirty(system_id,
false);
1999 cc->controller->setFallSpeed(comp.get_terminal_velocity());
2000 cc->controller->setLinearDamping(comp.get_linear_damping());
2003 comp.set_dirty(system_id,
false);
2006auto to_physics_cc(bullet::world& world,
2007 transform_component& transform,
2008 character_controller_component& comp) ->
bool
2010 bool transform_dirty =
transform.is_dirty(system_id);
2011 bool cc_dirty = comp.is_dirty(system_id);
2012 sync_character_controller_body(world, comp);
2013 if(transform_dirty || cc_dirty)
2015 auto owner = comp.get_owner();
2016 auto* cc =
owner.try_get<bullet::character_controller>();
2017 if(!cc || !cc->ghost)
2021 const auto&
p =
transform.get_position_global();
2022 const auto&
q =
transform.get_rotation_global();
2023 btTransform bt_trans(bullet::to_bullet(q), bullet::to_bullet(p + comp.get_center()));
2024 cc->ghost->setWorldTransform(bt_trans);
2030auto from_physics_cc(bullet::world& world,
2031 transform_component& transform,
2032 character_controller_component& comp) ->
bool
2034 auto owner = comp.get_owner();
2035 auto* cc =
owner.try_get<bullet::character_controller>();
2036 if(!cc || !cc->ghost)
2040 const auto& bt_trans = cc->ghost->getWorldTransform();
2041 auto p = bullet::from_bullet(bt_trans.getOrigin()) - comp.get_center();
2042 auto q = bullet::from_bullet(bt_trans.getRotation());
2043 float epsilon = 0.009f;
2044 bool changed =
transform.set_position_and_rotation_global(p, q, epsilon);
2046 comp.set_grounded(cc->controller->onGround());
2047 auto bt_vel = cc->controller->getLinearVelocity();
2048 comp.set_velocity_internal(bullet::from_bullet(bt_vel));
2051 comp.set_dirty(system_id,
false);
2055auto add_force(btRigidBody* body,
const btVector3&
force,
force_mode mode) ->
bool
2057 if(
force.fuzzyZero())
2065 body->applyCentralForce(
force);
2070 btVector3 acceleration_force =
force * body->getMass();
2071 body->applyCentralForce(acceleration_force);
2076 body->applyCentralImpulse(
force);
2081 btVector3 new_velocity = body->getLinearVelocity() +
force;
2082 body->setLinearVelocity(new_velocity);
2089auto add_torque(btRigidBody* body,
const btVector3& torque,
force_mode mode) ->
bool
2091 if(torque.fuzzyZero())
2099 body->applyTorque(torque);
2104 btVector3 inertia_tensor = body->getInvInertiaDiagLocal();
2105 btVector3 angular_acceleration(
2106 inertia_tensor.getX() != 0 ? torque.getX() * (1.0f / inertia_tensor.getX()) : 0.0f,
2107 inertia_tensor.getY() != 0 ? torque.getY() * (1.0f / inertia_tensor.getY()) : 0.0f,
2108 inertia_tensor.getZ() != 0 ? torque.getZ() * (1.0f / inertia_tensor.getZ()) : 0.0f);
2109 body->applyTorque(angular_acceleration);
2114 body->applyTorqueImpulse(torque);
2119 btVector3 new_velocity = body->getLinearVelocity() + torque;
2120 body->setAngularVelocity(new_velocity);
2132 bullet::setup_task_scheduler();
2133 bullet::override_combine_callbacks();
2138 bullet::cleanup_task_scheduler();
2144 auto world = r.ctx().find<bullet::world>();
2147 entt::handle
entity(r, e);
2149 sync_physics_body(*world, phisics,
true);
2156 auto world = r.ctx().find<bullet::world>();
2159 entt::handle
entity(r, e);
2160 destroy_phyisics_body(*world,
entity,
true);
2167 auto world = r.ctx().find<bullet::world>();
2170 entt::handle
entity(r, e);
2171 destroy_phyisics_body(*world,
entity,
false);
2177 auto world = r.ctx().find<bullet::world>();
2180 entt::handle
entity(r, e);
2182 sync_character_controller_body(*world, comp,
true);
2188 auto world = r.ctx().find<bullet::world>();
2191 entt::handle
entity(r, e);
2192 destroy_character_controller_body(*world,
entity,
true);
2198 auto world = r.ctx().find<bullet::world>();
2201 entt::handle
entity(r, e);
2202 destroy_character_controller_body(*world,
entity,
false);
2209 auto* cc =
owner.try_get<bullet::character_controller>();
2210 if(!cc || !cc->controller)
2214 cc->controller->setWalkDirection(bullet::to_bullet(displacement));
2220 auto* cc =
owner.try_get<bullet::character_controller>();
2221 if(!cc || !cc->controller)
2225 cc->controller->jump(bullet::to_bullet(direction));
2231 auto* cc =
owner.try_get<bullet::character_controller>();
2232 if(!cc || !cc->controller)
2236 cc->controller->applyImpulse(bullet::to_bullet(
impulse));
2242 auto* cc =
owner.try_get<bullet::character_controller>();
2243 if(!cc || !cc->controller)
2253 auto* cc =
owner.try_get<bullet::character_controller>();
2254 if(!cc || !cc->controller)
2258 cc->controller->setLinearVelocity(bullet::to_bullet(
velocity));
2264 auto* cc =
owner.try_get<bullet::character_controller>();
2265 if(!cc || !cc->controller)
2275 auto world = r.ctx().find<bullet::world>();
2278 entt::handle
entity(r, e);
2279 auto body =
entity.try_get<bullet::rigidbody>();
2282 set_rigidbody_active(*world, *body,
true);
2284 auto cc =
entity.try_get<bullet::character_controller>();
2287 world->add_character_controller(*cc);
2294 auto world = r.ctx().find<bullet::world>();
2297 entt::handle
entity(r, e);
2298 auto body =
entity.try_get<bullet::rigidbody>();
2301 set_rigidbody_active(*world, *body,
false);
2303 auto cc =
entity.try_get<bullet::character_controller>();
2306 world->remove_character_controller(*cc);
2312 float explosion_force,
2313 const math::vec3& explosion_position,
2314 float explosion_radius,
2315 float upwards_modifier,
2320 if(
auto bbody =
owner.try_get<bullet::rigidbody>())
2322 const auto& body = bbody->internal;
2325 if(body && body->getInvMass() > 0)
2328 btVector3 body_position = body->getWorldTransform().getOrigin();
2331 btVector3 direction = body_position - bullet::to_bullet(explosion_position);
2332 float distance = direction.length();
2335 if(distance > explosion_radius && explosion_radius > 0.0f)
2343 direction /= distance;
2347 direction.setZero();
2351 if(upwards_modifier != 0.0f)
2353 direction.setY(direction.getY() + upwards_modifier);
2354 direction.normalize();
2358 float attenuation = 1.0f - (distance / explosion_radius);
2359 btVector3
force = direction * explosion_force * attenuation;
2361 if(add_force(body.get(),
force, mode))
2363 comp.
set_velocity(bullet::from_bullet(body->getLinearVelocity()));
2375 if(
auto bbody =
owner.try_get<bullet::rigidbody>())
2377 const auto& body = bbody->internal;
2378 auto vector = bullet::to_bullet(
force);
2380 if(add_force(body.get(), vector, mode))
2382 comp.
set_velocity(bullet::from_bullet(body->getLinearVelocity()));
2392 if(
auto bbody =
owner.try_get<bullet::rigidbody>())
2394 auto vector = bullet::to_bullet(torque);
2395 const auto& body = bbody->internal;
2397 if(add_torque(body.get(), vector, mode))
2411 if(
auto bbody =
owner.try_get<bullet::rigidbody>())
2413 bbody->internal->clearForces();
2415 comp.
set_velocity(bullet::from_bullet(bbody->internal->getLinearVelocity()));
2424 const math::vec3& direction,
2430 auto& ec = ctx.get_cached<
ecs>();
2431 auto& registry = *ec.get_scene().registry;
2433 auto& world = registry.ctx().get<bullet::world>();
2439 const math::vec3& direction,
2445 auto& ec = ctx.get_cached<
ecs>();
2446 auto& registry = *ec.get_scene().registry;
2448 auto& world = registry.ctx().get<bullet::world>();
2454 const math::vec3& direction,
2461 auto& ec = ctx.get_cached<
ecs>();
2462 auto& registry = *ec.get_scene().registry;
2464 auto& world = registry.ctx().get<bullet::world>();
2470 const math::vec3& direction,
2477 auto& ec = ctx.get_cached<
ecs>();
2478 auto& registry = *ec.get_scene().registry;
2480 auto& world = registry.ctx().get<bullet::world>();
2489 auto& ec = ctx.get_cached<
ecs>();
2490 auto& registry = *ec.get_scene().registry;
2492 auto& world = registry.ctx().get<bullet::world>();
2500 auto& scn = ec.get_scene();
2501 auto& registry = *scn.registry;
2503 auto& world = registry.ctx().emplace<bullet::world>(bullet::create_dynamics_world());
2505 registry.on_destroy<bullet::rigidbody>().connect<&on_destroy_bullet_rigidbody_component>();
2506 registry.on_destroy<bullet::character_controller>().connect<&on_destroy_bullet_cc_component>();
2507 registry.on_construct<
active_component>().connect<&on_create_active_component>();
2508 registry.on_destroy<
active_component>().connect<&on_destroy_active_component>();
2511 [&](
auto e,
auto&& comp)
2513 sync_physics_body(world, comp,
true);
2516 [&](
auto e,
auto&& comp)
2518 sync_character_controller_body(world, comp,
true);
2525 auto& registry = *ec.get_scene().registry;
2527 auto& world = registry.ctx().get<bullet::world>();
2530 [&](
auto e,
auto&& comp)
2532 destroy_character_controller_body(world, comp.get_owner(),
true);
2535 [&](
auto e,
auto&& comp)
2537 destroy_phyisics_body(world, comp.get_owner(),
true);
2540 registry.on_construct<
active_component>().disconnect<&on_create_active_component>();
2541 registry.on_destroy<
active_component>().disconnect<&on_destroy_active_component>();
2542 registry.on_destroy<bullet::character_controller>().disconnect<&on_destroy_bullet_cc_component>();
2543 registry.on_destroy<bullet::rigidbody>().disconnect<&on_destroy_bullet_rigidbody_component>();
2545 registry.ctx().erase<bullet::world>();
2568 auto& registry = *ec.get_scene().registry;
2569 auto& world = registry.ctx().get<bullet::world>();
2571 if(dt > delta_t::zero())
2573 float fixed_time_step = 1.0f / 50.0f;
2574 int max_subs_steps = 3;
2580 max_subs_steps = ss.time.max_fixed_steps;
2584 world.elapsed += dt.count();
2587 while(world.elapsed >= fixed_time_step && steps < max_subs_steps)
2590 delta_t step_dt(fixed_time_step);
2591 ev.on_frame_fixed_update(ctx, step_dt);
2594 uint64_t physics_entities{};
2595 uint64_t physics_entities_synced{};
2600 [&](
auto e,
auto&& transform,
auto&& rigidbody,
auto&& active_comp)
2603 if(to_physics(world, transform, rigidbody))
2605 physics_entities_synced++;
2609 [&](
auto e,
auto&& transform,
auto&& cc_comp,
auto&& active_comp)
2611 to_physics_cc(world, transform, cc_comp);
2615 world.simulate(fixed_time_step, fixed_time_step, 1);
2617 physics_entities = {};
2618 physics_entities_synced = {};
2622 [&](
auto e,
auto&& transform,
auto&& rigidbody,
auto&& active_comp)
2625 if(from_physics(world, transform, rigidbody))
2627 physics_entities_synced++;
2631 [&](
auto e,
auto&& transform,
auto&& cc_comp,
auto&& active_comp)
2633 from_physics_cc(world, transform, cc_comp);
2641 world.process_manifolds();
2643 world.elapsed -= fixed_time_step;
2652 auto& registry = *ec.get_scene().registry;
2653 auto world = registry.ctx().find<bullet::world>();
2656 bullet::debugdraw drawer(dd);
2657 world->dynamics_world->setDebugDrawer(&drawer);
2659 world->dynamics_world->debugDrawWorld();
2661 world->dynamics_world->setDebugDrawer(
nullptr);
2680 const auto& p = transform.get_position_global();
2681 const auto& q = transform.get_rotation_global();
2683 if(cylinder_half_height < 0.0f)
2685 cylinder_half_height = 0.0f;
2688 math::vec3 up = q * math::vec3(0.0f, 1.0f, 0.0f);
2689 auto top =
center + up * cylinder_half_height;
unravel::physics_vector< contact_manifold > to_exit
std::shared_ptr< btBroadphaseInterface > broadphase
std::vector< unravel::manifold_point > contacts
int collision_filter_group
hpp::flat_map< contact_key, contact_record > contacts_cache
std::shared_ptr< btDiscreteDynamicsWorld > dynamics_world
std::shared_ptr< btCollisionDispatcher > dispatcher
std::shared_ptr< btConstraintSolverPoolMt > solver_pool
std::shared_ptr< btCapsuleShape > shape
std::shared_ptr< btRigidBody > internal
std::shared_ptr< btDefaultCollisionConfiguration > collision_config
std::shared_ptr< btConstraintSolver > solver
unravel::physics_vector< hit_info > hits
int collision_filter_mask
std::shared_ptr< btCollisionShape > internal_shape
std::shared_ptr< btPairCachingGhostObject > ghost
unravel::physics_vector< contact_manifold > to_enter
std::shared_ptr< btKinematicCharacterController > controller
Class representing a camera. Contains functionality for manipulating and updating a camera....
Component for character controller physics with sweep-based movement.
void set_velocity_internal(const math::vec3 &vel) noexcept
auto get_height() const noexcept -> float
auto get_radius() const noexcept -> float
auto get_center() const noexcept -> const math::vec3 &
void set_grounded(bool grounded) noexcept
auto get_owner() const noexcept -> entt::const_handle
Gets the owner of the component.
Component that handles physics properties and behaviors.
void set_velocity(const math::vec3 &velocity)
void set_angular_velocity(const math::vec3 &velocity)
auto is_kinematic() const noexcept -> bool
Checks if the component is kinematic.
Class that contains core data for audio listeners. There can only be one instance of it per scene.
auto has_script_components() const -> bool
std::chrono::duration< float > delta_t
bgfx::Transform transform
void vertex_unpack(float _output[4], attribute _attr, const vertex_layout &_decl, const void *_data, uint32_t _index)
void end(encoder *_encoder)
Hash specialization for batch_key to enable use in std::unordered_map.
hpp::small_vector< T, SmallSizeCapacity > physics_vector
@ convex
Convex mesh collision (can be dynamic, faster)
auto to_bx(const glm::vec3 &data) -> bx::Vec3
std::vector< math::color > color
std::vector< float > scale
std::vector< math::vec3 > start
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
void lineTo(float _x, float _y, float _z=0.0f)
void setColor(uint32_t _abgr)
void setWireframe(bool _wireframe)
void drawCapsule(const bx::Vec3 &_from, const bx::Vec3 &_to, float _radius)
void moveTo(float _x, float _y, float _z=0.0f)
void on_skip_next_frame(rtti::context &ctx)
static auto sphere_cast_all(const math::vec3 &origin, const math::vec3 &direction, float radius, float max_distance, int layer_mask, bool query_sensors) -> physics_vector< raycast_hit >
static void on_create_cc_component(entt::registry &r, entt::entity e)
static void on_create_component(entt::registry &r, entt::entity e)
static void set_character_linear_velocity(character_controller_component &comp, const math::vec3 &velocity)
static void warp_character(character_controller_component &comp, const math::vec3 &position)
static void on_create_active_component(entt::registry &r, entt::entity e)
static void draw_gizmo(rtti::context &ctx, physics_component &comp, const camera &cam, gfx::dd_raii &dd)
static auto ray_cast(const math::vec3 &origin, const math::vec3 &direction, float max_distance, int layer_mask, bool query_sensors) -> hpp::optional< raycast_hit >
void on_play_begin(rtti::context &ctx)
static void apply_force(physics_component &comp, const math::vec3 &force, force_mode mode)
static void sync_character_runtime_state(character_controller_component &comp)
static void on_destroy_active_component(entt::registry &r, entt::entity e)
void on_resume(rtti::context &ctx)
static void on_destroy_cc_component(entt::registry &r, entt::entity e)
void on_pause(rtti::context &ctx)
static void apply_impulse_character(character_controller_component &comp, const math::vec3 &impulse)
static void draw_system_gizmos(rtti::context &ctx, const camera &cam, gfx::dd_raii &dd)
static auto sphere_overlap(const math::vec3 &origin, float radius, int layer_mask, bool query_sensors) -> physics_vector< entt::entity >
static void move_character(character_controller_component &comp, const math::vec3 &displacement)
static void jump_character(character_controller_component &comp, const math::vec3 &direction)
static auto sphere_cast(const math::vec3 &origin, const math::vec3 &direction, float radius, float max_distance, int layer_mask, bool query_sensors) -> hpp::optional< raycast_hit >
static void apply_torque(physics_component &comp, const math::vec3 &toruqe, force_mode mode)
static void apply_explosion_force(physics_component &comp, float explosion_force, const math::vec3 &explosion_position, float explosion_radius, float upwards_modifier, force_mode mode)
static void on_destroy_component(entt::registry &r, entt::entity e)
static void clear_kinematic_velocities(physics_component &comp)
static void on_destroy_bullet_rigidbody_component(entt::registry &r, entt::entity e)
static void on_destroy_bullet_cc_component(entt::registry &r, entt::entity e)
void on_frame_update(rtti::context &ctx, delta_t dt)
static auto ray_cast_all(const math::vec3 &origin, const math::vec3 &direction, float max_distance, int layer_mask, bool query_sensors) -> physics_vector< raycast_hit >
void on_play_end(rtti::context &ctx)
Manages the entity-component-system (ECS) operations for the ACE framework.
static auto context() -> rtti::context &
void on_collision_enter(entt::handle a, entt::handle b, const std::vector< manifold_point > &manifolds)
void on_collision_exit(entt::handle a, entt::handle b, const std::vector< manifold_point > &manifolds)
void on_sensor_enter(entt::handle sensor, entt::handle other, const std::vector< manifold_point > &manifolds)
void on_sensor_exit(entt::handle sensor, entt::handle other, const std::vector< manifold_point > &manifolds)
struct unravel::settings::time_settings time