feat: add more collider types + camera snapping fix
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
#include <destrum/Components/Physics/ConvexHullCollider.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
nlohmann::json ConvexHullCollider::Serialize() const {
|
||||
auto data = SerializeCollider();
|
||||
data["maxVertices"] = m_MaxVertices;
|
||||
return data;
|
||||
}
|
||||
|
||||
void ConvexHullCollider::Deserialize(const nlohmann::json& data) {
|
||||
DeserializeCollider(data);
|
||||
if (data.contains("maxVertices")) {
|
||||
SetMaxVertices(data.at("maxVertices").get<int>());
|
||||
}
|
||||
}
|
||||
|
||||
void ConvexHullCollider::DrawDebugLines(const glm::vec4& color) const {
|
||||
DrawConvexHull(m_MaxVertices, color);
|
||||
}
|
||||
|
||||
void ConvexHullCollider::ImGuiInspector() {
|
||||
MeshShapeCollider::ImGuiInspector();
|
||||
|
||||
int maxVertices = m_MaxVertices;
|
||||
if (ImGui::SliderInt("Max vertices", &maxVertices, MinVertices, MaxVertices)) {
|
||||
SetMaxVertices(maxVertices);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <destrum/Components/Physics/CylinderCollider.h>
|
||||
|
||||
#include <destrum/Graphics/DebugDraw.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
void CylinderCollider::DrawDebugLines(const glm::vec4& color) const {
|
||||
DebugDraw::Cylinder(GetWorldCenter(), GetWorldRotation(), m_Radius, m_Height, color);
|
||||
}
|
||||
|
||||
void CylinderCollider::ImGuiInspector() {
|
||||
Collider::ImGuiInspector();
|
||||
|
||||
float radius = m_Radius;
|
||||
if (ImGui::DragFloat("Radius", &radius, 0.05f, 0.0001f)) {
|
||||
SetRadius(radius);
|
||||
}
|
||||
|
||||
float height = m_Height;
|
||||
if (ImGui::DragFloat("Height", &height, 0.05f, 0.0001f)) {
|
||||
SetHeight(height);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
#include <destrum/Components/Physics/MeshCollider.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <destrum/Components/Physics/Rigidbody.h>
|
||||
#include <destrum/Graphics/DebugDraw.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
|
||||
bool MeshCollider::UsesConvexFallback() const {
|
||||
const auto* rigidbody = GetGameObject()->GetComponent<Rigidbody>();
|
||||
return rigidbody != nullptr && rigidbody->GetType() == RigidbodyType::Dynamic;
|
||||
}
|
||||
|
||||
PhysicsShapeDesc MeshCollider::BuildPhysicsShape() const {
|
||||
if (UsesConvexFallback()) {
|
||||
return BuildConvexHullShape(DynamicHullVertices);
|
||||
}
|
||||
|
||||
auto source = GetSourceMesh();
|
||||
if (!source || source->indices.empty()) {
|
||||
return {};
|
||||
}
|
||||
return PhysicsShapeDesc::Mesh(std::move(source), GetShapeScale(), m_CenterOffset, m_IsTrigger);
|
||||
}
|
||||
|
||||
void MeshCollider::DrawDebugLines(const glm::vec4& color) const {
|
||||
if (UsesConvexFallback()) {
|
||||
DrawConvexHull(DynamicHullVertices, color);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto source = GetSourceMesh()) {
|
||||
DebugDraw::Triangles(GetShapeMatrix(), source->points, source->indices, color);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshCollider::ImGuiInspector() {
|
||||
MeshShapeCollider::ImGuiInspector();
|
||||
|
||||
if (UsesConvexFallback()) {
|
||||
ImGui::TextColored(ImVec4{1.0f, 0.6f, 0.2f, 1.0f}, "Dynamic rigidbody: using a convex hull");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
#include <destrum/Components/Physics/MeshShapeCollider.h>
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include <destrum/Components/MeshRendererComponent.h>
|
||||
#include <destrum/Graphics/DebugDraw.h>
|
||||
#include <destrum/Graphics/RenderResources.h>
|
||||
#include <destrum/Graphics/Renderer.h>
|
||||
#include <destrum/ObjectModel/GameObject.h>
|
||||
#include <destrum/ObjectModel/Transform.h>
|
||||
#include <destrum/Physics/PhysicsMeshCache.h>
|
||||
#include <destrum/Util/GameState.h>
|
||||
|
||||
namespace {
|
||||
struct Bounds {
|
||||
glm::vec3 center{0.0f};
|
||||
glm::vec3 halfExtents{0.0f};
|
||||
};
|
||||
|
||||
Bounds ComputeBounds(const PhysicsMeshData& mesh) {
|
||||
glm::vec3 min{std::numeric_limits<float>::max()};
|
||||
glm::vec3 max{std::numeric_limits<float>::lowest()};
|
||||
for (const glm::vec3& point : mesh.points) {
|
||||
min = glm::min(min, point);
|
||||
max = glm::max(max, point);
|
||||
}
|
||||
return {(min + max) * 0.5f, (max - min) * 0.5f};
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<const PhysicsMeshData> MeshShapeCollider::GetSourceMesh() const {
|
||||
if (m_CustomMesh) {
|
||||
return m_CustomMesh;
|
||||
}
|
||||
|
||||
const auto* meshRenderer = GetGameObject()->GetComponent<MeshRendererComponent>();
|
||||
if (meshRenderer == nullptr || meshRenderer->GetMeshID() == NULL_MESH_ID || !GameState::GetInstance().HasRenderer()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const RenderResources* resources = GameState::GetInstance().Renderer().getResources();
|
||||
if (resources == nullptr || !resources->meshes().isValid(meshRenderer->GetMeshID())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const MeshCache& meshes = resources->meshes();
|
||||
return PhysicsMeshCache::FromCPUMesh(meshes.getMeshKey(meshRenderer->GetMeshID()),
|
||||
meshes.getCPUMesh(meshRenderer->GetMeshID()));
|
||||
}
|
||||
|
||||
glm::vec3 MeshShapeCollider::GetShapeScale() const {
|
||||
glm::vec3 scale = GetTransform().GetWorldScale();
|
||||
for (int axis = 0; axis < 3; ++axis) {
|
||||
if (std::abs(scale[axis]) < 0.0001f) {
|
||||
scale[axis] = scale[axis] < 0.0f ? -0.0001f : 0.0001f;
|
||||
}
|
||||
}
|
||||
return scale;
|
||||
}
|
||||
|
||||
glm::mat4 MeshShapeCollider::GetShapeMatrix() const {
|
||||
return glm::translate(glm::mat4{1.0f}, GetWorldCenter()) *
|
||||
glm::mat4_cast(GetWorldRotation()) *
|
||||
glm::scale(glm::mat4{1.0f}, GetShapeScale());
|
||||
}
|
||||
|
||||
PhysicsShapeDesc MeshShapeCollider::BuildConvexHullShape(int maxVertices) const {
|
||||
const auto source = GetSourceMesh();
|
||||
if (!source || source->points.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const glm::vec3 scale = GetShapeScale();
|
||||
if (auto hull = PhysicsMeshCache::ConvexHull(source, maxVertices)) {
|
||||
return PhysicsShapeDesc::ConvexHull(std::move(hull), scale, m_CenterOffset, m_IsTrigger);
|
||||
}
|
||||
|
||||
const Bounds bounds = ComputeBounds(*source);
|
||||
return PhysicsShapeDesc::Box(glm::max(glm::abs(bounds.halfExtents * scale), glm::vec3{0.01f}),
|
||||
m_CenterOffset + bounds.center * scale,
|
||||
m_IsTrigger);
|
||||
}
|
||||
|
||||
void MeshShapeCollider::DrawConvexHull(int maxVertices, const glm::vec4& color) const {
|
||||
const auto source = GetSourceMesh();
|
||||
if (!source || source->points.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto hull = PhysicsMeshCache::ConvexHull(source, maxVertices)) {
|
||||
DebugDraw::Triangles(GetShapeMatrix(), hull->points, hull->indices, color);
|
||||
return;
|
||||
}
|
||||
|
||||
const Bounds bounds = ComputeBounds(*source);
|
||||
const glm::vec3 scale = GetShapeScale();
|
||||
DebugDraw::Box(GetWorldCenter() + GetWorldRotation() * (bounds.center * scale),
|
||||
GetWorldRotation(),
|
||||
glm::max(glm::abs(bounds.halfExtents * scale), glm::vec3{0.01f}),
|
||||
color);
|
||||
}
|
||||
|
||||
void MeshShapeCollider::ImGuiInspector() {
|
||||
Collider::ImGuiInspector();
|
||||
|
||||
if (m_CustomMesh) {
|
||||
ImGui::TextDisabled("Custom mesh: %zu points", m_CustomMesh->points.size());
|
||||
} else if (const auto source = GetSourceMesh()) {
|
||||
ImGui::TextDisabled("Mesh: %zu vertices, %zu triangles", source->points.size(), source->indices.size() / 3);
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4{1.0f, 0.6f, 0.2f, 1.0f}, "Needs a MeshRendererComponent with a mesh");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user