diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/NvFlex.h | 1155 | ||||
| -rw-r--r-- | include/NvFlexDevice.h | 75 | ||||
| -rw-r--r-- | include/NvFlexExt.h | 768 |
3 files changed, 1998 insertions, 0 deletions
diff --git a/include/NvFlex.h b/include/NvFlex.h new file mode 100644 index 0000000..a6b305c --- /dev/null +++ b/include/NvFlex.h @@ -0,0 +1,1155 @@ +// 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) 2013-2017 NVIDIA Corporation. All rights reserved. + +#ifndef NV_FLEX_H +#define NV_FLEX_H + +//! \cond HIDDEN_SYMBOLS +#if _WIN32 +#define NV_FLEX_API __declspec(dllexport) +#else +#define NV_FLEX_API +#endif + +// least 2 significant digits define minor version, eg: 10 -> version 0.10 +#define NV_FLEX_VERSION 110 + +//! \endcond + +/** \file NvFlex.h + * The main include file for the core Flex solver. + */ + +extern "C" { + +/** + * Opaque type representing a library that can create FlexSolvers, FlexTriangleMeshes, and NvFlexBuffers + */ +typedef struct NvFlexLibrary NvFlexLibrary; + +/** + * Opaque type representing a collection of particles and constraints + */ +typedef struct NvFlexSolver NvFlexSolver; + +/** + * Opaque type representing a data buffer, type and contents depends on usage, see NvFlexAllocBuffer() + */ +typedef struct NvFlexBuffer NvFlexBuffer; + +/** + * Controls behavior of NvFlexMap() + */ +enum NvFlexMapFlags +{ + eNvFlexMapWait = 0, //!< Calling thread will be blocked until buffer is ready for access, default + eNvFlexMapDoNotWait = 1, //!< Calling thread will check if buffer is ready for access, if not ready then the method will return NULL immediately + eNvFlexMapDiscard = 2 //!< Buffer contents will be discarded, this allows for efficent buffer reuse +}; + +/** + * Controls memory space of a NvFlexBuffer, see NvFlexAllocBuffer() + */ +enum NvFlexBufferType +{ + eNvFlexBufferHost = 0, //!< Host mappable buffer, pinned memory on CUDA, staging buffer on DX + eNvFlexBufferDevice = 1, //!< Device memory buffer, mapping this on CUDA will return a device memory pointer, and will return a buffer pointer on DX +}; + +/** + * Controls the relaxation method used by the solver to ensure convergence + */ +enum NvFlexRelaxationMode +{ + eNvFlexRelaxationGlobal = 0, //!< The relaxation factor is a fixed multiplier on each constraint's position delta + eNvFlexRelaxationLocal = 1 //!< The relaxation factor is a fixed multiplier on each constraint's delta divided by the particle's constraint count, convergence will be slower but more reliable +}; + + +/** + * Simulation parameters for a solver + */ +struct NvFlexParams +{ + int numIterations; //!< Number of solver iterations to perform per-substep + + float gravity[3]; //!< Constant acceleration applied to all particles + float radius; //!< The maximum interaction radius for particles + float solidRestDistance; //!< The distance non-fluid particles attempt to maintain from each other, must be in the range (0, radius] + float fluidRestDistance; //!< The distance fluid particles are spaced at the rest density, must be in the range (0, radius], for fluids this should generally be 50-70% of mRadius, for rigids this can simply be the same as the particle radius + + // common params + float dynamicFriction; //!< Coefficient of friction used when colliding against shapes + float staticFriction; //!< Coefficient of static friction used when colliding against shapes + float particleFriction; //!< Coefficient of friction used when colliding particles + float restitution; //!< Coefficient of restitution used when colliding against shapes, particle collisions are always inelastic + float adhesion; //!< Controls how strongly particles stick to surfaces they hit, default 0.0, range [0.0, +inf] + float sleepThreshold; //!< Particles with a velocity magnitude < this threshold will be considered fixed + + float maxSpeed; //!< The magnitude of particle velocity will be clamped to this value at the end of each step + float maxAcceleration; //!< The magnitude of particle acceleration will be clamped to this value at the end of each step (limits max velocity change per-second), useful to avoid popping due to large interpenetrations + + float shockPropagation; //!< Artificially decrease the mass of particles based on height from a fixed reference point, this makes stacks and piles converge faster + float dissipation; //!< Damps particle velocity based on how many particle contacts it has + float damping; //!< Viscous drag force, applies a force proportional, and opposite to the particle velocity + + // cloth params + float wind[3]; //!< Constant acceleration applied to particles that belong to dynamic triangles, drag needs to be > 0 for wind to affect triangles + float drag; //!< Drag force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the negative velocity direction + float lift; //!< Lift force applied to particles belonging to dynamic triangles, proportional to velocity^2*area in the direction perpendicular to velocity and (if possible), parallel to the plane normal + + // fluid params + bool fluid; //!< If true then particles with phase 0 are considered fluid particles and interact using the position based fluids method + float cohesion; //!< Control how strongly particles hold each other together, default: 0.025, range [0.0, +inf] + float surfaceTension; //!< Controls how strongly particles attempt to minimize surface area, default: 0.0, range: [0.0, +inf] + float viscosity; //!< Smoothes particle velocities using XSPH viscosity + float vorticityConfinement; //!< Increases vorticity by applying rotational forces to particles + float anisotropyScale; //!< Control how much anisotropy is present in resulting ellipsoids for rendering, if zero then anisotropy will not be calculated, see NvFlexGetAnisotropy() + float anisotropyMin; //!< Clamp the anisotropy scale to this fraction of the radius + float anisotropyMax; //!< Clamp the anisotropy scale to this fraction of the radius + float smoothing; //!< Control the strength of Laplacian smoothing in particles for rendering, if zero then smoothed positions will not be calculated, see NvFlexGetSmoothParticles() + float solidPressure; //!< Add pressure from solid surfaces to particles + float freeSurfaceDrag; //!< Drag force applied to boundary fluid particles + float buoyancy; //!< Gravity is scaled by this value for fluid particles + + // diffuse params + float diffuseThreshold; //!< Particles with kinetic energy + divergence above this threshold will spawn new diffuse particles + float diffuseBuoyancy; //!< Scales force opposing gravity that diffuse particles receive + float diffuseDrag; //!< Scales force diffuse particles receive in direction of neighbor fluid particles + int diffuseBallistic; //!< The number of neighbors below which a diffuse particle is considered ballistic + float diffuseSortAxis[3]; //!< Diffuse particles will be sorted by depth along this axis if non-zero + float diffuseLifetime; //!< Time in seconds that a diffuse particle will live for after being spawned, particles will be spawned with a random lifetime in the range [0, diffuseLifetime] + + // rigid params + float plasticThreshold; //!< Particles belonging to rigid shapes that move with a position delta magnitude > threshold will be permanently deformed in the rest pose + float plasticCreep; //!< Controls the rate at which particles in the rest pose are deformed for particles passing the deformation threshold + + // collision params + float collisionDistance; //!< Distance particles maintain against shapes, note that for robust collision against triangle meshes this distance should be greater than zero + float particleCollisionMargin; //!< Increases the radius used during neighbor finding, this is useful if particles are expected to move significantly during a single step to ensure contacts aren't missed on subsequent iterations + float shapeCollisionMargin; //!< Increases the radius used during contact finding against kinematic shapes + + float planes[8][4]; //!< Collision planes in the form ax + by + cz + d = 0 + int numPlanes; //!< Num collision planes + + NvFlexRelaxationMode relaxationMode;//!< How the relaxation is applied inside the solver + float relaxationFactor; //!< Control the convergence rate of the parallel solver, default: 1, values greater than 1 may lead to instability +}; + +/** + * Flags that control the a particle's behavior and grouping, use NvFlexMakePhase() to construct a valid 32bit phase identifier + */ +enum NvFlexPhase +{ + eNvFlexPhaseGroupMask = 0x00ffffff, //!< Low 24 bits represent the particle group for controlling collisions + + eNvFlexPhaseSelfCollide = 1 << 24, //!< If set this particle will interact with particles of the same group + eNvFlexPhaseSelfCollideFilter = 1 << 25, //!< If set this particle will ignore collisions with particles closer than the radius in the rest pose, this flag should not be specified unless valid rest positions have been specified using NvFlexSetRestParticles() + eNvFlexPhaseFluid = 1 << 26, //!< If set this particle will generate fluid density constraints for its overlapping neighbors +}; + +/** + * Generate a bit set for the particle phase, the group should be an integer < 2^24, and the flags should be a combination of FlexPhase enum values + */ +NV_FLEX_API inline int NvFlexMakePhase(int group, int flags) { return (group & eNvFlexPhaseGroupMask) | flags; } + + +/** + * Time spent in each section of the solver update, times in GPU seconds, see NvFlexUpdateSolver() + */ +struct NvFlexTimers +{ + float predict; //!< Time spent in prediction + float createCellIndices; //!< Time spent creating grid indices + float sortCellIndices; //!< Time spent sorting grid indices + float createGrid; //!< Time spent creating grid + float reorder; //!< Time spent reordering particles + float collideParticles; //!< Time spent finding particle neighbors + float collideShapes; //!< Time spent colliding convex shapes + float collideTriangles; //!< Time spent colliding triangle shapes + float collideFields; //!< Time spent colliding signed distance field shapes + float calculateDensity; //!< Time spent calculating fluid density + float solveDensities; //!< Time spent solving density constraints + float solveVelocities; //!< Time spent solving velocity constraints + float solveShapes; //!< Time spent solving rigid body constraints + float solveSprings; //!< Time spent solving distance constraints + float solveContacts; //!< Time spent solving contact constraints + float solveInflatables; //!< Time spent solving pressure constraints + float applyDeltas; //!< Time spent adding position deltas to particles + float calculateAnisotropy; //!< Time spent calculating particle anisotropy for fluid + float updateDiffuse; //!< Time spent updating diffuse particles + float updateTriangles; //!< Time spent updating dynamic triangles + float updateNormals; //!< Time spent updating vertex normals + float finalize; //!< Time spent finalizing state + float updateBounds; //!< Time spent updating particle bounds + float total; //!< Sum of all timers above +}; + +/** + * Flex error return codes + */ +enum NvFlexErrorSeverity +{ + eNvFlexLogError = 0, //!< Error messages + eNvFlexLogInfo = 1, //!< Information messages + eNvFlexLogWarning = 2, //!< Warning messages + eNvFlexLogDebug = 4, //!< Used only in debug version of dll + eNvFlexLogAll = -1, //!< All log types +}; + + +/** Defines the set of stages at which callbacks may be registered + */ +enum NvFlexSolverCallbackStage +{ + eNvFlexStageIterationStart, //!< Called at the beginning of each constraint iteration + eNvFlexStageIterationEnd, //!< Called at the end of each constraint iteration + eNvFlexStageSubstepBegin, //!< Called at the beginning of each substep after the prediction step has been completed + eNvFlexStageSubstepEnd, //!< Called at the end of each substep after the velocity has been updated by the constraints + eNvFlexStageUpdateEnd, //!< Called at the end of solver update after the final substep has completed + eNvFlexStageCount, //!< Number of stages +}; + +/** Defines the different DirectX compute modes that Flex can use +*/ +enum NvFlexComputeType +{ + eNvFlexCUDA, //!< Use CUDA compute for Flex, the application must link against the CUDA libraries + eNvFlexD3D11, //!< Use DirectX 11 compute for Flex, the application must link against the D3D libraries + eNvFlexD3D12, //!< Use DirectX 12 compute for Flex, the application must link against the D3D libraries +}; + +/** Structure containing pointers to the internal solver data that is passed to each registered solver callback + * + * @remarks Pointers to internal data are only valid for the lifetime of the callback and should not be stored. + * However, it is safe to launch kernels and memory transfers using the device pointers. + * + * @remarks Because Flex re-orders particle data internally for performance, the particle data in the callback is not + * in the same order as it was provided to the API. The callback provides arrays which map original particle indices + * to sorted positions and vice-versa. + * + * @remarks Particle positions may be modified during any callback, but velocity modifications should only occur during + * the eNvFlexStageUpdateEnd stage, otherwise any velocity changes will be discarded. + */ +struct NvFlexSolverCallbackParams +{ + NvFlexSolver* solver; //!< Pointer to the solver that the callback is registered to + void* userData; //!< Pointer to the user data provided to NvFlexRegisterSolverCallback() + + float* particles; //!< Device pointer to the active particle basic data in the form x,y,z,1/m + float* velocities; //!< Device pointer to the active particle velocity data in the form x,y,z,w (last component is not used) + int* phases; //!< Device pointer to the active particle phase data + + int numActive; //!< The number of active particles returned, the callback data only return pointers to active particle data, this is the same as NvFlexGetActiveCount() + + float dt; //!< The per-update time-step, this is the value passed to NvFlexUpdateSolver() + + const int* originalToSortedMap; //!< Device pointer that maps the sorted callback data to the original position given by SetParticles() + const int* sortedToOriginalMap; //!< Device pointer that maps the original particle index to the index in the callback data structure +}; + +/** Descriptor used to initialize Flex +*/ +struct NvFlexInitDesc +{ + int deviceIndex; //!< The GPU device index that should be used, if there is already a CUDA context on the calling thread then this parameter will be ignored and the active CUDA context used. Otherwise a new context will be created using the suggested device ordinal. + bool enableExtensions; //!< Enable or disable NVIDIA/AMD extensions in DirectX, can lead to improved performance. + void* renderDevice; //!< Direct3D device to use for simulation, if none is specified a new device and context will be created. + void* renderContext; //!< Direct3D context to use for simulation, if none is specified a new context will be created, in DirectX 12 this should be a pointer to the ID3D12CommandQueue where compute operations will take place. + + NvFlexComputeType computeType; //!< Set to eNvFlexD3D11 if DirectX 11 should be used, eNvFlexD3D12 for DirectX 12, this must match the libraries used to link the application +}; + +/** Solver callback definition, see NvFlexRegisterSolverCallback() + */ +struct NvFlexSolverCallback +{ + /** User data passed to the callback*/ + void* userData; + + /** Function pointer to a callback method */ + void (*function)(NvFlexSolverCallbackParams params); +}; + +/** + * Function pointer type for error reporting callbacks + */ +typedef void (*NvFlexErrorCallback)(NvFlexErrorSeverity type, const char* msg, const char* file, int line); + +/** +* Initialize library, should be called before any other API function. +* +* +* @param[in] version The version number the app is expecting, should almost always be NV_FLEX_VERSION +* @param[in] errorFunc The callback used for reporting errors. +* @param[in] desc The NvFlexInitDesc struct defining the device ordinal, D3D device/context and the type of D3D compute being used +* @return A pointer to a library instance that can be used to allocate shared object such as triangle meshes, buffers, etc +*/ +NV_FLEX_API NvFlexLibrary* NvFlexInit(int version = NV_FLEX_VERSION, NvFlexErrorCallback errorFunc = 0, NvFlexInitDesc * desc = 0); + +/** + * Shutdown library, users should manually destroy any previously created + * solvers to ensure memory is freed before calling this method. If a new CUDA context was created during NvFlexInit() then it will be destroyed. + * + * @param[in] lib The library intance to use + */ +NV_FLEX_API void NvFlexShutdown(NvFlexLibrary* lib); + +/** + * Get library version number + */ +NV_FLEX_API int NvFlexGetVersion(); + +/** + * Create a new particle solver + * + * @param[in] lib The library instance to use + * @param[in] maxParticles Maximum number of simulation particles possible for this solver + * @param[in] maxDiffuseParticles Maximum number of diffuse (non-simulation) particles possible for this solver + * @param[in] maxNeighborsPerParticle Maximum number of neighbors per particle possible for this solver + */ +NV_FLEX_API NvFlexSolver* NvFlexCreateSolver(NvFlexLibrary* lib, int maxParticles, int maxDiffuseParticles, int maxNeighborsPerParticle = 96); +/** + * Delete a particle solver + * + * @param[in] solver A valid solver pointer created from NvFlexCreateSolver() + */ +NV_FLEX_API void NvFlexDestroySolver(NvFlexSolver* solver); + +/** + * Return the library associated with a solver + * + * @param[in] solver A valid solver created with NvFlexCreateSolver() + * @return A library pointer + */ +NV_FLEX_API NvFlexLibrary* NvFlexGetSolverLibrary(NvFlexSolver* solver); + +/** Registers a callback for a solver stage, the callback will be invoked from the same thread that calls NvFlexUpdateSolver(). + * + * @param[in] solver A valid solver + * @param[in] function A pointer to a function that will be called during the solver update + * @param[in] stage The stage of the update at which the callback function will be called + * + * @return The previously registered callback for this slot, this allows multiple users to chain callbacks together + */ +NV_FLEX_API NvFlexSolverCallback NvFlexRegisterSolverCallback(NvFlexSolver* solver, NvFlexSolverCallback function, NvFlexSolverCallbackStage stage); + +/** + * Integrate particle solver forward in time. Below is an example of how to step Flex in the context of a simple game loop: + * + \code{.c} + + NvFlexLibrary* library = NvFlexInit(); + NvFlexSolver* solver = NvFlexCreateSolver(library); + + NvFlexBuffer* particleBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4), eNvFlexBufferHost); + NvFlexBuffer* velocityBuffer = NvFlexAllocBuffer(library, n, sizeof(Vec4), eNvFlexBufferHost); + NvFlexBuffer* phaseBuffer = NvFlexAllocBuffer(library, n, sizeof(int), eNvFlexBufferHost); + + while(!done) + { + // map buffers for reading / writing + float4* particles = (float4*)NvFlexMap(particles, eNvFlexMapWait); + float3* velocities = (float3*)NvFlexMap(velocities, eNvFlexMapWait); + int* phases = (int*)NvFlexMap(phases, eNvFlexMapWait); + + // spawn (user method) + SpawnParticles(particles, velocities, phases); + + // render (user method) + RenderParticles(particles, velocities, phases); + + // unmap buffers + NvFlexUnmap(particleBuffer); + NvFlexUnmap(velocityBuffer); + NvFlexUnmap(phaseBuffer); + + // write to device (async) + NvFlexSetParticles(particleBuffer, n); + NvFlexSetVelocities(velocityBuffer, n); + NvFlexSetPhases(phaseBuffer, n); + + // tick + NvFlexUpdateSolver(solver, dt, 1, NULL); + + // read back (async) + NvFlexGetParticles(particleBuffer, n); + NvFlexGetVelocities(velocityBuffer, n); + NvFlexGetPhases(phaseBuffer, n); + } + + NvFlexFreeBuffer(particleBuffer); + NvFlexFreeBuffer(velocityBuffer); + NvFlexFreeBuffer(phaseBuffer); + + NvFlexDestroySolver(solver); + NvFlexShutdown(library); + + + \endcode + * + * @param[in] solver A valid solver + * @param[in] dt Time to integrate the solver forward in time by + * @param[in] substeps The time dt will be divided into the number of sub-steps given by this parameter + * @param[in] enableTimers Whether to enable per-kernel timers for profiling. Note that profiling can substantially slow down overall performance so this param should only be true in non-release builds + */ +NV_FLEX_API void NvFlexUpdateSolver(NvFlexSolver* solver, float dt, int substeps, bool enableTimers); + +/** + * Update solver paramters + * + * @param[in] solver A valid solver + * @param[in] params Parameters structure in host memory, see NvFlexParams + */ +NV_FLEX_API void NvFlexSetParams(NvFlexSolver* solver, const NvFlexParams* params); + +/** + * Retrieve solver paramters, default values will be set at solver creation time + * + * @param[in] solver A valid solver + * @param[out] params Parameters structure in host memory, see NvFlexParams + */ + +NV_FLEX_API void NvFlexGetParams(NvFlexSolver* solver, NvFlexParams* params); + +/** + * Set the active particles indices in the solver + * + * @param[in] solver A valid solver + * @param[in] indices Holds the indices of particles that have been made active + * @param[in] n Number of particles to allocate + */ +NV_FLEX_API void NvFlexSetActive(NvFlexSolver* solver, NvFlexBuffer* indices, int n); + +/** + * Return the active particle indices + * + * @param[in] solver A valid solver + * @param[out] indices a buffer of indices at least activeCount in length + */ +NV_FLEX_API void NvFlexGetActive(NvFlexSolver* solver, NvFlexBuffer* indices); + +/** + * Return the number of active particles in the solver + * + * @param[in] solver A valid solver + * @return The number of active particles in the solver + */ +NV_FLEX_API int NvFlexGetActiveCount(NvFlexSolver* solver); + +/** + * Set the particles state of the solver, a particle consists of 4 floating point numbers, its x,y,z position followed by its inverse mass (1/m) + * + * @param[in] solver A valid solver + * @param[in] p Pointer to a buffer of particle data, should be 4*n in length + * @param[in] n The number of particles to set + * + */ +NV_FLEX_API void NvFlexSetParticles(NvFlexSolver* solver, NvFlexBuffer* p, int n); + +/** + * Get the particles state of the solver, a particle consists of 4 floating point numbers, its x,y,z position followed by its inverse mass (1/m) + * + * @param[in] solver A valid solver + * @param[out] p Pointer to a buffer of 4*n floats that will be filled out with the particle data, can be either a host or device pointer + * @param[in] n The number of particles to get, must be less than max particles passed to NvFlexCreateSolver + */ +NV_FLEX_API void NvFlexGetParticles(NvFlexSolver* solver, NvFlexBuffer* p, int n); + +/** + * Set the particle positions in their rest state, if eNvFlexPhaseSelfCollideFilter is set on the particle's + * phase attribute then particles that overlap in the rest state will not generate collisions with each other + * + * @param[in] solver A valid solver + * @param[in] p Pointer to a buffer of particle data, should be 4*n in length + * @param[in] n The number of particles to set + * + */ +NV_FLEX_API void NvFlexSetRestParticles(NvFlexSolver* solver, NvFlexBuffer* p, int n); + +/** + * Get the particle positions in their rest state + * + * @param[in] solver A valid solver + * @param[in] p Pointer to a buffer of particle data, should be 4*n in length + * @param[in] n The number of particles to set + * + */ +NV_FLEX_API void NvFlexGetRestParticles(NvFlexSolver* solver, NvFlexBuffer* p, int n); + + +/** + * Get the Laplacian smoothed particle positions for rendering, see NvFlexParams::smoothing + * + * @param[in] solver A valid solver + * @param[out] p Pointer to a buffer of 4*n floats that will be filled out with the data, can be either a host or device pointer + * @param[in] n The number of smooth particles to return + */ +NV_FLEX_API void NvFlexGetSmoothParticles(NvFlexSolver* solver, NvFlexBuffer* p, int n); + +/** + * Set the particle velocities, each velocity is a 3-tuple of x,y,z floating point values + * + * @param[in] solver A valid solver + * @param[in] v Pointer to a buffer of 3*n floats + * @param[in] n The number of velocities to set + * + */ +NV_FLEX_API void NvFlexSetVelocities(NvFlexSolver* solver, NvFlexBuffer* v, int n); +/** + * Get the particle velocities, each velocity is a 3-tuple of x,y,z floating point values + * + * @param[in] solver A valid solver + * @param[out] v Pointer to a buffer of 3*n floats that will be filled out with the data, can be either a host or device pointer + * @param[in] n The number of velocities to get + */ +NV_FLEX_API void NvFlexGetVelocities(NvFlexSolver* solver, NvFlexBuffer* v, int n); + +/** + * Set the particles phase id array, each particle has an associated phase id which + * controls how it interacts with other particles. Particles with phase 0 interact with all + * other phase types. + * + * Particles with a non-zero phase id only interact with particles whose phase differs + * from theirs. This is useful, for example, to stop particles belonging to a single + * rigid shape from interacting with each other. + * + * Phase 0 is used to indicate fluid particles when NvFlexParams::mFluid is set. + * + * @param[in] solver A valid solver + * @param[in] phases Pointer to a buffer of n integers containing the phases + * @param[in] n The number of phases to set + * + */ +NV_FLEX_API void NvFlexSetPhases(NvFlexSolver* solver, NvFlexBuffer* phases, int n); +/** + * Get the particle phase ids + * + * @param[in] solver A valid solver + * @param[out] phases Pointer to a buffer of n integers that will be filled with the phase data, can be either a host or device pointer + * @param[in] n The number of phases to get + */ +NV_FLEX_API void NvFlexGetPhases(NvFlexSolver* solver, NvFlexBuffer* phases, int n); + +/** + * Set per-particle normals to the solver, these will be overwritten after each simulation step, but can be used to initialize the normals to valid values + * + * @param[in] solver A valid solver + * @param[in] normals Pointer to a buffer of normals, should be 4*n in length + * @param[in] n The number of normals to set + * + */ +NV_FLEX_API void NvFlexSetNormals(NvFlexSolver* solver, NvFlexBuffer* normals, int n); + +/** + * Get per-particle normals from the solver, these are the world-space normals computed during surface tension, cloth, and rigid body calculations + * + * @param[in] solver A valid solver + * @param[out] normals Pointer to a buffer of normals, should be 4*n in length + * @param[in] n The number of normals to get + */ +NV_FLEX_API void NvFlexGetNormals(NvFlexSolver* solver, NvFlexBuffer* normals, int n); + + +/** + * Set distance constraints for the solver. Each distance constraint consists of two particle indices + * stored consecutively, a rest-length, and a stiffness value. These are not springs in the traditional + * sense, but behave somewhat like a traditional spring when lowering the stiffness coefficient. + * + * @param[in] solver A valid solver + * @param[in] indices Pointer to the spring indices array, should be 2*numSprings length, 2 indices per-spring + * @param[in] restLengths Pointer to a buffer of rest lengths, should be numSprings length + * @param[in] stiffness Pointer to the spring stiffness coefficents, should be numSprings in length, a negative stiffness value represents a tether constraint + * @param[in] numSprings The number of springs to set + * + */ +NV_FLEX_API void NvFlexSetSprings(NvFlexSolver* solver, NvFlexBuffer* indices, NvFlexBuffer* restLengths, NvFlexBuffer* stiffness, int numSprings); +/** + * Get the distance constraints from the solver + * + * @param[in] solver A valid solver + * @param[out] indices Pointer to the spring indices array, should be 2*numSprings length, 2 indices per-spring + * @param[out] restLengths Pointer to a buffer of rest lengths, should be numSprings length + * @param[out] stiffness Pointer to the spring stiffness coefficents, should be numSprings in length, a negative stiffness value represents a unilateral tether constraint (only resists stretching, not compression), valid range [-1, 1] + * @param[in] numSprings The number of springs to get + */ +NV_FLEX_API void NvFlexGetSprings(NvFlexSolver* solver, NvFlexBuffer* indices, NvFlexBuffer* restLengths, NvFlexBuffer* stiffness, int numSprings); + +/** + * Set rigid body constraints for the solver. + * @note A particle should not belong to more than one rigid body at a time. + * + * @param[in] solver A valid solver + * @param[in] offsets Pointer to a buffer of start offsets for a rigid in the indices array, should be numRigids+1 in length, the first entry must be 0 + * @param[in] indices Pointer to a buffer of indices for the rigid bodies, the indices for the jth rigid body start at indices[offsets[j]] and run to indices[offsets[j+1]] exclusive + * @param[in] restPositions Pointer to a buffer of local space positions relative to the rigid's center of mass (average position), this should be at least 3*numIndices in length in the format x,y,z + * @param[in] restNormals Pointer to a buffer of local space normals, this should be at least 4*numIndices in length in the format x,y,z,w where w is the (negative) signed distance of the particle inside its shape + * @param[in] stiffness Pointer to a buffer of rigid stiffness coefficents, should be numRigids in length, valid values in range [0, 1] + * @param[in] rotations Pointer to a buffer of quaternions (4*numRigids in length) + * @param[in] translations Pointer to a buffer of translations of the center of mass (3*numRigids in length) + * @param[in] numRigids The number of rigid bodies to set + * @param[in] numIndices The number of indices in the indices array + * + */ +NV_FLEX_API void NvFlexSetRigids(NvFlexSolver* solver, NvFlexBuffer* offsets, NvFlexBuffer* indices, NvFlexBuffer* restPositions, NvFlexBuffer* restNormals, NvFlexBuffer* stiffness, NvFlexBuffer* rotations, NvFlexBuffer* translations, int numRigids, int numIndices); + + +/** + * Get the rotation matrices for the rigid bodies in the solver + * + * @param[in] solver A valid solver + * @param[out] rotations Pointer to a buffer of quaternions, should be 4*numRigids floats in length + * @param[out] translations Pointer to a buffer of vectors to hold the rigid translations, should be 3*numRigids floats in length + */ +NV_FLEX_API void NvFlexGetRigidTransforms(NvFlexSolver* solver, NvFlexBuffer* rotations, NvFlexBuffer* translations); + +/** + * An opaque type representing a static triangle mesh in the solver + */ +typedef unsigned int NvFlexTriangleMeshId; + +/** + * An opaque type representing a signed distance field collision shape in the solver. + */ +typedef unsigned int NvFlexDistanceFieldId; + +/** + * An opaque type representing a convex mesh collision shape in the solver. + * Convex mesh shapes may consist of up to 64 planes of the form a*x + b*y + c*z + d = 0, + * particles will be constrained to the outside of the shape. + */ +typedef unsigned int NvFlexConvexMeshId; + +/** + * Create triangle mesh geometry, note that meshes may be used by multiple solvers if desired + * + * @param[in] lib The library instance to use + * @return A pointer to a triangle mesh object + */ +NV_FLEX_API NvFlexTriangleMeshId NvFlexCreateTriangleMesh(NvFlexLibrary* lib); + +/** + * Destroy a triangle mesh created with NvFlexCreateTriangleMesh() + * + * @param[in] lib The library instance to use + * @param[in] mesh A triangle mesh created with NvFlexCreateTriangleMesh() + */ +NV_FLEX_API void NvFlexDestroyTriangleMesh(NvFlexLibrary* lib, NvFlexTriangleMeshId mesh); + +/** + * Specifies the triangle mesh geometry (vertices and indices), this method will cause any internal + * data structures (e.g.: bounding volume hierarchies) to be rebuilt. + * + * @param[in] lib The library instance to use + * @param[in] mesh A triangle mesh created with NvFlexCreateTriangleMesh() + * @param[in] vertices Pointer to a buffer of float3 vertex positions + * @param[in] indices Pointer to a buffer of triangle indices, should be length numTriangles*3 + * @param[in] numVertices The number of vertices in the vertices array + * @param[in] numTriangles The number of triangles in the mesh + * @param[in] lower A pointer to a float3 vector holding the lower spatial bounds of the mesh + * @param[in] upper A pointer to a float3 vector holding the upper spatial bounds of the mesh + */ +NV_FLEX_API void NvFlexUpdateTriangleMesh(NvFlexLibrary* lib, NvFlexTriangleMeshId mesh, NvFlexBuffer* vertices, NvFlexBuffer* indices, int numVertices, int numTriangles, const float* lower, const float* upper); + +/** + * Retrieve the local space bounds of the mesh, these are the same values specified to NvFlexUpdateTriangleMesh() + * + * @param[in] lib The library instance to use + * @param[in] mesh Pointer to a triangle mesh object + * @param[out] lower Pointer to a buffer of 3 floats that the lower mesh bounds will be written to + * @param[out] upper Pointer to a buffer of 3 floats that the upper mesh bounds will be written to + */ +NV_FLEX_API void NvFlexGetTriangleMeshBounds(NvFlexLibrary* lib, const NvFlexTriangleMeshId mesh, float* lower, float* upper); + +/** + * Create a signed distance field collision shape, see NvFlexDistanceFieldId for details. + * + * @param[in] lib The library instance to use + * @return A pointer to a signed distance field object + */ +NV_FLEX_API NvFlexDistanceFieldId NvFlexCreateDistanceField(NvFlexLibrary* lib); + +/** + * Destroy a signed distance field + * + * @param[in] lib The library instance to use + * @param[in] sdf A signed distance field created with NvFlexCreateDistanceField() + */ +NV_FLEX_API void NvFlexDestroyDistanceField(NvFlexLibrary* lib, NvFlexDistanceFieldId sdf); + +/** + * Update the signed distance field volume data, this method will upload + * the field data to a 3D texture on the GPU + * + * @param[in] lib The library instance to use + * @param[in] sdf A signed distance field created with NvFlexCreateDistanceField() + * @param[in] dimx The x-dimension of the volume data in voxels + * @param[in] dimy The y-dimension of the volume data in voxels + * @param[in] dimz The z-dimension of the volume data in voxels + * @param[in] field The volume data stored such that the voxel at the x,y,z coordinate is addressed as field[z*dimx*dimy + y*dimx + x] + */ +NV_FLEX_API void NvFlexUpdateDistanceField(NvFlexLibrary* lib, NvFlexDistanceFieldId sdf, int dimx, int dimy, int dimz, NvFlexBuffer* field); + +/** + * Create a convex mesh collision shapes, see NvFlexConvexMeshId for details. + * + * @param[in] lib The library instance to use + * @return A pointer to a signed distance field object + */ +NV_FLEX_API NvFlexConvexMeshId NvFlexCreateConvexMesh(NvFlexLibrary* lib); + +/** + * Destroy a convex mesh + * + * @param[in] lib The library instance to use + * @param[in] convex A a convex mesh created with NvFlexCreateConvexMesh() + */ +NV_FLEX_API void NvFlexDestroyConvexMesh(NvFlexLibrary* lib, NvFlexConvexMeshId convex); + +/** + * Update the convex mesh geometry + * + * @param[in] lib The library instance to use + * @param[in] convex A valid convex mesh shape created from NvFlexCreateConvexMesh() + * @param[in] planes An array of planes, each plane consists of 4 floats in the form a*x + b*y + c*z + d = 0 + * @param[in] numPlanes The number of planes in the convex + * @param[in] lower The local space lower bound of the convex shape + * @param[in] upper The local space upper bound of the convex shape + */ +NV_FLEX_API void NvFlexUpdateConvexMesh(NvFlexLibrary* lib, NvFlexConvexMeshId convex, NvFlexBuffer* planes, int numPlanes, float* lower, float* upper); + +/** + * Retrieve the local space bounds of the mesh, these are the same values specified to NvFlexUpdateConvexMesh() + * + * @param[in] lib The library instance to use + * @param[in] mesh Pointer to a convex mesh object + * @param[out] lower Pointer to a buffer of 3 floats that the lower mesh bounds will be written to + * @param[out] upper Pointer to a buffer of 3 floats that the upper mesh bounds will be written to + */ +NV_FLEX_API void NvFlexGetConvexMeshBounds(NvFlexLibrary* lib, NvFlexConvexMeshId mesh, float* lower, float* upper); + +/** + * A basic sphere shape with origin at the center of the sphere and radius + */ +struct NvFlexSphereGeometry +{ + float radius; +}; + +/** + * A collision capsule extends along the x-axis with its local origin at the center of the capsule + */ +struct NvFlexCapsuleGeometry +{ + float radius; + float halfHeight; +}; + +/** + * A simple box with interior [-halfHeight, +halfHeight] along each dimension + */ +struct NvFlexBoxGeometry +{ + float halfExtents[3]; +}; + +/** + * A convex mesh instance with non-uniform scale + */ +struct NvFlexConvexMeshGeometry +{ + float scale[3]; + NvFlexConvexMeshId mesh; +}; + +/** + * A scaled triangle mesh instance with non-uniform scale + */ +struct NvFlexTriangleMeshGeometry +{ + float scale[3]; //!< The scale of the object from local space to world space + NvFlexTriangleMeshId mesh; //!< A triangle mesh pointer created by NvFlexCreateTriangleMesh() +}; + +/** + * A scaled signed distance field instance, the local origin of the SDF is at corner of the field corresponding to the first voxel. + * The field is mapped to the local space volume [0, 1] in each dimension. + */ +struct NvFlexSDFGeometry +{ + float scale; //!< Uniform scale of SDF, this corresponds to the world space width of the shape + NvFlexDistanceFieldId field; //!< A signed distance field pointer created by NvFlexCreateDistanceField() +}; + +/** + * This union allows collision geometry to be sent to Flex as a flat array of 16-byte data structures, + * the shape flags array specifies the type for each shape, see NvFlexSetShapes(). + */ +union NvFlexCollisionGeometry +{ + NvFlexSphereGeometry sphere; + NvFlexCapsuleGeometry capsule; + NvFlexBoxGeometry box; + NvFlexConvexMeshGeometry convexMesh; + NvFlexTriangleMeshGeometry triMesh; + NvFlexSDFGeometry sdf; +}; + +enum NvFlexCollisionShapeType +{ + eNvFlexShapeSphere = 0, //!< A sphere shape, see FlexSphereGeometry + eNvFlexShapeCapsule = 1, //!< A capsule shape, see FlexCapsuleGeometry + eNvFlexShapeBox = 2, //!< A box shape, see FlexBoxGeometry + eNvFlexShapeConvexMesh = 3, //!< A convex mesh shape, see FlexConvexMeshGeometry + eNvFlexShapeTriangleMesh = 4, //!< A triangle mesh shape, see FlexTriangleMeshGeometry + eNvFlexShapeSDF = 5, //!< A signed distance field shape, see FlexSDFGeometry +}; + +enum NvFlexCollisionShapeFlags +{ + eNvFlexShapeFlagTypeMask = 0x7, //!< Lower 3 bits holds the type of the collision shape + eNvFlexShapeFlagDynamic = 8, //!< Indicates the shape is dynamic and should have lower priority over static collision shapes + eNvFlexShapeFlagTrigger = 16, //!< Indicates that the shape is a trigger volume, this means it will not perform any collision response, but will be reported in the contacts array (see NvFlexGetContacts()) + + eNvFlexShapeFlagReserved = 0xffffff00 +}; + +/** + * Combines geometry type and static/dynamic flags + */ +NV_FLEX_API inline int NvFlexMakeShapeFlags(NvFlexCollisionShapeType type, bool dynamic) { return type | (dynamic?eNvFlexShapeFlagDynamic:0); } + +/** + * Set the collision shapes for the solver + * + * @param[in] solver A valid solver + * @param[in] geometry Pointer to a buffer of NvFlexCollisionGeometry entries, the type of each shape determines how many entries it has in the array + * @param[in] shapePositions Pointer to a buffer of translations for each shape in world space, should be 4*numShapes in length + * @param[in] shapeRotations Pointer to an a buffer of rotations for each shape stored as quaternion, should be 4*numShapes in length + * @param[in] shapePrevPositions Pointer to a buffer of translations for each shape at the start of the time step, should be 4*numShapes in length + * @param[in] shapePrevRotations Pointer to an a buffer of rotations for each shape stored as a quaternion at the start of the time step, should be 4*numShapees in length + * @param[in] shapeFlags The type and behavior of the shape, NvFlexCollisionShapeFlags for more detail + * @param[in] numShapes The number of shapes + * + */ +NV_FLEX_API void NvFlexSetShapes(NvFlexSolver* solver, NvFlexBuffer* geometry, NvFlexBuffer* shapePositions, NvFlexBuffer* shapeRotations, NvFlexBuffer* shapePrevPositions, NvFlexBuffer* shapePrevRotations, NvFlexBuffer* shapeFlags, int numShapes); + +/** + * Set dynamic triangles mesh indices, typically used for cloth. Flex will calculate normals and + * apply wind and drag effects to connected particles. See NvFlexParams::drag, NvFlexParams::wind. + * + * @param[in] solver A valid solver + * @param[in] indices Pointer to a buffer of triangle indices into the particles array, should be 3*numTris in length + * @param[in] normals Pointer to a buffer of triangle normals, should be 3*numTris in length, can be NULL + * @param[in] numTris The number of dynamic triangles + *s + */ +NV_FLEX_API void NvFlexSetDynamicTriangles(NvFlexSolver* solver, NvFlexBuffer* indices, NvFlexBuffer* normals, int numTris); +/** + * Get the dynamic triangle indices and normals. + * + * @param[in] solver A valid solver + * @param[out] indices Pointer to a buffer of triangle indices into the particles array, should be 3*numTris in length, if NULL indices will not be returned + * @param[out] normals Pointer to a buffer of triangle normals, should be 3*numTris in length, if NULL normals will be not be returned + * @param[in] numTris The number of dynamic triangles + */ +NV_FLEX_API void NvFlexGetDynamicTriangles(NvFlexSolver* solver, NvFlexBuffer* indices, NvFlexBuffer* normals, int numTris); + +/** + * Set inflatable shapes, an inflatable is a range of dynamic triangles (wound CCW) that represent a closed mesh. + * Each inflatable has a given rest volume, constraint scale (roughly equivalent to stiffness), and "over pressure" + * that controls how much the shape is inflated. + * + * @param[in] solver A valid solver + * @param[in] startTris Pointer to a buffer of offsets into the solver's dynamic triangles for each inflatable, should be numInflatables in length + * @param[in] numTris Pointer to a buffer of triangle counts for each inflatable, should be numInflatablesin length + * @param[in] restVolumes Pointer to a buffer of rest volumes for the inflatables, should be numInflatables in length + * @param[in] overPressures Pointer to a buffer of floats specifying the pressures for each inflatable, a value of 1.0 means the rest volume, > 1.0 means over-inflated, and < 1.0 means under-inflated, should be numInflatables in length + * @param[in] constraintScales Pointer to a buffer of scaling factors for the constraint, this is roughly equivalent to stiffness but includes a constraint scaling factor from position-based dynamics, see helper code for details, should be numInflatables in length + * @param[in] numInflatables Number of inflatables to set + * + */ +NV_FLEX_API void NvFlexSetInflatables(NvFlexSolver* solver, NvFlexBuffer* startTris, NvFlexBuffer* numTris, NvFlexBuffer* restVolumes, NvFlexBuffer* overPressures, NvFlexBuffer* constraintScales, int numInflatables); + +/** + * Get the density values for fluid particles + * + * @param[in] solver A valid solver + * @param[in] n The number of particle densities to return + * @param[out] densities Pointer to a buffer of floats, should be maxParticles in length, density values are normalized between [0, 1] where 1 represents the rest density + */ +NV_FLEX_API void NvFlexGetDensities(NvFlexSolver* solver, NvFlexBuffer* densities, int n); + +/** + * Get the anisotropy of fluid particles, the particle distribution for a particle is represented + * by 3 orthogonal vectors. Each 3-vector has unit length with the variance along that axis + * packed into the w component, i.e.: x,y,z,lambda. +* + * The anisotropy defines an oriented ellipsoid in worldspace that can be used for rendering + * or surface extraction. + * + * @param[in] solver A valid solver + * @param[out] q1 Pointer to a buffer of floats that receive the first basis vector and scale, should be 4*maxParticles in length + * @param[out] q2 Pointer to a buffer of floats that receive the second basis vector and scale, should be 4*maxParticles in length + * @param[out] q3 Pointer to a buffer of floats that receive the third basis vector and scale, should be 4*maxParticles in length + */ +NV_FLEX_API void NvFlexGetAnisotropy(NvFlexSolver* solver, NvFlexBuffer* q1, NvFlexBuffer* q2, NvFlexBuffer* q3); +/** + * Get the state of the diffuse particles. Diffuse particles are passively advected by the fluid + * velocity field. + * + * @param[in] solver A valid solver + * @param[out] p Pointer to a buffer of floats, should be 4*maxParticles in length, the w component represents the particles lifetime with 1 representing a new particle, and 0 representing an inactive particle + * @param[out] v Pointer to a buffer of floats, should be 4*maxParticles in length, the w component is not used + * @param[out] indices Pointer to a buffer of ints that specify particle indices in depth sorted order, should be maxParticles in length, see NvFlexParams::mDiffuseSortDir + */ +NV_FLEX_API int NvFlexGetDiffuseParticles(NvFlexSolver* solver, NvFlexBuffer* p, NvFlexBuffer* v, NvFlexBuffer* indices); + +/** + * Set the state of the diffuse particles. Diffuse particles are passively advected by the fluid + * velocity field. + * + * @param[in] solver A valid solver + * @param[in] p Pointer to a buffer of floats, should be 4*n in length, the w component represents the particles lifetime with 1 representing a new particle, and 0 representing an inactive particle + * @param[in] v Pointer to a buffer of floats, should be 4*n in length, the w component is not used + * @param[in] n Number of diffuse particles to set + * + */ +NV_FLEX_API void NvFlexSetDiffuseParticles(NvFlexSolver* solver, NvFlexBuffer* p, NvFlexBuffer* v, int n); + +/** + * Get the particle contact planes. Note this will only include contacts that were active on the last substep of an update, and will include all contact planes generated within NvFlexParams::shapeCollisionMargin. + * + * @param[in] solver A valid solver + * @param[out] planes Pointer to a destination buffer containing the contact planes for the particle, each particle can have up to 4 contact planes so this buffer should be 16*maxParticles in length + * @param[out] velocities Pointer to a destination buffer containing the velocity of the contact point on the shape in world space, the index of the shape (corresponding to the shape in NvFlexSetShapes() is stored in the w component), each particle can have up to 4 contact planes so this buffer should be 16*maxParticles in length + * @param[out] indices Pointer to a buffer of indices into the contacts buffer, the first contact plane for the i'th particle is given by planes[indices[i]*sizeof(float)*4] and subsequent contacts for that particle are stored sequentially, this array should be maxParticles in length + * @param[out] counts Pointer to a buffer of contact counts for each particle (will be <= 4), this buffer should be maxParticles in length + */ +NV_FLEX_API void NvFlexGetContacts(NvFlexSolver* solver, NvFlexBuffer* planes, NvFlexBuffer* velocities, NvFlexBuffer* indices, NvFlexBuffer* counts); + +/** + * Get the world space AABB of all particles in the solver, note that the bounds are calculated during the update (see NvFlexUpdateSolver()) so only become valid after an update has been performed. + * The returned bounds represent bounds of the particles in their predicted positions *before* the constraint solve. + * + * @param[in] solver A valid solver + * @param[out] lower Pointer to a buffer of 3 floats to receive the lower bounds + * @param[out] upper Pointer to a buffer of 3 floats to receive the upper bounds + */ +NV_FLEX_API void NvFlexGetBounds(NvFlexSolver* solver, NvFlexBuffer* lower, NvFlexBuffer* upper); + +/** + * + * @param[in] solver A valid solver + * @return The time in seconds between the first and last GPU operations executed by the last NvFlexUpdateSolver. + * + * @note This method causes the CPU to wait until the GPU has finished any outstanding work. + * To avoid blocking the calling thread it should be called after work has completed, e.g.: directly after a NvFlexMap(). + */ +NV_FLEX_API float NvFlexGetDeviceLatency(NvFlexSolver* solver); + +/** + * Fetch high-level GPU timers. + * + * @param[in] solver The solver instance to use + * @param[out] timers A struct containing the GPU latency of each stage in the physics pipeline. + * + * @note This method causes the CPU to wait until the GPU has finished any outstanding work. + * To avoid blocking the calling thread it should be called after work has completed, e.g.: directly after a NvFlexMap(). + * To capture there timers you must pass true for enableTimers in NvFlexUpdateSolver() + */ +NV_FLEX_API void NvFlexGetTimers(NvFlexSolver* solver, NvFlexTimers* timers); + +/** +* Holds the execution time for a specfic shader +*/ +struct NvFlexDetailTimer +{ + char* name; + float time; +}; + +/** +* Fetch per-shader GPU timers. +* +* @param[in] solver The solver instance to use +* @param[out] timers An array of NvFlexDetailTimer structures, each representing a unique shader. +* @return The number of detail timers in the timers array +* +* @note This method causes the CPU to wait until the GPU has finished any outstanding work. +* To avoid blocking the calling thread it should be called after work has completed, e.g.: directly after a NvFlexMap(). +* To capture there timers you must pass true for enableTimers in NvFlexUpdateSolver() +* Timers are valid until the next call to NvFlexGetDetailTimers +*/ +NV_FLEX_API int NvFlexGetDetailTimers(NvFlexSolver* solver, NvFlexDetailTimer** timers); + +/** + * Allocate a Flex buffer. Buffers are used to pass data to the API in an efficient manner. + * + * @param[in] lib The library instance to use + * @param[in] elementCount The number of elements in the buffer + * @param[in] elementByteStride The size of each element in bytes + * @param[in] type The type of buffer to allocate, can be either host memory or device memory + * @return A pointer to a NvFlexBuffer + */ +NV_FLEX_API NvFlexBuffer* NvFlexAllocBuffer(NvFlexLibrary* lib, int elementCount, int elementByteStride, NvFlexBufferType type); + +/** + * Free a Flex buffer + * + * @param[in] buf A buffer to free, must be allocated with NvFlexAllocBuffer() + */ +NV_FLEX_API void NvFlexFreeBuffer(NvFlexBuffer* buf); + +/** + * Maps a buffer for reading and writing. When the buffer is created with NvFlexBufferType::eHost, then the returned pointer will be a host memory address + * that can be read/written. + * Mapping a buffer implicitly synchronizes with the GPU to ensure that any reads or writes from the buffer (e.g.: from the NvFlexGet*() or NvFlexSet*()) methods have completed. + * + * @param[in] buffer A buffer allocated with NvFlexAllocBuffer() + * @param[in] flags Hints to Flex how the buffer is to be accessed, typically this should be eNvFlexMapWait (0) + * @return A pointer to the mapped memory + */ +NV_FLEX_API void* NvFlexMap(NvFlexBuffer* buffer, int flags); + +/** + * Unmaps a buffer that was mapped through NvFlexMap(), note that buffers must be unmapped before they can be passed to a NvFlexGet*() or NvFlexSet*() method + * + * @param[in] buffer A valid buffer allocated through NvFlexAllocBuffer() + */ +NV_FLEX_API void NvFlexUnmap(NvFlexBuffer* buffer); + +/** + * Registers an OpenGL buffer to Flex which can be used to copy directly into a graphics resource. Example usage is below + * + \code{.c} + + GLuint vbo; + glGenBuffers(1, &vbo); + glBindBuffer(GL_ARRAY_BUFFER, vbo); + glBufferData(GL_ARRAY_BUFFER, size, NULL, GL_DYNAMIC_DRAW) + + NvFlexBuffer* vboBuffer = NvFlexRegisterOGLBuffer(lib, vbo, n, sizeof(float)*4); + + // simulate + ... + + // copy directly from Flex into render buffer + NvFlexGetParticles(vboBuffer, n); + + // render + ... + + \endcode + * + * @param[in] lib The library instance to use + * @param[in] buf An OpenGL buffer identifier + * @param[in] elementCount The number of elements in the buffer + * @param[in] elementByteStride the size of each element in bytes + * @return A valid NvFlexBuffer pointer that may be used with NvFlexGet*() methods to populate the render buffer using direct GPU-GPU copies + */ +NV_FLEX_API NvFlexBuffer* NvFlexRegisterOGLBuffer(NvFlexLibrary* lib, int buf, int elementCount, int elementByteStride); + +/** + * Unregister a NvFlexBuffer allocated through NvFlexRegisterOGLBuffer() + * + * @param[in] buf A valid buffer + */ +NV_FLEX_API void NvFlexUnregisterOGLBuffer(NvFlexBuffer* buf); + +/** +* Registers a Direct3D buffer to Flex which can be used to copy directly into a graphics resource +* +* @param[in] lib The library instance to use +* @param[in] buffer A pointer to either an ID3D11Buffer or ID3D12Resource object +* @param[in] elementCount The number of elements in the buffer +* @param[in] elementByteStride the size of each element in bytes +* @return A valid NvFlexBuffer pointer that may be used with NvFlexGet*() methods to populate the render buffer using direct GPU-GPU copies +*/ +NV_FLEX_API NvFlexBuffer* NvFlexRegisterD3DBuffer(NvFlexLibrary* lib, void* buffer, int elementCount, int elementByteStride); + +/** +* Unregister a NvFlexBuffer allocated through NvFlexRegistereD3DBuffer() +* +* @param[in] buf A valid buffer +*/ +NV_FLEX_API void NvFlexUnregisterD3DBuffer(NvFlexBuffer* buf); + +/** + * Ensures that the CUDA context the library was initialized with is present on the current thread + * + * @param[in] lib The library instance to use + */ +NV_FLEX_API void NvFlexAcquireContext(NvFlexLibrary* lib); + +/** + * Restores the CUDA context (if any) that was present on the last call to NvFlexAcquireContext() + * Note: the acquire/restore pair of calls must come from the same thread + */ +NV_FLEX_API void NvFlexRestoreContext(NvFlexLibrary* lib); + +/** + * Returns a null-terminated string with the compute device name + * + * @param[in] lib The library instance to use + */ +NV_FLEX_API const char* NvFlexGetDeviceName(NvFlexLibrary* lib); + +/** + * Retrieve the device and context for the the library. + * On CUDA the context pointer will be filled with a pointer to a CUcontext structure + * On D3D the device and context pointers will be filled with pointers to a NvFlex::Device, and NvFlex::Context wrapper + * + * @param[in] lib Pointer to a valid library returned from NvFlexInit() + * @param[out] device Pointer to a device pointer, see description + * @param[out] context Pointer to a context pointer, see description + */ +NV_FLEX_API void NvFlexGetDeviceAndContext(NvFlexLibrary* lib, void** device, void** context); + + +/** + * Force a pipeline flush to ensure any queued work is submitted to the GPU + * + * @param[in] lib The library instance to use + */ +NV_FLEX_API void NvFlexFlush(NvFlexLibrary* lib); + +//! \cond HIDDEN_SYMBOLS + +/** + * Debug methods (unsupported) + */ + +NV_FLEX_API void NvFlexSetDebug(NvFlexSolver* solver, bool enable); +NV_FLEX_API void NvFlexGetShapeBVH(NvFlexSolver* solver, void* bvh); +NV_FLEX_API void NvFlexCopySolver(NvFlexSolver* dst, NvFlexSolver* src); + +//! \endcond + +} // extern "C" + +#endif // NV_FLEX_H diff --git a/include/NvFlexDevice.h b/include/NvFlexDevice.h new file mode 100644 index 0000000..8c1cda2 --- /dev/null +++ b/include/NvFlexDevice.h @@ -0,0 +1,75 @@ +// 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) 2013-2017 NVIDIA Corporation. All rights reserved. + +#ifndef NV_FLEX_DEVICE_H +#define NV_FLEX_DEVICE_H + +//! \cond HIDDEN_SYMBOLS +#ifndef NV_FLEX_API +#if _WIN32 +#define NV_FLEX_API __declspec(dllexport) +#else +#define NV_FLEX_API +#endif +#endif +//! \endcond + +/** \file + * NvFlexDevice is an optional helper library that performs some + * initialization tasks related to GPU device management. + * The library can be used to query the NVIDIA PhysX control panel for + * the selected "PhysX" GPU, and to create an optimized CUDA context. + * Currently the library is a closed source component but is purely optional. + * See the FlexDemo for an example of how to use the device API. + */ + +/** + * Returns the CUDA ordinal of the GPU selected as "PhysX" in the NVIDIA control panel. + * Returns -1 if there is no NVIDIA CUDA device available. + * + * @note The returned ordinal is a CUDA ordinal and does not correspond to the DXGI + * ordinal. D3D users should use their own device selection method and pass the appropriate + * DXGI device index or custom D3D devices to NvFlexInit(). + */ +NV_FLEX_API int NvFlexDeviceGetSuggestedOrdinal(); + +/** + * Creates a CUDA context optimized for Flex, returns true on success and sets the context + * as current on the calling thread. If using this method to initialize CUDA then you should + * ensure that no prior CUDA calls are made prior to avoid creating multiple contexts. + * + * @param[in] ordinal The CUDA ordinal of the GPU to create the context on, this can be the suggested ordinal (see flexDeviceGetSuggestedOrdinal()), or a manually selected ordinal. + */ +NV_FLEX_API bool NvFlexDeviceCreateCudaContext(int ordinal); + +/** + * Destroy the context associated with the current thread, can be used to destroy the CUDA context created by flexDeviceCreateCudaContext(). + */ +NV_FLEX_API void NvFlexDeviceDestroyCudaContext(); + + +#endif // NV_FLEX_DEVICE_H
\ No newline at end of file diff --git a/include/NvFlexExt.h b/include/NvFlexExt.h new file mode 100644 index 0000000..ec78b81 --- /dev/null +++ b/include/NvFlexExt.h @@ -0,0 +1,768 @@ +// 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) 2013-2017 NVIDIA Corporation. All rights reserved. + +#ifndef NV_FLEX_EXT_H +#define NV_FLEX_EXT_H + +/** \file NvFlexExt.h + * The main include file for the Flex extensions API, this is a collection of helper functions + * for asset creation, scene management, and sample code that builds on the Flex core API. + */ + +#include "NvFlex.h" + +#include <cassert> +#include <cstddef> + +// A vector type that wraps a NvFlexBuffer, behaves like a standard vector for POD types (no construction) +// The vector must be mapped using map() before any read/write access to elements or resize operation + +template <typename T> +struct NvFlexVector +{ + NvFlexVector(NvFlexLibrary* l, int size=0) : lib(l), buffer(NULL), mappedPtr(NULL), count(0), capacity(0) + { + if (size) + { + resize(size); + + // resize implicitly maps, unmap initial allocation + unmap(); + } + } + + NvFlexVector(NvFlexLibrary* l, const T* ptr, int size) : lib(l), buffer(NULL), mappedPtr(NULL), count(0), capacity(0) + { + assign(ptr, size); + unmap(); + } + + + ~NvFlexVector() + { + destroy(); + } + + NvFlexLibrary* lib; + NvFlexBuffer* buffer; + + T* mappedPtr; + int count; + int capacity; + + // reinitialize the vector leaving it unmapped + void init(int size) + { + destroy(); + resize(size); + unmap(); + } + + void destroy() + { + if (mappedPtr) + NvFlexUnmap(buffer); + + if (buffer) + NvFlexFreeBuffer(buffer); + + mappedPtr = NULL; + buffer = NULL; + capacity = 0; + count = 0; + } + + void map(int flags=eNvFlexMapWait) + { + if (!buffer) + return; + + assert(!mappedPtr); + mappedPtr = (T*)NvFlexMap(buffer, flags); + } + + void unmap() + { + if (!buffer) + return; + + assert(mappedPtr); + + NvFlexUnmap(buffer); + mappedPtr = 0; + } + + const T& operator[](int index) const + { + assert(mappedPtr); + assert(index < count); + + return mappedPtr[index]; + } + + T& operator[](int index) + { + assert(mappedPtr); + assert(index < count); + + return mappedPtr[index]; + } + + void push_back(const T& t) + { + assert(mappedPtr || !buffer); + + reserve(count+1); + + // copy element + mappedPtr[count++] = t; + } + + void assign(const T* srcPtr, int newCount) + { + assert(mappedPtr || !buffer); + + resize(newCount); + + memcpy(mappedPtr, srcPtr, newCount*sizeof(T)); + } + + void copyto(T* dest, int count) + { + assert(mappedPtr); + + memcpy(dest, mappedPtr, sizeof(T)*count); + } + + int size() const { return count; } + + bool empty() const { return size() == 0; } + + const T& back() const + { + assert(mappedPtr); + assert(!empty()); + + return mappedPtr[count-1]; + } + + void reserve(int minCapacity) + { + if (minCapacity > capacity) + { + // growth factor of 1.5 + const int newCapacity = minCapacity*3/2; + + NvFlexBuffer* newBuf = NvFlexAllocBuffer(lib, newCapacity, sizeof(T), eNvFlexBufferHost); + + // copy contents to new buffer + void* newPtr = NvFlexMap(newBuf, eNvFlexMapWait); + memcpy(newPtr, mappedPtr, count*sizeof(T)); + + // unmap old buffer, but leave new buffer mapped + unmap(); + + if (buffer) + NvFlexFreeBuffer(buffer); + + // swap + buffer = newBuf; + mappedPtr = (T*)newPtr; + capacity = newCapacity; + } + } + + // resizes mapped buffer and leaves new buffer mapped + void resize(int newCount) + { + assert(mappedPtr || !buffer); + + reserve(newCount); + + // resize but do not initialize new entries + count = newCount; + } + + void resize(int newCount, const T& val) + { + assert(mappedPtr || !buffer); + + const int startInit = count; + const int endInit = newCount; + + resize(newCount); + + // init any new entries + for (int i=startInit; i < endInit; ++i) + mappedPtr[i] = val; + } +}; + +extern "C" { + +/** + * Helper struct for storing the state of a moving frame, see NvFlexExtMovingFrameInit() + */ +struct NvFlexExtMovingFrame +{ + float position[3]; + float rotation[4]; + + float velocity[3]; + float omega[3]; + + float acceleration[3]; + float tau[3]; + + float delta[4][4]; +}; + +/** + * Creates a new moving frame struct. This helper method is used to calculate inertial forces for particles + * inside an attached parent frame. For example, when simulating cloth attached to the character, we would like to perform + * a local space simulation of the cloth to avoid excessive stretching and collision issues during fast animations. + * However, we would still like the cloth to respond to character movements in at least a limited, or controlled fashion. + * The NvFlexExtMovingFrame provides a way to include or remove these inertial forces. The basic usage is as follows: + * + \code{.c} + + NvFlexExtMovingFrame frame; + NvFlexExtMovingFrameInit(&frame, initialTranslation, initialRotation); + + const linearInertiaScale = 0.25f; + const angularInertiaScale 0.5; + + while(simulating) + { + float3 newPosition; + float4 newRotation; + + // move parent frame (character / emitter) according to application's animation system + Animate(newPosition, newRotation); + + // update the frame + NvFlexExtMovingFrameUpdate(frame, newPosition, newRotation, dt); + + // apply inertial forces and update particles + NvFlexExtMovingFrameApply(frame, particlePositions, particleVelocities, numParticles, linearInertiaScale, angularInertiaScale, dt); + } + + \endcode + + * @param[in] frame A pointer to a user-allocated NvFlexExtMovingFrame struct + * @param[in] worldTranslation A pointer to a vec3 storing the frame's initial translation in world space + * @param[in] worldRotation A pointer to a quaternion storing the frame's initial rotation in world space + */ +NV_FLEX_API void NvFlexExtMovingFrameInit(NvFlexExtMovingFrame* frame, const float* worldTranslation, const float* worldRotation); + +/* Update a frame to a new position, this will automatically update the velocity and acceleration of + * the frame, which can then be used to calculate inertial forces. This should be called once per-frame + * with the new position and time-step used when moving the frame. + * + * @param[in] frame A pointer to a user-allocated NvFlexExtMovingFrame struct + * @param[in] worldTranslation A pointer to a vec3 storing the frame's initial translation in world space + * @param[in] worldRotation A pointer to a quaternion storing the frame's initial rotation in world space + * @param[in] dt The time that elapsed since the last call to the frame update + */ +NV_FLEX_API void NvFlexExtMovingFrameUpdate(NvFlexExtMovingFrame* frame, const float* worldTranslation, const float* worldRotation, float dt); + +/* Teleport particles to the frame's new position and apply the inertial forces + * + * @param[in] frame A pointer to a user-allocated NvFlexExtMovingFrame struct + * @param[in] positions A pointer to an array of particle positions in (x, y, z, 1/m) format + * @param[in] velocities A pointer to an array of particle velocities in (vx, vy, vz) format + * @param[in] numParticles The number of particles to update + * @param[in] linearScale How strongly the translational inertial forces should be applied, 0.0 corresponds to a purely local space simulation removing all inertial forces, 1.0 corresponds to no inertial damping and has no benefit over regular world space simulation + * @param[in] angularScale How strongly the angular inertial forces should be applied, 0.0 corresponds to a purely local space simulation, 1.0 corresponds to no inertial damping + * @param[in] dt The time that elapsed since the last call to the frame update, should match the value passed to NvFlexExtMovingFrameUpdate() + */ +NV_FLEX_API void NvFlexExtMovingFrameApply(NvFlexExtMovingFrame* frame, float* positions, float* velocities, int numParticles, float linearScale, float angularScale, float dt); + + +/** + * Represents a group of particles and constraints, each asset + * can be instanced into a container using NvFlexExtCreateInstance() + */ +struct NvFlexExtAsset +{ + // particles + float* particles; //!< Local space particle positions, x,y,z,1/mass + int numParticles; //!< Number of particles + int maxParticles; //!< Maximum number of particles, allows extra space for tearable assets which duplicate particles + + // springs + int* springIndices; //!< Spring indices + float* springCoefficients; //!< Spring coefficients + float* springRestLengths; //!< Spring rest-lengths + int numSprings; //!< Number of springs + + // shapes + int* shapeIndices; //!< The indices of the shape matching constraints + int numShapeIndices; //!< Total number of indices for shape constraints + int* shapeOffsets; //!< Each entry stores the end of the shape's indices in the indices array (exclusive prefix sum of shape lengths) + float* shapeCoefficients; //!< The stiffness coefficient for each shape + float* shapeCenters; //!< The position of the center of mass of each shape, an array of vec3s mNumShapes in length + int numShapes; //!< The number of shape matching constraints + + // faces for cloth + int* triangleIndices; //!< Indexed triangle mesh indices for clothing + int numTriangles; //!< Number of triangles + + // inflatable params + bool inflatable; //!< Whether an inflatable constraint should be added + float inflatableVolume; //!< The rest volume for the inflatable constraint + float inflatablePressure; //!< How much over the rest volume the inflatable should attempt to maintain + float inflatableStiffness; //!< How stiff the inflatable is +}; + +/** + * Represents an instance of a FlexAsset in a container + */ +struct NvFlexExtInstance +{ + int* particleIndices; //!< Simulation particle indices + int numParticles; //!< Number of simulation particles + + int triangleIndex; //!< Index in the container's triangle array + int shapeIndex; //!< Index in the container's shape body constraints array + int inflatableIndex; //!< Index in the container's inflatables array + + float* shapeTranslations; //!< Shape matching group translations (vec3s) + float* shapeRotations; //!< Shape matching group rotations (quaternions) + + const NvFlexExtAsset* asset; //!< Source asset used to create this instance + + void* userData; //!< User data pointer +}; + +/** + * Opaque type representing a simulation + */ +typedef struct NvFlexExtContainer NvFlexExtContainer; + +/** + * Create an index buffer of unique vertices in the mesh (collapses vertices in the same position even if they have different normals / texcoords). + * This can be used to create simulation meshes from render meshes, and is typically done as a pre-pass before calling NvFlexExtCreateClothFromMesh(). + * + * @param[in] vertices A pointer to an array of float3 positions + * @param[in] numVertices The number of vertices in the mesh + * @param[out] uniqueVerts A list of unique mesh vertex indices, should be numVertices in length (worst case all verts are unique) + * @param[out] originalToUniqueMap Mapping from the original vertex index to the unique vertex index, should be numVertices in length + * @param[in] threshold The distance below which two vertices are considered duplicates + * @return The number of unique vertices in the mesh + */ +NV_FLEX_API int NvFlexExtCreateWeldedMeshIndices(const float* vertices, int numVertices, int* uniqueVerts, int* originalToUniqueMap, float threshold); + +/** + * Create a cloth asset consisting of stretch and bend distance constraints given an indexed triangle mesh. Stretch constraints will be placed along + * triangle edges, while bending constraints are placed over two edges. + * + * @param[in] particles Positions and masses of the particles in the format [x, y, z, 1/m] + * @param[in] numParticles The number of particles + * @param[in] indices The triangle indices, these should be 'welded' using NvFlexExtCreateWeldedMeshIndices() first + * @param[in] numTriangles The number of triangles + * @param[in] stretchStiffness The stiffness coefficient for stretch constraints + * @param[in] bendStiffness The stiffness coefficient used for bending constraints + * @param[in] tetherStiffness If > 0.0f then the function will create tethers attached to particles with zero inverse mass. These are unilateral, long-range attachments, which can greatly reduce stretching even at low iteration counts. + * @param[in] tetherGive Because tether constraints are so effective at reducing stiffness, it can be useful to allow a small amount of extension before the constraint activates. + * @param[in] pressure If > 0.0f then a volume (pressure) constraint will also be added to the asset, the rest volume and stiffness will be automatically computed by this function + * @return A pointer to an asset structure holding the particles and constraints + */ +NV_FLEX_API NvFlexExtAsset* NvFlexExtCreateClothFromMesh(const float* particles, int numParticles, const int* indices, int numTriangles, float stretchStiffness, float bendStiffness, float tetherStiffness, float tetherGive, float pressure); + +/** + * Create a cloth asset consisting of stretch and bend distance constraints given an indexed triangle mesh. This creates an asset with the same + * structure as NvFlexExtCreateClothFromMesh(), however tether constraints are not supported, and additional information regarding mesh topology + * will be stored with the asset to allow tearing. + * + * @note: Typically each instance of a tearable cloth mesh will have it's own asset. This is because the asset holds the topology of the mesh which is + * unique for each instance. + * + * @param[in] particles Positions and masses of the particles in the format [x, y, z, 1/m] + * @param[in] numParticles The number of particles + * @param[in] maxParticles The maximum number of particles for this asset, this will limit the amount of tearing that can be performed. + * @param[in] indices The triangle indices, these should be 'welded' using NvFlexExtCreateWeldedMeshIndices() first + * @param[in] numTriangles The number of triangles + * @param[in] stretchStiffness The stiffness coefficient for stretch constraints + * @param[in] bendStiffness The stiffness coefficient used for bending constraints + * @param[in] pressure If > 0.0f then a volume (pressure) constraint will also be added to the asset, the rest volume and stiffness will be automatically computed by this function + * @return A pointer to an asset structure holding the particles and constraints + */ +NV_FLEX_API NvFlexExtAsset* NvFlexExtCreateTearingClothFromMesh(const float* particles, int numParticles, int maxParticles, const int* indices, int numTriangles, float stretchStiffness, float bendStiffness, float pressure); + +/** + * Destroy an asset created with NvFlexExtCreateTearingClothFromMesh() + * @param[in] asset The asset to be destroyed. + */ +NV_FLEX_API void NvFlexExtDestroyTearingCloth(NvFlexExtAsset* asset); + +/** + * Particles and vertices may need to be copied during tearing. Because the user may maintain particle data + * outside of Flex, this structure describes how to update the particle data. The application should copy each + * existing particle given by srcIndex (in the asset's particle array) to the destIndex (also in the asset's array). + */ +struct NvFlexExtTearingParticleClone +{ + int srcIndex; + int destIndex; +}; + +/** + * The mesh topology may need to be updated to reference new particles during tearing. Because the user may maintain + * mesh topology outside of Flex, this structure describes the necessary updates that should be performed on the mesh. + * The triIndex member is the index of the index to be updated, e.g.: + * a triIndex value of 4 refers to the index 1 vertex (4%3) of the index 1 triangle (4/3). This entry in the indices + * array should be updated to point to the newParticleIndex. + */ +struct NvFlexExtTearingMeshEdit +{ + int triIndex; // index into the triangle indices array to update + int newParticleIndex; // new value for the index +}; + +/** + * Perform cloth mesh tearing, this function will calculate the strain on each distance constraint and perform splits if it is + * above a certain strain threshold (i.e.: length/restLength > maxStrain). + * + * @param[in] asset The asset describing the cloth constraint network, this must be created with NvFlexExtCreateTearingClothFromMesh() + * @param[in] maxStrain The maximum allowable strain on each edge + * @param[in] maxSplits The maximum number of constraint breaks that will be performed, this controls the 'rate' of mesh tearing + * @param[in] particleCopies Pointer to an array of NvFlexExtTearingParticleClone structures that describe the particle copies that need to be performed + * @param[in] numParticleCopies Pointer to an integer that will have the number of copies performed written to it + * @param[in] maxCopies The maximum number of particle copies that will be performed, multiple particles copies may be performed in response to one split + * @param[in] triangleEdits Pointer to an array of NvFlexExtTearingMeshEdit structures that describe the topology updates that need to be performed + * @param[in] numTriangleEdits Pointer to an integer that will have the number of topology updates written to it + * @param[in] maxEdits The maximum number of index buffer edits that will be output + */ +NV_FLEX_API void NvFlexExtTearClothMesh(NvFlexExtAsset* asset, float maxStrain, int maxSplits, NvFlexExtTearingParticleClone* particleCopies, int* numParticleCopies, int maxCopies, NvFlexExtTearingMeshEdit* triangleEdits, int* numTriangleEdits, int maxEdits); + +/** + * Create a shape body asset from a closed triangle mesh. The mesh is first voxelized at a spacing specified by the radius, and particles are placed at occupied voxels. + * + * @param[in] vertices Vertices of the triangle mesh + * @param[in] numVertices The number of vertices + * @param[in] indices The triangle indices + * @param[in] numTriangleIndices The number of triangles indices (triangles*3) + * @param[in] radius The spacing used for voxelization, note that the number of voxels grows proportional to the inverse cube of radius, currently this method limits construction to resolutions < 64^3 + * @param[in] expand Particles will be moved inwards (if negative) or outwards (if positive) from the surface of the mesh according to this factor + * @return A pointer to an asset structure holding the particles and constraints + */ +NV_FLEX_API NvFlexExtAsset* NvFlexExtCreateRigidFromMesh(const float* vertices, int numVertices, const int* indices, int numTriangleIndices, float radius, float expand); + +/** +* Create a shape body asset from a closed triangle mesh. The mesh is first voxelized at a spacing specified by the radius, and particles are placed at occupied voxels. +* +* @param[in] vertices Vertices of the triangle mesh +* @param[in] numVertices The number of vertices +* @param[in] indices The triangle indices +* @param[in] numTriangleIndices The number of triangles indices (triangles*3) +* @param[in] particleSpacing The spacing to use when creating particles +* @param[in] volumeSampling Control the resolution the mesh is voxelized at in order to generate interior sampling, if the mesh is not closed then this should be set to zero and surface sampling should be used instead +* @param[in] surfaceSampling Controls how many samples are taken of the mesh surface, this is useful to ensure fine features of the mesh are represented by particles, or if the mesh is not closed +* @param[in] clusterSpacing The spacing for shape-matching clusters, should be at least the particle spacing +* @param[in] clusterRadius Controls the overall size of the clusters, this controls how much overlap the clusters have which affects how smooth the final deformation is, if parts of the body are detaching then it means the clusters are not overlapping sufficiently to form a fully connected set of clusters +* @param[in] clusterStiffness Controls the stiffness of the resulting clusters +* @param[in] linkRadius Any particles below this distance will have additional distance constraints created between them +* @param[in] linkStiffness The stiffness of distance links +* @param[in] globalStiffness If this parameter is > 0.0f, adds an additional global cluster that consists of all particles in the shape. The stiffness of this cluster is the globalStiffness. +* @return A pointer to an asset structure holding the particles and constraints +*/ +NV_FLEX_API NvFlexExtAsset* NvFlexExtCreateSoftFromMesh(const float* vertices, int numVertices, const int* indices, int numTriangleIndices, float particleSpacing, float volumeSampling, float surfaceSampling, float clusterSpacing, float clusterRadius, float clusterStiffness, float linkRadius, float linkStiffness, float globalStiffness); + +/** + * Frees all memory associated with an asset created by one of the creation methods + * param[in] asset The asset to destroy. + */ +NV_FLEX_API void NvFlexExtDestroyAsset(NvFlexExtAsset* asset); + +/** +* Creates information for linear blend skining a graphics mesh to a set of transforms (bones) +* +* @param[in] vertices Vertices of the triangle mesh +* @param[in] numVertices The number of vertices +* @param[in] bones Pointer to an array of vec3 positions representing the bone positions +* @param[in] numBones Then number of bones +* @param[in] falloff The speed at which the bone's influence on a vertex falls off with distance +* @param[in] maxDistance The maximum distance a bone can be from a vertex before it will not influence it any more +* @param[out] skinningWeights The normalized weights for each bone, there are up to 4 weights per-vertex so this should be numVertices*4 in length +* @param[out] skinningIndices The indices of each bone corresponding to the skinning weight, will be -1 if this weight is not used +*/ +NV_FLEX_API void NvFlexExtCreateSoftMeshSkinning(const float* vertices, int numVertices, const float* bones, int numBones, float falloff, float maxDistance, float* skinningWeights, int* skinningIndices); + +/** + * Creates a wrapper object around a Flex solver that can hold assets / instances, the container manages sending and retrieving partical data from the solver + * + * @param[in] lib The library instance to use + * @param[in] solver The solver to wrap + * @param[in] maxParticles The maximum number of particles to manage + * @return A pointer to the new container + */ +NV_FLEX_API NvFlexExtContainer* NvFlexExtCreateContainer(NvFlexLibrary* lib, NvFlexSolver* solver, int maxParticles); + +/** + * Frees all memory associated with a container + * + * @param[in] container The container to destroy + */ +NV_FLEX_API void NvFlexExtDestroyContainer(NvFlexExtContainer* container); + +/** + * Allocates particles in the container. + * + * @param[in] container The container to allocate out of + * @param[in] n The number of particles to allocate + * @param[out] indices An n-length array of ints that will store the indices to the allocated particles + */ +NV_FLEX_API int NvFlexExtAllocParticles(NvFlexExtContainer* container, int n, int* indices); + +/** + * Free allocated particles + * + * @param[in] container The container to free from + * @param[in] n The number of particles to free + * @param[in] indices The indices of the particles to free + */ +NV_FLEX_API void NvFlexExtFreeParticles(NvFlexExtContainer* container, int n, const int* indices); + + +/** + * Retrives the indices of all active particles + * + * @param[in] container The container to free from + * @param[out] indices Returns the number of active particles + * @return The number of active particles + */ +NV_FLEX_API int NvFlexExtGetActiveList(NvFlexExtContainer* container, int* indices); + + +struct NvFlexExtParticleData +{ + float* particles; //!< Receives a pointer to the particle position / mass data + float* restParticles; //!< Receives a pointer to the particle's rest position (used for self collision culling) + float* velocities; //!< Receives a pointer to the particle velocity data + int* phases; //!< Receives a pointer to the particle phase data + float* normals; //!< Receives a pointer to the particle normal data with 16 byte stride in format [nx, ny, nz, nw] + + const float* lower; //!< Receive a pointer to the particle lower bounds [x, y, z] + const float* upper; //!< Receive a pointer to the particle upper bounds [x, y, z] +}; + +/** + * Returns pointers to the internal data stored by the container. These are host-memory pointers, and will + * remain valid NvFlexExtUnmapParticleData() is called. + * + @param container The container whose data should be accessed + */ +NV_FLEX_API NvFlexExtParticleData NvFlexExtMapParticleData(NvFlexExtContainer* container); +NV_FLEX_API void NvFlexExtUnmapParticleData(NvFlexExtContainer* container); + +struct NvFlexExtTriangleData +{ + int* indices; //!< Receives a pointer to the array of triangle index data + float* normals; //!< Receives a pointer to an array of triangle normal data stored with 16 byte stride, i.e.: [nx, ny, nz] +}; + +/** + * Access triangle constraint data, see NvFlexExtGetParticleData() for notes on ownership. + * + * @param container The container to retrive from + */ +NV_FLEX_API NvFlexExtTriangleData NvFlexExtMapTriangleData(NvFlexExtContainer* container); + +/** + * Unmap triangle data, see NvFlexExtMapTriangleData() + */ +NV_FLEX_API void NvFlexExtUnmapTriangleData(NvFlexExtContainer* container); + +struct NvFlexExtShapeData +{ + float* rotations; //!< Receives a pointer to the array quaternion rotation data in [x, y z, w] format + float* positions; //!< Receives a pointer to an array of shape body translations in [x, y, z] format + int n; //!< Number of valid tranforms +}; + +/** + * Access shape body constraint data, see NvFlexExtGetParticleData() for notes on ownership. + * + * @param container The container to retrive from + */ +NV_FLEX_API NvFlexExtShapeData NvFlexExtMapShapeData(NvFlexExtContainer* container); + +/** + * Unmap shape transform data, see NvFlexExtMapShapeData() + */ +NV_FLEX_API void NvFlexExtUnmapShapeData(NvFlexExtContainer* container); + +/** + * Creates an instance of an asset, the container will internally store a reference to the asset so it should remain valid for the instance lifetime. This + * method will allocate particles for the asset, assign their initial positions, velocity and phase. + * + * @param[in] container The container to spawn into + * @param[in] particleData Pointer to a mapped particle data struct, returned from NvFlexExtMapParticleData() + * @param[in] asset The asset to be spawned + * @param[in] transform A pointer to a 4x4 column major, column vector transform that specifies the initial world space configuration of the particles + * @param[in] vx The velocity of the particles along the x axis + * @param[in] vy The velocity of the particles along the y axis + * @param[in] vz The velocity of the particles along the z axis + * @param[in] phase The phase used for the particles + * @param[in] invMassScale A factor applied to the per particle inverse mass + * @return A pointer to the instance of the asset + */ +NV_FLEX_API NvFlexExtInstance* NvFlexExtCreateInstance(NvFlexExtContainer* container, NvFlexExtParticleData* particleData, const NvFlexExtAsset* asset, const float* transform, float vx, float vy, float vz, int phase, float invMassScale); + +/** Destoy an instance of an asset + * + * @param[in] container The container the instance belongs to + * @param[in] instance The instance to destroy + */ +NV_FLEX_API void NvFlexExtDestroyInstance(NvFlexExtContainer* container, const NvFlexExtInstance* instance); + +/** Notifies the container that asset data has changed and needs to be sent to the GPU + * this should be called if the constrains for an existing asset are modified by the user + * + * @param[in] container The container the instance referencing the asset belongs to + * @param[in] asset The asset which was modified (can be NULL) + */ +NV_FLEX_API void NvFlexExtNotifyAssetChanged(NvFlexExtContainer* container, const NvFlexExtAsset* asset); + +/** + * Updates the container, applies force fields, steps the solver forward in time, updates the host with the results synchronously. + * This is a helper function which performs a synchronous update using the following flow. + * + \code{.c} + // async update GPU data + NvFlexExtPushToDevice(container); + + // update solver + NvFlexUpdateSolver(container, dt, iterations); + + // async read data back to CPU + NvFlexExtPullFromDevice(container); + + // read / write particle data on CPU + NvFlexExtParticleData data = NvFlexExtMapParticleData(); + + // CPU particle processing + ProcessParticles(data); + + // unmap data + NvFlexExtUnmapParticleData(); + + \endcode + @param[in] container The container to update + @param[in] dt The time-step in seconds + @param[in] numSubsteps The number of substeps to perform + @param[in] enableTimers Whether to record detailed timers, see NvFlexUpdateSolver() + */ +NV_FLEX_API void NvFlexExtTickContainer(NvFlexExtContainer* container, float dt, int numSubsteps, bool enableTimers=false); + +/** + * Updates the device asynchronously, transfers any particle and constraint changes to the flex solver, + * expected to be called in the following sequence: NvFlexExtPushToDevice, NvFlexUpdateSolver, NvFlexExtPullFromDevice, flexSynchronize + * @param[in] container The container to update + */ +NV_FLEX_API void NvFlexExtPushToDevice(NvFlexExtContainer* container); + +/** + * Updates the host asynchronously, transfers particle and constraint data back to he host, + * expected to be called in the following sequence: NvFlexExtPushToDevice, NvFlexUpdateSolver, NvFlexExtPullFromDevice + * @param[in] container The container to update + */ +NV_FLEX_API void NvFlexExtPullFromDevice(NvFlexExtContainer* container); + +/** + * Synchronizes the per-instance data with the container's data, should be called after the synchronization with the solver read backs are complete + * + * @param[in] container The instances belonging to this container will be updated + */ +NV_FLEX_API void NvFlexExtUpdateInstances(NvFlexExtContainer* container); + + +/** + * Controls the way that force fields affect particles + */ +enum NvFlexExtForceMode +{ + //! Apply field value as a force. + eNvFlexExtModeForce = 0, + + //! Apply field value as an impulse. + eNvFlexExtModeImpulse = 1, + + //! Apply field value as a velocity change. + eNvFlexExtModeVelocityChange = 2, +}; + +/** + * Force field data, currently just supports radial fields + */ +struct NvFlexExtForceField +{ + float mPosition[3]; //!< Center of force field + float mRadius; //!< Radius of the force field + float mStrength; //!< Strength of the force field + NvFlexExtForceMode mMode; //!< Mode of field application + bool mLinearFalloff; //!< Linear or no falloff +}; + +/** + * Opaque type representing a force field callback structure that ecapsulates + * the force field kernels and associated data applied as a callback during the Flex update + */ +typedef struct NvFlexExtForceFieldCallback NvFlexExtForceFieldCallback; + +/** + * Create a NvFlexExtForceFieldCallback structure, each callback is associated with the + * passed in solver once the NvFlexExtSetForceFields() is called. + * + * @param[in] solver A valid solver created with NvFlexCreateSolver() + * @return A pointer to a callback structure + */ +NV_FLEX_API NvFlexExtForceFieldCallback* NvFlexExtCreateForceFieldCallback(NvFlexSolver* solver); + +/** + * Destroy the force field callback + * + * @param[in] callback A valid solver created with NvFlexExtCreateForceFieldCallback() + */ +NV_FLEX_API void NvFlexExtDestroyForceFieldCallback(NvFlexExtForceFieldCallback* callback); + +/** + * Set force fields on the container, these will be applied during the Flex update + * + * @param[in] callback The callback to update + * @param[in] forceFields A pointer to an array of force field data, may be host or GPU memory + * @param[in] numForceFields The number of force fields to send to the device + */ +NV_FLEX_API void NvFlexExtSetForceFields(NvFlexExtForceFieldCallback* callback, const NvFlexExtForceField* forceFields, int numForceFields); + + + +} // extern "C" + +#endif // NV_FLEX_EXT_H + |