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
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
|
<html>
<head>
<title>NVIDIA(R) Blast(R) SDK 1.1 API Reference: High Level (Toolkit) API (NvBlastTk)</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<LINK HREF="NVIDIA.css" REL="stylesheet" TYPE="text/css">
</head>
<body bgcolor="#FFFFFF">
<div id="header">
<hr class="first">
<img alt="" src="blast_logo.png">
<br>
<center>
<a class="qindex" href="main.html">Main Page</a>
<!-- <a class="qindex" href="hierarchy.html">Class Hierarchy</a> //-->
<a class="qindex" href="annotated.html">Class List</a>
<a class="qindex" href="functions.html">Class Members</a>
</center>
<hr class="second">
</div>
<!-- Generated by Doxygen 1.5.8 -->
<div class="contents">
<h1><a class="anchor" name="pagehlapi">High Level (Toolkit) API (NvBlastTk) </a></h1><b>Table of Contents</b><p>
<a class="el" href="pagehlapi.html#tkintroduction">Introduction to NvBlastTk</a><p>
<a class="el" href="pagehlapi.html#tk_class_hierarchy">NvBlastTk Class Hierarchy</a><p>
<a class="el" href="pagehlapi.html#tk_include_and_library">Linking and Header Files</a><p>
<a class="el" href="pagehlapi.html#framework_init">Creating the TkFramework</a><p>
<a class="el" href="pagehlapi.html#tkasset_creation">Creating a TkAsset</a><p>
<a class="el" href="pagehlapi.html#tkasset_instancing">Instancing a TkAsset: Creation of a TkActor and a TkFamily</a><p>
<a class="el" href="pagehlapi.html#tkgroups">Groups</a><p>
<a class="el" href="pagehlapi.html#damage_in_tk">Applying Damage to Actors and Families</a><p>
<a class="el" href="pagehlapi.html#tkjoints">Joints</a><p>
<a class="el" href="pagehlapi.html#tkevents">Events</a><p>
<a class="el" href="pagehlapi.html#tktypes">Object and Type Identification</a><p>
<br>
<h2><a class="anchor" name="tkintroduction">
Introduction to NvBlastTk</a></h2>
The high-level API, NvBlastTk (Tk stands for "toolkit"), is intended to be a more powerful library and a much more convenient entry point into the use of Blast™. Like the low-level library, Tk is physics and graphics-agnostic. Whereas the low-level API is C-style, Tk uses a C++ API. Everything in Tk is in the namespace:<p>
<div class="fragment"><pre class="fragment">Nv::Blast
</pre></div><p>
(the only exceptions are global-scope functions to create and access a framework singleton, see below). Every object in Tk is prefixed with 'Tk'. For example, the Tk framework interface is:<p>
<div class="fragment"><pre class="fragment"><a class="code" href="class_nv_1_1_blast_1_1_tk_framework.html">Nv::Blast::TkFramework</a>
</pre></div><p>
<b> For the remainder of this page we will be in the <a class="el" href="namespace_nv_1_1_blast.html">Nv::Blast</a> namespace, and will drop the explicit scope <a class="el" href="namespace_nv_1_1_blast.html">Nv::Blast</a>:: from our names. </b> <br>
<br>
<p>
BlastTk adds:<p>
<ul>
<li>An object class hierarchy (see <a class="el" href="pagehlapi.html#tk_class_hierarchy">NvBlastTk Class Hierarchy</a>, below).</li><li>A global framework, <b>TkFramework</b> (a singleton). This keeps track of <b>TkIdentifiable</b> objects and allows the user to query them based upon either GUID or <b>TkIdentifiable</b> subclass type, and also provides a number of functions to create the various objects in BlastTk.</li><li>Processing groups with a task interface (see <b>TkGroup</b>).</li><li>Event dispatching for actor families (see <b>TkFamily</b>).</li><li>Intra-actor and inter-actor joint management (see <b>TkJoint</b>). Note, these "joints" only hold descriptor data, since physical objects are not handled by BlastTk.</li></ul>
<p>
<br>
<h2><a class="anchor" name="tk_class_hierarchy">
NvBlastTk Class Hierarchy</a></h2>
<ul>
<li>There are two abstract interfaces, one of which deriving from the other: <b>TkObject <- TkIdentifiable</b>.<ul>
<li>Lightweight objects are derived from <b>TkObject</b>.</li><li>Objects which use a GUID and class identification are derieved from <b>TkIdentifiable</b>.</li></ul>
</li><li><b>TkAsset</b> derives from <b>TkIdentifiable</b>. This is mostly a wrapper for <a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a>, however it also stores extra data associated with the asset such as internal joint descriptors.</li><li><b>TkFamily</b> derives from <b>TkIdentifiable</b>. One of these objects is made when a <b>TkActor</b> is instanced from a <b>TkAsset</b>. All actors that are created by splitting the family's original actor remain within the same family. Actor and joint events are dispatched from the <b>TkFamily</b>.</li><li><b>TkGroup</b> derives from <b>TkIdentifiable</b>. Groups are processing units. The user may create as many groups as they please, and add or remove actors as they please from groups. The group provides a worker (TkGroupWorker) interface which allows the user to process multiple jobs in the group asynchoronously. These jobs, along with a call to TkGroup::endProcess(), perform the tasks of generating fracture commands, applying fracture commands, and actor splitting at the low-level. The user is informed of splitting through listeners given to TkFamily objects.</li><li><b>TkActor</b> derives from <b>TkObject</b>. It is mostly a wrapper for <a class="el" href="struct_nv_blast_actor.html">NvBlastActor</a>, but it also provides a number of damage functions to the user.</li><li><b>TkJoint</b> derives from <b>TkObject</b>. <b>TkAsset</b> descriptors, cause internal <b>TkJoint</b> obejcts to be created within an actor (joining chunks within the same actor). Alternatively, the TkFramework provides a function which allows the user to create an external joint between any two different actors. As actors split, internal joints may become external. The user gets notification whenever joints become external, or when actors joined by joints change or are deleted, through listeners attached to the associated TkFamily objects.</li></ul>
<p>
<br>
<h2><a class="anchor" name="tk_include_and_library">
Linking and Header Files</a></h2>
To use the BlastTk library, the application need only inlclude the header <a class="el" href="_nv_blast_tk_8h.html">NvBlastTk.h</a>, found in the <b>include/toolkit</b> folder, and link against the appropriate version of the NvBlastTk library. Depending on the platform and configuration, various suffixes will be added to the library name. The general naming scheme is<p>
NvBlastTk(config)(arch).(ext)<p>
(config) is DEBUG, CHECKED, OR PROFILE for the corresponding configurations. For a release configuration there is no (config) suffix.<p>
(arch) is _x86 or _x64 for Windows 32- and 64-bit builds, respectively, and empty for non-Windows platforms.<p>
(ext) is .lib for static linking and .dll for dynamic linking on Windows. On XBoxOne it is .lib, and on PS4 it is .a.<p>
<br>
<h2><a class="anchor" name="framework_init">
Creating the TkFramework</a></h2>
As a reminder, in this document we assume we are in the <a class="el" href="namespace_nv_1_1_blast.html">Nv::Blast</a> namespace:<p>
<div class="fragment"><pre class="fragment"><span class="keyword">using namespace </span>Nv::Blast;
</pre></div><p>
In order to use NvBlastTk, one first has to create a TkFramework singleton. This simply requires a call to the global function NvBlastTkFrameworkCreate:<p>
<div class="fragment"><pre class="fragment">TkFramework* framework = <a class="code" href="_nv_blast_tk_framework_8h.html#bffad36b5cbe769ac6d119bfb58d3523">NvBlastTkFrameworkCreate</a>();
</pre></div><p>
The framework may be accessed via:<p>
<div class="fragment"><pre class="fragment">TkFramework* framework = <a class="code" href="_nv_blast_tk_framework_8h.html#c9ef4ab9d817890d7a0f456cc6f07907">NvBlastTkFrameworkGet</a>();
</pre></div><p>
In the sections that follow, it is assumed that a framework has been created, and we have a pointer to it named 'framework' within scope.<p>
Finally, to release the framework, use<p>
<div class="fragment"><pre class="fragment">framework->release();
</pre></div><p>
This will release all assets, families, actors, joints, and groups.<p>
<br>
<h2><a class="anchor" name="tkasset_creation">
Creating a TkAsset</a></h2>
The TkAsset object is a high-level wrapper for the low-level <a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a> (see <a class="el" href="pagellapi.html#assets">Creating an Asset from a Descriptor (Authoring)</a>). The descriptor used to create a TkAsset, a TkAssetDesc, is derived from <a class="el" href="struct_nv_blast_asset_desc.html">NvBlastAssetDesc</a>. The base fields should be filled in as described in (<a class="el" href="pagellapi.html#assets">Creating an Asset from a Descriptor (Authoring)</a>). The new field is an optional array of flags to be associated with each bond in the base descriptor. Currently the only flag is "BondJointed," and if set will cause an "internal joint" to be created in actors (TkActor type) created from the asset. See (<a class="el" href="pagehlapi.html#tkjoints">Joints</a>) for more on joints in BlastTk.<p>
<div class="fragment"><pre class="fragment">TkAssetDesc desc;
myFunctionToFillInLowLevelAssetFields(desc); <span class="comment">// Fill in the low-level (NvBlastAssetDesc) fields as usual</span>
std::vector<uint8_t*> bondFlags(desc.bondCount, 0); <span class="comment">// Clear all flags</span>
<span class="comment">// Set BondJointed flags corresponding to joints selected by the user (assumes a myBondIsJointedFunction to make this selection)</span>
<span class="keywordflow">for</span> (uint32_t i = 0; i < desc.bondCount; ++i)
{
<span class="keywordflow">if</span> (myBondIsJointedFunction(i)) <span class="comment">// User-authored</span>
{
bondFlags[i] |= TkAssetDesc::BondJointed;
}
}
TkAsset* asset = framework->createAsset(desc); <span class="comment">// Create a new TkAsset</span>
</pre></div><p>
The createAsset function used above creates a low-level <a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a> from the base fields of the descriptor, and then adds internal joint descriptors based upon the bonds' centroids and attached chunks. An alternative method to create a TkAsset allows the user to pass in a pre-existing <a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a>, and a list of joint descriptors. If the TkAsset is to have no internal joints, then the joint descriptors are not necessary and with an <a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a> pointer <b>llAsset</b>, a TkAsset may be created simply by using<p>
<div class="fragment"><pre class="fragment">TkAsset* asset = framework->createAsset(llAsset);
</pre></div><p>
By default, such a TkAsset will not "own" the llAsset. When the TkAsset is released, the llAsset memory will be untouched. You can pass ownership to the TkAsset using all of the default parameters of the createAsset function:<p>
<div class="fragment"><pre class="fragment">TkAsset* asset = framework->createAsset(llAsset, <span class="keyword">nullptr</span>, 0, <span class="keyword">true</span>);
</pre></div><p>
The last parameter sets ownership. N.B.: in order for the TkAsset to own the underlying llAsset, and therefore release it when the TkAsset is released, the memory for the llAsset must be allocated using the allocator accessed through NvBlastGlobals (see <a class="el" href="pageglobalsapi.html">Globals API (NvBlastGlobals)</a>).<p>
If one wants to author internal joints in a TkAsset using this second createAsset method, one must pass in a valid array of joint descriptors of type TkAssetJointDesc. Each joint descriptor takes two positions and two node indices. The positions are the joint's attachment positions in asset space, and the nodes indices are those of the graph nodes that correspond to support chunks. These indices are not, in general, the same as the chunk indices. An example of initialization of the joint descriptors is given below.<p>
<div class="fragment"><pre class="fragment">std::vector<TkAssetJointDesc> jointDescs(jointCount); <span class="comment">// Assume jointCount = the number of joints to add</span>
jointDescs[0].nodeIndices[0] = 0; <span class="comment">// Attach node 0 to node 1</span>
jointDescs[0].nodeIndices[1] = 1;
jointDescs[0].attachPoistions[0] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); <span class="comment">// Attachment positions are often the same within an asset, but they don't have to be</span>
jointDescs[0].attachPoistions[1] = physx::PxVec3( 1.0f, 2.0f, 3.0f );
<span class="comment">// ... etc.</span>
TkAsset* asset = framework->createAsset(llAsset, jointDescs.data(), jointDescs.size());
</pre></div><p>
The code above assumes you know the support graph nodes to which you'd like to attach joints. Often, the user only knows the corresponding chunk indices. Fortunately it's easy to map chunk indices to graph node indices. In order to get the map, use the low-level function<p>
<div class="fragment"><pre class="fragment"><span class="keyword">const</span> uint32_t map = <a class="code" href="_nv_blast_8h.html#bff733fd05dc5b7a730336699a427c25">NvBlastAssetGetChunkToGraphNodeMap</a>(llAsset, logFn);
</pre></div><p>
This map is an array with an entry for every chunk index. To get the graph node index for a chunk indexed <b>chunkIndex</b>, use<p>
<div class="fragment"><pre class="fragment">uint32_t nodeIndex = map[chunkIndex];
</pre></div><p>
If the chunk indexed by <b>chunkIndex</b> does <em>not</em> correspond to a support chunk, then the mapped value will be UINT32_MAX, the invalid index. Otherwise, the mapped value will be a valid graph node index.<p>
Finally, to release a TkAsset, as with any TkObject-derived object, use the release() method:<p>
<div class="fragment"><pre class="fragment">asset->release();
</pre></div><p>
<br>
<h2><a class="anchor" name="tkasset_instancing">
Instancing a TkAsset: Creation of a TkActor and a TkFamily</a></h2>
Whereas with the Blast™ low-level (<a class="el" href="pagellapi.html">Low Level API (NvBlast)</a>), one must explicitly create a family (<a class="el" href="struct_nv_blast_family.html">NvBlastFamily</a>) from an asset (<a class="el" href="struct_nv_blast_asset.html">NvBlastAsset</a>) before creating the first actor (<a class="el" href="struct_nv_blast_actor.html">NvBlastActor</a>) in the family, NvBlastTk creates a TkFamily automatically when an unfractured TkActor is instanced from a TkAsset using the framework's createActor function. This family is accessible through the actor and any actor that is created from splitting it. The family is <em>not</em> released automatically when all actors within it have been released. The user must use the TkFamily's release() method (see TkObject base API) to do so. (Or wait until the framework is released.) If a family is released that contains actors, the actors within will be released as well.<p>
The TkFamily has a special role in NvBlastTk, holding user-supplied event listeners (TkEventListener). All <em>internal</em> actor creation and destruction events are broadcast to listeners through split events (TkSplitEvent). These signal when a fracturing operation has destroyed an actor and created child actors from it. TkActor creation or release that occurs from an explicit API call do not produce events. For example when creating a first unfractured instance of an asset using createAsset, or when calling the release() method on a TkActor. TkJoint events are similarly broadcast to receivers (TkJointEvent). These signal when the actors which are joined by the joints change, so that the user may update a corresponding physical joint. They also signal when a joint no longer attaches actors and is therefore unreferenced. The user may invalidate or release the joint using the TkObject release() method when this occurs (more on joint ownership in <a class="el" href="pagehlapi.html#tkjoints">Joints</a>).<p>
To create an unfractured TkActor instance from a TkAsset, one first fills in a descriptor (TkActorDesc) and passes it to the framework's createActor function. As with the TkAssetDesc, the TkActorDesc is derived from its low-level counterpart, the <a class="el" href="struct_nv_blast_actor_desc.html">NvBlastActorDesc</a>. In addition the TkActorDesc holds a pointer to the TkAsset being instanced. An example of TkActor creation is given below, given a TkAsset pointer <b>asset</b>.<p>
<div class="fragment"><pre class="fragment">TkActorDesc desc; <span class="comment">// The TkActorDesc constructor sets sane default values for the base (NvBlastActorDesc) fields, giving uniform chunk and bond healths of 1.0.</span>
desc.asset = asset; <span class="comment">// This field of TkActorDesc must be set to a valid asset pointer.</span>
TkActor* actor = framework->createActor(desc);
</pre></div><p>
The TkFamily created with the actor above may be accessed through the actor's getFamily field:<p>
<div class="fragment"><pre class="fragment">TkFamily& family = actor->getFamily();
</pre></div><p>
The returned value is a reference since a TkActor's family can never be NULL. Actors resulting from the split of a "parent" actor will always belong to the parent's family.<p>
For most applications, the user will need to create a listener object to pass to every family created, in order to keep their physics and graphics representations in sync with the splitting of the TkActor. For more on this, see <a class="el" href="pagehlapi.html#tkevents">Events</a>.<p>
<br>
<h2><a class="anchor" name="tkgroups">
Groups</a></h2>
One important feature of NvBlastTk is the ability to multitask damage processing. The mechanism by which the toolkit does this is the group object, TkGroup. Groups are created at the request of the user; the user may create as many groups as he or she likes. Actors may be added or removed from groups in any way the user wishes, with the only constraint being that a given actor may belong to no more than one group. A group is a processing object, much like a scene in a physics simulation. Indeed, a natural pattern would be to associate one group per physics scene, and synchronize the group processing with scene simulation. Another pattern would be to subdivide the world into neighborhoods, and associate each neighborhood with a group. A distributed game could take advantage of this structure to similarly distribute computation.<p>
Group processing is performed by <em>workers</em>, which have a TkGroupWorker API exposed to the user. The number of workers may be set by the user, with the idea being that this should correspond to the number of threads available for group processing. Processing starts with a call to TkGroup::startProcess(). This creates a number of jobs which the user may assign to workers as they like, each worker potentially on its own thread. The jobs calculate the effects of all damage taken by the group's actors. After all jobs have been run, the user must call TkGroup::endProcess(). This will result in all events being fired off to listeners associated with families with actors in the group.<p>
A convenience function, TkGroup::process(), is provided which uses one worker to perform all jobs sequentially on the calling thread. This is useful shortcut to get BlastTk up and running quickly. A multithreaded group processing implementation is given by <a class="el" href="class_nv_1_1_blast_1_1_ext_group_task_manager.html">Nv::Blast::ExtGroupTaskManager</a> (in <a class="el" href="_nv_blast_ext_px_task_8h.html">NvBlastExtPxTask.h</a>). This resides in <a class="el" href="pageextphysx.html">PhysX™ Extensions (NvBlastExtPhysX)</a>, because it uses physx::PxTask.<p>
Actors resulting from the split of a "parent" actor will be placed automatically into the group that the parent belonged to. This is similar to the assigment of families from a split, except that unlike families, the user then has the option to move the new actors to other groups, or no group at all.<p>
Also similar to families, groups are not automatically released when the last actor is removed from it. Unlike families, when a group is released, the actors which belong to the group are <em>not</em> released. They will, however, be removed from the group before the release is complete.<p>
A typical usage is outlined below. See <a class="el" href="pagehlapi.html#damage_in_tk">Applying Damage to Actors and Families</a> for methods of applying damage to actors.<p>
<div class="fragment"><pre class="fragment"><span class="comment">// Create actors from descriptors desc1, desc2, ... etc., and attach a listener to each new family created</span>
TkActor* actor1 = framework->createActor(desc1);
actor1->getFamily().addListener(gMyReceiver); <span class="comment">// gMyReceiver is a TkEventListener-derived object. More on events in a subsequent section.</span>
TkActor* actor2 = framework->createActor(desc2);
actor2->getFamily().addListener(gMyReceiver);
TkActor* actor3 = framework->createActor(desc3);
actor3->getFamily().addListener(gMyReceiver);
<span class="comment">// etc...</span>
<span class="comment">// Let's create two groups. First, create a group descriptor. This may be used to create both groups.</span>
TkGroupDesc groupDesc;
groupDesc.workerCount = 1; <span class="comment">// this example processes groups on the calling thread only</span>
<span class="comment">// Now create the groups</span>
TkGroup* group1 = framework->createGroup(groupDesc);
TkGroup* group2 = framework->createGroup(groupDesc);
<span class="comment">// Add actor1 and actor2 to group1, and actor2 to group3...</span>
group1->addActor(actor1);
group1->addActor(actor2);
group2->addActor(actor3);
<span class="comment">// etc...</span>
<span class="comment">// Now apply damage to all actors - *NOTE* damage is described in detail in the next section.</span>
<span class="comment">// For now we will just assume a "myDamageFunction" to apply the damage.</span>
myDamageFunction(actor1);
myDamageFunction(actor2);
myDamageFunction(actor3);
<span class="comment">// etc...</span>
<span class="comment">// Calling the groups' process functions will (synchronously) run all jobs to process damage taken by the contained actors.</span>
group1->process();
group2->process();
<span class="comment">// When the groups are no longer needed, they may be released with the usual release method.</span>
group1->release();
group2->release();
</pre></div><p>
<br>
<b>Multithreaded processing</b><p>
When distributing the jobs as mentioned above, every job must be processed exactly once (over all user tasks).<p>
The number of jobs processed per worker can range from a single job (resulting in a user task per job) to all jobs (like <a class="el" href="class_nv_1_1_blast_1_1_tk_group.html#e207854ae3e30047c6347f9fd3e7a3b9">Nv::Blast::TkGroup::process()</a> does).<p>
At any point in time, no more than the set workerCount amount of workers may have been acquired. Return the worker at the end of each task.<p>
<div class="fragment"><pre class="fragment"><a class="code" href="class_nv_1_1_blast_1_1_tk_group_worker.html">Nv::Blast::TkGroupWorker</a>* worker = group->acquireWorker();
<span class="comment">// process some jobs</span>
group->returnWorker(worker);
</pre></div><p>
<br>
<h2><a class="anchor" name="damage_in_tk">
Applying Damage to Actors and Families</a></h2>
Damage in NvBlastTk uses the same damage program scheme as the low-level SDK (see <a class="el" href="pagellapi.html#splitting">Damage and Fracturing</a>). One passes the program (<a class="el" href="struct_nv_blast_damage_program.html">NvBlastDamageProgram</a>), damage descriptor (program-dependent), and material (also program-dependent) to a TkActor::damage function. Ultimately, the damage descriptor and material data are all parameters used by the damage program. The distinction is that the damage descriptor should describe properties of the thing doing the damage, while the material should describe properties of the actor (the thing being damaged). The interpretation of this data is entirely up to the program's functions, however.<p>
For convenience, the user may set a default material in the actor's family. This assumes, of course, that the material parameters for this default are compatible with the program being used to damage the family's actors.<p>
Examples of the three TkActor damage methods are given below.<p>
<br>
<h3><a class="anchor" name="multiple_damage">
Multiple Damage Descriptors using NvBlastProgramParams</a></h3>
<b>N.B. - with this method of damage, the lifetime of the NvBlastProgramParams <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b><p>
<div class="fragment"><pre class="fragment"><a class="code" href="struct_nv_blast_damage_program.html">NvBlastDamageProgram</a> program =
{
myGraphShaderFunction, <span class="comment">// A function with the NvBlastGraphShaderFunction signature</span>
mySubgraphShaderFunction <span class="comment">// A function with the NvBlastSubgraphShaderFunction signature</span>
};
<span class="comment">// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension</span>
RadialDamageDesc damageDescs[2];
damageDescs[0].compressive = 10.0f;
damageDescs[0].position[0] = 1.0f;
damageDescs[0].position[1] = 2.0f;
damageDescs[0].position[2] = 3.0f;
damageDescs[0].minRadius = 0.0f;
damageDescs[0].maxRadius = 1.0f;
damageDescs[1].compressive = 100.0f;
damageDescs[1].position[0] = 3.0f;
damageDescs[1].position[1] = 4.0f;
damageDescs[1].position[2] = 5.0f;
damageDescs[1].minRadius = 0.0f;
damageDescs[1].maxRadius = 5.0f;
<span class="comment">// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension</span>
Material material;
material.health = 10.0f;
material.minDamageThreshold = 0.1f;
material.maxDamageThreshold = 0.8f;
<span class="comment">// Set the damage params struct</span>
NvBlastProgramParams params = { damageDescs, 2, &material };
<span class="comment">// Apply damage</span>
actor->damage(program, &params); <span class="comment">// params must be kept around until TkGroup::endProcess is called!</span>
</pre></div><p>
<br>
<h3><a class="anchor" name="single_damage_desc_default_material">
Single Damage Descriptor with Default TkFamily Material</a></h3>
This method of damage copies the damage descriptor into a buffer, so the user need <em>not</em> hold onto a copy after the damage function call. Only one damage descriptor may be passed in at once.<p>
To use this method, the user must first set a default material in the actor's family. For example:<p>
<div class="fragment"><pre class="fragment"><span class="comment">// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension</span>
Material material;
material.health = 10.0f;
material.minDamageThreshold = 0.1f;
material.maxDamageThreshold = 0.8f;
<span class="comment">// Set the default material used by the material-less TkActor::damage call</span>
actor->getFamily().setMaterial(&material);
</pre></div><p>
<b>N.B. the lifetime of the material set <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b><p>
Then to apply damage, use:<p>
<div class="fragment"><pre class="fragment"><a class="code" href="struct_nv_blast_damage_program.html">NvBlastDamageProgram</a> program =
{
myGraphShaderFunction, <span class="comment">// A function with the NvBlastGraphShaderFunction signature</span>
mySubgraphShaderFunction <span class="comment">// A function with the NvBlastSubgraphShaderFunction signature</span>
};
<span class="comment">// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension</span>
RadialDamageDesc damageDesc;
damageDesc.compressive = 10.0f;
damageDesc.position[0] = 1.0f;
damageDesc.position[1] = 2.0f;
damageDesc.position[2] = 3.0f;
damageDesc.minRadius = 0.0f;
damageDesc.maxRadius = 1.0f;
<span class="comment">// Apply damage</span>
actor->damage(program, &damageDesc, (uint32_t)<span class="keyword">sizeof</span>(RadialDamageDesc));
</pre></div><p>
<br>
<h3><a class="anchor" name="single_damage_desc_with_material">
Single Damage Descriptor with Specified Material</a></h3>
This method is just like the one above, except that the user has the opportunity to override the material used during damage.<p>
<b>N.B. - the lifetime of the material passed in <em>must</em> extend at least until the TkGroup::endProcess call for the actor.</b><p>
This call is just like the one above with an extra material parameter:<p>
<div class="fragment"><pre class="fragment">actor->damage(program, &damageDesc, (uint32_t)<span class="keyword">sizeof</span>(RadialDamageDesc), &material);
</pre></div><p>
<br>
<h2><a class="anchor" name="tkjoints">
Joints</a></h2>
Joints in NvBlastTk are abstract representations of physical joints. When joints become active, change the actors they join, or become unreferenced (the actors they join disappear), the user will receive notification via a TkJointUpdateEvent (see <a class="el" href="pagehlapi.html#tkevents">Events</a>).<p>
Joints may be defined as a part of a TkAsset, in which case they are consisdered "internal" joints. (See <a class="el" href="pagehlapi.html#tkasset_creation">Creating a TkAsset</a>.) Since the first instance of a TkAsset is a single TkActor, internal joints are defined between chunks within the same actor. Therefore they are not active (there is no point in joining two locations in a single rigid body). Upon splitting into multiple actors, however, an internal joint's chunks may now belong to two different TkActors. When this happens, the user will receive a TkJointUpdateEvent of subtype TkJointUpdateEvent::External. The event contains a pointer to the TkJoint, and from that the user has access to the information needed to create a physical joint between the rigid bodies that correspond to the joined TkActors.<p>
Joints may also be created externally at runtime, using the TkFramework::createJoint function. A joint created this way must be between two different TkActors. Because of this, the joint is immediately considered active, and so no TkJointUpdateEvent is generated from its creation. The user should create a physical joint to correspond to the joint returned by createJoint. An externally created joint of this type has another distinguishing characteristic: it may join an actor to "the world," or "Newtonial Reference Frame" (NRF). To do this, one TkFamily pointer in the joint descriptor is set to NULL. Examples are given below.<p>
<div class="fragment"><pre class="fragment">TkJointDesc desc;
desc.families[0] = &actor0->getFamily(); <span class="comment">// Assume we have a valid actor0 pointer</span>
desc.chunkIndices[0] = 1; <span class="comment">// This chunk *must* be a support chunk in the asset that created desc.families[0]</span>
desc.attachPositions[0] = physx::PxVec3(1.0f, 2.0f; 3.0f); <span class="comment">// The attach position is in asset space</span>
desc.families[1] = &actor1->getFamily(); <span class="comment">// Assume we have a valid actor1 pointer... note, actor0 and actor1 could have the same family</span>
desc.chunkIndices[1] = 10; <span class="comment">// This chunk *must* be a support chunk in the asset that created desc.families[1]</span>
desc.attachPositions[1] = physx::PxVec3(4.0f, 5.0f; 6.0f); <span class="comment">// The attach position is in asset space</span>
<span class="comment">// Create the external joint from the descriptor, which joins actor0 and actor1</span>
TkJoint* joint = framework->createJoint(desc);
<span class="comment">// Now join actor0 to the NRF</span>
<span class="comment">// desc.families[0] already contains actor0's family</span>
desc.chunkIndices[0] = 2; <span class="comment">// Again, this chunk must be a support chunk in the asset that created desc.families[0]</span>
desc.attachPositions[0] = physx::PxVec3(0.0f, 0.0f; 0.0f); <span class="comment">// The attach position is in asset space</span>
desc.families[1] = <span class="keyword">nullptr</span>; <span class="comment">// Setting the family to NULL designates the world (NRF)</span>
<span class="comment">// The value of desc.chunkIndices[1] is not used, since desc.families[1] is NULL</span>
desc.attachPositions[1] = physx::PxVec3(0.0f, 0.0f, 10.0f); <span class="comment">// Attach position in the world</span>
<span class="comment">// Create the external joint which joins actor0 to the world</span>
TkJoint* jointNRF = framework->createJoint(desc);
</pre></div><p>
<br>
<h3><a class="anchor" name="releasing_joints">
Releasing Joints</a></h3>
TkJoints are not released by Blast™, except when the TkFramework is released. Otherwise, the user is responsible for releasing TkJoints after they become unreferenced. This is facilitated by the Unreferenced subtype of the TkJointUpdateEvent. After receiving this event for joint, the user may choose to release, using the typical TkObject::release() method.<p>
<div class="fragment"><pre class="fragment">joint->release();
</pre></div><p>
Note, this method can be called <em>at any time</em>, even before the joint is unreferenced. When called, it will remove its references to its attached actors first, causing the joint to then become unreferenced. For example, if the user wishes to break a physical joint in their simulation, they can then release the corresponding TkJoint.<p>
It should be mentioned, however, that joints created with an asset are allocated differently from external joints created using TkFramework::createJoint. Internal joints created from the joint descriptors in a TkAsset are <em>block allocated</em> with every TkFamily that instances the asset. Calling the release() method on those joints will remove any remaining references to them (as mentioned above), but will not perform any deallocation. Only when the TkFamily itself is released will the internal joint memory for that family be released. <b>This is true even if the internal joints become "external" from actor splitting.</b> Joints that <em>become</em> external are still associated with a single family and their memory still resides with that family.<p>
On the other hand, joints that start out life external by way of the TkFramework::createJoint function have a separate allocation, and do not have memory tied to any TkFamily (even if both actors joined are in the same family). Releasing a family holding one of the actors in such a "purely external" joint will trigger a TkJointUpdateEvent of subtype Unreferenced, however, signalling that the joint is ready for user release.<p>
<br>
<h2><a class="anchor" name="tkevents">
Events</a></h2>
NvBlastTk uses events to communicate the results of actor splitting, joint updates from actor splitting, and fracture event buffers that can be used to synchronize fracturing between multiple clients.<p>
Events are broadcast to listeners which implement the TkEventListener interface. Listeners are held by TkFamily objects. During a TkGroup::endProcess call (see <a class="el" href="pagehlapi.html#tkgroups">Groups</a>), relevant events are broadcast to the listeners in the families associated with the actors in the group.<p>
A typical user's receiver implementation might take on the form shown below.<p>
<div class="fragment"><pre class="fragment"><span class="keyword">class </span>MyActorAndJointListener : <span class="keyword">public</span> TkEventListener
{
<span class="comment">// TkEventListener interface</span>
<span class="keywordtype">void</span> receive(<span class="keyword">const</span> TkEvent* events, uint32_t eventCount)<span class="keyword"> override</span>
<span class="keyword"> </span>{
<span class="comment">// Events are batched into an event buffer. Loop over all events:</span>
<span class="keywordflow">for</span> (uint32_t i = 0; i < eventCount; ++i)
{
<span class="keyword">const</span> TkEvent& <span class="keyword">event</span> = events[i];
<span class="comment">// See TkEvent documentation for event types</span>
<span class="keywordflow">switch</span> (event.type)
{
<span class="keywordflow">case</span> TkSplitEvent::EVENT_TYPE: <span class="comment">// A TkActor has split into smaller actors</span>
{
<span class="keyword">const</span> TkSplitEvent* splitEvent = <span class="keyword">event</span>.getPayload<TkSplitEvent>(); <span class="comment">// Split event payload</span>
<span class="comment">// The parent actor may no longer be valid. Instead, we receive the information it held</span>
<span class="comment">// which we need to update our app's representation (e.g. removal of the corresponding physics actor)</span>
myRemoveActorFunction(splitEvent->parentData.family, splitEvent->parentData.index, splitEvent->parentData.userData);
<span class="comment">// The split event contains an array of "child" actors that came from the parent. These are valid</span>
<span class="comment">// TkActor pointers and may be used to create physics and graphics representations in our application</span>
<span class="keywordflow">for</span> (uint32_t j = 0; j < splitEvent->numChildren; ++j)
{
myCreateActorFunction(splitEvent->children[j]);
}
}
<span class="keywordflow">break</span>;
<span class="keywordflow">case</span> TkJointUpdateEvent::EVENT_TYPE:
{
<span class="keyword">const</span> TkJointUpdateEvent* jointEvent = <span class="keyword">event</span>.getPayload<TkJointUpdateEvent>(); <span class="comment">// Joint update event payload</span>
<span class="comment">// Joint events have three subtypes, see which one we have</span>
<span class="keywordflow">switch</span> (jointEvent->subtype)
{
<span class="keywordflow">case</span> TkJointUpdateEvent::External:
myCreateJointFunction(jointEvent->joint); <span class="comment">// An internal joint has been "exposed" (now joins two different actors). Create a physics joint.</span>
<span class="keywordflow">break</span>;
<span class="keywordflow">case</span> TkJointUpdateEvent::Changed:
myUpdatejointFunction(jointEvent->joint); <span class="comment">// A joint's actors have changed, so we need to update its corresponding physics joint.</span>
<span class="keywordflow">break</span>;
<span class="keywordflow">case</span> TkJointUpdateEvent::Unreferenced:
myDestroyJointFunction(jointEvent->joint); <span class="comment">// This joint is no longer referenced, so we may delete the corresponding physics joint.</span>
<span class="keywordflow">break</span>;
}
}
<span class="comment">// Unhandled:</span>
<span class="keywordflow">case</span> TkFractureCommands::EVENT_TYPE:
<span class="keywordflow">case</span> TkFractureEvents::EVENT_TYPE:
<span class="keywordflow">default</span>:
<span class="keywordflow">break</span>;
}
}
}
};
</pre></div><p>
Whenever a new TkActor is created by the user (via TkFramework::createActor, see <a class="el" href="pagehlapi.html#tkasset_instancing">Instancing a TkAsset: Creation of a TkActor and a TkFamily</a>), its newly-made family should be given whatever listeners the user wishes to attach. For example,<p>
<div class="fragment"><pre class="fragment">TkActor* actor = framework->createActor(actorDesc);
actor->getFamily().addListener(myListener); <span class="comment">// myListener is an object which implements TkEventListener (see MyActorAndJointListener above, for example)</span>
</pre></div><p>
Listeners may also be removed from families at any time.<p>
<br>
<h2><a class="anchor" name="tktypes">
Object and Type Identification</a></h2>
NvBlastTk objects that are derived from TkIdentifiable (TkAsset, TkFamily, and TkGroup) support an object and class (type) identification system. The TkIdentifiable interfaces setID and getID allow the user to set and access an <a class="el" href="struct_nv_blast_i_d.html">NvBlastID</a> for each object. The <a class="el" href="struct_nv_blast_i_d.html">NvBlastID</a> is a 128-bit identifier. TkIdentifiable objects are tracked by the TkFramework, which may be used to look up an object by its <a class="el" href="struct_nv_blast_i_d.html">NvBlastID</a>.<p>
Upon creation, TkIdentifiable objects are given a GUID, a unique <a class="el" href="struct_nv_blast_i_d.html">NvBlastID</a>. The user is welcome to change the object's guid at any time, with the restriction that the GUID cannot be all zero bytes.<p>
With an object's GUID, one may look up the object using the TkFramework function findObjectByID:<p>
<div class="fragment"><pre class="fragment">TkIdentifiable* <span class="keywordtype">object</span> = framework->findObjectByID(<span class="keywordtype">id</span>); <span class="comment">// id = an NvBlastID GUID</span>
</pre></div><p>
If the object is found, a non-NULL pointer will be returned.<p>
TkIdentifiable-derived classes also have a class identification system, the TkType interface. From an individual object one may use the TkIdentifiable interface getType to access the class's TkType interface. Alternatively, one may use the TkFramework getType function with TkTypeIndex::Enum argument. For example, to get the TkType interface for the TkAsset class, use<p>
<div class="fragment"><pre class="fragment"><span class="keyword">const</span> TkType* assetType = framework->getType(TkTypeIndex::Asset);
</pre></div><p>
The type interface may be used:<p>
<ul>
<li>to access class-specific object lists in the framework,</li><li>identify the class of a TkIdentifiable obtained through ID lookup or deserialization, or</li><li>to obtain the class's name and format version number.</li></ul>
<p>
For example, to access a list of all families:<p>
<div class="fragment"><pre class="fragment"><span class="comment">// Get the TkFamily type interface</span>
<span class="keyword">const</span> TkType* familyType = framework->getType(TkTypeIndex::Family);
<span class="comment">// Get the family count to allocate a buffer</span>
<span class="keyword">const</span> uint32_t familyCount = framework->getObjectCount(familyType);
std::vector<TkIdentifiable*> families(familyCount);
<span class="comment">// Write the families to the buffer</span>
<span class="keyword">const</span> uint32_t familiesFound = framework->getObjects(families.data(), familyCount, familyType);
</pre></div><p>
In the above code, the values of familyCount and familiesFound should be equal. An alternative usage of TkFramework::getObjects allows the user to write to a (potentially) smaller buffer, iteratively. For example:<p>
<div class="fragment"><pre class="fragment">uint32_t familiesFound;
uint32_t totalFamilyCount = 0;
<span class="keywordflow">do</span>
{
<span class="comment">// Write to a fixed-size buffer</span>
TkIdentifiable* familyBuffer[16];
familiesFound = framework->getObjects(familyBuffer, 16, familyType, totalFamilyCount);
totalFamilyCount += familiesFound;
<span class="comment">// Process the families found so far</span>
myProcessFamiliesFunction(familyBuffer, familiesFound);
} <span class="keywordflow">while</span> (familiesFound == 16);
</pre></div><p>
To use the type interface to identify a class, perhaps after serialization or lookup by ID, one may do something like:<p>
<div class="fragment"><pre class="fragment">\\ Assume we have a TkIdentifiable pointer called <span class="stringliteral">"object"</span>
<span class="comment">// Get the type interfaces of interest</span>
<span class="keyword">const</span> TkType* assetType = framework->getType(TkTypeIndex::Asset);
<span class="keyword">const</span> TkType* familyType = framework->getType(TkTypeIndex::Family);
<span class="keywordflow">if</span> (object->getType() == *assetType)
{
TkAsset* asset = <span class="keyword">static_cast<</span>TkAsset*<span class="keyword">></span>(object);
<span class="comment">// Process the object as a TkAsset</span>
}
<span class="keywordflow">if</span> (object->getType() == *familyType)
<span class="keywordflow">else</span>
{
TkFamily* family = <span class="keyword">static_cast<</span>TkFamily*<span class="keyword">></span>(object);
<span class="comment">// Process the object as a TkFamily</span>
}
</pre></div><p>
A TkIdentifiable-derived class may be queried for its name using the TkType interface, using TkType::getName(). This function returns a const char pointer to a string.<p>
Finally, one may query the class for its current format version number using TkType::getVersion().<p>
<br>
</div>
<!-- start footer part -->
<div class="footer">
Copyright © 2015-2017 NVIDIA Corporation, 2701 San Tomas Expressway, Santa Clara, CA 95050 U.S.A. All rights reserved. <a href="http://www.nvidia.com ">www.nvidia.com</a>
</div>
</body>
</html>
|