5#include <math/transform.hpp>
17#define BT_USE_SSE_IN_API
18#include <BulletCollision/CollisionDispatch/btCollisionDispatcherMt.h>
19#include <BulletCollision/NarrowPhaseCollision/btRaycastCallback.h>
20#include <BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolverMt.h>
21#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorldMt.h>
23#include <btBulletCollisionCommon.h>
24#include <btBulletDynamicsCommon.h>
26#include <hpp/flat_map.hpp>
34#include "LinearMath/btThreads.h"
43 bool operator<(contact_key
const& o)
const
45 return a < o.a || (
a == o.a &&
b < o.b);
47 bool operator==(contact_key
const& o)
const
49 return a == o.a &&
b == o.b;
56struct hash<contact_key>
61 return (uint64_t)k.a.entity() * 0x9e3779b97f4a7c15ULL ^ ((uint64_t)k.b.entity() << 1);
70bool enable_logging =
false;
72enum class manifold_type
85struct contact_manifold
95const btVector3 gravity_sun(btScalar(0), btScalar(-274), btScalar(0));
96const btVector3 gravity_mercury(btScalar(0), btScalar(-3.7), btScalar(0));
97const btVector3 gravity_venus(btScalar(0), btScalar(-8.87), btScalar(0));
98const btVector3 gravity_earth(btScalar(0), btScalar(-9.8), btScalar(0));
99const btVector3 gravity_mars(btScalar(0), btScalar(-3.72), btScalar(0));
100const btVector3 gravity_jupiter(btScalar(0), btScalar(-24.79), btScalar(0));
101const btVector3 gravity_saturn(btScalar(0), btScalar(-10.44), btScalar(0));
102const btVector3 gravity_uranus(btScalar(0), btScalar(-8.69), btScalar(0));
103const btVector3 gravity_neptune(btScalar(0), btScalar(-11.15), btScalar(0));
104const btVector3 gravity_pluto(btScalar(0), btScalar(-0.62), btScalar(0));
105const btVector3 gravity_moon(btScalar(0), btScalar(-1.625), btScalar(0));
107auto to_bullet(
const math::vec3& v) -> btVector3
109 return {
v.x,
v.y,
v.z};
112auto from_bullet(
const btVector3& v) -> math::vec3
114 return {
v.getX(),
v.getY(),
v.getZ()};
117auto to_bullet(
const math::quat& q) -> btQuaternion
119 return {
q.x,
q.y,
q.z,
q.w};
122auto from_bullet(
const btQuaternion& q) -> math::quat
132auto to_bx(
const btVector3& data) -> bx::Vec3
134 return {data.getX(), data.getY(), data.getZ()};
137auto to_bx_color(
const btVector3& in) -> uint32_t
139#define COL32_R_SHIFT 0
140#define COL32_G_SHIFT 8
141#define COL32_B_SHIFT 16
142#define COL32_A_SHIFT 24
143#define COL32_A_MASK 0xFF000000
152class debugdraw :
public btIDebugDraw
154 int debug_mode_ = btIDebugDraw::DBG_DrawContactPoints;
155 DefaultColors our_colors_;
157 std::unique_ptr<DebugDrawEncoderScopePush> scope_;
168 scope_ = std::make_unique<DebugDrawEncoderScopePush>(dd_.
encoder);
172 auto getDefaultColors() const -> DefaultColors
override
178 void setDefaultColors(
const DefaultColors& colors)
override
180 our_colors_ = colors;
183 void drawLine(
const btVector3& from1,
const btVector3& to1,
const btVector3& color1)
override
192 void drawContactPoint(
const btVector3& point_on_b,
193 const btVector3& normal_on_b,
196 const btVector3& color)
override
198 drawLine(point_on_b, point_on_b + normal_on_b *
distance, color);
199 btVector3 ncolor(0, 0, 0);
200 drawLine(point_on_b, point_on_b + normal_on_b * 0.1, ncolor);
203 void setDebugMode(
int debugMode)
override
205 debug_mode_ = debugMode;
208 auto getDebugMode() const ->
int override
213 void flushLines()
override
218 void reportErrorWarning(
const char* warningString)
override
222 void draw3dText(
const btVector3& location,
const char* textString)
override
227static constexpr int COMBINE_BITS = 2;
228static constexpr int COMBINE_MASK = (1 << COMBINE_BITS) - 1;
229static constexpr int FRICTION_SHIFT = COMBINE_BITS;
230static constexpr int RESTITUTION_SHIFT = 0;
234 int f = (
static_cast<int>(friction) & COMBINE_MASK) << FRICTION_SHIFT;
235 int b = (
static_cast<int>(bounce) & COMBINE_MASK) << RESTITUTION_SHIFT;
270static btScalar per_body_combine(
const btCollisionObject* body0,
271 const btCollisionObject* body1,
278 auto mode = pick_combine_mode(mode0, mode1);
289 combined = (e0 + e1) * btScalar(0.5);
293 combined = btMin(e0, e1);
297 combined = btMax(e0, e1);
313static btScalar combined_restitution_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
315 int raw_mode0 = body0->getUserIndex2();
316 int raw_mode1 = body1->getUserIndex2();
317 auto mode0 = decode_restitution_combine(raw_mode0);
318 auto mode1 = decode_restitution_combine(raw_mode1);
320 return per_body_combine(body0, body1, body0->getRestitution(), body1->getRestitution(), mode0, mode1);
323static btScalar combined_friction_callback(
const btCollisionObject* body0,
324 const btCollisionObject* body1,
328 int raw_mode0 = body0->getUserIndex2();
329 int raw_mode1 = body1->getUserIndex2();
330 auto mode0 = decode_restitution_combine(raw_mode0);
331 auto mode1 = decode_restitution_combine(raw_mode1);
333 auto friction = per_body_combine(body0, body1, f0, f1, mode0, mode1);
334 const btScalar MAX_FRICTION = btScalar(10.);
335 if(friction < -MAX_FRICTION)
336 friction = -MAX_FRICTION;
337 if(friction > MAX_FRICTION)
338 friction = MAX_FRICTION;
342static btScalar combined_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
344 auto f0 = body0->getFriction();
345 auto f1 = body1->getFriction();
346 return combined_friction_callback(body0, body1, f0, f1);
349static btScalar combined_rolling_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
351 auto f0 = body0->getFriction() * body0->getRollingFriction();
352 auto f1 = body1->getFriction() * body1->getRollingFriction();
353 return combined_friction_callback(body0, body1, f0, f1);
356static btScalar combined_spinning_friction_callback(
const btCollisionObject* body0,
const btCollisionObject* body1)
358 auto f0 = body0->getFriction() * body0->getSpinningFriction();
359 auto f1 = body1->getFriction() * body1->getSpinningFriction();
360 return combined_friction_callback(body0, body1, f0, f1);
363void override_combine_callbacks()
366 gCalculateCombinedRestitutionCallback = combined_restitution_callback;
369 gCalculateCombinedFrictionCallback = combined_friction_callback;
370 gCalculateCombinedRollingFrictionCallback = combined_rolling_friction_callback;
371 gCalculateCombinedSpinningFrictionCallback = combined_spinning_friction_callback;
374void setup_task_scheduler()
378 btITaskScheduler* scheduler = btGetTaskScheduler();
380 scheduler = btCreateDefaultTaskScheduler();
383 scheduler = btGetSequentialTaskScheduler();
388 btSetTaskScheduler(scheduler);
393void cleanup_task_scheduler()
397 btITaskScheduler* scheduler = btGetTaskScheduler();
400 btSetTaskScheduler(
nullptr);
407auto get_entity_from_user_index(
unravel::ecs& ec,
int index) -> entt::handle
409 auto id =
static_cast<entt::entity
>(index);
411 return ec.get_scene().create_handle(
id);
414auto get_entity_id_from_user_index(
int index) -> entt::entity
418 auto id =
static_cast<entt::entity
>(index);
423auto has_scripting(entt::handle
a) ->
bool
431 return a_has_scripting;
434auto should_record_collision_event(entt::handle
a, entt::handle
b) ->
bool
448auto should_record_sensor_event(entt::handle
a, entt::handle
b) ->
bool
458template<
typename Callback>
459class filter_ray_callback :
public Callback
465 filter_ray_callback(
const btVector3& from,
const btVector3& to,
int mask,
bool sensors)
473 auto needsCollision(btBroadphaseProxy* proxy0)
const ->
bool override
475 if(!Callback::needsCollision(proxy0))
481 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
486 const auto* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
488 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
498using filter_closest_ray_callback = filter_ray_callback<btCollisionWorld::ClosestRayResultCallback>;
499using filter_all_hits_ray_callback = filter_ray_callback<btCollisionWorld::AllHitsRayResultCallback>;
502class sphere_closest_convex_result_callback :
public btCollisionWorld::ClosestConvexResultCallback
508 sphere_closest_convex_result_callback(
const btVector3& from,
const btVector3& to,
int layerMask,
bool sensors)
509 : btCollisionWorld::ClosestConvexResultCallback(from, to)
516 bool needsCollision(btBroadphaseProxy* proxy0)
const override
519 if(!btCollisionWorld::ClosestConvexResultCallback::needsCollision(proxy0))
522 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
528 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
531 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
541class sphere_all_convex_result_callback :
public btCollisionWorld::ConvexResultCallback
549 const btCollisionObject*
object =
nullptr;
557 m_closestHitFraction = btScalar(1.f);
561 btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,
bool normalInWorldSpace)
override
565 hi.object = convexResult.m_hitCollisionObject;
566 hi.fraction = convexResult.m_hitFraction;
568 if(normalInWorldSpace)
569 hi.normal = convexResult.m_hitNormalLocal;
574 convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal;
580 return m_closestHitFraction;
583 bool needsCollision(btBroadphaseProxy* proxy0)
const override
585 if(!ConvexResultCallback::needsCollision(proxy0))
589 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
594 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
596 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
605struct sphere_overlap_callback : btCollisionWorld::ContactResultCallback
607 btCollisionObject*
me{};
614 sphere_overlap_callback(btCollisionObject* obj,
int layerMask,
bool sensors)
619 m_closestDistanceThreshold = btScalar(1.f);
622 bool needsCollision(btBroadphaseProxy* proxy0)
const override
624 if(!btCollisionWorld::ContactResultCallback::needsCollision(proxy0))
628 if((proxy0->m_collisionFilterGroup & layer_mask) == 0)
633 const btCollisionObject* co =
static_cast<const btCollisionObject*
>(proxy0->m_clientObject);
635 if(!query_sensors && (co->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE))
643 btScalar addSingleResult(btManifoldPoint&,
644 const btCollisionObjectWrapper* w0,
647 const btCollisionObjectWrapper* w1,
651 const btCollisionObject* other =
652 (w0->getCollisionObject() == me ? w1->getCollisionObject() : w0->getCollisionObject());
653 hits.push_back(
const_cast<btCollisionObject*
>(other));
670 std::shared_ptr<btConstraintSolver>
solver;
675 struct contact_record
680 cm.contacts.reserve(4);
693 void add_rigidbody(
const rigidbody& body)
695 if(body.internal->isInWorld())
700 btAssert(in_simulate ==
false);
702 dynamics_world->addRigidBody(body.internal.get(), body.collision_filter_group, body.collision_filter_mask);
705 void remove_rigidbody(
const rigidbody& body)
707 if(!body.internal->isInWorld())
711 btAssert(in_simulate ==
false);
717 switch(manifold.type)
719 case manifold_type::sensor:
721 if(manifold.event == event_type::enter)
733 case manifold_type::collision:
735 if(manifold.event == event_type::enter)
753 void process_manifolds()
763 for(
auto& kv : contacts_cache)
764 kv.second.active_this_frame =
false;
772 for(
int i = 0;
i < nm; ++
i)
774 auto*
m =
dispatcher->getManifoldByIndexInternal(i);
775 if(
m->getNumContacts() == 0)
779 auto* objA =
m->getBody0();
780 auto* objB =
m->getBody1();
781 bool isSensorA = objA->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE;
782 bool isSensorB = objB->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE;
783 auto eA = get_entity_from_user_index(ec, objA->getUserIndex());
784 auto eB = get_entity_from_user_index(ec, objB->getUserIndex());
787 if(isSensorA || isSensorB)
791 contact_key
key{eA, eB};
795 it->second.active_this_frame =
true;
799 contact_manifold
cm{manifold_type::sensor, event_type::enter, eA, eB, {}};
801 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
803 rec.active_this_frame =
true;
808 contact_key
key{eB, eA};
812 it->second.active_this_frame =
true;
816 contact_manifold
cm{manifold_type::sensor, event_type::enter, eB, eA, {}};
818 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
820 rec.active_this_frame =
true;
827 contact_key
key{eA, eB};
832 it->second.active_this_frame =
true;
838 cm.type = manifold_type::collision;
839 cm.event = event_type::enter;
842 cm.contacts.reserve(
m->getNumContacts());
843 for(
int j = 0;
j <
m->getNumContacts(); ++
j)
845 auto const&
p =
m->getContactPoint(j);
847 mp.
a = from_bullet(
p.getPositionWorldOnA());
848 mp.
b = from_bullet(
p.getPositionWorldOnB());
853 cm.contacts.push_back(mp);
856 auto& rec =
contacts_cache.emplace(key, contact_record{}).first->second;
858 rec.active_this_frame =
true;
865 if(!it->second.active_this_frame)
867 auto cm = it->second.cm;
868 cm.event = event_type::exit;
879 for(
auto&
cm : to_enter)
881 process_manifold(scripting,
cm);
883 for(
auto&
cm : to_exit)
885 process_manifold(scripting,
cm);
889 void simulate(btScalar dt, btScalar fixed_time_step = 1.0 / 60.0,
int max_subs_steps = 10)
893 dynamics_world->stepSimulation(dt, max_subs_steps, fixed_time_step);
898 auto ray_cast_closest(
const math::vec3& origin,
899 const math::vec3& direction,
909 auto ray_origin = to_bullet(origin);
910 auto ray_end = to_bullet(origin + direction * max_distance);
914 ray_callback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
916 if(ray_callback.hasHit())
918 const btRigidBody* body = btRigidBody::upcast(ray_callback.m_collisionObject);
922 hit.
entity = get_entity_id_from_user_index(body->getUserIndex());
923 hit.
point = from_bullet(ray_callback.m_hitPointWorld);
924 hit.
normal = from_bullet(ray_callback.m_hitNormalWorld);
933 auto ray_cast_all(
const math::vec3& origin,
934 const math::vec3& direction,
944 auto ray_origin = to_bullet(origin);
945 auto ray_end = to_bullet(origin + direction * max_distance);
949 ray_callback.m_flags |= btTriangleRaycastCallback::kF_UseGjkConvexCastRaytest;
952 if(!ray_callback.hasHit())
960 hits.reserve(ray_callback.m_hitPointWorld.size());
961 for(
int i = 0;
i < ray_callback.m_hitPointWorld.size(); ++
i)
963 const btCollisionObject* collision_object = ray_callback.m_collisionObjects[
i];
964 const btRigidBody* body = btRigidBody::upcast(collision_object);
968 auto& hit =
hits.emplace_back();
970 hit.entity = get_entity_id_from_user_index(body->getUserIndex());
971 hit.point = from_bullet(ray_callback.m_hitPointWorld[i]);
972 hit.normal = from_bullet(ray_callback.m_hitNormalWorld[i]);
973 hit.distance = math::distance(origin, hit.point);
980 auto sphere_cast_closest(
const math::vec3& origin,
981 const math::vec3& direction,
993 btVector3 btOrigin = to_bullet(origin);
994 btVector3 btEnd = to_bullet(origin + direction * max_distance);
998 btSphereShape
shape(radius);
1003 start.setIdentity();
1005 start.setOrigin(btOrigin);
1006 end.setOrigin(btEnd);
1021 const btCollisionObject* obj = cb.m_hitCollisionObject;
1023 float fraction = cb.m_closestHitFraction;
1024 btVector3 hitPoint = btOrigin.lerp(btEnd,
fraction);
1025 btVector3
normal = cb.m_hitNormalWorld;
1028 const btRigidBody* body = btRigidBody::upcast(obj);
1032 hit.
entity = get_entity_id_from_user_index(body->getUserIndex());
1040 hit.
point = from_bullet(hitPoint);
1047 auto sphere_cast_all(
const math::vec3& origin,
1048 const math::vec3& direction,
1059 btVector3 btOrigin = to_bullet(origin);
1060 btVector3 btEnd = to_bullet(origin + direction * max_distance);
1063 start.setIdentity();
1065 start.setOrigin(btOrigin);
1066 end.setOrigin(btEnd);
1069 btSphereShape
shape(radius);
1078 std::sort(cb.hits.begin(),
1080 [](
auto&
a,
auto&
b)
1082 return a.fraction < b.fraction;
1087 hits.reserve(cb.hits.size());
1089 for(
const auto& hi : cb.hits)
1091 auto& hit =
hits.emplace_back();
1093 const btRigidBody* body = btRigidBody::upcast(hi.object);
1096 hit.
entity = get_entity_id_from_user_index(body->getUserIndex());
1103 btVector3 hitPoint = btOrigin.lerp(btEnd, hi.fraction);
1104 hit.
point = from_bullet(hitPoint);
1105 hit.
normal = from_bullet(hi.normal.normalized());
1106 hit.
distance = hi.fraction * max_distance;
1115 btSphereShape
sphere(radius);
1116 btCollisionObject tempObj;
1117 tempObj.setCollisionShape(&sphere);
1118 tempObj.setWorldTransform(btTransform(btQuaternion::getIdentity(), to_bullet(origin)));
1125 hits.reserve(cb.hits.size());
1127 for(
const auto& hi : cb.hits)
1129 auto& hit =
hits.emplace_back();
1131 const btRigidBody* body = btRigidBody::upcast(hi);
1134 hit = get_entity_id_from_user_index(body->getUserIndex());
1146auto get_world_from_user_pointer(
void* pointer) -> world&
1148 auto world =
reinterpret_cast<bullet::world*
>(pointer);
1152auto create_dynamics_world() -> bullet::world
1154 bullet::world world{};
1156 auto collision_config = std::make_shared<btDefaultCollisionConfiguration>();
1159 auto broadphase = std::make_shared<btDbvtBroadphase>();
1163 auto solver_pool = std::make_shared<btConstraintSolverPoolMt>(std::thread::hardware_concurrency() - 1);
1164 auto solver = std::make_shared<btSequentialImpulseConstraintSolverMt>();
1165 world.dynamics_world = std::make_shared<btDiscreteDynamicsWorldMt>(
dispatcher.get(),
1174 auto solver = std::make_shared<btSequentialImpulseConstraintSolver>();
1175 world.dynamics_world = std::make_shared<btDiscreteDynamicsWorld>(
dispatcher.get(),
1184 world.dynamics_world->setGravity(gravity_earth);
1185 world.dynamics_world->setForceUpdateAllAabbs(
false);
1189ATTRIBUTE_ALIGNED16(
class)
1190btCompoundShapeOwning : public btCompoundShape
1193 BT_DECLARE_ALIGNED_ALLOCATOR();
1195 ~btCompoundShapeOwning()
override
1198 for(
int i = 0;
i < m_children.size();
i++)
1200 delete m_children[
i].m_childShape;
1212const uint8_t system_id = 1;
1214void wake_up(bullet::rigidbody& body)
1218 body.internal->activate(
true);
1222auto make_rigidbody_shape(physics_component& comp) -> std::shared_ptr<btCompoundShape>
1225 auto cp = std::make_shared<bullet::btCompoundShapeOwning>();
1227 auto compound_shapes = comp.get_shapes();
1228 if(compound_shapes.empty())
1233 for(
const auto& s : compound_shapes)
1235 if(hpp::holds_alternative<physics_box_shape>(
s.shape))
1237 const auto&
shape = hpp::get<physics_box_shape>(
s.shape);
1238 auto half_extends =
shape.extends * 0.5f;
1240 btBoxShape* box_shape =
new btBoxShape({half_extends.x, half_extends.y, half_extends.z});
1242 btTransform local_transform = btTransform::getIdentity();
1243 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1244 cp->addChildShape(local_transform, box_shape);
1246 else if(hpp::holds_alternative<physics_sphere_shape>(
s.shape))
1248 const auto&
shape = hpp::get<physics_sphere_shape>(
s.shape);
1250 btSphereShape* sphere_shape =
new btSphereShape(
shape.radius);
1252 btTransform local_transform = btTransform::getIdentity();
1253 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1254 cp->addChildShape(local_transform, sphere_shape);
1256 else if(hpp::holds_alternative<physics_capsule_shape>(
s.shape))
1258 const auto&
shape = hpp::get<physics_capsule_shape>(
s.shape);
1260 btCapsuleShape* capsule_shape =
new btCapsuleShape(
shape.radius,
shape.length);
1262 btTransform local_transform = btTransform::getIdentity();
1263 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1264 cp->addChildShape(local_transform, capsule_shape);
1266 else if(hpp::holds_alternative<physics_cylinder_shape>(
s.shape))
1268 const auto&
shape = hpp::get<physics_cylinder_shape>(
s.shape);
1270 btVector3 half_extends(
shape.radius,
shape.length * 0.5f,
shape.radius);
1271 btCylinderShape* cylinder_shape =
new btCylinderShape(half_extends);
1273 btTransform local_transform = btTransform::getIdentity();
1274 local_transform.setOrigin(bullet::to_bullet(
shape.center));
1275 cp->addChildShape(local_transform, cylinder_shape);
1282void update_rigidbody_shape(bullet::rigidbody& body, physics_component& comp)
1284 auto shape = make_rigidbody_shape(comp);
1286 body.internal->setCollisionShape(
shape.get());
1287 body.internal_shape =
shape;
1290void update_rigidbody_shape_scale(bullet::world& world, bullet::rigidbody& body,
const math::vec3& s)
1292 auto bt_scale = body.internal_shape->getLocalScaling();
1293 auto scale = bullet::from_bullet(bt_scale);
1295 if(math::any(math::epsilonNotEqual(
scale, s, math::epsilon<float>())))
1297 bt_scale = bullet::to_bullet(s);
1298 body.internal_shape->setLocalScaling(bt_scale);
1299 world.dynamics_world->updateSingleAabb(body.internal.get());
1304void update_rigidbody_kind(bullet::rigidbody& body, physics_component& comp)
1307 auto flags = body.internal->getCollisionFlags();
1308 auto rbFlags = body.internal->getFlags();
1310 if(comp.is_kinematic())
1313 flags |= btCollisionObject::CF_KINEMATIC_OBJECT;
1314 flags &= ~btCollisionObject::CF_DYNAMIC_OBJECT;
1316 body.internal->setCollisionFlags(flags);
1321 flags &= ~btCollisionObject::CF_KINEMATIC_OBJECT;
1322 flags |= btCollisionObject::CF_DYNAMIC_OBJECT;
1323 body.internal->setCollisionFlags(flags);
1327void update_rigidbody_constraints(bullet::rigidbody& body, physics_component& comp)
1330 auto freeze_position = comp.get_freeze_position();
1331 btVector3 linear_factor(
float(!freeze_position.x),
float(!freeze_position.y),
float(!freeze_position.z));
1332 body.internal->setLinearFactor(linear_factor);
1335 auto velocity = body.internal->getLinearVelocity();
1337 body.internal->setLinearVelocity(
velocity);
1340 auto freeze_rotation = comp.get_freeze_rotation();
1341 btVector3 angular_factor(
float(!freeze_rotation.x),
float(!freeze_rotation.y),
float(!freeze_rotation.z));
1342 body.internal->setAngularFactor(angular_factor);
1353void update_rigidbody_velocity(bullet::rigidbody& body, physics_component& comp)
1355 body.internal->setLinearVelocity(bullet::to_bullet(comp.get_velocity()));
1360void update_rigidbody_angular_velocity(bullet::rigidbody& body, physics_component& comp)
1362 body.internal->setAngularVelocity(bullet::to_bullet(comp.get_angular_velocity()));
1367void update_rigidbody_collision_layer(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1369 int filter_group = comp.get_owner().get<layer_component>().layers.mask;
1370 int filter_mask = comp.get_collision_mask().mask;
1371 body.collision_filter_group = filter_group;
1372 body.collision_filter_mask = filter_mask;
1380 btBroadphaseProxy* proxy = body.internal->getBroadphaseHandle();
1386 if(body.collision_filter_group != proxy->m_collisionFilterGroup ||
1387 body.collision_filter_mask != proxy->m_collisionFilterMask)
1390 world.dynamics_world->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(
1392 world.dynamics_world->getDispatcher());
1395 proxy->m_collisionFilterGroup = body.collision_filter_group;
1396 proxy->m_collisionFilterMask = body.collision_filter_mask;
1399 world.dynamics_world->refreshBroadphaseProxy(body.internal.get());
1404void update_rigidbody_mass_and_inertia(bullet::rigidbody& body, physics_component& comp)
1407 btVector3 local_inertia(0, 0, 0);
1408 if(!comp.is_kinematic())
1410 auto shape = body.internal->getCollisionShape();
1413 mass = comp.get_mass();
1414 shape->calculateLocalInertia(
mass, local_inertia);
1417 body.internal->setMassProps(
mass, local_inertia);
1420void update_rigidbody_gravity(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1422 if(comp.is_using_gravity())
1424 body.internal->setGravity(world.dynamics_world->getGravity());
1428 body.internal->setGravity(btVector3{0, 0, 0});
1429 body.internal->setLinearVelocity(btVector3(0, 0, 0));
1433void update_rigidbody_material(bullet::rigidbody& body, physics_component& comp)
1435 auto mat = comp.get_material().get();
1437 int packed = bullet::encode_combine_modes(mat->friction_combine, mat->restitution_combine);
1438 if(body.internal->getUserIndex2() != packed)
1440 body.internal->setUserIndex2(packed);
1443 if(math::epsilonNotEqual(body.internal->getRestitution(), mat->restitution, math::epsilon<float>()))
1445 body.internal->setRestitution(mat->restitution);
1447 if(math::epsilonNotEqual(body.internal->getFriction(), mat->friction, math::epsilon<float>()))
1449 body.internal->setFriction(mat->friction);
1452 auto stiffness = mat->get_stiffness();
1453 if(math::epsilonNotEqual(body.internal->getContactStiffness(), stiffness, math::epsilon<float>()) ||
1454 math::epsilonNotEqual(body.internal->getContactDamping(), mat->damping, math::epsilon<float>()))
1456 body.internal->setContactStiffnessAndDamping(stiffness, mat->damping);
1460void update_rigidbody_sensor(bullet::rigidbody& body, physics_component& comp)
1462 auto flags = body.internal->getCollisionFlags();
1463 if(comp.is_sensor())
1465 body.internal->setCollisionFlags(flags | btCollisionObject::CF_NO_CONTACT_RESPONSE);
1469 body.internal->setCollisionFlags(flags & ~btCollisionObject::CF_NO_CONTACT_RESPONSE);
1473void set_rigidbody_active(bullet::world& world, bullet::rigidbody& body,
bool enabled)
1477 world.add_rigidbody(body);
1481 world.remove_rigidbody(body);
1485void update_rigidbody_full(bullet::world& world, bullet::rigidbody& body, physics_component& comp)
1487 update_rigidbody_kind(body, comp);
1488 update_rigidbody_shape(body, comp);
1489 update_rigidbody_mass_and_inertia(body, comp);
1490 update_rigidbody_material(body, comp);
1491 update_rigidbody_sensor(body, comp);
1492 update_rigidbody_constraints(body, comp);
1493 update_rigidbody_velocity(body, comp);
1494 update_rigidbody_angular_velocity(body, comp);
1495 update_rigidbody_gravity(world, body, comp);
1496 update_rigidbody_collision_layer(world, body, comp);
1499void make_rigidbody(bullet::world& world, entt::handle
entity, physics_component& comp)
1501 auto& body =
entity.emplace<bullet::rigidbody>();
1503 body.internal = std::make_shared<btRigidBody>(comp.get_mass(),
nullptr,
nullptr);
1504 body.internal->setUserIndex(
int(
entity.entity()));
1505 body.internal->setUserPointer(&world);
1506 body.internal->setFlags(BT_DISABLE_WORLD_GRAVITY);
1508 update_rigidbody_full(world, body, comp);
1510 if(
entity.all_of<active_component>())
1512 world.add_rigidbody(body);
1516void destroy_phyisics_body(bullet::world& world, entt::handle
entity,
bool from_physics_component)
1518 auto body =
entity.try_get<bullet::rigidbody>();
1520 if(body && body->internal)
1522 world.remove_rigidbody(*body);
1525 if(from_physics_component)
1527 entity.remove<bullet::rigidbody>();
1531void sync_physics_body(bullet::world& world, physics_component& comp,
bool force =
false)
1533 auto owner = comp.get_owner();
1537 destroy_phyisics_body(world, comp.get_owner(),
true);
1538 make_rigidbody(world, owner, comp);
1542 auto& body = owner.get<bullet::rigidbody>();
1546 set_rigidbody_active(world, body,
false);
1547 update_rigidbody_full(world, body, comp);
1548 set_rigidbody_active(world, body,
true);
1555 update_rigidbody_shape(body, comp);
1556 world.dynamics_world->updateSingleAabb(body.internal.get());
1560 update_rigidbody_mass_and_inertia(body, comp);
1565 update_rigidbody_sensor(body, comp);
1570 update_rigidbody_constraints(body, comp);
1575 update_rigidbody_velocity(body, comp);
1579 update_rigidbody_angular_velocity(body, comp);
1584 update_rigidbody_gravity(world, body, comp);
1588 update_rigidbody_material(body, comp);
1589 update_rigidbody_collision_layer(world, body, comp);
1592 if(!comp.is_kinematic())
1594 if(comp.are_any_properties_dirty())
1601 comp.set_dirty(system_id,
false);
1604auto sync_transforms(bullet::world& world, physics_component& comp,
const transform_component& transform) ->
bool
1606 auto owner = comp.get_owner();
1607 auto& body = owner.get<bullet::rigidbody>();
1614 const auto&
p =
transform.get_position_global();
1615 const auto&
q =
transform.get_rotation_global();
1616 const auto&
s =
transform.get_scale_global();
1618 auto bt_pos = bullet::to_bullet(p);
1619 auto bt_rot = bullet::to_bullet(q);
1620 btTransform bt_trans(bt_rot, bt_pos);
1621 body.internal->setWorldTransform(bt_trans);
1623 if(body.internal_shape && comp.is_autoscaled())
1625 update_rigidbody_shape_scale(world, body, s);
1633auto sync_state(physics_component& comp) ->
bool
1635 auto owner = comp.get_owner();
1636 auto body = owner.try_get<bullet::rigidbody>();
1638 if(!body || !body->internal)
1643 if(!body->internal->isActive())
1648 comp.set_velocity(bullet::from_bullet(body->internal->getLinearVelocity()));
1649 comp.set_angular_velocity(bullet::from_bullet(body->internal->getAngularVelocity()));
1654auto sync_transforms(physics_component& comp, transform_component& transform) ->
bool
1656 auto owner = comp.get_owner();
1657 auto body = owner.try_get<bullet::rigidbody>();
1659 if(!body || !body->internal)
1664 if(!body->internal->isActive())
1669 const auto& bt_trans = body->internal->getWorldTransform();
1670 auto p = bullet::from_bullet(bt_trans.getOrigin());
1671 auto q = bullet::from_bullet(bt_trans.getRotation());
1675 float epsilon = 0.009f;
1676 return transform.set_position_and_rotation_global(p, q, epsilon);
1679auto to_physics(bullet::world& world, transform_component& transform, physics_component& comp) ->
bool
1681 bool transform_dirty =
transform.is_dirty(system_id);
1682 bool rigidbody_dirty = comp.is_dirty(system_id);
1686 sync_physics_body(world, comp);
1689 if(transform_dirty || rigidbody_dirty)
1691 return sync_transforms(world, comp, transform);
1697auto from_physics(bullet::world& world, transform_component& transform, physics_component& comp) ->
bool
1701 bool result = sync_transforms(comp, transform);
1704 comp.set_dirty(system_id,
false);
1709auto add_force(btRigidBody* body,
const btVector3&
force,
force_mode mode) ->
bool
1711 if(
force.fuzzyZero())
1719 body->applyCentralForce(
force);
1724 btVector3 acceleration_force =
force * body->getMass();
1725 body->applyCentralForce(acceleration_force);
1730 body->applyCentralImpulse(
force);
1735 btVector3 new_velocity = body->getLinearVelocity() +
force;
1736 body->setLinearVelocity(new_velocity);
1743auto add_torque(btRigidBody* body,
const btVector3& torque,
force_mode mode) ->
bool
1745 if(torque.fuzzyZero())
1753 body->applyTorque(torque);
1758 btVector3 inertia_tensor = body->getInvInertiaDiagLocal();
1759 btVector3 angular_acceleration(
1760 inertia_tensor.getX() != 0 ? torque.getX() * (1.0f / inertia_tensor.getX()) : 0.0f,
1761 inertia_tensor.getY() != 0 ? torque.getY() * (1.0f / inertia_tensor.getY()) : 0.0f,
1762 inertia_tensor.getZ() != 0 ? torque.getZ() * (1.0f / inertia_tensor.getZ()) : 0.0f);
1763 body->applyTorque(angular_acceleration);
1768 body->applyTorqueImpulse(torque);
1773 btVector3 new_velocity = body->getLinearVelocity() + torque;
1774 body->setAngularVelocity(new_velocity);
1786 bullet::setup_task_scheduler();
1787 bullet::override_combine_callbacks();
1792 bullet::cleanup_task_scheduler();
1798 auto world = r.ctx().find<bullet::world>();
1801 entt::handle
entity(r, e);
1803 sync_physics_body(*world, phisics,
true);
1810 auto world = r.ctx().find<bullet::world>();
1813 entt::handle
entity(r, e);
1814 destroy_phyisics_body(*world,
entity,
true);
1821 auto world = r.ctx().find<bullet::world>();
1824 entt::handle
entity(r, e);
1825 destroy_phyisics_body(*world,
entity,
false);
1832 auto world = r.ctx().find<bullet::world>();
1835 entt::handle
entity(r, e);
1836 auto body =
entity.try_get<bullet::rigidbody>();
1839 set_rigidbody_active(*world, *body,
true);
1847 auto world = r.ctx().find<bullet::world>();
1850 entt::handle
entity(r, e);
1851 auto body =
entity.try_get<bullet::rigidbody>();
1854 set_rigidbody_active(*world, *body,
false);
1860 float explosion_force,
1861 const math::vec3& explosion_position,
1862 float explosion_radius,
1863 float upwards_modifier,
1868 if(
auto bbody = owner.try_get<bullet::rigidbody>())
1870 const auto& body = bbody->internal;
1873 if(body && body->getInvMass() > 0)
1876 btVector3 body_position = body->getWorldTransform().getOrigin();
1879 btVector3 direction = body_position - bullet::to_bullet(explosion_position);
1880 float distance = direction.length();
1883 if(
distance > explosion_radius && explosion_radius > 0.0f)
1895 direction.setZero();
1899 if(upwards_modifier != 0.0f)
1901 direction.setY(direction.getY() + upwards_modifier);
1902 direction.normalize();
1906 float attenuation = 1.0f - (
distance / explosion_radius);
1907 btVector3
force = direction * explosion_force * attenuation;
1909 if(add_force(body.get(),
force, mode))
1911 comp.
set_velocity(bullet::from_bullet(body->getLinearVelocity()));
1923 if(
auto bbody = owner.try_get<bullet::rigidbody>())
1925 const auto& body = bbody->internal;
1926 auto vector = bullet::to_bullet(
force);
1928 if(add_force(body.get(), vector, mode))
1930 comp.
set_velocity(bullet::from_bullet(body->getLinearVelocity()));
1940 if(
auto bbody = owner.try_get<bullet::rigidbody>())
1942 auto vector = bullet::to_bullet(torque);
1943 const auto& body = bbody->internal;
1945 if(add_torque(body.get(), vector, mode))
1959 if(
auto bbody = owner.try_get<bullet::rigidbody>())
1961 bbody->internal->clearForces();
1963 comp.
set_velocity(bullet::from_bullet(bbody->internal->getLinearVelocity()));
1972 const math::vec3& direction,
1978 auto& ec = ctx.get_cached<
ecs>();
1979 auto& registry = *ec.get_scene().registry;
1981 auto& world = registry.ctx().get<bullet::world>();
1987 const math::vec3& direction,
1993 auto& ec = ctx.get_cached<
ecs>();
1994 auto& registry = *ec.get_scene().registry;
1996 auto& world = registry.ctx().get<bullet::world>();
2002 const math::vec3& direction,
2009 auto& ec = ctx.get_cached<
ecs>();
2010 auto& registry = *ec.get_scene().registry;
2012 auto& world = registry.ctx().get<bullet::world>();
2018 const math::vec3& direction,
2025 auto& ec = ctx.get_cached<
ecs>();
2026 auto& registry = *ec.get_scene().registry;
2028 auto& world = registry.ctx().get<bullet::world>();
2037 auto& ec = ctx.get_cached<
ecs>();
2038 auto& registry = *ec.get_scene().registry;
2040 auto& world = registry.ctx().get<bullet::world>();
2048 auto& scn = ec.get_scene();
2049 auto& registry = *scn.registry;
2051 auto& world = registry.ctx().emplace<bullet::world>(bullet::create_dynamics_world());
2053 registry.on_destroy<bullet::rigidbody>().connect<&on_destroy_bullet_rigidbody_component>();
2054 registry.on_construct<
active_component>().connect<&on_create_active_component>();
2055 registry.on_destroy<
active_component>().connect<&on_destroy_active_component>();
2058 [&](
auto e,
auto&& comp)
2060 sync_physics_body(world, comp,
true);
2067 auto& registry = *ec.get_scene().registry;
2069 auto& world = registry.ctx().get<bullet::world>();
2072 [&](
auto e,
auto&& comp)
2074 destroy_phyisics_body(world, comp.get_owner(),
true);
2077 registry.on_construct<
active_component>().disconnect<&on_create_active_component>();
2078 registry.on_destroy<
active_component>().disconnect<&on_destroy_active_component>();
2079 registry.on_destroy<bullet::rigidbody>().disconnect<&on_destroy_bullet_rigidbody_component>();
2081 registry.ctx().erase<bullet::world>();
2103 auto& registry = *ec.get_scene().registry;
2104 auto& world = registry.ctx().get<bullet::world>();
2106 if(dt > delta_t::zero())
2108 float fixed_time_step = 1.0f / 50.0f;
2109 int max_subs_steps = 3;
2115 max_subs_steps = ss.time.max_fixed_steps;
2119 world.elapsed += dt.count();
2122 while(world.elapsed >= fixed_time_step && steps < max_subs_steps)
2124 delta_t step_dt(fixed_time_step);
2125 ev.on_frame_fixed_update(ctx, step_dt);
2128 uint64_t physics_entities{};
2129 uint64_t physics_entities_synced{};
2132 [&](
auto e,
auto&& transform,
auto&& rigidbody,
auto&& active_comp)
2135 if(to_physics(world, transform, rigidbody))
2137 physics_entities_synced++;
2145 world.simulate(fixed_time_step, fixed_time_step, 1);
2147 physics_entities = {};
2148 physics_entities_synced = {};
2151 [&](
auto e,
auto&& transform,
auto&& rigidbody,
auto&& active_comp)
2154 if(from_physics(world, transform, rigidbody))
2156 physics_entities_synced++;
2164 world.process_manifolds();
2166 world.elapsed -= fixed_time_step;
2175 auto& registry = *ec.get_scene().registry;
2176 auto world = registry.ctx().find<bullet::world>();
2179 bullet::debugdraw drawer(dd);
2180 world->dynamics_world->setDebugDrawer(&drawer);
2182 world->dynamics_world->debugDrawWorld();
2184 world->dynamics_world->setDebugDrawer(
nullptr);
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< 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
unravel::physics_vector< contact_manifold > to_enter
Class representing a camera. Contains functionality for manipulating and updating a camera....
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 end(encoder *_encoder)
auto start(seq_action action, const seq_scope_policy &scope_policy, hpp::source_location location) -> seq_id_t
Starts a new action.
@ sphere
Sphere type reflection probe.
hpp::small_vector< T, SmallSizeCapacity > physics_vector
auto to_bx(const glm::vec3 &data) -> bx::Vec3
void lineTo(float _x, float _y, float _z=0.0f)
void setColor(uint32_t _abgr)
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_component(entt::registry &r, entt::entity e)
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 on_destroy_active_component(entt::registry &r, entt::entity e)
void on_resume(rtti::context &ctx)
void on_pause(rtti::context &ctx)
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 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)
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_sensor_exit(entt::handle sensor, entt::handle other)
void on_sensor_enter(entt::handle sensor, entt::handle other)
void on_collision_exit(entt::handle a, entt::handle b, const std::vector< manifold_point > &manifolds)
struct unravel::settings::time_settings time