aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/authoring
diff options
context:
space:
mode:
authorAnton Novoselov <[email protected]>2017-08-01 12:53:38 +0300
committerAnton Novoselov <[email protected]>2017-08-01 12:53:38 +0300
commit236f03c0b9a4982328ed1201978f7f69d192d9b2 (patch)
treee486f2fa39dba203563895541e92c60ed3e25759 /sdk/extensions/authoring
parentAdded screens to welcome page (diff)
downloadblast-236f03c0b9a4982328ed1201978f7f69d192d9b2.tar.xz
blast-236f03c0b9a4982328ed1201978f7f69d192d9b2.zip
Blast 1.1 release (windows / linux)
see docs/release_notes.txt for details
Diffstat (limited to 'sdk/extensions/authoring')
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoring.h119
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringBondGenerator.h151
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringCollisionBuilder.h103
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringFractureTool.h276
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringMesh.h179
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringMeshCleaner.h71
-rw-r--r--sdk/extensions/authoring/include/NvBlastExtAuthoringTypes.h179
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtApexSharedParts.cpp48
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtApexSharedParts.h43
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoring.cpp262
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.cpp74
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.h50
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.cpp (renamed from sdk/extensions/authoring/source/NvBlastExtAuthoringBondGenerator.cpp)391
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.h104
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.cpp384
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.h60
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.cpp (renamed from sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilder.cpp)171
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.h73
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.cpp (renamed from sdk/extensions/authoring/source/NvBlastExtAuthoringFractureTool.cpp)415
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.h330
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringInternalCommon.h91
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp1626
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.h25
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.cpp (renamed from sdk/extensions/authoring/source/NvBlastExtAuthoringMesh.cpp)141
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.h212
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.cpp975
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.h193
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringPerlinNoise.h36
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp946
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.h200
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtAuthoringVSA.h36
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.cpp36
-rw-r--r--sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.h36
33 files changed, 5752 insertions, 2284 deletions
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoring.h b/sdk/extensions/authoring/include/NvBlastExtAuthoring.h
new file mode 100644
index 0000000..ce21c65
--- /dev/null
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoring.h
@@ -0,0 +1,119 @@
+// 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-2017 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTAUTHORING_H
+#define NVBLASTAUTHORING_H
+
+#include "NvBlastExtAuthoringTypes.h"
+
+namespace physx
+{
+ class PxCooking;
+ class PxPhysicsInsertionCallback;
+}
+
+namespace Nv
+{
+ namespace Blast
+ {
+ class Mesh;
+ class VoronoiSitesGenerator;
+ class FractureTool;
+ class ConvexMeshBuilder;
+ class BlastBondGenerator;
+ class MeshCleaner;
+ }
+}
+
+/**
+Constructs mesh object from array of triangles.
+User should call release() after usage.
+
+\param[in] positions Array for vertex positions, 3 * verticesCount floats will be read
+\param[in] normals Array for vertex normals, 3 * verticesCount floats will be read
+\param[in] uv Array for vertex uv coordinates, 2 * verticesCount floats will be read
+\param[in] verticesCount Number of vertices in mesh
+\param[in] indices Array of vertex indices. Indices contain vertex index triplets which form a mesh triangle.
+\param[in] indicesCount Indices count (should be equal to numberOfTriangles * 3)
+
+\return pointer to Nv::Blast::Mesh if it was created succefully otherwise return nullptr
+*/
+NVBLAST_API Nv::Blast::Mesh* NvBlastExtAuthoringCreateMesh(const physx::PxVec3* positions, const physx::PxVec3* normals,
+ const physx::PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount);
+
+/**
+Voronoi sites should not be generated outside of the fractured mesh, so VoronoiSitesGenerator
+should be supplied with fracture mesh.
+\param[in] mesh Fracture mesh
+\param[in] rnd User supplied random value generator.
+\return Pointer to VoronoiSitesGenerator. User's code should release it after usage.
+*/
+NVBLAST_API Nv::Blast::VoronoiSitesGenerator* NvBlastExtAuthoringCreateVoronoiSitesGenerator(Nv::Blast::Mesh* mesh,
+ Nv::Blast::RandomGeneratorBase* rng);
+
+/**
+Create FractureTool object.
+\return Pointer to create FractureTool. User's code should release it after usage.
+*/
+NVBLAST_API Nv::Blast::FractureTool* NvBlastExtAuthoringCreateFractureTool();
+
+/**
+Create BlastBondGenerator
+\return Pointer to created BlastBondGenerator. User's code should release it after usage.
+*/
+NVBLAST_API Nv::Blast::BlastBondGenerator* NvBlastExtAuthoringCreateBondGenerator(physx::PxCooking* cooking,
+ physx::PxPhysicsInsertionCallback* insertionCallback);
+
+/**
+Create ConvexMeshBuilder
+\return Pointer to created ConvexMeshBuilder. User's code should release it after usage.
+*/
+NVBLAST_API Nv::Blast::ConvexMeshBuilder* NvBlastExtAuthoringCreateConvexMeshBuilder(physx::PxCooking* cooking,
+ physx::PxPhysicsInsertionCallback* insertionCallback);
+
+/**
+Performs pending fractures and generates fractured asset, render and collision geometry
+
+\param[in] fTool Fracture tool created by NvBlastExtAuthoringCreateFractureTool
+\param[in] bondGenerator Bond generator created by NvBlastExtAuthoringCreateBondGenerator
+\param[in] collisionBuilder Collision builder created by NvBlastExtAuthoringCreateConvexMeshBuilder
+\param[in] defaultSupportDepth All new chunks will be marked as support if its depth equal to defaultSupportDepth.
+ By default leaves (chunks without children) marked as support.
+\return Authoring result
+*/
+NVBLAST_API Nv::Blast::AuthoringResult* NvBlastExtAuthoringProcessFracture(Nv::Blast::FractureTool& fTool,
+ Nv::Blast::BlastBondGenerator& bondGenerator, Nv::Blast::ConvexMeshBuilder& collisionBuilder, int32_t defaultSupportDepth = -1);
+
+
+/**
+ Creates MeshCleaner object
+ \return pointer to Nv::Blast::Mesh if it was created succefully otherwise return nullptr
+*/
+NVBLAST_API Nv::Blast::MeshCleaner* NvBlastExtAuthoringCreateMeshCleaner();
+
+#endif // ifndef NVBLASTAUTHORING_H
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringBondGenerator.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringBondGenerator.h
index 68767eb..4f5d0e6 100644
--- a/sdk/extensions/authoring/include/NvBlastExtAuthoringBondGenerator.h
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringBondGenerator.h
@@ -1,35 +1,54 @@
-/*
-* Copyright (c) 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 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) 2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGBONDGENERATOR_H
#define NVBLASTEXTAUTHORINGBONDGENERATOR_H
#include "NvBlastExtAuthoringTypes.h"
-#include "NvBlastExtAuthoringFractureTool.h"
-#include "NvBlastTypes.h"
-#include "../cooking/PxCooking.h"
-#include <PxPlane.h>
-#include <NvBlastExtAuthoringCollisionBuilder.h>
+
+namespace physx
+{
+class PxPlane;
+class PxCooking;
+class PxPhysicsInsertionCallback;
+}
+
struct NvBlastBondDesc;
struct NvBlastChunkDesc;
struct NvBlastBond;
-using namespace physx;
-
-
namespace Nv
{
namespace Blast
{
// Forward declarations
+class FractureTool;
class TriangleProcessor;
struct PlaneChunkIndexer;
@@ -61,73 +80,75 @@ struct PlaneChunkIndexer
class BlastBondGenerator
{
public:
-
- BlastBondGenerator(physx::PxCooking* cooking, physx::PxPhysicsInsertionCallback* insertionCallback) : mPxCooking(cooking), mPxInsertionCallback(insertionCallback){};
+ virtual ~BlastBondGenerator() {}
+
+ /**
+ Release BlastBondGenerator memory
+ */
+ virtual void release() = 0;
/**
This method based on marking triangles during fracture process, so can be used only with internally fractured meshes.
- \param[in] tool FractureTool which contains chunks representation, tool->finalizeFracturing() should be called before.
- \param[in] chunkIsSupport Array of flags, if true - chunk is support. Array size should be equal to chunk count in tool.
- \param[out] resultBondDescs Array of created bond descriptors.
- \param[out] resultChunkDescriptors Array of created chunk descriptors.
- \return 0 if success
+ \note User should call NVBLAST_FREE for resultBondDescs when it not needed anymore
+ \param[in] tool FractureTool which contains chunks representation, tool->finalizeFracturing() should be called before.
+ \param[in] chunkIsSupport Pointer to array of flags, if true - chunk is support. Array size should be equal to chunk count in tool.
+ \param[out] resultBondDescs Pointer to array of created bond descriptors.
+ \param[out] resultChunkDescriptors Pointer to array of created chunk descriptors.
+ \return Number of created bonds
*/
- int32_t buildDescFromInternalFracture(FractureTool* tool, const std::vector<bool>& chunkIsSupport, std::vector<NvBlastBondDesc>& resultBondDescs, std::vector<NvBlastChunkDesc>& resultChunkDescriptors);
+ virtual int32_t buildDescFromInternalFracture(FractureTool* tool, const bool* chunkIsSupport,
+ NvBlastBondDesc*& resultBondDescs, NvBlastChunkDesc*& resultChunkDescriptors) = 0;
/**
Creates bond description between two meshes
- \param[in] meshA Array of triangles of mesh A.
- \param[in] meshB Array of triangles of mesh B.
- \param[out] resultBond Result bond description.
- \param[in] conf Bond creation mode.
- \return 0 if success
+ \param[in] meshACount Number of triangles in mesh A
+ \param[in] meshA Pointer to array of triangles of mesh A.
+ \param[in] meshBCount Number of triangles in mesh B
+ \param[in] meshB Pointer to array of triangles of mesh B.
+ \param[out] resultBond Result bond description.
+ \param[in] conf Bond creation mode.
+ \return 0 if success
*/
- int32_t createBondBetweenMeshes(const std::vector<Triangle>& meshA, const std::vector<Triangle>& meshB, NvBlastBond& resultBond, BondGenerationConfig conf = BondGenerationConfig());
+ virtual int32_t createBondBetweenMeshes(uint32_t meshACount, const Triangle* meshA, uint32_t meshBCount, const Triangle* meshB,
+ NvBlastBond& resultBond, BondGenerationConfig conf = BondGenerationConfig()) = 0;
/**
Creates bond description between number of meshes
- \param[in] geometry Array of arrays of triangles for each chunk.
- \param[out] resultBond Array of result bonds.
- \param[in] overlaps Array of pairs - indexes of chunks, for which bond should be created.
- \param[in] cfg Bond creation mode.
- \return 0 if success
+ \note User should call NVBLAST_FREE for resultBondDescs when it not needed anymore
+ \param[in] meshCount Number of meshes
+ \param[in] geometryOffset Pointer to array of triangle offsets for each mesh.
+ Containts meshCount + 1 element, last one is total number of triangles in geometry
+ \param[in] geometry Pointer to array of triangles.
+ Triangles from geometryOffset[i] to geometryOffset[i+1] correspond to i-th mesh.
+ \param[in] overlapsCount Number of overlaps
+ \param[in] overlaps Pointer to array of pairs - indexes of chunks, for which bond should be created.
+ \param[out] resultBond Pointer to array of result bonds.
+ \param[in] cfg Bond creation mode.
+ \return Number of created bonds
*/
- int32_t createBondBetweenMeshes(const std::vector<std::vector<Triangle> >& geometry, std::vector<NvBlastBondDesc>& resultBond, const std::vector<std::pair<uint32_t, uint32_t> >& overlaps, BondGenerationConfig cfg);
+ virtual int32_t createBondBetweenMeshes(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ uint32_t overlapsCount, const uint32_t* overlapsA, const uint32_t* overlapsB,
+ NvBlastBondDesc*& resultBond, BondGenerationConfig cfg) = 0;
/**
Creates bond description for prefractured meshes, when there is no info about which chunks should be connected with bond.
- \param[in] geometry Array of arrays of triangles for each chunk.
- \param[in] chunkIsSupport Array of flags, if true - chunk is support. Array size should be equal to chunk count in tool.
- \param[out] resultBondDescs Array of result bonds.
- \param[in] conf Bond creation mode.
- \return 0 if success
+ \note User should call NVBLAST_FREE for resultBondDescs when it not needed anymore
+ \param[in] meshCount Number of meshes
+ \param[in] geometryOffset Pointer to array of triangle offsets for each mesh.
+ Containts meshCount + 1 element, last one is total number of triangles in geometry
+ \param[in] geometry Pointer to array of triangles.
+ Triangles from geometryOffset[i] to geometryOffset[i+1] correspond to i-th mesh.
+ \param[in] chunkIsSupport Pointer to array of flags, if true - chunk is support. Array size should be equal to chunk count in tool.
+ \param[out] resultBondDescs Pointer to array of result bonds.
+ \param[in] conf Bond creation mode.
+ \return Number of created bonds
*/
- int32_t bondsFromPrefractured(const std::vector<std::vector<Triangle>>& geometry, const std::vector<bool>& chunkIsSupport, std::vector<NvBlastBondDesc>& resultBondDescs, BondGenerationConfig conf = BondGenerationConfig());
+ virtual int32_t bondsFromPrefractured(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool*& chunkIsSupport, NvBlastBondDesc*& resultBondDescs,
+ BondGenerationConfig conf = BondGenerationConfig()) = 0;
-private:
- float processWithMidplanes(TriangleProcessor* trProcessor, const std::vector<physx::PxVec3>& chunk1Points, const std::vector<physx::PxVec3>& chunk2Points,
- const std::vector<physx::PxVec3>& hull1p,const std::vector<physx::PxVec3>& hull2p, physx::PxVec3& normal, physx::PxVec3& centroid);
-
- int32_t createFullBondListAveraged(const std::vector<std::vector<Triangle>>& chunksGeometry, const std::vector<bool>& supportFlags, std::vector<NvBlastBondDesc>& mResultBondDescs, BondGenerationConfig conf);
- int32_t createFullBondListExact(const std::vector<std::vector<Triangle>>& chunksGeometry, const std::vector<bool>& supportFlags, std::vector<NvBlastBondDesc>& mResultBondDescs, BondGenerationConfig conf);
- int32_t createFullBondListExactInternal(const std::vector<std::vector<Triangle>>& chunksGeometry, std::vector < PlaneChunkIndexer >& planeTriangleMapping , std::vector<NvBlastBondDesc>& mResultBondDescs);
- int32_t createBondForcedInternal(const std::vector<PxVec3>& hull0, const std::vector<PxVec3>& hull1,const CollisionHull& cHull0, const CollisionHull& cHull1,PxBounds3 bound0, PxBounds3 bound1, NvBlastBond& resultBond, float overlapping);
-
- void buildGeometryCache(const std::vector<std::vector<Triangle> >& geometry);
- void resetGeometryCache();
-
- physx::PxCooking* mPxCooking;
- physx::PxPhysicsInsertionCallback* mPxInsertionCallback;
-
-
- std::vector<std::vector<Triangle> > mGeometryCache;
-
- std::vector<PlaneChunkIndexer> mPlaneCache;
- std::vector<CollisionHull> mCHullCache;
- std::vector<std::vector<physx::PxVec3> > mHullsPointsCache;
- std::vector<physx::PxBounds3 > mBoundsCache;
};
} // namespace Blast
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringCollisionBuilder.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringCollisionBuilder.h
index b3e143a..1e851bb 100644
--- a/sdk/extensions/authoring/include/NvBlastExtAuthoringCollisionBuilder.h
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringCollisionBuilder.h
@@ -1,26 +1,42 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGCOLLISIONBUILDER_H
#define NVBLASTEXTAUTHORINGCOLLISIONBUILDER_H
#include "NvBlastTypes.h"
-#include <vector>
-#include <PxVec3.h>
namespace physx
{
- class PxCooking;
- class PxPhysicsInsertionCallback;
- class PxVec3;
- class PxConvexMesh;
+class PxCooking;
+class PxPhysicsInsertionCallback;
+class PxVec3;
+class PxConvexMesh;
}
@@ -29,32 +45,7 @@ namespace Nv
namespace Blast
{
-/**
- Collision hull geometry format.
-*/
-struct CollisionHull
-{
- /**
- Collision hull polygon format.
- */
- struct HullPolygon
- {
- // Polygon base plane
- float mPlane[4];
- // Number vertices in polygon
- uint16_t mNbVerts;
- // First index in CollisionHull.indices array for this polygon
- uint16_t mIndexBase;
- };
- ///**
-
- CollisionHull(){};
-
- std::vector<physx::PxVec3> points;
- std::vector<uint32_t> indices;
- std::vector<HullPolygon> polygonData;
-};
-
+struct CollisionHull;
/**
ConvexMeshBuilder provides routine to build collision hulls from array of vertices.
@@ -64,35 +55,38 @@ struct CollisionHull
class ConvexMeshBuilder
{
public:
+ virtual ~ConvexMeshBuilder() {}
/**
- Constructor should be provided with PxCoocking and PxPhysicsInsertionCallback objects.
+ Release ConvexMeshBuilder memory
*/
- ConvexMeshBuilder(physx::PxCooking* cooking, physx::PxPhysicsInsertionCallback* insertionCallback) : mInsertionCallback(insertionCallback), mCooking(cooking) {}
+ virtual void release() = 0;
/**
Method creates CollisionHull from provided array of vertices.
+ \param[in] verticesCount Number of vertices
\param[in] vertexData Vertex array of some object, for which collision geometry should be built
\param[out] output Reference on CollisionHull object in which generated geometry should be saved
*/
- void buildCollisionGeometry(const std::vector<physx::PxVec3>& vertexData, CollisionHull& output);
+ virtual CollisionHull* buildCollisionGeometry(uint32_t verticesCount, const physx::PxVec3* vertexData) = 0;
/**
Method creates PxConvexMesh from provided array of vertices.
- \param[in] vertexData Vertex array of some object, for which collision geometry should be built
+ \param[in] verticesCount Number of vertices
+ \param[in] vertexData Vertex array of some object, for which collision geometry should be built
\return pointer to the PxConvexMesh object if it was built successfully, 'nullptr' otherwise.
*/
- physx::PxConvexMesh* buildConvexMesh(std::vector<physx::PxVec3>& vertexData);
+ virtual physx::PxConvexMesh* buildConvexMesh(uint32_t verticesCount, const physx::PxVec3* vertexData) = 0;
/**
Method creates PxConvexMesh from provided ConvexHull geometry
- \param[in] hull ConvexHull geometry
+ \param[in] hull ConvexHull geometry
\return pointer to the PxConvexMesh object if it was built successfully, 'nullptr' otherwise.
*/
- physx::PxConvexMesh* buildConvexMesh(CollisionHull& hull);
+ virtual physx::PxConvexMesh* buildConvexMesh(const CollisionHull& hull) = 0;
/**
@@ -102,18 +96,13 @@ public:
This method trims all intersecting parts of collision geometry.
As a drawback, trimming collision geometry can lead to penetrating render meshes during simulation.
-
- \param[in] in ConvexHull geometry which should be clipped.
- \param[in] chunkDepth Array of depth levels of convex hulls corresponding chunks.
+ \param[in] chunksCount Number of chunks
+ \param[in,out] in ConvexHull geometry which should be clipped.
+ \param[in] chunkDepth Array of depth levels of convex hulls corresponding chunks.
*/
-
- void trimCollisionGeometry(std::vector<CollisionHull>& in, const std::vector<uint32_t>& chunkDepth);
-
+ virtual void trimCollisionGeometry(uint32_t chunksCount, CollisionHull** in, const uint32_t* chunkDepth) = 0;
-private:
- physx::PxPhysicsInsertionCallback* mInsertionCallback;
- physx::PxCooking* mCooking;
};
} // namespace Blast
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringFractureTool.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringFractureTool.h
index 528ffbc..82959ac 100644
--- a/sdk/extensions/authoring/include/NvBlastExtAuthoringFractureTool.h
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringFractureTool.h
@@ -1,19 +1,35 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTAUTHORINGFRACTURETOOL_H
#define NVBLASTAUTHORINGFRACTURETOOL_H
-#include "NvBlastExtAuthoringMesh.h"
-#include "NvBlastTypes.h"
-
+#include "NvBlastExtAuthoringTypes.h"
namespace Nv
{
@@ -21,8 +37,8 @@ namespace Blast
{
class SpatialAccelerator;
-class ChunkPostProcessor;
-
+class Triangulator;
+class Mesh;
/*
Chunk data, chunk with chunkId == 0 is always source mesh.
@@ -38,119 +54,83 @@ struct ChunkInfo
/*
Slicing fracturing configuration
-
-
- default:
- x_slices = 1;
- y_slices = 1;
- z_slices = 1;
-
- offset_variations = 0.f;
- angle_variations = 0.f;
- noiseAmplitude = 0.f;
- noiseFrequency = 1.f;
- noiseOctaveNumber = 1;
- surfaceResolution = 1;
*/
struct SlicingConfiguration
{
/**
Number of slices in each direction
*/
- int32_t x_slices, y_slices, z_slices;
+ int32_t x_slices = 1, y_slices = 1, z_slices = 1;
/**
Offset variation, value in [0, 1]
*/
- float offset_variations;
+ float offset_variations = 0.f;
+
/**
Angle variation, value in [0, 1]
*/
- float angle_variations;
-
+ float angle_variations = 0.f;
/**
Noisy slicing configutaion:
Amplitude of cutting surface noise. If it is 0 - noise is disabled.
*/
- float noiseAmplitude;
+ float noiseAmplitude = 0.f;
+
/**
Frequencey of cutting surface noise.
*/
- float noiseFrequency;
+ float noiseFrequency = 1.f;
+
/**
Octave number in slicing surface noise.
*/
- uint32_t noiseOctaveNumber;
- /**
- Cutting surface resolution.
- */
- int32_t surfaceResolution;
-
+ uint32_t noiseOctaveNumber = 1;
- SlicingConfiguration()
- {
- reset();
- }
/**
- Set default params.
+ Cutting surface resolution.
*/
- void reset()
- {
- x_slices = 1;
- y_slices = 1;
- z_slices = 1;
-
- offset_variations = 0.f;
- angle_variations = 0.f;
- noiseAmplitude = 0.f;
- noiseFrequency = 1.f;
- noiseOctaveNumber = 1;
- surfaceResolution = 1;
- }
-
+ int32_t surfaceResolution = 1;
};
-
/**
Class for voronoi sites generation inside supplied mesh.
*/
class VoronoiSitesGenerator
{
public:
-
- /**
- Voronoi sites should not be generated outside of the fractured mesh, so VoronoiSitesGenerator
- should be supplied with fracture mesh.
- \param[in] mesh Fracture mesh
- \param[in] rnd User supplied random value generator.
- \return
+ virtual ~VoronoiSitesGenerator() {}
+
+ /**
+ Release VoronoiSitesGenerator memory
*/
- VoronoiSitesGenerator(Mesh* mesh, RandomGeneratorBase* rnd);
- ~VoronoiSitesGenerator();
+ virtual void release() = 0;
/**
Set base fracture mesh
*/
- void setBaseMesh(Mesh* m);
+ virtual void setBaseMesh(const Mesh* mesh) = 0;
/**
- Returns reference on vector of generated voronoi sites.
+ Access to generated voronoi sites.
+ \param[out] Pointer to generated voronoi sites
+ \return Count of generated voronoi sites.
*/
- std::vector<physx::PxVec3>& getVoronoiSites();
+ virtual uint32_t getVoronoiSites(const physx::PxVec3*& sites) = 0;
/**
Add site in particular point
\param[in] site Site coordinates
*/
- void addSite(const physx::PxVec3& site);
+ virtual void addSite(const physx::PxVec3& site) = 0;
/**
Uniformly generate sites inside the mesh
\param[in] numberOfSites Number of generated sites
*/
- void uniformlyGenerateSitesInMesh(const uint32_t numberOfSites);
+ virtual void uniformlyGenerateSitesInMesh(uint32_t numberOfSites) = 0;
/**
Generate sites in clustered fashion
@@ -158,7 +138,7 @@ public:
\param[in] sitesPerCluster Number of sites in each cluster
\param[in] clusterRadius Voronoi cells cluster radius
*/
- void clusteredSitesGeneration(const uint32_t numberOfClusters, const uint32_t sitesPerCluster, float clusterRadius);
+ virtual void clusteredSitesGeneration(uint32_t numberOfClusters, uint32_t sitesPerCluster, float clusterRadius) = 0;
/**
Radial pattern of sites generation
@@ -170,7 +150,7 @@ public:
\param[in] angleOffset Angle offset at each radial step
\param[in] variability Randomness of sites distribution
*/
- void radialPattern(const physx::PxVec3& center, const physx::PxVec3& normal, float radius, int32_t angularSteps, int32_t radialSteps, float angleOffset = 0.0f, float variability = 0.0f);
+ virtual void radialPattern(const physx::PxVec3& center, const physx::PxVec3& normal, float radius, int32_t angularSteps, int32_t radialSteps, float angleOffset = 0.0f, float variability = 0.0f) = 0;
/**
Generate sites inside sphere
@@ -178,16 +158,16 @@ public:
\param[in] radius Radius of sphere
\param[in] center Center of sphere
*/
- void generateInSphere(const uint32_t count, const float radius, const physx::PxVec3& center);
+ virtual void generateInSphere(const uint32_t count, const float radius, const physx::PxVec3& center) = 0;
/**
Set stencil mesh. With stencil mesh sites are generated only inside both of fracture and stencil meshes.
\param[in] stencil Stencil mesh.
*/
- void setStencil(Mesh* stencil);
+ virtual void setStencil(const Mesh* stencil) = 0;
/**
Removes stencil mesh
*/
- void clearStencil();
+ virtual void clearStencil() = 0;
/**
Deletes sites inside supplied sphere
@@ -195,18 +175,9 @@ public:
\param[in] center Center of sphere
\param[in] eraserProbability Probability of removing some particular site
*/
- void deleteInSphere(const float radius, const physx::PxVec3& center, const float eraserProbability = 1);
-
-private:
- std::vector<physx::PxVec3> mGeneratedSites;
- Mesh* mMesh;
- Mesh* mStencil;
- RandomGeneratorBase* mRnd;
- SpatialAccelerator* mAccelerator;
+ virtual void deleteInSphere(const float radius, const physx::PxVec3& center, const float eraserProbability = 1) = 0;
};
-
-
/**
FractureTool class provides methods to fracture provided mesh and generate Blast asset data
*/
@@ -214,44 +185,34 @@ class FractureTool
{
public:
+ virtual ~FractureTool() {}
/**
- FractureTool can log asset creation info if logCallback is provided.
+ Release FractureTool memory
*/
- FractureTool(NvBlastLog logCallback = nullptr)
- {
- mPlaneIndexerOffset = 1;
- mChunkIdCounter = 0;
- mRemoveIslands = false;
- mLoggingCallback = logCallback;
- }
-
- ~FractureTool()
- {
- reset();
- }
+ virtual void release() = 0;
/**
Reset FractureTool state.
*/
- void reset();
+ virtual void reset() = 0;
/**
Set input mesh wich will be fractured, FractureTool will be reseted.
*/
- void setSourceMesh(Mesh* mesh);
+ virtual void setSourceMesh(const Mesh* mesh) = 0;
/**
- Get chunk mesh in polygonal representation
+ Get chunk mesh in polygonal representation. User's code should release it after usage.
*/
- Mesh getChunkMesh(int32_t chunkId);
+ virtual Mesh* createChunkMesh(int32_t chunkId) = 0;
/**
Input mesh is scaled and transformed internally to fit unit cube centered in origin.
Method provides offset vector and scale parameter;
*/
- void getTransformation(physx::PxVec3& offset, float& scale);
+ virtual void getTransformation(physx::PxVec3& offset, float& scale) = 0;
/**
@@ -262,7 +223,7 @@ public:
Case replaceChunk == true && chunkId == 0 considered as wrong input parameters
\return If 0, fracturing is successful.
*/
- int32_t voronoiFracturing(uint32_t chunkId, const std::vector<physx::PxVec3>& cellPoints, bool replaceChunk);
+ virtual int32_t voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPoints, bool replaceChunk) = 0;
/**
Fractures specified chunk with voronoi method. Cells can be scaled along x,y,z axes.
@@ -274,7 +235,7 @@ public:
Case replaceChunk == true && chunkId == 0 considered as wrong input parameters
\return If 0, fracturing is successful.
*/
- int32_t voronoiFracturing(uint32_t chunkId, const std::vector<physx::PxVec3>& cellPoints, const physx::PxVec3& scale, bool replaceChunk);
+ virtual int32_t voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPoints, const physx::PxVec3& scale, bool replaceChunk) = 0;
/**
@@ -287,37 +248,20 @@ public:
\return If 0, fracturing is successful.
*/
- int32_t slicing(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd);
+ virtual int32_t slicing(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd) = 0;
/**
Creates resulting fractured mesh geometry from intermediate format
*/
- void finalizeFracturing();
+ virtual void finalizeFracturing() = 0;
- /**
- Get chunk information
- */
- const std::vector<ChunkInfo>& getChunkList();
-
+ virtual uint32_t getChunkCount() const = 0;
/**
- Tesselate interior surfaces
- \param[in] averageEdgeLength - Average length of edge on internal surface.
- */
- void tesselate(float averageEdgeLength);
-
- /**
- Apply noise to interior surfaces. Must be called only after tesselation!
- \param[in] amplitude Amplitude of noise
- \param[in] frequency Frequency of noise
- \param[in] octaves Number of noise octaves
- \param[in] falloff - damping of noise around of external surface
- \param[in] relaxIterations - number of smoothing iterations before applying noise
- \param[in] relaxFactor - amount of smoothing before applying noise.
- \param[in] seed Random seed value
+ Get chunk information
*/
- void applyNoise(float amplitude, float frequency, int32_t octaves, float falloff, int32_t relaxIterations, float relaxFactor, int32_t seed = 0);
+ virtual const ChunkInfo& getChunkInfo(int32_t chunkIndex) = 0;
/**
Get percentage of mesh overlap.
@@ -326,110 +270,78 @@ public:
\param[in] meshB Mesh B
\return mesh overlap percentage
*/
- static float getMeshOverlap(Mesh& meshA, Mesh& meshB);
+ virtual float getMeshOverlap(const Mesh& meshA, const Mesh& meshB) = 0;
/**
Get chunk base mesh
\param[in] chunkIndex Chunk index
\param[out] output Array of triangles to be filled
+ \return number of triangles in base mesh
*/
- void getBaseMesh(int32_t chunkIndex, std::vector<Triangle>& output);
-
- /**
- Get chunk mesh with noise
- \param[in] chunkIndex Chunk index
- \param[out] output Array of triangles to be filled
- */
- void getNoisedMesh(int32_t chunkIndex, std::vector<Triangle>& output);
-
+ virtual uint32_t getBaseMesh(int32_t chunkIndex, Triangle*& output) = 0;
/**
Return index of chunk with specified chunkId
\param[in] chunkId Chunk ID
\return Chunk index in internal buffer, if not exist -1 is returned.
*/
- int32_t getChunkIndex(int32_t chunkId);
+ virtual int32_t getChunkIndex(int32_t chunkId) = 0;
/**
Return id of chunk with specified index.
\param[in] chunkIndex Chunk index
\return Chunk id or -1 if there is no such chunk.
*/
- int32_t getChunkId(int32_t chunkIndex);
+ virtual int32_t getChunkId(int32_t chunkIndex) = 0;
/**
Return depth level of the given chunk
\param[in] chunkId Chunk ID
\return Chunk depth or -1 if there is no such chunk.
*/
- int32_t getChunkDepth(int32_t chunkId);
+ virtual int32_t getChunkDepth(int32_t chunkId) = 0;
/**
Return array of chunks IDs with given depth.
- \param[in] depth Chunk depth
- \return Array of chunk IDs
+ \param[in] depth Chunk depth
+ \param[out] Pointer to array of chunk IDs
+ \return Number of chunks in array
*/
- std::vector<int32_t> getChunksIdAtDepth(uint32_t depth);
+ virtual uint32_t getChunksIdAtDepth(uint32_t depth, int32_t*& chunkIds) = 0;
/**
Get result geometry without noise as vertex and index buffers, where index buffers contain series of triplets
which represent triangles.
\param[out] vertexBuffer Array of vertices to be filled
- \param[out] indexBuffer Array of arrays of indices to be filled
+ \param[out] indexBuffer Array of indices to be filled
+ \param[out] indexBufferOffsets Array of offsets in indexBuffer for each base mesh.
+ Contains getChunkCount() + 1 elements. Last one is indexBuffer size
+ \return Number of vertices in vertexBuffer
*/
- void getBufferedBaseMeshes(std::vector<Vertex>& vertexBuffer, std::vector<std::vector<uint32_t> >& indexBuffer);
-
- /**
- Get result geometry after tesselation and application of noise as vertex and index buffers, where index buffers contain series of triplets
- which represent triangles.
- \param[out] vertexBuffer Array of vertices to be filled
- \param[out] indexBuffer Array of arrays of indices to be filled
- */
- void getBufferedNoiseMeshes(std::vector<Vertex>& vertexBuffer, std::vector<std::vector<uint32_t> >& indexBuffer);
+ virtual uint32_t getBufferedBaseMeshes(Vertex*& vertexBuffer, uint32_t*& indexBuffer, uint32_t*& indexBufferOffsets) = 0;
/**
Set automatic islands removing. May cause instabilities.
\param[in] isRemoveIslands Flag whether remove or not islands.
*/
- void setRemoveIslands(bool isRemoveIslands);
+ virtual void setRemoveIslands(bool isRemoveIslands) = 0;
/**
Try find islands and remove them on some specifical chunk. If chunk has childs, island removing can lead to wrong results! Apply it before further chunk splitting.
\param[in] chunkId Chunk ID which should be checked for islands
\return Number of found islands is returned
*/
- int32_t islandDetectionAndRemoving(int32_t chunkId);
-
-private:
- void eraseChunk(int32_t chunkId);
- bool isAncestorForChunk(int32_t ancestorId, int32_t chunkId);
- void deleteAllChildsOfChunk(int32_t chunkId);
- int32_t slicingNoisy(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd);
+ virtual int32_t islandDetectionAndRemoving(int32_t chunkId) = 0;
-protected:
/**
- Mesh scaled to unite-cube and translated to the origin
+ Check if input mesh contains open edges. Open edges can lead to wrong fracturing results.
+ \return true if mesh contains open edges
*/
- float mScaleFactor;
- physx::PxVec3 mOffset;
-
- /* Chunk mesh wrappers */
- std::vector<ChunkPostProcessor*> mChunkPostprocessors;
-
-
-
- int32_t mPlaneIndexerOffset;
- int32_t mChunkIdCounter;
- std::vector<ChunkInfo> mChunkData;
-
- bool mRemoveIslands;
-
- NvBlastLog mLoggingCallback;
+ virtual bool isMeshContainOpenEdges(const Mesh* input) = 0;
};
} // namespace Blast
} // namespace Nv
-
#endif // ifndef NVBLASTAUTHORINGFRACTURETOOL_H
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringMesh.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringMesh.h
index 2b1806a..039da52 100644
--- a/sdk/extensions/authoring/include/NvBlastExtAuthoringMesh.h
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringMesh.h
@@ -1,19 +1,35 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTAUTHORINGMESH_H
#define NVBLASTAUTHORINGMESH_H
#include "NvBlastExtAuthoringTypes.h"
-#include <vector>
-
namespace Nv
{
@@ -26,147 +42,106 @@ namespace Blast
class Mesh
{
public:
+ virtual ~Mesh() {}
/**
- Constructs mesh object from array of triangles.
- \param[in] position Array of vertex positions
- \param[in] normals Array of vertex normals
- \param[in] uv Array of vertex uv coordinates
- \param[in] verticesCount Vertices count
- \param[in] indices Array of vertex indices. Indices contain vertex index triplets which form a mesh triangle.
- \param[in] indicesCount Indices count (should be equal to numberOfTriangles * 3)
+ Release Mesh memory
*/
- Mesh(physx::PxVec3* position, physx::PxVec3* normals, physx::PxVec2* uv, uint32_t verticesCount, uint32_t* indices, uint32_t indicesCount);
+ virtual void release() = 0;
/**
- Constructs mesh object from array of facets.
- \param[in] vertices Array of vertices
- \param[in] edges Array of edges
- \param[in] facets Array of facets
- \param[in] posCount Vertices count
- \param[in] edgesCount Edges count
- \param[in] facetsCount Facets count
+ Return true if mesh is valid
*/
- Mesh(Vertex* vertices, Edge* edges, Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount);
+ virtual bool isValid() const = 0;
- ~Mesh();
+ /**
+ Return writable pointer on vertices array
+ */
+ virtual Vertex* getVerticesWritable() = 0;
/**
- Return true if mesh is valid
+ Return pointer on vertices array
+ */
+ virtual const Vertex* getVertices() const = 0;
+
+
+ /**
+ Return writable pointer on edges array
*/
- bool isValid();
+ virtual Edge* getEdgesWritable() = 0;
/**
- Return pointer on vertices array
+ Return pointer on edges array
*/
- Vertex* getVertices();
+ virtual const Edge* getEdges() const = 0;
/**
- Return pointer on edges array
+ Return writable pointer on facets array
*/
- Edge* getEdges();
+ virtual Facet* getFacetsBufferWritable() = 0;
/**
- Return pointer on facets array
+ Return pointer on facets array
*/
- Facet* getFacetsBuffer();
+ virtual const Facet* getFacetsBuffer() const = 0;
/**
+ Return writable pointer on specified facet
+ */
+ virtual Facet* getFacetWritable(int32_t facet) = 0;
+ /**
Return pointer on specified facet
*/
- Facet* getFacet(int32_t facet);
+ virtual const Facet* getFacet(int32_t facet) const = 0;
/**
Return edges count
*/
- uint32_t getEdgesCount();
+ virtual uint32_t getEdgesCount() const = 0;
/**
Return vertices count
*/
- uint32_t getVerticesCount();
+ virtual uint32_t getVerticesCount() const = 0;
/**
Return facet count
*/
- uint32_t getFacetCount();
+ virtual uint32_t getFacetCount() const = 0;
/**
Return reference on mesh bounding box.
*/
- physx::PxBounds3& getBoundingBox();
+ virtual const physx::PxBounds3& getBoundingBox() const = 0;
+
+ /**
+ Return writable reference on mesh bounding box.
+ */
+ virtual physx::PxBounds3& getBoundingBoxWritable() = 0;
+
+
+ /**
+ Set per-facet material id.
+ */
+ virtual void setMaterialId(int32_t* materialIds) = 0;
+
+ /**
+ Set per-facet smoothing group.
+ */
+ virtual void setSmoothingGroup(int32_t* smoothingGroup) = 0;
/**
Recalculate bounding box
*/
- void recalculateBoundingBox();
+ virtual void recalculateBoundingBox() = 0;
/**
Compute mesh volume. Can be used only for triangulated meshes.
Return mesh volume. If mesh is not triangulated return 0.
*/
- float getMeshVolume();
-
-private:
- std::vector<Vertex> mVertices;
- std::vector<Edge> mEdges;
- std::vector<Facet> mFacets;
- physx::PxBounds3 mBounds;
+ virtual float getMeshVolume() = 0;
};
-
-/**
- Helper functions
-*/
-
-/**
- Set cutting box at some particular position.
- \param[in] point Cutting face center
- \param[in] normal Cutting face normal
- \param[in] mesh Cutting box mesh
- \param[in] size Cutting box size
- \param[in] id Cutting box ID
-*/
-void setCuttingBox(const physx::PxVec3& point, const physx::PxVec3& normal, Mesh* mesh, float size, int32_t id);
-/**
- Create cutting box at some particular position.
- \param[in] point Cutting face center
- \param[in] normal Cutting face normal
- \param[in] size Cutting box size
- \param[in] id Cutting box ID
-*/
-Mesh* getCuttingBox(const physx::PxVec3& point, const physx::PxVec3& normal, float size, int32_t id);
-
-/**
- Create box at some particular position.
- \param[in] point Cutting face center
- \param[in] size Cutting box size
-*/
-Mesh* getBigBox(const physx::PxVec3& point, float size);
-
-/**
- Create slicing box with noisy cutting surface.
- \param[in] point Cutting face center
- \param[in] normal Cutting face normal
- \param[in] size Cutting box size
- \param[in] jaggedPlaneSize Noisy surface size
- \param[in] resolution Noisy surface resolution
- \param[in] id Cutting box ID
- \param[in] amplitude Noise amplitude
- \param[in] frequency Noise frequency
- \param[in] octaves Noise octaves
- \param[in] seed Random generator seed, used for noise generation.
-*/
-Mesh* getNoisyCuttingBoxPair(const physx::PxVec3& point, const physx::PxVec3& normal, float size, float jaggedPlaneSize, uint32_t resolution, int32_t id, float amplitude, float frequency, int32_t octaves, int32_t seed);
-
-
-/**
- Inverses normals of cutting box and sets indices.
- \param[in] mesh Cutting box mesh
- \param[in] id Cutting box ID
-*/
-void inverseNormalAndSetIndices(Mesh* mesh, int32_t id);
-
} // namespace Blast
} // namespace Nv
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringMeshCleaner.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringMeshCleaner.h
new file mode 100644
index 0000000..b352e80
--- /dev/null
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringMeshCleaner.h
@@ -0,0 +1,71 @@
+// 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-2017 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTAUTHORINGMESHCLEANER_H
+#define NVBLASTEXTAUTHORINGMESHCLEANER_H
+
+#include "NvBlastExtAuthoringTypes.h"
+
+/**
+ FractureTool has requirements to input meshes to fracture them successfully:
+ 1) Mesh should be closed (watertight)
+ 2) There should not be self-intersections and open-edges.
+*/
+
+/**
+ Mesh cleaner input is closed mesh with self-intersections and open-edges (only in the interior).
+ It tries to track outer hull to make input mesh solid and meet requierements of FractureTool. If mesh contained some internal cavities they will be removed.
+*/
+
+namespace Nv
+{
+namespace Blast
+{
+
+class Mesh;
+
+class MeshCleaner
+{
+public:
+ virtual ~MeshCleaner() {}
+
+ /**
+ Tries to remove self intersections and open edges in interior of mesh.
+ \param[in] mesh Mesh to be cleaned.
+ \return Cleaned mesh or nullptr if failed.
+ */
+ virtual Mesh* cleanMesh(const Mesh* mesh) = 0;
+
+ virtual void release() = 0;
+};
+
+
+} // namespace Blast
+} // namespace Nv
+
+#endif // ifndef NVBLASTEXTAUTHORINGMESHCLEANER_H \ No newline at end of file
diff --git a/sdk/extensions/authoring/include/NvBlastExtAuthoringTypes.h b/sdk/extensions/authoring/include/NvBlastExtAuthoringTypes.h
index de28866..13865f7 100644
--- a/sdk/extensions/authoring/include/NvBlastExtAuthoringTypes.h
+++ b/sdk/extensions/authoring/include/NvBlastExtAuthoringTypes.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTAUTHORINGTYPES_H
#define NVBLASTAUTHORINGTYPES_H
@@ -14,7 +32,6 @@
#include <PxVec3.h>
#include <PxVec2.h>
#include <PxBounds3.h>
-#include <algorithm>
#include "NvBlastTypes.h"
#define NOT_VALID_VERTEX INT32_MAX
@@ -51,6 +68,13 @@ struct Vertex
physx::PxVec2 uv[1]; // UV-coordinates array, currently supported only one UV coordinate.
};
+
+// Interior material ID
+#define MATERIAL_INTERIOR 1000
+#define SMOOTHING_GROUP_INTERIOR 1000
+
+
+
/**
Mesh triangle representation
*/
@@ -59,7 +83,9 @@ struct Triangle
Triangle() {};
Triangle(Vertex a, Vertex b, Vertex c) : a(a), b(b), c(c) {};
Vertex a, b, c;
- int32_t userInfo;
+ int32_t userData;
+ int32_t materialId;
+ int32_t smoothingGroup; // NOT SUPPORTED ATM.
physx::PxVec3 getNormal()
{
return ((b.p - a.p).cross(c.p - a.p));
@@ -91,10 +117,28 @@ struct TriangleIndexed
return (a == ea || a == eb || a == ec) && (b == ea || b == eb || b == ec);
}
+ Triangle convertToTriangle(Vertex* vertices)
+ {
+ Triangle tr;
+ tr.a = vertices[ea];
+ tr.b = vertices[eb];
+ tr.c = vertices[ec];
+
+ tr.userData = userData;
+ tr.materialId = materialId;
+ tr.smoothingGroup = smoothingGroup;
+ return tr;
+ }
+
uint32_t ea, eb, ec;
- int32_t userInfo;
+ int32_t materialId;
+ int32_t smoothingGroup;
+ int32_t userData;
};
+
+
+
/**
Mesh facet representation
*/
@@ -103,11 +147,14 @@ struct Facet
int32_t firstEdgeNumber;
uint32_t edgesCount;
int32_t userData;
- Facet(int32_t fEdge = 0, uint32_t eCount = 0, int32_t userData = 0) : firstEdgeNumber(fEdge), edgesCount(eCount), userData(userData) {}
+ int32_t materialId;
+ int32_t smoothingGroup;
+
+ Facet(int32_t fEdge = 0, uint32_t eCount = 0, int32_t materialId = 0, int32_t userData = 0, int32_t smoothingGroup = 0) : firstEdgeNumber(fEdge), edgesCount(eCount), materialId(materialId), userData(userData), smoothingGroup(smoothingGroup) {}
};
/**
-Abstract base class for user-defined random value generator.
+ Abstract base class for user-defined random value generator.
*/
class RandomGeneratorBase
{
@@ -119,6 +166,110 @@ public:
virtual ~RandomGeneratorBase() {};
};
+/**
+ Collision hull geometry format.
+*/
+struct CollisionHull
+{
+ /**
+ Collision hull polygon format.
+ */
+ struct HullPolygon
+ {
+ // Polygon base plane
+ float mPlane[4];
+ // Number vertices in polygon
+ uint16_t mNbVerts;
+ // First index in CollisionHull.indices array for this polygon
+ uint16_t mIndexBase;
+ };
+ ///**
+
+ uint32_t pointsCount;
+ uint32_t indicesCount;
+ uint32_t polygonDataCount;
+ physx::PxVec3* points;
+ uint32_t* indices;
+ HullPolygon* polygonData;
+
+ virtual ~CollisionHull() {}
+
+ virtual void release() = 0;
+};
+
+/**
+ Authoring results. Which contains NvBlastAsset, render and collision meshes
+*/
+struct AuthoringResult
+{
+ uint32_t chunkCount; //Number of chunks in Blast asset
+
+ uint32_t bondCount; //Number of bonds in Blast asset
+
+ NvBlastAsset* asset; //Blast asset
+
+ /**
+ assetToFractureChunkIdMap used for getting internal FractureChunkId with FractureTool::getChunkId.
+ FractureChunkId = FractureTool.getChunkId(aResult.assetToFractureChunkIdMap(AssetChunkId);
+ */
+ uint32_t* assetToFractureChunkIdMap;
+
+ /**
+ Offsets for render mesh geometry. Contains chunkCount + 1 element.
+ First triangle for i-th chunk: aResult.geometry[aResult.geometryOffset[i]]
+ aResult.geometryOffset[chunkCount+1] is total number of triangles in geometry
+ */
+ uint32_t* geometryOffset;
+
+ Triangle* geometry; //Raw array of Triangle for all chunks
+
+ NvBlastChunkDesc* chunkDescs; //Array of chunk descriptors. Contains chunkCount elements
+
+ NvBlastBondDesc* bondDescs; //Array of bond descriptors. Contains bondCount elements
+
+ /**
+ Collision hull offsets. Contains chunkCount + 1 element.
+ First collision hull for i-th chunk: aResult.collisionHull[aResult.collisionHullOffset[i]]
+ aResult.collisionHullOffset[chunkCount+1] is total number of collision hulls in collisionHull
+ */
+ uint32_t* collisionHullOffset;
+
+ CollisionHull** collisionHull; //Raw array of pointers to collision hull for all chunks.
+
+ /**
+ Array of chunk physics parameters. Contains chunkCount elements
+ */
+ struct ExtPxChunk* physicsChunks;
+
+ /**
+ Array of phisics subchunks (convex mesh) descriptors.
+ Use collisionHullOffset for accessing elements.
+ */
+ struct ExtPxSubchunk* physicsSubchunks;
+
+ /**
+ Array of material names.
+ */
+ char** materialNames;
+ /**
+ Size of array of material names.
+ */
+
+ uint32_t materialCount;
+
+ //// Member functions ////
+ virtual ~AuthoringResult() {}
+
+ /**
+ Free collision hulls data
+ */
+ virtual void releaseCollisionHulls() = 0;
+
+ /**
+ Free all data and AuthoringResult
+ */
+ virtual void release() = 0;
+};
} // namespace Blast
diff --git a/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.cpp b/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.cpp
index 73c59b8..7306b57 100644
--- a/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.cpp
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#include "NvBlastExtApexSharedParts.h"
@@ -906,14 +924,14 @@ static void _arrayVec3ToVec4(const PxVec3* src, const Vec3V& scale, Vec4V* dst,
}
-bool importerHullsInProximityApexFree(const std::vector<PxVec3>& hull0, PxBounds3& hull0Bounds, const physx::PxTransform& localToWorldRT0In, const physx::PxVec3& scale0In,
- const std::vector<PxVec3>& hull1, PxBounds3& hull1Bounds, const physx::PxTransform& localToWorldRT1In, const physx::PxVec3& scale1In,
+bool importerHullsInProximityApexFree(uint32_t hull0Count, const PxVec3* hull0, PxBounds3& hull0Bounds, const physx::PxTransform& localToWorldRT0In, const physx::PxVec3& scale0In,
+ uint32_t hull1Count, const PxVec3* hull1, PxBounds3& hull1Bounds, const physx::PxTransform& localToWorldRT1In, const physx::PxVec3& scale1In,
physx::PxF32 maxDistance, Separation* separation)
{
- const PxU32 numVerts0 = static_cast<PxU32>(hull0.size());
- const PxU32 numVerts1 = static_cast<PxU32>(hull1.size());
+ const PxU32 numVerts0 = static_cast<PxU32>(hull0Count);
+ const PxU32 numVerts1 = static_cast<PxU32>(hull1Count);
const PxU32 numAov0 = (numVerts0 + 3) >> 2;
const PxU32 numAov1 = (numVerts1 + 3) >> 2;
Vec4V* verts0 = (Vec4V*)alloca((numAov0 + numAov1) * sizeof(Vec4V) * 3);
@@ -936,8 +954,8 @@ bool importerHullsInProximityApexFree(const std::vector<PxVec3>& hull0, PxBounds
vert1[i] = hull1[i];
}
- _arrayVec3ToVec4(&vert0[0], scale0, verts0, numVerts0);
- _arrayVec3ToVec4(&vert1[0], scale1, verts1, numVerts1);
+ _arrayVec3ToVec4(vert0.data(), scale0, verts0, numVerts0);
+ _arrayVec3ToVec4(vert1.data(), scale1, verts1, numVerts1);
const PxTransform trans1To0 = localToWorldRT0In.transformInv(localToWorldRT1In);
diff --git a/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.h b/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.h
index 68e0412..5d1f990 100644
--- a/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.h
+++ b/sdk/extensions/authoring/source/NvBlastExtApexSharedParts.h
@@ -1,18 +1,35 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAPEXSHAREDPARTS_H
#define NVBLASTEXTAPEXSHAREDPARTS_H
#include "NvBlast.h"
-#include <vector>
#include <PxPlane.h>
namespace physx
{
@@ -40,9 +57,9 @@ struct Separation
/**
Function to compute midplane between two convex hulls. Is copied from APEX.
*/
-bool importerHullsInProximityApexFree(const std::vector<physx::PxVec3>& hull0, physx::PxBounds3& hull0Bounds, const physx::PxTransform& localToWorldRT0In, const physx::PxVec3& scale0In,
- const std::vector<physx::PxVec3>& hull1, physx::PxBounds3& hull1Bounds, const physx::PxTransform& localToWorldRT1In, const physx::PxVec3& scale1In,
- physx::PxF32 maxDistance, Separation* separation);
+bool importerHullsInProximityApexFree( uint32_t hull0Count, const physx::PxVec3* hull0, physx::PxBounds3& hull0Bounds, const physx::PxTransform& localToWorldRT0In, const physx::PxVec3& scale0In,
+ uint32_t hull1Count, const physx::PxVec3* hull1, physx::PxBounds3& hull1Bounds, const physx::PxTransform& localToWorldRT1In, const physx::PxVec3& scale1In,
+ physx::PxF32 maxDistance, Separation* separation);
} // namespace Blast
} // namespace Nv
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoring.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoring.cpp
new file mode 100644
index 0000000..95a7bee
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoring.cpp
@@ -0,0 +1,262 @@
+/*
+* 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.
+*/
+
+#include "NvBlastExtAuthoring.h"
+#include "NvBlastExtAuthoringMeshImpl.h"
+#include "NvBlastExtAuthoringMeshCleanerImpl.h"
+#include "NvBlastExtAuthoringFractureToolImpl.h"
+#include "NvBlastExtAuthoringCollisionBuilderImpl.h"
+#include "NvBlastExtAuthoringBondGeneratorImpl.h"
+#include "NvBlastTypes.h"
+#include "NvBlastIndexFns.h"
+#include "NvBlast.h"
+#include "NvBlastGlobals.h"
+#include "NvBlastExtPxAsset.h"
+
+#include <algorithm>
+#include <memory>
+
+using namespace Nv::Blast;
+using namespace physx;
+
+#define SAFE_ARRAY_NEW(T, x) ((x) > 0) ? new T[x] : nullptr;
+#define SAFE_ARRAY_DELETE(x) if (x != nullptr) {delete[] x; x = nullptr;}
+
+Mesh* NvBlastExtAuthoringCreateMesh(const PxVec3* position, const PxVec3* normals, const PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount)
+{
+ return new MeshImpl(position, normals, uv, verticesCount, indices, indicesCount);
+}
+
+MeshCleaner* NvBlastExtAuthoringCreateMeshCleaner()
+{
+ return new MeshCleanerImpl;
+}
+
+VoronoiSitesGenerator* NvBlastExtAuthoringCreateVoronoiSitesGenerator(Mesh* mesh, RandomGeneratorBase* rng)
+{
+ return new VoronoiSitesGeneratorImpl(mesh, rng);
+}
+
+FractureTool* NvBlastExtAuthoringCreateFractureTool()
+{
+ return new FractureToolImpl;
+}
+
+BlastBondGenerator* NvBlastExtAuthoringCreateBondGenerator(PxCooking* cooking, PxPhysicsInsertionCallback* insertionCallback)
+{
+ return new BlastBondGeneratorImpl(cooking, insertionCallback);
+}
+
+ConvexMeshBuilder* NvBlastExtAuthoringCreateConvexMeshBuilder(PxCooking* cooking, PxPhysicsInsertionCallback* insertionCallback)
+{
+ return new ConvexMeshBuilderImpl(cooking, insertionCallback);
+}
+
+void buildPhysicsChunks(ConvexMeshBuilder& collisionBuilder, AuthoringResult& result)
+{
+ uint32_t chunkCount = (uint32_t)result.chunkCount;
+ result.collisionHullOffset = SAFE_ARRAY_NEW(uint32_t, chunkCount + 1);
+ result.collisionHullOffset[0] = 0;
+ result.collisionHull = SAFE_ARRAY_NEW(CollisionHull*, chunkCount);
+ result.physicsSubchunks = SAFE_ARRAY_NEW(ExtPxSubchunk, chunkCount);
+ result.physicsChunks = SAFE_ARRAY_NEW(ExtPxChunk, chunkCount);
+ for (uint32_t i = 0; i < chunkCount; ++i)
+ {
+ std::vector<physx::PxVec3> vertices;
+ for (uint32_t p = result.geometryOffset[i]; p < result.geometryOffset[i+1]; ++p)
+ {
+ Nv::Blast::Triangle& tri = result.geometry[p];
+ vertices.push_back(tri.a.p);
+ vertices.push_back(tri.b.p);
+ vertices.push_back(tri.c.p);
+ }
+
+ result.collisionHullOffset[i + 1] = result.collisionHullOffset[i] + 1;
+ result.collisionHull[i] = collisionBuilder.buildCollisionGeometry((uint32_t)vertices.size(), vertices.data());
+ result.physicsSubchunks[i].transform = physx::PxTransform(physx::PxIdentity);
+ result.physicsSubchunks[i].geometry = physx::PxConvexMeshGeometry(collisionBuilder.buildConvexMesh(*result.collisionHull[i]));
+
+ result.physicsChunks[i].isStatic = false;
+ result.physicsChunks[i].subchunkCount = 1;
+ result.physicsChunks[i].firstSubchunkIndex = i;
+ //outPhysicsChunks.get()[i].subchunks = &outPhysicsSubchunks[i];
+ }
+}
+
+
+struct AuthoringResultImpl : public AuthoringResult
+{
+ void releaseCollisionHulls() override
+ {
+ if (collisionHull != nullptr)
+ {
+ for (uint32_t ch = 0; ch < collisionHullOffset[chunkCount]; ch++)
+ {
+ collisionHull[ch]->release();
+ }
+ SAFE_ARRAY_DELETE(collisionHullOffset);
+ SAFE_ARRAY_DELETE(collisionHull);
+ }
+ }
+
+ void release() override
+ {
+ releaseCollisionHulls();
+ NVBLAST_FREE(asset);
+ SAFE_ARRAY_DELETE(assetToFractureChunkIdMap);
+ SAFE_ARRAY_DELETE(geometryOffset);
+ SAFE_ARRAY_DELETE(geometry);
+ SAFE_ARRAY_DELETE(chunkDescs);
+ SAFE_ARRAY_DELETE(bondDescs);
+ SAFE_ARRAY_DELETE(physicsChunks);
+ SAFE_ARRAY_DELETE(physicsSubchunks);
+ delete this;
+ }
+};
+
+AuthoringResult* NvBlastExtAuthoringProcessFracture(FractureTool& fTool, BlastBondGenerator& bondGenerator, ConvexMeshBuilder& collisionBuilder, int32_t defaultSupportDepth)
+{
+ fTool.finalizeFracturing();
+ const uint32_t chunkCount = fTool.getChunkCount();
+ if (chunkCount == 0)
+ {
+ return nullptr;
+ }
+ AuthoringResultImpl* ret = new AuthoringResultImpl;
+ if (ret == nullptr)
+ {
+ return nullptr;
+ }
+ AuthoringResult& aResult = *ret;
+ aResult.chunkCount = chunkCount;
+
+ std::shared_ptr<bool> isSupport(new bool[chunkCount], [](bool* b) {delete[] b; });
+ memset(isSupport.get(), 0, sizeof(bool) * chunkCount);
+ for (uint32_t i = 0; i < fTool.getChunkCount(); ++i)
+ {
+ if (defaultSupportDepth < 0 || fTool.getChunkDepth(fTool.getChunkId(i)) < defaultSupportDepth)
+ {
+ isSupport.get()[i] = fTool.getChunkInfo(i).isLeaf;
+ }
+ else if (fTool.getChunkDepth(fTool.getChunkId(i)) == defaultSupportDepth)
+ {
+ isSupport.get()[i] = true;
+ }
+ }
+
+ BondGenerationConfig cnf;
+ cnf.bondMode = BondGenerationConfig::EXACT;
+
+ //NvBlastChunkDesc>& chunkDescs = aResult.chunkDescs;
+ //std::shared_ptr<NvBlastBondDesc>& bondDescs = aResult.bondDescs;
+ const uint32_t bondCount = bondGenerator.buildDescFromInternalFracture(&fTool, isSupport.get(), aResult.bondDescs, aResult.chunkDescs);
+ aResult.bondCount = bondCount;
+ if (bondCount == 0)
+ {
+ aResult.bondDescs = nullptr;
+ }
+
+ // order chunks, build map
+ std::vector<uint32_t> chunkReorderInvMap;
+ {
+ std::vector<uint32_t> chunkReorderMap(chunkCount);
+ std::vector<char> scratch(chunkCount * sizeof(NvBlastChunkDesc));
+ NvBlastEnsureAssetExactSupportCoverage(aResult.chunkDescs, chunkCount, scratch.data(), logLL);
+ NvBlastBuildAssetDescChunkReorderMap(chunkReorderMap.data(), aResult.chunkDescs, chunkCount, scratch.data(), logLL);
+ NvBlastApplyAssetDescChunkReorderMapInPlace(aResult.chunkDescs, chunkCount, aResult.bondDescs, bondCount, chunkReorderMap.data(), true, scratch.data(), logLL);
+ chunkReorderInvMap.resize(chunkReorderMap.size());
+ Nv::Blast::invertMap(chunkReorderInvMap.data(), chunkReorderMap.data(), static_cast<unsigned int>(chunkReorderMap.size()));
+ }
+
+ // get result geometry
+ aResult.geometryOffset = SAFE_ARRAY_NEW(uint32_t, chunkCount + 1);
+ aResult.assetToFractureChunkIdMap = SAFE_ARRAY_NEW(uint32_t, chunkCount + 1);
+ aResult.geometryOffset[0] = 0;
+ std::vector<Nv::Blast::Triangle*> chunkGeometry(chunkCount);
+ for (uint32_t i = 0; i < chunkCount; ++i)
+ {
+ uint32_t chunkIndex = chunkReorderInvMap[i];
+ aResult.geometryOffset[i+1] = aResult.geometryOffset[i] + fTool.getBaseMesh(chunkIndex, chunkGeometry[i]);
+ aResult.assetToFractureChunkIdMap[i] = chunkIndex;
+ }
+ aResult.geometry = SAFE_ARRAY_NEW(Triangle, aResult.geometryOffset[chunkCount]);
+ for (uint32_t i = 0; i < chunkCount; ++i)
+ {
+ uint32_t trianglesCount = aResult.geometryOffset[i + 1] - aResult.geometryOffset[i];
+ memcpy(aResult.geometry + aResult.geometryOffset[i], chunkGeometry[i], trianglesCount * sizeof(Nv::Blast::Triangle));
+ }
+
+ float maxX = INT32_MIN;
+ float maxY = INT32_MIN;
+ float maxZ = INT32_MIN;
+
+ float minX = INT32_MAX;
+ float minY = INT32_MAX;
+ float minZ = INT32_MAX;
+
+ for (uint32_t i = 0; i < bondCount; i++)
+ {
+ NvBlastBondDesc& bondDesc = aResult.bondDescs[i];
+
+ minX = std::min(minX, bondDesc.bond.centroid[0]);
+ maxX = std::max(maxX, bondDesc.bond.centroid[0]);
+
+ minY = std::min(minY, bondDesc.bond.centroid[1]);
+ maxY = std::max(maxY, bondDesc.bond.centroid[1]);
+
+ minZ = std::min(minZ, bondDesc.bond.centroid[2]);
+ maxZ = std::max(maxZ, bondDesc.bond.centroid[2]);
+ }
+
+ //std::cout << "Bond bounds: " << std::endl;
+ //std::cout << "MIN: " << minX << ", " << minY << ", " << minZ << std::endl;
+ //std::cout << "MAX: " << maxX << ", " << maxY << ", " << maxZ << std::endl;
+
+ // prepare physics data (convexes)
+ buildPhysicsChunks(collisionBuilder, aResult);
+
+ // set NvBlastChunk volume from Px geometry
+ for (uint32_t i = 0; i < chunkCount; i++)
+ {
+ float totalVolume = 0.f;
+ for (uint32_t k = 0; k < aResult.physicsChunks[i].subchunkCount; k++)
+ {
+ const auto& subChunk = aResult.physicsSubchunks[aResult.physicsChunks[i].firstSubchunkIndex + k];
+ physx::PxVec3 localCenterOfMass; physx::PxMat33 intertia; float mass;
+ subChunk.geometry.convexMesh->getMassInformation(mass, intertia, localCenterOfMass);
+ const physx::PxVec3 scale = subChunk.geometry.scale.scale;
+ mass *= scale.x * scale.y * scale.z;
+ totalVolume += mass / 1.0f; // unit density
+ }
+
+ aResult.chunkDescs[i].volume = totalVolume;
+ }
+
+ // build and serialize ExtPhysicsAsset
+ NvBlastAssetDesc descriptor;
+ descriptor.bondCount = bondCount;
+ descriptor.bondDescs = aResult.bondDescs;
+ descriptor.chunkCount = chunkCount;
+ descriptor.chunkDescs = aResult.chunkDescs;
+
+ std::vector<uint8_t> scratch(static_cast<unsigned int>(NvBlastGetRequiredScratchForCreateAsset(&descriptor, logLL)));
+ void* mem = NVBLAST_ALLOC(NvBlastGetAssetMemorySize(&descriptor, logLL));
+ aResult.asset = NvBlastCreateAsset(mem, &descriptor, scratch.data(), logLL);
+
+ //aResult.asset = std::shared_ptr<NvBlastAsset>(asset, [=](NvBlastAsset* asset)
+ //{
+ // NVBLAST_FREE(asset);
+ //});
+
+ //std::cout << "Done" << std::endl;
+ ret->materialCount = 0;
+ ret->materialNames = nullptr;
+ return ret;
+} \ No newline at end of file
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.cpp
index 075bce9..40ddec1 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.cpp
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#include "NvBlastExtAuthoringAccelerator.h"
#include "NvBlastExtAuthoringMesh.h"
@@ -25,16 +43,16 @@ DummyAccelerator::DummyAccelerator(int32_t count) :count(count)
{
current = 0;
}
-void DummyAccelerator::setState(Vertex* pos, Edge* ed, Facet& fc)
+void DummyAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
{
current = 0;
- (void)pos;
- (void)ed;
- (void)fc;
+ NV_UNUSED(pos);
+ NV_UNUSED(ed);
+ NV_UNUSED(fc);
}
void DummyAccelerator::setState(const physx::PxVec3& point) {
current = 0;
- (void)point;
+ NV_UNUSED(point);
}
int32_t DummyAccelerator::getNextFacet()
{
@@ -49,7 +67,7 @@ int32_t DummyAccelerator::getNextFacet()
-BBoxBasedAccelerator::BBoxBasedAccelerator(Mesh* mesh, int32_t resolution) : mResolution(resolution), alreadyGotValue(1)
+BBoxBasedAccelerator::BBoxBasedAccelerator(const Mesh* mesh, int32_t resolution) : mResolution(resolution), alreadyGotValue(1)
{
mBounds = mesh->getBoundingBox();
mSpatialMap.resize(resolution * resolution * resolution);
@@ -124,14 +142,14 @@ int32_t BBoxBasedAccelerator::getNextFacet()
}
return facetId;
}
-void BBoxBasedAccelerator::setState(Vertex* pos, Edge* ed, Facet& fc)
+void BBoxBasedAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
{
alreadyGotValue++;
mIteratorCell = -1;
mIteratorFacet = -1;
cellList.clear();
facetBox.setEmpty();
- Edge* edge = ed + fc.firstEdgeNumber;
+ const Edge* edge = ed + fc.firstEdgeNumber;
uint32_t count = fc.edgesCount;
for (uint32_t ec = 0; ec < count; ++ec)
{
@@ -195,13 +213,13 @@ bool BBoxBasedAccelerator::testCellPolygonIntersection(int32_t cellId, PxBounds3
return false;
}
-void BBoxBasedAccelerator::buildAccelStructure(Vertex* pos, Edge* edges, Facet* fc, int32_t facetCount)
+void BBoxBasedAccelerator::buildAccelStructure(const Vertex* pos, const Edge* edges, const Facet* fc, int32_t facetCount)
{
for (int32_t facet = 0; facet < facetCount; ++facet)
{
PxBounds3 bBox;
bBox.setEmpty();
- Edge* edge = &edges[0] + fc->firstEdgeNumber;
+ const Edge* edge = &edges[0] + fc->firstEdgeNumber;
int32_t count = fc->edgesCount;
for (int32_t ec = 0; ec < count; ++ec)
{
@@ -349,15 +367,15 @@ enum TrivialFlags
-int32_t testFacetUnitCubeIntersection(Vertex* vertices, Edge* edges, Facet& fc, PxBounds3 cube, float fattening)
+int32_t testFacetUnitCubeIntersection(const Vertex* vertices, const Edge* edges, const Facet& fc, PxBounds3 cube, float fattening)
{
- Edge* ed = edges + fc.firstEdgeNumber;
+ const Edge* ed = edges + fc.firstEdgeNumber;
int32_t trivialFlags = ALL_ONE;
cube.fattenFast(fattening);
for (uint32_t i = 0; i < fc.edgesCount; ++i)
{
{
- PxVec3& p = vertices[ed->s].p;
+ const PxVec3& p = vertices[ed->s].p;
if (cube.contains(p))
return 1;
if (p.x < cube.getCenter().x + 0.5)
@@ -376,7 +394,7 @@ int32_t testFacetUnitCubeIntersection(Vertex* vertices, Edge* edges, Facet& fc,
trivialFlags &= HAS_POINT_ABOVE_LOW_Z;
}
{
- PxVec3& p = vertices[ed->e].p;
+ const PxVec3& p = vertices[ed->e].p;
if (cube.contains(p))
return 1;
if (p.x < cube.getCenter().x + 0.5)
@@ -411,9 +429,9 @@ int32_t testFacetUnitCubeIntersection(Vertex* vertices, Edge* edges, Facet& fc,
/**
Compute normal
*/
- PxVec3& v1 = vertices[ed->s].p;
- PxVec3* v2 = nullptr;
- PxVec3* v3 = nullptr;
+ const PxVec3& v1 = vertices[ed->s].p;
+ const PxVec3* v2 = nullptr;
+ const PxVec3* v3 = nullptr;
for (uint32_t i = 0; i < fc.edgesCount; ++i)
{
@@ -476,7 +494,7 @@ int32_t testFacetUnitCubeIntersection(Vertex* vertices, Edge* edges, Facet& fc,
}
-IntersectionTestingAccelerator::IntersectionTestingAccelerator(Mesh* in, int32_t resolution)
+IntersectionTestingAccelerator::IntersectionTestingAccelerator(const Mesh* in, int32_t resolution)
{
@@ -563,7 +581,7 @@ int32_t IntersectionTestingAccelerator::getNextFacet()
return facetId;
}
-void IntersectionTestingAccelerator::setState(Vertex* pos, Edge* ed, Facet& fc)
+void IntersectionTestingAccelerator::setState(const Vertex* pos, const Edge* ed, const Facet& fc)
{
alreadyGotValue++;
mIteratorCell = -1;
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.h
index 8284cd7..909dc86 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringAccelerator.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGACCELERATOR_H
#define NVBLASTEXTAUTHORINGACCELERATOR_H
@@ -36,7 +54,7 @@ public:
\param[in] ed Edge buffer
\param[in] fc Facet which should be tested.
*/
- virtual void setState(Vertex* pos, Edge* ed, Facet& fc) = 0;
+ virtual void setState(const Vertex* pos, const Edge* ed, const Facet& fc) = 0;
/**
Set state of accelerator to return all facets which possibly can cover given point. Needed for testing whether point is inside mesh.
\param[in] point Point which should be tested.
@@ -62,7 +80,7 @@ public:
\param[in] count Mesh facets count for which accelerator should be built.
*/
DummyAccelerator(int32_t count);
- virtual void setState(Vertex* pos, Edge* ed, Facet& fc);
+ virtual void setState(const Vertex* pos, const Edge* ed, const Facet& fc);
virtual void setState(const physx::PxVec3& point);
virtual int32_t getNextFacet();
@@ -83,15 +101,15 @@ public:
\param[in] mesh Mesh for which acceleration structure should be built.
\param[in] resolution Resolution on 3d grid.
*/
- BBoxBasedAccelerator(Mesh* mesh, int32_t resolution);
+ BBoxBasedAccelerator(const Mesh* mesh, int32_t resolution);
virtual ~BBoxBasedAccelerator();
int32_t getNextFacet();
- void setState(Vertex* pos, Edge* ed, Facet& fc);
+ void setState(const Vertex* pos, const Edge* ed, const Facet& fc);
void setState(const physx::PxVec3& p);
private:
bool testCellPolygonIntersection(int32_t cellId, physx::PxBounds3& facetBB);
- void buildAccelStructure(Vertex* pos, Edge* edges, Facet* fc, int32_t facetCount);
+ void buildAccelStructure(const Vertex* pos, const Edge* edges, const Facet* fc, int32_t facetCount);
int32_t mResolution;
physx::PxBounds3 mBounds;
@@ -121,9 +139,9 @@ private:
class IntersectionTestingAccelerator : public SpatialAccelerator
{
public:
- IntersectionTestingAccelerator(Mesh* mesh, int32_t resolution);
+ IntersectionTestingAccelerator(const Mesh* mesh, int32_t resolution);
int32_t getNextFacet();
- void setState(Vertex* pos, Edge* ed, Facet& fc);
+ void setState(const Vertex* pos, const Edge* ed, const Facet& fc);
void setState(const physx::PxVec3& p);
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGenerator.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.cpp
index b2c3883..a4a2ce7 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGenerator.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.cpp
@@ -1,12 +1,30 @@
-/*
-* Copyright (c) 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 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) 2017 NVIDIA Corporation. All rights reserved.
+
// 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
@@ -15,22 +33,25 @@
#pragma warning(disable : 4702)
#endif
-#include <NvBlastExtAuthoringBondGenerator.h>
-#include <NvBlastTypes.h>
+#include <NvBlastExtAuthoringBondGeneratorImpl.h>
#include <NvBlast.h>
#include "NvBlastExtTriangleProcessor.h"
#include "NvBlastExtApexSharedParts.h"
-#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include "NvBlastExtAuthoringCollisionBuilderImpl.h"
#include "NvBlastExtAuthoringInternalCommon.h"
+#include "NvBlastExtAuthoringTypes.h"
#include <vector>
#include <map>
#include <PxPlane.h>
#include <algorithm>
#include <cmath>
+#include <memory>
using physx::PxVec3;
using physx::PxBounds3;
+#define SAFE_ARRAY_NEW(T, x) ((x) > 0) ? new T[x] : nullptr;
+
//#define DEBUG_OUTPUT
#ifdef DEBUG_OUTPUT
@@ -125,8 +146,7 @@ namespace Nv
int32_t m_chunkId;
};
-
- float BlastBondGenerator::processWithMidplanes(TriangleProcessor* trProcessor, const std::vector<PxVec3>& chunk1Points, const std::vector<PxVec3>& chunk2Points,
+ float BlastBondGeneratorImpl::processWithMidplanes(TriangleProcessor* trProcessor, const std::vector<PxVec3>& chunk1Points, const std::vector<PxVec3>& chunk2Points,
const std::vector<PxVec3>& hull1p, const std::vector<PxVec3>& hull2p, PxVec3& normal, PxVec3& centroid)
{
PxBounds3 bounds;
@@ -163,7 +183,7 @@ namespace Nv
chunk2Centroid *= (1.0f / chunk2Points.size());
Separation separation;
- if (!importerHullsInProximityApexFree(hull1p, aBounds, PxTransform(PxIdentity), PxVec3(1, 1, 1), hull2p, bBounds, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation))
+ if (!importerHullsInProximityApexFree(hull1p.size(), hull1p.data(), aBounds, PxTransform(PxIdentity), PxVec3(1, 1, 1), hull2p.size(), hull2p.data(), bBounds, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation))
{
return 0.0;
}
@@ -221,53 +241,39 @@ namespace Nv
return area * 0.5f;
}
-
- int32_t BlastBondGenerator::bondsFromPrefractured(const std::vector<std::vector<Triangle>>& geometry, const std::vector<bool>& chunkIsSupport, std::vector<NvBlastBondDesc>& resultBondDescs, BondGenerationConfig conf)
- {
- int32_t ret_val = 0;
- switch (conf.bondMode)
- {
- case BondGenerationConfig::AVERAGE:
- ret_val = createFullBondListAveraged(geometry, chunkIsSupport, resultBondDescs, conf);
- break;
- case BondGenerationConfig::EXACT:
- ret_val = createFullBondListExact(geometry, chunkIsSupport, resultBondDescs, conf);
- break;
- }
- return ret_val;
- }
-
- int32_t BlastBondGenerator::createFullBondListAveraged(const std::vector<std::vector<Triangle>>& chunksGeometry, const std::vector<bool>& supportFlags, std::vector<NvBlastBondDesc>& mResultBondDescs, BondGenerationConfig conf)
+ int32_t BlastBondGeneratorImpl::createFullBondListAveraged(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool* supportFlags, NvBlastBondDesc*& resultBondDescs, BondGenerationConfig conf)
{
NV_UNUSED(conf);
- std::vector<std::vector<PxVec3> > chunksPoints(chunksGeometry.size());
+ std::vector<std::vector<PxVec3> > chunksPoints(meshCount);
- for (uint32_t i = 0; i < chunksGeometry.size(); ++i)
+ for (uint32_t i = 0; i < meshCount; ++i)
{
if (!supportFlags[i])
{
continue;
}
- for (uint32_t j = 0; j < chunksGeometry[i].size(); ++j)
+ uint32_t count = geometryOffset[i + 1] - geometryOffset[i];
+ for (uint32_t j = 0; j < count; ++j)
{
- chunksPoints[i].push_back(chunksGeometry[i][j].a.p);
- chunksPoints[i].push_back(chunksGeometry[i][j].b.p);
- chunksPoints[i].push_back(chunksGeometry[i][j].c.p);
+ chunksPoints[i].push_back(geometry[geometryOffset[i] + j].a.p);
+ chunksPoints[i].push_back(geometry[geometryOffset[i] + j].b.p);
+ chunksPoints[i].push_back(geometry[geometryOffset[i] + j].c.p);
}
}
- Nv::Blast::ConvexMeshBuilder builder(mPxCooking, mPxInsertionCallback);
+ Nv::Blast::ConvexMeshBuilderImpl builder(mPxCooking, mPxInsertionCallback);
- std::vector<CollisionHull> cHulls(chunksGeometry.size());
+ std::vector<CollisionHull*> cHulls(meshCount);
- for (uint32_t i = 0; i < chunksGeometry.size(); ++i)
+ for (uint32_t i = 0; i < meshCount; ++i)
{
if (!supportFlags[i])
{
continue;
}
- builder.buildCollisionGeometry(chunksPoints[i], cHulls[i]);
+ cHulls[i] = builder.buildCollisionGeometry(chunksPoints[i].size(), chunksPoints[i].data());
}
std::vector<std::vector<PxVec3> > hullPoints(cHulls.size());
@@ -279,24 +285,23 @@ namespace Nv
continue;
}
- hullPoints[chunk].resize(cHulls[chunk].points.size());
- for (uint32_t i = 0; i < cHulls[chunk].points.size(); ++i)
+ hullPoints[chunk].resize(cHulls[chunk]->pointsCount);
+ for (uint32_t i = 0; i < cHulls[chunk]->pointsCount; ++i)
{
- hullPoints[chunk][i].x = cHulls[chunk].points[i].x;
- hullPoints[chunk][i].y = cHulls[chunk].points[i].y;
- hullPoints[chunk][i].z = cHulls[chunk].points[i].z;
+ hullPoints[chunk][i] = cHulls[chunk]->points[i];
}
+ cHulls[chunk]->release();
}
TriangleProcessor trProcessor;
-
- for (uint32_t i = 0; i < chunksGeometry.size(); ++i)
+ std::vector<NvBlastBondDesc> mResultBondDescs;
+ for (uint32_t i = 0; i < meshCount; ++i)
{
if (!supportFlags[i])
{
continue;
}
- for (uint32_t j = i + 1; j < chunksGeometry.size(); ++j)
+ for (uint32_t j = i + 1; j < meshCount; ++j)
{
if (!supportFlags[i])
{
@@ -327,8 +332,9 @@ namespace Nv
}
}
-
- return 0;
+ resultBondDescs = SAFE_ARRAY_NEW(NvBlastBondDesc, mResultBondDescs.size());
+ memcpy(resultBondDescs, mResultBondDescs.data(), sizeof(NvBlastBondDesc)*mResultBondDescs.size());
+ return mResultBondDescs.size();
}
uint32_t isSamePlane(PxPlane& a, PxPlane& b)
@@ -340,39 +346,48 @@ namespace Nv
return 1;
}
- int32_t BlastBondGenerator::createFullBondListExact(const std::vector<std::vector<Triangle>>& chunksGeometry, const std::vector<bool>& supportFlags, std::vector<NvBlastBondDesc>& mResultBondDescs, BondGenerationConfig conf)
+ int32_t BlastBondGeneratorImpl::createFullBondListExact(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool* supportFlags, NvBlastBondDesc*& resultBondDescs, BondGenerationConfig conf)
{
std::vector < PlaneChunkIndexer > planeTriangleMapping;
NV_UNUSED(conf);
- for (uint32_t i = 0; i < chunksGeometry.size(); ++i)
+ for (uint32_t i = 0; i < meshCount; ++i)
{
if (!supportFlags[i])
{
continue;
}
- for (uint32_t j = 0; j < chunksGeometry[i].size(); ++j)
+ uint32_t count = geometryOffset[i + 1] - geometryOffset[i];
+ for (uint32_t j = 0; j < count; ++j)
{
#ifdef DEBUG_OUTPUT
- meshBuffer.push_back(chunksGeometry[i][j].a.p );
- meshBuffer.push_back(chunksGeometry[i][j].b.p);
- meshBuffer.push_back(chunksGeometry[i][j].c.p );
+ meshBuffer.push_back(geometry[geometryOffset[i] + j].a.p );
+ meshBuffer.push_back(geometry[geometryOffset[i] + j].b.p);
+ meshBuffer.push_back(geometry[geometryOffset[i] + j].c.p );
#endif
- PxPlane nPlane = PxPlane(chunksGeometry[i][j].a.p, chunksGeometry[i][j].b.p, chunksGeometry[i][j].c.p);
+ PxPlane nPlane = PxPlane(geometry[geometryOffset[i] + j].a.p, geometry[geometryOffset[i] + j].b.p, geometry[geometryOffset[i] + j].c.p);
planeTriangleMapping.push_back(PlaneChunkIndexer(i, j, nPlane));
}
}
std::sort(planeTriangleMapping.begin(), planeTriangleMapping.end(), planeComparer);
- return createFullBondListExactInternal(chunksGeometry, planeTriangleMapping, mResultBondDescs);
+ return createFullBondListExactInternal(meshCount, geometryOffset, geometry, planeTriangleMapping, resultBondDescs);
}
- void BlastBondGenerator::buildGeometryCache(const std::vector<std::vector<Triangle> >& geometry)
+ void BlastBondGeneratorImpl::buildGeometryCache(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry)
{
- mGeometryCache = geometry;
- mHullsPointsCache.resize(geometry.size());
- mBoundsCache.resize(geometry.size());
- mCHullCache.resize(geometry.size());
+ uint32_t geometryCount = geometryOffset[meshCount];
+ for (uint32_t i = 0; i < meshCount; i++)
+ {
+ mGeometryCache.push_back(std::vector<Triangle>());
+ uint32_t count = geometryOffset[i + 1] - geometryOffset[i];
+ mGeometryCache.back().resize(count);
+ memcpy(mGeometryCache.back().data(), geometry + geometryOffset[i], sizeof(Triangle) * count);
+ }
+ mHullsPointsCache.resize(geometryCount);
+ mBoundsCache.resize(geometryCount);
+ mCHullCache.resize(geometryCount);
for (uint32_t i = 0; i < mGeometryCache.size(); ++i)
{
for (uint32_t j = 0; j < mGeometryCache[i].size(); ++j)
@@ -395,36 +410,39 @@ namespace Nv
chunksPoints[sp++] = mGeometryCache[ch][i].c.p;
}
- Nv::Blast::ConvexMeshBuilder builder(mPxCooking, mPxInsertionCallback);
-
- CollisionHull& cHull = mCHullCache[ch];
+ Nv::Blast::ConvexMeshBuilderImpl builder(mPxCooking, mPxInsertionCallback);
- builder.buildCollisionGeometry(chunksPoints, cHull);
+ mCHullCache[ch] = builder.buildCollisionGeometry(chunksPoints.size(), chunksPoints.data());
- mHullsPointsCache[ch].resize(cHull.points.size());
+ mHullsPointsCache[ch].resize(mCHullCache[ch]->pointsCount);
mBoundsCache[ch].setEmpty();
- for (uint32_t i = 0; i < cHull.points.size(); ++i)
+ for (uint32_t i = 0; i < mCHullCache[ch]->pointsCount; ++i)
{
- mHullsPointsCache[ch][i].x = cHull.points[i].x;
- mHullsPointsCache[ch][i].y = cHull.points[i].y;
- mHullsPointsCache[ch][i].z = cHull.points[i].z;
+ mHullsPointsCache[ch][i] = mCHullCache[ch]->points[i];
mBoundsCache[ch].include(mHullsPointsCache[ch][i]);
}
}
}
- void BlastBondGenerator::resetGeometryCache()
+ void BlastBondGeneratorImpl::resetGeometryCache()
{
mGeometryCache.clear();
mPlaneCache.clear();
mHullsPointsCache.clear();
+ for (auto h : mCHullCache)
+ {
+ h->release();
+ }
mCHullCache.clear();
mBoundsCache.clear();
}
- int32_t BlastBondGenerator::createFullBondListExactInternal(const std::vector<std::vector<Triangle>>& chunksGeometry, std::vector < PlaneChunkIndexer >& planeTriangleMapping, std::vector<NvBlastBondDesc>& mResultBondDescs)
+ int32_t BlastBondGeneratorImpl::createFullBondListExactInternal(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ std::vector<PlaneChunkIndexer>& planeTriangleMapping, NvBlastBondDesc*& resultBondDescs)
{
+ NV_UNUSED(meshCount);
+
std::map<std::pair<int32_t, int32_t>, std::pair<NvBlastBondDesc, int32_t> > bonds;
TriangleProcessor trPrc;
@@ -446,7 +464,7 @@ namespace Nv
// uint32_t endIndex = (uint32_t)planeTriangleMapping.size();
PlaneChunkIndexer& mappedTr = planeTriangleMapping[tIndex];
- const Triangle& trl = chunksGeometry[mappedTr.chunkId][mappedTr.trId];
+ const Triangle& trl = geometry[geometryOffset[mappedTr.chunkId] + mappedTr.trId];
PxPlane pln = mappedTr.plane;
TrPrcTriangle trp(trl.a.p, trl.b.p, trl.c.p);
PxVec3 trCentroid = (trl.a.p + trl.b.p + trl.c.p) * (1.0f / 3.0f);
@@ -493,8 +511,7 @@ namespace Nv
bonds[bondEndPoints].first.bond.normal[1] = pln.n[1];
bonds[bondEndPoints].first.bond.normal[2] = pln.n[2];
}
-
- const Triangle& trl2 = chunksGeometry[mappedTr2.chunkId][mappedTr2.trId];
+ const Triangle& trl2 = geometry[geometryOffset[mappedTr2.chunkId] + mappedTr2.trId];
TrPrcTriangle trp2(trl2.a.p, trl2.b.p, trl2.c.p);
@@ -536,6 +553,7 @@ namespace Nv
}
}
+ std::vector<NvBlastBondDesc> mResultBondDescs;
for (auto it : bonds)
{
if (it.second.first.bond.area > 0)
@@ -553,21 +571,23 @@ namespace Nv
saveGeometryToObj(meshBuffer, "Mesh.obj");
saveGeometryToObj(intersectionBuffer, "inter.obj");
#endif
- return 0;
+ resultBondDescs = SAFE_ARRAY_NEW(NvBlastBondDesc, mResultBondDescs.size());
+ memcpy(resultBondDescs, mResultBondDescs.data(), sizeof(NvBlastBondDesc)*mResultBondDescs.size());
+ return mResultBondDescs.size();
}
- int32_t BlastBondGenerator::createBondForcedInternal(const std::vector<PxVec3>& hull0, const std::vector<PxVec3>& hull1,
+ int32_t BlastBondGeneratorImpl::createBondForcedInternal(const std::vector<PxVec3>& hull0, const std::vector<PxVec3>& hull1,
const CollisionHull& cHull0,const CollisionHull& cHull1,
PxBounds3 bound0, PxBounds3 bound1, NvBlastBond& resultBond, float overlapping)
{
TriangleProcessor trProcessor;
Separation separation;
- importerHullsInProximityApexFree(hull0, bound0, PxTransform(PxIdentity), PxVec3(1, 1, 1), hull1, bound1, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation);
+ importerHullsInProximityApexFree(hull0.size(), hull0.data(), bound0, PxTransform(PxIdentity), PxVec3(1, 1, 1), hull1.size(), hull1.data(), bound1, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation);
if (std::isnan(separation.plane.d))
{
- importerHullsInProximityApexFree(hull0, bound0, PxTransform(PxVec3(0.000001f, 0.000001f, 0.000001f)), PxVec3(1, 1, 1), hull1, bound1, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation);
+ importerHullsInProximityApexFree(hull0.size(), hull0.data(), bound0, PxTransform(PxVec3(0.000001f, 0.000001f, 0.000001f)), PxVec3(1, 1, 1), hull1.size(), hull1.data(), bound1, PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.000, &separation);
if (std::isnan(separation.plane.d))
{
return 1;
@@ -581,9 +601,9 @@ namespace Nv
dst[0][0] = 0;
dst[0][1] = MAXIMUM_EXTENT;
- for (uint32_t p = 0; p < cHull0.points.size(); ++p)
+ for (uint32_t p = 0; p < cHull0.pointsCount; ++p)
{
- float d = pl.distance(PxVec3(cHull0.points[p].x, cHull0.points[p].y, cHull0.points[p].z));
+ float d = pl.distance(cHull0.points[p]);
if (PxAbs(d) > PxAbs(dst[0][0]))
{
dst[0][0] = d;
@@ -596,9 +616,9 @@ namespace Nv
dst[1][0] = 0;
dst[1][1] = MAXIMUM_EXTENT;
- for (uint32_t p = 0; p < cHull1.points.size(); ++p)
+ for (uint32_t p = 0; p < cHull1.pointsCount; ++p)
{
- float d = pl.distance(PxVec3(cHull1.points[p].x, cHull1.points[p].y, cHull1.points[p].z));
+ float d = pl.distance(cHull0.points[p]);
if (PxAbs(d) > PxAbs(dst[1][0]))
{
dst[1][0] = d;
@@ -612,16 +632,16 @@ namespace Nv
float cvOffset[2] = { dst[0][1] + (dst[0][0] - dst[0][1]) * overlapping, dst[1][1] + (dst[1][0] - dst[1][1]) * overlapping };
- for (uint32_t i = 0; i < cHull0.polygonData.size(); ++i)
+ for (uint32_t i = 0; i < cHull0.polygonDataCount; ++i)
{
- uint32_t offset = cHull0.polygonData[i].mIndexBase;
+ auto& pd = cHull0.polygonData[i];
PxVec3 result;
- for (uint32_t j = 0; j < cHull0.polygonData[i].mNbVerts; ++j)
+ for (uint32_t j = 0; j < pd.mNbVerts; ++j)
{
- uint32_t nxj = (j + 1) % cHull0.polygonData[i].mNbVerts;
- const uint32_t* ind = &cHull0.indices[0];
- PxVec3 a = hull0[ind[j + offset]] - pl.n * cvOffset[0];
- PxVec3 b = hull0[ind[nxj + offset]] - pl.n * cvOffset[0];
+ uint32_t nxj = (j + 1) % pd.mNbVerts;
+ const uint32_t* ind = cHull0.indices;
+ PxVec3 a = hull0[ind[j + pd.mIndexBase]] - pl.n * cvOffset[0];
+ PxVec3 b = hull0[ind[nxj + pd.mIndexBase]] - pl.n * cvOffset[0];
if (getPlaneSegmentIntersection(pl, a, b, result))
{
@@ -630,16 +650,16 @@ namespace Nv
}
}
- for (uint32_t i = 0; i < cHull1.polygonData.size(); ++i)
+ for (uint32_t i = 0; i < cHull1.polygonDataCount; ++i)
{
- uint32_t offset = cHull1.polygonData[i].mIndexBase;
+ auto& pd = cHull1.polygonData[i];
PxVec3 result;
- for (uint32_t j = 0; j < cHull1.polygonData[i].mNbVerts; ++j)
+ for (uint32_t j = 0; j < pd.mNbVerts; ++j)
{
- uint32_t nxj = (j + 1) % cHull1.polygonData[i].mNbVerts;
- const uint32_t* ind = &cHull1.indices[0];
- PxVec3 a = hull1[ind[j + offset]] - pl.n * cvOffset[1];
- PxVec3 b = hull1[ind[nxj + offset]] - pl.n * cvOffset[1];
+ uint32_t nxj = (j + 1) % pd.mNbVerts;
+ const uint32_t* ind = cHull1.indices;
+ PxVec3 a = hull1[ind[j + pd.mIndexBase]] - pl.n * cvOffset[1];
+ PxVec3 b = hull1[ind[nxj + pd.mIndexBase]] - pl.n * cvOffset[1];
if (getPlaneSegmentIntersection(pl, a, b, result))
{
@@ -696,56 +716,59 @@ namespace Nv
return 0;
}
-
- int32_t BlastBondGenerator::buildDescFromInternalFracture(FractureTool* tool, const std::vector<bool>& chunkIsSupport, std::vector<NvBlastBondDesc>& mResultBondDescs, std::vector<NvBlastChunkDesc>& mResultChunkDescriptors)
+ int32_t BlastBondGeneratorImpl::buildDescFromInternalFracture(FractureTool* tool, const bool* chunkIsSupport,
+ NvBlastBondDesc*& resultBondDescs, NvBlastChunkDesc*& resultChunkDescriptors)
{
- const std::vector<ChunkInfo>& chunkData = tool->getChunkList();
- std::vector<std::vector<Triangle> > trianglesBuffer(chunkData.size());
+ uint32_t chunkCount = tool->getChunkCount();
+ std::vector<uint32_t> trianglesCount(chunkCount);
+ std::vector<Triangle*> trianglesBuffer(chunkCount);
for (uint32_t i = 0; i < trianglesBuffer.size(); ++i)
{
- tool->getBaseMesh(i, trianglesBuffer[i]);
+ trianglesCount[i] = tool->getBaseMesh(i, trianglesBuffer[i]);
}
- if (chunkData.empty() || trianglesBuffer.empty())
+ if (chunkCount == 0)
{
- return 1;
+ return 0;
}
- mResultChunkDescriptors.resize(trianglesBuffer.size());
+ resultChunkDescriptors = SAFE_ARRAY_NEW(NvBlastChunkDesc, trianglesBuffer.size());
std::vector<Bond> bondDescriptors;
- mResultChunkDescriptors[0].parentChunkIndex = UINT32_MAX;
- mResultChunkDescriptors[0].userData = 0;
+ resultChunkDescriptors[0].parentChunkIndex = UINT32_MAX;
+ resultChunkDescriptors[0].userData = 0;
+ resultChunkDescriptors[0].flags = NvBlastChunkDesc::NoFlags;
{
PxVec3 chunkCentroid(0, 0, 0);
- for (uint32_t tr = 0; tr < trianglesBuffer[0].size(); ++tr)
+ for (uint32_t tr = 0; tr < trianglesCount[0]; ++tr)
{
chunkCentroid += trianglesBuffer[0][tr].a.p;
chunkCentroid += trianglesBuffer[0][tr].b.p;
chunkCentroid += trianglesBuffer[0][tr].c.p;
}
- chunkCentroid *= (1.0f / (3 * trianglesBuffer[0].size()));
- mResultChunkDescriptors[0].centroid[0] = chunkCentroid[0];
- mResultChunkDescriptors[0].centroid[1] = chunkCentroid[1];
- mResultChunkDescriptors[0].centroid[2] = chunkCentroid[2];
+ chunkCentroid *= (1.0f / (3 * trianglesCount[0]));
+ resultChunkDescriptors[0].centroid[0] = chunkCentroid[0];
+ resultChunkDescriptors[0].centroid[1] = chunkCentroid[1];
+ resultChunkDescriptors[0].centroid[2] = chunkCentroid[2];
}
- for (uint32_t i = 1; i < chunkData.size(); ++i)
+ for (uint32_t i = 1; i < chunkCount; ++i)
{
-
- mResultChunkDescriptors[i].userData = i;
- mResultChunkDescriptors[i].parentChunkIndex = tool->getChunkIndex(chunkData[i].parent);
+ NvBlastChunkDesc& desc = resultChunkDescriptors[i];
+ desc.userData = i;
+ desc.parentChunkIndex = tool->getChunkIndex(tool->getChunkInfo(i).parent);
+ desc.flags = NvBlastChunkDesc::NoFlags;
if (chunkIsSupport[i])
- mResultChunkDescriptors[i].flags = NvBlastChunkDesc::SupportFlag;
+ desc.flags = NvBlastChunkDesc::SupportFlag;
PxVec3 chunkCentroid(0, 0, 0);
- for (uint32_t tr = 0; tr < trianglesBuffer[i].size(); ++tr)
+ for (uint32_t tr = 0; tr < trianglesCount[i]; ++tr)
{
chunkCentroid += trianglesBuffer[i][tr].a.p;
chunkCentroid += trianglesBuffer[i][tr].b.p;
chunkCentroid += trianglesBuffer[i][tr].c.p;
Triangle& trRef = trianglesBuffer[i][tr];
- int32_t id = trRef.userInfo;
+ int32_t id = trRef.userData;
if (id == 0)
continue;
bondDescriptors.push_back(Bond());
@@ -754,10 +777,10 @@ namespace Nv
bond.m_planeIndex = id;
bond.triangleIndex = tr;
}
- chunkCentroid *= (1.0f / (3 * trianglesBuffer[i].size()));
- mResultChunkDescriptors[i].centroid[0] = chunkCentroid[0];
- mResultChunkDescriptors[i].centroid[1] = chunkCentroid[1];
- mResultChunkDescriptors[i].centroid[2] = chunkCentroid[2];
+ chunkCentroid *= (1.0f / (3 * trianglesCount[i]));
+ desc.centroid[0] = chunkCentroid[0];
+ desc.centroid[1] = chunkCentroid[1];
+ desc.centroid[2] = chunkCentroid[2];
}
std::sort(bondDescriptors.begin(), bondDescriptors.end());
if (bondDescriptors.empty())
@@ -778,6 +801,7 @@ namespace Nv
chunkId = -1;
planeId = bondDescriptors[0].m_planeIndex;
+ std::vector<NvBlastBondDesc> mResultBondDescs;
for (uint32_t i = 0; i <= bondDescriptors.size(); ++i)
{
if (i == bondDescriptors.size() || (chunkId != bondDescriptors[i].m_chunkId || abs(planeId) != abs(bondDescriptors[i].m_planeIndex)))
@@ -866,70 +890,81 @@ namespace Nv
bb.include(trianglesBuffer[chunkId][tr].c.p);
}
- return 0;
+ resultBondDescs = SAFE_ARRAY_NEW(NvBlastBondDesc, mResultBondDescs.size());
+ memcpy(resultBondDescs, mResultBondDescs.data(), sizeof(NvBlastBondDesc) * mResultBondDescs.size());
+
+ return mResultBondDescs.size();
}
- int32_t BlastBondGenerator::createBondBetweenMeshes(const std::vector<std::vector<Triangle> >& geometry, std::vector<NvBlastBondDesc>& resultBond,const std::vector<std::pair<uint32_t, uint32_t> >& overlaps, BondGenerationConfig cfg)
+ int32_t BlastBondGeneratorImpl::createBondBetweenMeshes(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ uint32_t overlapsCount, const uint32_t* overlapsA, const uint32_t* overlapsB, NvBlastBondDesc*& resultBond, BondGenerationConfig cfg)
{
if (cfg.bondMode == BondGenerationConfig::AVERAGE)
{
resetGeometryCache();
- buildGeometryCache(geometry);
+ buildGeometryCache(meshCount, geometryOffset, geometry);
}
- resultBond.clear();
- resultBond.resize(overlaps.size());
+ resultBond = SAFE_ARRAY_NEW(NvBlastBondDesc, overlapsCount);
if (cfg.bondMode == BondGenerationConfig::EXACT)
{
- for (uint32_t i = 0; i < overlaps.size(); ++i)
+ for (uint32_t i = 0; i < overlapsCount; ++i)
{
- resultBond[i].chunkIndices[0] = overlaps[i].first;
- resultBond[i].chunkIndices[1] = overlaps[i].second;
- createBondBetweenMeshes(geometry[overlaps[i].first], geometry[overlaps[i].second], resultBond[i].bond, cfg);
+ NvBlastBondDesc& desc = resultBond[i];
+ desc.chunkIndices[0] = overlapsA[i];
+ desc.chunkIndices[1] = overlapsB[i];
+ uint32_t meshACount = geometryOffset[overlapsA[i] + 1] - geometryOffset[overlapsA[i]];
+ uint32_t meshBCount = geometryOffset[overlapsB[i] + 1] - geometryOffset[overlapsB[i]];
+ createBondBetweenMeshes(meshACount, geometry + geometryOffset[overlapsA[i]],
+ meshBCount, geometry + geometryOffset[overlapsB[i]], desc.bond, cfg);
}
}
else
{
- for (uint32_t i = 0; i < overlaps.size(); ++i)
+ for (uint32_t i = 0; i < overlapsCount; ++i)
{
- resultBond[i].chunkIndices[0] = overlaps[i].first;
- resultBond[i].chunkIndices[1] = overlaps[i].second;
- createBondForcedInternal(mHullsPointsCache[overlaps[i].first], mHullsPointsCache[overlaps[i].second], mCHullCache[overlaps[i].first], mCHullCache[overlaps[i].second],
- mBoundsCache[overlaps[i].first], mBoundsCache[overlaps[i].second], resultBond[i].bond, 0.3f);
+ NvBlastBondDesc& desc = resultBond[i];
+ desc.chunkIndices[0] = overlapsA[i];
+ desc.chunkIndices[1] = overlapsB[i];
+ createBondForcedInternal(mHullsPointsCache[overlapsA[i]], mHullsPointsCache[overlapsB[i]], *mCHullCache[overlapsA[i]], *mCHullCache[overlapsB[i]],
+ mBoundsCache[overlapsA[i]], mBoundsCache[overlapsB[i]], desc.bond, 0.3f);
}
}
- return 0;
+ return overlapsCount;
}
-
- int32_t BlastBondGenerator::createBondBetweenMeshes(const std::vector<Triangle>& meshA, const std::vector<Triangle>& meshB, NvBlastBond& resultBond, BondGenerationConfig conf)
+ int32_t BlastBondGeneratorImpl::createBondBetweenMeshes(uint32_t meshACount, const Triangle* meshA, uint32_t meshBCount, const Triangle* meshB,
+ NvBlastBond& resultBond, BondGenerationConfig conf)
{
float overlapping = 0.3;
if (conf.bondMode == BondGenerationConfig::EXACT)
{
- std::vector<std::vector<Triangle> > chunks;
- chunks.push_back(meshA);
- chunks.push_back(meshB);
- std::vector<bool> isSupport(2, true);
- std::vector<NvBlastBondDesc> desc;
- createFullBondListExact(chunks, isSupport, desc, conf);
- if (desc.size() > 0)
+ std::vector<uint32_t> chunksOffsets = { 0, meshACount, meshACount + meshBCount };
+ std::vector<Triangle> chunks;
+ chunks.resize(meshACount + meshBCount);
+ memcpy(chunks.data(), meshA, sizeof(Triangle) * meshACount);
+ memcpy(chunks.data() + meshACount, meshB, sizeof(Triangle) * meshBCount);
+ std::shared_ptr<bool> isSupport(new bool[2] {true, true}, [](bool* b) { delete[] b; });
+ NvBlastBondDesc* desc;
+ uint32_t descSize = createFullBondListExact(2, chunksOffsets.data(), chunks.data(), isSupport.get(), desc, conf);
+ if (descSize > 0)
{
- resultBond = desc.back().bond;
+ resultBond = desc->bond;
}
else
{
+ memset(&resultBond, 0, sizeof(NvBlastBond));
return 1;
}
return 0;
}
- std::vector<PxVec3> chunksPoints1(meshA.size() * 3);
- std::vector<PxVec3> chunksPoints2(meshB.size() * 3);
+ std::vector<PxVec3> chunksPoints1(meshACount * 3);
+ std::vector<PxVec3> chunksPoints2(meshBCount * 3);
int32_t sp = 0;
- for (uint32_t i = 0; i < meshA.size(); ++i)
+ for (uint32_t i = 0; i < meshACount; ++i)
{
chunksPoints1[sp++] = meshA[i].a.p;
chunksPoints1[sp++] = meshA[i].b.p;
@@ -943,7 +978,7 @@ namespace Nv
}
sp = 0;
- for (uint32_t i = 0; i < meshB.size(); ++i)
+ for (uint32_t i = 0; i < meshBCount; ++i)
{
chunksPoints2[sp++] = meshB[i].a.p;
chunksPoints2[sp++] = meshB[i].b.p;
@@ -956,16 +991,16 @@ namespace Nv
}
- Nv::Blast::ConvexMeshBuilder builder(mPxCooking, mPxInsertionCallback);
+ Nv::Blast::ConvexMeshBuilderImpl builder(mPxCooking, mPxInsertionCallback);
- CollisionHull cHull[2];
+ CollisionHull* cHull[2];
- builder.buildCollisionGeometry(chunksPoints1, cHull[0]);
- builder.buildCollisionGeometry(chunksPoints2, cHull[1]);
+ cHull[0] = builder.buildCollisionGeometry(chunksPoints1.size(), chunksPoints1.data());
+ cHull[1] = builder.buildCollisionGeometry(chunksPoints2.size(), chunksPoints2.data());
std::vector<PxVec3> hullPoints[2];
- hullPoints[0].resize(cHull[0].points.size());
- hullPoints[1].resize(cHull[1].points.size());
+ hullPoints[0].resize(cHull[0]->pointsCount);
+ hullPoints[1].resize(cHull[1]->pointsCount);
PxBounds3 bb[2];
@@ -974,18 +1009,40 @@ namespace Nv
for (uint32_t cv = 0; cv < 2; ++cv)
{
- for (uint32_t i = 0; i < cHull[cv].points.size(); ++i)
+ for (uint32_t i = 0; i < cHull[cv]->pointsCount; ++i)
{
- hullPoints[cv][i].x = cHull[cv].points[i].x;
- hullPoints[cv][i].y = cHull[cv].points[i].y;
- hullPoints[cv][i].z = cHull[cv].points[i].z;
+ hullPoints[cv][i] = cHull[cv]->points[i];
bb[cv].include(hullPoints[cv][i]);
}
}
- return createBondForcedInternal(hullPoints[0], hullPoints[1], cHull[0], cHull[1], bb[0], bb[1], resultBond, overlapping);
+ auto ret = createBondForcedInternal(hullPoints[0], hullPoints[1], *cHull[0], *cHull[1], bb[0], bb[1], resultBond, overlapping);
+
+ cHull[0]->release();
+ cHull[1]->release();
+
+ return ret;
}
+ int32_t BlastBondGeneratorImpl::bondsFromPrefractured(uint32_t meshCount, const uint32_t* geometryCount, const Triangle* geometry,
+ const bool*& chunkIsSupport, NvBlastBondDesc*& resultBondDescs, BondGenerationConfig conf)
+ {
+ int32_t ret_val = 0;
+ switch (conf.bondMode)
+ {
+ case BondGenerationConfig::AVERAGE:
+ ret_val = createFullBondListAveraged(meshCount, geometryCount, geometry, chunkIsSupport, resultBondDescs, conf);
+ break;
+ case BondGenerationConfig::EXACT:
+ ret_val = createFullBondListExact(meshCount, geometryCount, geometry, chunkIsSupport, resultBondDescs, conf);
+ break;
+ }
+ return ret_val;
+ }
+ void BlastBondGeneratorImpl::release()
+ {
+ delete this;
+ }
}
}
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.h
new file mode 100644
index 0000000..35c4b23
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringBondGeneratorImpl.h
@@ -0,0 +1,104 @@
+// 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) 2017 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTAUTHORINGBONDGENERATORIMPL_H
+#define NVBLASTEXTAUTHORINGBONDGENERATORIMPL_H
+
+#include "NvBlastExtAuthoringBondGenerator.h"
+#include "NvBlastExtAuthoringFractureTool.h"
+#include "../cooking/PxCooking.h"
+#include <PxPlane.h>
+#include <NvBlastExtAuthoringCollisionBuilder.h>
+#include <vector>
+
+namespace Nv
+{
+namespace Blast
+{
+
+/**
+ Tool for gathering bond information from provided mesh geometry
+*/
+
+class BlastBondGeneratorImpl : public BlastBondGenerator
+{
+public:
+
+ BlastBondGeneratorImpl(physx::PxCooking* cooking, physx::PxPhysicsInsertionCallback* insertionCallback)
+ : mPxCooking(cooking), mPxInsertionCallback(insertionCallback){};
+
+ virtual void release() override;
+
+ virtual int32_t buildDescFromInternalFracture(FractureTool* tool, const bool* chunkIsSupport,
+ NvBlastBondDesc*& resultBondDescs, NvBlastChunkDesc*& resultChunkDescriptors) override;
+
+ virtual int32_t createBondBetweenMeshes(uint32_t meshACount, const Triangle* meshA, uint32_t meshBCount, const Triangle* meshB,
+ NvBlastBond& resultBond, BondGenerationConfig conf = BondGenerationConfig()) override;
+
+ virtual int32_t createBondBetweenMeshes(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ uint32_t overlapsCount, const uint32_t* overlapsA, const uint32_t* overlapsB,
+ NvBlastBondDesc*& resultBond, BondGenerationConfig cfg) override;
+
+ virtual int32_t bondsFromPrefractured(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool*& chunkIsSupport, NvBlastBondDesc*& resultBondDescs,
+ BondGenerationConfig conf = BondGenerationConfig()) override;
+
+private:
+ float processWithMidplanes( TriangleProcessor* trProcessor,
+ const std::vector<physx::PxVec3>& chunk1Points, const std::vector<physx::PxVec3>& chunk2Points,
+ const std::vector<physx::PxVec3>& hull1p, const std::vector<physx::PxVec3>& hull2p,
+ physx::PxVec3& normal, physx::PxVec3& centroid);
+
+ int32_t createFullBondListAveraged( uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool* supportFlags, NvBlastBondDesc*& resultBondDescs, BondGenerationConfig conf);
+ int32_t createFullBondListExact( uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ const bool* supportFlags, NvBlastBondDesc*& resultBondDescs, BondGenerationConfig conf);
+ int32_t createFullBondListExactInternal(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry,
+ std::vector<PlaneChunkIndexer>& planeTriangleMapping , NvBlastBondDesc*& resultBondDescs);
+ int32_t createBondForcedInternal( const std::vector<physx::PxVec3>& hull0, const std::vector<physx::PxVec3>& hull1,const CollisionHull& cHull0,
+ const CollisionHull& cHull1, physx::PxBounds3 bound0, physx::PxBounds3 bound1, NvBlastBond& resultBond, float overlapping);
+
+ void buildGeometryCache(uint32_t meshCount, const uint32_t* geometryOffset, const Triangle* geometry);
+ void resetGeometryCache();
+
+ physx::PxCooking* mPxCooking;
+ physx::PxPhysicsInsertionCallback* mPxInsertionCallback;
+
+
+ std::vector<std::vector<Triangle> > mGeometryCache;
+
+ std::vector<PlaneChunkIndexer> mPlaneCache;
+ std::vector<CollisionHull*> mCHullCache;
+ std::vector<std::vector<physx::PxVec3> > mHullsPointsCache;
+ std::vector<physx::PxBounds3 > mBoundsCache;
+};
+
+} // namespace Blast
+} // namespace Nv
+
+#endif // NVBLASTEXTAUTHORINGBONDGENERATORIMPL_H \ No newline at end of file
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.cpp
index b5030d7..7705173 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.cpp
@@ -1,15 +1,34 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
+
+#include "NvBlastGlobals.h"
#include "NvBlastExtAuthoringBooleanTool.h"
-#include "NvBlastExtAuthoringMesh.h"
+#include "NvBlastExtAuthoringMeshImpl.h"
#include "NvBlastExtAuthoringAccelerator.h"
#include <math.h>
@@ -41,7 +60,6 @@ NV_FORCE_INLINE void vec2Lerp(const PxVec2& a, const PxVec2& b, PxVec2& out, flo
out.y = (b.y - a.y) * t + a.y;
}
-
NV_FORCE_INLINE int32_t BooleanEvaluator::addIfNotExist(Vertex& p)
{
mVerticesAggregate.push_back(p);
@@ -187,18 +205,26 @@ int32_t shadowing10(const PxVec3& sEdge, const PxVec3& eEdge, const PxVec3& p)
Vertex-facet shadowing functions
*/
-int32_t vfStatus02(const PxVec3& p, const Vertex* points, const Edge* edges, int32_t edgesCount, Vertex& out1, Vertex& out2)
+int32_t vfStatus02(const PxVec3& 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)
{
- out2 = out1;
- out1 = pnt;
+ 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;
}
@@ -208,24 +234,24 @@ int32_t vfStatus02(const PxVec3& p, const Vertex* points, const Edge* edges, int
int32_t shadowing02(const PxVec3& p, const Vertex* points, const Edge* edges, int edgesCount, bool& hasOnFacetPoint, Vertex& onFacetPoint)
{
- Vertex p1, p2;
- int32_t stat = vfStatus02(p, points, edges, edgesCount, p1, p2);
+ 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];
PxVec3 vc = p2.p - p1.p;
float t = 0;
- t = (abs(vc.x) > abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y;
- t = (t < 0) ? 0 : t;
- t = (t > 1) ? 1 : t;
- z = t * vc.z + p1.p.z;
+ t = (std::abs(vc.x) > std::abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y;
+ t = 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);
@@ -237,18 +263,27 @@ int32_t shadowing02(const PxVec3& p, const Vertex* points, const Edge* edges, in
return 0;
}
-int32_t vfStatus20(const PxVec3& p, const Vertex* points, const Edge* edges, int32_t edgesCount, Vertex& out1, Vertex& out2)
+int32_t vfStatus20(const PxVec3& 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)
{
- out2 = out1;
- out1 = pnt;
+ 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;
}
@@ -257,17 +292,18 @@ int32_t vfStatus20(const PxVec3& p, const Vertex* points, const Edge* edges, int
int32_t shadowing20(const PxVec3& p, const Vertex* points, const Edge* edges, int edgesCount, bool& hasOnFacetPoint, Vertex& onFacetPoint)
{
- Vertex p1, p2;
- int32_t stat = vfStatus20(p, points, edges, edgesCount, p1, p2);
+ 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];
PxVec3 vc = p2.p - p1.p;
float t = 0;
- t = (abs(vc.x) > abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y;
- t = (t < 0) ? 0 : t;
- t = (t > 1) ? 1 : t;
-
+ t = (std::abs(vc.x) > std::abs(vc.y)) ? (p.x - p1.p.x) / vc.x : (p.y - p1.p.y) / vc.y;
+ t = PxClamp(t, 0.0f, 1.0f);
+
hasOnFacetPoint = true;
onFacetPoint.p.x = p.x;
onFacetPoint.p.y = p.y;
@@ -291,91 +327,72 @@ NV_FORCE_INLINE int32_t edgesCrossCheck(const PxVec3& eAs, const PxVec3& eAe, co
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 tempPoint;
Vertex bShadowingPair[2];
Vertex aShadowingPair[2];
bool hasOnEdge = false;
- int32_t shadowingType = shadowing10(eAs, eAe, eBs.p, tempPoint, hasOnEdge);
-
bool aShadowing = false;
- bool bShadowing = false;
+ bool bShadowing = false;
+ /**
+ Search for two pairs where parts of A shadows B, and where B shadows are.
+ Needed for search intersection point.
+ */
- if (shadowingType == 0 && hasOnEdge)
- {
- aShadowing = true;
- aShadowingPair[0] = eBs;
- aShadowingPair[1] = tempPoint;
- }
- else
+ for (auto p : { &eBs, &eBe })
{
- if (shadowingType == 1 || shadowingType == -1)
+ int32_t shadowingType = shadowing10(eAs, eAe, p->p, tempPoint, hasOnEdge);
+ if (shadowingType == 0 && !aShadowing && hasOnEdge)
{
- bShadowing = true;
- bShadowingPair[0] = eBs;
- bShadowingPair[1] = tempPoint;
+ aShadowing = true;
+ aShadowingPair[0] = *p;
+ aShadowingPair[1] = tempPoint;
}
- }
-
- shadowingType = shadowing10(eAs, eAe, eBe.p, tempPoint, hasOnEdge);
-
- if (shadowingType == 0 && !aShadowing && hasOnEdge)
- {
- aShadowing = true;
- aShadowingPair[0] = eBe;
- aShadowingPair[1] = tempPoint;
- }
- else
- {
- if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ else
{
- bShadowing = true;
- bShadowingPair[0] = eBe;
- bShadowingPair[1] = tempPoint;
+ if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ {
+ bShadowing = true;
+ bShadowingPair[0] = *p;
+ bShadowingPair[1] = tempPoint;
+ }
}
}
- shadowingType = shadowing01(eBs, eBe, eAe.p, tempPoint, hasOnEdge);
-
- if (shadowingType == 0 && !aShadowing && hasOnEdge)
+ if (!aShadowing || !bShadowing)
{
- aShadowing = true;
- aShadowingPair[1] = eAe;
- aShadowingPair[0] = tempPoint;
- }
- else
- {
- if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ for (auto p : { &eAs, &eAe })
{
- bShadowing = true;
- bShadowingPair[1] = eAe;
- bShadowingPair[0] = tempPoint;
- }
- }
+ int32_t shadowingType = shadowing01(eBs, eBe, p->p, tempPoint, hasOnEdge);
- shadowingType = shadowing01(eBs, eBe, eAs.p, tempPoint, hasOnEdge);
-
- if (shadowingType == 0 && !aShadowing && hasOnEdge)
- {
- aShadowing = true;
- aShadowingPair[1] = eAs;
- aShadowingPair[0] = tempPoint;
- }
- else
- {
- if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
- {
- bShadowing = true;
- bShadowingPair[1] = eAs;
- bShadowingPair[0] = tempPoint;
+ 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;
@@ -413,43 +430,30 @@ int32_t edgeFacetIntersection12(const Vertex& edSt, const Vertex& edEnd, const V
Vertex bShadowingPair[2];
Vertex aShadowingPair[2];
bool hasPoint = false;
- int32_t shadowingType = shadowing02(edEnd.p, points, edges, edgesCount, hasPoint, p1);
- status -= shadowingType;
bool aShadowing = false;
bool bShadowing = false;
-
- if (shadowingType == 0 && hasPoint)
+ int32_t mlt = -1;
+ int32_t shadowingType;
+ for (auto p : { &edEnd, &edSt })
{
- aShadowing = true;
- aShadowingPair[0] = p1;
- aShadowingPair[1] = edEnd;
- }
- else
- {
- if (shadowingType == 1 || shadowingType == -1)
+ shadowingType = shadowing02(p->p, points, edges, edgesCount, hasPoint, p1);
+ status += mlt * shadowingType;
+ if (shadowingType == 0 && !aShadowing && hasPoint)
{
- bShadowing = true;
- bShadowingPair[0] = p1;
- bShadowingPair[1] = edEnd;
+ aShadowing = true;
+ aShadowingPair[0] = p1;
+ aShadowingPair[1] = *p;
}
- }
-
- shadowingType = shadowing02(edSt.p, points, edges, edgesCount, hasPoint, p1);
- status += shadowingType;
- if (shadowingType == 0 && !aShadowing && hasPoint)
- {
- aShadowing = true;
- aShadowingPair[0] = p1;
- aShadowingPair[1] = edSt;
- }
- else
- {
- if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ else
{
- bShadowing = true;
- bShadowingPair[0] = p1;
- bShadowingPair[1] = edSt;
+ if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ {
+ bShadowing = true;
+ bShadowingPair[0] = p1;
+ bShadowingPair[1] = *p;
+ }
}
+ mlt = 1;
}
for (int32_t ed = 0; ed < edgesCount; ++ed)
@@ -472,14 +476,11 @@ int32_t edgeFacetIntersection12(const Vertex& edSt, const Vertex& edEnd, const V
}
}
}
- if (status == 0)
- {
- return 0;
- }
- if (!bShadowing || !aShadowing)
+ if (!status || !bShadowing || !aShadowing)
{
return 0;
}
+
float deltaPlus = bShadowingPair[0].p.z - bShadowingPair[1].p.z;
float div = 0;
if (deltaPlus != 0)
@@ -508,42 +509,32 @@ int32_t edgeFacetIntersection21(const Vertex& edSt, const Vertex& edEnd, const V
Vertex bShadowingPair[2];
Vertex aShadowingPair[2];
bool hasPoint = false;
- int32_t shadowingType = shadowing20(edEnd.p, points, edges, edgesCount, hasPoint, p1);
- status = shadowingType;
bool aShadowing = false;
bool bShadowing = false;
- if (shadowingType == 0 && hasPoint)
- {
- aShadowing = true;
- aShadowingPair[0] = edEnd;
- aShadowingPair[1] = p1;
- }
- else
+
+ int32_t shadowingType;
+ int32_t mlt = 1;
+ for (auto p : { &edEnd, &edSt })
{
- if (shadowingType == 1 || shadowingType == -1)
+ shadowingType = shadowing20(p->p, points, edges, edgesCount, hasPoint, p1);
+ status += mlt * shadowingType;
+
+ if (shadowingType == 0 && !aShadowing && hasPoint)
{
- bShadowing = true;
- bShadowingPair[0] = edEnd;
- bShadowingPair[1] = p1;
+ aShadowing = true;
+ aShadowingPair[0] = *p;
+ aShadowingPair[1] = p1;
}
- }
-
- shadowingType = shadowing20(edSt.p, points, edges, edgesCount, hasPoint, p1);
- status -= shadowingType;
- if (shadowingType == 0 && !aShadowing && hasPoint)
- {
- aShadowing = true;
- aShadowingPair[0] = edSt;
- aShadowingPair[1] = p1;
- }
- else
- {
- if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ else
{
- bShadowing = true;
- bShadowingPair[0] = edSt;
- bShadowingPair[1] = p1;
+ if ((shadowingType == 1 || shadowingType == -1) && !bShadowing)
+ {
+ bShadowing = true;
+ bShadowingPair[0] = *p;
+ bShadowingPair[1] = p1;
+ }
}
+ mlt = -1;
}
for (int32_t ed = 0; ed < edgesCount; ++ed)
@@ -569,11 +560,7 @@ int32_t edgeFacetIntersection21(const Vertex& edSt, const Vertex& edEnd, const V
}
}
}
- if (status == 0)
- {
- return 0;
- }
- if (!bShadowing || !aShadowing)
+ if (!status || !bShadowing || !aShadowing)
{
return 0;
}
@@ -595,7 +582,7 @@ int32_t edgeFacetIntersection21(const Vertex& edSt, const Vertex& edEnd, const V
return status;
}
-int32_t BooleanEvaluator::vertexMeshStatus03(const PxVec3& p, Mesh* mesh)
+int32_t BooleanEvaluator::vertexMeshStatus03(const PxVec3& p, const Mesh* mesh)
{
int32_t status = 0;
Vertex pnt;
@@ -604,7 +591,7 @@ int32_t BooleanEvaluator::vertexMeshStatus03(const PxVec3& p, Mesh* mesh)
int32_t facet = mAcceleratorB->getNextFacet();
while (facet != -1)
{
- Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber;
+ const Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber;
status += shadowing02(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoint, pnt);
facet = mAcceleratorB->getNextFacet();
}
@@ -618,7 +605,7 @@ int32_t BooleanEvaluator::vertexMeshStatus03(const PxVec3& p, Mesh* mesh)
return status;
}
-int32_t BooleanEvaluator::vertexMeshStatus30(const PxVec3& p, Mesh* mesh)
+int32_t BooleanEvaluator::vertexMeshStatus30(const PxVec3& p, const Mesh* mesh)
{
int32_t status = 0;
bool hasPoints = false;
@@ -627,7 +614,7 @@ int32_t BooleanEvaluator::vertexMeshStatus30(const PxVec3& p, Mesh* mesh)
int32_t facet = mAcceleratorA->getNextFacet();
while ( facet != -1)
{
- Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber;
+ const Edge* ed = mesh->getEdges() + mesh->getFacet(facet)->firstEdgeNumber;
status -= shadowing20(p, mesh->getVertices(), ed, mesh->getFacet(facet)->edgesCount, hasPoints, point);
facet = mAcceleratorA->getNextFacet();
}
@@ -675,7 +662,7 @@ struct VertexPairComparator
}
};
-int32_t BooleanEvaluator::isPointContainedInMesh(Mesh* msh, const PxVec3& point)
+int32_t BooleanEvaluator::isPointContainedInMesh(const Mesh* msh, const PxVec3& point)
{
if (msh == nullptr)
{
@@ -687,7 +674,7 @@ int32_t BooleanEvaluator::isPointContainedInMesh(Mesh* msh, const PxVec3& point)
}
-int32_t BooleanEvaluator::isPointContainedInMesh(Mesh* msh, SpatialAccelerator* spAccel, const PxVec3& point)
+int32_t BooleanEvaluator::isPointContainedInMesh(const Mesh* msh, SpatialAccelerator* spAccel, const PxVec3& point)
{
if (msh == nullptr)
{
@@ -724,8 +711,8 @@ void BooleanEvaluator::buildFaceFaceIntersections(BooleanConf mode)
Vertex newPointA;
Vertex newPointB;
- Vertex* meshAPoints = mMeshA->getVertices();
- Vertex* meshBPoints = mMeshB->getVertices();
+ const Vertex* meshAPoints = mMeshA->getVertices();
+ const Vertex* meshBPoints = mMeshB->getVertices();
EdgeWithParent newEdge;
mEdgeFacetIntersectionData12.clear();
mEdgeFacetIntersectionData21.clear();
@@ -739,10 +726,10 @@ void BooleanEvaluator::buildFaceFaceIntersections(BooleanConf mode)
int32_t facetA = mAcceleratorA->getNextFacet();
while (facetA != -1)
{
- Edge* facetBEdges = mMeshB->getEdges() + mMeshB->getFacet(facetB)->firstEdgeNumber;
- Edge* facetAEdges = mMeshA->getEdges() + mMeshA->getFacet(facetA)->firstEdgeNumber;
- Edge* fbe = facetBEdges;
- Edge* fae = facetAEdges;
+ 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();
PxVec3 compositeEndPoint(0, 0, 0);
@@ -814,7 +801,7 @@ void BooleanEvaluator::buildFaceFaceIntersections(BooleanConf mode)
}
if (retainedStarts.size() != retainedEnds.size())
{
- NVBLAST_LOG_ERROR(mLoggingCallback, "Not equal number of starting and ending vertices! Probably input mesh has open edges.");
+ NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges.");
return;
}
if (retainedStarts.size() > 1)
@@ -856,7 +843,7 @@ void BooleanEvaluator::buildFastFaceFaceIntersection(BooleanConf mode)
Vertex newPointA;
Vertex newPointB;
- Vertex* meshAPoints = mMeshA->getVertices();
+ const Vertex* meshAPoints = mMeshA->getVertices();
EdgeWithParent newEdge;
mEdgeFacetIntersectionData12.clear();
@@ -867,10 +854,10 @@ void BooleanEvaluator::buildFastFaceFaceIntersection(BooleanConf mode)
for (uint32_t facetA = 0; facetA < mMeshA->getFacetCount(); ++facetA)
{
- Edge* facetAEdges = mMeshA->getEdges() + mMeshA->getFacet(facetA)->firstEdgeNumber;
+ const Edge* facetAEdges = mMeshA->getEdges() + mMeshA->getFacet(facetA)->firstEdgeNumber;
int32_t facetB = 0;
- Edge* facetBEdges = mMeshB->getEdges() + mMeshB->getFacet(facetB)->firstEdgeNumber;
- Edge* fae = facetAEdges;
+ const Edge* facetBEdges = mMeshB->getEdges() + mMeshB->getFacet(facetB)->firstEdgeNumber;
+ const Edge* fae = facetAEdges;
retainedStarts.clear();
retainedEnds.clear();
PxVec3 compositeEndPoint(0, 0, 0);
@@ -911,7 +898,7 @@ void BooleanEvaluator::buildFastFaceFaceIntersection(BooleanConf mode)
}
if (retainedStarts.size() != retainedEnds.size())
{
- NVBLAST_LOG_ERROR(mLoggingCallback, "Not equal number of starting and ending vertices! Probably input mesh has open edges.");
+ NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges.");
return;
}
if (retainedStarts.size() > 1)
@@ -942,11 +929,11 @@ void BooleanEvaluator::collectRetainedPartsFromA(BooleanConf mode)
int32_t statusValue = 0;
int32_t inclusionValue = 0;
- Vertex* vertices = mMeshA->getVertices();
+ const Vertex* vertices = mMeshA->getVertices();
Vertex newPoint;
VertexComparator comp;
- PxBounds3& bMeshBoudning = mMeshB->getBoundingBox();
- Edge* facetEdges = mMeshA->getEdges();
+ const PxBounds3& bMeshBoudning = mMeshB->getBoundingBox();
+ const Edge* facetEdges = mMeshA->getEdges();
std::vector<Vertex> retainedStartVertices;
std::vector<Vertex> retainedEndVertices;
retainedStartVertices.reserve(255);
@@ -1053,7 +1040,7 @@ void BooleanEvaluator::collectRetainedPartsFromA(BooleanConf mode)
facetEdges++;
if (retainedStartVertices.size() != retainedEndVertices.size())
{
- NVBLAST_LOG_ERROR(mLoggingCallback, "Not equal number of starting and ending vertices! Probably input mesh has open edges.");
+ NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges.");
return;
}
if (retainedEndVertices.size() > 1)
@@ -1082,11 +1069,11 @@ void BooleanEvaluator::collectRetainedPartsFromB(BooleanConf mode)
{
int32_t statusValue = 0;
int32_t inclusionValue = 0;
- Vertex* vertices = mMeshB->getVertices();
+ const Vertex* vertices = mMeshB->getVertices();
Vertex newPoint;
VertexComparator comp;
- PxBounds3& aMeshBoudning = mMeshA->getBoundingBox();
- Edge* facetEdges = mMeshB->getEdges();
+ const PxBounds3& aMeshBoudning = mMeshA->getBoundingBox();
+ const Edge* facetEdges = mMeshB->getEdges();
std::vector<Vertex> retainedStartVertices;
std::vector<Vertex> retainedEndVertices;
retainedStartVertices.reserve(255);
@@ -1194,7 +1181,7 @@ void BooleanEvaluator::collectRetainedPartsFromB(BooleanConf mode)
facetEdges++;
if (retainedStartVertices.size() != retainedEndVertices.size())
{
- NVBLAST_LOG_ERROR(mLoggingCallback, "Not equal number of starting and ending vertices! Probably input mesh has open edges.");
+ NVBLAST_LOG_ERROR("Not equal number of starting and ending vertices! Probably input mesh has open edges.");
return;
}
if (retainedEndVertices.size() - lastPos > 1)
@@ -1222,7 +1209,7 @@ bool EdgeWithParentSortComp(const EdgeWithParent& a, const EdgeWithParent& b)
}
-void BooleanEvaluator::performBoolean(Mesh* meshA, Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode)
+void BooleanEvaluator::performBoolean(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode)
{
reset();
mMeshA = meshA;
@@ -1236,7 +1223,7 @@ void BooleanEvaluator::performBoolean(Mesh* meshA, Mesh* meshB, SpatialAccelerat
mAcceleratorB = nullptr;
}
-void BooleanEvaluator::performBoolean(Mesh* meshA, Mesh* meshB, BooleanConf mode)
+void BooleanEvaluator::performBoolean(const Mesh* meshA, const Mesh* meshB, BooleanConf mode)
{
reset();
mMeshA = meshA;
@@ -1247,7 +1234,7 @@ void BooleanEvaluator::performBoolean(Mesh* meshA, Mesh* meshB, BooleanConf mode
}
-void BooleanEvaluator::performFastCutting(Mesh* meshA, Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode)
+void BooleanEvaluator::performFastCutting(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode)
{
reset();
mMeshA = meshA;
@@ -1260,7 +1247,7 @@ void BooleanEvaluator::performFastCutting(Mesh* meshA, Mesh* meshB, SpatialAccel
mAcceleratorB = nullptr;
}
-void BooleanEvaluator::performFastCutting(Mesh* meshA, Mesh* meshB, BooleanConf mode)
+void BooleanEvaluator::performFastCutting(const Mesh* meshA, const Mesh* meshB, BooleanConf mode)
{
reset();
mMeshA = meshA;
@@ -1273,13 +1260,12 @@ void BooleanEvaluator::performFastCutting(Mesh* meshA, Mesh* meshB, BooleanConf
-BooleanEvaluator::BooleanEvaluator(NvBlastLog loggingCallback)
+BooleanEvaluator::BooleanEvaluator()
{
mMeshA = nullptr;
mMeshB = nullptr;
mAcceleratorA = nullptr;
mAcceleratorB = nullptr;
- mLoggingCallback = loggingCallback;
}
BooleanEvaluator::~BooleanEvaluator()
{
@@ -1301,6 +1287,7 @@ Mesh* BooleanEvaluator::createNewMesh()
int32_t lastParent = mEdgeAggregate[0].parent;
uint32_t collected = 0;
int32_t userData = 0;
+ int32_t materialId = 0;
for (uint32_t i = 0; i < mEdgeAggregate.size(); ++i)
{
if (mEdgeAggregate[i].parent != lastParent)
@@ -1308,12 +1295,14 @@ Mesh* BooleanEvaluator::createNewMesh()
if (lastParent < (int32_t)mMeshA->getFacetCount())
{
userData = mMeshA->getFacet(lastParent)->userData;
+ materialId = mMeshA->getFacet(lastParent)->materialId;
}
else
{
userData = mMeshB->getFacet(lastParent - mMeshA->getFacetCount())->userData;
+ materialId = mMeshB->getFacet(lastParent - mMeshA->getFacetCount())->materialId;
}
- newFacets.push_back(Facet(lastPos, collected, userData));
+ newFacets.push_back(Facet(lastPos, collected, materialId, userData));
lastPos = i;
lastParent = mEdgeAggregate[i].parent;
collected = 0;
@@ -1326,13 +1315,16 @@ Mesh* BooleanEvaluator::createNewMesh()
if (lastParent < (int32_t)mMeshA->getFacetCount())
{
userData = mMeshA->getFacet(lastParent)->userData;
+ materialId = mMeshA->getFacet(lastParent)->materialId;
+
}
else
{
userData = mMeshB->getFacet(pr)->userData;
+ materialId = mMeshB->getFacet(pr)->materialId;
}
- newFacets.push_back(Facet(lastPos, collected, userData));
- return new Mesh(&mVerticesAggregate[0], &newEdges[0], &newFacets[0], static_cast<uint32_t>(mVerticesAggregate.size()), static_cast<uint32_t>(mEdgeAggregate.size()), static_cast<uint32_t>(newFacets.size()));
+ newFacets.push_back(Facet(lastPos, collected, materialId, userData));
+ return new MeshImpl(mVerticesAggregate.data(), newEdges.data(), newFacets.data(), static_cast<uint32_t>(mVerticesAggregate.size()), static_cast<uint32_t>(mEdgeAggregate.size()), static_cast<uint32_t>(newFacets.size()));
}
void BooleanEvaluator::reset()
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.h
index 0b0b73a..f362495 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringBooleanTool.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGBOOLEANTOOL_H
#define NVBLASTEXTAUTHORINGBOOLEANTOOL_H
@@ -92,7 +110,7 @@ class BooleanEvaluator
{
public:
- BooleanEvaluator(NvBlastLog logCallback = nullptr);
+ BooleanEvaluator();
~BooleanEvaluator();
/**
@@ -103,7 +121,7 @@ public:
\param[in] spAccelB Acceleration structure for mesh B
\param[in] mode Boolean operation type
*/
- void performBoolean(Mesh* meshA, Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode);
+ void performBoolean(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode);
/**
Perform boolean operation on two polygonal meshes (A and B).
@@ -111,7 +129,7 @@ public:
\param[in] meshB Mesh B
\param[in] mode Boolean operation type
*/
- void performBoolean(Mesh* meshA, Mesh* meshB, BooleanConf mode);
+ void performBoolean(const Mesh* meshA, const Mesh* meshB, BooleanConf mode);
/**
Perform cutting of mesh with some large box, which represents cutting plane. This method skips part of intersetion computations, so
@@ -122,7 +140,7 @@ public:
\param[in] spAccelB Acceleration structure for cutting box
\param[in] mode Boolean operation type
*/
- void performFastCutting(Mesh* meshA, Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode);
+ void performFastCutting(const Mesh* meshA, const Mesh* meshB, SpatialAccelerator* spAccelA, SpatialAccelerator* spAccelB, BooleanConf mode);
/**
Perform cutting of mesh with some large box, which represents cutting plane. This method skips part of intersetion computations, so
@@ -131,7 +149,7 @@ public:
\param[in] meshB Cutting box
\param[in] mode Boolean operation type
*/
- void performFastCutting(Mesh* meshA, Mesh* meshB, BooleanConf mode);
+ void performFastCutting(const Mesh* meshA, const Mesh* meshB, BooleanConf mode);
/**
Test whether point contained in mesh.
@@ -139,7 +157,7 @@ public:
\param[in] point Point which should be tested
\return not 0 if point is inside of mesh
*/
- int32_t isPointContainedInMesh(Mesh* mesh, const physx::PxVec3& point);
+ int32_t isPointContainedInMesh(const Mesh* mesh, const physx::PxVec3& point);
/**
Test whether point contained in mesh.
\param[in] mesh Mesh geometry
@@ -147,7 +165,7 @@ public:
\param[in] point Point which should be tested
\return not 0 if point is inside of mesh
*/
- int32_t isPointContainedInMesh(Mesh* mesh, SpatialAccelerator* spAccel, const physx::PxVec3& point);
+ int32_t isPointContainedInMesh(const Mesh* mesh, SpatialAccelerator* spAccel, const physx::PxVec3& point);
/**
@@ -172,11 +190,11 @@ private:
void addEdgeIfValid(EdgeWithParent& ed);
private:
- int32_t vertexMeshStatus03(const physx::PxVec3& p, Mesh* mesh);
- int32_t vertexMeshStatus30(const physx::PxVec3& p, Mesh* mesh);
+ int32_t vertexMeshStatus03(const physx::PxVec3& p, const Mesh* mesh);
+ int32_t vertexMeshStatus30(const physx::PxVec3& p, const Mesh* mesh);
- Mesh* mMeshA;
- Mesh* mMeshB;
+ const Mesh* mMeshA;
+ const Mesh* mMeshB;
SpatialAccelerator* mAcceleratorA;
SpatialAccelerator* mAcceleratorB;
@@ -186,8 +204,6 @@ private:
std::vector<std::vector<EdgeFacetIntersectionData> > mEdgeFacetIntersectionData12;
std::vector<std::vector<EdgeFacetIntersectionData> > mEdgeFacetIntersectionData21;
-
- NvBlastLog mLoggingCallback;
};
} // namespace Blast
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilder.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.cpp
index becdce9..39c7586 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilder.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.cpp
@@ -1,14 +1,32 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
-#include "NvBlastExtAuthoringCollisionBuilder.h"
+
+#include "NvBlastExtAuthoringCollisionBuilderImpl.h"
#include <PxConvexMesh.h>
#include <PxVec3.h>
#include <PxBounds3.h>
@@ -18,18 +36,31 @@
#include <NvBlastExtAuthoringInternalCommon.h>
#include <NvBlastExtAuthoringBooleanTool.h>
-#include <NvBlastExtAuthoringMesh.h>
+#include <NvBlastExtAuthoringMeshImpl.h>
using namespace physx;
+#define SAFE_ARRAY_NEW(T, x) ((x) > 0) ? new T[x] : nullptr;
+#define SAFE_ARRAY_DELETE(x) if (x != nullptr) {delete[] x; x = nullptr;}
+
namespace Nv
{
namespace Blast
{
-void ConvexMeshBuilder::buildCollisionGeometry(const std::vector<PxVec3>& vData, CollisionHull& output)
+void CollisionHullImpl::release()
+{
+ SAFE_ARRAY_DELETE(points);
+ SAFE_ARRAY_DELETE(indices);
+ SAFE_ARRAY_DELETE(polygonData);
+ delete this;
+}
+
+CollisionHull* ConvexMeshBuilderImpl::buildCollisionGeometry(uint32_t verticesCount, const physx::PxVec3* vData)
{
- std::vector<physx::PxVec3> vertexData = vData;
+ CollisionHull* output = new CollisionHullImpl();
+ std::vector<physx::PxVec3> vertexData(verticesCount);
+ memcpy(vertexData.data(), vData, sizeof(physx::PxVec3) * verticesCount);
PxConvexMeshDesc convexMeshDescr;
PxConvexMesh* resultConvexMesh;
@@ -72,13 +103,16 @@ void ConvexMeshBuilder::buildCollisionGeometry(const std::vector<PxVec3>& vData,
convexMeshDescr.points.count = (uint32_t)vertexData.size();
resultConvexMesh = mCooking->createConvexMesh(convexMeshDescr, *mInsertionCallback);
}
- output.polygonData.resize(resultConvexMesh->getNbPolygons());
- output.points.resize(resultConvexMesh->getNbVertices());
+ output->polygonDataCount = resultConvexMesh->getNbPolygons();
+ if (output->polygonDataCount)
+ output->polygonData = SAFE_ARRAY_NEW(CollisionHull::HullPolygon, output->polygonDataCount);
+ output->pointsCount = resultConvexMesh->getNbVertices();
+ output->points = SAFE_ARRAY_NEW(PxVec3, output->pointsCount);
int32_t indicesCount = 0;
PxHullPolygon hPoly;
for (uint32_t i = 0; i < resultConvexMesh->getNbPolygons(); ++i)
{
- CollisionHull::HullPolygon& pd = output.polygonData[i];
+ CollisionHull::HullPolygon& pd = output->polygonData[i];
resultConvexMesh->getPolygonData(i, hPoly);
pd.mIndexBase = hPoly.mIndexBase;
pd.mNbVerts = hPoly.mNbVerts;
@@ -98,47 +132,49 @@ void ConvexMeshBuilder::buildCollisionGeometry(const std::vector<PxVec3>& vData,
pd.mPlane[3] /= length;
indicesCount = PxMax(indicesCount, pd.mIndexBase + pd.mNbVerts);
}
- output.indices.resize(indicesCount);
+ output->indicesCount = indicesCount;
+ output->indices = SAFE_ARRAY_NEW(uint32_t, indicesCount);
for (uint32_t i = 0; i < resultConvexMesh->getNbVertices(); ++i)
{
PxVec3 p = resultConvexMesh->getVertices()[i] * scale + bbCenter;
- output.points[i] = p;
+ output->points[i] = p;
}
for (int32_t i = 0; i < indicesCount; ++i)
{
- output.indices[i] = resultConvexMesh->getIndexBuffer()[i];
+ output->indices[i] = resultConvexMesh->getIndexBuffer()[i];
}
resultConvexMesh->release();
+ return output;
}
-void ConvexMeshBuilder::trimCollisionGeometry(std::vector<CollisionHull>& in, const std::vector<uint32_t>& chunkDepth)
+void ConvexMeshBuilderImpl::trimCollisionGeometry(uint32_t chunksCount, CollisionHull** in, const uint32_t* chunkDepth)
{
- std::vector<std::vector<PxPlane> > chunkMidplanes(in.size());
- std::vector<PxVec3> centers(in.size());
- std::vector<PxBounds3> hullsBounds(in.size());
- for (uint32_t i = 0; i < in.size(); ++i)
+ std::vector<std::vector<PxPlane> > chunkMidplanes(chunksCount);
+ std::vector<PxVec3> centers(chunksCount);
+ std::vector<PxBounds3> hullsBounds(chunksCount);
+ for (uint32_t i = 0; i < chunksCount; ++i)
{
hullsBounds[i].setEmpty();
centers[i] = PxVec3(0, 0, 0);
- for (uint32_t p = 0; p < in[i].points.size(); ++p)
+ for (uint32_t p = 0; p < in[i]->pointsCount; ++p)
{
- centers[i] += in[i].points[p];
- hullsBounds[i].include(in[i].points[p]);
+ centers[i] += in[i]->points[p];
+ hullsBounds[i].include(in[i]->points[p]);
}
centers[i] = hullsBounds[i].getCenter();
}
Separation params;
- for (uint32_t hull = 0; hull < in.size(); ++hull)
+ for (uint32_t hull = 0; hull < chunksCount; ++hull)
{
- for (uint32_t hull2 = hull + 1; hull2 < in.size(); ++hull2)
+ for (uint32_t hull2 = hull + 1; hull2 < chunksCount; ++hull2)
{
if (chunkDepth[hull] != chunkDepth[hull2])
{
continue;
}
- if (importerHullsInProximityApexFree(in[hull].points, hullsBounds[hull], PxTransform(PxIdentity), PxVec3(1, 1, 1),
- in[hull2].points, hullsBounds[hull2], PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.0, &params) == false)
+ if (importerHullsInProximityApexFree(in[hull]->pointsCount, in[hull]->points, hullsBounds[hull], PxTransform(PxIdentity), PxVec3(1, 1, 1),
+ in[hull2]->pointsCount, in[hull2]->points, hullsBounds[hull2], PxTransform(PxIdentity), PxVec3(1, 1, 1), 0.0, &params) == false)
{
continue;
}
@@ -147,22 +183,22 @@ void ConvexMeshBuilder::trimCollisionGeometry(std::vector<CollisionHull>& in, co
float d = FLT_MAX;
PxVec3 n1;
PxVec3 n2;
- for (uint32_t p = 0; p < in[hull].points.size(); ++p)
+ for (uint32_t p = 0; p < in[hull]->pointsCount; ++p)
{
- float ld = (in[hull].points[p] - c2).magnitude();
+ float ld = (in[hull]->points[p] - c2).magnitude();
if (ld < d)
{
- n1 = in[hull].points[p];
+ n1 = in[hull]->points[p];
d = ld;
}
}
d = FLT_MAX;
- for (uint32_t p = 0; p < in[hull2].points.size(); ++p)
+ for (uint32_t p = 0; p < in[hull2]->pointsCount; ++p)
{
- float ld = (in[hull2].points[p] - c1).magnitude();
+ float ld = (in[hull2]->points[p] - c1).magnitude();
if (ld < d)
{
- n2 = in[hull2].points[p];
+ n2 = in[hull2]->points[p];
d = ld;
}
}
@@ -176,31 +212,32 @@ void ConvexMeshBuilder::trimCollisionGeometry(std::vector<CollisionHull>& in, co
}
}
std::vector<PxVec3> hPoints;
- for (uint32_t i = 0; i < in.size(); ++i)
+ for (uint32_t i = 0; i < chunksCount; ++i)
{
std::vector<Facet> facets;
std::vector<Vertex> vertices;
std::vector<Edge> edges;
- for (uint32_t fc = 0; fc < in[i].polygonData.size(); ++fc)
+ for (uint32_t fc = 0; fc < in[i]->polygonDataCount; ++fc)
{
Facet nFc;
nFc.firstEdgeNumber = edges.size();
- uint32_t n = in[i].polygonData[fc].mNbVerts;
+ auto& pd = in[i]->polygonData[fc];
+ uint32_t n = pd.mNbVerts;
for (uint32_t ed = 0; ed < n; ++ed)
{
- uint32_t vr1 = in[i].indices[(ed) + in[i].polygonData[fc].mIndexBase];
- uint32_t vr2 = in[i].indices[(ed + 1) % n + in[i].polygonData[fc].mIndexBase];
+ uint32_t vr1 = in[i]->indices[(ed) + pd.mIndexBase];
+ uint32_t vr2 = in[i]->indices[(ed + 1) % n + pd.mIndexBase];
edges.push_back(Edge(vr1, vr2));
}
nFc.edgesCount = n;
facets.push_back(nFc);
}
- vertices.resize(in[i].points.size());
- for (uint32_t vr = 0; vr < in[i].points.size(); ++vr)
+ vertices.resize(in[i]->pointsCount);
+ for (uint32_t vr = 0; vr < in[i]->pointsCount; ++vr)
{
- vertices[vr].p = in[i].points[vr];
+ vertices[vr].p = in[i]->points[vr];
}
- Mesh* hullMesh = new Mesh(vertices.data(), edges.data(), facets.data(), vertices.size(), edges.size(), facets.size());
+ Mesh* hullMesh = new MeshImpl(vertices.data(), edges.data(), facets.data(), vertices.size(), edges.size(), facets.size());
BooleanEvaluator evl;
Mesh* cuttingMesh = getCuttingBox(PxVec3(0, 0, 0), PxVec3(0, 0, 1), 40, 0);
for (uint32_t p = 0; p < chunkMidplanes[i].size(); ++p)
@@ -228,52 +265,60 @@ void ConvexMeshBuilder::trimCollisionGeometry(std::vector<CollisionHull>& in, co
hPoints[v] = hullMesh->getVertices()[v].p;
}
delete hullMesh;
- buildCollisionGeometry(hPoints, in[i]);
+ if (in[i] != nullptr)
+ {
+ in[i]->release();
+ }
+ in[i] = buildCollisionGeometry(hPoints.size(), hPoints.data());
}
}
-PxConvexMesh* ConvexMeshBuilder::buildConvexMesh(std::vector<PxVec3>& vertexData)
+PxConvexMesh* ConvexMeshBuilderImpl::buildConvexMesh(uint32_t verticesCount, const physx::PxVec3* vertexData)
{
- CollisionHull hull;
- buildCollisionGeometry(vertexData, hull);
+ CollisionHull* hull = buildCollisionGeometry(verticesCount, vertexData);
PxConvexMeshDesc convexMeshDescr;
- convexMeshDescr.indices.data = hull.indices.data();
- convexMeshDescr.indices.count = (uint32_t)hull.indices.size();
+ convexMeshDescr.indices.data = hull->indices;
+ convexMeshDescr.indices.count = (uint32_t)hull->indicesCount;
convexMeshDescr.indices.stride = sizeof(uint32_t);
- convexMeshDescr.points.data = hull.points.data();
- convexMeshDescr.points.count = (uint32_t)hull.points.size();
+ convexMeshDescr.points.data = hull->points;
+ convexMeshDescr.points.count = (uint32_t)hull->pointsCount;
convexMeshDescr.points.stride = sizeof(PxVec3);
- convexMeshDescr.polygons.data = hull.polygonData.data();
- convexMeshDescr.polygons.count = (uint32_t)hull.polygonData.size();
+ convexMeshDescr.polygons.data = hull->polygonData;
+ convexMeshDescr.polygons.count = (uint32_t)hull->polygonDataCount;
convexMeshDescr.polygons.stride = sizeof(PxHullPolygon);
PxConvexMesh* convexMesh = mCooking->createConvexMesh(convexMeshDescr, *mInsertionCallback);
+ hull->release();
return convexMesh;
}
-PxConvexMesh* ConvexMeshBuilder::buildConvexMesh(CollisionHull& hull)
+PxConvexMesh* ConvexMeshBuilderImpl::buildConvexMesh(const CollisionHull& hull)
{
PxConvexMeshDesc convexMeshDescr;
- convexMeshDescr.indices.data = hull.indices.data();
- convexMeshDescr.indices.count = (uint32_t)hull.indices.size();
+ convexMeshDescr.indices.data = hull.indices;
+ convexMeshDescr.indices.count = (uint32_t)hull.indicesCount;
convexMeshDescr.indices.stride = sizeof(uint32_t);
- convexMeshDescr.points.data = hull.points.data();
- convexMeshDescr.points.count = (uint32_t)hull.points.size();
+ convexMeshDescr.points.data = hull.points;
+ convexMeshDescr.points.count = (uint32_t)hull.pointsCount;
convexMeshDescr.points.stride = sizeof(PxVec3);
- convexMeshDescr.polygons.data = hull.polygonData.data();
- convexMeshDescr.polygons.count = (uint32_t)hull.polygonData.size();
+ convexMeshDescr.polygons.data = hull.polygonData;
+ convexMeshDescr.polygons.count = (uint32_t)hull.polygonDataCount;
convexMeshDescr.polygons.stride = sizeof(PxHullPolygon);
PxConvexMesh* convexMesh = mCooking->createConvexMesh(convexMeshDescr, *mInsertionCallback);
return convexMesh;
}
+void ConvexMeshBuilderImpl::release()
+{
+ delete this;
+}
} // namespace Blast
} // namespace Nv
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.h
new file mode 100644
index 0000000..709c880
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringCollisionBuilderImpl.h
@@ -0,0 +1,73 @@
+// 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-2017 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTAUTHORINGCOLLISIONBUILDERIIMPL_H
+#define NVBLASTEXTAUTHORINGCOLLISIONBUILDERIIMPL_H
+
+#include "NvBlastExtAuthoringCollisionBuilder.h"
+#include "NvBlastExtAuthoringTypes.h"
+
+namespace Nv
+{
+namespace Blast
+{
+
+struct CollisionHullImpl : public CollisionHull
+{
+ void release() override;
+};
+
+class ConvexMeshBuilderImpl : public ConvexMeshBuilder
+{
+public:
+
+ /**
+ Constructor should be provided with PxCoocking and PxPhysicsInsertionCallback objects.
+ */
+ ConvexMeshBuilderImpl(physx::PxCooking* cooking, physx::PxPhysicsInsertionCallback* insertionCallback) : mInsertionCallback(insertionCallback), mCooking(cooking) {}
+
+ virtual void release() override;
+
+ virtual CollisionHull* buildCollisionGeometry(uint32_t verticesCount, const physx::PxVec3* vertexData) override;
+
+ virtual physx::PxConvexMesh* buildConvexMesh(uint32_t verticesCount, const physx::PxVec3* vertexData) override;
+
+ virtual physx::PxConvexMesh* buildConvexMesh(const CollisionHull& hull) override;
+
+ virtual void trimCollisionGeometry(uint32_t chunksCount, CollisionHull** in, const uint32_t* chunkDepth) override;
+
+private:
+ physx::PxPhysicsInsertionCallback* mInsertionCallback;
+ physx::PxCooking* mCooking;
+};
+
+} // namespace Blast
+} // namespace Nv
+
+
+#endif // ifndef NVBLASTEXTAUTHORINGCOLLISIONBUILDERIIMPL_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureTool.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.cpp
index 48830fe..91c81bc 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureTool.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.cpp
@@ -8,7 +8,9 @@
* license agreement from NVIDIA CORPORATION is strictly prohibited.
*/
-#include "NvBlastExtAuthoringFractureTool.h"
+#include "NvBlastExtAuthoringFractureToolImpl.h"
+#include "NvBlastExtAuthoringMeshImpl.h"
+
// 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
#if NV_VC && NV_VC < 14
@@ -22,6 +24,7 @@
#include "NvBlastExtAuthoringBooleanTool.h"
#include "NvBlastExtAuthoringAccelerator.h"
#include "NvBlast.h"
+#include "NvBlastGlobals.h"
#include "NvBlastExtAuthoringPerlinNoise.h"
#include <NvBlastAssert.h>
using namespace physx;
@@ -133,7 +136,7 @@ bool blastBondComparator(const NvBlastBondDesc& a, const NvBlastBondDesc& b)
#define MAX_VORONOI_ATTEMPT_NUMBER 450
-VoronoiSitesGenerator::VoronoiSitesGenerator(Mesh* mesh, RandomGeneratorBase* rnd)
+VoronoiSitesGeneratorImpl::VoronoiSitesGeneratorImpl(const Mesh* mesh, RandomGeneratorBase* rnd)
{
mMesh = mesh;
mRnd = rnd;
@@ -141,7 +144,7 @@ VoronoiSitesGenerator::VoronoiSitesGenerator(Mesh* mesh, RandomGeneratorBase* rn
mStencil = nullptr;
}
-void VoronoiSitesGenerator::setBaseMesh(Mesh* m)
+void VoronoiSitesGeneratorImpl::setBaseMesh(const Mesh* m)
{
mGeneratedSites.clear();
delete mAccelerator;
@@ -149,28 +152,32 @@ void VoronoiSitesGenerator::setBaseMesh(Mesh* m)
mAccelerator = new BBoxBasedAccelerator(mMesh, DEFAULT_BB_ACCELARATOR_RES);
}
-VoronoiSitesGenerator::~VoronoiSitesGenerator()
+VoronoiSitesGeneratorImpl::~VoronoiSitesGeneratorImpl()
{
delete mAccelerator;
mAccelerator = nullptr;
}
+void VoronoiSitesGeneratorImpl::release()
+{
+ delete this;
+}
-void VoronoiSitesGenerator::setStencil(Mesh* stencil)
+void VoronoiSitesGeneratorImpl::setStencil(const Mesh* stencil)
{
mStencil = stencil;
}
-void VoronoiSitesGenerator::clearStencil()
+void VoronoiSitesGeneratorImpl::clearStencil()
{
mStencil = nullptr;
}
-void VoronoiSitesGenerator::uniformlyGenerateSitesInMesh(const uint32_t sitesCount)
+void VoronoiSitesGeneratorImpl::uniformlyGenerateSitesInMesh(const uint32_t sitesCount)
{
- BooleanEvaluator voronoiMeshEval(nullptr);
+ BooleanEvaluator voronoiMeshEval;
PxVec3 mn = mMesh->getBoundingBox().minimum;
PxVec3 mx = mMesh->getBoundingBox().maximum;
PxVec3 vc = mx - mn;
@@ -198,9 +205,9 @@ void VoronoiSitesGenerator::uniformlyGenerateSitesInMesh(const uint32_t sitesCou
}
-void VoronoiSitesGenerator::clusteredSitesGeneration(const uint32_t numberOfClusters, const uint32_t sitesPerCluster, float clusterRadius)
+void VoronoiSitesGeneratorImpl::clusteredSitesGeneration(const uint32_t numberOfClusters, const uint32_t sitesPerCluster, float clusterRadius)
{
- BooleanEvaluator voronoiMeshEval(nullptr);
+ BooleanEvaluator voronoiMeshEval;
PxVec3 mn = mMesh->getBoundingBox().minimum;
PxVec3 mx = mMesh->getBoundingBox().maximum;
PxVec3 middle = (mx + mn) * 0.5;
@@ -260,15 +267,15 @@ void VoronoiSitesGenerator::clusteredSitesGeneration(const uint32_t numberOfClus
#define IN_SPHERE_ATTEMPT_NUMBER 20
-void VoronoiSitesGenerator::addSite(const physx::PxVec3& site)
+void VoronoiSitesGeneratorImpl::addSite(const physx::PxVec3& site)
{
mGeneratedSites.push_back(site);
}
-void VoronoiSitesGenerator::generateInSphere(const uint32_t count, const float radius, const physx::PxVec3& center)
+void VoronoiSitesGeneratorImpl::generateInSphere(const uint32_t count, const float radius, const physx::PxVec3& center)
{
- BooleanEvaluator voronoiMeshEval(nullptr);
+ BooleanEvaluator voronoiMeshEval;
uint32_t attemptNumber = 0;
uint32_t generatedSites = 0;
std::vector<PxVec3> tempPoints;
@@ -295,7 +302,7 @@ void VoronoiSitesGenerator::generateInSphere(const uint32_t count, const float r
}
-void VoronoiSitesGenerator::deleteInSphere(const float radius, const physx::PxVec3& center, float deleteProbability)
+void VoronoiSitesGeneratorImpl::deleteInSphere(const float radius, const physx::PxVec3& center, float deleteProbability)
{
float r2 = radius * radius;
for (uint32_t i = 0; i < mGeneratedSites.size(); ++i)
@@ -310,11 +317,11 @@ void VoronoiSitesGenerator::deleteInSphere(const float radius, const physx::PxVe
}
-void VoronoiSitesGenerator::radialPattern(const physx::PxVec3& center, const physx::PxVec3& normal, float radius, int32_t angularSteps, int32_t radialSteps, float angleOffset, float variability)
+void VoronoiSitesGeneratorImpl::radialPattern(const physx::PxVec3& center, const physx::PxVec3& normal, float radius, int32_t angularSteps, int32_t radialSteps, float angleOffset, float variability)
{
// mGeneratedSites.push_back(center);
physx::PxVec3 t1, t2;
- if (abs(normal.z) < 0.9)
+ if (std::abs(normal.z) < 0.9)
{
t1 = normal.cross(PxVec3(0, 0, 1));
}
@@ -346,14 +353,16 @@ void VoronoiSitesGenerator::radialPattern(const physx::PxVec3& center, const phy
}
}
-
-std::vector<PxVec3>& VoronoiSitesGenerator::getVoronoiSites()
+uint32_t VoronoiSitesGeneratorImpl::getVoronoiSites(const physx::PxVec3*& sites)
{
- return mGeneratedSites;
+ if (mGeneratedSites.size())
+ {
+ sites = &mGeneratedSites[0];
+ }
+ return (uint32_t)mGeneratedSites.size();
}
-
-int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<physx::PxVec3>& cellPointsIn, bool replaceChunk)
+int32_t FractureToolImpl::voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPointsIn, bool replaceChunk)
{
if (chunkId == 0 && replaceChunk)
{
@@ -361,7 +370,7 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
}
int32_t chunkIndex = getChunkIndex(chunkId);
- if (chunkIndex == -1 || cellPointsIn.size() < 2)
+ if (chunkIndex == -1 || cellCount < 2)
{
return 1;
}
@@ -373,8 +382,8 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
Mesh* mesh = mChunkData[chunkIndex].meshData;
- std::vector<PxVec3> cellPoints(cellPointsIn.size());
- for (uint32_t i = 0; i < cellPointsIn.size(); ++i)
+ std::vector<PxVec3> cellPoints(cellCount);
+ for (uint32_t i = 0; i < cellCount; ++i)
{
cellPoints[i] = (cellPointsIn[i] - mOffset) * (1.0f / mScaleFactor);
}
@@ -382,8 +391,8 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
/**
Prebuild accelerator structure
*/
- BooleanEvaluator eval(mLoggingCallback);
- BooleanEvaluator voronoiMeshEval(mLoggingCallback);
+ BooleanEvaluator eval;
+ BooleanEvaluator voronoiMeshEval;
BBoxBasedAccelerator spAccel = BBoxBasedAccelerator(mesh, DEFAULT_BB_ACCELARATOR_RES);
@@ -436,20 +445,86 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
return 0;
}
-Mesh FractureTool::getChunkMesh(int32_t chunkId)
+Mesh* FractureToolImpl::createChunkMesh(int32_t chunkId)
{
- Mesh temp = *mChunkData[getChunkIndex(chunkId)].meshData;
- for (uint32_t i = 0; i < temp.getVerticesCount(); ++i)
+ int32_t chunkIndex = getChunkIndex(chunkId);
+ if (chunkIndex < 0 || static_cast<size_t>(chunkIndex) >= mChunkData.size())
{
- temp.getVertices()[i].p = temp.getVertices()[i].p * mScaleFactor + mOffset;
+ return nullptr;
}
- temp.recalculateBoundingBox();
+
+ auto temp = new MeshImpl(*reinterpret_cast<MeshImpl*>(mChunkData[chunkIndex].meshData));
+ for (uint32_t i = 0; i < temp->getVerticesCount(); ++i)
+ {
+ temp->getVerticesWritable()[i].p = temp->getVertices()[i].p * mScaleFactor + mOffset;
+ }
+ temp->recalculateBoundingBox();
return temp;
}
+bool FractureToolImpl::isMeshContainOpenEdges(const Mesh* input)
+{
+ std::map<PxVec3, int32_t, VrtPositionComparator> vertexMapping;
+ std::vector<int32_t> vertexRemappingArray(input->getVerticesCount());
+ std::vector<Edge> remappedEdges(input->getEdgesCount());
+ /**
+ Remap vertices
+ */
+
+ const Vertex* vrx = input->getVertices();
+ for (uint32_t i = 0; i < input->getVerticesCount(); ++i)
+ {
+ auto it = vertexMapping.find(vrx->p);
+ if (it == vertexMapping.end())
+ {
+ vertexMapping[vrx->p] = i;
+ vertexRemappingArray[i] = i;
+ }
+ else
+ {
+ vertexRemappingArray[i] = it->second;
+ }
+ ++vrx;
+ }
+
+ const Edge* ed = input->getEdges();
+ for (uint32_t i = 0; i < input->getEdgesCount(); ++i)
+ {
+ remappedEdges[i].s = vertexRemappingArray[ed->s];
+ remappedEdges[i].e = vertexRemappingArray[ed->e];
+ if (remappedEdges[i].e < remappedEdges[i].s)
+ {
+ std::swap(remappedEdges[i].s, remappedEdges[i].e);
+ }
+ ++ed;
+ }
+
+ std::sort(remappedEdges.begin(), remappedEdges.end());
+
+ int32_t collected = 1;
+ for (uint32_t i = 1; i < remappedEdges.size(); ++i)
+ {
+ if (remappedEdges[i - 1].s == remappedEdges[i].s && remappedEdges[i - 1].e == remappedEdges[i].e)
+ {
+ collected++;
+ }
+ else
+ {
+ if (collected & 1)
+ {
+ return true;
+ }
+ else
+ {
+ collected = 1;
+ }
+ }
+ }
+ return collected & 1;
+}
-int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<physx::PxVec3>& cellPointsIn, const physx::PxVec3& scale, bool replaceChunk)
+int32_t FractureToolImpl::voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPointsIn, const physx::PxVec3& scale, bool replaceChunk)
{
if (chunkId == 0 && replaceChunk)
{
@@ -457,7 +532,7 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
}
int32_t chunkIndex = getChunkIndex(chunkId);
- if (chunkIndex == -1 || cellPointsIn.size() < 2)
+ if (chunkIndex == -1 || cellCount < 2)
{
return 1;
}
@@ -469,8 +544,8 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
Mesh* mesh = mChunkData[chunkIndex].meshData;
- std::vector<PxVec3> cellPoints(cellPointsIn.size());
- for (uint32_t i = 0; i < cellPointsIn.size(); ++i)
+ std::vector<PxVec3> cellPoints(cellCount);
+ for (uint32_t i = 0; i < cellCount; ++i)
{
cellPoints[i] = (cellPointsIn[i] - mOffset) * (1.0f / mScaleFactor);
@@ -482,8 +557,8 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
/**
Prebuild accelerator structure
*/
- BooleanEvaluator eval(mLoggingCallback);
- BooleanEvaluator voronoiMeshEval(mLoggingCallback);
+ BooleanEvaluator eval;
+ BooleanEvaluator voronoiMeshEval;
BBoxBasedAccelerator spAccel = BBoxBasedAccelerator(mesh, DEFAULT_BB_ACCELARATOR_RES);
@@ -507,9 +582,9 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
for (uint32_t v = 0; v < cell->getVerticesCount(); ++v)
{
- cell->getVertices()[v].p.x *= scale.x;
- cell->getVertices()[v].p.y *= scale.y;
- cell->getVertices()[v].p.z *= scale.z;
+ cell->getVerticesWritable()[v].p.x *= scale.x;
+ cell->getVerticesWritable()[v].p.y *= scale.y;
+ cell->getVerticesWritable()[v].p.z *= scale.z;
}
cell->recalculateBoundingBox();
DummyAccelerator dmAccel(cell->getFacetCount());
@@ -546,7 +621,7 @@ int32_t FractureTool::voronoiFracturing(uint32_t chunkId, const std::vector<phys
}
-int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd)
+int32_t FractureToolImpl::slicing(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd)
{
if (conf.noiseAmplitude != 0)
{
@@ -570,9 +645,9 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
chunkIndex = getChunkIndex(chunkId);
- Mesh* mesh = new Mesh(*mChunkData[chunkIndex].meshData);
+ Mesh* mesh = new MeshImpl(*reinterpret_cast <MeshImpl*>(mChunkData[chunkIndex].meshData));
- BooleanEvaluator bTool(mLoggingCallback);
+ BooleanEvaluator bTool;
int32_t x_slices = conf.x_slices;
int32_t y_slices = conf.y_slices;
@@ -607,8 +682,8 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
PxVec3 randVect = PxVec3(2 * rnd->getRandomValue() - 1, 2 * rnd->getRandomValue() - 1, 2 * rnd->getRandomValue() - 1);
PxVec3 lDir = dir + randVect * conf.angle_variations;
- setCuttingBox(center, lDir, slBox, 20, mPlaneIndexerOffset);
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
+ setCuttingBox(center, -lDir, slBox, 20, mPlaneIndexerOffset);
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
ch.meshData = bTool.createNewMesh();
if (ch.meshData != 0)
@@ -617,7 +692,7 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
}
inverseNormalAndSetIndices(slBox, -mPlaneIndexerOffset);
++mPlaneIndexerOffset;
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
Mesh* result = bTool.createNewMesh();
delete mesh;
mesh = result;
@@ -647,8 +722,8 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
PxVec3 lDir = dir + randVect * conf.angle_variations;
- setCuttingBox(center, lDir, slBox, 20, mPlaneIndexerOffset);
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
+ setCuttingBox(center, -lDir, slBox, 20, mPlaneIndexerOffset);
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
ch.meshData = bTool.createNewMesh();
if (ch.meshData != 0)
{
@@ -656,7 +731,7 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
}
inverseNormalAndSetIndices(slBox, -mPlaneIndexerOffset);
++mPlaneIndexerOffset;
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
Mesh* result = bTool.createNewMesh();
delete mesh;
mesh = result;
@@ -685,8 +760,8 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
{
PxVec3 randVect = PxVec3(2 * rnd->getRandomValue() - 1, 2 * rnd->getRandomValue() - 1, 2 * rnd->getRandomValue() - 1);
PxVec3 lDir = dir + randVect * conf.angle_variations;
- setCuttingBox(center, lDir, slBox, 20, mPlaneIndexerOffset);
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
+ setCuttingBox(center, -lDir, slBox, 20, mPlaneIndexerOffset);
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
ch.meshData = bTool.createNewMesh();
if (ch.meshData != 0)
{
@@ -696,7 +771,7 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
}
inverseNormalAndSetIndices(slBox, -mPlaneIndexerOffset);
++mPlaneIndexerOffset;
- bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_INTERSECION());
+ bTool.performFastCutting(mesh, slBox, BooleanConfigurations::BOOLEAN_DIFFERENCE());
Mesh* result = bTool.createNewMesh();
delete mesh;
mesh = result;
@@ -735,7 +810,7 @@ int32_t FractureTool::slicing(uint32_t chunkId, SlicingConfiguration conf, bool
return 0;
}
-int32_t FractureTool::slicingNoisy(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd)
+int32_t FractureToolImpl::slicingNoisy(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd)
{
if (replaceChunk && chunkId == 0)
{
@@ -754,9 +829,9 @@ int32_t FractureTool::slicingNoisy(uint32_t chunkId, SlicingConfiguration conf,
chunkIndex = getChunkIndex(chunkId);
- Mesh* mesh = new Mesh(*mChunkData[chunkIndex].meshData);
+ Mesh* mesh = new MeshImpl(*reinterpret_cast <MeshImpl*>(mChunkData[chunkIndex].meshData));
- BooleanEvaluator bTool(mLoggingCallback);
+ BooleanEvaluator bTool;
int32_t x_slices = conf.x_slices;
int32_t y_slices = conf.y_slices;
@@ -784,7 +859,7 @@ int32_t FractureTool::slicingNoisy(uint32_t chunkId, SlicingConfiguration conf,
std::vector<ChunkInfo> ySlicedChunks;
std::vector<uint32_t> newlyCreatedChunksIds;
float noisyPartSize = 1.8f;
- int32_t acceleratorRes = 5;
+ int32_t acceleratorRes = 8;
/**
Slice along x direction
*/
@@ -930,7 +1005,7 @@ int32_t FractureTool::slicingNoisy(uint32_t chunkId, SlicingConfiguration conf,
-int32_t FractureTool::getChunkIndex(int32_t chunkId)
+int32_t FractureToolImpl::getChunkIndex(int32_t chunkId)
{
for (uint32_t i = 0; i < mChunkData.size(); ++i)
{
@@ -942,7 +1017,7 @@ int32_t FractureTool::getChunkIndex(int32_t chunkId)
return -1;
}
-int32_t FractureTool::getChunkDepth(int32_t chunkId)
+int32_t FractureToolImpl::getChunkDepth(int32_t chunkId)
{
int32_t chunkIndex = getChunkIndex(chunkId);
if (chunkIndex == -1)
@@ -960,41 +1035,50 @@ int32_t FractureTool::getChunkDepth(int32_t chunkId)
return depth;
}
-std::vector<int32_t> FractureTool::getChunksIdAtDepth(uint32_t depth)
+uint32_t FractureToolImpl::getChunksIdAtDepth(uint32_t depth, int32_t*& chunkIds)
{
- std::vector<int32_t> chunkIds;
+ std::vector<int32_t> _chunkIds;
for (uint32_t i = 0; i < mChunkData.size(); ++i)
{
if (getChunkDepth(mChunkData[i].chunkId) == (int32_t)depth)
{
- chunkIds.push_back(mChunkData[i].chunkId);
+ _chunkIds.push_back(mChunkData[i].chunkId);
}
}
- return chunkIds;
+ chunkIds = new int32_t[_chunkIds.size()];
+ memcpy(chunkIds, _chunkIds.data(), _chunkIds.size() * sizeof(int32_t));
+
+ return (uint32_t)_chunkIds.size();
}
-void FractureTool::getTransformation(PxVec3& offset, float& scale)
+void FractureToolImpl::getTransformation(PxVec3& offset, float& scale)
{
offset = mOffset;
scale = mScaleFactor;
}
-void FractureTool::setSourceMesh(Mesh* mesh)
+void FractureToolImpl::setSourceMesh(const Mesh* meshInput)
{
- if (mesh == nullptr)
+ if (meshInput == nullptr)
{
return;
}
reset();
+ if (isMeshContainOpenEdges(meshInput))
+ {
+ NVBLAST_LOG_WARNING("WARNING! Input mesh contains open edges, it may lead to wrong fractruing results!. \n");
+ }
+
+
mChunkData.resize(1);
- mChunkData[0].meshData = new Mesh(*mesh);
+ mChunkData[0].meshData = new MeshImpl(*reinterpret_cast <const MeshImpl*>(meshInput));
mChunkData[0].parent = -1;
mChunkData[0].isLeaf = true;
mChunkData[0].chunkId = mChunkIdCounter++;
- mesh = mChunkData[0].meshData;
+ Mesh* mesh = mChunkData[0].meshData;
/**
Move to origin and scale to unit cube
@@ -1005,24 +1089,30 @@ void FractureTool::setSourceMesh(Mesh* mesh)
mScaleFactor = std::max(bbSizes.x, std::max(bbSizes.y, bbSizes.z));
- Vertex* verticesBuffer = mesh->getVertices();
+ Vertex* verticesBuffer = mesh->getVerticesWritable();
for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
{
verticesBuffer[i].p = (verticesBuffer[i].p - mOffset) * (1.0f / mScaleFactor);
}
- mesh->getBoundingBox().minimum = (mesh->getBoundingBox().minimum - mOffset) * (1.0f / mScaleFactor);
- mesh->getBoundingBox().maximum = (mesh->getBoundingBox().maximum - mOffset) * (1.0f / mScaleFactor);
+ mesh->getBoundingBoxWritable().minimum = (mesh->getBoundingBox().minimum - mOffset) * (1.0f / mScaleFactor);
+ mesh->getBoundingBoxWritable().maximum = (mesh->getBoundingBox().maximum - mOffset) * (1.0f / mScaleFactor);
for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
{
- mesh->getFacet(i)->userData = 0; // Mark facet as initial boundary facet
+ mesh->getFacetWritable(i)->userData = 0; // Mark facet as initial boundary facet
}
}
-void FractureTool::reset()
+void FractureToolImpl::release()
+{
+ delete this;
+}
+
+
+void FractureToolImpl::reset()
{
mChunkPostprocessors.clear();
for (uint32_t i = 0; i < mChunkData.size(); ++i)
@@ -1035,9 +1125,7 @@ void FractureTool::reset()
}
-
-
-bool FractureTool::isAncestorForChunk(int32_t ancestorId, int32_t chunkId)
+bool FractureToolImpl::isAncestorForChunk(int32_t ancestorId, int32_t chunkId)
{
if (ancestorId == chunkId)
{
@@ -1059,7 +1147,7 @@ bool FractureTool::isAncestorForChunk(int32_t ancestorId, int32_t chunkId)
return false;
}
-void FractureTool::eraseChunk(int32_t chunkId)
+void FractureToolImpl::eraseChunk(int32_t chunkId)
{
deleteAllChildsOfChunk(chunkId);
int32_t index = getChunkIndex(chunkId);
@@ -1072,7 +1160,7 @@ void FractureTool::eraseChunk(int32_t chunkId)
}
-void FractureTool::deleteAllChildsOfChunk(int32_t chunkId)
+void FractureToolImpl::deleteAllChildsOfChunk(int32_t chunkId)
{
std::vector<int32_t> chunkToDelete;
for (uint32_t i = 0; i < mChunkData.size(); ++i)
@@ -1091,7 +1179,7 @@ void FractureTool::deleteAllChildsOfChunk(int32_t chunkId)
}
}
-void FractureTool::finalizeFracturing()
+void FractureToolImpl::finalizeFracturing()
{
for (uint32_t i = 0; i < mChunkPostprocessors.size(); ++i)
{
@@ -1100,7 +1188,7 @@ void FractureTool::finalizeFracturing()
mChunkPostprocessors.resize(mChunkData.size());
for (uint32_t i = 0; i < mChunkPostprocessors.size(); ++i)
{
- mChunkPostprocessors[i] = new ChunkPostProcessor();
+ mChunkPostprocessors[i] = new Triangulator();
}
for (uint32_t i = 0; i < mChunkPostprocessors.size(); ++i)
@@ -1131,89 +1219,38 @@ void FractureTool::finalizeFracturing()
}
-const std::vector<ChunkInfo>& FractureTool::getChunkList()
+uint32_t FractureToolImpl::getChunkCount() const
{
- return mChunkData;
+ return (uint32_t)mChunkData.size();
}
-void FractureTool::getBaseMesh(int32_t chunkIndex, std::vector<Triangle>& output)
+const ChunkInfo& FractureToolImpl::getChunkInfo(int32_t chunkId)
{
- NVBLAST_ASSERT(mChunkPostprocessors.size() > 0);
- if (mChunkPostprocessors.size() == 0)
- {
- return; // finalizeFracturing() should be called before getting mesh!
- }
- output = mChunkPostprocessors[chunkIndex]->getBaseMesh();
-
- /* Scale mesh back */
-
- for (uint32_t i = 0; i < output.size(); ++i)
- {
- output[i].a.p = output[i].a.p * mScaleFactor + mOffset;
- output[i].b.p = output[i].b.p * mScaleFactor + mOffset;
- output[i].c.p = output[i].c.p * mScaleFactor + mOffset;
- }
+ return mChunkData[chunkId];
}
-void FractureTool::getNoisedMesh(int32_t chunkIndex, std::vector<Triangle>& output)
+uint32_t FractureToolImpl::getBaseMesh(int32_t chunkIndex, Triangle*& output)
{
NVBLAST_ASSERT(mChunkPostprocessors.size() > 0);
if (mChunkPostprocessors.size() == 0)
- {
- return; // finalizeFracturing() should be called before getting mesh!
- }
-
- if (mChunkData[chunkIndex].chunkId == 0)
- {
- output = mChunkPostprocessors[chunkIndex]->getBaseMesh();
- }
- else
- {
- output = mChunkPostprocessors[chunkIndex]->getNoisyMesh();
+ {
+ return 0; // finalizeFracturing() should be called before getting mesh!
}
+ auto baseMesh = mChunkPostprocessors[chunkIndex]->getBaseMesh();
+ output = new Triangle[baseMesh.size()];
+ memcpy(output, baseMesh.data(), baseMesh.size() * sizeof(Triangle));
- for (uint32_t i = 0; i < output.size(); ++i)
- {
- output[i].a.p = output[i].a.p * mScaleFactor + mOffset;
- output[i].b.p = output[i].b.p * mScaleFactor + mOffset;
- output[i].c.p = output[i].c.p * mScaleFactor + mOffset;
- }
-}
+ /* Scale mesh back */
-void FractureTool::tesselate(float averateEdgeLength)
-{
- NVBLAST_ASSERT(mChunkPostprocessors.size() > 0);
- if (mChunkPostprocessors.size() == 0)
+ for (uint32_t i = 0; i < baseMesh.size(); ++i)
{
- return; // finalizeFracturing() should be called before tesselation!
+ Triangle& triangle = output[i];
+ triangle.a.p = triangle.a.p * mScaleFactor + mOffset;
+ triangle.b.p = triangle.b.p * mScaleFactor + mOffset;
+ triangle.c.p = triangle.c.p * mScaleFactor + mOffset;
}
- for (uint32_t i = 0; i < mChunkPostprocessors.size(); ++i)
- {
- if (mChunkData[i].chunkId == 0) // skip source mesh
- {
- continue;
- }
- mChunkPostprocessors[i]->tesselateInternalSurface(averateEdgeLength / mScaleFactor);
- }
-}
-
-void FractureTool::applyNoise(float amplitude, float frequency, int32_t octaves, float falloff, int32_t relaxIterations, float relaxFactor, int32_t seed)
-{
- octaves = octaves <= 0 ? 1 : octaves;
- if (mChunkPostprocessors.empty())
- {
- return;
- }
- SimplexNoise noise(amplitude / mScaleFactor, frequency * mScaleFactor, octaves, seed);
- for (uint32_t i = 0; i < mChunkPostprocessors.size(); ++i)
- {
- if (mChunkData[i].chunkId == 0) // skip source mesh
- {
- continue;
- }
- mChunkPostprocessors[i]->applyNoise(noise, falloff, relaxIterations, relaxFactor);
- }
+ return baseMesh.size();
}
float getVolume(std::vector<Triangle>& triangles)
@@ -1230,7 +1267,7 @@ float getVolume(std::vector<Triangle>& triangles)
return (1.0f / 6.0f) * PxAbs(volume);
}
-float FractureTool::getMeshOverlap(Mesh& meshA, Mesh& meshB)
+float FractureToolImpl::getMeshOverlap(const Mesh& meshA, const Mesh& meshB)
{
BooleanEvaluator bTool;
bTool.performBoolean(&meshA, &meshB, BooleanConfigurations::BOOLEAN_INTERSECION());
@@ -1240,7 +1277,7 @@ float FractureTool::getMeshOverlap(Mesh& meshA, Mesh& meshB)
return 0.0f;
}
- ChunkPostProcessor postProcessor;
+ Triangulator postProcessor;
postProcessor.triangulate(&meshA);
float baseVolume = getVolume(postProcessor.getBaseMesh());
@@ -1297,19 +1334,19 @@ void weldVertices(std::map<Vertex, uint32_t, VrtComp>& vertexMapping, std::vecto
}
-void FractureTool::setRemoveIslands(bool isRemoveIslands)
+void FractureToolImpl::setRemoveIslands(bool isRemoveIslands)
{
mRemoveIslands = isRemoveIslands;
}
-int32_t FractureTool::islandDetectionAndRemoving(int32_t chunkId)
+int32_t FractureToolImpl::islandDetectionAndRemoving(int32_t chunkId)
{
if (chunkId == 0)
{
return 0;
}
int32_t chunkIndex = getChunkIndex(chunkId);
- ChunkPostProcessor prc;
+ Triangulator prc;
prc.triangulate(mChunkData[chunkIndex].meshData);
Mesh* chunk = mChunkData[chunkIndex].meshData;
@@ -1403,7 +1440,7 @@ int32_t FractureTool::islandDetectionAndRemoving(int32_t chunkId)
std::vector<uint32_t> compVertexMapping(chunk->getVerticesCount(), 0);
- Vertex* vrts = chunk->getVertices();
+ const Vertex* vrts = chunk->getVertices();
for (uint32_t v = 0; v < chunk->getVerticesCount(); ++v)
{
int32_t vComp = comps[mapping[v]];
@@ -1411,8 +1448,8 @@ int32_t FractureTool::islandDetectionAndRemoving(int32_t chunkId)
compVertices[vComp].push_back(vrts[v]);
}
- Facet* fcb = chunk->getFacetsBuffer();
- Edge* edb = chunk->getEdges();
+ const Facet* fcb = chunk->getFacetsBuffer();
+ const Edge* edb = chunk->getEdges();
for (uint32_t fc = 0; fc < chunk->getFacetCount(); ++fc)
{
@@ -1436,13 +1473,13 @@ int32_t FractureTool::islandDetectionAndRemoving(int32_t chunkId)
}
delete mChunkData[chunkIndex].meshData;
- mChunkData[chunkIndex].meshData = new Mesh(compVertices[0].data(), compEdges[0].data(), compFacets[0].data(), static_cast<uint32_t>(compVertices[0].size()),
+ mChunkData[chunkIndex].meshData = new MeshImpl(compVertices[0].data(), compEdges[0].data(), compFacets[0].data(), static_cast<uint32_t>(compVertices[0].size()),
static_cast<uint32_t>(compEdges[0].size()), static_cast<uint32_t>(compFacets[0].size()));;
for (int32_t i = 1; i < cComp; ++i)
{
mChunkData.push_back(ChunkInfo(mChunkData[chunkIndex]));
mChunkData.back().chunkId = mChunkIdCounter++;
- mChunkData.back().meshData = new Mesh(compVertices[i].data(), compEdges[i].data(), compFacets[i].data(), static_cast<uint32_t>(compVertices[i].size()),
+ mChunkData.back().meshData = new MeshImpl(compVertices[i].data(), compEdges[i].data(), compFacets[i].data(), static_cast<uint32_t>(compVertices[i].size()),
static_cast<uint32_t>(compEdges[i].size()), static_cast<uint32_t>(compFacets[i].size()));
}
@@ -1451,60 +1488,52 @@ int32_t FractureTool::islandDetectionAndRemoving(int32_t chunkId)
return 0;
}
-void FractureTool::getBufferedBaseMeshes(std::vector<Vertex>& vertexBuffer, std::vector<std::vector<uint32_t> >& indexBuffer)
+uint32_t FractureToolImpl::getBufferedBaseMeshes(Vertex*& vertexBuffer, uint32_t*& indexBuffer,
+ uint32_t*& indexBufferOffsets)
{
std::map<Vertex, uint32_t, VrtComp> vertexMapping;
- vertexBuffer.clear();
- indexBuffer.clear();
- indexBuffer.resize(mChunkPostprocessors.size());
+ std::vector<Vertex> _vertexBuffer;
+ std::vector<std::vector<uint32_t>> _indexBuffer(mChunkPostprocessors.size());
+
+ indexBufferOffsets = new uint32_t[mChunkPostprocessors.size() + 1];
+ uint32_t totalIndices = 0;
for (uint32_t ch = 0; ch < mChunkPostprocessors.size(); ++ch)
{
std::vector<Triangle>& trb = mChunkPostprocessors[ch]->getBaseMesh();
- weldVertices(vertexMapping, vertexBuffer, indexBuffer[ch], trb);
+
+ weldVertices(vertexMapping, _vertexBuffer, _indexBuffer[ch], trb);
+
+ indexBufferOffsets[ch] = totalIndices;
+ totalIndices += _indexBuffer[ch].size();
}
- for (uint32_t i = 0; i < vertexBuffer.size(); ++i)
+ indexBufferOffsets[mChunkPostprocessors.size()] = totalIndices;
+
+ for (uint32_t i = 0; i < _vertexBuffer.size(); ++i)
{
- vertexBuffer[i].p = vertexBuffer[i].p * mScaleFactor + mOffset;
+ _vertexBuffer[i].p = _vertexBuffer[i].p * mScaleFactor + mOffset;
}
-}
-int32_t FractureTool::getChunkId(int32_t chunkIndex)
-{
- if (chunkIndex < 0 || static_cast<uint32_t>(chunkIndex) >= mChunkData.size())
+ vertexBuffer = new Vertex[_vertexBuffer.size()];
+ indexBuffer = new uint32_t[totalIndices];
+
+ memcpy(vertexBuffer, _vertexBuffer.data(), _vertexBuffer.size() * sizeof(Vertex));
+ for (uint32_t ch = 0; ch < _indexBuffer.size(); ++ch)
{
- return -1;
+ memcpy(indexBuffer + indexBufferOffsets[ch], _indexBuffer[ch].data(), _indexBuffer[ch].size() * sizeof(uint32_t));
}
- return mChunkData[chunkIndex].chunkId;
+
+ return _vertexBuffer.size();
}
-void FractureTool::getBufferedNoiseMeshes(std::vector<Vertex>& vertexBuffer, std::vector<std::vector<uint32_t> >& indexBuffer)
+int32_t FractureToolImpl::getChunkId(int32_t chunkIndex)
{
- std::map<Vertex, uint32_t, VrtComp> vertexMapping;
- vertexBuffer.clear();
- indexBuffer.clear();
- indexBuffer.resize(mChunkPostprocessors.size());
-
- for (uint32_t ch = 0; ch < mChunkPostprocessors.size(); ++ch)
- {
- if (ch == 0)
- {
- std::vector<Triangle>& trb = mChunkPostprocessors[ch]->getBaseMesh();
- weldVertices(vertexMapping, vertexBuffer, indexBuffer[ch], trb);
- }
- else
- {
- std::vector<Triangle>& trb = mChunkPostprocessors[ch]->getNoisyMesh();
- weldVertices(vertexMapping, vertexBuffer, indexBuffer[ch], trb);
- }
- }
- for (uint32_t i = 0; i < vertexBuffer.size(); ++i)
+ if (chunkIndex < 0 || static_cast<uint32_t>(chunkIndex) >= mChunkData.size())
{
- vertexBuffer[i].p = vertexBuffer[i].p * mScaleFactor + mOffset;
+ return -1;
}
+ return mChunkData[chunkIndex].chunkId;
}
-
} // namespace Blast
} // namespace Nv
-
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.h
new file mode 100644
index 0000000..9b656e3
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringFractureToolImpl.h
@@ -0,0 +1,330 @@
+/*
+* 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.
+*/
+
+#ifndef NVBLASTAUTHORINGFRACTURETOOLIMPL_H
+#define NVBLASTAUTHORINGFRACTURETOOLIMPL_H
+
+#include "NvBlastExtAuthoringFractureTool.h"
+#include "NvBlastExtAuthoringMesh.h"
+#include <vector>
+
+namespace Nv
+{
+namespace Blast
+{
+
+class SpatialAccelerator;
+class Triangulator;
+
+
+/**
+ Class for voronoi sites generation inside supplied mesh.
+*/
+class VoronoiSitesGeneratorImpl : public VoronoiSitesGenerator
+{
+public:
+
+ /**
+ Voronoi sites should not be generated outside of the fractured mesh, so VoronoiSitesGenerator
+ should be supplied with fracture mesh.
+ \param[in] mesh Fracture mesh
+ \param[in] rnd User supplied random value generator.
+ \return
+ */
+ VoronoiSitesGeneratorImpl(const Mesh* mesh, RandomGeneratorBase* rnd);
+ ~VoronoiSitesGeneratorImpl();
+
+ void release() override;
+
+ /**
+ Set base fracture mesh
+ */
+ void setBaseMesh(const Mesh* m) override;
+
+ /**
+ Access to generated voronoi sites.
+ \note User should call NVBLAST_FREE for hulls and hullsOffset when it not needed anymore
+ \param[out] Pointer to generated voronoi sites
+ \return Count of generated voronoi sites.
+ */
+ uint32_t getVoronoiSites(const physx::PxVec3*& sites) override;
+
+ /**
+ Add site in particular point
+ \param[in] site Site coordinates
+ */
+ void addSite(const physx::PxVec3& site) override;
+ /**
+ Uniformly generate sites inside the mesh
+ \param[in] numberOfSites Number of generated sites
+ */
+ void uniformlyGenerateSitesInMesh(uint32_t numberOfSites) override;
+
+ /**
+ Generate sites in clustered fashion
+ \param[in] numberOfClusters Number of generated clusters
+ \param[in] sitesPerCluster Number of sites in each cluster
+ \param[in] clusterRadius Voronoi cells cluster radius
+ */
+ void clusteredSitesGeneration(uint32_t numberOfClusters, uint32_t sitesPerCluster, float clusterRadius) override;
+
+ /**
+ Radial pattern of sites generation
+ \param[in] center Center of generated pattern
+ \param[in] normal Normal to plane in which sites are generated
+ \param[in] radius Pattern radius
+ \param[in] angularSteps Number of angular steps
+ \param[in] radialSteps Number of radial steps
+ \param[in] angleOffset Angle offset at each radial step
+ \param[in] variability Randomness of sites distribution
+ */
+ void radialPattern(const physx::PxVec3& center, const physx::PxVec3& normal, float radius, int32_t angularSteps, int32_t radialSteps, float angleOffset = 0.0f, float variability = 0.0f) override;
+
+ /**
+ Generate sites inside sphere
+ \param[in] count Count of generated sites
+ \param[in] radius Radius of sphere
+ \param[in] center Center of sphere
+ */
+ void generateInSphere(const uint32_t count, const float radius, const physx::PxVec3& center) override;
+ /**
+ Set stencil mesh. With stencil mesh sites are generated only inside both of fracture and stencil meshes.
+ \param[in] stencil Stencil mesh.
+ */
+ void setStencil(const Mesh* stencil) override;
+ /**
+ Removes stencil mesh
+ */
+ void clearStencil() override;
+
+ /**
+ Deletes sites inside supplied sphere
+ \param[in] radius Radius of sphere
+ \param[in] center Center of sphere
+ \param[in] eraserProbability Probability of removing some particular site
+ */
+ void deleteInSphere(const float radius, const physx::PxVec3& center, const float eraserProbability = 1) override;
+
+private:
+ std::vector <physx::PxVec3> mGeneratedSites;
+ const Mesh* mMesh;
+ const Mesh* mStencil;
+ RandomGeneratorBase* mRnd;
+ SpatialAccelerator* mAccelerator;
+};
+
+
+
+/**
+ FractureTool class provides methods to fracture provided mesh and generate Blast asset data
+*/
+class FractureToolImpl : public FractureTool
+{
+
+public:
+
+ /**
+ FractureTool can log asset creation info if logCallback is provided.
+ */
+ FractureToolImpl()
+ {
+ mPlaneIndexerOffset = 1;
+ mChunkIdCounter = 0;
+ mRemoveIslands = false;
+ }
+
+ ~FractureToolImpl()
+ {
+ reset();
+ }
+
+ void release() override;
+
+ /**
+ Reset FractureTool state.
+ */
+ void reset() override;
+
+
+ /**
+ Set input mesh wich will be fractured, FractureTool will be reseted.
+ */
+ void setSourceMesh(const Mesh* mesh) override;
+
+ /**
+ Get chunk mesh in polygonal representation
+ */
+ Mesh* createChunkMesh(int32_t chunkId) override;
+
+ /**
+ Input mesh is scaled and transformed internally to fit unit cube centered in origin.
+ Method provides offset vector and scale parameter;
+ */
+ void getTransformation(physx::PxVec3& offset, float& scale) override;
+
+
+ /**
+ Fractures specified chunk with voronoi method.
+ \param[in] chunkId Chunk to fracture
+ \param[in] cellPoints Array of voronoi sites
+ \param[in] replaceChunk if 'true', newly generated chunks will replace source chunk, if 'false', newly generated chunks will be at next depth level, source chunk will be parent for them.
+ Case replaceChunk == true && chunkId == 0 considered as wrong input parameters
+ \return If 0, fracturing is successful.
+ */
+ int32_t voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPoints, bool replaceChunk) override;
+
+ /**
+ Fractures specified chunk with voronoi method. Cells can be scaled along x,y,z axes.
+ \param[in] chunkId Chunk to fracture
+ \param[in] cellPoints Array of voronoi sites
+ \param[in] cellPoints Array of voronoi sites
+ \param[in] scale Voronoi cells scaling factor
+ \param[in] replaceChunk if 'true', newly generated chunks will replace source chunk, if 'false', newly generated chunks will be at next depth level, source chunk will be parent for them.
+ Case replaceChunk == true && chunkId == 0 considered as wrong input parameters
+ \return If 0, fracturing is successful.
+ */
+ int32_t voronoiFracturing(uint32_t chunkId, uint32_t cellCount, const physx::PxVec3* cellPoints, const physx::PxVec3& scale, bool replaceChunk) override;
+
+
+ /**
+ Fractures specified chunk with slicing method.
+ \param[in] chunkId Chunk to fracture
+ \param[in] conf Slicing parameters, see SlicingConfiguration.
+ \param[in] replaceChunk if 'true', newly generated chunks will replace source chunk, if 'false', newly generated chunks will be at next depth level, source chunk will be parent for them.
+ Case replaceChunk == true && chunkId == 0 considered as wrong input parameters
+ \param[in] rnd User supplied random number generator
+
+ \return If 0, fracturing is successful.
+ */
+ int32_t slicing(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd) override;
+
+
+ /**
+ Creates resulting fractured mesh geometry from intermediate format
+ */
+ void finalizeFracturing() override;
+
+ uint32_t getChunkCount() const override;
+
+ /**
+ Get chunk information
+ */
+ const ChunkInfo& getChunkInfo(int32_t chunkIndex) override;
+
+ /**
+ Get percentage of mesh overlap.
+ percentage computed as volume(intersection(meshA , meshB)) / volume (meshA)
+ \param[in] meshA Mesh A
+ \param[in] meshB Mesh B
+ \return mesh overlap percentage
+ */
+ float getMeshOverlap(const Mesh& meshA, const Mesh& meshB) override;
+
+ /**
+ Get chunk base mesh
+ \note User should call NVBLAST_FREE for output when it not needed anymore
+ \param[in] chunkIndex Chunk index
+ \param[out] output Array of triangles to be filled
+ \return number of triangles in base mesh
+ */
+ uint32_t getBaseMesh(int32_t chunkIndex, Triangle*& output) override;
+
+ /**
+ Return index of chunk with specified chunkId
+ \param[in] chunkId Chunk ID
+ \return Chunk index in internal buffer, if not exist -1 is returned.
+ */
+ int32_t getChunkIndex(int32_t chunkId) override;
+
+ /**
+ Return id of chunk with specified index.
+ \param[in] chunkIndex Chunk index
+ \return Chunk id or -1 if there is no such chunk.
+ */
+ int32_t getChunkId(int32_t chunkIndex) override;
+
+ /**
+ Return depth level of the given chunk
+ \param[in] chunkId Chunk ID
+ \return Chunk depth or -1 if there is no such chunk.
+ */
+ int32_t getChunkDepth(int32_t chunkId) override;
+
+ /**
+ Return array of chunks IDs with given depth.
+ \note User should call NVBLAST_FREE for chunkIds when it not needed anymore
+ \param[in] depth Chunk depth
+ \param[out] Pointer to array of chunk IDs
+ \return Number of chunks in array
+ */
+ uint32_t getChunksIdAtDepth(uint32_t depth, int32_t*& chunkIds) override;
+
+
+ /**
+ Get result geometry without noise as vertex and index buffers, where index buffers contain series of triplets
+ which represent triangles.
+ \note User should call NVBLAST_FREE for vertexBuffer, indexBuffer and indexBufferOffsets when it not needed anymore
+ \param[out] vertexBuffer Array of vertices to be filled
+ \param[out] indexBuffer Array of indices to be filled
+ \param[out] indexBufferOffsets Array of offsets in indexBuffer for each base mesh.
+ Contains getChunkCount() + 1 elements. Last one is indexBuffer size
+ \return Number of vertices in vertexBuffer
+ */
+ uint32_t getBufferedBaseMeshes(Vertex*& vertexBuffer, uint32_t*& indexBuffer, uint32_t*& indexBufferOffsets) override;
+
+ /**
+ Set automatic islands removing. May cause instabilities.
+ \param[in] isRemoveIslands Flag whether remove or not islands.
+ */
+ void setRemoveIslands(bool isRemoveIslands) override;
+
+ /**
+ Try find islands and remove them on some specifical chunk. If chunk has childs, island removing can lead to wrong results! Apply it before further chunk splitting.
+ \param[in] chunkId Chunk ID which should be checked for islands
+ \return Number of found islands is returned
+ */
+ int32_t islandDetectionAndRemoving(int32_t chunkId) override;
+
+ /**
+ Check if input mesh contains open edges. Open edges can lead to wrong fracturing results.
+ \return true if mesh contains open edges
+ */
+ bool isMeshContainOpenEdges(const Mesh* input) override;
+
+private:
+ void eraseChunk(int32_t chunkId);
+ bool isAncestorForChunk(int32_t ancestorId, int32_t chunkId);
+ void deleteAllChildsOfChunk(int32_t chunkId);
+ int32_t slicingNoisy(uint32_t chunkId, SlicingConfiguration conf, bool replaceChunk, RandomGeneratorBase* rnd);
+
+protected:
+ /**
+ Mesh scaled to unite-cube and translated to the origin
+ */
+ float mScaleFactor;
+ physx::PxVec3 mOffset;
+
+ /* Chunk mesh wrappers */
+ std::vector<Triangulator*> mChunkPostprocessors;
+
+
+
+ int32_t mPlaneIndexerOffset;
+ int32_t mChunkIdCounter;
+ std::vector<ChunkInfo> mChunkData;
+
+ bool mRemoveIslands;
+};
+
+} // namespace Blast
+} // namespace Nv
+
+
+#endif // ifndef NVBLASTAUTHORINGFRACTURETOOLIMPL_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringInternalCommon.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringInternalCommon.h
index b8fb20e..862016f 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringInternalCommon.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringInternalCommon.h
@@ -1,16 +1,35 @@
-/*
-* Copyright (c) 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 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) 2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTINTERNALCOMMON_H
#define NVBLASTINTERNALCOMMON_H
#include "NvBlastExtAuthoringTypes.h"
+#include <algorithm>
using namespace physx;
@@ -74,15 +93,15 @@ Computes best direction to project points.
*/
NV_FORCE_INLINE ProjectionDirections getProjectionDirection(const physx::PxVec3& normal)
{
- float maxv = std::max(abs(normal.x), std::max(abs(normal.y), abs(normal.z)));
+ float maxv = std::max(std::abs(normal.x), std::max(std::abs(normal.y), std::abs(normal.z)));
ProjectionDirections retVal;
- if (maxv == abs(normal.x))
+ if (maxv == std::abs(normal.x))
{
retVal = YZ_PLANE;
if (normal.x < 0) retVal = (ProjectionDirections)((int)retVal | (int)OPPOSITE_WINDING);
return retVal;
}
- if (maxv == abs(normal.y))
+ if (maxv == std::abs(normal.y))
{
retVal = ZX_PLANE;
if (normal.y > 0) retVal = (ProjectionDirections)((int)retVal | (int)OPPOSITE_WINDING);
@@ -187,6 +206,54 @@ NV_INLINE bool getPlaneSegmentIntersection(const PxPlane& pl, const PxVec3& a, c
return true;
}
+
+#define VEC_COMPARISON_OFFSET 1e-5f
+/**
+Vertex comparator for vertex welding.
+*/
+struct VrtComp
+{
+ bool 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;
+ };
+};
+
+/**
+Vertex comparator for vertex welding (not accounts normal and uv parameters of vertice).
+*/
+struct VrtPositionComparator
+{
+ bool operator()(const physx::PxVec3& a, const physx::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;
+ };
+};
+
} // namespace Blast
} // namespace Nv
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp
new file mode 100644
index 0000000..602ae75
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.cpp
@@ -0,0 +1,1626 @@
+
+#include <PxVec3.h>
+#include <PxVec2.h>
+#include <vector>
+#include <queue>
+#include <map>
+
+#include <NvBlastExtAuthoringMeshCleanerImpl.h>
+#include <NvBlastExtAuthoringMeshImpl.h>
+#include <NvBlastExtAuthoringInternalCommon.h>
+#include <boost/multiprecision/cpp_int.hpp>
+
+
+
+
+using physx::PxVec3;
+using physx::PxVec2;
+
+using namespace Nv::Blast;
+using namespace boost::multiprecision;
+
+/**
+ Exact rational vector types.
+*/
+struct RVec3
+{
+ cpp_rational x, y, z;
+ RVec3()
+ {
+
+ }
+
+ bool isZero()
+ {
+ return x.is_zero() && y.is_zero() && z.is_zero();
+ }
+
+ RVec3(cpp_rational _x, cpp_rational _y, cpp_rational _z)
+ {
+ x = _x;
+ y = _y;
+ z = _z;
+ }
+
+ RVec3(const PxVec3& p)
+ {
+ x = cpp_rational(p.x);
+ y = cpp_rational(p.y);
+ z = cpp_rational(p.z);
+ }
+ PxVec3 toVec3()
+ {
+ return PxVec3(x.convert_to<float>(), y.convert_to<float>(), z.convert_to<float>());
+ }
+
+ RVec3 operator-(const RVec3& b) const
+ {
+ return RVec3(x - b.x, y - b.y, z - b.z);
+ }
+ RVec3 operator+(const RVec3& b) const
+ {
+ return RVec3(x + b.x, y + b.y, z + b.z);
+ }
+ RVec3 cross(const RVec3& in) const
+ {
+ return RVec3(y * in.z - in.y * z, in.x * z - x * in.z, x * in.y - in.x * y);
+ }
+ cpp_rational dot(const RVec3& in) const
+ {
+ return x * in.x + y * in.y + z * in.z;
+ }
+ RVec3 operator*(const cpp_rational& in) const
+ {
+ return RVec3(x * in, y * in, z * in);
+ }
+
+
+};
+
+struct RVec2
+{
+ cpp_rational x, y;
+ RVec2()
+ {
+
+ }
+
+ RVec2(cpp_rational _x, cpp_rational _y)
+ {
+ x = _x;
+ y = _y;
+ }
+
+ RVec2(const PxVec2& p)
+ {
+ x = cpp_rational(p.x);
+ y = cpp_rational(p.y);
+ }
+ PxVec2 toVec2()
+ {
+ return PxVec2(x.convert_to<float>(), y.convert_to<float>());
+ }
+
+ RVec2 operator-(const RVec2& b) const
+ {
+ return RVec2(x - b.x, y - b.y);
+ }
+ RVec2 operator+(const RVec2& b) const
+ {
+ return RVec2(x + b.x, y + b.y);
+ }
+ cpp_rational cross(const RVec2& in) const
+ {
+ return x * in.y - y * in.x;
+ }
+ cpp_rational dot(const RVec2& in) const
+ {
+ return x * in.x + y * in.y;
+ }
+ RVec2 operator*(const cpp_rational& in) const
+ {
+ return RVec2(x * in, y * in);
+ }
+};
+struct RatPlane
+{
+ RVec3 n;
+ cpp_rational d;
+
+ RatPlane(const RVec3& a, const RVec3& b, const RVec3& c)
+ {
+ n = (b - a).cross(c - a);
+ d = -n.dot(a);
+ };
+ cpp_rational distance(RVec3& in)
+ {
+ return n.dot(in) + d;
+ }
+};
+
+bool isSame(const RatPlane& a, const RatPlane& b)
+{
+ if (a.d != b.d) return false;
+ if (a.n.x != b.n.x || a.n.y != b.n.y || a.n.z != b.n.z) return false;
+ return true;
+}
+
+RVec3 planeSegmInters(RVec3& a, RVec3& b, RatPlane& pl)
+{
+ cpp_rational t = -(a.dot(pl.n) + pl.d) / pl.n.dot(b - a);
+ RVec3 on = a + (b - a) * t;
+ return on;
+}
+
+enum POINT_CLASS
+{
+ ON_AB = 0,
+ ON_BC = 1,
+ ON_AC = 2,
+ INSIDE_TR,
+ OUTSIDE_TR,
+ ON_VERTEX
+};
+
+
+int32_t isPointInside(const RVec2& a, const RVec2& b, const RVec2& c, const RVec2& p)
+{
+ cpp_rational v1 = (b - a).cross(p - a);
+ cpp_rational v2 = (c - b).cross(p - b);
+ cpp_rational v3 = (a - c).cross(p - c);
+
+
+
+ int32_t v1s = v1.sign();
+ int32_t v2s = v2.sign();
+ int32_t v3s = v3.sign();
+
+ if (v1s * v2s < 0 || v1s * v3s < 0 || v2s * v3s < 0) return OUTSIDE_TR;
+
+ if (v1s == 0 && v2s == 0) return OUTSIDE_TR;
+ if (v1s == 0 && v3s == 0) return OUTSIDE_TR;
+ if (v2s == 0 && v3s == 0) return OUTSIDE_TR;
+
+ if (v1s == 0) return ON_AB;
+ if (v2s == 0) return ON_BC;
+ if (v3s == 0) return ON_AC;
+
+ return INSIDE_TR;
+}
+
+RVec2 getProjectedPointWithWinding(const RVec3& point, ProjectionDirections dir)
+{
+ if (dir & YZ_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.z, point.y);
+ }
+ else
+ return RVec2(point.y, point.z);
+ }
+ if (dir & ZX_PLANE)
+ {
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.z, point.x);
+ }
+ return RVec2(point.x, point.z);
+ }
+ if (dir & OPPOSITE_WINDING)
+ {
+ return RVec2(point.y, point.x);
+ }
+ return RVec2(point.x, point.y);
+}
+
+struct DelTriangle
+{
+ int32_t p[3];
+ int32_t n[3];
+ int32_t parentTriangle;
+ int32_t getEdWP(int32_t vrt)
+ {
+ if (p[0] == vrt) return 1;
+ if (p[1] == vrt) return 2;
+ if (p[2] == vrt) return 0;
+ return -1;
+ }
+ int32_t getEdId(int32_t v1, int32_t v2)
+ {
+ if (p[0] == v1 && p[1] == v2) return 0;
+ if (p[1] == v1 && p[2] == v2) return 1;
+ if (p[2] == v1 && p[0] == v2) return 2;
+ return -1;
+ }
+ int32_t getOppP(int32_t v1, int32_t v2)
+ {
+ if (p[0] == v1 && p[1] == v2) return 2;
+ if (p[1] == v1 && p[2] == v2) return 0;
+ if (p[2] == v1 && p[0] == v2) return 1;
+ return -1;
+ }
+
+ int32_t getOppPoint(int32_t v1, int32_t v2)
+ {
+ if (p[0] != v1 && p[0] != v2) return p[0];
+ if (p[1] != v1 && p[1] != v2) return p[1];
+ if (p[2] != v1 && p[2] != v2) return p[2];
+ return -1;
+ }
+ bool compare(const DelTriangle& t) const
+ {
+ if (p[0] == t.p[0] && p[1] == t.p[1] && p[2] == t.p[2]) return true;
+ if (p[1] == t.p[0] && p[2] == t.p[1] && p[0] == t.p[2]) return true;
+ if (p[2] == t.p[0] && p[0] == t.p[1] && p[1] == t.p[2]) return true;
+ return false;
+ }
+
+};
+
+struct DelEdge
+{
+ int32_t s, e;
+ int32_t nr, nl;
+};
+
+
+bool isIntersectsTriangle(RVec2& a, RVec2& b, RVec2& c, RVec2& s, RVec2& e)
+{
+ RVec2 vec = e - s;
+
+ if ((a - s).cross(vec) * (b - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = b - a;
+ if ((s - a).cross(vec2) * (e - a).cross(vec) < 0) return true;
+ }
+
+ if ((b - s).cross(vec) * (c - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = c - b;
+ if ((s - b).cross(vec2) * (e - b).cross(vec) < 0) return true;
+ }
+
+ if ((a - s).cross(vec) * (c - s).cross(vec) < 0)
+ {
+ RVec2 vec2 = a - c;
+ if ((s - c).cross(vec2) * (e - c).cross(vec) < 0) return true;
+ }
+
+ return false;
+}
+
+
+inline int32_t inCircumcircle(RVec2& a, RVec2& b, RVec2& c, RVec2& p)
+{
+ RVec2 ta = a - p;
+ RVec2 tb = b - p;
+ RVec2 tc = c - p;
+ cpp_rational ad = ta.dot(ta);
+ cpp_rational bd = tb.dot(tb);
+ cpp_rational cd = tc.dot(tc);
+
+ cpp_rational pred = ta.x * (tb.y * cd - tc.y * bd) - ta.y * (tb.x * cd - tc.x * bd) + ad * (tb.x * tc.y - tc.x * tb.y);
+
+
+ if (pred > 0) return 1;
+ if (pred < 0) return -1;
+ return 0;
+}
+
+int32_t getEdge(std::vector<DelEdge>& edges, int32_t s, int32_t e)
+{
+ for (uint32_t i = 0; i < edges.size(); ++i)
+ {
+ if (edges[i].s == s && edges[i].e == e) return i;
+ }
+
+ edges.push_back(DelEdge());
+ edges.back().s = s;
+ edges.back().e = e;
+ return edges.size() - 1;
+}
+
+void reubildAdjacency(std::vector<DelTriangle>& state)
+{
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ state[i].n[0] = state[i].n[1] = state[i].n[2] = -1;
+ }
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ if (state[i].p[0] == -1) continue;
+ for (uint32_t j = i + 1; j < state.size(); ++j)
+ {
+ if (state[j].p[0] == -1) continue;
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ for (uint32_t c = 0; c < 3; ++c)
+ {
+ if (state[i].p[k] == state[j].p[(c + 1) % 3] && state[i].p[(k + 1) % 3] == state[j].p[c]) { state[i].n[k] = j; state[j].n[c] = i; }
+ }
+ }
+ }
+ }
+}
+
+void insertPoint(std::vector<RVec2>& vertices, std::vector<DelTriangle>& state, int32_t p, const std::vector<Edge>& edges)
+{
+ std::queue<int32_t> triangleToCheck;
+
+ for (uint32_t i = 0; i < state.size(); ++i)
+ {
+ if (state[i].p[0] == -1) continue;
+ DelTriangle ctr = state[i];
+ int32_t cv = isPointInside(vertices[ctr.p[0]], vertices[ctr.p[1]], vertices[ctr.p[2]], vertices[p]);
+
+ if (cv == OUTSIDE_TR) continue;
+ if (cv == INSIDE_TR)
+ {
+ uint32_t taInd = state.size();
+ uint32_t tbInd = state.size() + 1;
+ uint32_t tcInd = state.size() + 2;
+ state.resize(state.size() + 3);
+
+ state[taInd].p[0] = ctr.p[2];
+ state[taInd].p[1] = ctr.p[0];
+ state[taInd].p[2] = p;
+
+ state[taInd].n[0] = ctr.n[2];
+ state[taInd].n[1] = tbInd;
+ state[taInd].n[2] = tcInd;
+
+ state[tbInd].p[0] = ctr.p[0];
+ state[tbInd].p[1] = ctr.p[1];
+ state[tbInd].p[2] = p;
+
+ state[tbInd].n[0] = ctr.n[0];
+ state[tbInd].n[1] = tcInd;
+ state[tbInd].n[2] = taInd;
+
+ state[tcInd].p[0] = ctr.p[1];
+ state[tcInd].p[1] = ctr.p[2];
+ state[tcInd].p[2] = p;
+
+ state[tcInd].n[0] = ctr.n[1];
+ state[tcInd].n[1] = taInd;
+ state[tcInd].n[2] = tbInd;
+
+
+ triangleToCheck.push(taInd);
+ triangleToCheck.push(tbInd);
+ triangleToCheck.push(tcInd);
+
+
+ /**
+ Change neighboors
+ */
+ int32_t nb = state[i].n[0];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[1], state[i].p[0])] = tbInd;
+ nb = state[i].n[1];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[2], state[i].p[1])] = tcInd;
+ nb = state[i].n[2];
+ if (nb != -1)
+ state[nb].n[state[nb].getEdId(state[i].p[0], state[i].p[2])] = taInd;
+
+
+ state[i].p[0] = -1;
+ }
+ else
+ {
+ uint32_t taInd = state.size();
+ uint32_t tbInd = state.size() + 1;
+ state.resize(state.size() + 2);
+
+ int32_t bPoint = state[i].p[(cv + 2) % 3];
+
+ state[taInd].p[0] = bPoint;
+ state[taInd].p[1] = state[i].p[cv];
+ state[taInd].p[2] = p;
+
+ state[tbInd].p[0] = bPoint;
+ state[tbInd].p[1] = p;
+ state[tbInd].p[2] = state[i].p[(cv + 1) % 3];
+
+ state[taInd].n[0] = state[i].n[(cv + 2) % 3];
+ state[taInd].n[1] = -1;
+ state[taInd].n[2] = tbInd;
+
+ state[tbInd].n[0] = taInd;
+ state[tbInd].n[1] = -1;
+ state[tbInd].n[2] = state[i].n[(cv + 1) % 3];
+
+ if (state[i].n[(cv + 1) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[i].n[(cv + 1) % 3]].n[k] == (int32_t)i) {
+ state[state[i].n[(cv + 1) % 3]].n[k] = tbInd; break;
+ }
+ if (state[i].n[(cv + 2) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[i].n[(cv + 2) % 3]].n[k] == (int32_t)i) {
+ state[state[i].n[(cv + 2) % 3]].n[k] = taInd; break;
+ }
+
+ triangleToCheck.push(taInd);
+ triangleToCheck.push(tbInd);
+
+ int32_t total = 2;
+ int32_t oppositeTr = 0;
+ if (state[i].n[cv] != -1)
+ {
+ oppositeTr = state[i].n[cv];
+ total += 2;
+ uint32_t tcInd = state.size();
+ uint32_t tdInd = state.size() + 1;
+ state.resize(state.size() + 2);
+
+ int32_t oped = state[oppositeTr].getEdId(state[i].p[(cv + 1) % 3], state[i].p[cv]);
+
+
+ state[tcInd].n[0] = state[oppositeTr].n[(oped + 2) % 3];
+ state[tcInd].n[1] = tbInd;
+ state[tbInd].n[1] = tcInd;
+ state[tcInd].n[2] = tdInd;
+
+ state[tdInd].n[0] = tcInd;
+ state[tdInd].n[1] = taInd;
+ state[taInd].n[1] = tdInd;
+ state[tdInd].n[2] = state[oppositeTr].n[(oped + 1) % 3];
+ if (state[oppositeTr].n[(oped + 2) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[oppositeTr].n[(oped + 2) % 3]].n[k] == oppositeTr) {
+ state[state[oppositeTr].n[(oped + 2) % 3]].n[k] = tcInd; break;
+ }
+ if (state[oppositeTr].n[(oped + 1) % 3] != -1)
+ for (int32_t k = 0; k < 3; ++k)
+ if (state[state[oppositeTr].n[(oped + 1) % 3]].n[k] == oppositeTr) {
+ state[state[oppositeTr].n[(oped + 1) % 3]].n[k] = tdInd; break;
+ }
+
+ int32_t pop = state[oppositeTr].p[(oped + 2) % 3];
+ state[tcInd].p[0] = pop;
+ state[tcInd].p[1] = state[i].p[(cv + 1) % 3];
+ state[tcInd].p[2] = p;
+
+ state[tdInd].p[0] = pop;
+ state[tdInd].p[1] = p;
+ state[tdInd].p[2] = state[i].p[cv];
+
+
+ state[oppositeTr].p[0] = -1;
+ triangleToCheck.push(tcInd);
+ triangleToCheck.push(tdInd);
+ }
+ state[i].p[0] = -1;
+ }
+ break;
+ }
+
+ while (!triangleToCheck.empty())
+ {
+ int32_t ctrid = triangleToCheck.front();
+ triangleToCheck.pop();
+ DelTriangle& ctr = state[ctrid];
+ int32_t oppTr = -5;
+ int32_t ced = 0;
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (ctr.p[i] != p && ctr.p[(i + 1) % 3] != p)
+ {
+ ced = i;
+ oppTr = ctr.n[i];
+ break;
+ }
+ }
+ if (oppTr == -1) continue;
+ bool toCont = false;
+ for (size_t i = 0; i < edges.size(); ++i)
+ {
+ if ((int32_t)edges[i].s == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].e) { toCont = true; break; }
+ if ((int32_t)edges[i].e == ctr.p[ced] && ctr.p[(ced + 1) % 3] == (int32_t)edges[i].s) { toCont = true; break; }
+ }
+ if (toCont) continue;
+
+
+ DelTriangle& otr = state[oppTr];
+
+ if (inCircumcircle(vertices[state[oppTr].p[0]], vertices[state[oppTr].p[1]], vertices[state[oppTr].p[2]], vertices[p]) > 0)
+ {
+ int32_t notPIndx = 0;
+ for (; notPIndx < 3; ++notPIndx)
+ {
+ if (otr.p[notPIndx] != ctr.p[0] && otr.p[notPIndx] != ctr.p[1] && otr.p[notPIndx] != ctr.p[2])
+ break;
+ }
+
+ int32_t oppCed = state[oppTr].getEdId(ctr.p[(ced + 1) % 3], ctr.p[ced]);
+
+ int32_t ntr1 = ctrid, ntr2 = oppTr;
+
+ DelTriangle nt1, nt2;
+ nt1.p[0] = state[oppTr].p[notPIndx];
+ nt1.p[1] = p;
+ nt1.n[0] = ntr2;
+ nt1.p[2] = ctr.p[ced];
+ nt1.n[1] = ctr.n[(ced + 2) % 3];
+ nt1.n[2] = otr.n[(oppCed + 1) % 3];
+
+ if (nt1.n[2] != -1)
+ for (uint32_t k = 0; k < 3; ++k)
+ if (state[nt1.n[2]].n[k] == oppTr) state[nt1.n[2]].n[k] = ntr1;
+
+ nt2.p[0] = p;
+ nt2.p[1] = state[oppTr].p[notPIndx];
+ nt2.n[0] = ntr1;
+ nt2.p[2] = ctr.p[(ced + 1) % 3];
+ nt2.n[1] = otr.n[(oppCed + 2) % 3];
+ nt2.n[2] = ctr.n[(ced + 1) % 3];
+ if (nt2.n[2] != -1)
+ for (uint32_t k = 0; k < 3; ++k)
+ if (state[nt2.n[2]].n[k] == ctrid) state[nt2.n[2]].n[k] = ntr2;
+ state[ntr1] = nt1;
+ state[ntr2] = nt2;
+ triangleToCheck.push(ntr1);
+ triangleToCheck.push(ntr2);
+ }
+ }
+
+}
+
+bool edgeIsIntersected(const RVec2& a, const RVec2& b, const RVec2& es, const RVec2& ee)
+{
+ RVec2 t = b - a;
+ cpp_rational temp = (es - a).cross(t) * (ee - a).cross(t);
+
+ if (temp < 0)
+ {
+ t = es - ee;
+ if ((a - ee).cross(t) * (b - ee).cross(t) <= 0) return true;
+ }
+ return false;
+}
+
+void triangulatePseudoPolygon(std::vector<RVec2>& vertices, int32_t ba, int32_t bb, std::vector<int32_t>& pseudo, std::vector<DelTriangle>& output)
+{
+ if (pseudo.empty()) return;
+
+ int32_t c = 0;
+ if (pseudo.size() > 1)
+ {
+ for (uint32_t i = 1; i < pseudo.size(); ++i)
+ {
+ if (inCircumcircle(vertices[ba], vertices[bb], vertices[pseudo[c]], vertices[pseudo[i]]) > 0)
+ {
+ c = i;
+ }
+ }
+ std::vector<int32_t> toLeft;
+ std::vector<int32_t> toRight;
+
+ for (int32_t t = 0; t < c; ++t)
+ {
+ toLeft.push_back(pseudo[t]);
+ }
+ for (size_t t = c + 1; t < pseudo.size(); ++t)
+ {
+ toRight.push_back(pseudo[t]);
+ }
+ if (toLeft.size() > 0)
+ triangulatePseudoPolygon(vertices, ba, pseudo[c], toLeft, output);
+ if (toRight.size() > 0)
+ triangulatePseudoPolygon(vertices, pseudo[c], bb, toRight, output);
+ }
+ output.push_back(DelTriangle());
+ output.back().p[0] = ba;
+ output.back().p[1] = bb;
+ output.back().p[2] = pseudo[c];
+}
+
+
+
+void insertEdge(std::vector<RVec2>& vertices, std::vector<DelTriangle>& output, int32_t edBeg, int32_t edEnd)
+{
+ bool hasEdge = false;
+ for (auto& it : output)
+ {
+ for (uint32_t i = 0; i < 3; ++i)
+ if ((it.p[i] == edBeg || it.p[i] == edEnd) && (it.p[(i + 1) % 3] == edBeg || it.p[(i + 1) % 3] == edEnd))
+ {
+ hasEdge = true;
+ }
+ }
+ if (hasEdge) return;
+
+ int32_t startTriangle = -1;
+ int32_t edg = -1;
+ for (uint32_t i = 0; i < output.size(); ++i)
+ {
+ if (output[i].p[0] == -1) continue;
+
+ if (output[i].p[0] == edBeg || output[i].p[1] == edBeg || output[i].p[2] == edBeg)
+ {
+ edg = output[i].getEdWP(edBeg);
+ if (edgeIsIntersected(vertices[edBeg], vertices[edEnd], vertices[output[i].p[edg]], vertices[output[i].p[(edg + 1) % 3]]))
+ {
+ startTriangle = i;
+ break;
+ }
+ }
+ }
+ if (startTriangle == -1)
+ {
+ return;
+ }
+ int32_t cvertex = edBeg;
+
+ std::vector<int32_t> pointsAboveEdge;
+ std::vector<int32_t> pointsBelowEdge;
+
+ RVec2 vec = vertices[edEnd] - vertices[edBeg];
+
+ if (vec.cross(vertices[output[startTriangle].p[edg]] - vertices[edBeg]) > 0)
+ {
+ pointsAboveEdge.push_back(output[startTriangle].p[edg]);
+ pointsBelowEdge.push_back(output[startTriangle].p[(edg + 1) % 3]);
+ }
+ else
+ {
+ pointsBelowEdge.push_back(output[startTriangle].p[edg]);
+ pointsAboveEdge.push_back(output[startTriangle].p[(edg + 1) % 3]);
+ }
+
+ while (1)
+ {
+ DelTriangle& ctr = output[startTriangle];
+ int32_t oed = ctr.getEdWP(cvertex);
+ int32_t nextTriangle = ctr.n[oed];
+
+ if (output[nextTriangle].p[0] == edEnd || output[nextTriangle].p[1] == edEnd || output[nextTriangle].p[2] == edEnd)
+ {
+ ctr.p[0] = -1;
+ output[nextTriangle].p[0] = -1;
+ break;
+ }
+
+ DelTriangle& otr = output[nextTriangle];
+ int32_t opp = otr.p[otr.getOppP(ctr.p[(oed + 1) % 3], ctr.p[oed % 3])];
+
+ int32_t nextPoint = 0;
+ if (vec.cross((vertices[opp] - vertices[edBeg])) > 0)
+ {
+ pointsAboveEdge.push_back(opp);
+ if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) > 0)
+ {
+ nextPoint = ctr.p[(oed + 1) % 3];
+ }
+ else
+ {
+ nextPoint = ctr.p[oed];
+ }
+ }
+ else
+ {
+ pointsBelowEdge.push_back(opp);
+
+ if (vec.cross(vertices[ctr.p[(oed + 1) % 3]] - vertices[edBeg]) < 0)
+ {
+ nextPoint = ctr.p[(oed + 1) % 3];
+ }
+ else
+ {
+ nextPoint = ctr.p[oed];
+ }
+ }
+ startTriangle = nextTriangle;
+ cvertex = nextPoint;
+ ctr.p[0] = -1;
+ }
+ triangulatePseudoPolygon(vertices, edBeg, edEnd, pointsAboveEdge, output);
+ std::reverse(pointsBelowEdge.begin(), pointsBelowEdge.end());
+ triangulatePseudoPolygon(vertices, edEnd, edBeg, pointsBelowEdge, output);
+ reubildAdjacency(output);
+}
+
+
+
+
+
+
+void buildCDT(std::vector<RVec3>& vertices, std::vector<Edge>& edges, std::vector<DelTriangle>& output, ProjectionDirections dr)
+{
+ std::vector<DelTriangle> state;
+
+ DelTriangle crt;
+ std::vector<bool> added(vertices.size(), false);
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ crt.p[i] = edges[i].s;
+ added[edges[i].s] = true;
+ crt.n[i] = -1; // dont have neighboors;
+ }
+ state.push_back(crt);
+
+
+ std::vector<RVec2> p2d(vertices.size());
+ for (uint32_t i = 0; i < vertices.size(); ++i)
+ {
+ p2d[i] = getProjectedPointWithWinding(vertices[i], dr);
+ }
+
+ for (size_t i = 0; i < edges.size(); ++i)
+ {
+ if (!added[edges[i].s])
+ {
+ insertPoint(p2d, state, edges[i].s, edges);
+ added[edges[i].s] = true;
+ }
+ if (!added[edges[i].e])
+ {
+ insertPoint(p2d, state, edges[i].e, edges);
+ added[edges[i].e] = true;
+ }
+ if (edges[i].s != edges[i].e)
+ {
+ insertEdge(p2d, state, edges[i].s, edges[i].e);
+ }
+ }
+
+ for (uint32_t t = 0; t < state.size(); ++t)
+ {
+ if (state[t].p[0] != -1)
+ {
+ output.push_back(state[t]);
+ }
+ }
+}
+
+int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v);
+
+void getTriangleIntersectionCoplanar(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr)
+{
+ std::vector<cpp_rational> intr1[3];
+ std::vector<cpp_rational> intr2[3];
+
+ RVec3 p1[3];
+ p1[0] = stencil[tr1][0];
+ p1[1] = stencil[tr1][1];
+ p1[2] = stencil[tr1][3];
+
+ RVec3 p2[3];
+ p2[0] = stencil[tr2][0];
+ p2[1] = stencil[tr2][1];
+ p2[2] = stencil[tr2][3];
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ for (uint32_t j = 0; j < 3; ++j)
+ {
+ intersectSegments(p1[i], p1[(i + 1) % 3], p2[j], p2[(j + 1) % 3], dr, intr1[i], intr2[j]);
+ }
+ }
+
+ int32_t inRel1[3];
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ inRel1[i] = isPointInside(getProjectedPointWithWinding(p2[0], dr), getProjectedPointWithWinding(p2[1], dr), getProjectedPointWithWinding(p2[2], dr), getProjectedPointWithWinding(p1[i], dr));
+ }
+
+ int32_t inRel2[3];
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ inRel2[i] = isPointInside(getProjectedPointWithWinding(p1[0], dr), getProjectedPointWithWinding(p1[1], dr), getProjectedPointWithWinding(p1[2], dr), getProjectedPointWithWinding(p2[i], dr));
+ }
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (inRel1[i] == INSIDE_TR && inRel1[(i + 1) % 3] == INSIDE_TR)
+ {
+ stencil[tr2].push_back(p1[i]);
+ stencil[tr2].push_back(p1[(i + 1) % 3]);
+ }
+ else
+ {
+ if (inRel1[i] == INSIDE_TR && intr1[i].size() == 1)
+ {
+ stencil[tr2].push_back(p1[i]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ }
+ if (inRel1[(i + 1) % 3] == INSIDE_TR && intr1[i].size() == 1)
+ {
+ stencil[tr2].push_back(p1[(i + 1) % 3]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ }
+ if (intr1[i].size() == 2)
+ {
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][0] + p1[i]);
+ stencil[tr2].push_back((p1[(i + 1) % 3] - p1[i]) * intr1[i][1] + p1[i]);
+ }
+ }
+ }
+
+ for (uint32_t i = 0; i < 3; ++i)
+ {
+ if (inRel2[i] == INSIDE_TR && inRel2[(i + 1) % 3] == INSIDE_TR)
+ {
+ stencil[tr1].push_back(p2[i]);
+ stencil[tr1].push_back(p2[(i + 1) % 3]);
+ }
+ else
+ {
+ if (inRel2[i] == INSIDE_TR && intr2[i].size() == 1)
+ {
+ stencil[tr1].push_back(p2[i]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ }
+ if (inRel2[(i + 1) % 3] == INSIDE_TR && intr2[i].size() == 1)
+ {
+ stencil[tr1].push_back(p2[(i + 1) % 3]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ }
+ if (intr2[i].size() == 2)
+ {
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][0] + p2[i]);
+ stencil[tr1].push_back((p2[(i + 1) % 3] - p2[i]) * intr2[i][1] + p2[i]);
+ }
+ }
+ }
+}
+
+
+int32_t getTriangleIntersection3d(uint32_t tr1, uint32_t tr2, std::vector<std::vector<RVec3>>& stencil, ProjectionDirections dr)
+{
+ RatPlane pl1(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]);
+ if (pl1.n.isZero())
+ {
+ std::swap(tr1, tr2);
+ pl1 = RatPlane(stencil[tr1][0], stencil[tr1][1], stencil[tr1][3]);
+ if (pl1.n.isZero()) return 0;
+ }
+
+
+ cpp_rational d1 = pl1.distance(stencil[tr2][0]);
+ cpp_rational d2 = pl1.distance(stencil[tr2][1]);
+ cpp_rational d3 = pl1.distance(stencil[tr2][3]);
+
+ int32_t sd1 = d1.sign();
+ int32_t sd2 = d2.sign();
+ int32_t sd3 = d3.sign();
+
+
+ if (sd1 == 0 && sd2 == 0 && sd3 == 0)
+ {
+ getTriangleIntersectionCoplanar(tr1, tr2, stencil, dr);
+ return 0;
+ }
+ /**
+ Never intersected
+ */
+ if (sd1 < 0 && sd2 < 0 && sd3 < 0)
+ return 0;
+ if (sd1 > 0 && sd2 > 0 && sd3 > 0)
+ return 0;
+
+ RVec3 tb0 = stencil[tr2][0];
+ RVec3 tb1 = stencil[tr2][1];
+ RVec3 tb2 = stencil[tr2][3];
+
+ if (sd1 * sd3 > 0)
+ {
+ std::swap(tb1, tb2);
+ std::swap(d2, d3);
+ }
+ else
+ {
+ if (sd2 * sd3 > 0)
+ {
+ std::swap(tb0, tb2);
+ std::swap(d1, d3);
+ }
+ else
+ {
+ if (sd3 == 0 && sd1 * sd2 < 0)
+ {
+ std::swap(tb0, tb2);
+ std::swap(d1, d3);
+ }
+ }
+ }
+
+ RatPlane pl2(stencil[tr2][0], stencil[tr2][1], stencil[tr2][3]);
+
+ cpp_rational d21 = pl2.distance(stencil[tr1][0]);
+ cpp_rational d22 = pl2.distance(stencil[tr1][1]);
+ cpp_rational d23 = pl2.distance(stencil[tr1][3]);
+
+ int32_t sd21 = d21.sign();
+ int32_t sd22 = d22.sign();
+ int32_t sd23 = d23.sign();
+
+ if (sd21 < 0 && sd22 < 0 && sd23 < 0)
+ return 0;
+ if (sd21 > 0 && sd22 > 0 && sd23 > 0)
+ return 0;
+
+
+ RVec3 ta0 = stencil[tr1][0];
+ RVec3 ta1 = stencil[tr1][1];
+ RVec3 ta2 = stencil[tr1][3];
+
+
+ if (sd21 * sd23 > 0)
+ {
+ std::swap(ta1, ta2);
+ std::swap(d22, d23);
+ }
+ else
+ {
+ if (sd22 * sd23 > 0)
+ {
+ std::swap(ta0, ta2);
+ std::swap(d21, d23);
+ }
+ else
+ {
+ if (sd23 == 0 && sd21 * sd22 < 0)
+ {
+ std::swap(ta0, ta2);
+ std::swap(d21, d23);
+ }
+ }
+ }
+ //////////////////////////////////////////////////
+ RVec3 dir = ta2 - ta0;
+
+ cpp_rational dirPlaneDot = dir.dot(pl2.n);
+
+
+ RVec3 pointOnIntersectionLine;
+ if (dirPlaneDot != 0)
+ {
+ pointOnIntersectionLine = ta0 - dir * (d21 / dirPlaneDot);
+ }
+ else
+ {
+ pointOnIntersectionLine = ta0;
+ }
+ RVec3 interLineDir = pl1.n.cross(pl2.n);
+ cpp_rational sqd = interLineDir.dot(interLineDir);
+ if (sqd.is_zero()) return 0;
+
+ cpp_rational t1p2 = (ta1 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t1p3 = (ta2 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t1p2param = t1p2;
+ if (d22 != d23)
+ {
+ t1p2param = t1p2 + (t1p3 - t1p2) * (d22 / (d22 - d23));
+ }
+
+ t1p2 = (tb0 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ t1p3 = (tb2 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t2p1param = t1p2;
+ if (d1 != d3)
+ {
+ t2p1param = t1p2 + (t1p3 - t1p2) * d1 / (d1 - d3);
+ }
+
+ t1p2 = (tb1 - pointOnIntersectionLine).dot(interLineDir) / sqd;
+ cpp_rational t2p2param = t1p2;
+ if (d2 != d3)
+ {
+ t2p2param = t1p2 + (t1p3 - t1p2) * d2 / (d2 - d3);
+ }
+ cpp_rational beg1 = 0;
+
+ if (t1p2param < 0)
+ {
+ std::swap(beg1, t1p2param);
+ }
+ if (t2p2param < t2p1param)
+ {
+ std::swap(t2p2param, t2p1param);
+ }
+ cpp_rational minEnd = std::min(t1p2param, t2p2param);
+ cpp_rational maxBeg = std::max(beg1, t2p1param);
+
+ if (minEnd > maxBeg)
+ {
+ RVec3 p1 = pointOnIntersectionLine + interLineDir * maxBeg;
+ RVec3 p2 = pointOnIntersectionLine + interLineDir * minEnd;
+
+ stencil[tr1].push_back(p1);
+ stencil[tr1].push_back(p2);
+
+ stencil[tr2].push_back(p1);
+ stencil[tr2].push_back(p2);
+ return 1;
+ }
+ return 0;
+}
+
+int32_t intersectSegments(RVec3& s1, RVec3& e1, RVec3& s2, RVec3& e2, ProjectionDirections dir, std::vector<cpp_rational>& t1v, std::vector<cpp_rational>& t2v)
+{
+ RVec2 s1p = getProjectedPointWithWinding(s1, dir);
+ RVec2 e1p = getProjectedPointWithWinding(e1, dir);
+
+ RVec2 s2p = getProjectedPointWithWinding(s2, dir);
+ RVec2 e2p = getProjectedPointWithWinding(e2, dir);
+
+ RVec2 dir1 = e1p - s1p;
+ RVec2 dir2 = s2p - e2p;
+
+ cpp_rational crs = dir1.cross(dir2);
+ if (crs != 0)
+ {
+ cpp_rational c1 = s2p.x - s1p.x;
+ cpp_rational c2 = s2p.y - s1p.y;
+
+ cpp_rational det1 = c1 * dir2.y - c2 * dir2.x;
+ cpp_rational det2 = dir1.x * c2 - dir1.y * c1;
+
+ cpp_rational t1 = det1 / crs;
+ cpp_rational t2 = det2 / crs;
+
+ if (t1 > 0 && t1 < 1 && (t2 >= 0 && t2 <= 1))
+ {
+ t1v.push_back(t1);
+ }
+ if (t2 > 0 && t2 < 1 && (t1 >= 0 && t1 <= 1))
+ {
+ t2v.push_back(t2);
+ }
+
+ }
+ else
+ {
+ if (dir1.cross(s2p - s1p) == 0)
+ {
+ if (dir1.x != 0)
+ {
+ cpp_rational t1 = (s2p.x - s1p.x) / dir1.x;
+ cpp_rational t2 = (e2p.x - s1p.x) / dir1.x;
+ if (t1 > 0 && t1 < 1) t1v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t1v.push_back(t2);
+ }
+ else
+ {
+ if (dir1.y != 0)
+ {
+ cpp_rational t1 = (s2p.y - s1p.y) / dir1.y;
+ cpp_rational t2 = (e2p.y - s1p.y) / dir1.y;
+ if (t1 > 0 && t1 < 1) t1v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t1v.push_back(t2);
+ }
+ }
+ }
+ if (dir2.cross(s1p - s2p) == 0)
+ {
+ dir2 = e2p - s2p;
+ if (dir2.x != 0)
+ {
+ cpp_rational t1 = (s1p.x - s2p.x) / dir2.x;
+ cpp_rational t2 = (e1p.x - s2p.x) / dir2.x;
+ if (t1 > 0 && t1 < 1) t2v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t2v.push_back(t2);
+ }
+ else
+ {
+ if (dir2.y != 0)
+ {
+ cpp_rational t1 = (s1p.y - s2p.y) / dir2.y;
+ cpp_rational t2 = (e1p.y - s2p.y) / dir2.y;
+ if (t1 > 0 && t1 < 1) t2v.push_back(t1);
+ if (t2 > 0 && t2 < 1) t2v.push_back(t2);
+ }
+ }
+ }
+ }
+ return 1;
+}
+
+struct RVec3Comparer
+{
+ bool operator()(const RVec3& a, const RVec3& b) const
+ {
+ if (a.x < b.x) return true;
+ if (a.x > b.x) return false;
+ if (a.y < b.y) return true;
+ if (a.y > b.y) return false;
+ if (a.z < b.z) return true;
+ return false;
+ }
+};
+
+void getBarycentricCoords(PxVec2& a, PxVec2& b, PxVec2& c, PxVec2& p, float& u, float& v)
+{
+ PxVec3 v1(b.x - a.x, c.x - a.x, a.x - p.x);
+ PxVec3 v2(b.y - a.y, c.y - a.y, a.y - p.y);
+
+ PxVec3 resl = v1.cross(v2);
+ u = resl.x / resl.z;
+ v = resl.y / resl.z;
+}
+
+
+Mesh* MeshCleanerImpl::cleanMesh(const Mesh* mesh)
+{
+ /**
+ ======= Get mesh data ===========
+ */
+ std::vector<Vertex> vertices;
+ std::vector<Edge> edges;
+ std::vector<Facet> facets;
+
+ vertices.resize(mesh->getVerticesCount());
+ edges.resize(mesh->getEdgesCount());
+ facets.resize(mesh->getFacetCount());
+
+ PxBounds3 bnd;
+ bnd.setEmpty();
+
+ for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
+ {
+ vertices[i] = mesh->getVertices()[i];
+ bnd.include(vertices[i].p);
+ }
+ for (uint32_t i = 0; i < mesh->getEdgesCount(); ++i)
+ {
+ edges[i] = mesh->getEdges()[i];
+ }
+ for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
+ {
+ facets[i] = mesh->getFacetsBuffer()[i];
+ }
+ //======================================
+
+ /**
+ Transform vertices to fit unit cube and snap them to grid.
+ **/
+ float scale = 1.0f / bnd.getExtents().abs().maxElement();
+
+ int32_t gridSize = 10000; // Grid resolution to which vertices position will be snapped.
+
+ for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
+ {
+ vertices[i].p = (vertices[i].p - bnd.minimum) * scale;
+ vertices[i].p.x = std::floor(vertices[i].p.x * gridSize) / gridSize;
+ vertices[i].p.y = std::floor(vertices[i].p.y * gridSize) / gridSize;
+ vertices[i].p.z = std::floor(vertices[i].p.z * gridSize) / gridSize;
+ }
+
+ std::vector<std::vector<RVec3>> triangleStencil(facets.size());
+
+ std::vector<PxVec3> facetsNormals(facets.size());
+ std::vector<PxBounds3> facetBound(facets.size());
+
+
+ for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1)
+ {
+ if (facets[tr1].edgesCount != 3)
+ {
+ return nullptr;
+ }
+ int32_t fed = facets[tr1].firstEdgeNumber;
+ triangleStencil[tr1].push_back(vertices[edges[fed].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed].e].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 1].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 1].e].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 2].s].p);
+ triangleStencil[tr1].push_back(vertices[edges[fed + 2].e].p);
+
+ facetBound[tr1].setEmpty();
+ facetBound[tr1].include(vertices[edges[fed].s].p);
+ facetBound[tr1].include(vertices[edges[fed].e].p);
+ facetBound[tr1].include(vertices[edges[fed + 2].s].p);
+ facetBound[tr1].fattenFast(0.001f);
+
+ facetsNormals[tr1] = (vertices[edges[fed + 1].s].p - vertices[edges[fed].s].p).cross(vertices[edges[fed + 2].s].p - vertices[edges[fed].s].p);
+ }
+
+ /**
+ Build intersections between all pairs of triangles.
+ */
+ for (uint32_t tr1 = 0; tr1 < facets.size(); ++tr1)
+ {
+ if (triangleStencil[tr1].empty()) continue;
+ for (uint32_t tr2 = tr1 + 1; tr2 < facets.size(); ++tr2)
+ {
+ if (triangleStencil[tr2].empty()) continue;
+ if (facetBound[tr1].intersects(facetBound[tr2]) == false) continue;
+
+ getTriangleIntersection3d(tr1, tr2, triangleStencil, getProjectionDirection(facetsNormals[tr1]));
+ }
+ }
+
+ /**
+ Reintersect all segments
+ */
+ for (uint32_t tr = 0; tr < triangleStencil.size(); ++tr)
+ {
+ std::vector<RVec3>& ctr = triangleStencil[tr];
+ std::vector<std::vector<cpp_rational> > perSegmentInters(ctr.size() / 2);
+ for (uint32_t sg1 = 6; sg1 < ctr.size(); sg1 += 2)
+ {
+ for (uint32_t sg2 = sg1 + 2; sg2 < ctr.size(); sg2 += 2)
+ {
+ intersectSegments(ctr[sg1], ctr[sg1 + 1], ctr[sg2], ctr[sg2 + 1], getProjectionDirection(facetsNormals[tr]), perSegmentInters[sg1 / 2], perSegmentInters[sg2 / 2]);
+ }
+ }
+
+ std::vector<RVec3> newStencil;
+ newStencil.reserve(ctr.size());
+
+ for (uint32_t i = 0; i < ctr.size(); i += 2)
+ {
+ int32_t csm = i / 2;
+ if (perSegmentInters[csm].size() == 0)
+ {
+ newStencil.push_back(ctr[i]);
+ newStencil.push_back(ctr[i + 1]);
+ }
+ else
+ {
+ cpp_rational current = 0;
+ newStencil.push_back(ctr[i]);
+ std::sort(perSegmentInters[csm].begin(), perSegmentInters[csm].end());
+ for (size_t j = 0; j < perSegmentInters[csm].size(); ++j)
+ {
+ if (perSegmentInters[csm][j] > current)
+ {
+ current = perSegmentInters[csm][j];
+ RVec3 pnt = (ctr[i + 1] - ctr[i]) * current + ctr[i];
+ newStencil.push_back(pnt);
+ newStencil.push_back(pnt);
+ }
+ }
+ newStencil.push_back(ctr[i + 1]);
+ }
+ }
+ ctr = newStencil;
+ }
+
+ std::vector<RVec3> finalPoints;
+
+ std::vector<std::vector<Edge>> tsten(facets.size());
+
+ {
+ std::map<RVec3, uint32_t, RVec3Comparer> mapping;
+ for (uint32_t tr1 = 0; tr1 < triangleStencil.size(); ++tr1)
+ {
+ for (uint32_t j = 0; j < triangleStencil[tr1].size(); j += 2)
+ {
+
+ auto it = mapping.find(triangleStencil[tr1][j]);
+ int32_t pt = 0;
+ if (it == mapping.end())
+ {
+ mapping[triangleStencil[tr1][j]] = finalPoints.size();
+ pt = finalPoints.size();
+ finalPoints.push_back(triangleStencil[tr1][j]);
+ }
+ else
+ {
+ pt = it->second;
+ }
+
+ Edge newed;
+
+ newed.s = pt;
+
+ it = mapping.find(triangleStencil[tr1][j + 1]);
+ if (it == mapping.end())
+ {
+ mapping[triangleStencil[tr1][j + 1]] = finalPoints.size();
+ pt = finalPoints.size();
+ finalPoints.push_back(triangleStencil[tr1][j + 1]);
+ }
+ else
+ {
+ pt = it->second;
+ }
+ newed.e = pt;
+ bool hasNewEdge = false;
+ for (uint32_t e = 0; e < tsten[tr1].size(); ++e)
+ {
+ if (tsten[tr1][e].s == newed.s && tsten[tr1][e].e == newed.e)
+ {
+ hasNewEdge = true;
+ break;
+ }
+ if (tsten[tr1][e].e == newed.s && tsten[tr1][e].s == newed.e)
+ {
+ hasNewEdge = true;
+ break;
+ }
+ }
+ if (!hasNewEdge) tsten[tr1].push_back(newed);
+ }
+ }
+ }
+
+ /**
+ Build constrained DT
+ */
+ std::vector<DelTriangle> trs;
+ for (uint32_t i = 0; i < tsten.size(); ++i)
+ {
+
+ if (tsten[i].size() < 3) continue;
+ if (tsten[i].size() > 3)
+ {
+ int32_t oldSize = trs.size();
+ buildCDT(finalPoints, tsten[i], trs, getProjectionDirection(facetsNormals[i]));
+ for (uint32_t k = oldSize; k < trs.size(); ++k)
+ trs[k].parentTriangle = i;
+ }
+ else
+ {
+ trs.push_back(DelTriangle());
+ trs.back().parentTriangle = i;
+ for (uint32_t v = 0; v < 3; ++v)
+ trs.back().p[v] = tsten[i][v].s;
+ }
+
+ }
+
+ /**
+ Remove 'deleted' triangles from array.
+ */
+ {
+ std::vector < DelTriangle > trstemp;
+ trstemp.reserve(trs.size());
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] != -1)
+ trstemp.push_back(trs[i]);
+ }
+ trs = trstemp;
+ }
+
+ /**
+ Filter exterior surface
+ */
+ std::vector<bool> fillingMask(trs.size(), false);
+
+ std::map<std::pair<int32_t, int32_t>, int32_t> edgeMap;
+ std::vector<std::vector<int32_t> > edgeToTriangleMapping;
+
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ if (trs[i].p[0] == trs[i].p[1] || trs[i].p[2] == trs[i].p[1] || trs[i].p[2] == trs[i].p[0])
+ {
+ trs[i].p[0] = -1;
+ continue;
+ }
+ #if 0 // Filter null-area triangles.
+ if ((finalPoints[trs[i].p[1]] - finalPoints[trs[i].p[0]]).cross(finalPoints[trs[i].p[2]] - finalPoints[trs[i].p[0]]).isZero())
+ {
+ trs[i].p[0] = -1;
+ continue;
+ }
+ #endif
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ int32_t es = trs[i].p[k];
+ int32_t ee = trs[i].p[(k + 1) % 3];
+ if (es > ee)
+ {
+ std::swap(es, ee);
+ }
+ auto pr = std::make_pair(es, ee);
+ auto iter = edgeMap.find(pr);
+ if (iter == edgeMap.end())
+ {
+ edgeMap[pr] = edgeToTriangleMapping.size();
+ trs[i].n[k] = edgeToTriangleMapping.size();
+ edgeToTriangleMapping.resize(edgeToTriangleMapping.size() + 1);
+ edgeToTriangleMapping.back().push_back(i);
+ }
+ else
+ {
+ for (uint32_t j = 0; j < edgeToTriangleMapping[iter->second].size(); ++j)
+ {
+ if (trs[edgeToTriangleMapping[iter->second][j]].compare(trs[i]))
+ {
+ trs[i].p[0] = -1;
+ break;
+ }
+ }
+ if (trs[i].p[0] != -1)
+ {
+ trs[i].n[k] = iter->second;
+ edgeToTriangleMapping[iter->second].push_back(i);
+ }
+ }
+ }
+ }
+
+ std::queue<int32_t> trque;
+ float maxx = -1000;
+ int32_t best = 0;
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ float m = std::max(finalPoints[trs[i].p[0]].x.convert_to<float>(), std::max(finalPoints[trs[i].p[1]].x.convert_to<float>(), finalPoints[trs[i].p[2]].x.convert_to<float>()));
+ if (m > maxx && facetsNormals[trs[i].parentTriangle].x > 0)
+ {
+ maxx = m;
+ best = i;
+ }
+ }
+
+ trque.push(best);
+ while (!trque.empty())
+ {
+ int32_t trid = trque.front();
+ fillingMask[trid] = true;
+ DelTriangle& tr = trs[trque.front()];
+ trque.pop();
+
+ for (uint32_t ed = 0; ed < 3; ++ed)
+ {
+ auto& tlist = edgeToTriangleMapping[tr.n[ed]];
+ if (tlist.size() == 2)
+ {
+ for (uint32_t k = 0; k < tlist.size(); ++k)
+ {
+ int32_t to = tlist[k];
+ if (to != trid && !fillingMask[to] && edgeToTriangleMapping[trs[to].n[0]].size() > 0 && edgeToTriangleMapping[trs[to].n[1]].size() > 0 && edgeToTriangleMapping[trs[to].n[2]].size() > 0)
+ {
+ trque.push(tlist[k]);
+ fillingMask[tlist[k]] = true;
+ }
+ }
+ }
+ if (tlist.size() > 2)
+ {
+ int32_t bestPath = (tlist[0] == trid) ? tlist[1] : tlist[0];
+ RVec3 start = finalPoints[trs[trid].p[ed]];
+ RVec3 axis = finalPoints[trs[trid].p[(ed + 1) % 3]] - start;
+ RVec3 nAxis = finalPoints[trs[trid].p[(ed + 2) % 3]] - start;
+ RVec3 normal = axis.cross(nAxis);
+
+
+ uint32_t op = trs[bestPath].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]);
+
+ RVec3 dir2 = (finalPoints[op] - start);
+ RVec3 normal2 = dir2.cross(axis);
+ cpp_rational bestDir = normal.cross(normal2).dot(axis);
+ cpp_rational oldDist = normal2.dot(normal2);
+ for (uint32_t k = 0; k < tlist.size(); ++k)
+ {
+ if (tlist[k] == trid) continue;
+ op = trs[tlist[k]].getOppPoint(trs[trid].p[ed], trs[trid].p[(ed + 1) % 3]);
+ dir2 = (finalPoints[op] - start);
+ normal2 = dir2.cross(axis);
+ cpp_rational newOne = normal.cross(normal2).dot(axis);
+
+ if (newOne * oldDist < bestDir * normal2.dot(normal2))
+ {
+ oldDist = normal2.dot(normal2);
+ bestPath = tlist[k];
+ bestDir = newOne;
+ }
+ }
+ if (!fillingMask[bestPath] && edgeToTriangleMapping[trs[bestPath].n[0]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[1]].size() > 0 && edgeToTriangleMapping[trs[bestPath].n[2]].size() > 0)
+ {
+ trque.push(bestPath);
+ fillingMask[bestPath] = true;
+ }
+ }
+ edgeToTriangleMapping[tr.n[ed]].clear();
+ }
+
+ }
+ for (uint32_t id = 0; id < trs.size(); ++id)
+ {
+ if (!fillingMask[id])
+ {
+ trs[id].p[0] = -1; // Remove triangle
+ }
+ }
+ /////////////////////////////////////////////////////////////////////////////////////////////
+
+ std::vector<PxVec3> newVertices;
+ newVertices.resize(finalPoints.size());
+ for (uint32_t i = 0; i < finalPoints.size(); ++i)
+ {
+ newVertices[i].x = finalPoints[i].x.convert_to<float>();
+ newVertices[i].y = finalPoints[i].y.convert_to<float>();
+ newVertices[i].z = finalPoints[i].z.convert_to<float>();
+ }
+ /**
+ Rescale mesh to initial coordinates.
+ */
+ for (uint32_t i = 0; i < finalPoints.size(); ++i)
+ {
+ newVertices[i] = newVertices[i] * (1.0f / scale) + bnd.minimum;
+ }
+ for (uint32_t i = 0; i < vertices.size(); ++i)
+ {
+ vertices[i].p = vertices[i].p * (1.0f / scale) + bnd.minimum;
+ }
+
+ std::vector<Triangle> result;
+ result.reserve(trs.size());
+ {
+ std::vector<PxVec2> projectedTriangles(facets.size() * 3);
+ std::vector<Vertex> normalTriangles(facets.size() * 3);
+
+ for (uint32_t i = 0; i < facets.size(); ++i)
+ {
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ normalTriangles[i * 3 + k] = vertices[edges[facets[i].firstEdgeNumber + k].s];
+ projectedTriangles[i * 3 + k] = getProjectedPointWithWinding(vertices[edges[facets[i].firstEdgeNumber + k].s].p, getProjectionDirection(facetsNormals[i]));
+ }
+ }
+
+ for (uint32_t i = 0; i < trs.size(); ++i)
+ {
+ if (trs[i].p[0] == -1) continue;
+ int32_t id = 0;
+ int32_t parentTriangle = trs[i].parentTriangle;
+ float u = 0, v = 0;
+ result.resize(result.size() + 1);
+ result.back().materialId = facets[parentTriangle].materialId;
+ result.back().smoothingGroup = facets[parentTriangle].smoothingGroup;
+ for (auto vert : { &result.back().a, &result.back().b , &result.back().c })
+ {
+ vert->p = newVertices[trs[i].p[id]];
+ PxVec2 p = getProjectedPointWithWinding(vert->p, getProjectionDirection(facetsNormals[parentTriangle]));
+ getBarycentricCoords(projectedTriangles[parentTriangle * 3], projectedTriangles[parentTriangle * 3 + 1], projectedTriangles[parentTriangle * 3 + 2], p, u, v);
+ vert->uv[0] = (1 - u - v) * normalTriangles[parentTriangle * 3].uv[0] + u * normalTriangles[parentTriangle * 3 + 1].uv[0] + v * normalTriangles[parentTriangle * 3 + 2].uv[0];
+ vert->n = (1 - u - v) * normalTriangles[parentTriangle * 3].n + u * normalTriangles[parentTriangle * 3 + 1].n + v * normalTriangles[parentTriangle * 3 + 2].n;
+ ++id;
+ }
+ }
+ }
+
+ /**
+ Reuse old buffers to create Mesh
+ */
+ std::vector<PxVec3> newMeshVertices(result.size() * 3);
+ std::vector<PxVec3> newMeshNormals(result.size() * 3);
+ std::vector<PxVec2> newMeshUvs(result.size() * 3);
+
+ std::vector<int32_t> newMaterialIds(result.size());
+ std::vector<int32_t> newSmoothingGroups(result.size());
+
+
+ for (uint32_t i = 0; i < result.size(); ++i)
+ {
+ Vertex* arr[3] = { &result[i].a, &result[i].b , &result[i].c };
+ for (uint32_t k = 0; k < 3; ++k)
+ {
+ newMeshVertices[i * 3 + k] = arr[k]->p;
+ newMeshNormals[i * 3 + k] = arr[k]->n;
+ newMeshUvs[i * 3 + k] = arr[k]->uv[0];
+ }
+ }
+ std::vector<uint32_t> serializedIndices;
+ serializedIndices.reserve(result.size() * 3);
+ int32_t cindex = 0;
+ for (uint32_t i = 0; i < result.size(); ++i)
+ {
+ newMaterialIds[i] = result[i].materialId;
+ newSmoothingGroups[i] = result[i].smoothingGroup;
+
+ for (uint32_t pi = 0; pi < 3; ++pi)
+ serializedIndices.push_back(cindex++);
+ }
+
+ MeshImpl* rMesh = new MeshImpl(newMeshVertices.data(), newMeshNormals.data(), newMeshUvs.data(), static_cast<uint32_t>(newMeshVertices.size()), serializedIndices.data(), static_cast<uint32_t>(serializedIndices.size()));
+ rMesh->setMaterialId(newMaterialIds.data());
+ rMesh->setSmoothingGroup(newSmoothingGroups.data());
+ return rMesh;
+}
+
+void MeshCleanerImpl::release()
+{
+ delete this;
+}
+
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.h
new file mode 100644
index 0000000..0eb1a85
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshCleanerImpl.h
@@ -0,0 +1,25 @@
+#include "NvBlastExtAuthoringMeshCleaner.h"
+
+namespace Nv
+{
+namespace Blast
+{
+
+class Mesh;
+
+class MeshCleanerImpl : public MeshCleaner
+{
+public:
+ /**
+ Tries to remove self intersections and open edges in interior of mesh.
+ \param[in] mesh Mesh to be cleaned.
+ \return Cleaned mesh or nullptr if failed.
+ */
+ virtual Mesh* cleanMesh(const Nv::Blast::Mesh* mesh) override;
+ virtual void release() override;
+
+ ~MeshCleanerImpl() {};
+};
+
+}
+} \ No newline at end of file
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMesh.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.cpp
index a25d2fe..3497fda 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringMesh.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.cpp
@@ -10,10 +10,11 @@
#define _CRT_SECURE_NO_WARNINGS
-#include "NvBlastExtAuthoringMesh.h"
+#include "NvBlastExtAuthoringMeshImpl.h"
#include "NvBlastExtAuthoringTypes.h"
#include <string.h>
#include "NvBlastExtAuthoringPerlinNoise.h"
+#include <cmath>
using physx::PxVec2;
using physx::PxVec3;
@@ -24,7 +25,7 @@ namespace Nv
namespace Blast
{
-Mesh::Mesh(PxVec3* position, PxVec3* normals, PxVec2* uv, uint32_t verticesCount, uint32_t* indices, uint32_t indicesCount)
+MeshImpl::MeshImpl(const PxVec3* position, const PxVec3* normals, const PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount)
{
mVertices.resize(verticesCount);
@@ -81,11 +82,14 @@ Mesh::Mesh(PxVec3* position, PxVec3* normals, PxVec2* uv, uint32_t verticesCount
mEdges[i + 2].e = indices[i];
mFacets[facetId].firstEdgeNumber = i;
mFacets[facetId].edgesCount = 3;
+ mFacets[facetId].materialId = 0;
+ //Unassigned for now
+ mFacets[facetId].smoothingGroup = -1;
facetId++;
}
}
-Mesh::Mesh(Vertex* vertices, Edge* edges, Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount)
+MeshImpl::MeshImpl(const Vertex* vertices, const Edge* edges, const Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount)
{
mVertices.resize(posCount);
mEdges.resize(edgesCount);
@@ -101,7 +105,7 @@ Mesh::Mesh(Vertex* vertices, Edge* edges, Facet* facets, uint32_t posCount, uint
}
}
-float Mesh::getMeshVolume()
+float MeshImpl::getMeshVolume()
{
/**
Check if mesh boundary consist only of triangles
@@ -124,53 +128,80 @@ float Mesh::getMeshVolume()
volume += (a.x * b.y * c.z - a.x * b.z * c.y - a.y * b.x * c.z + a.y * b.z * c.x + a.z * b.x * c.y - a.z * b.y * c.x);
}
- return (1.0f / 6.0f) * abs(volume);
+ return (1.0f / 6.0f) * std::abs(volume);
}
-uint32_t Mesh::getFacetCount()
+uint32_t MeshImpl::getFacetCount() const
{
return static_cast<uint32_t>(mFacets.size());
}
-Vertex* Mesh::getVertices()
+Vertex* MeshImpl::getVerticesWritable()
{
return mVertices.data();
}
-Edge* Mesh::getEdges()
+Edge* MeshImpl::getEdgesWritable()
{
return mEdges.data();
}
-uint32_t Mesh::getEdgesCount()
+const Vertex* MeshImpl::getVertices() const
+{
+ return mVertices.data();
+}
+
+const Edge* MeshImpl::getEdges() const
+{
+ return mEdges.data();
+}
+
+uint32_t MeshImpl::getEdgesCount() const
{
return static_cast<uint32_t>(mEdges.size());
}
-uint32_t Mesh::getVerticesCount()
+uint32_t MeshImpl::getVerticesCount() const
{
return static_cast<uint32_t>(mVertices.size());
}
-Facet* Mesh::getFacetsBuffer()
+Facet* MeshImpl::getFacetsBufferWritable()
{
return mFacets.data();
}
-Facet* Mesh::getFacet(int32_t facet)
+const Facet* MeshImpl::getFacetsBuffer() const
+{
+ return mFacets.data();
+}
+Facet* MeshImpl::getFacetWritable(int32_t facet)
+{
+ return &mFacets[facet];
+}
+const Facet* MeshImpl::getFacet(int32_t facet) const
{
return &mFacets[facet];
}
+MeshImpl::~MeshImpl()
+{
+}
+
+void MeshImpl::release()
+{
+ delete this;
+}
-Mesh::~Mesh()
+const PxBounds3& MeshImpl::getBoundingBox() const
{
+ return mBounds;
}
-PxBounds3& Mesh::getBoundingBox()
+PxBounds3& MeshImpl::getBoundingBoxWritable()
{
return mBounds;
}
-void Mesh::recalculateBoundingBox()
+void MeshImpl::recalculateBoundingBox()
{
mBounds.setEmpty();
for (uint32_t i = 0; i < mVertices.size(); ++i)
@@ -184,7 +215,7 @@ void Mesh::recalculateBoundingBox()
void getTangents(PxVec3& normal, PxVec3& t1, PxVec3& t2)
{
- if (abs(normal.z) < 0.9)
+ if (std::abs(normal.z) < 0.9)
{
t1 = normal.cross(PxVec3(0, 0, 1));
}
@@ -249,61 +280,85 @@ Mesh* getCuttingBox(const PxVec3& point, const PxVec3& normal, float size, int32
edges.push_back(Edge(1, 2));
edges.push_back(Edge(2, 3));
edges.push_back(Edge(3, 0));
- facets.push_back(Facet(0, 4, id));
+ facets.push_back(Facet(0, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(0, 3));
edges.push_back(Edge(3, 7));
edges.push_back(Edge(7, 4));
edges.push_back(Edge(4, 0));
- facets.push_back(Facet(4, 4, id));
+ facets.push_back(Facet(4, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(3, 2));
edges.push_back(Edge(2, 6));
edges.push_back(Edge(6, 7));
edges.push_back(Edge(7, 3));
- facets.push_back(Facet(8, 4, id));
+ facets.push_back(Facet(8, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(5, 6));
edges.push_back(Edge(6, 2));
edges.push_back(Edge(2, 1));
edges.push_back(Edge(1, 5));
- facets.push_back(Facet(12, 4, id));
+ facets.push_back(Facet(12, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(4, 5));
edges.push_back(Edge(5, 1));
edges.push_back(Edge(1, 0));
edges.push_back(Edge(0, 4));
- facets.push_back(Facet(16, 4, id));
+ facets.push_back(Facet(16, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(4, 7));
edges.push_back(Edge(7, 6));
edges.push_back(Edge(6, 5));
edges.push_back(Edge(5, 4));
- facets.push_back(Facet(20, 4, id));
- return new Mesh(positions.data(), edges.data(), facets.data(), static_cast<uint32_t>(positions.size()), static_cast<uint32_t>(edges.size()), static_cast<uint32_t>(facets.size()));
+ facets.push_back(Facet(20, 4, MATERIAL_INTERIOR, id));
+ return new MeshImpl(positions.data(), edges.data(), facets.data(), static_cast<uint32_t>(positions.size()), static_cast<uint32_t>(edges.size()), static_cast<uint32_t>(facets.size()));
}
void inverseNormalAndSetIndices(Mesh* mesh, int32_t id)
{
for (uint32_t i = 0; i < mesh->getVerticesCount(); ++i)
{
- mesh->getVertices()[i].n *= -1.0f;
+ mesh->getVerticesWritable()[i].n *= -1.0f;
}
for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
{
- mesh->getFacet(i)->userData = id;
+ mesh->getFacetWritable(i)->userData = id;
}
+}
+void MeshImpl::setMaterialId(int32_t* materialId)
+{
+ if (materialId != nullptr)
+ {
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ mFacets[i].materialId = *materialId;
+ ++materialId;
+ }
+ }
}
+void MeshImpl::setSmoothingGroup(int32_t* smoothingGroup)
+{
+ if (smoothingGroup != nullptr)
+ {
+ for (uint32_t i = 0; i < mFacets.size(); ++i)
+ {
+ mFacets[i].smoothingGroup = *smoothingGroup;
+ ++smoothingGroup;
+ }
+ }
+}
+
+
void setCuttingBox(const PxVec3& point, const PxVec3& normal, Mesh* mesh, float size, int32_t id)
{
PxVec3 t1, t2;
PxVec3 lNormal = normal.getNormalized();
getTangents(lNormal, t1, t2);
- Vertex* positions = mesh->getVertices();
+ Vertex* positions = mesh->getVerticesWritable();
positions[0].p = point + (t1 + t2) * size;
positions[1].p = point + (t2 - t1) * size;
@@ -332,12 +387,12 @@ void setCuttingBox(const PxVec3& point, const PxVec3& normal, Mesh* mesh, float
for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
{
- mesh->getFacet(i)->userData = id;
+ mesh->getFacetWritable(i)->userData = id;
}
mesh->recalculateBoundingBox();
}
-bool Mesh::isValid()
+bool MeshImpl::isValid() const
{
return mVertices.size() > 0 && mEdges.size() > 0 && mFacets.size() > 0;
}
@@ -388,7 +443,7 @@ Mesh* getNoisyCuttingBoxPair(const physx::PxVec3& point, const physx::PxVec3& no
edges.push_back(Edge(i * (resolution + 1) + j + 1, (i + 1) * (resolution + 1) + j + 1));
edges.push_back(Edge((i + 1) * (resolution + 1) + j + 1, (i + 1) * (resolution + 1) + j));
edges.push_back(Edge((i + 1) * (resolution + 1) + j, i * (resolution + 1) + j));
- facets.push_back(Facet(start, 4, id));
+ facets.push_back(Facet(start, 4, MATERIAL_INTERIOR, id));
}
}
uint32_t offset = (resolution + 1) * (resolution + 1);
@@ -437,7 +492,7 @@ Mesh* getNoisyCuttingBoxPair(const physx::PxVec3& point, const physx::PxVec3& no
edges.push_back(Edge(9 + offset, 8 + offset));
edges.push_back(Edge(8 + offset, 11 + offset));
- facets.push_back(Facet(edgeOffset, 8, id));
+ facets.push_back(Facet(edgeOffset, 8, MATERIAL_INTERIOR, id));
@@ -445,34 +500,34 @@ Mesh* getNoisyCuttingBoxPair(const physx::PxVec3& point, const physx::PxVec3& no
edges.push_back(Edge(3 + offset, 7 + offset));
edges.push_back(Edge(7 + offset, 4 + offset));
edges.push_back(Edge(4 + offset, 0 + offset));
- facets.push_back(Facet(8 + edgeOffset, 4, id));
+ facets.push_back(Facet(8 + edgeOffset, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(3 + offset, 2 + offset));
edges.push_back(Edge(2 + offset, 6 + offset));
edges.push_back(Edge(6 + offset, 7 + offset));
edges.push_back(Edge(7 + offset, 3 + offset));
- facets.push_back(Facet(12 + edgeOffset, 4, id));
+ facets.push_back(Facet(12 + edgeOffset, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(5 + offset, 6 + offset));
edges.push_back(Edge(6 + offset, 2 + offset));
edges.push_back(Edge(2 + offset, 1 + offset));
edges.push_back(Edge(1 + offset, 5 + offset));
- facets.push_back(Facet(16 + edgeOffset, 4, id));
+ facets.push_back(Facet(16 + edgeOffset, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(4 + offset, 5 + offset));
edges.push_back(Edge(5 + offset, 1 + offset));
edges.push_back(Edge(1 + offset, 0 + offset));
edges.push_back(Edge(0 + offset, 4 + offset));
- facets.push_back(Facet(20 + edgeOffset, 4, id));
+ facets.push_back(Facet(20 + edgeOffset, 4, MATERIAL_INTERIOR, id));
edges.push_back(Edge(4 + offset, 7 + offset));
edges.push_back(Edge(7 + offset, 6 + offset));
edges.push_back(Edge(6 + offset, 5 + offset));
edges.push_back(Edge(5 + offset, 4 + offset));
- facets.push_back(Facet(24 + edgeOffset, 4, id));
+ facets.push_back(Facet(24 + edgeOffset, 4, MATERIAL_INTERIOR, id));
//
- return new Mesh(vertices.data(), edges.data(), facets.data(), vertices.size(), edges.size(), facets.size());
+ return new MeshImpl(vertices.data(), edges.data(), facets.data(), vertices.size(), edges.size(), facets.size());
}
Mesh* getBigBox(const PxVec3& point, float size)
@@ -517,41 +572,41 @@ Mesh* getBigBox(const PxVec3& point, float size)
edges.push_back(Edge(1, 2));
edges.push_back(Edge(2, 3));
edges.push_back(Edge(3, 0));
- facets.push_back(Facet(0, 4));
+ facets.push_back(Facet(0, 4, MATERIAL_INTERIOR, 0));
edges.push_back(Edge(0, 3));
edges.push_back(Edge(3, 7));
edges.push_back(Edge(7, 4));
edges.push_back(Edge(4, 0));
- facets.push_back(Facet(4, 4));
+ facets.push_back(Facet(4, 4, MATERIAL_INTERIOR, 0));
edges.push_back(Edge(3, 2));
edges.push_back(Edge(2, 6));
edges.push_back(Edge(6, 7));
edges.push_back(Edge(7, 3));
- facets.push_back(Facet(8, 4));
+ facets.push_back(Facet(8, 4, MATERIAL_INTERIOR, 0));
edges.push_back(Edge(5, 6));
edges.push_back(Edge(6, 2));
edges.push_back(Edge(2, 1));
edges.push_back(Edge(1, 5));
- facets.push_back(Facet(12, 4));
+ facets.push_back(Facet(12, 4, MATERIAL_INTERIOR, 0));
edges.push_back(Edge(4, 5));
edges.push_back(Edge(5, 1));
edges.push_back(Edge(1, 0));
edges.push_back(Edge(0, 4));
- facets.push_back(Facet(16, 4));
+ facets.push_back(Facet(16, 4, MATERIAL_INTERIOR, 0));
edges.push_back(Edge(4, 7));
edges.push_back(Edge(7, 6));
edges.push_back(Edge(6, 5));
edges.push_back(Edge(5, 4));
- facets.push_back(Facet(20, 4));
+ facets.push_back(Facet(20, 4, MATERIAL_INTERIOR, 0));
for (int i = 0; i < 8; ++i)
positions[i].n = PxVec3(0, 0, 0);
- return new Mesh(positions.data(), edges.data(), facets.data(), static_cast<uint32_t>(positions.size()), static_cast<uint32_t>(edges.size()), static_cast<uint32_t>(facets.size()));
+ return new MeshImpl(positions.data(), edges.data(), facets.data(), static_cast<uint32_t>(positions.size()), static_cast<uint32_t>(edges.size()), static_cast<uint32_t>(facets.size()));
}
} // namespace Blast
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.h
new file mode 100644
index 0000000..ee36f9c
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshImpl.h
@@ -0,0 +1,212 @@
+/*
+* 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.
+*/
+
+#ifndef NVBLASTAUTHORINGMESHIMPL_H
+#define NVBLASTAUTHORINGMESHIMPL_H
+
+#include "NvBlastExtAuthoringMesh.h"
+#include <vector>
+
+namespace Nv
+{
+namespace Blast
+{
+
+/**
+ Class for internal mesh representation
+*/
+class MeshImpl : public Mesh
+{
+public:
+
+ /**
+ Constructs mesh object from array of triangles.
+ \param[in] position Array of vertex positions
+ \param[in] normals Array of vertex normals
+ \param[in] uv Array of vertex uv coordinates
+ \param[in] verticesCount Vertices count
+ \param[in] indices Array of vertex indices. Indices contain vertex index triplets which form a mesh triangle.
+ \param[in] indicesCount Indices count (should be equal to numberOfTriangles * 3)
+ */
+ MeshImpl(const physx::PxVec3* position, const physx::PxVec3* normals, const physx::PxVec2* uv, uint32_t verticesCount, const uint32_t* indices, uint32_t indicesCount);
+
+ /**
+ Constructs mesh object from array of facets.
+ \param[in] vertices Array of vertices
+ \param[in] edges Array of edges
+ \param[in] facets Array of facets
+ \param[in] posCount Vertices count
+ \param[in] edgesCount Edges count
+ \param[in] facetsCount Facets count
+ */
+ MeshImpl(const Vertex* vertices, const Edge* edges, const Facet* facets, uint32_t posCount, uint32_t edgesCount, uint32_t facetsCount);
+
+ ~MeshImpl();
+
+ virtual void release() override;
+
+ /**
+ Return true if mesh is valid
+ */
+ bool isValid() const override;
+
+ /**
+ Return pointer on vertices array
+ */
+ Vertex* getVerticesWritable() override;
+
+ /**
+ Return pointer on edges array
+ */
+ Edge* getEdgesWritable() override;
+
+ /**
+ Return pointer on facets array
+ */
+ Facet* getFacetsBufferWritable() override;
+
+ /**
+ Return pointer on vertices array
+ */
+ const Vertex* getVertices() const override;
+
+ /**
+ Return pointer on edges array
+ */
+ const Edge* getEdges() const override;
+
+ /**
+ Return pointer on facets array
+ */
+ const Facet* getFacetsBuffer() const override;
+
+ /**
+ Return writable pointer on specified facet
+ */
+ Facet* getFacetWritable(int32_t facet) override;
+
+ /**
+ Return writable pointer on specified facet
+ */
+ const Facet* getFacet(int32_t facet) const override;
+
+ /**
+ Return edges count
+ */
+ uint32_t getEdgesCount() const override;
+
+ /**
+ Return vertices count
+ */
+ uint32_t getVerticesCount() const override;
+
+ /**
+ Return facet count
+ */
+ uint32_t getFacetCount() const override;
+
+
+ /**
+ Return reference on mesh bounding box.
+ */
+ const physx::PxBounds3& getBoundingBox() const override;
+
+ /**
+ Return writable reference on mesh bounding box.
+ */
+ physx::PxBounds3& getBoundingBoxWritable() override;
+
+ /**
+ Recalculate bounding box
+ */
+ void recalculateBoundingBox() override;
+
+ /**
+ Compute mesh volume. Can be used only for triangulated meshes.
+ Return mesh volume. If mesh is not triangulated return 0.
+ */
+ float getMeshVolume() override;
+
+
+ /**
+ Set per-facet material id.
+ */
+ void setMaterialId(int32_t* materialIds) override;
+
+ /**
+ Set per-facet smoothing group.
+ */
+ void setSmoothingGroup(int32_t* smoothingGroup) override;
+
+private:
+ std::vector<Vertex> mVertices;
+ std::vector<Edge> mEdges;
+ std::vector<Facet> mFacets;
+ physx::PxBounds3 mBounds;
+};
+
+
+/**
+ Helper functions
+*/
+
+/**
+ Set cutting box at some particular position.
+ \param[in] point Cutting face center
+ \param[in] normal Cutting face normal
+ \param[in] mesh Cutting box mesh
+ \param[in] size Cutting box size
+ \param[in] id Cutting box ID
+*/
+void setCuttingBox(const physx::PxVec3& point, const physx::PxVec3& normal, Mesh* mesh, float size, int32_t id);
+/**
+ Create cutting box at some particular position.
+ \param[in] point Cutting face center
+ \param[in] normal Cutting face normal
+ \param[in] size Cutting box size
+ \param[in] id Cutting box ID
+*/
+Mesh* getCuttingBox(const physx::PxVec3& point, const physx::PxVec3& normal, float size, int32_t id);
+
+/**
+ Create box at some particular position.
+ \param[in] point Cutting face center
+ \param[in] size Cutting box size
+*/
+Mesh* getBigBox(const physx::PxVec3& point, float size);
+
+/**
+ Create slicing box with noisy cutting surface.
+ \param[in] point Cutting face center
+ \param[in] normal Cutting face normal
+ \param[in] size Cutting box size
+ \param[in] jaggedPlaneSize Noisy surface size
+ \param[in] resolution Noisy surface resolution
+ \param[in] id Cutting box ID
+ \param[in] amplitude Noise amplitude
+ \param[in] frequency Noise frequency
+ \param[in] octaves Noise octaves
+ \param[in] seed Random generator seed, used for noise generation.
+*/
+Mesh* getNoisyCuttingBoxPair(const physx::PxVec3& point, const physx::PxVec3& normal, float size, float jaggedPlaneSize, uint32_t resolution, int32_t id, float amplitude, float frequency, int32_t octaves, int32_t seed);
+
+
+/**
+ Inverses normals of cutting box and sets indices.
+ \param[in] mesh Cutting box mesh
+ \param[in] id Cutting box ID
+*/
+void inverseNormalAndSetIndices(Mesh* mesh, int32_t id);
+
+} // namespace Blast
+} // namespace Nv
+
+
+#endif // ifndef NVBLASTAUTHORINGMESHIMPL_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.cpp
new file mode 100644
index 0000000..72e9413
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.cpp
@@ -0,0 +1,975 @@
+// 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) 2017 NVIDIA Corporation. All rights reserved.
+
+
+// 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 "NvBlastExtAuthoringMeshNoiser.h"
+#include "NvBlastExtAuthoringPerlinNoise.h"
+#include <set>
+#include <queue>
+#include <NvBlastAssert.h>
+
+using namespace Nv::Blast;
+using namespace std;
+
+
+void MeshNoiser::computeFalloffAndNormals()
+{
+ // Map newly created vertices according to positions
+
+ computePositionedMapping();
+
+ mGeometryGraph.resize(mVertices.size());
+ for (uint32_t i = 0; i < mEdges.size(); ++i)
+ {
+ if (mTrMeshEdToTr[i].c == 0)
+ {
+ continue;
+ }
+ int32_t v1 = mPositionMappedVrt[mEdges[i].s];
+ int32_t v2 = mPositionMappedVrt[mEdges[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 < mEdges.size(); ++i)
+ {
+ if (mTrMeshEdToTr[i].c != 0 && (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE))
+ {
+ int32_t v1 = mPositionMappedVrt[mEdges[i].s];
+ int32_t v2 = mPositionMappedVrt[mEdges[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-6f && ((be - as).cross(ae - as)).magnitudeSquared() < 1e-6f;
+}
+
+void MeshNoiser::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 MeshNoiser::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();
+
+ }
+ }
+
+}
+
+NV_FORCE_INLINE void markEdge(int32_t ui, int32_t ed, std::vector<MeshNoiser::EdgeFlag>& shortMarkup, std::vector<int32_t>& lastOwner)
+{
+ if (shortMarkup[ed] == MeshNoiser::NONE)
+ {
+ if (ui == 0)
+ {
+ shortMarkup[ed] = MeshNoiser::EXTERNAL_EDGE;
+ }
+ else
+ {
+ shortMarkup[ed] = MeshNoiser::INTERNAL_EDGE;
+ }
+ lastOwner[ed] = ui;
+ }
+ else
+ {
+ if (ui != 0)
+ {
+ if (shortMarkup[ed] == MeshNoiser::EXTERNAL_EDGE)
+ {
+ shortMarkup[ed] = MeshNoiser::EXTERNAL_BORDER_EDGE;
+ }
+ if ((shortMarkup[ed] == MeshNoiser::INTERNAL_EDGE) && ui != lastOwner[ed])
+ {
+ shortMarkup[ed] = MeshNoiser::INTERNAL_BORDER_EDGE;
+ }
+ }
+ else
+ {
+ if (shortMarkup[ed] != MeshNoiser::EXTERNAL_EDGE)
+ {
+ shortMarkup[ed] = MeshNoiser::EXTERNAL_BORDER_EDGE;
+ }
+ }
+ }
+}
+
+void MeshNoiser::prebuildEdgeFlagArray()
+{
+ mRestrictionFlag.clear();
+ mRestrictionFlag.resize(mVertices.size());
+ mEdgeFlag.clear();
+ mEdgeFlag.resize(mEdges.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(mEdges.size());
+
+
+ for (uint32_t i = 0; i < mEdges.size(); ++i)
+ {
+ Edge tmp = Edge(mPositionMappedVrt[mEdges[i].s], mPositionMappedVrt[mEdges[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(mEdges.size(), NONE);
+ std::vector<int32_t> lastOwner(mEdges.size(), 0);
+
+ std::vector<std::vector<int32_t> > edgeOverlap(mEdges.size());
+ for (auto it1 = mPositionEdgeMap.begin(); it1 != mPositionEdgeMap.end(); ++it1)
+ {
+ auto it2 = it1;
+ it2++;
+ for (; it2 != mPositionEdgeMap.end(); ++it2)
+ {
+ Edge& ed1 = mEdges[it1->second];
+ Edge& ed2 = mEdges[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 < mTriangles.size(); ++i)
+ {
+ int32_t ui = mTriangles[i].userData;
+ int32_t ed = mPositionBasedEdges[findEdge(Edge(mTriangles[i].ea, mTriangles[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(mTriangles[i].ea, mTriangles[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(mTriangles[i].eb, mTriangles[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 < mEdges.size(); ++i)
+ {
+ mEdgeFlag[i] = shortMarkup[mPositionBasedEdges[i]];
+ }
+
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].userData != 0) continue;
+
+ int32_t ed = findEdge(Edge(mTriangles[i].ea, mTriangles[i].eb));
+ mEdgeFlag[ed] = EXTERNAL_EDGE;
+ ed = findEdge(Edge(mTriangles[i].ec, mTriangles[i].eb));
+ mEdgeFlag[ed] = EXTERNAL_EDGE;
+ ed = findEdge(Edge(mTriangles[i].ea, mTriangles[i].ec));
+ mEdgeFlag[ed] = EXTERNAL_EDGE;
+ }
+}
+
+
+
+
+NV_FORCE_INLINE int32_t MeshNoiser::addVerticeIfNotExist(const 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 int32_t MeshNoiser::addEdge(const Edge& e)
+{
+ Edge ed = e;
+ if (ed.e < ed.s) std::swap(ed.s, ed.e);
+ auto it = mEdgeMap.find(ed);
+ if (it == mEdgeMap.end())
+ {
+ mTrMeshEdToTr.push_back(EdgeToTriangles());
+ mEdgeMap[ed] = (int)mEdgeMap.size();
+ mEdges.push_back(ed);
+ mEdgeFlag.push_back(INTERNAL_EDGE);
+ return (int32_t)mEdges.size() - 1;
+ }
+ else
+ {
+ return it->second;
+ }
+}
+
+NV_FORCE_INLINE int32_t MeshNoiser::findEdge(const Edge& e)
+{
+ Edge ed = e;
+ if (ed.e < ed.s) std::swap(ed.s, ed.e);
+ auto it = mEdgeMap.find(ed);
+ if (it == mEdgeMap.end())
+ {
+ return -1;
+ }
+ else
+ {
+ return it->second;
+ }
+}
+
+
+/**
+ Weld input vertices, build edge and triangle buffers
+*/
+void MeshNoiser::setMesh(const vector<Triangle>& mesh)
+{
+ uint32_t a, b, c;
+ PxBounds3 box;
+ box.setEmpty();
+ for (uint32_t i = 0; i < mesh.size(); ++i)
+ {
+ const Triangle& tr = mesh[i];
+ a = addVerticeIfNotExist(tr.a);
+ b = addVerticeIfNotExist(tr.b);
+ c = addVerticeIfNotExist(tr.c);
+ box.include(tr.a.p);
+ box.include(tr.b.p);
+ box.include(tr.c.p);
+ addEdge(Edge(a, b));
+ addEdge(Edge(b, c));
+ addEdge(Edge(a, c));
+ mTriangles.push_back(TriangleIndexed(a, b, c));
+ mTriangles.back().userData = tr.userData;
+ mTriangles.back().materialId = tr.materialId;
+ mTriangles.back().smoothingGroup = tr.smoothingGroup;
+
+ }
+ mOffset = box.getCenter();
+ mScale = max(box.getExtents(0), max(box.getExtents(1), box.getExtents(2)));
+ float invScale = 1.0f / mScale;
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].p = mVertices[i].p - box.getCenter();
+ mVertices[i].p *= invScale;
+ }
+}
+
+
+void MeshNoiser::tesselateInternalSurface(float maxLenIn)
+{
+ if (mTriangles.empty())
+ {
+ return;
+ }
+
+ updateEdgeTriangleInfo();
+ prebuildEdgeFlagArray();
+ mRestrictionFlag.resize(mVertices.size(), 0);
+ for (uint32_t i = 0; i < mEdges.size(); ++i)
+ {
+ if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE || mEdgeFlag[i] == INTERNAL_BORDER_EDGE)
+ {
+ mRestrictionFlag[mEdges[i].s] = 1;
+ mRestrictionFlag[mEdges[i].e] = 1;
+ }
+ }
+
+
+ float 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)mEdges.size();
+ for (uint32_t i = 0; i < oldSize; ++i)
+ {
+ if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == INTERNAL_BORDER_EDGE)
+ {
+ continue;
+ }
+ if ((mVertices[mEdges[i].s].p - mVertices[mEdges[i].e].p).magnitudeSquared() < minD)
+ {
+ collapseEdge(i);
+ }
+ }
+ oldSize = (uint32_t)mEdges.size();
+ updateEdgeTriangleInfo();
+ for (uint32_t i = 0; i < oldSize; ++i)
+ {
+ if (mEdgeFlag[i] == EXTERNAL_EDGE)
+ {
+ continue;
+ }
+ if ((mVertices[mEdges[i].s].p - mVertices[mEdges[i].e].p).magnitudeSquared() > mlSq)
+ {
+ divideEdge(i);
+ }
+ }
+ }
+ computeFalloffAndNormals();
+ prebuildTesselatedTriangles();
+ isTesselated = true;
+}
+
+void MeshNoiser::updateEdgeTriangleInfo()
+{
+ mTrMeshEdToTr.clear();
+ mTrMeshEdToTr.resize(mEdges.size());
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ TriangleIndexed& tr = mTriangles[i];
+ if (tr.ea == NOT_VALID_VERTEX)
+ continue;
+ int32_t ed = addEdge(Edge(tr.ea, tr.eb));
+ mTrMeshEdToTr[ed].add(i);
+ ed = addEdge(Edge(tr.ea, tr.ec));
+ mTrMeshEdToTr[ed].add(i);
+ ed = addEdge(Edge(tr.ec, tr.eb));
+ mTrMeshEdToTr[ed].add(i);
+ }
+}
+
+void MeshNoiser::updateVertEdgeInfo()
+{
+ mVertexToTriangleMap.clear();
+ mVertexToTriangleMap.resize(mVertices.size());
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ TriangleIndexed& tr = mTriangles[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 < mEdges.size(); ++i)
+ {
+ if (mTrMeshEdToTr[i].c != 0)
+ {
+ mVertexValence[mEdges[i].s]++;
+ mVertexValence[mEdges[i].e]++;
+ }
+ }
+}
+
+
+void MeshNoiser::collapseEdge(int32_t id)
+{
+ Edge cEdge = mEdges[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 (mTriangles[mVertexToTriangleMap[from][i]].ea == NOT_VALID_VERTEX)
+ continue;
+ if (neighboorTriangles.insert(mVertexToTriangleMap[from][i]).second && mTriangles[mVertexToTriangleMap[from][i]].isContainEdge(from, to))
+ {
+ trWithEdge[cntr] = mVertexToTriangleMap[from][i];
+ cntr++;
+ }
+ }
+ for (uint32_t i = 0; i < mVertexToTriangleMap[to].size(); ++i)
+ {
+ if (mTriangles[mVertexToTriangleMap[to][i]].ea == NOT_VALID_VERTEX)
+ continue;
+ if (neighboorTriangles.insert(mVertexToTriangleMap[to][i]).second && mTriangles[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 (mTriangles[i].ea == from || mTriangles[i].eb == from || mTriangles[i].ec == from)
+ {
+ if (mTriangles[i].ea != to && mTriangles[i].ea != from)
+ connectedToBegin.insert(mTriangles[i].ea);
+ if (mTriangles[i].eb != to && mTriangles[i].eb != from)
+ connectedToBegin.insert(mTriangles[i].eb);
+ if (mTriangles[i].ec != to && mTriangles[i].ec != from)
+ connectedToBegin.insert(mTriangles[i].ec);
+ }
+
+ if (mTriangles[i].ea == to || mTriangles[i].eb == to || mTriangles[i].ec == to)
+ {
+ if (mTriangles[i].ea != to && mTriangles[i].ea != from)
+ connectedToEnd.insert(mTriangles[i].ea);
+ if (mTriangles[i].eb != to && mTriangles[i].eb != from)
+ connectedToEnd.insert(mTriangles[i].eb);
+ if (mTriangles[i].ec != to && mTriangles[i].ec != from)
+ connectedToEnd.insert(mTriangles[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 ((mTriangles[tr].ea == from || mTriangles[tr].eb == from || mTriangles[tr].ec == from) &&
+ (mTriangles[tr].ea == to || mTriangles[tr].eb == to || mTriangles[tr].ec == to) &&
+ (mTriangles[tr].ea == currV || mTriangles[tr].eb == currV || mTriangles[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 = mTriangles[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;
+ }
+ }
+ mTriangles[trWithEdge[0]].ea = NOT_VALID_VERTEX;
+ if (cntr == 2)mTriangles[trWithEdge[1]].ea = NOT_VALID_VERTEX;
+
+ for (int32_t i : neighboorTriangles)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ continue;
+ if (mTriangles[i].ea == from)
+ {
+ mTriangles[i].ea = to;
+ mVertexToTriangleMap[from].clear();
+ mVertexToTriangleMap[to].push_back(i);
+ }
+ else
+ if (mTriangles[i].eb == from)
+ {
+ mTriangles[i].eb = to;
+ mVertexToTriangleMap[from].clear();
+ mVertexToTriangleMap[to].push_back(i);
+ }
+ else
+ if (mTriangles[i].ec == from)
+ {
+ mTriangles[i].ec = to;
+ mVertexToTriangleMap[from].clear();
+ mVertexToTriangleMap[to].push_back(i);
+ }
+ }
+ }
+}
+
+
+void MeshNoiser::divideEdge(int32_t id)
+{
+
+ if (mTrMeshEdToTr[id].c == 0 )
+ {
+ return;
+ }
+
+ Edge cEdge = mEdges[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 = mTriangles[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 = addEdge(Edge(pbf[p], nv));
+ uint32_t ind2 = addEdge(Edge(nv, pbf[pnx]));
+ uint32_t ind3 = addEdge(Edge(nv, pbf[opp]));
+
+
+ mEdgeFlag[ind1] = snapRestriction;
+ mEdgeFlag[ind2] = snapRestriction;
+ mEdgeFlag[ind3] = INTERNAL_EDGE;
+
+ mTrMeshEdToTr[ind1].add(mTrMeshEdToTr[id].tr[t]);
+ int32_t userInfo = mTriangles[mTrMeshEdToTr[id].tr[t]].userData;
+ int32_t matId = mTriangles[mTrMeshEdToTr[id].tr[t]].materialId;
+ mTriangles[mTrMeshEdToTr[id].tr[t]] = TriangleIndexed(pbf[p], nv, pbf[opp]);
+ mTriangles[mTrMeshEdToTr[id].tr[t]].userData = userInfo;
+ mTriangles[mTrMeshEdToTr[id].tr[t]].materialId = matId;
+ mTrMeshEdToTr[ind2].add((int32_t)mTriangles.size());
+ mTrMeshEdToTr[ind3].add((int32_t)mTrMeshEdToTr[id].tr[t]);
+ mTrMeshEdToTr[ind3].add((int32_t)mTriangles.size());
+ mTriangles.push_back(TriangleIndexed(nv,pbf[pnx], pbf[opp]));
+ mTriangles.back().userData = userInfo;
+ mTriangles.back().materialId = matId;
+ int32_t ed1 = findEdge(Edge(pbf[pnx], pbf[opp]));
+ mTrMeshEdToTr[ed1].replace(oldTriangleIndex, (int32_t)mTriangles.size() - 1);
+ break;
+ }
+ }
+ }
+}
+
+
+float falloffFunction(float x, float mx)
+{
+ float t = (x) / (mx + 1e-6f);
+ t = std::min(1.0f, t);
+ return t * t;
+}
+
+void MeshNoiser::recalcNoiseDirs()
+{
+ /**
+ Compute normals direction to apply noise
+ */
+ mVerticesNormalsSmoothed.resize(mVertices.size(), PxVec3(0, 0, 0));
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ {
+ continue;
+ }
+ TriangleIndexed& tr = mTriangles[i];
+ if (tr.userData == 0) continue;
+
+ if (tr.userData < 0)
+ mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]] += mVertices[tr.ea].n.getNormalized();
+ else
+ mVerticesNormalsSmoothed[mPositionMappedVrt[tr.ea]] -= mVertices[tr.ea].n.getNormalized();
+
+ if (tr.userData < 0)
+ mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]] += mVertices[tr.eb].n.getNormalized();
+ else
+ mVerticesNormalsSmoothed[mPositionMappedVrt[tr.eb]] -= mVertices[tr.eb].n.getNormalized();
+
+ if (tr.userData < 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 MeshNoiser::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 < mEdges.size(); ++i)
+ {
+ if (mTrMeshEdToTr[i].c != 0)
+ {
+ if (mEdgeFlag[i] == EXTERNAL_EDGE || mEdgeFlag[i] == EXTERNAL_BORDER_EDGE)
+ {
+ mRestrictionFlag[mEdges[i].e] = true;
+ mRestrictionFlag[mEdges[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 < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ {
+ continue;
+ }
+ TriangleIndexed& tr = mTriangles[i];
+ if (tr.userData == 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 < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ {
+ continue;
+ }
+ TriangleIndexed& tr = mTriangles[i];
+ if (tr.userData == 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]];
+ }
+
+ mResultTriangles.clear();
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ {
+ continue;
+ }
+ mResultTriangles.push_back(Triangle(localVertices[mTriangles[i].ea], localVertices[mTriangles[i].eb], localVertices[mTriangles[i].ec]));
+ mResultTriangles.back().userData = mTriangles[i].userData;
+ mResultTriangles.back().materialId = mTriangles[i].materialId;
+ mResultTriangles.back().smoothingGroup = mTriangles[i].smoothingGroup;
+
+ }
+}
+
+
+void MeshNoiser::prebuildTesselatedTriangles()
+{
+ mResultTriangles.clear();
+
+ for (uint32_t i = 0; i < mVertices.size(); ++i)
+ {
+ mVertices[i].p = mVertices[i].p * mScale + mOffset;
+ }
+
+ for (uint32_t i = 0; i < mTriangles.size(); ++i)
+ {
+ if (mTriangles[i].ea == NOT_VALID_VERTEX)
+ {
+ continue;
+ }
+ mResultTriangles.push_back(Triangle(mVertices[mTriangles[i].ea], mVertices[mTriangles[i].eb], mVertices[mTriangles[i].ec]));
+ mResultTriangles.back().userData = mTriangles[i].userData;
+ mResultTriangles.back().materialId = mTriangles[i].materialId;
+ mResultTriangles.back().smoothingGroup = mTriangles[i].smoothingGroup;
+
+ }
+
+}
+
+
+std::vector<Triangle> MeshNoiser::getMesh()
+{
+ return mResultTriangles;
+}
+
+
+void MeshNoiser::reset()
+{
+ mVertices.clear();
+ mTriangles.clear();
+ mEdges.clear();
+ mVertMap.clear();
+ mEdgeMap.clear();
+ mResultTriangles.clear();
+ mRestrictionFlag.clear();
+ mEdgeFlag.clear();
+ mTrMeshEdToTr.clear();
+ mVertexValence.clear();
+ mVertexToTriangleMap.clear();
+
+ mVerticesDistances.clear();
+ mVerticesNormalsSmoothed.clear();
+ mPositionMappedVrt.clear();
+ mGeometryGraph.clear();
+
+ isTesselated = false;
+ mOffset = PxVec3(0, 0, 0);
+ mScale = 1.0f;
+} \ No newline at end of file
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.h
new file mode 100644
index 0000000..893cf63
--- /dev/null
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringMeshNoiser.h
@@ -0,0 +1,193 @@
+// 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-2017 NVIDIA Corporation. All rights reserved.
+
+
+#ifndef NVBLASTEXTAUTHORINGMESHNOISER_H
+#define NVBLASTEXTAUTHORINGMESHNOISER_H
+#include <vector>
+#include <map>
+#include "NvBlastExtAuthoringInternalCommon.h"
+
+namespace Nv
+{
+ namespace Blast
+ {
+ class SimplexNoise;
+
+ /**
+ Structure used on tesselation stage. Maps edge to two neighboor triangles
+ */
+ struct EdgeToTriangles
+ {
+ int32_t tr[2];
+ int32_t c;
+ EdgeToTriangles()
+ {
+ c = 0;
+ }
+ /**
+ Add triangle to edge. Should not be called more than twice for one edge!!!!.
+ */
+ void add(int32_t t)
+ {
+ tr[c] = t;
+ ++c;
+ }
+ /**
+ Replaces mapping from one triangle to another.
+ */
+ void replace(int32_t from, int32_t to)
+ {
+ if (tr[0] == from)
+ {
+ tr[0] = to;
+ }
+ else
+ {
+ if (c == 2 && tr[1] == from)
+ {
+ tr[1] = to;
+ }
+ }
+ }
+ /**
+ Get triangle which is mapped by this edge and which index is different than provided.
+ */
+ int32_t getNot(int32_t id)
+ {
+ if (tr[0] != id)
+ {
+ return tr[0];
+ }
+ if (c == 2 && tr[1] != id)
+ {
+ return tr[1];
+ }
+ return -1;
+ }
+
+ };
+
+ /**
+ Tool for graphic mesh tesselation and adding noise to internal surface. Each triangle must have initialized
+ Triangle::userInfo field (0 for external surface triangles and != 0 for internal)
+ */
+ class MeshNoiser
+ {
+ public:
+ MeshNoiser()
+ {
+ reset();
+ }
+
+ void reset();
+
+ /**
+ Edge flags
+ */
+ enum EdgeFlag { INTERNAL_EDGE, EXTERNAL_BORDER_EDGE, INTERNAL_BORDER_EDGE, EXTERNAL_EDGE, NONE };
+
+
+ /**
+ Set mesh to tesselate and apply noise
+ */
+ void setMesh(const std::vector<Triangle>& mesh);
+
+ /**
+ Tesselate internal surface.
+ \param[in] maxLen - maximal length of edge on internal surface.
+ */
+ void tesselateInternalSurface(float maxLen);
+
+ /**
+ Apply noise to internal surface. Must be called only after tesselation!!!
+ \param[in] noise - noise generator
+ \param[in] falloff - damping of noise around of external surface
+ \param[in] relaxIterations - number of smoothing iterations before applying noise
+ \param[in] relaxFactor - amount of smooting before applying noise.
+ */
+ void applyNoise(SimplexNoise& noise, float falloff, int32_t relaxIterations, float relaxFactor);
+
+ std::vector<Triangle> getMesh();
+
+ private:
+ PxVec3 mOffset;
+ float mScale;
+ bool isTesselated;
+ /**
+ Mesh data
+ */
+ std::vector<Vertex> mVertices;
+ std::vector<TriangleIndexed> mTriangles;
+ std::vector<Edge> mEdges;
+ std::map<Vertex, int32_t, VrtComp> mVertMap;
+ std::map<Edge, int32_t> mEdgeMap;
+
+
+ /**
+ Final triangles.
+ */
+ std::vector<Triangle> mResultTriangles;
+
+
+ int32_t addVerticeIfNotExist(const Vertex& p);
+ int32_t addEdge(const Edge& e);
+ int32_t findEdge(const Edge& e);
+
+
+
+ void collapseEdge(int32_t id);
+ void divideEdge(int32_t id);
+ void updateVertEdgeInfo();
+ void updateEdgeTriangleInfo();
+ void relax(int32_t iterations, float factor, std::vector<Vertex>& vertices);
+ void recalcNoiseDirs();
+
+
+ std::vector<bool> mRestrictionFlag;
+ std::vector<EdgeFlag> mEdgeFlag;
+ std::vector<EdgeToTriangles> mTrMeshEdToTr;
+ std::vector<int32_t> mVertexValence;
+ std::vector<std::vector<int32_t> > mVertexToTriangleMap;
+
+
+
+ std::vector<float> mVerticesDistances;
+ std::vector<physx::PxVec3> mVerticesNormalsSmoothed;
+ std::vector<int32_t> mPositionMappedVrt;
+ std::vector<std::vector<int32_t> > mGeometryGraph;
+
+ void prebuildEdgeFlagArray();
+ void computePositionedMapping();
+ void computeFalloffAndNormals();
+
+ void prebuildTesselatedTriangles();
+ };
+
+ } // namespace Blast
+} // namespace Nv
+#endif // ! NVBLASTEXTAUTHORINGMESHNOISER_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringPerlinNoise.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringPerlinNoise.h
index 95308c2..2b17f0c 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringPerlinNoise.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringPerlinNoise.h
@@ -1,12 +1,30 @@
-/*
-* Copyright (c) 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 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) 2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGPERLINNOISE_H
#define NVBLASTEXTAUTHORINGPERLINNOISE_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp
index 0b7187f..cc2442c 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.cpp
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
// 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
@@ -24,13 +42,11 @@
#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
@@ -38,40 +54,6 @@ 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;
@@ -100,7 +82,7 @@ inline bool pointInside(PxVec2 a, PxVec2 b, PxVec2 c, PxVec2 pnt)
(v1 <= 0.0f && v2 <= 0.0f && v3 <= 0.0f);
}
-void ChunkPostProcessor::triangulatePolygonWithEarClipping(std::vector<uint32_t>& inputPolygon, Vertex* vert, ProjectionDirections dir)
+void Triangulator::triangulatePolygonWithEarClipping(std::vector<uint32_t>& inputPolygon, Vertex* vert, ProjectionDirections dir)
{
// return;
//for (uint32_t i = 0; i < inputPolygon.size(); ++i)
@@ -144,10 +126,6 @@ void ChunkPostProcessor::triangulatePolygonWithEarClipping(std::vector<uint32_t>
}
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);
@@ -321,7 +299,7 @@ int32_t unitePolygons(std::vector<uint32_t>& externalLoop, std::vector<uint32_t>
return 0;
}
-void ChunkPostProcessor::buildPolygonAndTriangulate(std::vector<Edge>& edges, Vertex* vertices, int32_t userData)
+void Triangulator::buildPolygonAndTriangulate(std::vector<Edge>& edges, Vertex* vertices, int32_t userData, int32_t materialId, int32_t smoothingGroup)
{
std::vector<std::vector<uint32_t> > serializedLoops;
@@ -439,7 +417,7 @@ void ChunkPostProcessor::buildPolygonAndTriangulate(std::vector<Edge>& edges, Ve
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)
+ if (loopsInfo[intPoly].area > 0 || loopsInfo[intPoly].used || std::abs(loopsInfo[intPoly].area) > loopsInfo[extPoly].area)
{
continue;
}
@@ -454,11 +432,13 @@ void ChunkPostProcessor::buildPolygonAndTriangulate(std::vector<Edge>& edges, Ve
}
for (uint32_t i = oldSize; i < mBaseMeshTriangles.size(); ++i)
{
- mBaseMeshTriangles[i].userInfo = userData;
+ mBaseMeshTriangles[i].userData = userData;
+ mBaseMeshTriangles[i].materialId = materialId;
+ mBaseMeshTriangles[i].smoothingGroup = smoothingGroup;
}
}
-NV_FORCE_INLINE int32_t ChunkPostProcessor::addVerticeIfNotExist(Vertex& p)
+NV_FORCE_INLINE int32_t Triangulator::addVerticeIfNotExist(const Vertex& p)
{
auto it = mVertMap.find(p);
if (it == mVertMap.end())
@@ -473,7 +453,7 @@ NV_FORCE_INLINE int32_t ChunkPostProcessor::addVerticeIfNotExist(Vertex& p)
}
}
-NV_FORCE_INLINE void ChunkPostProcessor::addEdgeIfValid(EdgeWithParent& ed)
+NV_FORCE_INLINE void Triangulator::addEdgeIfValid(EdgeWithParent& ed)
{
if (ed.s == ed.e)
return;
@@ -497,14 +477,14 @@ NV_FORCE_INLINE void ChunkPostProcessor::addEdgeIfValid(EdgeWithParent& ed)
-void ChunkPostProcessor::prepare(Mesh* mesh)
+void Triangulator::prepare(const Mesh* mesh)
{
- Edge* ed = mesh->getEdges();
- Vertex* vr = mesh->getVertices();
+ const Edge* ed = mesh->getEdges();
+ const Vertex* vr = mesh->getVertices();
mBaseMapping.resize(mesh->getVerticesCount());
for (uint32_t i = 0; i < mesh->getFacetCount(); ++i)
{
- Facet* fc = mesh->getFacet(i);
+ const 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]);
@@ -527,29 +507,17 @@ void ChunkPostProcessor::prepare(Mesh* mesh)
}
-void ChunkPostProcessor::reset()
+void Triangulator::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)
+void Triangulator::triangulate(const Mesh* mesh)
{
reset();
if (mesh == nullptr || !mesh->isValid())
@@ -569,17 +537,16 @@ void ChunkPostProcessor::triangulate(Mesh* mesh)
{
if (temp.empty() == false)
{
- buildPolygonAndTriangulate(temp, &mVertices[0], mesh->getFacet(fP)->userData);
+ buildPolygonAndTriangulate(temp, mVertices.data(), mesh->getFacet(fP)->userData, mesh->getFacet(fP)->materialId, mesh->getFacet(fP)->smoothingGroup);
}
temp.clear();
fP = mBaseMeshEdges[i].parent;
}
temp.push_back(Edge(mBaseMeshEdges[i].s, mBaseMeshEdges[i].e));
}
- buildPolygonAndTriangulate(temp, &mVertices[0], mesh->getFacet(fP)->userData);
+ buildPolygonAndTriangulate(temp, mVertices.data(), mesh->getFacet(fP)->userData, mesh->getFacet(fP)->materialId, mesh->getFacet(fP)->smoothingGroup);
/* Build final triangles */
-
mBaseMeshResultTriangles.clear();
for (uint32_t i = 0; i < mBaseMeshTriangles.size(); ++i)
{
@@ -588,683 +555,19 @@ void ChunkPostProcessor::triangulate(Mesh* mesh)
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;
- }
- }
- }
-}
-
+ mBaseMeshResultTriangles.back().userData = mBaseMeshTriangles[i].userData;
+ mBaseMeshResultTriangles.back().materialId = mBaseMeshTriangles[i].materialId;
+ mBaseMeshResultTriangles.back().smoothingGroup = mBaseMeshTriangles[i].smoothingGroup;
-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)
+void Triangulator::computePositionedMapping()
{
- 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);
+ mPositionMappedVrt.resize(mVertices.size());
for (uint32_t i = 0; i < mVertices.size(); ++i)
{
@@ -1280,159 +583,6 @@ void ChunkPostProcessor::prebuildEdgeFlagArray()
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
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.h
index 83942f4..c5cb5b1 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringTriangulator.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGTRIANGULATOR_H
#define NVBLASTEXTAUTHORINGTRIANGULATOR_H
@@ -22,95 +40,19 @@ namespace Nv
{
namespace Blast
{
-class SimplexNoise;
-
-/**
- Vertex comparator for vertex welding.
-*/
-struct VrtComp
-{
- bool operator()(const Vertex& a, const Vertex& b) const;
-};
-
-/**
- Vertex comparator for vertex welding (not accounts normal and uv parameters of vertice).
-*/
-struct VrtPositionComparator
-{
- bool operator()(const physx::PxVec3& a, const physx::PxVec3& b) const;
-};
-
-/**
- Structure used on tesselation stage. Maps edge to two neighboor triangles
-*/
-struct EdgeToTriangles
-{
- int32_t tr[2];
- int32_t c;
- EdgeToTriangles()
- {
- c = 0;
- }
- /**
- Add triangle to edge. Should not be called more than twice for one edge!!!!.
- */
- void add(int32_t t)
- {
- tr[c] = t;
- ++c;
- }
- /**
- Replaces mapping from one triangle to another.
- */
- void replace(int32_t from, int32_t to)
- {
- if (tr[0] == from)
- {
- tr[0] = to;
- }
- else
- {
- if (c == 2 && tr[1] == from)
- {
- tr[1] = to;
- }
- }
- }
- /**
- Get triangle which is mapped by this edge and which index is different than provided.
- */
- int32_t getNot(int32_t id)
- {
- if (tr[0] != id)
- {
- return tr[0];
- }
- if (c == 2 && tr[1] != id)
- {
- return tr[1];
- }
- return -1;
- }
-
-};
/**
Tool for doing all post processing steps of authoring.
*/
-class ChunkPostProcessor
+class Triangulator
{
public:
/**
- Edge flags
- */
- enum EdgeFlag{ INTERNAL_EDGE, EXTERNAL_BORDER_EDGE, INTERNAL_BORDER_EDGE, EXTERNAL_EDGE, NONE };
-
- /**
Triangulates provided mesh and saves result internally. Uses Ear-clipping algorithm.
\param[in] mesh Mesh for triangulation
*/
- void triangulate(Mesh* mesh);
+ void triangulate(const Mesh* mesh);
/**
\return Return array of triangles of base mesh.
@@ -127,8 +69,6 @@ public:
{
return mBaseMeshTriangles;
}
-
-
/**
\return Return mapping from vertices of input Mesh to internal vertices buffer. Used for island detection.
*/
@@ -143,7 +83,6 @@ public:
{
return mPositionMappedVrt;
};
-
/**
\return Return internal vertex buffer size. Vertices internally are welded with some threshold.
*/
@@ -151,44 +90,15 @@ public:
{
return static_cast<uint32_t>(mVertices.size());
}
- /**
- Tesselate internal surface.
- \param[in] maxLen - maximal length of edge on internal surface.
- */
- void tesselateInternalSurface(float maxLen);
-
- /**
- Apply noise to internal surface. Must be called only after tesselation!!!
- \param[in] noise - noise generator
- \param[in] falloff - damping of noise around of external surface
- \param[in] relaxIterations - number of smoothing iterations before applying noise
- \param[in] relaxFactor - amount of smooting before applying noise.
- */
- void applyNoise(SimplexNoise& noise, float falloff, int32_t relaxIterations, float relaxFactor);
-
- /**
- \return Return array of noised mesh triangles.
- */
- std::vector<Triangle>& getNoisyMesh()
- {
- return mTesselatedMeshResultTriangles;
- };
/**
- Removes all information about mesh triangulation, tesselation, etc.
+ Removes all information about mesh triangulation.
*/
void reset();
private:
-
-
- void collapseEdge(int32_t id);
- void divideEdge(int32_t id);
- void updateVertEdgeInfo();
- void updateEdgeTriangleInfo();
-
- int32_t addVerticeIfNotExist(Vertex& p);
+ int32_t addVerticeIfNotExist(const Vertex& p);
void addEdgeIfValid(EdgeWithParent& ed);
/* Data used before triangulation to build polygon loops*/
@@ -198,60 +108,26 @@ private:
std::map<Vertex, int32_t, VrtComp> mVertMap;
std::map<EdgeWithParent, int32_t, EdgeComparator> mEdgeMap;
std::vector<uint32_t> mBaseMapping;
-
+ std::vector<int32_t> mPositionMappedVrt;
+ /* ------------------------------------------------------------ */
/**
Unite all almost similar vertices, update edges according to this changes
*/
- void prepare(Mesh* mesh);
-
- /* ------------------------------------------------------------ */
-
- /* Triangulation and tesselation stage data */
- bool isTesselated;
-
- std::map<Edge, int32_t> mTrMeshEdgeMap;
- std::vector<Edge> mTrMeshEdges;
- std::vector<EdgeToTriangles> mTrMeshEdToTr;
- std::vector<int32_t> mVertexValence;
- std::vector<std::vector<int32_t> > mVertexToTriangleMap;
-
- std::vector<bool> mRestrictionFlag;
- std::vector<EdgeFlag> mEdgeFlag;
-
- std::vector<float> mVerticesDistances;
- std::vector<physx::PxVec3> mVerticesNormalsSmoothed;
- std::vector<int32_t> mPositionMappedVrt;
- std::vector<std::vector<int32_t> > mGeometryGraph;
-
-
- int32_t addEdgeTr(const Edge& ed);
- int32_t findEdge(const Edge& e);
-
- void prebuildEdgeFlagArray();
- void computePositionedMapping();
-
- void computeFalloffAndNormals();
-
+ void prepare(const Mesh* mesh);
+
void triangulatePolygonWithEarClipping(std::vector<uint32_t>& inputPolygon, Vertex* vert, ProjectionDirections dir);
- void buildPolygonAndTriangulate(std::vector<Edge>& edges, Vertex* vertices, int32_t userData);
+ void buildPolygonAndTriangulate(std::vector<Edge>& edges, Vertex* vertices, int32_t userData, int32_t materialId, int32_t smoothingGroup);
+ void computePositionedMapping();
- void relax(int32_t iterations, float factor, std::vector<Vertex>& vertices);
- void recalcNoiseDirs();
-
- std::vector<TriangleIndexed> mBaseMeshTriangles;
- std::vector<TriangleIndexed> mTesselatedMeshTriangles;
-
+ std::vector<TriangleIndexed> mBaseMeshTriangles;
/**
Final triangles
*/
- void prebuildTesselatedTriangles();
-
std::vector<Triangle> mBaseMeshResultTriangles;
- std::vector<Triangle> mTesselatedMeshResultTriangles;
};
} // namespace Blast
diff --git a/sdk/extensions/authoring/source/NvBlastExtAuthoringVSA.h b/sdk/extensions/authoring/source/NvBlastExtAuthoringVSA.h
index fd0c9c9..62d73c1 100644
--- a/sdk/extensions/authoring/source/NvBlastExtAuthoringVSA.h
+++ b/sdk/extensions/authoring/source/NvBlastExtAuthoringVSA.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTAUTHORINGVSA_H
#define NVBLASTEXTAUTHORINGVSA_H
diff --git a/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.cpp b/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.cpp
index 3c3e540..0ec4c20 100644
--- a/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.cpp
+++ b/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.cpp
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#include "NvBlastExtTriangleProcessor.h"
#include "NvBlastExtAuthoringInternalCommon.h"
diff --git a/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.h b/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.h
index db9f682..0b32218 100644
--- a/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.h
+++ b/sdk/extensions/authoring/source/NvBlastExtTriangleProcessor.h
@@ -1,12 +1,30 @@
-/*
-* 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 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-2017 NVIDIA Corporation. All rights reserved.
+
#ifndef NVBLASTEXTTRIANGLEPROCESSOR_H
#define NVBLASTEXTTRIANGLEPROCESSOR_H