aboutsummaryrefslogtreecommitdiff
path: root/sdk/extensions/stress/include/NvBlastExtStressSolver.h
blob: ef1325988e9073ae8a315f0ea2ac366c739dcc95 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
// 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