feat: add more collider types + camera snapping fix
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <destrum/Components/Physics/MeshShapeCollider.h>
|
||||
|
||||
class ConvexHullCollider final : public MeshShapeCollider {
|
||||
public:
|
||||
static constexpr int MinVertices = 4;
|
||||
static constexpr int MaxVertices = 256;
|
||||
|
||||
explicit ConvexHullCollider(GameObject& owner, int maxVertices = 64)
|
||||
: MeshShapeCollider(owner)
|
||||
, m_MaxVertices(std::clamp(maxVertices, MinVertices, MaxVertices)) {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "ConvexHullCollider";
|
||||
}
|
||||
|
||||
nlohmann::json Serialize() const override;
|
||||
void Deserialize(const nlohmann::json& data) override;
|
||||
void ImGuiInspector() override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||
return BuildConvexHullShape(m_MaxVertices);
|
||||
}
|
||||
|
||||
[[nodiscard]] int GetMaxVertices() const {
|
||||
return m_MaxVertices;
|
||||
}
|
||||
|
||||
void SetMaxVertices(int maxVertices) {
|
||||
m_MaxVertices = std::clamp(maxVertices, MinVertices, MaxVertices);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
int m_MaxVertices{64};
|
||||
};
|
||||
@@ -0,0 +1,66 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <destrum/Components/Physics/Collider.h>
|
||||
|
||||
class CylinderCollider final : public Collider {
|
||||
public:
|
||||
explicit CylinderCollider(GameObject& owner, float radius = 0.5f, float height = 1.0f)
|
||||
: Collider(owner)
|
||||
, m_Radius(std::max(radius, 0.0001f))
|
||||
, m_Height(std::max(height, 0.0001f)) {}
|
||||
|
||||
void Update(float) override {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "CylinderCollider";
|
||||
}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
auto data = SerializeCollider();
|
||||
data["radius"] = m_Radius;
|
||||
data["height"] = m_Height;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("radius")) {
|
||||
SetRadius(data.at("radius").get<float>());
|
||||
}
|
||||
if (data.contains("height")) {
|
||||
SetHeight(data.at("height").get<float>());
|
||||
}
|
||||
}
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override {
|
||||
return PhysicsShapeDesc::Cylinder(m_Radius, m_Height, m_CenterOffset, m_IsTrigger);
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetRadius() const {
|
||||
return m_Radius;
|
||||
}
|
||||
|
||||
void SetRadius(float radius) {
|
||||
m_Radius = std::max(radius, 0.0001f);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
[[nodiscard]] float GetHeight() const {
|
||||
return m_Height;
|
||||
}
|
||||
|
||||
void SetHeight(float height) {
|
||||
m_Height = std::max(height, 0.0001f);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
private:
|
||||
float m_Radius{0.5f};
|
||||
float m_Height{1.0f};
|
||||
};
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include <destrum/Components/Physics/MeshShapeCollider.h>
|
||||
|
||||
// Exact triangle mesh for static and kinematic bodies. Dynamic bodies can't use one, they get a convex hull instead.
|
||||
class MeshCollider final : public MeshShapeCollider {
|
||||
public:
|
||||
static constexpr int DynamicHullVertices = 64;
|
||||
|
||||
explicit MeshCollider(GameObject& owner)
|
||||
: MeshShapeCollider(owner) {}
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
return "MeshCollider";
|
||||
}
|
||||
|
||||
nlohmann::json Serialize() const override {
|
||||
return SerializeCollider();
|
||||
}
|
||||
|
||||
void Deserialize(const nlohmann::json& data) override {
|
||||
DeserializeCollider(data);
|
||||
}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
void DrawDebugLines(const glm::vec4& color) const override;
|
||||
|
||||
[[nodiscard]] PhysicsShapeDesc BuildPhysicsShape() const override;
|
||||
|
||||
[[nodiscard]] bool UsesConvexFallback() const;
|
||||
};
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <destrum/Components/Physics/Collider.h>
|
||||
|
||||
// Base for colliders shaped by the MeshRendererComponent on the same object. Unlike the primitive colliders,
|
||||
// the mesh is in local units, so the transform's world scale is applied.
|
||||
class MeshShapeCollider : public Collider {
|
||||
public:
|
||||
explicit MeshShapeCollider(GameObject& owner)
|
||||
: Collider(owner) {}
|
||||
|
||||
void Update(float) override {}
|
||||
|
||||
void ImGuiInspector() override;
|
||||
|
||||
// Used instead of the MeshRenderer mesh, not serialized
|
||||
void SetCustomMesh(std::shared_ptr<const PhysicsMeshData> mesh) {
|
||||
m_CustomMesh = std::move(mesh);
|
||||
NotifyPhysicsChanged();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::shared_ptr<const PhysicsMeshData> GetSourceMesh() const;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] glm::vec3 GetShapeScale() const;
|
||||
[[nodiscard]] glm::mat4 GetShapeMatrix() const;
|
||||
|
||||
// Falls back to a box around the mesh when it has no volume
|
||||
[[nodiscard]] PhysicsShapeDesc BuildConvexHullShape(int maxVertices) const;
|
||||
void DrawConvexHull(int maxVertices, const glm::vec4& color) const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<const PhysicsMeshData> m_CustomMesh;
|
||||
};
|
||||
@@ -4,6 +4,9 @@
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace DebugDraw {
|
||||
void Arc(const glm::vec3& center, const glm::vec3& axisA, const glm::vec3& axisB, float radius,
|
||||
float fromAngle, float toAngle, const glm::vec4& color, int segments = 16);
|
||||
@@ -14,6 +17,12 @@ namespace DebugDraw {
|
||||
void Sphere(const glm::vec3& center, float radius, const glm::vec4& color);
|
||||
|
||||
void Capsule(const glm::vec3& center, const glm::quat& rotation, float radius, float height, const glm::vec4& color);
|
||||
void Cylinder(const glm::vec3& center, const glm::quat& rotation, float radius, float height, const glm::vec4& color);
|
||||
|
||||
// Wireframe of an indexed triangle list, stops after maxTriangles
|
||||
void Triangles(const glm::mat4& transform, const std::vector<glm::vec3>& points,
|
||||
const std::vector<std::uint32_t>& indices, const glm::vec4& color,
|
||||
std::size_t maxTriangles = 20000);
|
||||
}
|
||||
|
||||
#endif // DEBUGDRAW_H
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include <destrum/Physics/PhysicsTypes.h>
|
||||
|
||||
struct CPUMesh;
|
||||
|
||||
// Shares collision data between colliders using the same mesh, so physics backends can share their shapes too.
|
||||
// Main thread only.
|
||||
namespace PhysicsMeshCache {
|
||||
[[nodiscard]] std::shared_ptr<const PhysicsMeshData> FromCPUMesh(const std::string& key, const CPUMesh& mesh);
|
||||
|
||||
// Null when the points don't span a volume (e.g. a plane)
|
||||
[[nodiscard]] std::shared_ptr<const PhysicsMeshData> ConvexHull(const std::shared_ptr<const PhysicsMeshData>& source,
|
||||
int maxVertices);
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
@@ -17,7 +19,10 @@ enum class PhysicsShapeType {
|
||||
None,
|
||||
Box,
|
||||
Sphere,
|
||||
Capsule
|
||||
Capsule,
|
||||
Cylinder,
|
||||
ConvexHull,
|
||||
Mesh
|
||||
};
|
||||
|
||||
struct PhysicsBodyHandle {
|
||||
@@ -50,6 +55,12 @@ struct PhysicsMaterialDesc {
|
||||
float restitution{0.0f};
|
||||
};
|
||||
|
||||
// Triangles share vertices through indices. A convex hull only uses the points, the indices are for drawing it.
|
||||
struct PhysicsMeshData {
|
||||
std::vector<glm::vec3> points;
|
||||
std::vector<std::uint32_t> indices;
|
||||
};
|
||||
|
||||
struct PhysicsShapeDesc {
|
||||
PhysicsShapeType type{PhysicsShapeType::None};
|
||||
|
||||
@@ -59,9 +70,14 @@ struct PhysicsShapeDesc {
|
||||
// Sphere / capsule
|
||||
float radius{0.5f};
|
||||
|
||||
// Capsule full height, including the two hemispheres.
|
||||
// Capsule full height, including the two hemispheres. Cylinder full height.
|
||||
float height{2.0f};
|
||||
|
||||
// Convex hull / mesh, in the collider's local space before scale. Backends may cache
|
||||
// shapes per mesh data, so it must not be modified once shared.
|
||||
std::shared_ptr<const PhysicsMeshData> mesh;
|
||||
glm::vec3 scale{1.0f};
|
||||
|
||||
// Local offset from the rigidbody transform.
|
||||
glm::vec3 centerOffset{0.0f};
|
||||
|
||||
@@ -101,6 +117,45 @@ struct PhysicsShapeDesc {
|
||||
desc.isTrigger = isTrigger;
|
||||
return desc;
|
||||
}
|
||||
|
||||
[[nodiscard]] static PhysicsShapeDesc Cylinder(float radius,
|
||||
float height,
|
||||
const glm::vec3& centerOffset = glm::vec3{0.0f},
|
||||
bool isTrigger = false) {
|
||||
PhysicsShapeDesc desc{};
|
||||
desc.type = PhysicsShapeType::Cylinder;
|
||||
desc.radius = radius;
|
||||
desc.height = height;
|
||||
desc.centerOffset = centerOffset;
|
||||
desc.isTrigger = isTrigger;
|
||||
return desc;
|
||||
}
|
||||
|
||||
[[nodiscard]] static PhysicsShapeDesc ConvexHull(std::shared_ptr<const PhysicsMeshData> hull,
|
||||
const glm::vec3& scale = glm::vec3{1.0f},
|
||||
const glm::vec3& centerOffset = glm::vec3{0.0f},
|
||||
bool isTrigger = false) {
|
||||
PhysicsShapeDesc desc{};
|
||||
desc.type = PhysicsShapeType::ConvexHull;
|
||||
desc.mesh = std::move(hull);
|
||||
desc.scale = scale;
|
||||
desc.centerOffset = centerOffset;
|
||||
desc.isTrigger = isTrigger;
|
||||
return desc;
|
||||
}
|
||||
|
||||
[[nodiscard]] static PhysicsShapeDesc Mesh(std::shared_ptr<const PhysicsMeshData> mesh,
|
||||
const glm::vec3& scale = glm::vec3{1.0f},
|
||||
const glm::vec3& centerOffset = glm::vec3{0.0f},
|
||||
bool isTrigger = false) {
|
||||
PhysicsShapeDesc desc{};
|
||||
desc.type = PhysicsShapeType::Mesh;
|
||||
desc.mesh = std::move(mesh);
|
||||
desc.scale = scale;
|
||||
desc.centerOffset = centerOffset;
|
||||
desc.isTrigger = isTrigger;
|
||||
return desc;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhysicsBodyDesc {
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include <destrum/Components/Spinner.h>
|
||||
#include <destrum/Components/Physics/BoxCollider.h>
|
||||
#include <destrum/Components/Physics/CapsuleCollider.h>
|
||||
#include <destrum/Components/Physics/ConvexHullCollider.h>
|
||||
#include <destrum/Components/Physics/CylinderCollider.h>
|
||||
#include <destrum/Components/Physics/MeshCollider.h>
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/Components/Physics/SphereCollider.h>
|
||||
#include <destrum/Components/UI/Canvas.h>
|
||||
@@ -32,7 +35,7 @@
|
||||
X(Rigidbody) \
|
||||
X(BoxCollider) \
|
||||
X(SphereCollider) \
|
||||
X(CapsuleCollider) \
|
||||
X(CapsuleCollider) X(CylinderCollider) X(ConvexHullCollider) X(MeshCollider) \
|
||||
X(Canvas) \
|
||||
X(RectTransform) \
|
||||
X(UIImage) \
|
||||
|
||||
Reference in New Issue
Block a user