// This code contains NVIDIA Confidential Information and is disclosed to you // under a form of NVIDIA software license agreement provided separately to you. // // Notice // NVIDIA Corporation and its licensors retain all intellectual property and // proprietary rights in and to this software and related documentation and // any modifications thereto. Any use, reproduction, disclosure, or // distribution of this software and related documentation without an express // license agreement from NVIDIA Corporation is strictly prohibited. // // ALL NVIDIA DESIGN SPECIFICATIONS, CODE ARE PROVIDED "AS IS.". NVIDIA MAKES // NO WARRANTIES, EXPRESSED, IMPLIED, STATUTORY, OR OTHERWISE WITH RESPECT TO // THE MATERIALS, AND EXPRESSLY DISCLAIMS ALL IMPLIED WARRANTIES OF NONINFRINGEMENT, // MERCHANTABILITY, AND FITNESS FOR A PARTICULAR PURPOSE. // // Information and code furnished is believed to be accurate and reliable. // However, NVIDIA Corporation assumes no responsibility for the consequences of use of such // information or for any infringement of patents or other rights of third parties that may // result from its use. No license is granted by implication or otherwise under any patent // or patent rights of NVIDIA Corporation. Details are subject to change without notice. // This code supersedes and replaces all information previously supplied. // NVIDIA Corporation products are not authorized for use as critical // components in life support devices or systems without express written approval of // NVIDIA Corporation. // // Copyright (c) 2016-2018 NVIDIA Corporation. All rights reserved. #ifndef NVBLASTEXTSTRESSSOLVER_H #define NVBLASTEXTSTRESSSOLVER_H #include "NvBlastTypes.h" #include "NvCTypes.h" namespace Nv { namespace Blast { /** Stress Solver Settings Stress on every bond is calculated as stress = (bond.linearStress * stressLinearFactor + bond.angularStress * stressAngularFactor) / hardness; where: bond.linearStress = the linear stress force on particular bond bond.angularStress = the angular stress force on particular bond stressLinearFactor, stressAngularFactor, hardness = multiplier parameters set by this struct Support graph reduction: graphReductionLevel is the number of node merge passes. The resulting graph will be roughly 2^graphReductionLevel times smaller than the original. */ struct ExtStressSolverSettings { float hardness; //!< hardness of bond's material float stressLinearFactor; //!< linear stress on bond multiplier float stressAngularFactor; //!< angular stress on bond multiplier uint32_t bondIterationsPerFrame; //!< number of bond iterations to perform per frame, @see getIterationsPerFrame() below uint32_t graphReductionLevel; //!< graph reduction level ExtStressSolverSettings() : hardness(1000.0f), stressLinearFactor(0.25f), stressAngularFactor(0.75f), bondIterationsPerFrame(18000), graphReductionLevel(3) {} }; /** Parameter to addForce() calls, determines the exact operation that is carried out. @see ExtStressSolver.addForce() */ struct ExtForceMode { enum Enum { IMPULSE, //!< parameter has unit of mass * distance /time VELOCITY, //!< parameter has unit of distance / time, i.e. the effect is mass independent: a velocity change. }; }; /** Stress Solver. Uses NvBlastFamily, allocates and prepares its graph once when it's created. Then it's being quickly updated on every actor split. It uses NvBlastAsset support graph, you can apply forces on nodes and stress on bonds will be calculated as the result. When stress on bond exceeds it's health bond is considered broken (overstressed). Basic usage: 1. Create it with create function once for family 2. Fill node info for every node in support graph or use setAllNodesInfoFromLL() function. 3. Use notifyActorCreated / notifyActorDestroyed whenever actors are created and destroyed in family. 4. Every frame: Apply forces (there are different functions for it see @addForce) 5. Every frame: Call update() for actual solver to process. 6. If getOverstressedBondCount() > 0 use generateFractureCommands() functions to get FractureCommands with bonds fractured */ class NV_DLL_EXPORT ExtStressSolver { public: //////// creation //////// /** Create a new ExtStressSolver. \param[in] family The ExtPxFamily instance to calculate stress on. \param[in] settings The settings to be set on ExtStressSolver. \return the new ExtStressSolver if successful, NULL otherwise. */ static ExtStressSolver* create(NvBlastFamily& family, ExtStressSolverSettings settings = ExtStressSolverSettings()); //////// interface //////// /** Release this stress solver. */ virtual void release() = 0; /** Set node info. All the required info per node for stress solver is set with this function. Call it for every node in graph or use setAllNodesInfoFromLL(). \param[in] graphNodeIndex Index of the node in support graph. see NvBlastSupportGraph. \param[in] mass Node mass. For static node it is irrelevant. \param[in] volume Node volume. For static node it is irrelevant. \param[in] localPosition Node local position. \param[in] isStatic Is node static. */ virtual void setNodeInfo(uint32_t graphNodeIndex, float mass, float volume, NvcVec3 localPosition, bool isStatic) = 0; /** Set all nodes info using low level NvBlastAsset data. Uses NvBlastChunk's centroid and volume. Uses 'world' node to mark nodes as static. \param[in] density Density. Used to convert volume to mass. */ virtual void setAllNodesInfoFromLL(float density = 1.0f) = 0; /** Set stress solver settings. Changing graph reduction level will lead to graph being rebuilt (which is fast, but still not recommended). All other settings are applied instantly and can be changed every frame. \param[in] settings The settings to be set on ExtStressSolver. */ virtual void setSettings(const ExtStressSolverSettings& settings) = 0; /** Get stress solver settings. \return the pointer to stress solver settings currently set. */ virtual const ExtStressSolverSettings& getSettings() const = 0; /** Notify stress solver on newly created actor. Call this function for all initial actors present in family and later upon every actor split. \param[in] actor The actor created. \return true if actor will take part in stress solver process. false if actor doesn't contain any bonds. */ virtual bool notifyActorCreated(const NvBlastActor& actor) = 0; /** Notify stress solver on destroyed actor. Call this function when actor is destroyed (split futher) or deactivated. \param[in] actor The actor destroyed. */ virtual void notifyActorDestroyed(const NvBlastActor& actor) = 0; /** Apply external impulse on particular actor of family. This function will find nearest actor's graph node to apply impulse on. \param[in] actor The actor to apply impulse on. \param[in] localPosition Local position in actor's coordinates to apply impulse on. \param[in] localForce Force to apply in local actor's coordinates. \param[in] mode The mode to use when applying the force/impulse(see #ExtForceMode) \return true iff node was found and force applied. */ virtual bool addForce(const NvBlastActor& actor, NvcVec3 localPosition, NvcVec3 localForce, ExtForceMode::Enum mode = ExtForceMode::IMPULSE) = 0; /** Apply external impulse on particular node. \param[in] graphNodeIndex The graph node index to apply impulse on. See #NvBlastSupportGraph. \param[in] localForce Force to apply in local actor's coordinates. \param[in] mode The mode to use when applying the force/impulse(see #ExtForceMode) */ virtual void addForce(uint32_t graphNodeIndex, NvcVec3 localForce, ExtForceMode::Enum mode = ExtForceMode::IMPULSE) = 0; /** Apply external gravity on particular actor of family. This function applies gravity on every node withing actor, so it makes sense only for static actors. \param[in] actor The actor to apply impulse on. \param[in] localGravity Gravity to apply in local actor's coordinates. ExtForceMode::VELOCITY is used. \return true iff force was applied on at least one node. */ virtual bool addGravityForce(const NvBlastActor& actor, NvcVec3 localGravity) = 0; /** Apply centrifugal force produced by actor's angular movement. \param[in] actor The actor to apply impulse on. \param[in] localCenterMass Actor's local center of mass. \param[in] localAngularVelocity Local angular velocity of an actor. \return true iff force was applied on at least one node. */ virtual bool addAngularVelocity(const NvBlastActor& actor, NvcVec3 localCenterMass, NvcVec3 localAngularVelocity) = 0; /** Update stress solver. Actual performance heavy stress calculation happens there. Call it after all relevant forces were applied, usually every frame. */ virtual void update() = 0; /** Get overstressed/broken bonds count. This count is updated after every update() call. Number of overstressed bond directly hints if any bond fracture is recommended by stress solver. \return the overstressed bonds count. */ virtual uint32_t getOverstressedBondCount() const = 0; /** Generate fracture commands for particular actor. Calling this function if getOverstressedBondCount() == 0 or actor has no bond doesn't make sense, bondFractureCount will be '0'. Filled fracture commands buffer can be passed directly to NvBlastActorApplyFracture. IMPORTANT: NvBlastFractureBuffers::bondFractures will point to internal stress solver memory which will be valid till next call of any of generateFractureCommands() functions or stress solver release() call. \param[in] actor The actor to fill fracture commands for. \param[in] commands Pointer to command buffer to fill. */ virtual void generateFractureCommands(const NvBlastActor& actor, NvBlastFractureBuffers& commands) = 0; /** Generate fracture commands for whole family. A bit faster way to get all fractured bonds than calling generateFractureCommands() for every actor. Calling this function if getOverstressedBondCount() == 0 or actor has no bond doesn't make sense, bondFractureCount will be '0'. IMPORTANT: NvBlastFractureBuffers::bondFractures will point to internal stress solver memory which will be valid till next call of any of generateFractureCommands() functions or stress solver release() call. \param[in] commands Pointer to command buffer to fill. */ virtual void generateFractureCommands(NvBlastFractureBuffers& commands) = 0; /** Generate fracture commands for every actor in family. Actors and commands buffer must be passed in order to be filled. It's recommended for bufferSize to be the count of actor with more then one bond in family. Calling this function if getOverstressedBondCount() == 0 or actor has no bond doesn't make sense, '0' will be returned. IMPORTANT: NvBlastFractureBuffers::bondFractures will point to internal stress solver memory which will be valid till next call of any of generateFractureCommands() functions or stress solver release() call. \param[out] buffer A user-supplied array of NvBlastActor pointers to fill. \param[out] commandsBuffer A user-supplied array of NvBlastFractureBuffers to fill. \param[in] bufferSize The number of elements available to write into buffer. \return the number of actors and command buffers written to the buffer. */ virtual uint32_t generateFractureCommandsPerActor(const NvBlastActor** actorBuffer, NvBlastFractureBuffers* commandsBuffer, uint32_t bufferSize) = 0; /** Reset stress solver. Stress solver uses warm start internally, calling this function will flush all previous data calculated and also zeros frame count. This function is to be used for debug purposes. */ virtual void reset() = 0; /** Get stress solver linear error. \return the total linear error of stress calculation. */ virtual float getStressErrorLinear() const = 0; /** Get stress solver angular error. \return the total angular error of stress calculation. */ virtual float getStressErrorAngular() const = 0; /** Get stress solver total frames count (update() calls) since it was created (or reset). \return the frames count. */ virtual uint32_t getFrameCount() const = 0; /** Get stress solver bonds count, after graph reduction was applied. \return the bonds count. */ virtual uint32_t getBondCount() const = 0; /** Debug Render Mode */ enum DebugRenderMode { STRESS_GRAPH = 0, //!< render only stress graph STRESS_GRAPH_NODES_IMPULSES = 1, //!< render stress graph + nodes impulses after solving stress STRESS_GRAPH_BONDS_IMPULSES = 2 //!< render stress graph + bonds impulses after solving stress }; /** Used to store a single line and colour for debug rendering. */ struct DebugLine { DebugLine(const NvcVec3& p0, const NvcVec3& p1, const uint32_t& c) : pos0(p0), color0(c), pos1(p1), color1(c) {} NvcVec3 pos0; uint32_t color0; NvcVec3 pos1; uint32_t color1; }; /** Debug Buffer */ struct DebugBuffer { const DebugLine* lines; uint32_t lineCount; }; /** Fill debug render for passed array of support graph nodes. NOTE: Returned DebugBuffer points into internal memory which is valid till next fillDebugRender() call. \param[in] nodes Node indices of support graph to debug render for. \param[in] nodeCount Node indices count. \param[in] mode Debug render mode. \param[in] scale Scale to be applied on impulses. \return debug buffer with array of lines */ virtual const DebugBuffer fillDebugRender(const uint32_t* nodes, uint32_t nodeCount, DebugRenderMode mode, float scale = 1.0f) = 0; //////// helpers //////// /** Get solver iteration per frame (update() call) for particular settings and bondCount. Helper method to know how many solver iterations are made per frame. This function made so transparent to make it clear how ExtStressSolverSettings::bondIterationsPerFrame is used. \param[in] settings Debug render mode. \param[in] bondCount Scale to be applied on impulses. \return the iterations per frame count. */ static uint32_t getIterationsPerFrame(const ExtStressSolverSettings& settings, uint32_t bondCount) { uint32_t perFrame = settings.bondIterationsPerFrame / (bondCount + 1); return perFrame > 0 ? perFrame : 1; } /** Get iteration per frame (update() call). Helper method to know how many solver iterations are made per frame. \return the iterations per frame count. */ uint32_t getIterationsPerFrame() const { return getIterationsPerFrame(getSettings(), getBondCount()); } }; } // namespace Blast } // namespace Nv #endif // ifndef NVBLASTEXTSTRESSSOLVER_H