Partial implementation of a generic convex polyhedron object
This commit is contained in:
parent
ea1dd57996
commit
400cbb35d9
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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