1#include "RigidBodySystem.h"
3#include "PhysicsManager.h"
5#include "Systems/Core/TransformSystem.h"
9#include "Services/Services.h"
10#include "Services/Time.h"
12#include "EntityStore.h"
13#include "Components/Core/MotionComponent.h"
15#include "CollisionComponent.h"
17#include "Platform/Instrumentation.h"
19#include "Foundation/Logging/Logger.h"
21#include <glm/gtc/type_ptr.hpp>
22#include <glm/gtx/matrix_decompose.hpp>
33 void updateMassProperties(RigidBodyData & data,
float mass,
const glm::vec3 & scale)
35 const float margin = scale.x < scale.y && scale.x < scale.z ? scale.x : (scale.y < scale.z ? scale.y : scale.z);
36 const float marginMultiplier = 0.1f;
38 data.collisionShape->setLocalScaling(toBullet(scale));
40 auto diff = scale - glm::vec3(1, 1, 1);
42 if (glm::any(glm::greaterThan(glm::abs(diff), glm::vec3(0.01f, 0.01f, 0.01f)))) {
43 data.collisionShape->setMargin(margin * marginMultiplier);
48 if (data.collisionShape->getShapeType() != EMPTY_SHAPE_PROXYTYPE) data.collisionShape->calculateLocalInertia(mass, inertia);
52 data.rigidBody->setMassProps(mass, inertia);
53 data.rigidBody->updateInertiaTensor();
70 if (pool.size() && glm::any(glm::notEqual(context->transformSystem->
getOrigin(), glm::dvec3(0, 0, 0)))) {
71 LOG_ERROR(logger,
"Physics not supported using global origin.");
77 auto elapsed = context->
time->getAnimationTimeDelta();
79 for (
auto & c : pool) {
80 if (!c.isActive())
continue;
82 auto & data = getData(&c);
86 if (!data.rigidBody) {
89 if (!collisionComponent || !collisionComponent->collisionShape) {
92 data.collisionShape = collisionComponent->collisionShape;
94 context->transformSystem->updateLocalToWorldTransform(*transformComponent,
true);
95 auto worldTransform = context->transformSystem->getLocalToWorld(transformComponent);
97 auto scale = glm::vec3(glm::length(worldTransform[0]), glm::length(worldTransform[1]), glm::length(worldTransform[2]));
98 auto rotation = glm::normalize(glm::quat_cast(glm::mat3(worldTransform * glm::scale(glm::vec3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z)))));
99 auto position = glm::vec3(worldTransform[3]);
102 updateMassProperties(data, c.mass, scale);
104 btVector3 localInertia(0, 0, 0);
107 if (data.collisionShape->getShapeType() != EMPTY_SHAPE_PROXYTYPE) data.collisionShape->calculateLocalInertia(c.mass, localInertia);
110 const btTransform origin(toBullet(rotation), toBullet(position));
112 data.lastPosition = position;
114 data.motionState = std::make_unique<btDefaultMotionState>(origin);
116 btRigidBody::btRigidBodyConstructionInfo ci(c.mass, data.motionState.get(), data.collisionShape, localInertia);
118 ci.m_friction = c.friction;
119 ci.m_rollingFriction = c.rollingFriction;
120 ci.m_spinningFriction = c.spinningFriction;
121 ci.m_linearDamping = c.linearDamping;
122 ci.m_angularDamping = c.angularDamping;
123 ci.m_restitution = c.restitution;
125 data.rigidBody = std::make_unique<btRigidBody>(ci);
126 data.rigidBody->setCcdMotionThreshold(c.ccdMotionThreshold);
127 data.rigidBody->setCcdSweptSphereRadius(c.ccdSweptSphereRadius);
128 data.rigidBody->setLinearFactor(toBullet(c.linearFactor));
129 data.rigidBody->setAngularFactor(toBullet(c.angularFactor));
130 data.shared = std::make_unique<SharedRigidBodyData>();
131 data.shared->entity = context->
store->
getEntity(c.getContainer()->getId());
132 data.rigidBody->setUserPointer(data.shared.get());
133 data.kinematic = c.kinematic;
135 auto flags = data.rigidBody->getCollisionFlags();
136 flags |= c.kinematic ? btCollisionObject::CF_KINEMATIC_OBJECT : 0;
139 data.rigidBody->setActivationState(DISABLE_DEACTIVATION);
142 data.rigidBody->setCollisionFlags(flags);
144 manager->addRigidBody(data.rigidBody.get());
147 if (!data.rigidBody)
continue;
149 if (c.kinematic != data.kinematic) {
150 manager->removeRigidBody(data.rigidBody.get());
152 auto flags = data.rigidBody->getCollisionFlags();
155 flags |= btCollisionObject::CF_KINEMATIC_OBJECT;
156 data.rigidBody->setActivationState(DISABLE_DEACTIVATION);
158 flags &= ~btCollisionObject::CF_KINEMATIC_OBJECT;
159 data.rigidBody->activate(
true);
161 context->transformSystem->updateLocalToWorldTransform(*transformComponent,
true);
162 auto worldTransform = context->transformSystem->getLocalToWorld(transformComponent);
164 auto scale = glm::vec3(glm::length(worldTransform[0]), glm::length(worldTransform[1]), glm::length(worldTransform[2]));
166 if (glm::any(glm::greaterThan(glm::abs(scale - data.scale), glm::vec3(0.001f)))) {
167 updateMassProperties(data, c.mass, scale);
171 data.rigidBody->setCollisionFlags(flags);
172 data.kinematic = c.kinematic;
174 manager->addRigidBody(data.rigidBody.get());
178 auto motionState =
static_cast<btDefaultMotionState *
>(data.motionState.get());
180 context->transformSystem->updateLocalToWorldTransform(*transformComponent,
true);
181 const auto & worldTransform = context->transformSystem->getLocalToWorld(transformComponent);
183 const auto scale = glm::vec3(glm::length(worldTransform[0]), glm::length(worldTransform[1]), glm::length(worldTransform[2]));
184 const auto rotation = glm::normalize(glm::quat_cast(glm::mat3(worldTransform * glm::scale(glm::vec3(1.0f / scale.x, 1.0f / scale.y, 1.0f / scale.z)))));
185 const auto position = glm::vec3(worldTransform[3]);
187 if (glm::any(glm::greaterThan(glm::abs(scale - data.scale), glm::vec3(0.001f)))) {
188 manager->removeRigidBody(data.rigidBody.get());
189 updateMassProperties(data, c.mass, scale);
190 manager->addRigidBody(data.rigidBody.get());
193 const btTransform origin(toBullet(rotation), toBullet(position));
195 motionState->setWorldTransform(origin);
199 if(motionComponent !=
nullptr) {
200 data.rigidBody->setLinearVelocity(toBullet(motionComponent->velocity));
201 data.rigidBody->setAngularVelocity(toBullet(motionComponent->angularVelocity));
204 glm::vec3 deltaPosition = position - data.lastPosition;
205 glm::vec3 velocity = deltaPosition /
static_cast<float>(elapsed);
206 data.rigidBody->setLinearVelocity(toBullet(velocity));
209 data.lastPosition = position;
211 btTransform transform;
212 data.motionState->getWorldTransform(transform);
214 auto btOrigin = transform.getOrigin();
215 auto btRotation = transform.getRotation();
217 transformComponent->position = *
reinterpret_cast<const glm::vec3 *
>(&btOrigin);
218 transformComponent->rotation = *
reinterpret_cast<const glm::quat *
>(&btRotation);
219 transformComponent->setChanged();
222 if (motionComponent !=
nullptr) {
223 motionComponent->
angularVelocity = *
reinterpret_cast<const glm::vec3 *
>(&data.rigidBody->getAngularVelocity());
224 motionComponent->velocity = *
reinterpret_cast<const glm::vec3 *
>(&data.rigidBody->getLinearVelocity());
225 motionComponent->setChanged();
234 manager->postUpdate(context);
235 base::postUpdate(context);
241 manager->waitForASync(context);
244 auto & data = getData(c);
246 if (data.rigidBody) {
247 manager->removeRigidBody(data.rigidBody.get());
250 base::destroyComponent(component);
ComponentType * getComponent() const
Context * context
Pointer to the Context instance the system lives in.
void postUpdate()
Perform post update logic in the system.
void update()
Updates the system state to that of the current frame.
void preUpdate()
Run the pre-update method of the system.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class Services > services
Services.
class EntityStore * store
Entity store.
std::unique_ptr< class Time > time
Time service instance.
EntityPtr getEntity(const StringView &name, bool logIfNotFound=true) const
Retrieve a reference to the shared entity pointer to the Entity with the given name.
void destroyComponent(ComponentHandle component) final
Log implementation class.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
Handle to a Component instance.
ComponentType * resolveComponent() const
glm::vec3 angularVelocity
Angular velocity.