Example physics implemented.
This commit is contained in:
9
src/dawn/physics/CMakeLists.txt
Normal file
9
src/dawn/physics/CMakeLists.txt
Normal file
@@ -0,0 +1,9 @@
|
||||
# Copyright (c) 2024 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
PhysicsManager.cpp
|
||||
)
|
325
src/dawn/physics/PhysicsManager.cpp
Normal file
325
src/dawn/physics/PhysicsManager.cpp
Normal file
@@ -0,0 +1,325 @@
|
||||
// Copyright (c) 2024 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include "PhysicsManager.hpp"
|
||||
#include "game/Game.hpp"
|
||||
#include "scene/Scene.hpp"
|
||||
#include "component/physics/Collider.hpp"
|
||||
|
||||
using namespace Dawn;
|
||||
using namespace JPH;
|
||||
using namespace JPH::literals;
|
||||
|
||||
static void TraceImpl(const char *inFMT, ...) {
|
||||
// Format the message
|
||||
va_list list;
|
||||
va_start(list, inFMT);
|
||||
char buffer[1024];
|
||||
vsnprintf(buffer, sizeof(buffer), inFMT, list);
|
||||
va_end(list);
|
||||
|
||||
// Print to the TTY
|
||||
// std::cout << buffer << std::endl;
|
||||
}
|
||||
|
||||
#ifdef JPH_ENABLE_ASSERTS
|
||||
static bool AssertFailedImpl(
|
||||
const char *inExpression,
|
||||
const char *inMessage,
|
||||
const char *inFile,
|
||||
uint inLine
|
||||
) {
|
||||
// Print to the TTY
|
||||
std::cout << inFile << ":" << inLine << ": (" << inExpression << ") " << (inMessage != nullptr? inMessage : "") << std::endl;
|
||||
|
||||
// Breakpoint
|
||||
return true;
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace Layers {
|
||||
static constexpr ObjectLayer NON_MOVING = 0;
|
||||
static constexpr ObjectLayer MOVING = 1;
|
||||
static constexpr ObjectLayer NUM_LAYERS = 2;
|
||||
};
|
||||
|
||||
/// Class that determines if two object layers can collide
|
||||
class ObjectLayerPairFilterImpl : public ObjectLayerPairFilter {
|
||||
public:
|
||||
virtual bool ShouldCollide(
|
||||
ObjectLayer inObject1,
|
||||
ObjectLayer inObject2
|
||||
) const override {
|
||||
switch (inObject1) {
|
||||
case Layers::NON_MOVING:
|
||||
return inObject2 == Layers::MOVING;
|
||||
case Layers::MOVING:
|
||||
return true;
|
||||
default:
|
||||
JPH_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
namespace BroadPhaseLayers {
|
||||
static constexpr BroadPhaseLayer NON_MOVING(0);
|
||||
static constexpr BroadPhaseLayer MOVING(1);
|
||||
static constexpr uint NUM_LAYERS(2);
|
||||
};
|
||||
|
||||
|
||||
class BPLayerInterfaceImpl final : public BroadPhaseLayerInterface {
|
||||
public:
|
||||
BPLayerInterfaceImpl() {
|
||||
mObjectToBroadPhase[Layers::NON_MOVING] = BroadPhaseLayers::NON_MOVING;
|
||||
mObjectToBroadPhase[Layers::MOVING] = BroadPhaseLayers::MOVING;
|
||||
}
|
||||
|
||||
virtual uint GetNumBroadPhaseLayers() const override {
|
||||
return BroadPhaseLayers::NUM_LAYERS;
|
||||
}
|
||||
|
||||
virtual BroadPhaseLayer GetBroadPhaseLayer(
|
||||
ObjectLayer inLayer
|
||||
) const override {
|
||||
JPH_ASSERT(inLayer < Layers::NUM_LAYERS);
|
||||
return mObjectToBroadPhase[inLayer];
|
||||
}
|
||||
|
||||
#if defined(JPH_EXTERNAL_PROFILE) || defined(JPH_PROFILE_ENABLED)
|
||||
virtual const char * GetBroadPhaseLayerName(
|
||||
BroadPhaseLayer inLayer
|
||||
) const override {
|
||||
switch ((BroadPhaseLayer::Type)inLayer) {
|
||||
case (BroadPhaseLayer::Type)BroadPhaseLayers::NON_MOVING:
|
||||
return "NON_MOVING";
|
||||
case (BroadPhaseLayer::Type)BroadPhaseLayers::MOVING:
|
||||
return "MOVING";
|
||||
default:
|
||||
JPH_ASSERT(false); return "INVALID";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
BroadPhaseLayer mObjectToBroadPhase[Layers::NUM_LAYERS];
|
||||
};
|
||||
|
||||
class ObjectVsBroadPhaseLayerFilterImpl : public ObjectVsBroadPhaseLayerFilter {
|
||||
public:
|
||||
virtual bool ShouldCollide(
|
||||
ObjectLayer inLayer1,
|
||||
BroadPhaseLayer inLayer2
|
||||
) const override {
|
||||
switch (inLayer1) {
|
||||
case Layers::NON_MOVING:
|
||||
return inLayer2 == BroadPhaseLayers::MOVING;
|
||||
case Layers::MOVING:
|
||||
return true;
|
||||
default:
|
||||
JPH_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// An example contact listener
|
||||
class MyContactListener : public ContactListener {
|
||||
public:
|
||||
// See: ContactListener
|
||||
virtual ValidateResult OnContactValidate(
|
||||
const Body &inBody1,
|
||||
const Body &inBody2,
|
||||
RVec3Arg inBaseOffset,
|
||||
const CollideShapeResult &inCollisionResult
|
||||
) override {
|
||||
// std::cout << "Contact validate callback" << std::endl;
|
||||
return ValidateResult::AcceptAllContactsForThisBodyPair;
|
||||
}
|
||||
|
||||
virtual void OnContactAdded(
|
||||
const Body &inBody1,
|
||||
const Body &inBody2,
|
||||
const ContactManifold &inManifold,
|
||||
ContactSettings &ioSettings
|
||||
) override {
|
||||
// std::cout << "A contact was added" << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnContactPersisted(
|
||||
const Body &inBody1,
|
||||
const Body &inBody2,
|
||||
const ContactManifold &inManifold,
|
||||
ContactSettings &ioSettings
|
||||
) override {
|
||||
// std::cout << "A contact was persisted" << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnContactRemoved(
|
||||
const SubShapeIDPair &inSubShapePair
|
||||
) override {
|
||||
// std::cout << "A contact was removed" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
// An example activation listener
|
||||
class MyBodyActivationListener : public BodyActivationListener {
|
||||
public:
|
||||
virtual void OnBodyActivated(
|
||||
const BodyID &inBodyID,
|
||||
uint64 inBodyUserData
|
||||
) override {
|
||||
// std::cout << "A body got activated" << std::endl;
|
||||
}
|
||||
|
||||
virtual void OnBodyDeactivated(
|
||||
const BodyID &inBodyID,
|
||||
uint64 inBodyUserData
|
||||
) override {
|
||||
// std::cout << "A body went to sleep" << std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
const uint cMaxBodies = 1024;
|
||||
const uint cNumBodyMutexes = 0;
|
||||
const uint cMaxBodyPairs = 1024;
|
||||
const uint cMaxContactConstraints = 1024;
|
||||
BPLayerInterfaceImpl broadPhaseLayerInterface;
|
||||
ObjectVsBroadPhaseLayerFilterImpl objectVsBroadPhaseLayerFilter;
|
||||
ObjectLayerPairFilterImpl objectVsObjectLayerFilter;
|
||||
MyBodyActivationListener bodyActivationListener;
|
||||
MyContactListener contactListener;
|
||||
|
||||
std::shared_ptr<Game> PhysicsManager::getGame() {
|
||||
auto g = game.lock();
|
||||
assertNotNull(g, "Game is null");
|
||||
return g;
|
||||
}
|
||||
|
||||
BodyInterface & PhysicsManager::getBodyInterface() {
|
||||
return physicsSystem.GetBodyInterface();
|
||||
}
|
||||
|
||||
void PhysicsManager::init(const std::shared_ptr<Game> &game) {
|
||||
this->game = game;
|
||||
|
||||
RegisterDefaultAllocator();
|
||||
|
||||
Trace = TraceImpl;
|
||||
JPH_IF_ENABLE_ASSERTS(AssertFailed = AssertFailedImpl;)
|
||||
|
||||
Factory::sInstance = new Factory();
|
||||
RegisterTypes();
|
||||
|
||||
tempAllocator = std::make_shared<TempAllocatorImpl>(10 * 1024 * 1024);
|
||||
jobSystem = std::make_shared<JobSystemThreadPool>(
|
||||
cMaxPhysicsJobs,
|
||||
cMaxPhysicsBarriers,
|
||||
thread::hardware_concurrency() - 1
|
||||
);
|
||||
|
||||
physicsSystem.Init(
|
||||
cMaxBodies,
|
||||
cNumBodyMutexes,
|
||||
cMaxBodyPairs,
|
||||
cMaxContactConstraints,
|
||||
broadPhaseLayerInterface,
|
||||
objectVsBroadPhaseLayerFilter,
|
||||
objectVsObjectLayerFilter
|
||||
);
|
||||
|
||||
physicsSystem.SetBodyActivationListener(&bodyActivationListener);
|
||||
|
||||
physicsSystem.SetContactListener(&contactListener);
|
||||
|
||||
BodyInterface &bodyInterface = physicsSystem.GetBodyInterface();
|
||||
|
||||
BoxShapeSettings floorShapeSettings(Vec3(100.0f, 1.0f, 100.0f));
|
||||
floorShapeSettings.SetEmbedded();
|
||||
ShapeSettings::ShapeResult floorShapeResult = floorShapeSettings.Create();
|
||||
ShapeRefC floorShape = floorShapeResult.Get();
|
||||
BodyCreationSettings floorSettings(
|
||||
floorShape,
|
||||
RVec3(0.0_r, -1.0_r, 0.0_r),
|
||||
Quat::sIdentity(),
|
||||
EMotionType::Static,
|
||||
Layers::NON_MOVING
|
||||
);
|
||||
Body *floor = bodyInterface.CreateBody(floorSettings);
|
||||
bodyInterface.AddBody(floor->GetID(), EActivation::DontActivate);
|
||||
|
||||
// BodyCreationSettings sphereSettings(
|
||||
// new SphereShape(0.5f),
|
||||
// RVec3(0.0_r, 2.0_r, 0.0_r),
|
||||
// Quat::sIdentity(),
|
||||
// EMotionType::Dynamic,
|
||||
// Layers::MOVING
|
||||
// );
|
||||
// sphereId = bodyInterface.CreateAndAddBody(
|
||||
// sphereSettings,
|
||||
// EActivation::Activate
|
||||
// );
|
||||
// bodyInterface.SetLinearVelocity(sphereId, Vec3(0.0f, -5.0f, 0.0f));
|
||||
// physicsSystem.OptimizeBroadPhase();
|
||||
}
|
||||
|
||||
void PhysicsManager::update() {
|
||||
BodyInterface &bodyInterface = physicsSystem.GetBodyInterface();
|
||||
|
||||
const float cDeltaTime = getGame()->timeManager.delta;
|
||||
const int cCollisionSteps = 1;
|
||||
|
||||
auto scene = getGame()->getCurrentScene();
|
||||
if(scene == nullptr) return;
|
||||
|
||||
// // Now we're ready to simulate the body, keep simulating until it goes to sleep
|
||||
// uint step = 0;
|
||||
// if(!bodyInterface.IsActive(sphereId)) return;
|
||||
// // ++step;
|
||||
|
||||
// // Output current position and velocity of the sphere
|
||||
// RVec3 position = bodyInterface.GetCenterOfMassPosition(sphereId);
|
||||
// Vec3 velocity = bodyInterface.GetLinearVelocity(sphereId);
|
||||
|
||||
// Step the world
|
||||
physicsSystem.Update(
|
||||
cDeltaTime,
|
||||
cCollisionSteps,
|
||||
tempAllocator.get(),
|
||||
jobSystem.get()
|
||||
);
|
||||
|
||||
auto colliders = scene->findComponents<Collider>();
|
||||
for(auto &collider : colliders) {
|
||||
auto bodyId = collider->getBodyId();
|
||||
if(!bodyInterface.IsActive(bodyId)) continue;
|
||||
|
||||
auto pos = bodyInterface.GetCenterOfMassPosition(bodyId);
|
||||
auto rot = bodyInterface.GetRotation(bodyId);
|
||||
collider->getItem()->setLocalPosition(glm::vec3(pos.GetX(), pos.GetY(), pos.GetZ()));
|
||||
collider->getItem()->setLocalRotation(glm::quat(rot.GetW(), rot.GetX(), rot.GetY(), rot.GetZ()));
|
||||
}
|
||||
}
|
||||
|
||||
PhysicsManager::~PhysicsManager() {
|
||||
BodyInterface &bodyInterface = physicsSystem.GetBodyInterface();
|
||||
|
||||
// bodyInterface.RemoveBody(sphereId);
|
||||
// bodyInterface.DestroyBody(sphereId);
|
||||
|
||||
// Remove and destroy the floor
|
||||
// bodyInterface.RemoveBody(floor->GetID());
|
||||
// bodyInterface.DestroyBody(floor->GetID());
|
||||
|
||||
tempAllocator = nullptr;
|
||||
jobSystem = nullptr;
|
||||
|
||||
UnregisterTypes();
|
||||
delete Factory::sInstance;
|
||||
Factory::sInstance = nullptr;
|
||||
|
||||
game.reset();
|
||||
}
|
54
src/dawn/physics/PhysicsManager.hpp
Normal file
54
src/dawn/physics/PhysicsManager.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (c) 2024 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawn.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
class Game;
|
||||
|
||||
class PhysicsManager final {
|
||||
private:
|
||||
std::weak_ptr<Game> game;
|
||||
|
||||
protected:
|
||||
JPH::PhysicsSystem physicsSystem;
|
||||
std::shared_ptr<JPH::TempAllocatorImpl> tempAllocator;
|
||||
std::shared_ptr<JPH::JobSystemThreadPool> jobSystem;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Gets the game associated with the PhysicsManager.
|
||||
*
|
||||
* @return The game associated with the PhysicsManager.
|
||||
*/
|
||||
std::shared_ptr<Game> getGame();
|
||||
|
||||
/**
|
||||
* Gets the JoltPhysics body interface system.
|
||||
*
|
||||
* @return The JoltPhysics body interface system.
|
||||
*/
|
||||
JPH::BodyInterface & getBodyInterface();
|
||||
|
||||
/**
|
||||
* Initializes the PhysicsManager.
|
||||
*
|
||||
* @param game The game to initialize the PhysicsManager with.
|
||||
*/
|
||||
void init(const std::shared_ptr<Game> &game);
|
||||
|
||||
/**
|
||||
* Updates the PhysicsManager.
|
||||
*/
|
||||
void update();
|
||||
|
||||
/**
|
||||
* Deconstructs the PhysicsManager.
|
||||
*/
|
||||
~PhysicsManager();
|
||||
};
|
||||
}
|
Reference in New Issue
Block a user