Implemented a custom physics engine #316
|
@ -131,6 +131,7 @@
|
|||
Colliders:
|
||||
- Is Trigger: false
|
||||
Type: Box
|
||||
Half Extents: {x: 1, y: 1, z: 1}
|
||||
Friction: 0.400000006
|
||||
Bounciness: 0
|
||||
Density: 1
|
||||
|
|
|
@ -18,6 +18,19 @@
|
|||
#include "Math/SHMatrix.h"
|
||||
#include "Physics/Collision/SHCollider.h"
|
||||
|
||||
/*
|
||||
* Local box vertices, faces & half-edges
|
||||
*
|
||||
* Vertices (Front/Back Face):
|
||||
*
|
||||
* 3/7 ---------- 2/6
|
||||
* | |
|
||||
* | |
|
||||
* | |
|
||||
* 0/4 ---------- 1/5
|
||||
*
|
||||
*/
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
@ -29,6 +42,7 @@ namespace SHADE
|
|||
, SHBox ()
|
||||
, relativeExtents { SHVec3::One }
|
||||
, scale { SHVec3::One }
|
||||
, polyhedron { nullptr }
|
||||
{}
|
||||
|
||||
SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept
|
||||
|
@ -36,6 +50,7 @@ namespace SHADE
|
|||
, SHBox (rhs.Center, rhs.Extents, rhs.Orientation)
|
||||
, relativeExtents { rhs.relativeExtents }
|
||||
, scale { rhs.scale }
|
||||
, polyhedron { rhs.polyhedron }
|
||||
{
|
||||
|
||||
material = rhs.material;
|
||||
|
@ -52,6 +67,7 @@ namespace SHADE
|
|||
, SHBox (rhs.Center, rhs.Extents, rhs.Orientation)
|
||||
, relativeExtents { rhs.relativeExtents }
|
||||
, scale { rhs.scale }
|
||||
, polyhedron { rhs.polyhedron }
|
||||
{
|
||||
|
||||
material = rhs.material;
|
||||
|
@ -93,6 +109,7 @@ namespace SHADE
|
|||
|
||||
relativeExtents = rhs.relativeExtents;
|
||||
scale = rhs.scale;
|
||||
polyhedron = rhs.polyhedron;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
@ -120,6 +137,7 @@ namespace SHADE
|
|||
|
||||
relativeExtents = rhs.relativeExtents;
|
||||
scale = rhs.scale;
|
||||
polyhedron = rhs.polyhedron;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
// Project Headers
|
||||
#include "Math/Geometry/SHBox.h"
|
||||
#include "SHCollisionShape.h"
|
||||
#include "SHConvexPolyhedron.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
|
@ -152,6 +153,7 @@ namespace SHADE
|
|||
|
||||
SHVec3 relativeExtents;
|
||||
SHVec3 scale; // Intended to be passed in by the base collider.
|
||||
SHConvexPolyhedron* polyhedron; // Defines the polyhedron by it's half edges.
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,216 @@
|
|||
/****************************************************************************************
|
||||
* \file SHConvexPolyhedron.cpps
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Implementation for a convex polyhedron structure.
|
||||
*
|
||||
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||
* disclosure of this file or its contents without the prior written consent
|
||||
* of DigiPen Institute of Technology is prohibited.
|
||||
****************************************************************************************/
|
||||
|
||||
#include <SHpch.h>
|
||||
|
||||
// Primary Header
|
||||
#include "SHConvexPolyhedron.h"
|
||||
|
||||
// Helper Macros
|
||||
|
||||
#define BUILD_UINT64_FROM_UINT32S(a, b) (uint64_t)a << 32 | b
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHConvexPolyhedron::HalfEdge::HalfEdge() noexcept
|
||||
: tailVertexIndex { -1 }
|
||||
, headVertexIndex { -1 }
|
||||
, edgeIndex { -1 }
|
||||
, twinEdgeIndex { -1 }
|
||||
, faceIndex { -1 }
|
||||
{}
|
||||
|
||||
SHConvexPolyhedron::HalfEdge::HalfEdge(const HalfEdge& rhs) noexcept
|
||||
: tailVertexIndex { rhs.tailVertexIndex }
|
||||
, headVertexIndex { rhs.headVertexIndex }
|
||||
, edgeIndex { rhs.edgeIndex }
|
||||
, twinEdgeIndex { rhs.twinEdgeIndex }
|
||||
, faceIndex { rhs.faceIndex }
|
||||
{}
|
||||
|
||||
SHConvexPolyhedron::HalfEdge::HalfEdge(HalfEdge&& rhs) noexcept
|
||||
: tailVertexIndex { rhs.tailVertexIndex }
|
||||
, headVertexIndex { rhs.headVertexIndex }
|
||||
, edgeIndex { rhs.edgeIndex }
|
||||
, twinEdgeIndex { rhs.twinEdgeIndex }
|
||||
, faceIndex { rhs.faceIndex }
|
||||
{}
|
||||
|
||||
SHConvexPolyhedron::Face::Face(const Face& rhs) noexcept
|
||||
: normal { rhs.normal }
|
||||
{
|
||||
std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices));
|
||||
}
|
||||
|
||||
SHConvexPolyhedron::Face::Face(Face&& rhs) noexcept
|
||||
: normal { rhs.normal }
|
||||
{
|
||||
std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices));
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Operator Overload Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(const HalfEdge& rhs) noexcept
|
||||
{
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
tailVertexIndex = rhs.tailVertexIndex;
|
||||
headVertexIndex = rhs.headVertexIndex;
|
||||
edgeIndex = rhs.edgeIndex ;
|
||||
twinEdgeIndex = rhs.twinEdgeIndex ;
|
||||
faceIndex = rhs.faceIndex ;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::HalfEdge::operator=(HalfEdge&& rhs) noexcept
|
||||
{
|
||||
tailVertexIndex = rhs.tailVertexIndex;
|
||||
headVertexIndex = rhs.headVertexIndex;
|
||||
edgeIndex = rhs.edgeIndex ;
|
||||
twinEdgeIndex = rhs.twinEdgeIndex ;
|
||||
faceIndex = rhs.faceIndex ;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(const Face& rhs) noexcept
|
||||
{
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
normal = rhs.normal;
|
||||
|
||||
vertexIndices.clear();
|
||||
std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
SHConvexPolyhedron::Face& SHConvexPolyhedron::Face::operator=(Face&& rhs) noexcept
|
||||
{
|
||||
normal = rhs.normal;
|
||||
|
||||
vertexIndices.clear();
|
||||
std::ranges::copy(rhs.vertexIndices.begin(), rhs.vertexIndices.end(), std::back_inserter(vertexIndices));
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Getter Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
int32_t SHConvexPolyhedron::GetFaceCount() const noexcept
|
||||
{
|
||||
return static_cast<int32_t>(faces.size());
|
||||
}
|
||||
|
||||
int32_t SHConvexPolyhedron::GetHalfEdgeCount() const noexcept
|
||||
{
|
||||
return static_cast<int32_t>(halfEdges.size());
|
||||
}
|
||||
|
||||
const SHConvexPolyhedron::Face& SHConvexPolyhedron::GetFace(int32_t index) const
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int32_t>(faces.size()))
|
||||
throw std::invalid_argument("Index out-of-range!");
|
||||
|
||||
return faces[index];
|
||||
}
|
||||
|
||||
const SHConvexPolyhedron::HalfEdge& SHConvexPolyhedron::GetHalfEdge(int32_t index) const
|
||||
{
|
||||
if (index < 0 || index >= static_cast<int32_t>(halfEdges.size()))
|
||||
throw std::invalid_argument("Index out-of-range!");
|
||||
|
||||
return halfEdges[index];
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Public Member Function Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
void SHConvexPolyhedron::AddFace(const Face& face)
|
||||
{
|
||||
faces.emplace_back(face);
|
||||
}
|
||||
|
||||
void SHConvexPolyhedron::BuildPolyhedron() noexcept
|
||||
{
|
||||
// We use the pair of vertex IDs on a half-edge to prevent duplicates
|
||||
std::unordered_map<uint64_t, HalfEdge> edgeMap;
|
||||
edgeMap.clear();
|
||||
|
||||
if (faces.empty())
|
||||
{
|
||||
SHLOGV_CRITICAL("Unable to build convex polyhedron, no faces have been added!")
|
||||
return;
|
||||
}
|
||||
|
||||
// For each face, build half edges
|
||||
for (size_t i = 0; i < faces.size(); ++i)
|
||||
{
|
||||
const Face& FACE = faces[i];
|
||||
|
||||
// Iterate through vertices and build half-edges
|
||||
for (size_t j = 0; j < FACE.vertexIndices.size(); ++j)
|
||||
{
|
||||
const int32_t TAIL = FACE.vertexIndices[j];
|
||||
const int32_t HEAD = (TAIL + 1) > FACE.vertexIndices.back() ? FACE.vertexIndices.front() : TAIL + 1; // Wrap around
|
||||
|
||||
const uint64_t NEW_EDGE_ID = BUILD_UINT64_FROM_UINT32S(TAIL, HEAD);
|
||||
const uint64_t TWIN_EDGE_ID = BUILD_UINT64_FROM_UINT32S(HEAD, TAIL);
|
||||
|
||||
// Check if the half-edge has already been inserted
|
||||
auto newEdgeIter = edgeMap.find(NEW_EDGE_ID);
|
||||
if (newEdgeIter == edgeMap.end())
|
||||
{
|
||||
// Reuse the iterator for mapping with the twin
|
||||
newEdgeIter = edgeMap.emplace(NEW_EDGE_ID, HalfEdge{}).first;
|
||||
|
||||
HalfEdge& newHalfEdge = newEdgeIter->second;
|
||||
newHalfEdge.tailVertexIndex = TAIL;
|
||||
newHalfEdge.headVertexIndex = HEAD;
|
||||
newHalfEdge.faceIndex = static_cast<int32_t>(i);
|
||||
|
||||
// Set edge index of the newly inserted edge as the size of the map - 1
|
||||
// Since it is an unordered map, it will just be at the back
|
||||
newHalfEdge.edgeIndex = static_cast<int32_t>(edgeMap.size()) - 1;
|
||||
}
|
||||
|
||||
// Find twin edge if one exists
|
||||
auto twinEdgeIter = edgeMap.find(TWIN_EDGE_ID);
|
||||
if (twinEdgeIter != edgeMap.end())
|
||||
{
|
||||
// Set the twin index of both the edges
|
||||
HalfEdge& newHalfEdge = newEdgeIter->second;
|
||||
HalfEdge& twinHalfEdge = twinEdgeIter->second;
|
||||
|
||||
newHalfEdge.twinEdgeIndex = twinHalfEdge.edgeIndex;
|
||||
twinHalfEdge.twinEdgeIndex = newHalfEdge.edgeIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Copy all half edges into the vector
|
||||
// At this point, no duplicates should be in the map and all edges should be linked.
|
||||
for (auto& halfEdge : edgeMap | std::views::values)
|
||||
halfEdges.emplace_back(halfEdge);
|
||||
}
|
||||
|
||||
} // namespace SHADE
|
|
@ -0,0 +1,144 @@
|
|||
/****************************************************************************************
|
||||
* \file SHConvexPolyhedron.h
|
||||
* \author Diren D Bharwani, diren.dbharwani, 390002520
|
||||
* \brief Interface for a convex polyhedron structure.
|
||||
*
|
||||
* \copyright Copyright (C) 2022 DigiPen Institute of Technology. Reproduction or
|
||||
* disclosure of this file or its contents without the prior written consent
|
||||
* of DigiPen Institute of Technology is prohibited.
|
||||
****************************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
|
||||
// Project Headers
|
||||
#include "Math/Vector/SHVec3.h"
|
||||
|
||||
namespace SHADE
|
||||
{
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*-----------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Encapsulates data for a convex polyhedron's geometry represented as faces & half edges.
|
||||
*/
|
||||
class SH_API SHConvexPolyhedron
|
||||
{
|
||||
public:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Type Definitions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
struct HalfEdge
|
||||
{
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
//Head and tail forms the edge.
|
||||
//Head <----- Tail
|
||||
int32_t tailVertexIndex;
|
||||
|
||||
// Head is also tail of the next edge.
|
||||
int32_t headVertexIndex;
|
||||
|
||||
int32_t edgeIndex;
|
||||
// Other half of the edge on a different face.
|
||||
// Important for extrapolating face normals.
|
||||
int32_t twinEdgeIndex;
|
||||
|
||||
// Adjacent face of this edge.
|
||||
int32_t faceIndex;
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
HalfEdge () noexcept;
|
||||
HalfEdge (const HalfEdge& rhs) noexcept;
|
||||
HalfEdge (HalfEdge&& rhs) noexcept;
|
||||
~HalfEdge () noexcept = default;
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
HalfEdge& operator= (const HalfEdge& rhs) noexcept;
|
||||
HalfEdge& operator= (HalfEdge&& rhs) noexcept;
|
||||
};
|
||||
|
||||
struct Face
|
||||
{
|
||||
public:
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
SHVec3 normal;
|
||||
std::vector<int32_t> vertexIndices; // Must be in CCW order
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Constructors & Destructor */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
Face () noexcept = default;
|
||||
Face (const Face& rhs) noexcept;
|
||||
Face (Face&& rhs) noexcept;
|
||||
~Face () noexcept = default;
|
||||
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
/* Operator Overloads */
|
||||
/*-------------------------------------------------------------------------------*/
|
||||
|
||||
Face& operator= (const Face& rhs) noexcept;
|
||||
Face& operator= (Face&& rhs) noexcept;
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Getter Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
[[nodiscard]] int32_t GetFaceCount () const noexcept;
|
||||
[[nodiscard]] int32_t GetHalfEdgeCount () const noexcept;
|
||||
|
||||
[[nodiscard]] const Face& GetFace (int32_t index) const;
|
||||
[[nodiscard]] const HalfEdge& GetHalfEdge (int32_t index) const;
|
||||
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Member Functions */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Adds a face to the polyhedron. The face must be constructed outside the polyhedron.
|
||||
* @param face
|
||||
* The face to insert.
|
||||
*/
|
||||
void AddFace (const Face& face);
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Builds the half-edges of the polyhedron using the faces. <br/>
|
||||
* Before this method is invoked, there must be some faces.
|
||||
* @return
|
||||
*/
|
||||
void BuildPolyhedron() noexcept;
|
||||
|
||||
private:
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
/* Data Members */
|
||||
/*---------------------------------------------------------------------------------*/
|
||||
|
||||
float radius = 0.2f; // Default Radius is 2 cm
|
||||
|
||||
// Store the faces and half-edges
|
||||
|
||||
std::vector<Face> faces;
|
||||
std::vector<HalfEdge> halfEdges;
|
||||
|
||||
};
|
||||
|
||||
} // namespace SHADE
|
Loading…
Reference in New Issue