// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2016-2020 NVIDIA Corporation. All rights reserved. #include "NvBlastGlobals.h" #include "NvBlastExtAuthoringBooleanTool.h" #include "NvBlastExtAuthoringMeshImpl.h" #include "NvBlastExtAuthoringAccelerator.h" #include #include #include #include using physx::PxBounds3; namespace Nv { namespace Blast { /* Linear interpolation of vectors */ NV_FORCE_INLINE void vec3Lerp(const NvcVec3& a, const NvcVec3& b, NvcVec3& out, float t) { out.x = (b.x - a.x) * t + a.x; out.y = (b.y - a.y) * t + a.y; out.z = (b.z - a.z) * t + a.z; } NV_FORCE_INLINE void vec2Lerp(const NvcVec2& a, const NvcVec2& b, NvcVec2& out, float t) { out.x = (b.x - a.x) * t + a.x; out.y = (b.y - a.y) * t + a.y; } NV_FORCE_INLINE int32_t BooleanEvaluator::addIfNotExist(Vertex& p) { mVerticesAggregate.push_back(p); return static_cast(mVerticesAggregate.size()) - 1; } NV_FORCE_INLINE void BooleanEvaluator::addEdgeIfValid(EdgeWithParent& ed) { mEdgeAggregate.push_back(ed); } /** Vertex level shadowing functions */ NV_FORCE_INLINE int32_t vertexShadowing(const NvcVec3& a, const NvcVec3& b) { return (b.x >= a.x) ? 1 : 0; } /** Vertex-edge status functions */ NV_FORCE_INLINE int32_t veStatus01(const NvcVec3& sEdge, const NvcVec3& eEdge, const NvcVec3& p) { return vertexShadowing(p, eEdge) - vertexShadowing(p, sEdge); } NV_FORCE_INLINE int32_t veStatus10(const NvcVec3& sEdge, const NvcVec3& eEdge, const NvcVec3& p) { return -vertexShadowing(eEdge, p) + vertexShadowing(sEdge, p); } bool shouldSwap(const NvcVec3& a, const NvcVec3& b) { if (a.x < b.x) return false; if (a.x > b.x) return true; if (a.y < b.y) return false; if (a.y > b.y) return true; if (a.z < b.z) return false; if (a.z > b.z) return true; return false; } /** Vertex-edge shadowing functions */ int32_t shadowing01(Vertex sEdge, Vertex eEdge, const NvcVec3& p, Vertex& onEdgePoint, bool& hasOnEdge) { int32_t winding = veStatus01(sEdge.p, eEdge.p, p); if (sEdge.p.x > eEdge.p.x) { std::swap(sEdge, eEdge); } if (winding != 0) { float t = (p.x - sEdge.p.x) / (eEdge.p.x - sEdge.p.x); if (t >= 1) { onEdgePoint = eEdge; } else if (t <= 0) { onEdgePoint = sEdge; } else { vec3Lerp(sEdge.p, eEdge.p, onEdgePoint.p, t); vec3Lerp(sEdge.n, eEdge.n, onEdgePoint.n, t); vec2Lerp(sEdge.uv[0], eEdge.uv[0], onEdgePoint.uv[0], t); } hasOnEdge = true; if (onEdgePoint.p.y >= p.y) { return winding; } } else { hasOnEdge = false; } return 0; } int32_t shadowing10(Vertex sEdge, Vertex eEdge, const NvcVec3& p, Vertex& onEdgePoint, bool& hasOnEdge) { int32_t winding = veStatus10(sEdge.p, eEdge.p, p); if (sEdge.p.x > eEdge.p.x) { std::swap(sEdge, eEdge); } if (winding != 0) { float t = (p.x - sEdge.p.x) / (eEdge.p.x - sEdge.p.x); if (t >= 1) { onEdgePoint = eEdge; } else if (t <= 0) { onEdgePoint = sEdge; } else { vec3Lerp(sEdge.p, eEdge.p, onEdgePoint.p, t); vec3Lerp(sEdge.n, eEdge.n, onEdgePoint.n, t); vec2Lerp(sEdge.uv[0], eEdge.uv[0], onEdgePoint.uv[0], t); } hasOnEdge = true; if (onEdgePoint.p.y < p.y) { return winding; } } else { hasOnEdge = false; } return 0; } int32_t shadowing01(NvcVec3 sEdge, NvcVec3 eEdge, const NvcVec3& p) { int32_t winding = veStatus01(sEdge, eEdge, p); if (winding != 0) { if (sEdge.x > eEdge.x) { std::swap(sEdge, eEdge); } float t = ((p.x - sEdge.x) / (eEdge.x - sEdge.x)); NvcVec3 onEdgePoint; if (t >= 1) onEdgePoint = eEdge; else if (t <= 0) onEdgePoint = sEdge; else vec3Lerp(sEdge, eEdge, onEdgePoint, t); if (onEdgePoint.y >= p.y) { return winding; } } return 0; } int32_t shadowing10(NvcVec3 sEdge, NvcVec3 eEdge, const NvcVec3& p) { int32_t winding = veStatus10(sEdge, eEdge, p); if (winding != 0) { if (sEdge.x > eEdge.x) { std::swap(sEdge, eEdge); } float t = ((p.x - sEdge.x) / (eEdge.x - sEdge.x)); NvcVec3 onEdgePoint; if (t >= 1) onEdgePoint = eEdge; else if (t <= 0) onEdgePoint = sEdge; else vec3Lerp(sEdge, eEdge, onEdgePoint, t); if (onEdgePoint.y < p.y) { return winding; } } return 0; } /** Vertex-facet shadowing functions */ int32_t vfStatus02(const NvcVec3& p, const Vertex* points, const Edge* edges, int32_t edgesCount, Vertex* out) { int32_t val = 0; Vertex pnt; bool hasOnEdge = false; out[0].p.y = -MAXIMUM_EXTENT; out[1].p.y = MAXIMUM_EXTENT; for (int32_t i = 0; i < edgesCount; ++i) { val -= shadowing01(points[edges->s], points[edges->e], p, pnt, hasOnEdge); if (hasOnEdge != 0) { if (p.y > pnt.p.y && pnt.p.y > out[0].p.y) { out[0] = pnt; } if (p.y <= pnt.p.y && pnt.p.y < out[1].p.y) { out[1] = pnt; } } ++edges; } return val; } int32_t shadowing02(const NvcVec3& p, const Vertex* points, const Edge* edges, int edgesCount, bool& hasOnFacetPoint, Vertex& onFacetPoint) { Vertex outp[2]; int32_t stat = vfStatus02(p, points, edges, edgesCount, outp); float z = 0; hasOnFacetPoint = false; if (stat != 0) { Vertex& p1 = outp[0]; Vertex& p2 = outp[1]; NvcVec3 vc = p2.p - p1.p; float t = 0; t = (std::abs(vc.x) > std::abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y; t = physx::PxClamp(t, 0.0f, 1.0f); z = t * vc.z + p1.p.z; hasOnFacetPoint = true; onFacetPoint.p.x = p.x; onFacetPoint.p.y = p.y; onFacetPoint.p.z = z; vec2Lerp(p1.uv[0], p2.uv[0], onFacetPoint.uv[0], t); vec3Lerp(p1.n, p2.n, onFacetPoint.n, t); if (z >= p.z) { return stat; } } return 0; } int32_t vfStatus20(const NvcVec3& p, const Vertex* points, const Edge* edges, int32_t edgesCount, Vertex* out) { int32_t val = 0; Vertex pnt; bool hasOnEdge = false; out[0].p.y = -MAXIMUM_EXTENT; out[1].p.y = MAXIMUM_EXTENT; for (int32_t i = 0; i < edgesCount; ++i) { val += shadowing10(points[edges->s], points[edges->e], p, pnt, hasOnEdge); if (hasOnEdge != 0) { if (p.y > pnt.p.y && pnt.p.y > out[0].p.y) { out[0] = pnt; } if (p.y <= pnt.p.y && pnt.p.y < out[1].p.y) { out[1] = pnt; } } ++edges; } return val; } int32_t shadowing20(const NvcVec3& p, const Vertex* points, const Edge* edges, int edgesCount, bool& hasOnFacetPoint, Vertex& onFacetPoint) { Vertex outp[2]; int32_t stat = vfStatus20(p, points, edges, edgesCount, outp); hasOnFacetPoint = false; if (stat != 0) { Vertex& p1 = outp[0]; Vertex& p2 = outp[1]; NvcVec3 vc = p2.p - p1.p; float t = 0; t = (std::abs(vc.x) > std::abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y; t = physx::PxClamp(t, 0.0f, 1.0f); hasOnFacetPoint = true; onFacetPoint.p.x = p.x; onFacetPoint.p.y = p.y; onFacetPoint.p.z = t * vc.z + p1.p.z; vec2Lerp(p1.uv[0], p2.uv[0], onFacetPoint.uv[0], t); vec3Lerp(p1.n, p2.n, onFacetPoint.n, t); if (onFacetPoint.p.z < p.z) { return stat; } } return 0; } NV_FORCE_INLINE int32_t edgesCrossCheck(const NvcVec3& eAs, const NvcVec3& eAe, const NvcVec3& eBs, const NvcVec3& eBe) { return shadowing01(eBs, eBe, eAe) - shadowing01(eBs, eBe, eAs) + shadowing10(eAs, eAe, eBe) - shadowing10(eAs, eAe, eBs); } int32_t edgesIntersection(const Vertex& eAs, const Vertex& eAe, const Vertex& eBs, const Vertex& eBe, Vertex& intersectionA, Vertex& intersectionB, bool& hasPoints) { int32_t status = edgesCrossCheck(eAs.p, eAe.p, eBs.p, eBe.p); hasPoints = false; if (status == 0) { return 0; } Vertex tempPoint; Vertex bShadowingPair[2]; Vertex aShadowingPair[2]; bool hasOnEdge = false; bool aShadowing = false; bool bShadowing = false; /** Search for two pairs where parts of A shadows B, and where B shadows A. Needed for search intersection point. */ for (auto p : { &eBs, &eBe }) { int32_t shadowingType = shadowing10(eAs, eAe, p->p, tempPoint, hasOnEdge); if (shadowingType == 0 && !aShadowing && hasOnEdge) { aShadowing = true; aShadowingPair[0] = *p; aShadowingPair[1] = tempPoint; } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[0] = *p; bShadowingPair[1] = tempPoint; } } } if (!aShadowing || !bShadowing) { for (auto p : { &eAs, &eAe }) { int32_t shadowingType = shadowing01(eBs, eBe, p->p, tempPoint, hasOnEdge); if (shadowingType == 0 && !aShadowing && hasOnEdge) { aShadowing = true; aShadowingPair[1] = *p; aShadowingPair[0] = tempPoint; } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[1] = *p; bShadowingPair[0] = tempPoint; } } } } float deltaPlus = bShadowingPair[0].p.y - bShadowingPair[1].p.y; float deltaMinus = aShadowingPair[0].p.y - aShadowingPair[1].p.y; float div = 0; if (deltaPlus > 0) div = deltaPlus / (deltaPlus - deltaMinus); else div = 0; intersectionA.p = bShadowingPair[1].p - div * (bShadowingPair[1].p - aShadowingPair[1].p); intersectionA.n = bShadowingPair[1].n - div * (bShadowingPair[1].n - aShadowingPair[1].n); intersectionA.uv[0] = bShadowingPair[1].uv[0] - (bShadowingPair[1].uv[0] - aShadowingPair[1].uv[0]) * div; intersectionB.p = intersectionA.p; intersectionB.p.z = bShadowingPair[0].p.z - div * (bShadowingPair[0].p.z - aShadowingPair[0].p.z); intersectionB.n = bShadowingPair[0].n - div * (bShadowingPair[0].n - aShadowingPair[0].n); intersectionB.uv[0] = bShadowingPair[0].uv[0] - (bShadowingPair[0].uv[0] - aShadowingPair[0].uv[0]) * div; hasPoints = true; return status; } NV_FORCE_INLINE int32_t edgeEdgeShadowing(const Vertex& eAs, const Vertex& eAe, const Vertex& eBs, const Vertex& eBe, Vertex& intersectionA, Vertex& intersectionB, bool& hasPoints) { int32_t status = edgesIntersection(eAs, eAe, eBs, eBe, intersectionA, intersectionB, hasPoints); if (intersectionB.p.z >= intersectionA.p.z) { return status; } return 0; } int32_t edgeFacetIntersection12(const Vertex& edSt, const Vertex& edEnd, const Vertex* points, const Edge* edges, int edgesCount, Vertex& intersectionA, Vertex& intersectionB) { int32_t status = 0; Vertex p1, p2; Vertex bShadowingPair[2]; Vertex aShadowingPair[2]; bool hasPoint = false; bool aShadowing = false; bool bShadowing = false; int32_t mlt = -1; int32_t shadowingType; for (auto p : { &edEnd, &edSt }) { shadowingType = shadowing02(p->p, points, edges, edgesCount, hasPoint, p1); status += mlt * shadowingType; if (shadowingType == 0 && !aShadowing && hasPoint) { aShadowing = true; aShadowingPair[0] = p1; aShadowingPair[1] = *p; } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[0] = p1; bShadowingPair[1] = *p; } } mlt = 1; } for (int32_t ed = 0; ed < edgesCount; ++ed) { if (shouldSwap(points[edges[ed].s].p, points[edges[ed].e].p)) { shadowingType = -edgeEdgeShadowing(edSt, edEnd, points[edges[ed].e], points[edges[ed].s], p1, p2, hasPoint); } else { shadowingType = edgeEdgeShadowing(edSt, edEnd, points[edges[ed].s], points[edges[ed].e], p1, p2, hasPoint); } status -= shadowingType; if (shadowingType == 0 && !aShadowing && hasPoint) { aShadowing = true; aShadowingPair[0] = p2; aShadowingPair[1] = p1; } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[0] = p2; bShadowingPair[1] = p1; } } } if (!status || !bShadowing || !aShadowing) { return 0; } float deltaPlus = bShadowingPair[0].p.z - bShadowingPair[1].p.z; float div = 0; if (deltaPlus != 0) { float deltaMinus = aShadowingPair[0].p.z - aShadowingPair[1].p.z; div = deltaPlus / (deltaPlus - deltaMinus); } intersectionA.p = bShadowingPair[1].p - div * (bShadowingPair[1].p - aShadowingPair[1].p); intersectionA.n = bShadowingPair[1].n - div * (bShadowingPair[1].n - aShadowingPair[1].n); intersectionA.uv[0] = bShadowingPair[1].uv[0] - (bShadowingPair[1].uv[0] - aShadowingPair[1].uv[0]) * div; intersectionB.p = intersectionA.p; intersectionB.n = bShadowingPair[0].n - div * (bShadowingPair[0].n - aShadowingPair[0].n); intersectionB.uv[0] = bShadowingPair[0].uv[0] - (bShadowingPair[0].uv[0] - aShadowingPair[0].uv[0]) * div; return status; } int32_t edgeFacetIntersection21(const Vertex& edSt, const Vertex& edEnd, const Vertex* points, const Edge* edges, int edgesCount, Vertex& intersectionA, Vertex& intersectionB) { int32_t status = 0; Vertex p1, p2; Vertex bShadowingPair[2]; Vertex aShadowingPair[2]; bool hasPoint = false; bool aShadowing = false; bool bShadowing = false; int32_t shadowingType; int32_t mlt = 1; for (auto p : { &edEnd, &edSt }) { shadowingType = shadowing20(p->p, points, edges, edgesCount, hasPoint, p1); status += mlt * shadowingType; if (shadowingType == 0 && !aShadowing && hasPoint) { aShadowing = true; aShadowingPair[0] = *p; aShadowingPair[1] = p1; } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[0] = *p; bShadowingPair[1] = p1; } } mlt = -1; } for (int32_t ed = 0; ed < edgesCount; ++ed) { if (shouldSwap(points[edges[ed].s].p, points[edges[ed].e].p)) { shadowingType = -edgeEdgeShadowing(points[edges[ed].e], points[edges[ed].s], edSt, edEnd, p1, p2, hasPoint); } else { shadowingType = edgeEdgeShadowing(points[edges[ed].s], points[edges[ed].e], edSt, edEnd, p1, p2, hasPoint); } status -= shadowingType; if (shadowingType == 0) { if (!aShadowing && hasPoint) { aShadowing = true; aShadowingPair[0] = p2; aShadowingPair[1] = p1; } } else { if ((shadowingType == 1 || shadowingType == -1) && !bShadowing) { bShadowing = true; bShadowingPair[0] = p2; bShadowingPair[1] = p1; } } } if (!status || !bShadowing || !aShadowing) { return 0; } float deltaPlus = bShadowingPair[0].p.z - bShadowingPair[1].p.z; float div = 0; if (deltaPlus != 0) { float deltaMinus = aShadowingPair[0].p.z - aShadowingPair[1].p.z; div = deltaPlus / (deltaPlus - deltaMinus); } intersectionA.p = bShadowingPair[1].p - div * (bShadowingPair[1].p - aShadowingPair[1].p); intersectionA.n = bShadowingPair[1].n - div * (bShadowingPair[1].n - aShadowingPair[1].n); intersectionA.uv[0] = bShadowingPair[1].uv[0] - (bShadowingPair[1].uv[0] - aShadowingPair[1].uv[0]) * div; intersectionB.p = intersectionA.p; intersectionB.n = bShadowingPair[0].n - div * (bShadowingPair[0].n - aShadowingPair[0].n); intersectionB.uv[0] = bShadowingPair[0].uv[0] - (bShadowingPair[0].uv[0] - aShadowingPair[0].uv[0]) * div; return status; } int32_t BooleanEvaluator::vertexMeshStatus03(const NvcVec3& p, const Mesh* mesh) { int32_t status = 0; Vertex pnt; bool hasPoint = false; mAcceleratorB->setState(p); int32_t facet = mAcceleratorB->getNextFacet(); while (facet != -1) { const Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber; status += shadowing02(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoint, pnt); facet = mAcceleratorB->getNextFacet(); } //for (int32_t facet = 0; facet < mesh->getFacetCount(); ++facet) //{ // Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber; // status += shadowing02(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoint, pnt); //}; return status; } int32_t BooleanEvaluator::vertexMeshStatus30(const NvcVec3& p, const Mesh* mesh) { int32_t status = 0; bool hasPoints = false; Vertex point; mAcceleratorA->setState(p); int32_t facet = mAcceleratorA->getNextFacet(); while ( facet != -1) { const Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber; status -= shadowing20(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoints, point); facet = mAcceleratorA->getNextFacet(); } //for (int32_t facet = 0; facet < mesh->getFacetCount(); ++facet) //{ // Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber; // status -= shadowing20(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoints, point); //} return status; } NV_FORCE_INLINE int32_t inclusionValue03(BooleanConf& conf, int32_t xValue) { return conf.ca + conf.ci * xValue; } NV_FORCE_INLINE int32_t inclusionValueEdgeFace(BooleanConf& conf, int32_t xValue) { return conf.ci * xValue; } NV_FORCE_INLINE int32_t inclusionValue30(BooleanConf& conf, int32_t xValue) { return conf.cb + conf.ci * xValue; } struct VertexComparator { VertexComparator(NvcVec3 base = NvcVec3()) : basePoint(base) {}; NvcVec3 basePoint; bool operator()(const Vertex& a, const Vertex& b) { return dot(b.p - a.p, basePoint) > 0.0; } }; struct VertexPairComparator { VertexPairComparator(NvcVec3 base = NvcVec3()) : basePoint(base) {}; NvcVec3 basePoint; bool operator()(const std::pair& a, const std::pair& b) { return dot(b.first.p - a.first.p, basePoint) > 0.0; } }; int32_t BooleanEvaluator::isPointContainedInMesh(const Mesh* msh, const NvcVec3& point) { if (msh == nullptr) { return 0; } DummyAccelerator dmAccel(msh->getFacetCount()); mAcceleratorA = &dmAccel; return vertexMeshStatus30(point, msh); } int32_t BooleanEvaluator::isPointContainedInMesh(const Mesh* msh, SpatialAccelerator* spAccel, const NvcVec3& point) { if (msh == nullptr) { return 0; } mAcceleratorA = spAccel; return vertexMeshStatus30(point, msh); } void BooleanEvaluator::buildFaceFaceIntersections(BooleanConf mode) { int32_t statusValue = 0; int32_t inclusionValue = 0; std::vector > retainedStarts; std::vector> retainedEnds; VertexPairComparator comp; Vertex newPointA; Vertex newPointB; const Vertex* meshAPoints = mMeshA->getVertices(); const Vertex* meshBPoints = mMeshB->getVertices(); EdgeWithParent newEdge; mEdgeFacetIntersectionData12.clear(); mEdgeFacetIntersectionData21.clear(); mEdgeFacetIntersectionData12.resize(mMeshA->getFacetCount()); mEdgeFacetIntersectionData21.resize(mMeshB->getFacetCount()); for (uint32_t facetB = 0; facetB < mMeshB->getFacetCount(); ++facetB) { mAcceleratorA->setState(mMeshB->getVertices(), mMeshB->getEdges(), *mMeshB->getFacet(facetB)); int32_t facetA = mAcceleratorA->getNextFacet(); while (facetA != -1) { const Edge* facetBEdges = mMeshB->getEdges() + mMeshB->getFacet(facetB)->firstEdgeNumber; const Edge* facetAEdges = mMeshA->getEdges() + mMeshA->getFacet(facetA)->firstEdgeNumber; const Edge* fbe = facetBEdges; const Edge* fae = facetAEdges; retainedStarts.clear(); retainedEnds.clear(); NvcVec3 compositeEndPoint = {0, 0, 0}; NvcVec3 compositeStartPoint = {0, 0, 0}; uint32_t facetAEdgeCount = mMeshA->getFacet(facetA)->edgesCount; uint32_t facetBEdgeCount = mMeshB->getFacet(facetB)->edgesCount; int32_t ic = 0; for (uint32_t i = 0; i < facetAEdgeCount; ++i) { if (shouldSwap(meshAPoints[fae->e].p, meshAPoints[fae->s].p)) { statusValue = -edgeFacetIntersection12(meshAPoints[fae->e], meshAPoints[fae->s], mMeshB->getVertices(), facetBEdges, facetBEdgeCount, newPointA, newPointB); } else { statusValue = edgeFacetIntersection12(meshAPoints[fae->s], meshAPoints[fae->e], mMeshB->getVertices(), facetBEdges, facetBEdgeCount, newPointA, newPointB); } inclusionValue = -inclusionValueEdgeFace(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEnds.push_back(std::make_pair(newPointA, newPointB)); compositeEndPoint = compositeEndPoint + newPointA.p; } mEdgeFacetIntersectionData12[facetA].push_back(EdgeFacetIntersectionData(i, statusValue, newPointA)); } if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStarts.push_back(std::make_pair(newPointA, newPointB)); compositeStartPoint = compositeStartPoint + newPointA.p; } mEdgeFacetIntersectionData12[facetA].push_back(EdgeFacetIntersectionData(i, statusValue, newPointA)); } fae++; } for (uint32_t i = 0; i < facetBEdgeCount; ++i) { if (shouldSwap(meshBPoints[fbe->e].p, meshBPoints[fbe->s].p)) { statusValue = -edgeFacetIntersection21(meshBPoints[(fbe)->e], meshBPoints[(fbe)->s], mMeshA->getVertices(), facetAEdges, facetAEdgeCount, newPointA, newPointB); } else { statusValue = edgeFacetIntersection21(meshBPoints[(fbe)->s], meshBPoints[(fbe)->e], mMeshA->getVertices(), facetAEdges, facetAEdgeCount, newPointA, newPointB); } inclusionValue = inclusionValueEdgeFace(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEnds.push_back(std::make_pair(newPointA, newPointB)); compositeEndPoint = compositeEndPoint + newPointB.p; } mEdgeFacetIntersectionData21[facetB].push_back(EdgeFacetIntersectionData( i, statusValue, newPointB)); } if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStarts.push_back(std::make_pair(newPointA, newPointB)); compositeStartPoint = compositeStartPoint + newPointB.p; } mEdgeFacetIntersectionData21[facetB].push_back(EdgeFacetIntersectionData(i, statusValue, newPointB)); } fbe++; } if (retainedStarts.size() != retainedEnds.size()) { NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges."); return; } for (uint32_t rv = 0; rv < retainedStarts.size(); ++rv) { newEdge.s = addIfNotExist(retainedStarts[rv].first); newEdge.e = addIfNotExist(retainedEnds[rv].first); newEdge.parent = facetA; addEdgeIfValid(newEdge); newEdge.parent = facetB + mMeshA->getFacetCount(); newEdge.e = addIfNotExist(retainedStarts[rv].second); newEdge.s = addIfNotExist(retainedEnds[rv].second); addEdgeIfValid(newEdge); } facetA = mAcceleratorA->getNextFacet(); } // while (*iter != -1) } // for (uint32_t facetB = 0; facetB < mMeshB->getFacetCount(); ++facetB) } void BooleanEvaluator::buildFastFaceFaceIntersection(BooleanConf mode) { int32_t statusValue = 0; int32_t inclusionValue = 0; std::vector > retainedStarts; std::vector> retainedEnds; VertexPairComparator comp; Vertex newPointA; Vertex newPointB; const Vertex* meshAPoints = mMeshA->getVertices(); EdgeWithParent newEdge; mEdgeFacetIntersectionData12.clear(); mEdgeFacetIntersectionData21.clear(); mEdgeFacetIntersectionData12.resize(mMeshA->getFacetCount()); mEdgeFacetIntersectionData21.resize(mMeshB->getFacetCount()); for (uint32_t facetA = 0; facetA < mMeshA->getFacetCount(); ++facetA) { const Edge* facetAEdges = mMeshA->getEdges() + mMeshA->getFacet(facetA)->firstEdgeNumber; int32_t facetB = 0; const Edge* facetBEdges = mMeshB->getEdges() + mMeshB->getFacet(facetB)->firstEdgeNumber; const Edge* fae = facetAEdges; retainedStarts.clear(); retainedEnds.clear(); NvcVec3 compositeEndPoint = {0, 0, 0}; NvcVec3 compositeStartPoint = {0, 0, 0}; uint32_t facetAEdgeCount = mMeshA->getFacet(facetA)->edgesCount; uint32_t facetBEdgeCount = mMeshB->getFacet(facetB)->edgesCount; int32_t ic = 0; for (uint32_t i = 0; i < facetAEdgeCount; ++i) { if (shouldSwap(meshAPoints[fae->e].p, meshAPoints[fae->s].p)) { statusValue = -edgeFacetIntersection12(meshAPoints[fae->e], meshAPoints[fae->s], mMeshB->getVertices(), facetBEdges, facetBEdgeCount, newPointA, newPointB); } else { statusValue = edgeFacetIntersection12(meshAPoints[fae->s], meshAPoints[fae->e], mMeshB->getVertices(), facetBEdges, facetBEdgeCount, newPointA, newPointB); } inclusionValue = -inclusionValueEdgeFace(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEnds.push_back(std::make_pair(newPointA, newPointB)); compositeEndPoint = compositeEndPoint + newPointA.p; } mEdgeFacetIntersectionData12[facetA].push_back(EdgeFacetIntersectionData(i, statusValue, newPointA)); } if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStarts.push_back(std::make_pair(newPointA, newPointB)); compositeStartPoint = compositeStartPoint + newPointA.p; } mEdgeFacetIntersectionData12[facetA].push_back(EdgeFacetIntersectionData(i, statusValue, newPointA)); } fae++; } if (retainedStarts.size() != retainedEnds.size()) { NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges."); return; } if (retainedStarts.size() > 1) { comp.basePoint = compositeEndPoint - compositeStartPoint; std::sort(retainedStarts.begin(), retainedStarts.end(), comp); std::sort(retainedEnds.begin(), retainedEnds.end(), comp); } for (uint32_t rv = 0; rv < retainedStarts.size(); ++rv) { newEdge.s = addIfNotExist(retainedStarts[rv].first); newEdge.e = addIfNotExist(retainedEnds[rv].first); newEdge.parent = facetA; addEdgeIfValid(newEdge); newEdge.parent = facetB + mMeshA->getFacetCount(); newEdge.e = addIfNotExist(retainedStarts[rv].second); newEdge.s = addIfNotExist(retainedEnds[rv].second); addEdgeIfValid(newEdge); } } } void BooleanEvaluator::collectRetainedPartsFromA(BooleanConf mode) { int32_t statusValue = 0; int32_t inclusionValue = 0; const Vertex* vertices = mMeshA->getVertices(); Vertex newPoint; VertexComparator comp; const PxBounds3& bMeshBoudning = toPxShared(mMeshB->getBoundingBox()); const Edge* facetEdges = mMeshA->getEdges(); std::vector retainedStartVertices; std::vector retainedEndVertices; retainedStartVertices.reserve(255); retainedEndVertices.reserve(255); int32_t ic = 0; for (uint32_t facetId = 0; facetId < mMeshA->getFacetCount(); ++facetId) { retainedStartVertices.clear(); retainedEndVertices.clear(); for (uint32_t i = 0; i < mMeshA->getFacet(facetId)->edgesCount; ++i) { NvcVec3 compositeEndPoint = {0, 0, 0}; NvcVec3 compositeStartPoint = {0, 0, 0}; int32_t lastPos = static_cast(retainedEndVertices.size()); /* Test start and end point of edge against mesh */ if (bMeshBoudning.contains(toPxShared(vertices[facetEdges->s].p))) { statusValue = vertexMeshStatus03(vertices[facetEdges->s].p, mMeshB); } else { statusValue = 0; } inclusionValue = -inclusionValue03(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(vertices[facetEdges->s]); compositeEndPoint = compositeEndPoint + vertices[facetEdges->s].p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(vertices[facetEdges->s]); compositeStartPoint = compositeStartPoint + vertices[facetEdges->s].p; } } } if (bMeshBoudning.contains(toPxShared(vertices[facetEdges->e].p))) { statusValue = vertexMeshStatus03(vertices[facetEdges->e].p, mMeshB); } else { statusValue = 0; } inclusionValue = inclusionValue03(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(vertices[facetEdges->e]); compositeEndPoint = compositeEndPoint + vertices[facetEdges->e].p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(vertices[facetEdges->e]); compositeStartPoint = compositeStartPoint + vertices[facetEdges->e].p; } } } /* Test edge intersection with mesh*/ for (uint32_t intrs = 0; intrs < mEdgeFacetIntersectionData12[facetId].size(); ++intrs) { EdgeFacetIntersectionData& intr = mEdgeFacetIntersectionData12[facetId][intrs]; if (intr.edId != (int32_t)i) continue; newPoint = intr.intersectionPoint; inclusionValue = inclusionValueEdgeFace(mode, intr.intersectionType); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(newPoint); compositeEndPoint = compositeEndPoint + newPoint.p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(newPoint); compositeStartPoint = compositeStartPoint + newPoint.p; } } } } facetEdges++; if (retainedStartVertices.size() != retainedEndVertices.size()) { NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges."); return; } if (retainedEndVertices.size() > 1) { comp.basePoint = compositeEndPoint - compositeStartPoint; std::sort(retainedStartVertices.begin() + lastPos, retainedStartVertices.end(), comp); std::sort(retainedEndVertices.begin() + lastPos, retainedEndVertices.end(), comp); } } EdgeWithParent newEdge; for (uint32_t rv = 0; rv < retainedStartVertices.size(); ++rv) { newEdge.s = addIfNotExist(retainedStartVertices[rv]); newEdge.e = addIfNotExist(retainedEndVertices[rv]); newEdge.parent = facetId; addEdgeIfValid(newEdge); } } return; } void BooleanEvaluator::collectRetainedPartsFromB(BooleanConf mode) { int32_t statusValue = 0; int32_t inclusionValue = 0; const Vertex* vertices = mMeshB->getVertices(); Vertex newPoint; VertexComparator comp; const PxBounds3& aMeshBoudning = toPxShared(mMeshA->getBoundingBox()); const Edge* facetEdges = mMeshB->getEdges(); std::vector retainedStartVertices; std::vector retainedEndVertices; retainedStartVertices.reserve(255); retainedEndVertices.reserve(255); int32_t ic = 0; for (uint32_t facetId = 0; facetId < mMeshB->getFacetCount(); ++facetId) { retainedStartVertices.clear(); retainedEndVertices.clear(); for (uint32_t i = 0; i < mMeshB->getFacet(facetId)->edgesCount; ++i) { NvcVec3 compositeEndPoint = {0, 0, 0}; NvcVec3 compositeStartPoint = {0, 0, 0}; int32_t lastPos = static_cast(retainedEndVertices.size()); if (aMeshBoudning.contains(toPxShared(vertices[facetEdges->s].p))) { statusValue = vertexMeshStatus30(vertices[facetEdges->s].p, mMeshA); } else { statusValue = 0; } inclusionValue = -inclusionValue30(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(vertices[facetEdges->s]); compositeEndPoint = compositeEndPoint + vertices[facetEdges->s].p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(vertices[facetEdges->s]); compositeStartPoint = compositeStartPoint + vertices[facetEdges->s].p; } } } if (aMeshBoudning.contains(toPxShared(vertices[facetEdges->e].p))) { statusValue = vertexMeshStatus30(vertices[facetEdges->e].p, mMeshA); } else { statusValue = 0; } inclusionValue = inclusionValue30(mode, statusValue); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(vertices[facetEdges->e]); compositeEndPoint = compositeEndPoint + vertices[facetEdges->e].p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(vertices[facetEdges->e]); compositeStartPoint = compositeStartPoint + vertices[facetEdges->e].p; } } } for (uint32_t intrs = 0; intrs < mEdgeFacetIntersectionData21[facetId].size(); ++intrs) { EdgeFacetIntersectionData& intr = mEdgeFacetIntersectionData21[facetId][intrs]; if (intr.edId != (int32_t)i) continue; newPoint = intr.intersectionPoint; inclusionValue = inclusionValueEdgeFace(mode, intr.intersectionType); if (inclusionValue > 0) { for (ic = 0; ic < inclusionValue; ++ic) { retainedEndVertices.push_back(newPoint); compositeEndPoint = compositeEndPoint + newPoint.p; } } else { if (inclusionValue < 0) { for (ic = 0; ic < -inclusionValue; ++ic) { retainedStartVertices.push_back(newPoint); compositeStartPoint = compositeStartPoint + newPoint.p; } } } } facetEdges++; if (retainedStartVertices.size() != retainedEndVertices.size()) { NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges."); return; } if (retainedEndVertices.size() - lastPos > 1) { comp.basePoint = compositeEndPoint - compositeStartPoint; std::sort(retainedStartVertices.begin() + lastPos, retainedStartVertices.end(), comp); std::sort(retainedEndVertices.begin() + lastPos, retainedEndVertices.end(), comp); } } EdgeWithParent newEdge; for (uint32_t rv = 0; rv < retainedStartVertices.size(); ++rv) { newEdge.s = addIfNotExist(retainedStartVertices[rv]); newEdge.e = addIfNotExist(retainedEndVertices[rv]); newEdge.parent = facetId + mMeshA->getFacetCount(); addEdgeIfValid(newEdge); } } return; } bool EdgeWithParentSortComp(const EdgeWithParent& a, const EdgeWithParent& b) { return a.parent < b.parent; } void BooleanEvaluator::performBoolean(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode) { reset(); mMeshA = meshA; mMeshB = meshB; mAcceleratorA = spAccelA; mAcceleratorB = spAccelB; buildFaceFaceIntersections(mode); collectRetainedPartsFromA(mode); collectRetainedPartsFromB(mode); mAcceleratorA = nullptr; mAcceleratorB = nullptr; } void BooleanEvaluator::performBoolean(const Mesh* meshA, const Mesh* meshB, BooleanConf mode) { reset(); mMeshA = meshA; mMeshB = meshB; DummyAccelerator ac = DummyAccelerator(mMeshA->getFacetCount()); DummyAccelerator bc = DummyAccelerator(mMeshB->getFacetCount()); performBoolean(meshA, meshB, &ac, &bc, mode); } void BooleanEvaluator::performFastCutting(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode) { reset(); mMeshA = meshA; mMeshB = meshB; mAcceleratorA = spAccelA; mAcceleratorB = spAccelB; buildFastFaceFaceIntersection(mode); collectRetainedPartsFromA(mode); mAcceleratorA = nullptr; mAcceleratorB = nullptr; } void BooleanEvaluator::performFastCutting(const Mesh* meshA, const Mesh* meshB, BooleanConf mode) { reset(); mMeshA = meshA; mMeshB = meshB; DummyAccelerator ac = DummyAccelerator(mMeshA->getFacetCount()); DummyAccelerator bc = DummyAccelerator(mMeshB->getFacetCount()); performFastCutting(meshA, meshB, &ac, &bc, mode); } BooleanEvaluator::BooleanEvaluator() { mMeshA = nullptr; mMeshB = nullptr; mAcceleratorA = nullptr; mAcceleratorB = nullptr; } BooleanEvaluator::~BooleanEvaluator() { reset(); } Mesh* BooleanEvaluator::createNewMesh() { if (mEdgeAggregate.size() == 0) { return nullptr; } std::sort(mEdgeAggregate.begin(), mEdgeAggregate.end(), EdgeWithParentSortComp); std::vector newFacets; std::vector newEdges(mEdgeAggregate.size()); int32_t lastPos = 0; uint32_t lastParent = mEdgeAggregate[0].parent; uint32_t collected = 0; int64_t userData = 0; int32_t materialId = 0; int32_t smoothingGroup = 0; for (uint32_t i = 0; i < mEdgeAggregate.size(); ++i) { if (mEdgeAggregate[i].parent != lastParent) { if (lastParent < mMeshA->getFacetCount()) { userData = mMeshA->getFacet(lastParent)->userData; materialId = mMeshA->getFacet(lastParent)->materialId; smoothingGroup = mMeshA->getFacet(lastParent)->smoothingGroup; } else { userData = mMeshB->getFacet(lastParent - mMeshA->getFacetCount())->userData; materialId = mMeshB->getFacet(lastParent - mMeshA->getFacetCount())->materialId; smoothingGroup = mMeshB->getFacet(lastParent - mMeshA->getFacetCount())->smoothingGroup; } newFacets.push_back({ lastPos, collected, userData, materialId, smoothingGroup }); lastPos = i; lastParent = mEdgeAggregate[i].parent; collected = 0; } collected++; newEdges[i].s = mEdgeAggregate[i].s; newEdges[i].e = mEdgeAggregate[i].e; } if (lastParent < mMeshA->getFacetCount()) { userData = mMeshA->getFacet(lastParent)->userData; materialId = mMeshA->getFacet(lastParent)->materialId; smoothingGroup = mMeshA->getFacet(lastParent)->smoothingGroup; } else { uint32_t pr = lastParent - mMeshA->getFacetCount(); userData = mMeshB->getFacet(pr)->userData; materialId = mMeshB->getFacet(pr)->materialId; smoothingGroup = mMeshB->getFacet(pr)->smoothingGroup; } newFacets.push_back({ lastPos, collected, userData, materialId, smoothingGroup }); return new MeshImpl(mVerticesAggregate.data(), newEdges.data(), newFacets.data(), static_cast(mVerticesAggregate.size()), static_cast(mEdgeAggregate.size()), static_cast(newFacets.size())); } void BooleanEvaluator::reset() { mMeshA = nullptr; mMeshB = nullptr; mAcceleratorA = nullptr; mAcceleratorB = nullptr; mEdgeAggregate.clear(); mVerticesAggregate.clear(); mEdgeFacetIntersectionData12.clear(); mEdgeFacetIntersectionData21.clear(); } } // namespace Blast } // namespace Nv