Partial implementation of a generic convex polyhedron object

This commit is contained in:
Diren D Bharwani 2022-12-30 00:45:37 +08:00
parent ea1dd57996
commit 400cbb35d9
5 changed files with 392 additions and 11 deletions

View File

@ -131,6 +131,7 @@
Colliders: Colliders:
- Is Trigger: false - Is Trigger: false
Type: Box Type: Box
Half Extents: {x: 1, y: 1, z: 1}
Friction: 0.400000006 Friction: 0.400000006
Bounciness: 0 Bounciness: 0
Density: 1 Density: 1

View File

@ -18,6 +18,19 @@
#include "Math/SHMatrix.h" #include "Math/SHMatrix.h"
#include "Physics/Collision/SHCollider.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 namespace SHADE
{ {
/*-----------------------------------------------------------------------------------*/ /*-----------------------------------------------------------------------------------*/
@ -29,6 +42,7 @@ namespace SHADE
, SHBox () , SHBox ()
, relativeExtents { SHVec3::One } , relativeExtents { SHVec3::One }
, scale { SHVec3::One } , scale { SHVec3::One }
, polyhedron { nullptr }
{} {}
SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept SHBoxCollisionShape::SHBoxCollisionShape(const SHBoxCollisionShape& rhs) noexcept
@ -36,6 +50,7 @@ namespace SHADE
, SHBox (rhs.Center, rhs.Extents, rhs.Orientation) , SHBox (rhs.Center, rhs.Extents, rhs.Orientation)
, relativeExtents { rhs.relativeExtents } , relativeExtents { rhs.relativeExtents }
, scale { rhs.scale } , scale { rhs.scale }
, polyhedron { rhs.polyhedron }
{ {
material = rhs.material; material = rhs.material;
@ -52,6 +67,7 @@ namespace SHADE
, SHBox (rhs.Center, rhs.Extents, rhs.Orientation) , SHBox (rhs.Center, rhs.Extents, rhs.Orientation)
, relativeExtents { rhs.relativeExtents } , relativeExtents { rhs.relativeExtents }
, scale { rhs.scale } , scale { rhs.scale }
, polyhedron { rhs.polyhedron }
{ {
material = rhs.material; material = rhs.material;
@ -93,6 +109,7 @@ namespace SHADE
relativeExtents = rhs.relativeExtents; relativeExtents = rhs.relativeExtents;
scale = rhs.scale; scale = rhs.scale;
polyhedron = rhs.polyhedron;
return *this; return *this;
} }
@ -120,6 +137,7 @@ namespace SHADE
relativeExtents = rhs.relativeExtents; relativeExtents = rhs.relativeExtents;
scale = rhs.scale; scale = rhs.scale;
polyhedron = rhs.polyhedron;
return *this; return *this;
} }

View File

@ -13,6 +13,7 @@
// Project Headers // Project Headers
#include "Math/Geometry/SHBox.h" #include "Math/Geometry/SHBox.h"
#include "SHCollisionShape.h" #include "SHCollisionShape.h"
#include "SHConvexPolyhedron.h"
namespace SHADE namespace SHADE
{ {
@ -152,6 +153,7 @@ namespace SHADE
SHVec3 relativeExtents; SHVec3 relativeExtents;
SHVec3 scale; // Intended to be passed in by the base collider. SHVec3 scale; // Intended to be passed in by the base collider.
SHConvexPolyhedron* polyhedron; // Defines the polyhedron by it's half edges.
}; };

View File

@ -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

View File

@ -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