diff options
| author | Anton Novoselov <[email protected]> | 2017-08-01 12:53:38 +0300 |
|---|---|---|
| committer | Anton Novoselov <[email protected]> | 2017-08-01 12:53:38 +0300 |
| commit | 236f03c0b9a4982328ed1201978f7f69d192d9b2 (patch) | |
| tree | e486f2fa39dba203563895541e92c60ed3e25759 /sdk/extensions/authoring | |
| parent | Added screens to welcome page (diff) | |
| download | blast-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')
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, ¶ms) == 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, ¶ms) == 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 |