From e22424b7d71ef833d6ca6e61dd788b919fff6d6b Mon Sep 17 00:00:00 2001 From: Joseph Walton-Rivers <joseph@walton-rivers.uk> Date: Sun, 24 Apr 2022 19:13:14 +0100 Subject: [PATCH] test scene using bullet physics --- demo/demo/rollball.cpp | 22 +++++++---- fggl/phys/bullet/simulation.cpp | 57 ++++++++++++++++++++++++++--- fggl/scenes/game.cpp | 2 + include/fggl/math/types.hpp | 9 +++++ include/fggl/phys/bullet/bullet.hpp | 1 + include/fggl/phys/types.hpp | 39 +++++++++++++++++++- 6 files changed, 116 insertions(+), 14 deletions(-) diff --git a/demo/demo/rollball.cpp b/demo/demo/rollball.cpp index 4146ccd..24b50bf 100644 --- a/demo/demo/rollball.cpp +++ b/demo/demo/rollball.cpp @@ -46,6 +46,10 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) { auto transform = glm::scale(fggl::data::OFFSET_NONE, {1.0f, 5.f, 41.0f}); fggl::data::make_cube(meshComponent.mesh, transform ); world.set<fggl::data::StaticMesh>(prefabs.wallX, &meshComponent); + + auto* rb = world.add<fggl::phys::RigidBody>(prefabs.wallX); + rb->mass = fggl::phys::MASS_STATIC; // flag the object as static + rb->shape = new fggl::phys::Box({0.5F, 2.5F, 20.5F}); } { @@ -60,6 +64,10 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) { auto transform = glm::scale(fggl::data::OFFSET_NONE, {39.f, 5.f, 1.0f}); fggl::data::make_cube(meshComponent.mesh, transform ); world.set<fggl::data::StaticMesh>(prefabs.wallZ, &meshComponent); + + auto* rb = world.add<fggl::phys::RigidBody>(prefabs.wallZ); + rb->mass = fggl::phys::MASS_STATIC; // flag the object as static + rb->shape = new fggl::phys::Box({39.0F / 2, 2.5F, 0.5F}); } { @@ -67,18 +75,18 @@ static void setupPrefabs(fggl::ecs3::World& world, Prefabs& prefabs) { prefabs.floor = world.create(true); world.add<fggl::math::Transform>(prefabs.floor); - auto* rb = world.add<fggl::phys::RigidBody>(prefabs.floor); - rb->mass = fggl::phys::STATIC_MASS; - + // create a procedural cube, but scale it to be plane-like + // TODO proper planes fggl::data::StaticMesh meshComponent; meshComponent.pipeline = "phong"; - - // create a procedural cube, but scale the model to be a long wall auto transform = glm::scale(fggl::data::OFFSET_NONE, {40.f, 0.5f, 40.0f}); - - // TODO proper planes fggl::data::make_cube(meshComponent.mesh, transform ); world.set<fggl::data::StaticMesh>(prefabs.floor, &meshComponent); + + // physics: a static cube + auto* rb = world.add<fggl::phys::RigidBody>(prefabs.floor); + rb->mass = fggl::phys::MASS_STATIC; // flag the object as static + rb->shape = new fggl::phys::Box({20.0F, 0.5F, 20.0F}); } { diff --git a/fggl/phys/bullet/simulation.cpp b/fggl/phys/bullet/simulation.cpp index bfd1f1e..381ac73 100644 --- a/fggl/phys/bullet/simulation.cpp +++ b/fggl/phys/bullet/simulation.cpp @@ -48,7 +48,33 @@ namespace fggl::phys::bullet { auto myRot = myState->euler(); btQuaternion rotation; rotation.setEulerZYX(myRot.x, myRot.y, myRot.z); - btState->motion = new btDefaultMotionState(btTransform(rotation, position)); + + btTransform transform; + transform.setIdentity(); + transform.setRotation(rotation); + transform.setOrigin(position); + + btState->motion = new btDefaultMotionState(transform); + } + + inline btCollisionShape* shapeToBullet(const phys::RigidBody* fgglBody) { + if ( fgglBody->shape == nullptr ) { + // they forgot to put a shape, we'll assume a unit sphere to avoid crashes... + return new btSphereShape(0.5f); + } + + switch (fgglBody->shape->type) { + case phys::ShapeType::BOX: { + auto extents = ((phys::Box*)fgglBody->shape)->extents; + return new btBoxShape({extents.x, extents.y, extents.z}); + } + case phys::ShapeType::SPHERE: { + float radius = ((phys::Sphere*)fgglBody->shape)->radius; + return new btSphereShape(radius); + } + default: + return new btSphereShape(0.5f); + } } void BulletPhysicsEngine::checkForPhys() { @@ -62,22 +88,38 @@ namespace fggl::phys::bullet { } btComp = m_ecs->add<BulletBody>(ent); - auto fgBody = m_ecs->get<phys::RigidBody>(ent); + const auto* fgBody = m_ecs->get<phys::RigidBody>(ent); // setup the starting motion state auto* transform = m_ecs->get<math::Transform>(ent); build_motation_state(transform, btComp); + btCollisionShape* colShape = shapeToBullet(fgBody); + btVector3 localInt(0, 0, 0); + if ( !fgBody->isStatic() ) { + colShape->calculateLocalInertia(fgBody->mass, localInt); + } + // setup the construction information - // FIXME the world shouldn't be made only of unit spheres... - btSphereShape* shape = new btSphereShape(0.5f); btRigidBody::btRigidBodyConstructionInfo bodyCI( fgBody->mass, btComp->motion, - shape + colShape, + localInt ); btComp->body = new btRigidBody(bodyCI); + + if (!fgBody->isStatic()) { + // FIXME this is for testing, needs to be removed + btComp->body->setRestitution(0.5f); + btComp->body->setRollingFriction(0.0f); + } m_world->addRigidBody(btComp->body); + + if ( !fgBody->isStatic() ) { + btComp->body->applyTorque({50.0f, 0.5f, 0.5f}); + btComp->body->applyImpulse({5.0f, 0.5f, 0.5f}, {0.0f, 0.0f, 0.0f}); + } } } @@ -94,6 +136,11 @@ namespace fggl::phys::bullet { auto& btPos = bTransform.getOrigin(); math::vec3 pos{btPos.x(), btPos.y(), btPos.z()}; transform->origin( pos ); + + // set the rotation + const auto& btRot = bTransform.getRotation(); + math::quat rot{btRot.x(), btRot.y(), btRot.z(), btRot.w()}; + transform->setRotation(rot); } } diff --git a/fggl/scenes/game.cpp b/fggl/scenes/game.cpp index 0cf1717..92aace6 100644 --- a/fggl/scenes/game.cpp +++ b/fggl/scenes/game.cpp @@ -38,6 +38,8 @@ namespace fggl::scenes { // setup the scene m_world = std::make_unique<ecs3::World>(*m_owner.registry()); + + // FIXME this ties bullet to the game state - which shouldn't be the case m_phys = std::make_unique<phys::bullet::BulletPhysicsEngine>(m_world.get()); } diff --git a/include/fggl/math/types.hpp b/include/fggl/math/types.hpp index 70f2a22..4639d48 100644 --- a/include/fggl/math/types.hpp +++ b/include/fggl/math/types.hpp @@ -22,6 +22,7 @@ namespace fggl::math { constexpr float HALF_PI = M_PI_2; constexpr float TAU = PI * 2; + // math types (aliased for ease of use) using vec4 = glm::vec4; using vec4f = glm::vec4; @@ -43,6 +44,9 @@ namespace fggl::math { using mat4 = glm::mat4; using quat = glm::quat; + constexpr static const math::vec2 VEC2_ZERO {0.0F, 0.0F}; + constexpr static const math::vec3 VEC3_ZERO {0.0F, 0.0F, 0.0F}; + // fastFloor from OpenSimplex2 inline int fastFloor(double x) { int xi = (int) x; @@ -120,6 +124,11 @@ namespace fggl::math { return m_origin; } + void setRotation(const math::quat& newRot) { + m_rotation = newRot; + update(); + } + inline void rotate(math::vec3 axis, float angle) { // documentation claims this is in degrees, based on experimentation this actually appears to be radians... m_rotation = glm::rotate(m_rotation, angle, axis); diff --git a/include/fggl/phys/bullet/bullet.hpp b/include/fggl/phys/bullet/bullet.hpp index e5d301f..d377796 100644 --- a/include/fggl/phys/bullet/bullet.hpp +++ b/include/fggl/phys/bullet/bullet.hpp @@ -51,6 +51,7 @@ namespace fggl::phys::bullet { void onLoad(ecs3::ModuleManager &manager, ecs3::TypeRegistry &types) override { // dependencies types.make<phys::RigidBody>(); + types.make<phys::Dynamics>(); // my types types.make<phys::bullet::BulletBody>(); diff --git a/include/fggl/phys/types.hpp b/include/fggl/phys/types.hpp index 8ae73b6..4f06ade 100644 --- a/include/fggl/phys/types.hpp +++ b/include/fggl/phys/types.hpp @@ -26,11 +26,46 @@ #define FGGL_PHYS_TYPES_HPP namespace fggl::phys { - constexpr float STATIC_MASS = 0.0F; + constexpr float MASS_STATIC = 0.0F; + constexpr float MASS_DEFAULT = 1.0F; + + enum class ShapeType { + UNSET, + BOX, + SPHERE + }; + + struct PhyShape { + math::vec3 offset = math::VEC3_ZERO; + const ShapeType type; + + inline PhyShape(ShapeType typ) : type(typ) {} + }; + + struct Box : public PhyShape { + math::vec3 extents; + explicit inline Box(math::vec3 ext) : PhyShape(ShapeType::BOX), extents(ext) {} + }; + + struct Sphere : public PhyShape { + float radius = 1.0F; + explicit inline Sphere(float rad) : PhyShape(ShapeType::SPHERE), radius(rad) {} + }; struct RigidBody { constexpr static const char* name = "phys::Body"; - float mass = 1.0F; + float mass = MASS_DEFAULT; + PhyShape* shape = nullptr; + + [[nodiscard]] + inline bool isStatic() const { + return mass == MASS_STATIC; + } + }; + + struct Dynamics { + constexpr static const char* name = "phys::Dynamics"; + math::vec3 force = math::VEC3_ZERO; }; class PhysicsEngine { -- GitLab