Program Listing for File mesh_splitter.hpp¶
↰ Return to documentation for file (/home/runner/work/Legion-Engine/Legion-Engine/legion/engine/physics/mesh_splitter_utils/mesh_splitter.hpp
)
#pragma once
#include <core/core.hpp>
#include <physics/mesh_splitter_utils/mesh_splitter_typedefs.hpp>
#include <physics/mesh_splitter_utils/mesh_half_edge.hpp>
#include <physics/mesh_splitter_utils/splittable_polygon.hpp>
#include <rendering/components/renderable.hpp>
#include <physics/mesh_splitter_utils/primitive_mesh.hpp>
#include <rendering/components/renderable.hpp>
#include <physics/mesh_splitter_utils/half_edge_finder.hpp>
#include <physics/mesh_splitter_utils/mesh_splitter_debug_helpers.hpp>
#include <physics/mesh_splitter_utils/intersecting_polygon_organizer.hpp>
#include <physics/mesh_splitter_utils/mesh_split_params.hpp>
#include <physics/mesh_splitter_utils/intersection_edge_info.hpp>
namespace legion::physics
{
struct MeshSplitter
{
ecs::entity_handle owner;
std::vector<ecs::entity_handle> splitTester;
rendering::material_handle ownerMaterialH;
std::vector<SplittablePolygonPtr> meshPolygons;
//MeshSplitterDebugHelper debugHelper;
//------------------------------------------------------ Function related to Mesh Splitter Initialization ---------------------------------------------//
void InitializePolygons(ecs::entity_handle entity);
void BFSPolygonize(std::queue<meshHalfEdgePtr>& halfEdgeQueue, const math::mat4& transform)
{
//while edge queue is not empty
while (!halfEdgeQueue.empty())
{
meshHalfEdgePtr startEdge = halfEdgeQueue.front();
halfEdgeQueue.pop();
if (!startEdge->isVisited)
{
SplittablePolygonPtr polygon = nullptr;
if (BFSIdentifyPolygon(startEdge, polygon, halfEdgeQueue, transform))
{
meshPolygons.push_back(polygon);
}
}
}
}
bool BFSIdentifyPolygon(meshHalfEdgePtr startEdge
, std::shared_ptr<SplittablePolygon>& polygon, std::queue<meshHalfEdgePtr>& halfEdgeQueue
, const math::mat4& transform)
{
log::debug("->BFSIdentifyPolygon");
//polygonEdgeList : edges considered to be in the same polygon
std::vector<meshHalfEdgePtr> edgesInPolygon;
meshHalfEdgePtr nextEdge = nullptr;
meshHalfEdgePtr prevEdge = nullptr;
//startEdge may not form a triangle,we early out if this happens
if (!startEdge->attemptGetTrianglesInEdges(nextEdge, prevEdge))
{
return false;
}
edgesInPolygon.push_back(startEdge);
edgesInPolygon.push_back(nextEdge);
edgesInPolygon.push_back(prevEdge);
//mark all edges visited
startEdge->markTriangleEdgeVisited();
//get all neigbors of the startEdge Triangle and put them in unvisitedEdgeQueue
std::queue<meshHalfEdgePtr> unvisitedEdgeQueue;
startEdge->populateQueueWithTriangleNeighbor(unvisitedEdgeQueue);
std::vector<meshHalfEdgePtr> edgesNotInPolygon;
const math::vec3 comparisonNormal = startEdge->calculateEdgeNormal(transform);
//BFS search for adjacent triangles with same normal
while (!unvisitedEdgeQueue.empty())
{
//log::debug("Pop Edge");
auto edgeToCheck = unvisitedEdgeQueue.front();
unvisitedEdgeQueue.pop();
if (!edgeToCheck) { continue; }
if (!edgeToCheck->isVisited && edgeToCheck->isTriangleValid())
{
edgeToCheck->markTriangleEdgeVisited();
//if triangle has same normal as original
if (edgeToCheck->isNormalCloseEnough(comparisonNormal, transform))
{
//add all edges in triangle to polygonEdgeList
edgeToCheck->populateVectorWithTriangle(edgesInPolygon);
//add neigbors to polygonEdgeNonVisitedQueue
edgeToCheck->populateQueueWithTriangleNeighbor(unvisitedEdgeQueue);
}
else
{
//add edge to edgesNotInPolygon
edgeToCheck->populateVectorWithTriangle(edgesNotInPolygon);
}
}
}
for (auto edge : edgesNotInPolygon)
{
edge->isVisited = false;
halfEdgeQueue.push(edge);
}
math::vec3 localNormal = math::inverse(transform) * math::vec4(comparisonNormal, 0);
polygon = std::make_shared<SplittablePolygon>(edgesInPolygon, localNormal);
polygon->AssignEdgeOwnership();
polygon->IdentifyBoundaries(transform);
return true;
}
//--------------------------------------------------------- Function related to splitting ----------------------------------------------------------------//
void MultipleSplitMesh(const std::vector<MeshSplitParams>& splittingPlanes, std::vector<ecs::entity_handle>& entitiesGenerated,
bool keepBelow = true,int debugAt = -1);
void SplitPolygons
(std::vector<SplittablePolygonPtr>& polygonsToSplit,
const math::vec3& planeNormal,
const math::vec3& planePosition,
const math::mat4& transform,
std::vector<std::vector<SplittablePolygonPtr>>& resultingIslands,
bool keepBelow = true, bool shouldDebug = false);
//--------------------------------------------------------- Function related to polygon copying ----------------------------------------------------------------//
void CopyPolygons(std::vector<SplittablePolygonPtr>& originalSplitMesh, std::vector<SplittablePolygonPtr>& copySplitMesh);
void CopyEdgeVector(std::vector<meshHalfEdgePtr>& originalHalfEdgeList, std::vector<meshHalfEdgePtr>& resultCopyList);
//--------------------------------------------------------- MeshSplitting helper functions ----------------------------------------------------------------//
void BFSFindRequestedAndIntersecting(
SplittablePolygonPtr& intialPolygon,
std::vector<SplittablePolygonPtr>& originalSplitMesh,
std::vector<SplittablePolygonPtr>& originalNonSplitMesh, SplitState requestedState);
void DetectIntersectionIsland(std::vector<SplittablePolygonPtr>& splitPolygons,
std::vector<std::vector<SplittablePolygonPtr>>& intersectionIslands);
void SplitPolygon(SplittablePolygonPtr splitPolygon
, const math::mat4& transform, const math::vec3 cutPosition
, const math::vec3 cutNormal, SplitState requestedState,
std::vector<IntersectionEdgeInfo>& generatedIntersectionEdges, bool shouldDebug = false);
bool FindFirstIntersectingOrRequestedState(SplittablePolygonPtr& outfirstFound, SplitState requestedState
, std::vector<SplittablePolygonPtr>& polygonList)
{
for (auto polygon : polygonList)
{
if (!polygon->isVisited)
{
auto polygonSplitState = polygon->GetPolygonSplitState();
if (polygonSplitState == SplitState::Split
|| polygonSplitState == requestedState)
{
outfirstFound = polygon;
return true;
}
}
}
return false;
}
bool FindFirstUnivistedIntersectionPolygon(std::vector< SplittablePolygonPtr>& splitPolygon, SplittablePolygonPtr& foundPolygon)
{
for (auto polygonPtr : splitPolygon)
{
if (!polygonPtr->isVisited)
{
foundPolygon = polygonPtr;
return true;
}
}
return false;
}
SplittablePolygonPtr CreateIntersectionPolygon(
std::vector<IntersectionEdgeInfo>& generatedIntersectionEdges,
const math::vec3& localSplitNormal)
{
//log::debug("CreateIntersectionPolygon");
std::vector<meshHalfEdgePtr> edgesCreated;
math::vec3 localCentroid{};
//---------------------------------- Instantiate Edges and connect them into a triangle -------------------------------------//
for (IntersectionEdgeInfo& info : generatedIntersectionEdges)
{
//instantiate edge and set its pairing
meshHalfEdgePtr firstEdge = std::make_shared<MeshHalfEdge>(info.first,math::vec2(0.0f));
meshHalfEdgePtr secondEdge = std::make_shared<MeshHalfEdge>(info.second, math::vec2(0.0f));
//temporarily second edge to info.second
meshHalfEdgePtr thirdEdge = std::make_shared<MeshHalfEdge>(info.second, math::vec2(0.0f));
info.centroidEdge = thirdEdge;
info.instantiatedEdge = firstEdge;
info.pairingToConnectTo->setPairing(info.instantiatedEdge);
info.instantiatedEdge->isBoundary = true;
MeshHalfEdge::connectIntoTriangle(firstEdge, secondEdge, thirdEdge);
info.instantiatedEdge->populateVectorWithTriangle(edgesCreated);
localCentroid += info.first;
}
localCentroid /= (float)generatedIntersectionEdges.size();
//---------------------------------- Set the centroid edge to the local centroid of the polygon -------------------------------------//
for (IntersectionEdgeInfo& info : generatedIntersectionEdges)
{
info.centroidEdge->position = localCentroid;
assert(info.instantiatedEdge->nextEdge->nextEdge);
}
//---------------------------------- Set pairing information of all edges ---------------------------------------------//
for (IntersectionEdgeInfo& info : generatedIntersectionEdges)
{
float currentClosestDistance = std::numeric_limits<float>::max();
meshHalfEdgePtr closestEdge = nullptr;
//get closest unvisisted IntersectionEdgeInfo
const math::vec3& pointToCompare = info.second;
//find edge closest to pointToCompare
for (IntersectionEdgeInfo& otherInfo : generatedIntersectionEdges)
{
assert(otherInfo.instantiatedEdge);
if (info.instantiatedEdge == otherInfo.instantiatedEdge) { continue; }
float distanceFound = math::distance2(pointToCompare, otherInfo.first);
//log::debug("distanceFound {}" , distanceFound);
if (distanceFound < currentClosestDistance)
{
currentClosestDistance = distanceFound;
closestEdge = otherInfo.centroidEdge;
}
}
assert(closestEdge);
auto infoEdge = info.instantiatedEdge->nextEdge;
auto infoEdgePairing = closestEdge;
infoEdge->setPairing(infoEdgePairing);
}
auto polygon = std::make_shared<SplittablePolygon>(edgesCreated, localSplitNormal);
polygon->AssignEdgeOwnership();
return polygon;
};
#pragma endregion
//--------------------------------------------------------- Functions related to Debugging ---------------------------------------------------//
void DestroyTestSplitter(ecs::EcsRegistry* m_ecs)
{
for (auto splitObject : splitTester)
{
m_ecs->destroyEntity(splitObject);
}
splitTester.clear();
}
void TestSplit()
{
if (!splitTester.empty())
{
std::vector<MeshSplitParams> splittingPlanes;
for (auto splitObject : splitTester)
{
auto [posH, rotH, scaleH] = splitObject.get_component_handles<transform>();
const math::mat4 transform = math::compose(scaleH.read(), rotH.read(), posH.read());
const math::vec3 worldUp = transform * math::vec4(0, 1, 0, 0);
splittingPlanes.push_back(MeshSplitParams(posH.read(), math::normalize(worldUp)));
}
std::vector<ecs::entity_handle> entities;
MultipleSplitMesh(splittingPlanes, entities);
}
else
{
log::error("Split tester not set");
}
}
void DEBUG_DrawPolygonData(const math::mat4& transform);
};
}