diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
| commit | e1bf674c16e3c8472b29574159c789cd3f0c64e0 (patch) | |
| tree | 9f0cfce09c71a2c27ff19589fcad6cd83504477c /sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp | |
| parent | first commit (diff) | |
| download | blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.tar.xz blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.zip | |
Updating to [email protected] and [email protected] with a new directory structure.
NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this.
Diffstat (limited to 'sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp')
| -rw-r--r-- | sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp | 1439 |
1 files changed, 1439 insertions, 0 deletions
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp new file mode 100644 index 0000000..0b7187f --- /dev/null +++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp @@ -0,0 +1,1439 @@ +/* +* Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved. +* +* NVIDIA CORPORATION and its licensors retain all intellectual property +* and proprietary rights in and to this software, 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. +*/ + +// This warning arises when using some stl containers with older versions of VC +// c:\program files (x86)\microsoft visual studio 12.0\vc\include\xtree(1826): warning C4702: unreachable code +#include "NvPreprocessor.h" +#if NV_VC && NV_VC < 14 +#pragma warning(disable : 4702) +#endif +#include "NvBlastExtAuthoringTriangulator.h" +#include "NvBlastExtAuthoringMesh.h" +#include "NvBlastExtAuthoringTypes.h" +#include <math.h> +#include "NvPreprocessor.h" +#include <algorithm> +#include <vector> +#include <set> +#include "NvBlastExtAuthoringBooleanTool.h" +#include <queue> +#include "NvBlastExtAuthoringPerlinNoise.h" +#include <NvBlastAssert.h> + +using physx::PxVec3; +using physx::PxVec2; + +#define VEC_COMPARISON_OFFSET 1e-5f +#define TWO_VERTICES_THRESHOLD 1e-7 + +namespace Nv +{ +namespace Blast +{ + +bool VrtComp::operator()(const Vertex& a, const Vertex& b) const +{ + if (a.p.x + VEC_COMPARISON_OFFSET < b.p.x) return true; + if (a.p.x - VEC_COMPARISON_OFFSET > b.p.x) return false; + if (a.p.y + VEC_COMPARISON_OFFSET < b.p.y) return true; + if (a.p.y - VEC_COMPARISON_OFFSET > b.p.y) return false; + if (a.p.z + VEC_COMPARISON_OFFSET < b.p.z) return true; + if (a.p.z - VEC_COMPARISON_OFFSET > b.p.z) return false; + + if (a.n.x + 1e-3 < b.n.x) return true; + if (a.n.x - 1e-3 > b.n.x) return false; + if (a.n.y + 1e-3 < b.n.y) return true; + if (a.n.y - 1e-3 > b.n.y) return false; + if (a.n.z + 1e-3 < b.n.z) return true; + if (a.n.z - 1e-3 > b.n.z) return false; + + + if (a.uv[0].x + 1e-3 < b.uv[0].x) return true; + if (a.uv[0].x - 1e-3 > b.uv[0].x) return false; + if (a.uv[0].y + 1e-3 < b.uv[0].y) return true; + return false; +} + +bool VrtPositionComparator::operator()(const PxVec3& a, const PxVec3& b) const +{ + if (a.x + VEC_COMPARISON_OFFSET < b.x) return true; + if (a.x - VEC_COMPARISON_OFFSET > b.x) return false; + if (a.y + VEC_COMPARISON_OFFSET < b.y) return true; + if (a.y - VEC_COMPARISON_OFFSET > b.y) return false; + if (a.z + VEC_COMPARISON_OFFSET < b.z) return true; + if (a.z - VEC_COMPARISON_OFFSET > b.z) return false; + return false; +} + +NV_FORCE_INLINE bool compareTwoVertices(const PxVec3& a, const PxVec3& b) +{ + return std::abs(b.x - a.x) < TWO_VERTICES_THRESHOLD && std::abs(b.y - a.y) < TWO_VERTICES_THRESHOLD && std::abs(b.z - a.z) < TWO_VERTICES_THRESHOLD; +} +NV_FORCE_INLINE bool compareTwoVertices(const PxVec2& a, const PxVec2& b) +{ + return std::abs(b.x - a.x) < TWO_VERTICES_THRESHOLD && std::abs(b.y - a.y) < TWO_VERTICES_THRESHOLD; +} + +NV_FORCE_INLINE float getRotation(const PxVec2& a, const PxVec2& b) +{ + return a.x * b.y - a.y * b.x; +} + +inline bool pointInside(PxVec2 a, PxVec2 b, PxVec2 c, PxVec2 pnt) +{ + if (compareTwoVertices(a, pnt) || compareTwoVertices(b, pnt) || compareTwoVertices(c, pnt)) + { + return false; + } + float v1 = (getRotation((b - a), (pnt - a))); + float v2 = (getRotation((c - b), (pnt - b))); + float v3 = (getRotation((a - c), (pnt - c))); + + return (v1 >= 0.0f && v2 >= 0.0f && v3 >= 0.0f) || + (v1 <= 0.0f && v2 <= 0.0f && v3 <= 0.0f); + +} +void ChunkPostProcessor::triangulatePolygonWithEarClipping(std::vector<uint32_t>& inputPolygon, Vertex* vert, ProjectionDirections dir) +{ + // return; + //for (uint32_t i = 0; i < inputPolygon.size(); ++i) + //{ + // mBaseMeshTriangles.push_back(TriangleIndexed(inputPolygon[i], inputPolygon[i], inputPolygon[(i + 1) % inputPolygon.size()])); + //} + //return; + int32_t vCount = static_cast<int32_t>(inputPolygon.size()); + + if (vCount < 3) + { + return; + } + for (int32_t curr = 0; curr < vCount && vCount > 2; ++curr) + { + int32_t prev = (curr == 0) ? vCount - 1 : curr - 1; + int32_t next = (curr == vCount - 1) ? 0 : curr + 1; + + Vertex cV = vert[inputPolygon[curr]]; + Vertex nV = vert[inputPolygon[prev]]; + Vertex pV = vert[inputPolygon[next]]; + + PxVec2 cVp = getProjectedPoint(cV.p, dir); + PxVec2 nVp = getProjectedPoint(nV.p, dir); + PxVec2 pVp = getProjectedPoint(pV.p, dir); + + // Check wheather curr is ear-tip + float rot = getRotation((pVp - nVp).getNormalized(), (cVp - nVp).getNormalized()); + if (!(dir & OPPOSITE_WINDING)) rot = -rot; + if (rot > 0.0001) + { + bool good = true; + for (int vrt = 0; vrt < vCount; ++vrt) + { + if (vrt == curr || vrt == prev || vrt == next) continue; + if (pointInside(cVp, nVp, pVp, getProjectedPoint(vert[inputPolygon[vrt]].p, dir))) + { + good = false; + break; + } + } + if (good) + { + addEdgeTr(Edge(inputPolygon[curr], inputPolygon[prev])); + addEdgeTr(Edge(inputPolygon[next], inputPolygon[prev])); + addEdgeTr(Edge(inputPolygon[curr], inputPolygon[next])); + + mBaseMeshTriangles.push_back(TriangleIndexed(inputPolygon[curr], inputPolygon[prev], inputPolygon[next])); + vCount--; + inputPolygon.erase(inputPolygon.begin() + curr); + curr = -1; + } + } + } +} + + + +struct LoopInfo +{ + LoopInfo() + { + used = false; + } + PxVec3 normal; + float area; + int32_t index; + bool used; + bool operator<(const LoopInfo& b) const + { + return area < b.area; + } +}; + +int32_t unitePolygons(std::vector<uint32_t>& externalLoop, std::vector<uint32_t>& internalLoop, Vertex* vrx, ProjectionDirections dir) +{ + if (externalLoop.size() < 3 || internalLoop.size() < 3) + return 1; + /** + Find point with maximum x-coordinate + */ + float x_max = -MAXIMUM_EXTENT; + int32_t mIndex = -1; + for (uint32_t i = 0; i < internalLoop.size(); ++i) + { + float nx = getProjectedPoint(vrx[internalLoop[i]].p, dir).x; + if (nx > x_max) + { + mIndex = i; + x_max = nx; + } + } + if (mIndex == -1) + { + return 1; + } + + /** + Search for base point on external loop + */ + float minX = MAXIMUM_EXTENT; + int32_t vrtIndex = -1; + bool isFromBuffer = 0; + PxVec2 holePoint = getProjectedPoint(vrx[internalLoop[mIndex]].p, dir); + PxVec2 computedPoint; + for (uint32_t i = 0; i < externalLoop.size(); ++i) + { + int32_t nx = (i + 1) % externalLoop.size(); + PxVec2 pnt1 = getProjectedPoint(vrx[externalLoop[i]].p, dir); + PxVec2 pnt2 = getProjectedPoint(vrx[externalLoop[nx]].p, dir); + if (pnt1.x < x_max && pnt2.x < x_max) + { + continue; + } + PxVec2 vc = pnt2 - pnt1; + if (vc.y == 0 && pnt1.y == holePoint.y) + { + if (pnt1.x < minX && pnt1.x < pnt2.x && pnt1.x > x_max) + { + minX = pnt1.x; + vrtIndex = i; + isFromBuffer = true; + } + if (pnt2.x < minX && pnt2.x < pnt1.x && pnt2.x > x_max) + { + minX = pnt2.x; + vrtIndex = nx; + isFromBuffer = true; + } + } + else + { + float t = (holePoint.y - pnt1.y) / vc.y; + if (t <= 1 && t >= 0) + { + PxVec2 tempPoint = vc * t + pnt1; + if (tempPoint.x < minX && tempPoint.x > x_max) + { + minX = tempPoint.x; + vrtIndex = i; + isFromBuffer = false; + computedPoint = tempPoint; + } + } + } + } + if (vrtIndex == -1) + { + // std::cout << "Triangulation: base vertex for inner loop is not found..." << std::endl; + return 1; + } + int32_t bridgePoint = -1; + float bestAngle = 100; + if (!isFromBuffer) + { + PxVec2 ex1 = getProjectedPoint(vrx[externalLoop[vrtIndex]].p, dir); + PxVec2 ex2 = getProjectedPoint(vrx[externalLoop[(vrtIndex + 1) % externalLoop.size()]].p, dir); + + if (ex1.x > ex2.x) + { + vrtIndex = (vrtIndex + 1) % externalLoop.size(); + ex1 = ex2; + } + /* Check if some point is inside triangle */ + bool notFound = true; + for (int32_t i = 0; i < (int32_t)externalLoop.size(); ++i) + { + PxVec2 tempPoint = getProjectedPoint(vrx[externalLoop[i]].p, dir); + if (pointInside(holePoint, ex1, computedPoint, tempPoint)) + { + notFound = false; + PxVec2 cVp = getProjectedPoint(vrx[externalLoop[i]].p, dir); + PxVec2 pVp = getProjectedPoint(vrx[externalLoop[(i - 1 + externalLoop.size()) % externalLoop.size()]].p, dir); + PxVec2 nVp = getProjectedPoint(vrx[externalLoop[(i + 1) % externalLoop.size()]].p, dir); + float rt = getRotation((cVp - pVp).getNormalized(), (nVp - pVp).getNormalized()); + if ((dir & OPPOSITE_WINDING)) rt = -rt; + if (rt < 0.000001) + continue; + float tempAngle = PxVec2(1, 0).dot((tempPoint - holePoint).getNormalized()); + if (bestAngle < tempAngle) + { + bestAngle = tempAngle; + bridgePoint = i; + } + } + } + if (notFound) + { + bridgePoint = vrtIndex; + } + if (bridgePoint == -1) + { + // std::cout << "Triangulation: bridge vertex for inner loop is not found..." << std::endl; + return 1; + } + } + else + { + bridgePoint = vrtIndex; + } + std::vector<uint32_t> temporal; + + for (int32_t i = 0; i <= bridgePoint; ++i) + { + temporal.push_back(externalLoop[i]); + } + temporal.push_back(internalLoop[mIndex]); + for (int32_t i = (mIndex + 1) % internalLoop.size(); i != mIndex; i = (i + 1) % internalLoop.size()) + { + temporal.push_back(internalLoop[i]); + } + temporal.push_back(internalLoop[mIndex]); + for (uint32_t i = bridgePoint; i < externalLoop.size(); ++i) + { + temporal.push_back(externalLoop[i]); + } + externalLoop = temporal; + return 0; +} + +void ChunkPostProcessor::buildPolygonAndTriangulate(std::vector<Edge>& edges, Vertex* vertices, int32_t userData) +{ + std::vector<std::vector<uint32_t> > serializedLoops; + + std::set<int> visitedVertices; + std::vector<int> used(edges.size(), 0); + uint32_t collected = 0; + + std::vector<int> edgesIds; + /** + Add first edge to polygon + */ + edgesIds.push_back(0); + visitedVertices.insert(edges[0].s); + visitedVertices.insert(edges[0].e); + used[0] = true; + collected = 1; + uint32_t lastEdge = 0; + bool successfullPass = false; + for (; collected < edges.size();) + { + successfullPass = false; + for (uint32_t p = 0; p < edges.size(); ++p) + { + if (used[p] == 0 && edges[p].s == edges[lastEdge].e) + { + successfullPass = true; + collected++; + used[p] = true; + edgesIds.push_back(p); + lastEdge = p; + if (visitedVertices.find(edges[p].e) != visitedVertices.end()) // if we formed loop, detach it and triangulate + { + serializedLoops.push_back(std::vector<uint32_t>()); + std::vector<uint32_t>& serializedPositions = serializedLoops.back(); + while (edgesIds.size() > 0) + { + serializedPositions.push_back(edges[edgesIds.back()].s); + visitedVertices.erase(edges[edgesIds.back()].s); + if (edges[edgesIds.back()].s == edges[p].e) + { + edgesIds.pop_back(); + break; + } + edgesIds.pop_back(); + } + if (edgesIds.size() > 0) + { + lastEdge = edgesIds.back(); + } + else + { + for (uint32_t t = 0; t < edges.size(); ++t) + { + if (used[t] == 0) + { + edgesIds.push_back(t); + visitedVertices.insert(edges[t].s); + visitedVertices.insert(edges[t].e); + used[t] = true; + collected++; + lastEdge = t; + break; + } + } + } + } + else + { + visitedVertices.insert(edges[p].e); + } + } + } + if (!successfullPass) + { + break; + } + } + + std::vector<LoopInfo> loopsInfo(serializedLoops.size()); + // Compute normal to whole polygon, and areas of loops + PxVec3 wholeFacetNormal(0, 0, 0); + for (uint32_t loop = 0; loop < serializedLoops.size(); ++loop) + { + PxVec3 loopNormal(0, 0, 0); + std::vector<uint32_t>& pos = serializedLoops[loop]; + for (uint32_t vrt = 1; vrt + 1 < serializedLoops[loop].size(); ++vrt) + { + loopNormal += (vertices[pos[vrt]].p - vertices[pos[0]].p).cross(vertices[pos[vrt + 1]].p - vertices[pos[0]].p); + } + loopsInfo[loop].area = loopNormal.magnitude(); + loopsInfo[loop].normal = loopNormal; + loopsInfo[loop].index = loop; + wholeFacetNormal += loopNormal; + } + + // Change areas signs according to winding direction + for (uint32_t loop = 0; loop < serializedLoops.size(); ++loop) + { + if (wholeFacetNormal.dot(loopsInfo[loop].normal) < 0) + { + loopsInfo[loop].area = -loopsInfo[loop].area; + } + } + ProjectionDirections dir = getProjectionDirection(wholeFacetNormal); + std::sort(loopsInfo.begin(), loopsInfo.end()); + + std::vector<PxVec3> tempPositions; + int32_t oldSize = static_cast<int32_t>(mBaseMeshTriangles.size()); + for (uint32_t extPoly = 0; extPoly < loopsInfo.size(); ++extPoly) + { + if (loopsInfo[extPoly].area < 0) + { + continue; // Polygon with negative area is hole + } + int32_t baseLoop = loopsInfo[extPoly].index; + for (uint32_t intPoly = 0; intPoly < loopsInfo.size(); ++intPoly) + { + if (loopsInfo[intPoly].area > 0 || loopsInfo[intPoly].used || abs(loopsInfo[intPoly].area) > loopsInfo[extPoly].area) + { + continue; + } + int32_t holeLoop = loopsInfo[intPoly].index; + + if (!unitePolygons(serializedLoops[baseLoop], serializedLoops[holeLoop], vertices, dir)) + { + loopsInfo[intPoly].used = true; + }; + } + triangulatePolygonWithEarClipping(serializedLoops[baseLoop],vertices, dir); + } + for (uint32_t i = oldSize; i < mBaseMeshTriangles.size(); ++i) + { + mBaseMeshTriangles[i].userInfo = userData; + } +} + +NV_FORCE_INLINE int32_t ChunkPostProcessor::addVerticeIfNotExist(Vertex& p) +{ + auto it = mVertMap.find(p); + if (it == mVertMap.end()) + { + mVertMap[p] = static_cast<int32_t>(mVertices.size()); + mVertices.push_back(p); + return static_cast<int32_t>(mVertices.size()) - 1; + } + else + { + return it->second; + } +} + +NV_FORCE_INLINE void ChunkPostProcessor::addEdgeIfValid(EdgeWithParent& ed) +{ + if (ed.s == ed.e) + return; + EdgeWithParent opposite(ed.e, ed.s, ed.parent); + auto it = mEdgeMap.find(opposite); + if (it == mEdgeMap.end()) + { + mEdgeMap[ed] = static_cast<int32_t>(mBaseMeshEdges.size()); + mBaseMeshEdges.push_back(ed); + } + else + { + if (mBaseMeshEdges[it->second].s == NOT_VALID_VERTEX) + { + mBaseMeshEdges[it->second].s = ed.s; + mBaseMeshEdges[it->second].e = ed.e; + } + mBaseMeshEdges[it->second].s = NOT_VALID_VERTEX; + } +} + + + +void ChunkPostProcessor::prepare(Mesh* mesh) +{ + Edge* ed = mesh->getEdges(); + Vertex* vr = mesh->getVertices(); + mBaseMapping.resize(mesh->getVerticesCount()); + for (uint32_t i = 0; i < mesh->getFacetCount(); ++i) + { + Facet* fc = mesh->getFacet(i); + for (uint32_t j = fc->firstEdgeNumber; j < fc->firstEdgeNumber + fc->edgesCount; ++j) + { + int32_t a = addVerticeIfNotExist(vr[ed[j].s]); + int32_t b = addVerticeIfNotExist(vr[ed[j].e]); + mBaseMapping[ed[j].s] = a; + mBaseMapping[ed[j].e] = b; + EdgeWithParent e(a, b, i); + addEdgeIfValid(e); + } + } + std::vector<EdgeWithParent> temp; + temp.reserve(mBaseMeshEdges.size()); + for (uint32_t i = 0; i < mBaseMeshEdges.size(); ++i) + { + if (mBaseMeshEdges[i].s != NOT_VALID_VERTEX) + { + temp.push_back(mBaseMeshEdges[i]); + } + } + +} + +void ChunkPostProcessor::reset() +{ + isTesselated = false; + mVertices.clear(); + mBaseMeshEdges.clear(); + mVertMap.clear(); + mEdgeMap.clear(); + mTrMeshEdgeMap.clear(); + mTrMeshEdges.clear(); + mTrMeshEdToTr.clear(); + mBaseMeshTriangles.clear(); + mEdgeFlag.clear(); + mVertexValence.clear(); + mRestrictionFlag.clear(); + mVerticesDistances.clear(); + mVerticesNormalsSmoothed.clear(); + + mBaseMeshResultTriangles.clear(); + mTesselatedMeshResultTriangles.clear(); + mTesselatedMeshTriangles.clear(); +} + +void ChunkPostProcessor::triangulate(Mesh* mesh) +{ + reset(); + if (mesh == nullptr || !mesh->isValid()) + { + return; + } + prepare(mesh); + if (mBaseMeshEdges.empty()) + { + return; + } + std::vector<Edge> temp; + int32_t fP = mBaseMeshEdges[0].parent; + for (uint32_t i = 0; i < mBaseMeshEdges.size(); ++i) + { + if (fP != mBaseMeshEdges[i].parent) + { + if (temp.empty() == false) + { + buildPolygonAndTriangulate(temp, &mVertices[0], mesh->getFacet(fP)->userData); + } + temp.clear(); + fP = mBaseMeshEdges[i].parent; + } + temp.push_back(Edge(mBaseMeshEdges[i].s, mBaseMeshEdges[i].e)); + } + buildPolygonAndTriangulate(temp, &mVertices[0], mesh->getFacet(fP)->userData); + + /* Build final triangles */ + + mBaseMeshResultTriangles.clear(); + for (uint32_t i = 0; i < mBaseMeshTriangles.size(); ++i) + { + if (mBaseMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + mBaseMeshResultTriangles.push_back(Triangle(mVertices[mBaseMeshTriangles[i].ea], mVertices[mBaseMeshTriangles[i].eb], mVertices[mBaseMeshTriangles[i].ec])); + mBaseMeshResultTriangles.back().userInfo = mBaseMeshTriangles[i].userInfo; + } + + computePositionedMapping(); +} + +void ChunkPostProcessor::prebuildTesselatedTriangles() +{ + mTesselatedMeshResultTriangles.clear(); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + mTesselatedMeshResultTriangles.push_back(Triangle(mVertices[mTesselatedMeshTriangles[i].ea], mVertices[mTesselatedMeshTriangles[i].eb], mVertices[mTesselatedMeshTriangles[i].ec])); + mTesselatedMeshResultTriangles.back().userInfo = mTesselatedMeshTriangles[i].userInfo; + } + +} + + +int32_t ChunkPostProcessor::addEdgeTr(const Edge& e) +{ + Edge ed = e; + if (ed.e < ed.s) std::swap(ed.s, ed.e); + auto it = mTrMeshEdgeMap.find(ed); + if (it == mTrMeshEdgeMap.end()) + { + mTrMeshEdToTr.push_back(EdgeToTriangles()); + mTrMeshEdgeMap[ed] = (int)mTrMeshEdToTr.size() - 1; + mTrMeshEdges.push_back(ed); + mEdgeFlag.push_back(INTERNAL_EDGE); + return (int32_t)mTrMeshEdToTr.size() - 1; + } + else + { + return it->second; + } +} + +int32_t ChunkPostProcessor::findEdge(const Edge& e) +{ + Edge ed = e; + if (ed.e < ed.s) std::swap(ed.s, ed.e); + auto it = mTrMeshEdgeMap.find(ed); + if (it == mTrMeshEdgeMap.end()) + { + return -1; + } + return it->second; +} + +void ChunkPostProcessor::updateEdgeTriangleInfo() +{ + mTrMeshEdToTr.clear(); + mTrMeshEdToTr.resize(mTrMeshEdges.size()); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + TriangleIndexed& tr = mTesselatedMeshTriangles[i]; + if (tr.ea == NOT_VALID_VERTEX) + continue; + int32_t ed = addEdgeTr(Edge(tr.ea, tr.eb)); + mTrMeshEdToTr[ed].add(i); + ed = addEdgeTr(Edge(tr.ea, tr.ec)); + mTrMeshEdToTr[ed].add(i); + ed = addEdgeTr(Edge(tr.ec, tr.eb)); + mTrMeshEdToTr[ed].add(i); + } +} + +void ChunkPostProcessor::updateVertEdgeInfo() +{ + mVertexToTriangleMap.clear(); + mVertexToTriangleMap.resize(mVertices.size()); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + TriangleIndexed& tr = mTesselatedMeshTriangles[i]; + if (tr.ea == NOT_VALID_VERTEX) continue; + mVertexToTriangleMap[tr.ea].push_back(i); + mVertexToTriangleMap[tr.eb].push_back(i); + mVertexToTriangleMap[tr.ec].push_back(i); + } + mVertexValence.clear(); + mVertexValence.resize(mVertices.size(), 0); + + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + if (mTrMeshEdToTr[i].c != 0) + { + mVertexValence[mTrMeshEdges[i].s]++; + mVertexValence[mTrMeshEdges[i].e]++; + } + } +} + + +void ChunkPostProcessor::collapseEdge(int32_t id) +{ + Edge cEdge = mTrMeshEdges[id]; + uint32_t from = cEdge.s; + uint32_t to = cEdge.e; + + + if (mRestrictionFlag[from] && mRestrictionFlag[to]) + { + return; + } + + if (mVertexValence[from] > mVertexValence[to]) + { + std::swap(from, to); + } + + if (mRestrictionFlag[from]) + { + std::swap(from, to); + } + + std::set<int32_t> connectedToBegin; + std::set<int32_t> connectedToEnd; + std::set<int32_t> neighboorTriangles; + + int32_t trWithEdge[2] = {-1, -1}; + int32_t cntr = 0; + for (uint32_t i = 0; i < mVertexToTriangleMap[from].size(); ++i) + { + if (mTesselatedMeshTriangles[mVertexToTriangleMap[from][i]].ea == NOT_VALID_VERTEX) + continue; + if (neighboorTriangles.insert(mVertexToTriangleMap[from][i]).second && mTesselatedMeshTriangles[mVertexToTriangleMap[from][i]].isContainEdge(from, to)) + { + trWithEdge[cntr] = mVertexToTriangleMap[from][i]; + cntr++; + } + } + for (uint32_t i = 0; i < mVertexToTriangleMap[to].size(); ++i) + { + if (mTesselatedMeshTriangles[mVertexToTriangleMap[to][i]].ea == NOT_VALID_VERTEX) + continue; + if (neighboorTriangles.insert(mVertexToTriangleMap[to][i]).second && mTesselatedMeshTriangles[mVertexToTriangleMap[to][i]].isContainEdge(from, to)) + { + trWithEdge[cntr] = mVertexToTriangleMap[to][i]; + cntr++; + } + } + + if (cntr == 0) + { + return; + } + if (cntr > 2) + { + return; + } + + for (uint32_t i: neighboorTriangles) + { + if (mTesselatedMeshTriangles[i].ea == from || mTesselatedMeshTriangles[i].eb == from || mTesselatedMeshTriangles[i].ec == from) + { + if (mTesselatedMeshTriangles[i].ea != to && mTesselatedMeshTriangles[i].ea != from) + connectedToBegin.insert(mTesselatedMeshTriangles[i].ea); + if (mTesselatedMeshTriangles[i].eb != to && mTesselatedMeshTriangles[i].eb != from) + connectedToBegin.insert(mTesselatedMeshTriangles[i].eb); + if (mTesselatedMeshTriangles[i].ec != to && mTesselatedMeshTriangles[i].ec != from) + connectedToBegin.insert(mTesselatedMeshTriangles[i].ec); + } + + if (mTesselatedMeshTriangles[i].ea == to || mTesselatedMeshTriangles[i].eb == to || mTesselatedMeshTriangles[i].ec == to) + { + if (mTesselatedMeshTriangles[i].ea != to && mTesselatedMeshTriangles[i].ea != from) + connectedToEnd.insert(mTesselatedMeshTriangles[i].ea); + if (mTesselatedMeshTriangles[i].eb != to && mTesselatedMeshTriangles[i].eb != from) + connectedToEnd.insert(mTesselatedMeshTriangles[i].eb); + if (mTesselatedMeshTriangles[i].ec != to && mTesselatedMeshTriangles[i].ec != from) + connectedToEnd.insert(mTesselatedMeshTriangles[i].ec); + } + } + bool canBeCollapsed = true; + for (auto it = connectedToBegin.begin(); it != connectedToBegin.end(); ++it) + { + uint32_t currV = *it; + if (connectedToEnd.find(currV) == connectedToEnd.end()) + continue; + bool found = false; + for (int32_t tr : neighboorTriangles) + { + if ((mTesselatedMeshTriangles[tr].ea == from || mTesselatedMeshTriangles[tr].eb == from || mTesselatedMeshTriangles[tr].ec == from) && + (mTesselatedMeshTriangles[tr].ea == to || mTesselatedMeshTriangles[tr].eb == to || mTesselatedMeshTriangles[tr].ec == to) && + (mTesselatedMeshTriangles[tr].ea == currV || mTesselatedMeshTriangles[tr].eb == currV || mTesselatedMeshTriangles[tr].ec == currV)) + { + found = true; + break; + } + } + if (!found) + { + canBeCollapsed = false; + break; + } + } + + if (canBeCollapsed) + { + for (int32_t i : neighboorTriangles) + { + if (trWithEdge[0] == i) continue; + if (cntr == 2 && trWithEdge[1] == i) continue; + TriangleIndexed tr = mTesselatedMeshTriangles[i]; + PxVec3 oldNormal = (mVertices[tr.eb].p - mVertices[tr.ea].p).cross(mVertices[tr.ec].p - mVertices[tr.ea].p); + + if (tr.ea == from) + { + tr.ea = to; + } + else + if (tr.eb == from) + { + tr.eb = to; + } + else + if (tr.ec == from) + { + tr.ec = to; + } + PxVec3 newNormal = (mVertices[tr.eb].p - mVertices[tr.ea].p).cross(mVertices[tr.ec].p - mVertices[tr.ea].p); + if (newNormal.magnitude() < 1e-8f) + { + canBeCollapsed = false; + break; + } + if (oldNormal.dot(newNormal) < 0) + { + canBeCollapsed = false; + break; + } + } + } + + if (canBeCollapsed) + { + mTesselatedMeshTriangles[trWithEdge[0]].ea = NOT_VALID_VERTEX; + if (cntr == 2)mTesselatedMeshTriangles[trWithEdge[1]].ea = NOT_VALID_VERTEX; + + for (int32_t i : neighboorTriangles) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + continue; + if (mTesselatedMeshTriangles[i].ea == from) + { + mTesselatedMeshTriangles[i].ea = to; + mVertexToTriangleMap[from].clear(); + mVertexToTriangleMap[to].push_back(i); + } + else + if (mTesselatedMeshTriangles[i].eb == from) + { + mTesselatedMeshTriangles[i].eb = to; + mVertexToTriangleMap[from].clear(); + mVertexToTriangleMap[to].push_back(i); + } + else + if (mTesselatedMeshTriangles[i].ec == from) + { + mTesselatedMeshTriangles[i].ec = to; + mVertexToTriangleMap[from].clear(); + mVertexToTriangleMap[to].push_back(i); + } + } + } +} + + +void ChunkPostProcessor::divideEdge(int32_t id) +{ + + if (mTrMeshEdToTr[id].c == 0 ) + { + return; + } + + Edge cEdge = mTrMeshEdges[id]; + EdgeFlag snapRestriction = mEdgeFlag[id]; + Vertex middle; + uint32_t nv = NOT_VALID_VERTEX; + for (int32_t t = 0; t < mTrMeshEdToTr[id].c; ++t) + { + int32_t oldTriangleIndex = mTrMeshEdToTr[id].tr[t]; + TriangleIndexed tr = mTesselatedMeshTriangles[mTrMeshEdToTr[id].tr[t]]; + + if (tr.ea == NOT_VALID_VERTEX) + { + continue; + } + + uint32_t pbf[3]; + pbf[0] = tr.ea; + pbf[1] = tr.eb; + pbf[2] = tr.ec; + for (int32_t p = 0; p < 3; ++p) + { + int32_t pnx = (p + 1) % 3; + int32_t opp = (p + 2) % 3; + + if ((pbf[p] == cEdge.s && pbf[pnx] == cEdge.e) || (pbf[p] == cEdge.e && pbf[pnx] == cEdge.s)) + { + if (nv == NOT_VALID_VERTEX) + { + middle.p = (mVertices[pbf[p]].p + mVertices[pbf[pnx]].p) * 0.5f; + middle.n = (mVertices[pbf[p]].n + mVertices[pbf[pnx]].n) * 0.5f; + middle.uv[0] = (mVertices[pbf[p]].uv[0] + mVertices[pbf[pnx]].uv[0]) * 0.5f; + + nv = (uint32_t)mVertices.size(); + mVertices.push_back(middle); + } + if (nv < mRestrictionFlag.size()) + { + mRestrictionFlag[nv] = ((snapRestriction == EXTERNAL_BORDER_EDGE) || (snapRestriction == INTERNAL_BORDER_EDGE)); + } + else + { + mRestrictionFlag.push_back((snapRestriction == EXTERNAL_BORDER_EDGE) || (snapRestriction == INTERNAL_BORDER_EDGE)); + } + + uint32_t ind1 = addEdgeTr(Edge(pbf[p], nv)); + uint32_t ind2 = addEdgeTr(Edge(nv, pbf[pnx])); + uint32_t ind3 = addEdgeTr(Edge(nv, pbf[opp])); + + + mEdgeFlag[ind1] = snapRestriction; + mEdgeFlag[ind2] = snapRestriction; + mEdgeFlag[ind3] = INTERNAL_EDGE; + + mTrMeshEdToTr[ind1].add(mTrMeshEdToTr[id].tr[t]); + int32_t userInfo = mTesselatedMeshTriangles[mTrMeshEdToTr[id].tr[t]].userInfo; + mTesselatedMeshTriangles[mTrMeshEdToTr[id].tr[t]] = TriangleIndexed(pbf[p], nv, pbf[opp]); + mTesselatedMeshTriangles[mTrMeshEdToTr[id].tr[t]].userInfo = userInfo; + mTrMeshEdToTr[ind2].add((int32_t)mTesselatedMeshTriangles.size()); + mTrMeshEdToTr[ind3].add((int32_t)mTrMeshEdToTr[id].tr[t]); + mTrMeshEdToTr[ind3].add((int32_t)mTesselatedMeshTriangles.size()); + mTesselatedMeshTriangles.push_back(TriangleIndexed(nv,pbf[pnx], pbf[opp])); + mTesselatedMeshTriangles.back().userInfo = userInfo; + int32_t ed1 = findEdge(Edge(pbf[pnx], pbf[opp])); + mTrMeshEdToTr[ed1].replace(oldTriangleIndex, (int32_t)mTesselatedMeshTriangles.size() - 1); + break; + } + } + } +} + + +NV_FORCE_INLINE void markEdge(int32_t ui, int32_t ed, std::vector<ChunkPostProcessor::EdgeFlag>& shortMarkup, std::vector<int32_t>& lastOwner) +{ + if (shortMarkup[ed] == ChunkPostProcessor::NONE) + { + if (ui == 0) + { + shortMarkup[ed] = ChunkPostProcessor::EXTERNAL_EDGE; + } + else + { + shortMarkup[ed] = ChunkPostProcessor::INTERNAL_EDGE; + } + lastOwner[ed] = ui; + } + else + { + if (ui != 0) + { + if (shortMarkup[ed] == ChunkPostProcessor::EXTERNAL_EDGE) + { + shortMarkup[ed] = ChunkPostProcessor::EXTERNAL_BORDER_EDGE; + } + if ((shortMarkup[ed] == ChunkPostProcessor::INTERNAL_EDGE) && ui != lastOwner[ed]) + { + shortMarkup[ed] = ChunkPostProcessor::INTERNAL_BORDER_EDGE; + } + } + else + { + if (shortMarkup[ed] != ChunkPostProcessor::EXTERNAL_EDGE) + { + shortMarkup[ed] = ChunkPostProcessor::EXTERNAL_BORDER_EDGE; + } + } + } +} + +float falloffFunction(float x, float mx) +{ + float t = (x) / (mx + 1e-6f); + t = std::min(1.0f, t); + return t * t; +} + +void ChunkPostProcessor::recalcNoiseDirs() +{ + /** + Compute normals direction to apply noise + */ + mVerticesNormalsSmoothed.resize(mVertices.size(), PxVec3(0, 0, 0)); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + TriangleIndexed& tr = mTesselatedMeshTriangles[i]; + if (tr.userInfo == 0) continue; + + if (tr.userInfo < 0) + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]] += mVertices[tr.ea].n.getNormalized(); + else + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]] -= mVertices[tr.ea].n.getNormalized(); + + if (tr.userInfo < 0) + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]] += mVertices[tr.eb].n.getNormalized(); + else + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]] -= mVertices[tr.eb].n.getNormalized(); + + if (tr.userInfo < 0) + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ec]] += mVertices[tr.ec].n.getNormalized(); + else + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ec]] -= mVertices[tr.ec].n.getNormalized(); + + } + for (uint32_t i = 0; i < mVerticesNormalsSmoothed.size(); ++i) + { + + mVerticesNormalsSmoothed[i] = mVerticesNormalsSmoothed[mPositionMappedVrt[i]]; + mVerticesNormalsSmoothed[i].normalize(); + } +} + + + +void ChunkPostProcessor::applyNoise(SimplexNoise& noise, float falloff, int32_t relaxIterations, float relaxFactor) +{ + NVBLAST_ASSERT(isTesselated); + if (isTesselated == false) + { + return; + } + mRestrictionFlag.clear(); + mRestrictionFlag.resize(mVertices.size(), false); + + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + if (mTrMeshEdToTr[i].c != 0) + { + if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE) + { + mRestrictionFlag[mTrMeshEdges[i].e] = true; + mRestrictionFlag[mTrMeshEdges[i].s] = true; + } + } + } + std::vector<Vertex> localVertices = mVertices; + + recalcNoiseDirs(); + + relax(relaxIterations, relaxFactor, localVertices); + + + /** + Apply noise + */ + for (uint32_t i = 0; i < localVertices.size(); ++i) + { + + if (!mRestrictionFlag[i]) + { + + float d = noise.sample(localVertices[i].p); + localVertices[i].p += (falloffFunction(mVerticesDistances[i], falloff)) * mVerticesNormalsSmoothed[i] * d; + } + } + + + /* Recalculate smoothed normals*/ + mVerticesNormalsSmoothed.assign(mVerticesNormalsSmoothed.size(), PxVec3(0, 0, 0)); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + TriangleIndexed& tr = mTesselatedMeshTriangles[i]; + if (tr.userInfo == 0) continue; + + Triangle pTr(localVertices[tr.ea], localVertices[tr.eb], localVertices[tr.ec]); + PxVec3 nrm = pTr.getNormal().getNormalized(); + + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]] += nrm; + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]] += nrm; + mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ec]] += nrm; + } + for (uint32_t i = 0; i < mVerticesNormalsSmoothed.size(); ++i) + { + mVerticesNormalsSmoothed[i] = mVerticesNormalsSmoothed[mPositionMappedVrt[i]]; + mVerticesNormalsSmoothed[i].normalize(); + } + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + TriangleIndexed& tr = mTesselatedMeshTriangles[i]; + if (tr.userInfo == 0) continue; + + localVertices[tr.ea].n = mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]]; + localVertices[tr.eb].n = mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]]; + localVertices[tr.ec].n = mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ec]]; + } + + mTesselatedMeshResultTriangles.clear(); + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].ea == NOT_VALID_VERTEX) + { + continue; + } + mTesselatedMeshResultTriangles.push_back(Triangle(localVertices[mTesselatedMeshTriangles[i].ea], localVertices[mTesselatedMeshTriangles[i].eb], localVertices[mTesselatedMeshTriangles[i].ec])); + mTesselatedMeshResultTriangles.back().userInfo = mTesselatedMeshTriangles[i].userInfo; + } + + +} + + +void ChunkPostProcessor::computePositionedMapping() +{ + std::map<PxVec3, int32_t, VrtPositionComparator> mPosMap; + mPositionMappedVrt.clear(); + mPositionMappedVrt.resize(mVertices.size()); + + for (uint32_t i = 0; i < mVertices.size(); ++i) + { + auto it = mPosMap.find(mVertices[i].p); + + if (it == mPosMap.end()) + { + mPosMap[mVertices[i].p] = i; + mPositionMappedVrt[i] = i; + } + else + { + mPositionMappedVrt[i] = it->second; + } + } +} + +void ChunkPostProcessor::computeFalloffAndNormals() +{ + // Map newly created vertices according to positions + + computePositionedMapping(); + + mGeometryGraph.resize(mVertices.size()); + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + if (mTrMeshEdToTr[i].c == 0) + { + continue; + } + int32_t v1 = mPositionMappedVrt[mTrMeshEdges[i].s]; + int32_t v2 = mPositionMappedVrt[mTrMeshEdges[i].e]; + + if (std::find(mGeometryGraph[v1].begin(), mGeometryGraph[v1].end(), v2) == mGeometryGraph[v1].end()) + mGeometryGraph[v1].push_back(v2); + if (std::find(mGeometryGraph[v2].begin(), mGeometryGraph[v2].end(), v1) == mGeometryGraph[v2].end()) + mGeometryGraph[v2].push_back(v1); + } + mVerticesDistances.clear(); + mVerticesDistances.resize(mVertices.size(), 10000.0f); + + std::queue<int32_t> que; + + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + if (mTrMeshEdToTr[i].c != 0 && (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE)) + { + int32_t v1 = mPositionMappedVrt[mTrMeshEdges[i].s]; + int32_t v2 = mPositionMappedVrt[mTrMeshEdges[i].e]; + mVerticesDistances[v1] = 0.0f; + mVerticesDistances[v2] = 0.0f; + que.push(v1); + que.push(v2); + } + } + while (!que.empty()) + { + int32_t curr = que.front(); + que.pop(); + + for (uint32_t i = 0; i < mGeometryGraph[curr].size(); ++i) + { + int32_t to = mGeometryGraph[curr][i]; + float d = mVerticesDistances[curr] + 0.1f;// (mVertices[to].p - mVertices[curr].p).magnitudeSquared(); + if (d < mVerticesDistances[to]) + { + mVerticesDistances[to] = d; + que.push(to); + } + } + } + + for (uint32_t i = 0; i < mVerticesDistances.size(); ++i) + { + int32_t from = mPositionMappedVrt[i]; + mVerticesDistances[i] = mVerticesDistances[from]; + } +} + +bool edgeOverlapTest(PxVec3& as, PxVec3& ae, PxVec3& bs, PxVec3& be) +{ + //return false; + if (std::max(std::min(as.x, ae.x), std::min(bs.x, be.x)) > std::min(std::max(as.x, ae.x), std::max(bs.x, be.x))) return false; + if (std::max(std::min(as.y, ae.y), std::min(bs.y, be.y)) > std::min(std::max(as.y, ae.y), std::max(bs.y, be.y))) return false; + if (std::max(std::min(as.z, ae.z), std::min(bs.z, be.z)) > std::min(std::max(as.z, ae.z), std::max(bs.z, be.z))) return false; + + return ((bs - as).cross(ae - as)).magnitudeSquared() < 1e-12f && ((be - as).cross(ae - as)).magnitudeSquared() < 1e-12f; +} + +void ChunkPostProcessor::relax(int32_t iteration, float factor, std::vector<Vertex>& vertices) +{ + std::vector<PxVec3> verticesTemp(vertices.size()); + std::vector<PxVec3> normalsTemp(vertices.size()); + for (int32_t iter = 0; iter < iteration; ++iter) + { + for (uint32_t i = 0; i < vertices.size(); ++i) + { + if (mRestrictionFlag[i]) + { + continue; + } + PxVec3 cps = vertices[i].p; + PxVec3 cns = mVerticesNormalsSmoothed[i]; + PxVec3 averaged(0, 0, 0); + PxVec3 averagedNormal(0, 0, 0); + + for (uint32_t p = 0; p < mGeometryGraph[mPositionMappedVrt[i]].size(); ++p) + { + int32_t to = mGeometryGraph[mPositionMappedVrt[i]][p]; + averaged += vertices[to].p; + averagedNormal += mVerticesNormalsSmoothed[to]; + + } + averaged *= (1.0f / mGeometryGraph[mPositionMappedVrt[i]].size()); + averagedNormal *= (1.0f / mGeometryGraph[mPositionMappedVrt[i]].size()); + verticesTemp[i] = cps + (averaged - cps) * factor; + normalsTemp[i] = cns * (1.0f - factor) + averagedNormal * factor; + } + for (uint32_t i = 0; i < vertices.size(); ++i) + { + if (mRestrictionFlag[i]) + { + continue; + } + vertices[i].p = verticesTemp[i]; + mVerticesNormalsSmoothed[i] = normalsTemp[i].getNormalized(); + + } + } + +} + +void ChunkPostProcessor::prebuildEdgeFlagArray() +{ + mRestrictionFlag.clear(); + mRestrictionFlag.resize(mVertices.size()); + mEdgeFlag.clear(); + mEdgeFlag.resize(mTrMeshEdges.size(), NONE); + + std::map<PxVec3, int32_t, VrtPositionComparator> mPosMap; + mPositionMappedVrt.clear(); + mPositionMappedVrt.resize(mVertices.size(), 0); + + for (uint32_t i = 0; i < mVertices.size(); ++i) + { + auto it = mPosMap.find(mVertices[i].p); + + if (it == mPosMap.end()) + { + mPosMap[mVertices[i].p] = i; + mPositionMappedVrt[i] = i; + } + else + { + mPositionMappedVrt[i] = it->second; + } + } + + std::map<Edge, int32_t> mPositionEdgeMap; + std::vector<int32_t> mPositionBasedEdges(mTrMeshEdges.size()); + + + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + Edge tmp = Edge(mPositionMappedVrt[mTrMeshEdges[i].s], mPositionMappedVrt[mTrMeshEdges[i].e]); + if (tmp.e < tmp.s) std::swap(tmp.e, tmp.s); + auto it = mPositionEdgeMap.find(tmp); + if (it == mPositionEdgeMap.end()) + { + mPositionEdgeMap[tmp] = i; + mPositionBasedEdges[i] = i; + } + else + { + mPositionBasedEdges[i] = it->second; + } + } + + std::vector<EdgeFlag> shortMarkup(mTrMeshEdges.size(), NONE); + std::vector<int32_t> lastOwner(mTrMeshEdges.size(), 0); + + std::vector<std::vector<int32_t> > edgeOverlap(mTrMeshEdges.size()); + for (auto it1 = mPositionEdgeMap.begin(); it1 != mPositionEdgeMap.end(); ++it1) + { + auto it2 = it1; + it2++; + for (; it2 != mPositionEdgeMap.end(); ++it2) + { + Edge& ed1 = mTrMeshEdges[it1->second]; + Edge& ed2 = mTrMeshEdges[it2->second]; + + if (edgeOverlapTest(mVertices[ed1.s].p, mVertices[ed1.e].p, mVertices[ed2.s].p, mVertices[ed2.e].p)) + { + edgeOverlap[it1->second].push_back(it2->second); + } + } + } + + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + int32_t ui = mTesselatedMeshTriangles[i].userInfo; + int32_t ed = mPositionBasedEdges[findEdge(Edge(mTesselatedMeshTriangles[i].ea, mTesselatedMeshTriangles[i].eb))]; + + + markEdge(ui, ed, shortMarkup, lastOwner); + for (uint32_t ov = 0; ov < edgeOverlap[ed].size(); ++ov) + { + markEdge(ui, edgeOverlap[ed][ov], shortMarkup, lastOwner); + } + + ed = mPositionBasedEdges[findEdge(Edge(mTesselatedMeshTriangles[i].ea, mTesselatedMeshTriangles[i].ec))]; + markEdge(ui, ed, shortMarkup, lastOwner); + for (uint32_t ov = 0; ov < edgeOverlap[ed].size(); ++ov) + { + markEdge(ui, edgeOverlap[ed][ov], shortMarkup, lastOwner); + } + + ed = mPositionBasedEdges[findEdge(Edge(mTesselatedMeshTriangles[i].eb, mTesselatedMeshTriangles[i].ec))]; + markEdge(ui, ed, shortMarkup, lastOwner); + for (uint32_t ov = 0; ov < edgeOverlap[ed].size(); ++ov) + { + markEdge(ui, edgeOverlap[ed][ov], shortMarkup, lastOwner); + } + + } + + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + mEdgeFlag[i] = shortMarkup[mPositionBasedEdges[i]]; + } + + for (uint32_t i = 0; i < mTesselatedMeshTriangles.size(); ++i) + { + if (mTesselatedMeshTriangles[i].userInfo != 0) continue; + + int32_t ed = findEdge(Edge(mTesselatedMeshTriangles[i].ea, mTesselatedMeshTriangles[i].eb)); + mEdgeFlag[ed] = EXTERNAL_EDGE; + ed = findEdge(Edge(mTesselatedMeshTriangles[i].ec, mTesselatedMeshTriangles[i].eb)); + mEdgeFlag[ed] = EXTERNAL_EDGE; + ed = findEdge(Edge(mTesselatedMeshTriangles[i].ea, mTesselatedMeshTriangles[i].ec)); + mEdgeFlag[ed] = EXTERNAL_EDGE; + } +} + + + +void ChunkPostProcessor::tesselateInternalSurface(float maxLenIn) +{ + mTesselatedMeshTriangles = mBaseMeshTriangles; + if (mTesselatedMeshTriangles.empty()) + { + return; + } + + updateEdgeTriangleInfo(); + prebuildEdgeFlagArray(); + mRestrictionFlag.resize(mVertices.size(), 0); + for (uint32_t i = 0; i < mTrMeshEdges.size(); ++i) + { + if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE || mEdgeFlag[i] == INTERNAL_BORDER_EDGE) + { + mRestrictionFlag[mTrMeshEdges[i].s] = 1; + mRestrictionFlag[mTrMeshEdges[i].e] = 1; + } + } + + + float maxLen = std::max(0.1f, maxLenIn); + while (maxLen > maxLenIn) + { + float mlSq = maxLen * maxLen; + float minD = maxLen * 0.5f; + minD = minD * minD; + + for (int32_t iter = 0; iter < 15; ++iter) + { + updateVertEdgeInfo(); + uint32_t oldSize = (uint32_t)mTrMeshEdges.size(); + for (uint32_t i = 0; i < oldSize; ++i) + { + if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == INTERNAL_BORDER_EDGE) + { + continue; + } + if ((mVertices[mTrMeshEdges[i].s].p - mVertices[mTrMeshEdges[i].e].p).magnitudeSquared() < minD) + { + collapseEdge(i); + } + } + + oldSize = (uint32_t)mTrMeshEdges.size(); + updateEdgeTriangleInfo(); + for (uint32_t i = 0; i < oldSize; ++i) + { + if (mEdgeFlag[i] == EXTERNAL_EDGE) + { + continue; + } + if ((mVertices[mTrMeshEdges[i].s].p - mVertices[mTrMeshEdges[i].e].p).magnitudeSquared() > mlSq) + { + divideEdge(i); + } + } + } + maxLen *= 0.3; + maxLen = std::max(maxLen, maxLenIn); + } + computeFalloffAndNormals(); + prebuildTesselatedTriangles(); + isTesselated = true; +} + +} // namespace Blast +} // namespace Nv
\ No newline at end of file |