Physics system progress

Added CharacterController creation
Reworked and refactored shape and body system internally
Code cleanup
Brought back Hull serializing for Quake map brushes
Updated Editor panels accordingly
This commit is contained in:
Antoine Pilote
2023-07-03 19:16:02 -04:00
parent 7c95beefcc
commit fc183b4813
14 changed files with 370 additions and 258 deletions

View File

@@ -17,30 +17,21 @@ public:
BeginComponentTable(CHARACTER CONTROLLER, Nuake::CharacterControllerComponent);
{
{
ImGui::Text("Height");
ImGui::Text("Friction");
ImGui::TableNextColumn();
ImGui::DragFloat("##Height", &component.Height, 0.01f, 0.1f, 100.0f);
ImGui::DragFloat("##Friction", &component.Friction, 0.01f, 0.1f, 100.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Height, 1.0f)
ComponentTableReset(component.Friction, 0.5f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Radius");
ImGui::Text("Max Slope Angle");
ImGui::TableNextColumn();
ImGui::DragFloat("##Radius", &component.Radius, 0.01f, 0.1f, 10.0f);
ImGui::DragFloat("##MaxSlopeAngle", &component.MaxSlopeAngle, 0.01f, 0.1f, 90.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Radius, 0.25f)
}
ImGui::TableNextColumn();
{
ImGui::Text("Mass");
ImGui::TableNextColumn();
ImGui::DragFloat("##Mass", &component.Mass, 0.001f, 0.00001f, 10.0f);
ImGui::TableNextColumn();
ComponentTableReset(component.Mass, 0.001f)
ComponentTableReset(component.MaxSlopeAngle, 0.45f)
}
}
EndComponentTable()

View File

@@ -6,14 +6,21 @@ namespace Nuake
{
namespace Physics
{
CharacterController::CharacterController(float height, float radius, float mass, Vector3 position)
CharacterController::CharacterController(const Ref<PhysicShape>& shape, float friction, float maxSlopeAngle)
{
Shape = shape;
Friction = friction;
MaxSlopeAngle = maxSlopeAngle;
}
void CharacterController::SetEntity(Entity& ent)
{
Owner = ent;
}
Entity CharacterController::GetEntity() const
{
return Owner;
}
void CharacterController::MoveAndSlide(glm::vec3 velocity)

View File

@@ -1,6 +1,8 @@
#pragma once
#include "src/Core/Core.h"
#include "src/Core/Maths.h"
#include "src/Core/Physics/PhysicsShapes.h"
#include "src/Scene/Entities/Entity.h"
namespace Nuake
{
@@ -11,26 +13,30 @@ namespace Nuake
class CharacterController
{
public:
Vector3 Position;
Entity Owner;
bool IsOnGround = false;
bool m_hittingWall;
float m_stepHeight = 0.35f;
float m_MaxSlopeAngle = 45.0f;
float m_stepHeight = 0.35f;
float MaxSlopeAngle = 45.0f;
float Friction = 0.5f;
Ref<PhysicShape> Shape;
//bool m_onJumpableGround; // A bit lower contact than just onGround
float m_bottomYOffset;
float m_bottomRoundedRegionYOffset;
glm::vec3 m_manualVelocity;
std::vector<glm::vec3> m_surfaceHitNormals;
float m_jumpRechargeTimer;
CharacterController(float height, float radius, float mass, Vector3 position);
CharacterController(const Ref<PhysicShape>& shape, float friction, float maxSlopeAngle);
void SetEntity(Entity& ent);
Entity GetEntity() const;
void MoveAndSlide(glm::vec3 velocity);
bool IsOnFloor()

View File

@@ -1,11 +1,11 @@
#include "DynamicWorld.h"
#include "Rigibody.h"
#include "../Core/Core.h"
#include <src/Vendors/glm/ext/quaternion_common.hpp>
#include <src/Core/Logger.h>
#include "src/Core/Core.h"
#include "src/Core/Logger.h"
#include <src/Core/Physics/PhysicsShapes.h>
#include <src/Vendors/glm/ext/quaternion_common.hpp>
#include "src/Vendors/glm/gtx/matrix_decompose.hpp"
#include <Jolt/Jolt.h>
@@ -241,103 +241,21 @@ namespace Nuake
void DynamicWorld::AddRigidbody(Ref<RigidBody> rb)
{
JPH::BodyInterface& bodyInterface = _JoltPhysicsSystem->GetBodyInterface();
JPH::ShapeSettings::ShapeResult shapeResult;
auto rbShape = rb->GetShape();
switch (rbShape->GetType())
{
case RigidbodyShapes::BOX:
{
Box* box = (Box*)rbShape.get();
const Vector3& boxSize = box->GetSize();
JPH::BoxShapeSettings shapeSettings(JPH::Vec3(boxSize.x, boxSize.y, boxSize.z));
shapeResult = shapeSettings.Create();
}
break;
case RigidbodyShapes::SPHERE:
{
Sphere* sphere = (Sphere*)rbShape.get();
const float sphereRadius = sphere->GetRadius();
JPH::SphereShapeSettings shapeSettings(sphereRadius);
shapeResult = shapeSettings.Create();
}
break;
case RigidbodyShapes::CAPSULE:
{
Capsule* capsule = (Capsule*)rbShape.get();
const float radius = capsule->GetRadius();
const float height = capsule->GetHeight();
JPH::CapsuleShapeSettings shapeSettings(height / 2.0f, radius);
shapeResult = shapeSettings.Create();
}
break;
case RigidbodyShapes::CYLINDER:
{
Cylinder* capsule = (Cylinder*)rbShape.get();
const float radius = capsule->GetRadius();
const float height = capsule->GetHeight();
JPH::CylinderShapeSettings shapeSettings(height / 2.0f, radius);
shapeResult = shapeSettings.Create();
}
break;
case RigidbodyShapes::MESH:
{
MeshShape* meshShape = (MeshShape*)rbShape.get();
const auto& mesh = meshShape->GetMesh();
const auto& vertices = mesh->GetVertices();
const auto& indices = mesh->GetIndices();
JPH::TriangleList triangles;
triangles.reserve(indices.size());
Matrix4 transform = rb->_transform;
transform[3] = Vector4(0, 0, 0, 1.0f);
for (int i = 0; i < indices.size() - 3; i += 3)
{
const Vector3& p1 = vertices[indices[i]].position;
const Vector3& p2 = vertices[indices[i + 1]].position;
const Vector3& p3 = vertices[indices[i + 2]].position;
const Vector4& tp1 = transform * Vector4(p1, 1.0f);
const Vector4& tp2 = transform * Vector4(p2, 1.0f);
const Vector4& tp3 = transform * Vector4(p3, 1.0f);
triangles.push_back(JPH::Triangle(JPH::Float3(tp1.x, tp1.y, tp1.z), JPH::Float3(tp2.x, tp2.y, tp2.z), JPH::Float3(tp3.x, tp3.y, tp3.z)));
}
JPH::MeshShapeSettings shapeSettings(std::move(triangles));
shapeResult = shapeSettings.Create();
}
break;
case CONVEX_HULL:
{
ConvexHullShape* shape = (ConvexHullShape*)rbShape.get();
const auto& hullPoints = shape->GetPoints();
JPH::Array<JPH::Vec3> points;
points.reserve(std::size(hullPoints));
for (const auto& p : hullPoints)
{
points.push_back(JPH::Vec3(p.x, p.y, p.z));
}
JPH::ConvexHullShapeSettings shapeSettings(points);
shapeResult = shapeSettings.Create();
}
break;
}
const float mass = rb->_mass;
JPH::EMotionType motionType = JPH::EMotionType::Static;
float mass = rb->_mass;
// According to jolt documentation, Mesh shapes should only be static.
if (mass > 0.0f && rb->GetShape()->GetType() != MESH)
const bool isMeshShape = rb->GetShape()->GetType() == MESH;
if (mass > 0.0f && !isMeshShape)
{
motionType = JPH::EMotionType::Dynamic;
}
const auto& startPos = rb->GetPosition();
const auto& joltPos = JPH::Vec3(startPos.x, startPos.y, startPos.z);
JPH::BodyCreationSettings bodySettings(shapeResult.Get(), joltPos, JPH::Quat::sIdentity(), motionType, Layers::MOVING);
auto joltShape = GetJoltShape(rb->GetShape());
JPH::BodyCreationSettings bodySettings(joltShape, joltPos, JPH::Quat::sIdentity(), motionType, Layers::MOVING);
if (mass > 0.0f)
{
@@ -358,12 +276,16 @@ namespace Nuake
void DynamicWorld::AddCharacterController(Ref<CharacterController> cc)
{
auto settings = new JPH::CharacterSettings();
JPH::Ref<JPH::CharacterSettings> settings = new JPH::CharacterSettings();
settings->mMaxSlopeAngle = JPH::DegreesToRadians(45.0f);
settings->mLayer = Layers::MOVING;
settings->mFriction = 0.5f;
settings->mShape = GetJoltShape(cc->Shape);
// Shape here
auto& joltPos = JPH::Vec3(cc->Position.x, cc->Position.y, cc->Position.z);
JPH::Character* character = new JPH::Character(settings, joltPos, JPH::Quat::sIdentity(), cc->GetEntity().GetID() , _JoltPhysicsSystem.get());
character->AddToPhysicsSystem(JPH::EActivation::Activate);
}
RaycastResult DynamicWorld::Raycast(glm::vec3 from, glm::vec3 to)
@@ -454,5 +376,94 @@ namespace Nuake
_JoltBodyInterface->RemoveBodies(reinterpret_cast<JPH::BodyID*>(_registeredBodies.data()), _registeredBodies.size());
_registeredBodies.clear();
}
JPH::Ref<JPH::Shape> DynamicWorld::GetJoltShape(const Ref<PhysicShape> shape)
{
JPH::ShapeSettings::ShapeResult result;
switch (shape->GetType())
{
case RigidbodyShapes::BOX:
{
Box* box = (Box*)shape.get();
const Vector3& boxSize = box->GetSize();
JPH::BoxShapeSettings shapeSettings(JPH::Vec3(boxSize.x, boxSize.y, boxSize.z));
result = shapeSettings.Create();
}
break;
case RigidbodyShapes::SPHERE:
{
Sphere* sphere = (Sphere*)shape.get();
const float sphereRadius = sphere->GetRadius();
JPH::SphereShapeSettings shapeSettings(sphereRadius);
result = shapeSettings.Create();
}
break;
case RigidbodyShapes::CAPSULE:
{
Capsule* capsule = (Capsule*)shape.get();
const float radius = capsule->GetRadius();
const float height = capsule->GetHeight();
JPH::CapsuleShapeSettings shapeSettings(height / 2.0f, radius);
result = shapeSettings.Create();
}
break;
case RigidbodyShapes::CYLINDER:
{
Cylinder* capsule = (Cylinder*)shape.get();
const float radius = capsule->GetRadius();
const float height = capsule->GetHeight();
JPH::CylinderShapeSettings shapeSettings(height / 2.0f, radius);
result = shapeSettings.Create();
}
break;
case RigidbodyShapes::MESH:
{
MeshShape* meshShape = (MeshShape*)shape.get();
const auto& mesh = meshShape->GetMesh();
const auto& vertices = mesh->GetVertices();
const auto& indices = mesh->GetIndices();
JPH::TriangleList triangles;
triangles.reserve(indices.size());
Matrix4 transform; //rb->_transform;
transform[3] = Vector4(0, 0, 0, 1.0f);
for (int i = 0; i < indices.size() - 3; i += 3)
{
const Vector3& p1 = vertices[indices[i]].position;
const Vector3& p2 = vertices[indices[i + 1]].position;
const Vector3& p3 = vertices[indices[i + 2]].position;
const Vector4& tp1 = transform * Vector4(p1, 1.0f);
const Vector4& tp2 = transform * Vector4(p2, 1.0f);
const Vector4& tp3 = transform * Vector4(p3, 1.0f);
triangles.push_back(JPH::Triangle(JPH::Float3(tp1.x, tp1.y, tp1.z), JPH::Float3(tp2.x, tp2.y, tp2.z), JPH::Float3(tp3.x, tp3.y, tp3.z)));
}
JPH::MeshShapeSettings shapeSettings(std::move(triangles));
result = shapeSettings.Create();
}
break;
case CONVEX_HULL:
{
auto* convexHullShape = (Physics::ConvexHullShape*)shape.get();
const auto& hullPoints = convexHullShape->GetPoints();
JPH::Array<JPH::Vec3> points;
points.reserve(std::size(hullPoints));
for (const auto& p : hullPoints)
{
points.push_back(JPH::Vec3(p.x, p.y, p.z));
}
JPH::ConvexHullShapeSettings shapeSettings(points);
result = shapeSettings.Create();
}
break;
}
return result.Get();
}
}
}

View File

@@ -10,6 +10,7 @@
#include "CharacterController.h"
#include <Jolt/Jolt.h>
#include "src/Core/Core.h"
namespace JPH
{
class PhysicsSystem;
@@ -17,8 +18,13 @@ namespace JPH
class ContactListener;
class BodyActivationListener;
class BodyInterface;
class Shape;
template<class T>
class Ref;
}
namespace Nuake
{
class BPLayerInterfaceImpl;
@@ -26,7 +32,8 @@ namespace Nuake
class MyBodyActivationListener;
namespace Physics {
class DynamicWorld {
class DynamicWorld
{
private:
uint32_t _stepCount;
@@ -38,6 +45,7 @@ namespace Nuake
BPLayerInterfaceImpl* _JoltBroadphaseLayerInterface;
std::vector<uint32_t> _registeredBodies;
std::vector<uint32_t> _registeredCharacters;
public:
DynamicWorld();
@@ -54,7 +62,7 @@ namespace Nuake
void Clear();
private:
JPH::Ref<JPH::Shape> GetJoltShape(const Ref<PhysicShape> shape);
};
}
}

View File

@@ -58,8 +58,6 @@ namespace Nuake
JPH::Factory::sInstance = new JPH::Factory();
JPH::RegisterTypes();
// This is the max amount of rigid bodies that you can add to the physics system. If you try to add more you'll get an error.
// Note: This value is low because this is a simple test. For a real project use something in the order of 65536.
m_World = new Physics::DynamicWorld();
m_World->SetGravity(glm::vec3(0, -3, 0));

View File

@@ -12,24 +12,27 @@ namespace Nuake
}
// Sphere
Box::Box(glm::vec3 size) {
Box::Box(glm::vec3 size)
{
Size = size;
m_Type = BOX;
}
Box::Box(float x, float y, float z) {
Box::Box(float x, float y, float z)
{
Size = glm::vec3(x, y, z);
m_Type = BOX;
}
// Sphere
Sphere::Sphere(float radius) {
Sphere::Sphere(float radius)
{
Radius = radius;
m_Type = SPHERE;
}
void Sphere::SetRadius(float radius) {
void Sphere::SetRadius(float radius)
{
Radius = radius;
}
}

View File

@@ -20,7 +20,7 @@ namespace Nuake
RigidBody();
RigidBody(glm::vec3 position, Entity handle);
RigidBody(float mass, glm::vec3 position, Matrix4 _transform, Ref<PhysicShape> shape, Entity entity, glm::vec3 initialVel = glm::vec3(0, 0, 0));
RigidBody(float mass, glm::vec3 position, Matrix4 transform, Ref<PhysicShape> shape, Entity entity, glm::vec3 initialVel = glm::vec3(0, 0, 0));
void UpdateTransform();

View File

@@ -39,7 +39,7 @@ namespace Nuake
void RigidBody::SetEntityID(Entity ent)
{
_entity = ent;
}
}
}

View File

@@ -29,25 +29,26 @@ namespace Nuake {
Meshes = std::vector<Ref<Mesh>>();
Materials = std::vector<Ref<Material>>();
Rigidbody = std::vector<Ref<Physics::RigidBody>>();
Hulls = std::vector<std::vector<Vector3>>();
}
json Serialize()
{
BEGIN_SERIALIZE();
//for (uint32_t i = 0; i < Hulls.size() - 1; i++)
//{
// json hullPointsJson;
for (uint32_t i = 0; i < Hulls.size(); i++)
{
json hullPointsJson;
// size_t hullSize = Hulls[i].size();
// for (uint32_t j = 0; j < hullSize; j++)
// {
// hullPointsJson[j]["x"] = Hulls[i][j].x;
// hullPointsJson[j]["y"] = Hulls[i][j].y;
// hullPointsJson[j]["z"] = Hulls[i][j].z;
// }
// j["Hulls"][i] = hullPointsJson;
//}
size_t hullSize = Hulls[i].size();
for (uint32_t j = 0; j < hullSize; j++)
{
hullPointsJson[j]["x"] = Hulls[i][j].x;
hullPointsJson[j]["y"] = Hulls[i][j].y;
hullPointsJson[j]["z"] = Hulls[i][j].z;
}
j["Hulls"][i] = hullPointsJson;
}
j["IsSolid"] = IsSolid;
END_SERIALIZE();

View File

@@ -7,28 +7,36 @@ namespace Nuake {
public:
Ref<Physics::CharacterController> CharacterController;
float Height = 1.0f;
float Radius = 0.2f;
float Mass = 25.0f;
float Friction = 0.5f;
float MaxSlopeAngle = 0.45f;
CharacterControllerComponent()
{
}
json Serialize() {
json Serialize()
{
BEGIN_SERIALIZE();
SERIALIZE_VAL(Height);
SERIALIZE_VAL(Radius);
SERIALIZE_VAL(Mass);
SERIALIZE_VAL(Friction);
SERIALIZE_VAL(MaxSlopeAngle);
END_SERIALIZE();
}
bool Deserialize(const std::string str) {
bool Deserialize(const std::string str)
{
BEGIN_DESERIALIZE();
Height = j["Height"];
Radius = j["Radius"];
Mass = j["Mass"];
if (j.contains("Friction"))
{
Friction = j["Friction"];
}
if (j.contains("MaxSlopeAngle"))
{
MaxSlopeAngle = j["MaxSlopeAngle"];
}
return true;
}
};

View File

@@ -8,6 +8,7 @@ namespace Nuake {
public:
int SubMesh = 0;
bool IsTrigger;
Ref<Physics::MeshShape> Shape;
json Serialize()
{

View File

@@ -22,113 +22,12 @@ namespace Nuake
bool PhysicsSystem::Init()
{
// Create physic world.
auto view = m_Scene->m_Registry.view<TransformComponent, RigidBodyComponent>();
for (auto e : view)
{
auto [transform, rigidBodyComponent] = view.get<TransformComponent, RigidBodyComponent>(e);
Entity ent = Entity({ e, m_Scene });
Ref<Physics::RigidBody> rigidBody;
if (ent.HasComponent<BoxColliderComponent>())
{
float mass = rigidBodyComponent.Mass;
BoxColliderComponent& boxComponent = ent.GetComponent<BoxColliderComponent>();
Ref<Physics::Box> boxShape = CreateRef<Physics::Box>(boxComponent.Size);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), boxShape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<CapsuleColliderComponent>())
{
auto& capsuleComponent = ent.GetComponent<CapsuleColliderComponent>();
float radius = capsuleComponent.Radius;
float height = capsuleComponent.Height;
auto capsuleShape = CreateRef<Physics::Capsule>(radius, height);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), capsuleShape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<SphereColliderComponent>())
{
float mass = rigidBodyComponent.Mass;
const auto& component = ent.GetComponent<SphereColliderComponent>();
auto shape = CreateRef<Physics::Sphere>(component.Radius);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), shape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<MeshColliderComponent>())
{
if (!ent.HasComponent<ModelComponent>())
{
Logger::Log("Cannot use mesh collider without model component", WARNING);
}
const auto& modelComponent = ent.GetComponent<ModelComponent>();
const auto& component = ent.GetComponent<MeshColliderComponent>();
if (modelComponent.ModelResource)
{
uint32_t subMeshId = component.SubMesh;
const std::vector<Ref<Mesh>>& submeshes = modelComponent.ModelResource->GetMeshes();
if (subMeshId >= submeshes.size())
{
Logger::Log("Cannot create mesh collider, invalid submesh ID", WARNING);
}
Ref<Mesh> mesh = submeshes[subMeshId];
auto shape = CreateRef<Physics::MeshShape>(mesh);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), shape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
}
}
//const auto characterControllerView = m_Scene->m_Registry.view<TransformComponent, CharacterControllerComponent>();
//for (auto e : characterControllerView)
//{
// Entity ent = Entity({ e, m_Scene });
// auto [transformComponent, ccc] = view.get<TransformComponent, CharacterControllerComponent>(e);
//auto& physicsObject = CreateRef<Physics::CharacterController>(ccc.);
//}
//// character controllers
//auto ccview = m_Scene->m_Registry.view<TransformComponent, CharacterControllerComponent>();
//for (auto e : ccview)
//{
// auto [transform, cc] = ccview.get<TransformComponent, CharacterControllerComponent>(e);
// cc.CharacterController = CreateRef<Physics::CharacterController>(cc.Height, cc.Radius, cc.Mass, transform.GetLocalPosition());
// Entity ent = Entity({ e, m_Scene });
// cc.CharacterController->SetEntity(ent);
// PhysicsManager::Get()->RegisterCharacterController(cc.CharacterController);
//}
auto bspView = m_Scene->m_Registry.view<TransformComponent, BSPBrushComponent, ModelComponent>();
for (auto e : bspView)
{
Entity ent = Entity({ e, m_Scene });
auto [transform, brush, model] = bspView.get<TransformComponent, BSPBrushComponent, ModelComponent>(e);
if (!brush.IsSolid)
continue;
for (const auto& h : brush.Hulls)
{
Ref<Physics::ConvexHullShape> meshShape = CreateRef<Physics::ConvexHullShape>(h);
Ref<Physics::RigidBody> btRigidbody = CreateRef<Physics::RigidBody>(0.0f, transform.GetGlobalPosition(), transform.GetGlobalTransform(), meshShape, ent);
btRigidbody->SetEntityID(Entity{ e, m_Scene });
brush.Rigidbody.push_back(btRigidbody);
PhysicsManager::Get().RegisterBody(btRigidbody);
}
}
InitializeRigidbodies();
InitializeCharacterControllers();
InitializeQuakeMap();
// TODO: Triggers
//auto bspTriggerView = m_Scene->m_Registry.view<TransformComponent, BSPBrushComponent, TriggerZone>();
//for (auto e : bspTriggerView)
//{
@@ -140,6 +39,7 @@ namespace Nuake
// PhysicsManager::Get()->RegisterGhostBody(ghostBody);
//}
return true;
}
@@ -219,4 +119,175 @@ namespace Nuake
{
PhysicsManager::Get().Reset();
}
void PhysicsSystem::InitializeQuakeMap()
{
auto quakeBrushesView = m_Scene->m_Registry.view<TransformComponent, BSPBrushComponent, ModelComponent>();
for (auto e : quakeBrushesView)
{
const auto [transformComponent, brushComponent, modelComponent] = quakeBrushesView.get<TransformComponent, BSPBrushComponent, ModelComponent>(e);
// Doesn't apply to non-solid brushes
if (!brushComponent.IsSolid)
{
continue;
}
for (const auto& hull : brushComponent.Hulls)
{
const auto entity = Entity({ e, m_Scene });
const Vector3 startPosition = transformComponent.GetGlobalPosition();
const Matrix4 startTransform = transformComponent.GetGlobalTransform();
const auto collisionShape = CreateRef<Physics::ConvexHullShape>(hull);
auto rigidBody = CreateRef<Physics::RigidBody>(0.0f, startPosition, startTransform, collisionShape, entity);
brushComponent.Rigidbody.push_back(rigidBody);
PhysicsManager::Get().RegisterBody(rigidBody);
}
}
}
void PhysicsSystem::InitializeShapes()
{
const auto boxView = m_Scene->m_Registry.view<BoxColliderComponent>();
for (auto entity : boxView)
{
auto boxComponent = boxView.get<BoxColliderComponent>(entity);
boxComponent.Box = CreateRef<Physics::Box>(boxComponent.Size);
}
const auto capsuleView = m_Scene->m_Registry.view<CapsuleColliderComponent>();
for (auto entity : capsuleView)
{
auto capsuleComponent = capsuleView.get<CapsuleColliderComponent>(entity);
float radius = capsuleComponent.Radius;
float height = capsuleComponent.Height;
capsuleComponent.Capsule = CreateRef<Physics::Capsule>(radius, height);
}
const auto sphereView = m_Scene->m_Registry.view<SphereColliderComponent>();
for (auto entity : sphereView)
{
auto sphereComponent = sphereView.get<SphereColliderComponent>(entity);
sphereComponent.Sphere = CreateRef<Physics::Sphere>(sphereComponent.Radius);
}
const auto meshColliderView = m_Scene->m_Registry.view<MeshColliderComponent>();
for (auto e : meshColliderView)
{
Entity entity { e, m_Scene };
if (!entity.HasComponent<ModelComponent>())
{
Logger::Log("Cannot use mesh collider without model component", WARNING);
}
auto meshColliderComponent = meshColliderView.get<MeshColliderComponent>(e);
const auto& modelComponent = entity.GetComponent<ModelComponent>();
if (modelComponent.ModelResource)
{
uint32_t subMeshId = meshColliderComponent.SubMesh;
const std::vector<Ref<Mesh>>& submeshes = modelComponent.ModelResource->GetMeshes();
if (subMeshId >= submeshes.size())
{
Logger::Log("Cannot create mesh collider, invalid submesh ID", WARNING);
}
Ref<Mesh> mesh = submeshes[subMeshId];
meshColliderComponent.Shape = CreateRef<Physics::MeshShape>(mesh);
}
}
}
void PhysicsSystem::InitializeRigidbodies()
{
auto view = m_Scene->m_Registry.view<TransformComponent, RigidBodyComponent>();
for (auto e : view)
{
auto [transform, rigidBodyComponent] = view.get<TransformComponent, RigidBodyComponent>(e);
Entity ent = Entity({ e, m_Scene });
Ref<Physics::RigidBody> rigidBody;
if (ent.HasComponent<BoxColliderComponent>())
{
float mass = rigidBodyComponent.Mass;
BoxColliderComponent& boxComponent = ent.GetComponent<BoxColliderComponent>();
Ref<Physics::Box> boxShape = CreateRef<Physics::Box>(boxComponent.Size);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), boxShape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<CapsuleColliderComponent>())
{
auto& capsuleComponent = ent.GetComponent<CapsuleColliderComponent>();
float radius = capsuleComponent.Radius;
float height = capsuleComponent.Height;
auto capsuleShape = CreateRef<Physics::Capsule>(radius, height);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), capsuleShape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<SphereColliderComponent>())
{
float mass = rigidBodyComponent.Mass;
const auto& component = ent.GetComponent<SphereColliderComponent>();
auto shape = CreateRef<Physics::Sphere>(component.Radius);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), shape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
if (ent.HasComponent<MeshColliderComponent>())
{
if (!ent.HasComponent<ModelComponent>())
{
Logger::Log("Cannot use mesh collider without model component", WARNING);
}
const auto& modelComponent = ent.GetComponent<ModelComponent>();
const auto& component = ent.GetComponent<MeshColliderComponent>();
if (modelComponent.ModelResource)
{
uint32_t subMeshId = component.SubMesh;
const std::vector<Ref<Mesh>>& submeshes = modelComponent.ModelResource->GetMeshes();
if (subMeshId >= submeshes.size())
{
Logger::Log("Cannot create mesh collider, invalid submesh ID", WARNING);
}
Ref<Mesh> mesh = submeshes[subMeshId];
auto shape = CreateRef<Physics::MeshShape>(mesh);
rigidBody = CreateRef<Physics::RigidBody>(rigidBodyComponent.Mass, transform.GetGlobalPosition(), transform.GetGlobalTransform(), shape, ent);
PhysicsManager::Get().RegisterBody(rigidBody);
}
}
}
}
void PhysicsSystem::InitializeCharacterControllers()
{
auto characterControllerView = m_Scene->m_Registry.view<TransformComponent, CharacterControllerComponent>();
for (const auto& e : characterControllerView)
{
Entity entity = Entity({ e, m_Scene });
auto [transformComponent, characterControllerComponent] = characterControllerView.get<TransformComponent, CharacterControllerComponent>(e);
if (entity.HasComponent<CapsuleColliderComponent>())
{
const auto& capsuleColliderComponent = entity.GetComponent<CapsuleColliderComponent>();
auto& capsule = capsuleColliderComponent.Capsule;
float friction = characterControllerComponent.Friction;
float maxSlopeAngle = characterControllerComponent.MaxSlopeAngle;
auto characterController = CreateRef<Physics::CharacterController>(capsule, friction, maxSlopeAngle);
characterControllerComponent.CharacterController = characterController;
PhysicsManager::Get().RegisterCharacterController(characterControllerComponent.CharacterController);
}
// TODO: Other types of collider supported for character controller?
}
}
}

View File

@@ -12,5 +12,12 @@ namespace Nuake
void Draw() override {}
void FixedUpdate(Timestep ts) override;
void Exit() override;
private:
void InitializeShapes();
void InitializeQuakeMap();
void InitializeRigidbodies();
void InitializeCharacterControllers();
};
}