From 7115f60b91b5717d90f643fd692010905c7004db Mon Sep 17 00:00:00 2001 From: Bryan Galdrikian Date: Thu, 31 May 2018 11:36:08 -0700 Subject: Blast 1.1.3. See docs/release_notes.txt. --- docs/_source/api_hl_users_guide.txt | 1410 +++++++++++++++++------------------ 1 file changed, 705 insertions(+), 705 deletions(-) mode change 100644 => 100755 docs/_source/api_hl_users_guide.txt (limited to 'docs/_source/api_hl_users_guide.txt') diff --git a/docs/_source/api_hl_users_guide.txt b/docs/_source/api_hl_users_guide.txt old mode 100644 new mode 100755 index ae8dd4a..34d843e --- a/docs/_source/api_hl_users_guide.txt +++ b/docs/_source/api_hl_users_guide.txt @@ -1,705 +1,705 @@ -/*! \page pagehlapi High Level (Toolkit) API (NvBlastTk) - -Table of Contents - -\subpage tkintroduction - -\subpage tk_class_hierarchy - -\subpage tk_include_and_library - -\subpage framework_init - -\subpage tkasset_creation - -\subpage tkasset_instancing - -\subpage tkgroups - -\subpage damage_in_tk - -\subpage tkjoints - -\subpage tkevents - -\subpage tktypes - -
-\section tkintroduction Introduction to NvBlastTk - -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&tm;. 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: - -\code -Nv::Blast -\endcode - -(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: - -\code -Nv::Blast::TkFramework -\endcode - - -For the remainder of this page we will be in the Nv::Blast namespace, and will drop the explicit scope Nv::Blast:: from our names. - -
-
- - -BlastTk adds: - -- An object class hierarchy (see \ref tk_class_hierarchy, below). -- A global framework, TkFramework (a singleton). This keeps track of TkIdentifiable objects and allows -the user to query them based upon either GUID or TkIdentifiable subclass type, and also provides a number of functions to create the various objects in BlastTk. -- Processing groups with a task interface (see TkGroup). -- Event dispatching for actor families (see TkFamily). -- Intra-actor and inter-actor joint management (see TkJoint). Note, these "joints" only hold descriptor data, since physical objects are not handled by BlastTk. - -
-\section tk_class_hierarchy NvBlastTk Class Hierarchy - -- There are two abstract interfaces, one of which deriving from the other: TkObject <- TkIdentifiable. - - Lightweight objects are derived from TkObject. - - Objects which use a GUID and class identification are derieved from TkIdentifiable. -- TkAsset derives from TkIdentifiable. This is mostly a wrapper for NvBlastAsset, however it also stores -extra data associated with the asset such as internal joint descriptors. -- TkFamily derives from TkIdentifiable. One of these objects is made when a TkActor is instanced -from a TkAsset. 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 TkFamily. -- TkGroup derives from TkIdentifiable. 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. -- TkActor derives from TkObject. It is mostly a wrapper for NvBlastActor, but it also provides a number of damage functions -to the user. -- TkJoint derives from TkObject. TkAsset descriptors, cause internal TkJoint 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. - -
-\section tk_include_and_library Linking and Header Files - -To use the BlastTk library, the application need only inlclude the header NvBlastTk.h, found in the include/toolkit 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 - -NvBlastTk(config)(arch).(ext) - -(config) is DEBUG, CHECKED, OR PROFILE for the corresponding configurations. For a release configuration there is no (config) suffix. - -(arch) is _x86 or _x64 for Windows 32- and 64-bit builds, respectively, and empty for non-Windows platforms. - -(ext) is .lib for static linking and .dll for dynamic linking on Windows. On XBoxOne it is .lib, and on PS4 it is .a. - - -
-\section framework_init Creating the TkFramework - -As a reminder, in this document we assume we are in the Nv::Blast namespace: - -\code -using namespace Nv::Blast; -\endcode - -In order to use NvBlastTk, one first has to create a TkFramework singleton. This simply requires a call -to the global function NvBlastTkFrameworkCreate: - -\code -TkFramework* framework = NvBlastTkFrameworkCreate(); -\endcode - -The framework may be accessed via: - -\code -TkFramework* framework = NvBlastTkFrameworkGet(); -\endcode - -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. - -Finally, to release the framework, use - -\code -framework->release(); -\endcode - -This will release all assets, families, actors, joints, and groups. - -
-\section tkasset_creation Creating a TkAsset - -The TkAsset object is a high-level wrapper for the low-level NvBlastAsset (see \ref assets). The descriptor used to create a TkAsset, a TkAssetDesc, is derived from -NvBlastAssetDesc. The base fields should be filled in as described in (\ref assets). 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 (\ref tkjoints) for more on joints in BlastTk. - -\code -TkAssetDesc desc; - -myFunctionToFillInLowLevelAssetFields(desc); // Fill in the low-level (NvBlastAssetDesc) fields as usual - -std::vector bondFlags(desc.bondCount, 0); // Clear all flags - -// Set BondJointed flags corresponding to joints selected by the user (assumes a myBondIsJointedFunction to make this selection) -for (uint32_t i = 0; i < desc.bondCount; ++i) -{ - if (myBondIsJointedFunction(i)) // User-authored - { - bondFlags[i] |= TkAssetDesc::BondJointed; - } -} - -TkAsset* asset = framework->createAsset(desc); // Create a new TkAsset -\endcode - -The createAsset function used above creates a low-level NvBlastAsset 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 NvBlastAsset, 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 NvBlastAsset -pointer llAsset, a TkAsset may be created simply by using - -\code -TkAsset* asset = framework->createAsset(llAsset); -\endcode - -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: - -\code -TkAsset* asset = framework->createAsset(llAsset, nullptr, 0, true); -\endcode - -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 \ref pageglobalsapi). - -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. - -\code -std::vector jointDescs(jointCount); // Assume jointCount = the number of joints to add -jointDescs[0].nodeIndices[0] = 0; // Attach node 0 to node 1 -jointDescs[0].nodeIndices[1] = 1; -jointDescs[0].attachPoistions[0] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); // Attachment positions are often the same within an asset, but they don't have to be -jointDescs[0].attachPoistions[1] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); -// ... etc. - -TkAsset* asset = framework->createAsset(llAsset, jointDescs.data(), jointDescs.size()); -\endcode - -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 - -\code -const uint32_t map = NvBlastAssetGetChunkToGraphNodeMap(llAsset, logFn); -\endcode - -This map is an array with an entry for every chunk index. To get the graph node index for a chunk indexed chunkIndex, use - -\code -uint32_t nodeIndex = map[chunkIndex]; -\endcode - -If the chunk indexed by chunkIndex does not 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. - -Finally, to release a TkAsset, as with any TkObject-derived object, use the release() method: - -\code -asset->release(); -\endcode - -
-\section tkasset_instancing Instancing a TkAsset: Creation of a TkActor and a TkFamily - -Whereas with the Blast&tm; low-level (\ref pagellapi), one must explicitly create a family (NvBlastFamily) from an asset (NvBlastAsset) before creating -the first actor (NvBlastActor) 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 -not 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. - -The TkFamily has a special role in NvBlastTk, holding user-supplied event listeners (\ref TkEventListener). All internal 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 \ref tkjoints). - -To create an unfractured TkActor instance from a TkAsset, one first fills in a descriptor (\ref TkActorDesc) and passes it to the framework's createActor function. -As with the TkAssetDesc, the TkActorDesc is derived from its low-level counterpart, the NvBlastActorDesc. In addition the TkActorDesc holds a pointer to -the TkAsset being instanced. An example of TkActor creation is given below, given a TkAsset pointer asset. - -\code -TkActorDesc desc; // The TkActorDesc constructor sets sane default values for the base (NvBlastActorDesc) fields, giving uniform chunk and bond healths of 1.0. -desc.asset = asset; // This field of TkActorDesc must be set to a valid asset pointer. - -TkActor* actor = framework->createActor(desc); -\endcode - -The TkFamily created with the actor above may be accessed through the actor's getFamily field: - -\code -TkFamily& family = actor->getFamily(); -\endcode - -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. - -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 \ref tkevents. - -
-\section tkgroups Groups - -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. - -Group processing is performed by workers, 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. - -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 Nv::Blast::ExtGroupTaskManager (in NvBlastExtPxTask.h). -This resides in \ref pageextphysx, because it uses physx::PxTask. - -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. - -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 not released. They will, however, be removed from the group before the release is complete. - -A typical usage is outlined below. See \ref damage_in_tk for methods of applying damage to actors. - -\code -// Create actors from descriptors desc1, desc2, ... etc., and attach a listener to each new family created -TkActor* actor1 = framework->createActor(desc1); -actor1->getFamily().addListener(gMyReceiver); // gMyReceiver is a TkEventListener-derived object. More on events in a subsequent section. -TkActor* actor2 = framework->createActor(desc2); -actor2->getFamily().addListener(gMyReceiver); -TkActor* actor3 = framework->createActor(desc3); -actor3->getFamily().addListener(gMyReceiver); -// etc... - -// Let's create two groups. First, create a group descriptor. This may be used to create both groups. -TkGroupDesc groupDesc; -groupDesc.workerCount = 1; // this example processes groups on the calling thread only - -// Now create the groups -TkGroup* group1 = framework->createGroup(groupDesc); -TkGroup* group2 = framework->createGroup(groupDesc); - -// Add actor1 and actor2 to group1, and actor2 to group3... -group1->addActor(actor1); -group1->addActor(actor2); -group2->addActor(actor3); -// etc... - -// Now apply damage to all actors - *NOTE* damage is described in detail in the next section. -// For now we will just assume a "myDamageFunction" to apply the damage. -myDamageFunction(actor1); -myDamageFunction(actor2); -myDamageFunction(actor3); -// etc... - -// Calling the groups' process functions will (synchronously) run all jobs to process damage taken by the contained actors. -group1->process(); -group2->process(); - -// When the groups are no longer needed, they may be released with the usual release method. -group1->release(); -group2->release(); -\endcode - -
-Multithreaded processing - -When distributing the jobs as mentioned above, every job must be processed exactly once (over all user tasks). - -The number of jobs processed per worker can range from a single job (resulting in a user task per job) to all jobs (like Nv::Blast::TkGroup::process() does). - -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. - -\code -Nv::Blast::TkGroupWorker* worker = group->acquireWorker(); -// process some jobs -group->returnWorker(worker); -\endcode - -
-\section damage_in_tk Applying Damage to Actors and Families - -Damage in NvBlastTk uses the same damage program scheme as the low-level SDK (see \ref splitting). One passes the program -(NvBlastDamageProgram), 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. - -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. - -Examples of the three TkActor damage methods are given below. - -
-\subsection multiple_damage Multiple Damage Descriptors using NvBlastProgramParams - -N.B. - with this method of damage, the lifetime of the NvBlastProgramParams must extend at -least until the TkGroup::endProcess call for the actor. - -\code -NvBlastDamageProgram program = -{ - myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature - mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature -}; - -// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension -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; - -// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension -Material material; - -material.health = 10.0f; -material.minDamageThreshold = 0.1f; -material.maxDamageThreshold = 0.8f; - -// Set the damage params struct -NvBlastProgramParams params = { damageDescs, 2, &material }; - -// Apply damage -actor->damage(program, ¶ms); // params must be kept around until TkGroup::endProcess is called! -\endcode - -
-\subsection single_damage_desc_default_material Single Damage Descriptor with Default TkFamily Material - -This method of damage copies the damage descriptor into a buffer, so the user need not hold onto -a copy after the damage function call. Only one damage descriptor may be passed in at once. - -To use this method, the user must first set a default material in the actor's family. For example: - -\code -// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension -Material material; - -material.health = 10.0f; -material.minDamageThreshold = 0.1f; -material.maxDamageThreshold = 0.8f; - -// Set the default material used by the material-less TkActor::damage call -actor->getFamily().setMaterial(&material); -\endcode - -N.B. the lifetime of the material set must extend at least until the TkGroup::endProcess call for the actor. - -Then to apply damage, use: - -\code -NvBlastDamageProgram program = -{ - myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature - mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature -}; - -// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension -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; - -// Apply damage -actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc)); -\endcode - -
-\subsection single_damage_desc_with_material Single Damage Descriptor with Specified Material - -This method is just like the one above, except that the user has the opportunity to override the material used during damage. - -N.B. - the lifetime of the material passed in must extend at least until the TkGroup::endProcess call for the actor. - -This call is just like the one above with an extra material parameter: - -\code -actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc), &material); -\endcode - -
-\section tkjoints Joints - -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 \ref tkevents). - -Joints may be defined as a part of a TkAsset, in which case they are consisdered "internal" joints. (See \ref tkasset_creation.) -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. - -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. - -\code -TkJointDesc desc; -desc.families[0] = &actor0->getFamily(); // Assume we have a valid actor0 pointer -desc.chunkIndices[0] = 1; // This chunk *must* be a support chunk in the asset that created desc.families[0] -desc.attachPositions[0] = physx::PxVec3(1.0f, 2.0f; 3.0f); // The attach position is in asset space -desc.families[1] = &actor1->getFamily(); // Assume we have a valid actor1 pointer... note, actor0 and actor1 could have the same family -desc.chunkIndices[1] = 10; // This chunk *must* be a support chunk in the asset that created desc.families[1] -desc.attachPositions[1] = physx::PxVec3(4.0f, 5.0f; 6.0f); // The attach position is in asset space - -// Create the external joint from the descriptor, which joins actor0 and actor1 -TkJoint* joint = framework->createJoint(desc); - -// Now join actor0 to the NRF -// desc.families[0] already contains actor0's family -desc.chunkIndices[0] = 2; // Again, this chunk must be a support chunk in the asset that created desc.families[0] -desc.attachPositions[0] = physx::PxVec3(0.0f, 0.0f; 0.0f); // The attach position is in asset space -desc.families[1] = nullptr; // Setting the family to NULL designates the world (NRF) -// The value of desc.chunkIndices[1] is not used, since desc.families[1] is NULL -desc.attachPositions[1] = physx::PxVec3(0.0f, 0.0f, 10.0f); // Attach position in the world - -// Create the external joint which joins actor0 to the world -TkJoint* jointNRF = framework->createJoint(desc); -\endcode - -
-\subsection releasing_joints Releasing Joints - -TkJoints are not released by Blast&tm;, 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. - -\code -joint->release(); -\endcode - -Note, this method can be called at any time, 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. - -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 block allocated 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. This is true even if the internal joints become "external" from actor splitting. Joints -that become external are still associated with a single family and their memory still resides with that family. - -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. - -
-\section tkevents Events - -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. - -Events are broadcast to listeners which implement the TkEventListener interface. Listeners are held by TkFamily objects. During -a TkGroup::endProcess call (see \ref tkgroups), relevant events are broadcast to the listeners in the families associated with the actors -in the group. - -A typical user's receiver implementation might take on the form shown below. - -\code -class MyActorAndJointListener : public TkEventListener -{ - // TkEventListener interface - void receive(const TkEvent* events, uint32_t eventCount) override - { - // Events are batched into an event buffer. Loop over all events: - for (uint32_t i = 0; i < eventCount; ++i) - { - const TkEvent& event = events[i]; - - // See TkEvent documentation for event types - switch (event.type) - { - case TkSplitEvent::EVENT_TYPE: // A TkActor has split into smaller actors - { - const TkSplitEvent* splitEvent = event.getPayload(); // Split event payload - - // The parent actor may no longer be valid. Instead, we receive the information it held - // which we need to update our app's representation (e.g. removal of the corresponding physics actor) - myRemoveActorFunction(splitEvent->parentData.family, splitEvent->parentData.index, splitEvent->parentData.userData); - - // The split event contains an array of "child" actors that came from the parent. These are valid - // TkActor pointers and may be used to create physics and graphics representations in our application - for (uint32_t j = 0; j < splitEvent->numChildren; ++j) - { - myCreateActorFunction(splitEvent->children[j]); - } - } - break; - - case TkJointUpdateEvent::EVENT_TYPE: - { - const TkJointUpdateEvent* jointEvent = event.getPayload(); // Joint update event payload - - // Joint events have three subtypes, see which one we have - switch (jointEvent->subtype) - { - case TkJointUpdateEvent::External: - myCreateJointFunction(jointEvent->joint); // An internal joint has been "exposed" (now joins two different actors). Create a physics joint. - break; - case TkJointUpdateEvent::Changed: - myUpdatejointFunction(jointEvent->joint); // A joint's actors have changed, so we need to update its corresponding physics joint. - break; - case TkJointUpdateEvent::Unreferenced: - myDestroyJointFunction(jointEvent->joint); // This joint is no longer referenced, so we may delete the corresponding physics joint. - break; - } - } - - // Unhandled: - case TkFractureCommands::EVENT_TYPE: - case TkFractureEvents::EVENT_TYPE: - default: - break; - } - } - } -}; -\endcode - -Whenever a new TkActor is created by the user (via TkFramework::createActor, see \ref tkasset_instancing), its newly-made family should -be given whatever listeners the user wishes to attach. For example, - -\code -TkActor* actor = framework->createActor(actorDesc); - -actor->getFamily().addListener(myListener); // myListener is an object which implements TkEventListener (see MyActorAndJointListener above, for example) -\endcode - -Listeners may also be removed from families at any time. - -
-\section tktypes Object and Type Identification - -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 NvBlastID for each object. The NvBlastID -is a 128-bit identifier. TkIdentifiable objects are tracked by the TkFramework, which may be used to look up an object by its NvBlastID. - -Upon creation, TkIdentifiable objects are given a GUID, a unique NvBlastID. The user is welcome to change the object's guid at any time, with -the restriction that the GUID cannot be all zero bytes. - -With an object's GUID, one may look up the object using the TkFramework function findObjectByID: - -\code -TkIdentifiable* object = framework->findObjectByID(id); // id = an NvBlastID GUID -\endcode - -If the object is found, a non-NULL pointer will be returned. - -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 - -\code -const TkType* assetType = framework->getType(TkTypeIndex::Asset); -\endcode - -The type interface may be used: - - - to access class-specific object lists in the framework, - - identify the class of a TkIdentifiable obtained through ID lookup or deserialization, or - - to obtain the class's name and format version number. - -For example, to access a list of all families: - -\code -// Get the TkFamily type interface -const TkType* familyType = framework->getType(TkTypeIndex::Family); - -// Get the family count to allocate a buffer -const uint32_t familyCount = framework->getObjectCount(familyType); -std::vector families(familyCount); - -// Write the families to the buffer -const uint32_t familiesFound = framework->getObjects(families.data(), familyCount, familyType); -\endcode - -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: - -\code -uint32_t familiesFound; -uint32_t totalFamilyCount = 0; -do -{ - // Write to a fixed-size buffer - TkIdentifiable* familyBuffer[16]; - familiesFound = framework->getObjects(familyBuffer, 16, familyType, totalFamilyCount); - totalFamilyCount += familiesFound; - - // Process the families found so far - myProcessFamiliesFunction(familyBuffer, familiesFound); -} while (familiesFound == 16); -\endcode - -To use the type interface to identify a class, perhaps after serialization or lookup by ID, one may do something like: - -\code -\\ Assume we have a TkIdentifiable pointer called "object" - -// Get the type interfaces of interest -const TkType* assetType = framework->getType(TkTypeIndex::Asset); -const TkType* familyType = framework->getType(TkTypeIndex::Family); - -if (object->getType() == *assetType) -{ - TkAsset* asset = static_cast(object); - - // Process the object as a TkAsset -} -if (object->getType() == *familyType) -else -{ - TkFamily* family = static_cast(object); - - // Process the object as a TkFamily -} -\endcode - -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. - -Finally, one may query the class for its current format version number using TkType::getVersion(). - -
-*/ +/*! \page pagehlapi High Level (Toolkit) API (NvBlastTk) + +Table of Contents + +\subpage tkintroduction + +\subpage tk_class_hierarchy + +\subpage tk_include_and_library + +\subpage framework_init + +\subpage tkasset_creation + +\subpage tkasset_instancing + +\subpage tkgroups + +\subpage damage_in_tk + +\subpage tkjoints + +\subpage tkevents + +\subpage tktypes + +
+\section tkintroduction Introduction to NvBlastTk + +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&tm;. 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: + +\code +Nv::Blast +\endcode + +(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: + +\code +Nv::Blast::TkFramework +\endcode + + +For the remainder of this page we will be in the Nv::Blast namespace, and will drop the explicit scope Nv::Blast:: from our names. + +
+
+ + +BlastTk adds: + +- An object class hierarchy (see \ref tk_class_hierarchy, below). +- A global framework, TkFramework (a singleton). This keeps track of TkIdentifiable objects and allows +the user to query them based upon either GUID or TkIdentifiable subclass type, and also provides a number of functions to create the various objects in BlastTk. +- Processing groups with a task interface (see TkGroup). +- Event dispatching for actor families (see TkFamily). +- Intra-actor and inter-actor joint management (see TkJoint). Note, these "joints" only hold descriptor data, since physical objects are not handled by BlastTk. + +
+\section tk_class_hierarchy NvBlastTk Class Hierarchy + +- There are two abstract interfaces, one of which deriving from the other: TkObject <- TkIdentifiable. + - Lightweight objects are derived from TkObject. + - Objects which use a GUID and class identification are derieved from TkIdentifiable. +- TkAsset derives from TkIdentifiable. This is mostly a wrapper for NvBlastAsset, however it also stores +extra data associated with the asset such as internal joint descriptors. +- TkFamily derives from TkIdentifiable. One of these objects is made when a TkActor is instanced +from a TkAsset. 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 TkFamily. +- TkGroup derives from TkIdentifiable. 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. +- TkActor derives from TkObject. It is mostly a wrapper for NvBlastActor, but it also provides a number of damage functions +to the user. +- TkJoint derives from TkObject. TkAsset descriptors, cause internal TkJoint 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. + +
+\section tk_include_and_library Linking and Header Files + +To use the BlastTk library, the application need only inlclude the header NvBlastTk.h, found in the include/toolkit 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 + +NvBlastTk(config)(arch).(ext) + +(config) is DEBUG, CHECKED, OR PROFILE for the corresponding configurations. For a release configuration there is no (config) suffix. + +(arch) is _x86 or _x64 for Windows 32- and 64-bit builds, respectively, and empty for non-Windows platforms. + +(ext) is .lib for static linking and .dll for dynamic linking on Windows. On XBoxOne it is .lib, and on PS4 it is .a. + + +
+\section framework_init Creating the TkFramework + +As a reminder, in this document we assume we are in the Nv::Blast namespace: + +\code +using namespace Nv::Blast; +\endcode + +In order to use NvBlastTk, one first has to create a TkFramework singleton. This simply requires a call +to the global function NvBlastTkFrameworkCreate: + +\code +TkFramework* framework = NvBlastTkFrameworkCreate(); +\endcode + +The framework may be accessed via: + +\code +TkFramework* framework = NvBlastTkFrameworkGet(); +\endcode + +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. + +Finally, to release the framework, use + +\code +framework->release(); +\endcode + +This will release all assets, families, actors, joints, and groups. + +
+\section tkasset_creation Creating a TkAsset + +The TkAsset object is a high-level wrapper for the low-level NvBlastAsset (see \ref assets). The descriptor used to create a TkAsset, a TkAssetDesc, is derived from +NvBlastAssetDesc. The base fields should be filled in as described in (\ref assets). 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 (\ref tkjoints) for more on joints in BlastTk. + +\code +TkAssetDesc desc; + +myFunctionToFillInLowLevelAssetFields(desc); // Fill in the low-level (NvBlastAssetDesc) fields as usual + +std::vector bondFlags(desc.bondCount, 0); // Clear all flags + +// Set BondJointed flags corresponding to joints selected by the user (assumes a myBondIsJointedFunction to make this selection) +for (uint32_t i = 0; i < desc.bondCount; ++i) +{ + if (myBondIsJointedFunction(i)) // User-authored + { + bondFlags[i] |= TkAssetDesc::BondJointed; + } +} + +TkAsset* asset = framework->createAsset(desc); // Create a new TkAsset +\endcode + +The createAsset function used above creates a low-level NvBlastAsset 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 NvBlastAsset, 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 NvBlastAsset +pointer llAsset, a TkAsset may be created simply by using + +\code +TkAsset* asset = framework->createAsset(llAsset); +\endcode + +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: + +\code +TkAsset* asset = framework->createAsset(llAsset, nullptr, 0, true); +\endcode + +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 \ref pageglobalsapi). + +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. + +\code +std::vector jointDescs(jointCount); // Assume jointCount = the number of joints to add +jointDescs[0].nodeIndices[0] = 0; // Attach node 0 to node 1 +jointDescs[0].nodeIndices[1] = 1; +jointDescs[0].attachPoistions[0] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); // Attachment positions are often the same within an asset, but they don't have to be +jointDescs[0].attachPoistions[1] = physx::PxVec3( 1.0f, 2.0f, 3.0f ); +// ... etc. + +TkAsset* asset = framework->createAsset(llAsset, jointDescs.data(), jointDescs.size()); +\endcode + +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 + +\code +const uint32_t map = NvBlastAssetGetChunkToGraphNodeMap(llAsset, logFn); +\endcode + +This map is an array with an entry for every chunk index. To get the graph node index for a chunk indexed chunkIndex, use + +\code +uint32_t nodeIndex = map[chunkIndex]; +\endcode + +If the chunk indexed by chunkIndex does not 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. + +Finally, to release a TkAsset, as with any TkObject-derived object, use the release() method: + +\code +asset->release(); +\endcode + +
+\section tkasset_instancing Instancing a TkAsset: Creation of a TkActor and a TkFamily + +Whereas with the Blast&tm; low-level (\ref pagellapi), one must explicitly create a family (NvBlastFamily) from an asset (NvBlastAsset) before creating +the first actor (NvBlastActor) 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 +not 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. + +The TkFamily has a special role in NvBlastTk, holding user-supplied event listeners (\ref TkEventListener). All internal 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 \ref tkjoints). + +To create an unfractured TkActor instance from a TkAsset, one first fills in a descriptor (\ref TkActorDesc) and passes it to the framework's createActor function. +As with the TkAssetDesc, the TkActorDesc is derived from its low-level counterpart, the NvBlastActorDesc. In addition the TkActorDesc holds a pointer to +the TkAsset being instanced. An example of TkActor creation is given below, given a TkAsset pointer asset. + +\code +TkActorDesc desc; // The TkActorDesc constructor sets sane default values for the base (NvBlastActorDesc) fields, giving uniform chunk and bond healths of 1.0. +desc.asset = asset; // This field of TkActorDesc must be set to a valid asset pointer. + +TkActor* actor = framework->createActor(desc); +\endcode + +The TkFamily created with the actor above may be accessed through the actor's getFamily field: + +\code +TkFamily& family = actor->getFamily(); +\endcode + +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. + +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 \ref tkevents. + +
+\section tkgroups Groups + +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. + +Group processing is performed by workers, 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. + +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 Nv::Blast::ExtGroupTaskManager (in NvBlastExtPxTask.h). +This resides in \ref pageextphysx, because it uses physx::PxTask. + +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. + +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 not released. They will, however, be removed from the group before the release is complete. + +A typical usage is outlined below. See \ref damage_in_tk for methods of applying damage to actors. + +\code +// Create actors from descriptors desc1, desc2, ... etc., and attach a listener to each new family created +TkActor* actor1 = framework->createActor(desc1); +actor1->getFamily().addListener(gMyReceiver); // gMyReceiver is a TkEventListener-derived object. More on events in a subsequent section. +TkActor* actor2 = framework->createActor(desc2); +actor2->getFamily().addListener(gMyReceiver); +TkActor* actor3 = framework->createActor(desc3); +actor3->getFamily().addListener(gMyReceiver); +// etc... + +// Let's create two groups. First, create a group descriptor. This may be used to create both groups. +TkGroupDesc groupDesc; +groupDesc.workerCount = 1; // this example processes groups on the calling thread only + +// Now create the groups +TkGroup* group1 = framework->createGroup(groupDesc); +TkGroup* group2 = framework->createGroup(groupDesc); + +// Add actor1 and actor2 to group1, and actor2 to group3... +group1->addActor(actor1); +group1->addActor(actor2); +group2->addActor(actor3); +// etc... + +// Now apply damage to all actors - *NOTE* damage is described in detail in the next section. +// For now we will just assume a "myDamageFunction" to apply the damage. +myDamageFunction(actor1); +myDamageFunction(actor2); +myDamageFunction(actor3); +// etc... + +// Calling the groups' process functions will (synchronously) run all jobs to process damage taken by the contained actors. +group1->process(); +group2->process(); + +// When the groups are no longer needed, they may be released with the usual release method. +group1->release(); +group2->release(); +\endcode + +
+Multithreaded processing + +When distributing the jobs as mentioned above, every job must be processed exactly once (over all user tasks). + +The number of jobs processed per worker can range from a single job (resulting in a user task per job) to all jobs (like Nv::Blast::TkGroup::process() does). + +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. + +\code +Nv::Blast::TkGroupWorker* worker = group->acquireWorker(); +// process some jobs +group->returnWorker(worker); +\endcode + +
+\section damage_in_tk Applying Damage to Actors and Families + +Damage in NvBlastTk uses the same damage program scheme as the low-level SDK (see \ref splitting). One passes the program +(NvBlastDamageProgram), 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. + +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. + +Examples of the three TkActor damage methods are given below. + +
+\subsection multiple_damage Multiple Damage Descriptors using NvBlastProgramParams + +N.B. - with this method of damage, the lifetime of the NvBlastProgramParams must extend at +least until the TkGroup::endProcess call for the actor. + +\code +NvBlastDamageProgram program = +{ + myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature + mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature +}; + +// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension +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; + +// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension +Material material; + +material.health = 10.0f; +material.minDamageThreshold = 0.1f; +material.maxDamageThreshold = 0.8f; + +// Set the damage params struct +NvBlastProgramParams params = { damageDescs, 2, &material }; + +// Apply damage +actor->damage(program, ¶ms); // params must be kept around until TkGroup::endProcess is called! +\endcode + +
+\subsection single_damage_desc_default_material Single Damage Descriptor with Default TkFamily Material + +This method of damage copies the damage descriptor into a buffer, so the user need not hold onto +a copy after the damage function call. Only one damage descriptor may be passed in at once. + +To use this method, the user must first set a default material in the actor's family. For example: + +\code +// The example material "Material" is modeled after NvBlastExtMaterial in the NvBlastExtShaders extension +Material material; + +material.health = 10.0f; +material.minDamageThreshold = 0.1f; +material.maxDamageThreshold = 0.8f; + +// Set the default material used by the material-less TkActor::damage call +actor->getFamily().setMaterial(&material); +\endcode + +N.B. the lifetime of the material set must extend at least until the TkGroup::endProcess call for the actor. + +Then to apply damage, use: + +\code +NvBlastDamageProgram program = +{ + myGraphShaderFunction, // A function with the NvBlastGraphShaderFunction signature + mySubgraphShaderFunction // A function with the NvBlastSubgraphShaderFunction signature +}; + +// The example struct "RadialDamageDesc" is modeled after NvBlastExtRadialDamageDesc in the NvBlastExtShaders extension +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; + +// Apply damage +actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc)); +\endcode + +
+\subsection single_damage_desc_with_material Single Damage Descriptor with Specified Material + +This method is just like the one above, except that the user has the opportunity to override the material used during damage. + +N.B. - the lifetime of the material passed in must extend at least until the TkGroup::endProcess call for the actor. + +This call is just like the one above with an extra material parameter: + +\code +actor->damage(program, &damageDesc, (uint32_t)sizeof(RadialDamageDesc), &material); +\endcode + +
+\section tkjoints Joints + +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 \ref tkevents). + +Joints may be defined as a part of a TkAsset, in which case they are consisdered "internal" joints. (See \ref tkasset_creation.) +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. + +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. + +\code +TkJointDesc desc; +desc.families[0] = &actor0->getFamily(); // Assume we have a valid actor0 pointer +desc.chunkIndices[0] = 1; // This chunk *must* be a support chunk in the asset that created desc.families[0] +desc.attachPositions[0] = physx::PxVec3(1.0f, 2.0f; 3.0f); // The attach position is in asset space +desc.families[1] = &actor1->getFamily(); // Assume we have a valid actor1 pointer... note, actor0 and actor1 could have the same family +desc.chunkIndices[1] = 10; // This chunk *must* be a support chunk in the asset that created desc.families[1] +desc.attachPositions[1] = physx::PxVec3(4.0f, 5.0f; 6.0f); // The attach position is in asset space + +// Create the external joint from the descriptor, which joins actor0 and actor1 +TkJoint* joint = framework->createJoint(desc); + +// Now join actor0 to the NRF +// desc.families[0] already contains actor0's family +desc.chunkIndices[0] = 2; // Again, this chunk must be a support chunk in the asset that created desc.families[0] +desc.attachPositions[0] = physx::PxVec3(0.0f, 0.0f; 0.0f); // The attach position is in asset space +desc.families[1] = nullptr; // Setting the family to NULL designates the world (NRF) +// The value of desc.chunkIndices[1] is not used, since desc.families[1] is NULL +desc.attachPositions[1] = physx::PxVec3(0.0f, 0.0f, 10.0f); // Attach position in the world + +// Create the external joint which joins actor0 to the world +TkJoint* jointNRF = framework->createJoint(desc); +\endcode + +
+\subsection releasing_joints Releasing Joints + +TkJoints are not released by Blast&tm;, 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. + +\code +joint->release(); +\endcode + +Note, this method can be called at any time, 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. + +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 block allocated 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. This is true even if the internal joints become "external" from actor splitting. Joints +that become external are still associated with a single family and their memory still resides with that family. + +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. + +
+\section tkevents Events + +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. + +Events are broadcast to listeners which implement the TkEventListener interface. Listeners are held by TkFamily objects. During +a TkGroup::endProcess call (see \ref tkgroups), relevant events are broadcast to the listeners in the families associated with the actors +in the group. + +A typical user's receiver implementation might take on the form shown below. + +\code +class MyActorAndJointListener : public TkEventListener +{ + // TkEventListener interface + void receive(const TkEvent* events, uint32_t eventCount) override + { + // Events are batched into an event buffer. Loop over all events: + for (uint32_t i = 0; i < eventCount; ++i) + { + const TkEvent& event = events[i]; + + // See TkEvent documentation for event types + switch (event.type) + { + case TkSplitEvent::EVENT_TYPE: // A TkActor has split into smaller actors + { + const TkSplitEvent* splitEvent = event.getPayload(); // Split event payload + + // The parent actor may no longer be valid. Instead, we receive the information it held + // which we need to update our app's representation (e.g. removal of the corresponding physics actor) + myRemoveActorFunction(splitEvent->parentData.family, splitEvent->parentData.index, splitEvent->parentData.userData); + + // The split event contains an array of "child" actors that came from the parent. These are valid + // TkActor pointers and may be used to create physics and graphics representations in our application + for (uint32_t j = 0; j < splitEvent->numChildren; ++j) + { + myCreateActorFunction(splitEvent->children[j]); + } + } + break; + + case TkJointUpdateEvent::EVENT_TYPE: + { + const TkJointUpdateEvent* jointEvent = event.getPayload(); // Joint update event payload + + // Joint events have three subtypes, see which one we have + switch (jointEvent->subtype) + { + case TkJointUpdateEvent::External: + myCreateJointFunction(jointEvent->joint); // An internal joint has been "exposed" (now joins two different actors). Create a physics joint. + break; + case TkJointUpdateEvent::Changed: + myUpdatejointFunction(jointEvent->joint); // A joint's actors have changed, so we need to update its corresponding physics joint. + break; + case TkJointUpdateEvent::Unreferenced: + myDestroyJointFunction(jointEvent->joint); // This joint is no longer referenced, so we may delete the corresponding physics joint. + break; + } + } + + // Unhandled: + case TkFractureCommands::EVENT_TYPE: + case TkFractureEvents::EVENT_TYPE: + default: + break; + } + } + } +}; +\endcode + +Whenever a new TkActor is created by the user (via TkFramework::createActor, see \ref tkasset_instancing), its newly-made family should +be given whatever listeners the user wishes to attach. For example, + +\code +TkActor* actor = framework->createActor(actorDesc); + +actor->getFamily().addListener(myListener); // myListener is an object which implements TkEventListener (see MyActorAndJointListener above, for example) +\endcode + +Listeners may also be removed from families at any time. + +
+\section tktypes Object and Type Identification + +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 NvBlastID for each object. The NvBlastID +is a 128-bit identifier. TkIdentifiable objects are tracked by the TkFramework, which may be used to look up an object by its NvBlastID. + +Upon creation, TkIdentifiable objects are given a GUID, a unique NvBlastID. The user is welcome to change the object's guid at any time, with +the restriction that the GUID cannot be all zero bytes. + +With an object's GUID, one may look up the object using the TkFramework function findObjectByID: + +\code +TkIdentifiable* object = framework->findObjectByID(id); // id = an NvBlastID GUID +\endcode + +If the object is found, a non-NULL pointer will be returned. + +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 + +\code +const TkType* assetType = framework->getType(TkTypeIndex::Asset); +\endcode + +The type interface may be used: + + - to access class-specific object lists in the framework, + - identify the class of a TkIdentifiable obtained through ID lookup or deserialization, or + - to obtain the class's name and format version number. + +For example, to access a list of all families: + +\code +// Get the TkFamily type interface +const TkType* familyType = framework->getType(TkTypeIndex::Family); + +// Get the family count to allocate a buffer +const uint32_t familyCount = framework->getObjectCount(familyType); +std::vector families(familyCount); + +// Write the families to the buffer +const uint32_t familiesFound = framework->getObjects(families.data(), familyCount, familyType); +\endcode + +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: + +\code +uint32_t familiesFound; +uint32_t totalFamilyCount = 0; +do +{ + // Write to a fixed-size buffer + TkIdentifiable* familyBuffer[16]; + familiesFound = framework->getObjects(familyBuffer, 16, familyType, totalFamilyCount); + totalFamilyCount += familiesFound; + + // Process the families found so far + myProcessFamiliesFunction(familyBuffer, familiesFound); +} while (familiesFound == 16); +\endcode + +To use the type interface to identify a class, perhaps after serialization or lookup by ID, one may do something like: + +\code +\\ Assume we have a TkIdentifiable pointer called "object" + +// Get the type interfaces of interest +const TkType* assetType = framework->getType(TkTypeIndex::Asset); +const TkType* familyType = framework->getType(TkTypeIndex::Family); + +if (object->getType() == *assetType) +{ + TkAsset* asset = static_cast(object); + + // Process the object as a TkAsset +} +if (object->getType() == *familyType) +else +{ + TkFamily* family = static_cast(object); + + // Process the object as a TkFamily +} +\endcode + +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. + +Finally, one may query the class for its current format version number using TkType::getVersion(). + +
+*/ -- cgit v1.2.3