Revision control
+ // Redistribution and use in source and binary forms, with or without
+ // modification, are permitted provided that the following conditions
+ // are met:
+ // * Redistributions of source code must retain the above copyright
+ // notice, this list of conditions and the following disclaimer.
+ // * Redistributions in binary form must reproduce the above copyright
+ // notice, this list of conditions and the following disclaimer in the
+ // documentation and/or other materials provided with the distribution.
+ // * Neither the name of NVIDIA CORPORATION nor the names of its
+ // contributors may be used to endorse or promote products derived
+ // from this software without specific prior written permission.
+ //
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
+ // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ // OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ //
+ // Copyright (c) 2008-2026 NVIDIA Corporation. All rights reserved.
+ // Copyright (c) 2004-2008 AGEIA Technologies, Inc. All rights reserved.
+ // Copyright (c) 2001-2004 NovodeX AG. All rights reserved.
+
+ #ifndef PX_ISOSURFACE_EXTRACTION_H
+ #define PX_ISOSURFACE_EXTRACTION_H
+
+
+ #include "cudamanager/PxCudaContext.h"
+ #include "cudamanager/PxCudaContextManager.h"
+
+ #include "foundation/PxSimpleTypes.h"
+ #include "foundation/PxVec4.h"
+ #include "PxParticleSystem.h"
+
+ #include "PxSparseGridParams.h"
+
+ #include "foundation/PxArray.h"
+ #include "PxParticleGpu.h"
+
+ #if !PX_DOXYGEN
+ namespace physx
+ {
+ #endif
+
+ #if PX_SUPPORT_GPU_PHYSX
+
+ /**
+ \brief Identifies filter type to be applied on the isosurface grid.
+ */
+ struct PxIsosurfaceGridFilteringType
+ {
+ enum Enum
+ {
+ eNONE = 0, //!< No filtering
+ eSMOOTH = 1, //!< Gaussian-blur-like filtering
+ eGROW = 2, //!< A dilate/erode operation will be applied that makes the fluid grow approximately one cell size
+ eSHRINK = 3 //!< A dilate/erode operation will be applied that makes the fluid shrink approximately one cell size
+ };
+ };
+
+ /**
+ \brief Parameters to define the isosurface extraction settings like isosurface level, filtering etc.
+ */
+ struct PxIsosurfaceParams
+ {
+ /**
+ \brief Default constructor.
+ */
+ PX_INLINE PxIsosurfaceParams()
+ {
+ particleCenterToIsosurfaceDistance = 0.2f;
+ numMeshSmoothingPasses = 4;
+ numMeshNormalSmoothingPasses = 4;
+ gridFilteringFlags = 0;
+ gridSmoothingRadius = 0.2f;
+ }
+
+ /**
+ \brief Clears the filtering operations
+ */
+ PX_INLINE void clearFilteringPasses()
+ {
+ gridFilteringFlags = 0;
+ }
+
+ /**
+ \brief Adds a smoothing pass after the existing ones
+
+ At most 32 smoothing passes can be defined. Every pass can repeat itself up to 4 times.
+
+ \param[in] operation The smoothing operation to add
+ \return The index of the smoothing pass that was added
+ */
+ PX_INLINE PxU64 addGridFilteringPass(PxIsosurfaceGridFilteringType::Enum operation)
+ {
+ for (PxU32 i = 0; i < 32; ++i)
+ {
+ PxIsosurfaceGridFilteringType::Enum o;
+ if (!getGridFilteringPass(i, o))
+ {
+ setGridFilteringPass(i, operation);
+ return i;
+ }
+ }
+ return 0xFFFFFFFFFFFFFFFF;
+ }
+
+ /**
+ \brief Sets the operation of a smoothing pass
+
+ \param[in] passIndex The index of the smoothing pass whose operation should be set <b>Range:</b> [0, 31]
+ \param[in] operation The operation the modified smoothing will perform
+ */
+ PX_INLINE void setGridFilteringPass(PxU32 passIndex, PxIsosurfaceGridFilteringType::Enum operation)
+ {
+ PX_ASSERT(passIndex < 32u);
+ PxU32 shift = passIndex * 2;
+ gridFilteringFlags &= ~(PxU64(3) << shift);
+ gridFilteringFlags |= PxU64(operation) << shift;
+ }
+
+ /**
+ \brief Returns the operation of a smoothing pass
+
+ \param[in] passIndex The index of the smoothing pass whose operation is requested <b>Range:</b> [0, 31]
+ \param[out] operation The operation the requested smoothing pass will perform
+ \return true if the requested pass performs an operation
+ */
+ PX_INLINE bool getGridFilteringPass(PxU32 passIndex, PxIsosurfaceGridFilteringType::Enum& operation) const
+ {
+ PxU32 shift = passIndex * 2;
+ PxU64 v = gridFilteringFlags >> shift;
+ v &= 3; //Extract last 2 bits
+ operation = PxIsosurfaceGridFilteringType::Enum(v);
+ return operation != PxIsosurfaceGridFilteringType::eNONE;
+ }
+
+ PxReal particleCenterToIsosurfaceDistance; //!< Distance form a particle center to the isosurface
+ PxU32 numMeshSmoothingPasses; //!< Number of Taubin mesh postprocessing smoothing passes. Using an even number of passes lead to less shrinking.
+ PxU32 numMeshNormalSmoothingPasses; //!< Number of mesh normal postprocessing smoothing passes.
+ PxU64 gridFilteringFlags; //!< Encodes the smoothing steps to apply on the sparse grid. Use setGridSmoothingPass method to set up.
+ PxReal gridSmoothingRadius; //!< Gaussian blur smoothing kernel radius used for smoothing operations on the grid
+ };
+
+ /**
+ \brief Base class for isosurface extractors. Allows to register the data arrays for the isosurface and to obtain the number vertices/triangles in use.
+ */
+ class PxIsosurfaceExtractor
+ {
+ public:
+ /**
+ \brief Returns the isosurface parameters.
+
+ \return The isosurfacesettings used for the isosurface extraction
+ */
+ virtual PxIsosurfaceParams getIsosurfaceParams() const = 0;
+
+ /**
+ \brief Set the isosurface extraction parameters
+
+ Allows to configure the isosurface extraction by controlling threshold value, smoothing options etc.
+
+ \param[in] params A collection of settings to control the isosurface extraction
+ */
+ virtual void setIsosurfaceParams(const PxIsosurfaceParams& params) = 0;
+
+ /**
+ \brief Returns the number of vertices that the current isosurface triangle mesh uses
+
+ \return The number of vertices currently in use
+ */
+ virtual PxU32 getNumVertices() const = 0;
+
+ /**
+ \brief Returns the number of triangles that the current isosurface triangle mesh uses
+
+ \return The number of triangles currently in use
+ */
+ virtual PxU32 getNumTriangles() const = 0;
+
+ /**
+ \brief Returns the maximum number of vertices that the isosurface triangle mesh can contain
+
+ \return The maximum number of vertices that can be genrated
+ */
+ virtual PxU32 getMaxVertices() const = 0;
+
+ /**
+ \brief Returns the maximum number of triangles that the isosurface triangle mesh can contain
+
+ \return The maximum number of triangles that can be generated
+ */
+ virtual PxU32 getMaxTriangles() const = 0;
+
+ /**
+ \brief Resizes the internal triangle mesh buffers.
+
+ If the output buffers are device buffers, nothing will get resized but new output buffers can be set using setResultBufferDevice.
+ For host side output buffers, temporary buffers will get resized. The new host side result buffers with the same size must be set using setResultBufferHost.
+
+ \param[in] maxNumVertices The maximum number of vertices the output buffer can hold
+ \param[in] maxNumTriangles The maximum number of triangles the ouput buffer can hold
+ */
+ virtual void setMaxVerticesAndTriangles(PxU32 maxNumVertices, PxU32 maxNumTriangles) = 0;
+
+ /**
+ \brief The maximal number of particles the isosurface extractor can process
+
+ \return The maximal number of particles
+ */
+ virtual PxU32 getMaxParticles() const = 0;
+
+ /**
+ \brief Sets the maximal number of particles the isosurface extractor can process
+
+ \param[in] maxParticles The maximal number of particles
+ */
+ virtual void setMaxParticles(PxU32 maxParticles) = 0;
+
+ /**
+ \brief Releases the isosurface extractor instance and its data
+ */
+ virtual void release() = 0;
+
+ /**
+ \brief Triggers the compuation of a new isosurface based on the specified particle locations
+
+ \param[in] deviceParticlePos A gpu pointer pointing to the start of the particle array
+ \param[in] numParticles The number of particles
+ \param[in] stream The stream on which all the gpu work will be performed
+ \param[in] phases A phase value per particle
+ \param[in] validPhaseMask A mask that specifies which phases should contribute to the isosurface. If the binary and operation
+ between this mask and the particle phase is non zero, then the particle will contribute to the isosurface
+ \param[in] activeIndices Optional array with indices of all active particles
+ \param[in] anisotropy1 Optional anisotropy information, x axis direction (xyz) and scale in w component
+ \param[in] anisotropy2 Optional anisotropy information, y axis direction (xyz) and scale in w component
+ \param[in] anisotropy3 Optional anisotropy information, z axis direction (xyz) and scale in w component
+ \param[in] anisotropyFactor A factor to multiply with the anisotropy scale
+ */
+ virtual void extractIsosurface(PxVec4* deviceParticlePos, const PxU32 numParticles, CUstream stream, PxU32* phases = NULL, PxU32 validPhaseMask = PxParticlePhaseFlag::eParticlePhaseFluid,
+ PxU32* activeIndices = NULL, PxVec4* anisotropy1 = NULL, PxVec4* anisotropy2 = NULL, PxVec4* anisotropy3 = NULL, PxReal anisotropyFactor = 1.0f) = 0;
+
+ /**
+ \brief Allows to register the host buffers into which the final isosurface triangle mesh will get stored
+
+ \param[in] vertices A host buffer to store the vertices of the isosurface mesh
+ \param[in] triIndices A host buffer to store the triangles of the isosurface mesh
+ \param[in] normals A host buffer to store the normals of the isosurface mesh
+ */
+ virtual void setResultBufferHost(PxVec4* vertices, PxU32* triIndices, PxVec4* normals = NULL) = 0;
+
+ /**
+ \brief Allows to register the host buffers into which the final isosurface triangle mesh will get stored
+
+ \param[in] vertices A device buffer to store the vertices of the isosurface mesh
+ \param[in] triIndices A device buffer to store the triangles of the isosurface mesh
+ \param[in] normals A device buffer to store the normals of the isosurface mesh
+ */
+ virtual void setResultBufferDevice(PxVec4* vertices, PxU32* triIndices, PxVec4* normals) = 0;
+
+ /**
+ \brief Enables or disables the isosurface extractor
+
+ \param[in] enabled The boolean to set the extractor to enabled or disabled
+ */
+ virtual void setEnabled(bool enabled) = 0;
+
+ /**
+ \brief Allows to query if the isosurface extractor is enabled
+
+ \return True if enabled, false otherwise
+ */
+ virtual bool isEnabled() const = 0;
+
+ /**
+ \brief Destructor
+ */
+ virtual ~PxIsosurfaceExtractor() {}
+ };
+
+ /**
+ \brief Base class for sparse grid based isosurface extractors. Allows to register the data arrays for the isosurface and to obtain the number vertices/triangles in use.
+ */
+ class PxSparseGridIsosurfaceExtractor : public PxIsosurfaceExtractor
+ {
+ /**
+ \brief Returns the sparse grid parameters.
+
+ \return The sparse grid settings used for the isosurface extraction
+ */
+ virtual PxSparseGridParams getSparseGridParams() const = 0;
+
+ /**
+ \brief Set the sparse grid parameters
+
+ Allows to configure cell size, number of subgrids etc.
+
+ \param[in] params A collection of settings to control the isosurface grid
+ */
+ virtual void setSparseGridParams(const PxSparseGridParams& params) = 0;
+ };
+
+ /**
+ \brief Default implementation of a particle system callback to trigger the isosurface extraction. A call to fetchResultsParticleSystem() on the
+ PxScene will synchronize the work such that the caller knows that the post solve task completed.
+ */
+ class PxIsosurfaceCallback : public PxParticleSystemCallback
+ {
+ public:
+ /**
+ \brief Initializes the isosurface callback
+
+ \param[in] isosurfaceExtractor The isosurface extractor
+ \param[in] validPhaseMask The valid phase mask marking the phase bits that particles must have set in order to contribute to the isosurface
+ */
+ void initialize(PxIsosurfaceExtractor* isosurfaceExtractor, PxU32 validPhaseMask = PxParticlePhaseFlag::eParticlePhaseFluid)
+ {
+ mIsosurfaceExtractor = isosurfaceExtractor;
+ mValidPhaseMask = validPhaseMask;
+ }
+
+ virtual void onPostSolve(const PxGpuMirroredPointer<PxGpuParticleSystem>& gpuParticleSystem, CUstream stream)
+ {
+ mIsosurfaceExtractor->extractIsosurface(reinterpret_cast<PxVec4*>(gpuParticleSystem.mHostPtr->mUnsortedPositions_InvMass),
+ gpuParticleSystem.mHostPtr->mCommonData.mMaxParticles, stream, gpuParticleSystem.mHostPtr->mUnsortedPhaseArray, mValidPhaseMask);
+ }
+
+ virtual void onBegin(const PxGpuMirroredPointer<PxGpuParticleSystem>& /*gpuParticleSystem*/, CUstream /*stream*/) { }
+
+ virtual void onAdvance(const PxGpuMirroredPointer<PxGpuParticleSystem>& /*gpuParticleSystem*/, CUstream /*stream*/) { }
+
+ private:
+ PxIsosurfaceExtractor* mIsosurfaceExtractor;
+ PxU32 mValidPhaseMask;
+ };
+
+ #endif
+
+ #if !PX_DOXYGEN
+ } // namespace physx
+ #endif
+
+ #endif