feat: remove SimplePhysicsWorld
This commit is contained in:
@@ -127,7 +127,6 @@ set(SRC_FILES
|
|||||||
"src/Util/SceneInspector.cpp"
|
"src/Util/SceneInspector.cpp"
|
||||||
|
|
||||||
"src/Physics/PhysicsWorld.cpp"
|
"src/Physics/PhysicsWorld.cpp"
|
||||||
"src/Physics/SimplePhysicsWorld.cpp"
|
|
||||||
"src/Physics/PhysicsSceneBridge.cpp"
|
"src/Physics/PhysicsSceneBridge.cpp"
|
||||||
"src/Physics/JoltPhysicsWorld.cpp"
|
"src/Physics/JoltPhysicsWorld.cpp"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,19 +4,9 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <destrum/Physics/PhysicsWorld.h>
|
#include <destrum/Physics/PhysicsWorld.h>
|
||||||
#include <destrum/Physics/SimplePhysicsWorld.h>
|
|
||||||
|
|
||||||
class GameObject;
|
class GameObject;
|
||||||
|
|
||||||
// Small helper you can store inside Scene.
|
|
||||||
//
|
|
||||||
// Example:
|
|
||||||
// class Scene {
|
|
||||||
// public:
|
|
||||||
// PhysicsSceneBridge& GetPhysics() { return m_Physics; }
|
|
||||||
// private:
|
|
||||||
// PhysicsSceneBridge m_Physics{std::make_unique<SimplePhysicsWorld>()};
|
|
||||||
// };
|
|
||||||
class PhysicsSceneBridge final {
|
class PhysicsSceneBridge final {
|
||||||
public:
|
public:
|
||||||
explicit PhysicsSceneBridge(std::unique_ptr<PhysicsWorld> world);
|
explicit PhysicsSceneBridge(std::unique_ptr<PhysicsWorld> world);
|
||||||
|
|||||||
@@ -1,89 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include <destrum/Physics/PhysicsWorld.h>
|
|
||||||
|
|
||||||
class Rigidbody;
|
|
||||||
|
|
||||||
// Simple CPU placeholder backend.
|
|
||||||
//
|
|
||||||
// This is NOT a replacement for Jolt/PhysX/Bullet.
|
|
||||||
// It exists so your component/scene/render sync can be implemented and tested
|
|
||||||
// before the real backend is added.
|
|
||||||
//
|
|
||||||
// It supports:
|
|
||||||
// - static, dynamic, kinematic bodies
|
|
||||||
// - gravity
|
|
||||||
// - force/impulse integration
|
|
||||||
// - very simple sphere/box/capsule raycasts using bounding spheres
|
|
||||||
//
|
|
||||||
// It does NOT support:
|
|
||||||
// - collision response
|
|
||||||
// - contacts
|
|
||||||
// - friction
|
|
||||||
// - constraints
|
|
||||||
// - real character controllers
|
|
||||||
class SimplePhysicsWorld final : public PhysicsWorld {
|
|
||||||
public:
|
|
||||||
explicit SimplePhysicsWorld(const glm::vec3& gravity = glm::vec3{0.0f, -9.81f, 0.0f});
|
|
||||||
|
|
||||||
void Step(float fixedDt) override;
|
|
||||||
|
|
||||||
PhysicsBodyHandle CreateBody(const PhysicsBodyDesc& desc) override;
|
|
||||||
void DestroyBody(PhysicsBodyHandle body) override;
|
|
||||||
|
|
||||||
void SetBodyTransform(PhysicsBodyHandle body, const PhysicsTransform& transform) override;
|
|
||||||
PhysicsTransform GetBodyTransform(PhysicsBodyHandle body) const override;
|
|
||||||
|
|
||||||
void SetLinearVelocity(PhysicsBodyHandle body, const glm::vec3& velocity) override;
|
|
||||||
glm::vec3 GetLinearVelocity(PhysicsBodyHandle body) const override;
|
|
||||||
|
|
||||||
void AddForce(PhysicsBodyHandle body, const glm::vec3& force) override;
|
|
||||||
void AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse) override;
|
|
||||||
|
|
||||||
bool Raycast(const glm::vec3& origin,
|
|
||||||
const glm::vec3& direction,
|
|
||||||
float maxDistance,
|
|
||||||
PhysicsRaycastHit& hit,
|
|
||||||
PhysicsBodyHandle ignoreBody = {}) const override;
|
|
||||||
|
|
||||||
void SyncKinematicBodiesToPhysics(float fixedDt) override;
|
|
||||||
void SyncDynamicBodiesToTransforms();
|
|
||||||
|
|
||||||
[[nodiscard]] const glm::vec3& GetGravity() const { return m_Gravity; }
|
|
||||||
void SetGravity(const glm::vec3& gravity) { m_Gravity = gravity; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct BodyRecord {
|
|
||||||
bool alive{false};
|
|
||||||
|
|
||||||
PhysicsBodyHandle handle{};
|
|
||||||
PhysicsBodyDesc desc{};
|
|
||||||
|
|
||||||
PhysicsTransform previousTransform{};
|
|
||||||
PhysicsTransform currentTransform{};
|
|
||||||
|
|
||||||
glm::vec3 linearVelocity{0.0f};
|
|
||||||
glm::vec3 accumulatedForce{0.0f};
|
|
||||||
|
|
||||||
Rigidbody* rigidbody{nullptr};
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] BodyRecord* FindBody(PhysicsBodyHandle body);
|
|
||||||
[[nodiscard]] const BodyRecord* FindBody(PhysicsBodyHandle body) const;
|
|
||||||
|
|
||||||
[[nodiscard]] float GetApproxBoundingRadius(const BodyRecord& body) const;
|
|
||||||
[[nodiscard]] static bool RaySphere(const glm::vec3& origin,
|
|
||||||
const glm::vec3& dirNormalized,
|
|
||||||
const glm::vec3& center,
|
|
||||||
float radius,
|
|
||||||
float maxDistance,
|
|
||||||
float& outDistance);
|
|
||||||
|
|
||||||
glm::vec3 m_Gravity{0.0f, -9.81f, 0.0f};
|
|
||||||
|
|
||||||
std::vector<BodyRecord> m_Bodies;
|
|
||||||
std::uint32_t m_NextId{0};
|
|
||||||
};
|
|
||||||
@@ -1,291 +0,0 @@
|
|||||||
#include <destrum/Physics/SimplePhysicsWorld.h>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cmath>
|
|
||||||
#include <limits>
|
|
||||||
|
|
||||||
#include <destrum/Components/Physics/Rigidbody.h>
|
|
||||||
#include <destrum/ObjectModel/GameObject.h>
|
|
||||||
#include <destrum/ObjectModel/Transform.h>
|
|
||||||
|
|
||||||
SimplePhysicsWorld::SimplePhysicsWorld(const glm::vec3& gravity)
|
|
||||||
: m_Gravity(gravity) {
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicsBodyHandle SimplePhysicsWorld::CreateBody(const PhysicsBodyDesc& desc) {
|
|
||||||
BodyRecord record{};
|
|
||||||
record.alive = true;
|
|
||||||
record.handle = PhysicsBodyHandle{m_NextId++};
|
|
||||||
record.desc = desc;
|
|
||||||
record.previousTransform = desc.transform;
|
|
||||||
record.currentTransform = desc.transform;
|
|
||||||
|
|
||||||
if (desc.owner) {
|
|
||||||
record.rigidbody = desc.owner->GetComponent<Rigidbody>();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_Bodies.emplace_back(record);
|
|
||||||
return record.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::DestroyBody(PhysicsBodyHandle body) {
|
|
||||||
if (BodyRecord* record = FindBody(body)) {
|
|
||||||
record->alive = false;
|
|
||||||
record->rigidbody = nullptr;
|
|
||||||
record->desc.owner = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::SetBodyTransform(PhysicsBodyHandle body, const PhysicsTransform& transform) {
|
|
||||||
BodyRecord* record = FindBody(body);
|
|
||||||
if (!record) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
record->previousTransform = record->currentTransform;
|
|
||||||
record->currentTransform = transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
PhysicsTransform SimplePhysicsWorld::GetBodyTransform(PhysicsBodyHandle body) const {
|
|
||||||
const BodyRecord* record = FindBody(body);
|
|
||||||
if (!record) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
return record->currentTransform;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::SetLinearVelocity(PhysicsBodyHandle body, const glm::vec3& velocity) {
|
|
||||||
BodyRecord* record = FindBody(body);
|
|
||||||
if (!record) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
record->linearVelocity = velocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
glm::vec3 SimplePhysicsWorld::GetLinearVelocity(PhysicsBodyHandle body) const {
|
|
||||||
const BodyRecord* record = FindBody(body);
|
|
||||||
if (!record) {
|
|
||||||
return glm::vec3{0.0f};
|
|
||||||
}
|
|
||||||
|
|
||||||
return record->linearVelocity;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::AddForce(PhysicsBodyHandle body, const glm::vec3& force) {
|
|
||||||
BodyRecord* record = FindBody(body);
|
|
||||||
if (!record || record->desc.type != RigidbodyType::Dynamic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
record->accumulatedForce += force;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::AddImpulse(PhysicsBodyHandle body, const glm::vec3& impulse) {
|
|
||||||
BodyRecord* record = FindBody(body);
|
|
||||||
if (!record || record->desc.type != RigidbodyType::Dynamic) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float invMass = record->desc.mass > 0.0f ? 1.0f / record->desc.mass : 0.0f;
|
|
||||||
record->linearVelocity += impulse * invMass;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::Step(float fixedDt) {
|
|
||||||
if (fixedDt <= 0.0f) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (BodyRecord& body : m_Bodies) {
|
|
||||||
if (!body.alive || !body.desc.owner ||
|
|
||||||
body.desc.owner->IsBeingDestroyed() ||
|
|
||||||
!body.desc.owner->IsActiveInHierarchy()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
body.previousTransform = body.currentTransform;
|
|
||||||
|
|
||||||
if (body.desc.type != RigidbodyType::Dynamic) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float invMass = body.desc.mass > 0.0f ? 1.0f / body.desc.mass : 0.0f;
|
|
||||||
|
|
||||||
glm::vec3 acceleration{0.0f};
|
|
||||||
|
|
||||||
if (body.desc.useGravity) {
|
|
||||||
acceleration += m_Gravity;
|
|
||||||
}
|
|
||||||
|
|
||||||
acceleration += body.accumulatedForce * invMass;
|
|
||||||
|
|
||||||
// Semi-implicit Euler.
|
|
||||||
body.linearVelocity += acceleration * fixedDt;
|
|
||||||
body.currentTransform.position += body.linearVelocity * fixedDt;
|
|
||||||
|
|
||||||
body.accumulatedForce = glm::vec3{0.0f};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compact dead records occasionally.
|
|
||||||
m_Bodies.erase(
|
|
||||||
std::remove_if(m_Bodies.begin(), m_Bodies.end(),
|
|
||||||
[](const BodyRecord& body) { return !body.alive; }),
|
|
||||||
m_Bodies.end());
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::SyncKinematicBodiesToPhysics(float fixedDt) {
|
|
||||||
for (BodyRecord& body : m_Bodies) {
|
|
||||||
if (!body.alive || body.desc.type != RigidbodyType::Kinematic || !body.desc.owner ||
|
|
||||||
body.desc.owner->IsBeingDestroyed() || !body.desc.owner->IsActiveInHierarchy()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform& transform = body.desc.owner->GetTransform();
|
|
||||||
|
|
||||||
body.previousTransform = body.currentTransform;
|
|
||||||
body.currentTransform.position = transform.GetWorldPosition();
|
|
||||||
body.currentTransform.rotation = transform.GetWorldRotation();
|
|
||||||
body.linearVelocity = fixedDt > 0.0f
|
|
||||||
? (body.currentTransform.position - body.previousTransform.position) / fixedDt
|
|
||||||
: glm::vec3{0.0f};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SimplePhysicsWorld::SyncDynamicBodiesToTransforms() {
|
|
||||||
for (BodyRecord& body : m_Bodies) {
|
|
||||||
if (!body.alive || body.desc.type != RigidbodyType::Dynamic || !body.desc.owner ||
|
|
||||||
body.desc.owner->IsBeingDestroyed() || !body.desc.owner->IsActiveInHierarchy()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Transform& transform = body.desc.owner->GetTransform();
|
|
||||||
transform.SetWorldPosition(body.currentTransform.position);
|
|
||||||
transform.SetWorldRotation(body.currentTransform.rotation);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimplePhysicsWorld::Raycast(const glm::vec3& origin,
|
|
||||||
const glm::vec3& direction,
|
|
||||||
float maxDistance,
|
|
||||||
PhysicsRaycastHit& hit,
|
|
||||||
PhysicsBodyHandle ignoreBody) const {
|
|
||||||
if (maxDistance <= 0.0f) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float len = glm::length(direction);
|
|
||||||
if (len <= 0.00001f) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const glm::vec3 dir = direction / len;
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
float bestDistance = std::numeric_limits<float>::max();
|
|
||||||
|
|
||||||
for (const BodyRecord& body : m_Bodies) {
|
|
||||||
if (!body.alive || body.desc.shape.type == PhysicsShapeType::None ||
|
|
||||||
!body.desc.owner || body.desc.owner->IsBeingDestroyed() ||
|
|
||||||
!body.desc.owner->IsActiveInHierarchy() ||
|
|
||||||
body.desc.shape.isTrigger ||
|
|
||||||
(ignoreBody.IsValid() && body.handle.id == ignoreBody.id)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
float distance = 0.0f;
|
|
||||||
const float radius = GetApproxBoundingRadius(body);
|
|
||||||
const glm::vec3 center = body.currentTransform.position
|
|
||||||
+ body.currentTransform.rotation * body.desc.shape.centerOffset;
|
|
||||||
|
|
||||||
if (RaySphere(origin, dir, center, radius, maxDistance, distance)) {
|
|
||||||
if (distance < bestDistance) {
|
|
||||||
bestDistance = distance;
|
|
||||||
found = true;
|
|
||||||
|
|
||||||
hit.object = body.desc.owner;
|
|
||||||
hit.body = body.handle;
|
|
||||||
hit.distance = distance;
|
|
||||||
hit.point = origin + dir * distance;
|
|
||||||
|
|
||||||
const glm::vec3 n = hit.point - center;
|
|
||||||
hit.normal = glm::length(n) > 0.00001f ? glm::normalize(n) : glm::vec3{0.0f, 1.0f, 0.0f};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return found;
|
|
||||||
}
|
|
||||||
|
|
||||||
SimplePhysicsWorld::BodyRecord* SimplePhysicsWorld::FindBody(PhysicsBodyHandle body) {
|
|
||||||
for (BodyRecord& record : m_Bodies) {
|
|
||||||
if (record.alive && record.handle == body) {
|
|
||||||
return &record;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SimplePhysicsWorld::BodyRecord* SimplePhysicsWorld::FindBody(PhysicsBodyHandle body) const {
|
|
||||||
for (const BodyRecord& record : m_Bodies) {
|
|
||||||
if (record.alive && record.handle == body) {
|
|
||||||
return &record;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
float SimplePhysicsWorld::GetApproxBoundingRadius(const BodyRecord& body) const {
|
|
||||||
const PhysicsShapeDesc& shape = body.desc.shape;
|
|
||||||
|
|
||||||
switch (shape.type) {
|
|
||||||
case PhysicsShapeType::Box:
|
|
||||||
return glm::length(shape.halfExtents);
|
|
||||||
|
|
||||||
case PhysicsShapeType::Sphere:
|
|
||||||
return shape.radius;
|
|
||||||
|
|
||||||
case PhysicsShapeType::Capsule:
|
|
||||||
return shape.height * 0.5f;
|
|
||||||
|
|
||||||
case PhysicsShapeType::None:
|
|
||||||
default:
|
|
||||||
return 0.0f;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SimplePhysicsWorld::RaySphere(const glm::vec3& origin,
|
|
||||||
const glm::vec3& dirNormalized,
|
|
||||||
const glm::vec3& center,
|
|
||||||
float radius,
|
|
||||||
float maxDistance,
|
|
||||||
float& outDistance) {
|
|
||||||
const glm::vec3 oc = origin - center;
|
|
||||||
|
|
||||||
const float a = glm::dot(dirNormalized, dirNormalized);
|
|
||||||
const float b = 2.0f * glm::dot(oc, dirNormalized);
|
|
||||||
const float c = glm::dot(oc, oc) - radius * radius;
|
|
||||||
|
|
||||||
const float discriminant = b * b - 4.0f * a * c;
|
|
||||||
if (discriminant < 0.0f) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const float sqrtDisc = std::sqrt(discriminant);
|
|
||||||
const float t0 = (-b - sqrtDisc) / (2.0f * a);
|
|
||||||
const float t1 = (-b + sqrtDisc) / (2.0f * a);
|
|
||||||
|
|
||||||
float t = t0;
|
|
||||||
if (t < 0.0f) {
|
|
||||||
t = t1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t < 0.0f || t > maxDistance) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
outDistance = t;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
#include <destrum/Serialization/PrefabCache.h>
|
#include <destrum/Serialization/PrefabCache.h>
|
||||||
#include <destrum/Serialization/PrefabSerializer.h>
|
#include <destrum/Serialization/PrefabSerializer.h>
|
||||||
#include <destrum/Serialization/SceneSerializer.h>
|
#include <destrum/Serialization/SceneSerializer.h>
|
||||||
#include <destrum/Physics/SimplePhysicsWorld.h>
|
|
||||||
#include <destrum/Physics/JoltPhysicsWorld.h>
|
#include <destrum/Physics/JoltPhysicsWorld.h>
|
||||||
#include <destrum/Components/Physics/SphereCollider.h>
|
#include <destrum/Components/Physics/SphereCollider.h>
|
||||||
#include <destrum/Components/Physics/BoxCollider.h>
|
#include <destrum/Components/Physics/BoxCollider.h>
|
||||||
@@ -384,7 +383,10 @@ namespace {
|
|||||||
|
|
||||||
void testPhysicsWorldUnits()
|
void testPhysicsWorldUnits()
|
||||||
{
|
{
|
||||||
SimplePhysicsWorld world{glm::vec3{0.0f}};
|
JoltPhysicsWorld world{{
|
||||||
|
.workerThreadCount = 1,
|
||||||
|
.gravity = glm::vec3{0.0f}
|
||||||
|
}};
|
||||||
GameObject object{"scaled-physics"};
|
GameObject object{"scaled-physics"};
|
||||||
object.GetTransform().SetLocalScale(glm::vec3{0.5f});
|
object.GetTransform().SetLocalScale(glm::vec3{0.5f});
|
||||||
object.AddComponent<SphereCollider>(1.0f);
|
object.AddComponent<SphereCollider>(1.0f);
|
||||||
|
|||||||
Reference in New Issue
Block a user