diff options
| author | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
|---|---|---|
| committer | Bryan Galdrikian <[email protected]> | 2017-02-24 09:32:20 -0800 |
| commit | e1bf674c16e3c8472b29574159c789cd3f0c64e0 (patch) | |
| tree | 9f0cfce09c71a2c27ff19589fcad6cd83504477c /docs/_source/api_ll_users_guide.txt | |
| parent | first commit (diff) | |
| download | blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.tar.xz blast-e1bf674c16e3c8472b29574159c789cd3f0c64e0.zip | |
Updating to [email protected] and [email protected] with a new directory structure.
NvBlast folder is gone, files have been moved to top level directory. README is changed to reflect this.
Diffstat (limited to 'docs/_source/api_ll_users_guide.txt')
| -rw-r--r-- | docs/_source/api_ll_users_guide.txt | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/docs/_source/api_ll_users_guide.txt b/docs/_source/api_ll_users_guide.txt new file mode 100644 index 0000000..33d12db --- /dev/null +++ b/docs/_source/api_ll_users_guide.txt @@ -0,0 +1,389 @@ +/*! \page pagellapi Low Level API (NvBlast) + +<b>Table of Contents</b> + +\subpage llintroduction + +\subpage include_and_library + +\subpage assets + +\subpage actors_and_families + +\subpage splitting + +<br> +\section llintroduction Introduction + +The low-level API is the core of Blast&tm; destruction. It is designed to be a minimal API that allows an experienced user to incorporate destruction +into their application. Summarizing what the low-level API has, or rather <em>doesn't</em> have: + +- There is no physics representation. The low-level API is agnostic with respect to any physics engine, and furthermore does not have +any notion of collision geometry. The NvBlastActor is an abstraction which is intended to correspond to a rigid body. However +it is up to the user to make that connection. The NvBlastActor references a list of visible chunk indices, which correspond to +NvBlastChunk data in the asset. The NvBlastChunk contains a userData field which can be used to associate collision +geometry with the actor based upon the visible chunks. The same is true for constraints created between actors. Bonds contain a +userData field that can be used to inform the user that actors should have joints created at a particular location. After that it is up to the +user to create the joint, and Blast&tm; does not manage them in any way. +- There is no graphics representation. Just as there is no notion of collision geometry, there is no notion of graphics geometry either. +The NvBlastChunk userData field (see the item above) can be used to associate graphics geometry with the actor based upon the visible chunks. +- There is no notion of threading. The API is a collection of free functions for which is is up to the user to call from appropriate threads. +Blast&tm; guarantees that it is safe to operate on different actors from different threads. +- There is no global memory manager, message handler, etc. Most functions take an optional message function pointer argument, in order to report +warnings or errors. Memory is managed by the user, and functions that build objects require an appropriately-sized memory block to be passed in. +A corresponding utility function that calculates the memory requirements is always present alongside such functions. Temporary storage needed by a +function is always handled via user-supplied scratch space. For scratch, there is always a corresponding "RequiredScratch" function +or documentation which lets the user know how much scratch space is needed based upon the function arguments. +- One form of serialization is simply handled as a memory copy. Data associated with an asset or family (see \ref pagedefinitions) is +available to the user, and may be copied and stored by the user. There are corresponding data association functions which may be used to recreate +assets and families. Families contain a number of actors and so this form of deserialization recreates all actors in the family. +These deserialization operations simply tie pointers in those objects to data within the given family. The families come with format +version numbers, and association will only occur when the version number matches the current version used by the SDK. +- Single-actor serialization and deserialization is supported. This is not as light-weight as family serialization, but may be a better serialization +model for a particular application. To deserialize a single actor, one must have a family to hold the actor, created from the appropriate +asset. If none exists already, the user may create an empty family. After that, all actors that had been in that family may be deserialized +into it one-at-a-time, in any order. +- No data format coversion is done. As mentioned above, data association will only occur with a current format version. It is up to extension +functions to perform data conversion. (See \ref pageextserialization.) + +<br> +\section include_and_library Linking and Header Files + +To use the low-level Blast&tm; SDK, the application need only inlclude the header NvBlast.h, found in the top-level <b>include</b> folder, and link +against the appropriate version of the NvBlast library. Depending on the platform and configuration, various suffixes will be added to the library +name. The general naming scheme is + +NvBlast(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. + +<br> +\section assets Creating an Asset from a Descriptor (Authoring) + +The NvBlastAsset is an opaque type pointing to an object constructed by Blast&tm; in memory allocated by the user. +To create an asset from a descriptor, use the function NvBlastAssetCreate. See the function documentation for a +description of its parameters. + +<b>N.B., there are strict rules for the ordering of chunks with an asset, and also conditions on the chunks marked as "support" +(using the NvBlastChunkDesc::SupportFlag). See the function documentation for these conditions. NvBlastAssetCreate does +<em>not</em> reorder chunks or modify support flags to meet these conditions. If the conditions are not met, NvBlastAssetCreate +fails and returns NULL. However, Blast&tm; provides helper functions to reorder chunk descriptors and modify the support flags +within those descriptors so that they are valid for asset creation. The helper functions return a mapping from the original +chunk ordering to the new chunk ordering, so that corresponding adjustments or mappings may be made for graphics and other data +the user associates with chunks.</b> + +Example code is given below. + +\code +std::vector<NvBlastChunkDesc> chunkDescs; +chunkDescs.resize( chunkCount ); // chunkCount > 0 + +chunkDescs[0].parentChunkIndex = UINT32_MAX; // invalid index denotes a chunk hierarchy root +chunkDescs[0].centroid[0] = 0.f; // centroid position in asset-local space +chunkDescs[0].centroid[1] = 0.f; +chunkDescs[0].centroid[2] = 0.f; +chunkDescs[0].volume = 1.f; // Unit volume +chunkDescs[0].flags = NvBlastChunkDesc::NoFlags; +chunkDescs[0].ID = 0; // User-supplied ID. For example, this can be the index of the chunkDesc. + // The ID can be left undefined. + +chunkDescs[1].parentChunkIndex = 0; // child of chunk described by chunkDescs[0] +chunkDescs[1].centroid[0] = 2.f; // centroid position in asset-local space +chunkDescs[1].centroid[1] = 4.f; +chunkDescs[1].centroid[2] = 6.f; +chunkDescs[1].volume = 1.0; // Unit volume +chunkDescs[1].flags = NvBlastChunkDesc::SupportFlag; // This chunk should be represented in the support graph +chunkDescs[1].ID = 1; + +// ... etc. + +std::vector<NvBlastBondDesc> bondDescs; +bondDescs.resize( bondCount ); // bondCount > 0 + +bondDescs[0].chunkIndices[0] = 1; // chunkIndices refer to chunk descriptor indices for support chunks +bondDescs[0].chunkIndices[1] = 2; +bondDescs[0].bond.m_normal[0] = 1.f; // normal in the +x direction +bondDescs[0].bond.m_normal[1] = 0.f; +bondDescs[0].bond.m_normal[2] = 0.f; +bondDescs[0].bond.m_area = 1.0; // unit area +bondDescs[0].bond.m_centroid[0] = 1.f; // centroid position in asset-local space +bondDescs[0].bond.m_centroid[1] = 2.f; +bondDescs[0].bond.m_centroid[2] = 3.f; +bondDescs[0].m_userData = 0; // this can be used to tell the user more information about this + // bond for example to create a joint when this bond breaks + +// ... etc. + +// Set the fields of the descriptor +NvBlastAssetDesc assetDesc; +assetDesc.chunkCount = chunkCount; +assetDesc.chunkDescs = chunkDescs.data(); +assetDesc.bondCount = bondCount; +assetDesc.bondDescs = bondDescs.data(); + +// Now ensure the support coverage in the chunk descriptors is exact, and the chunks are correctly ordered +std::vector<char> scratch( chunkCount * sizeof(NvBlastChunkDesc) ); // This is enough scratch for both NvBlastEnsureAssetExactSupportCoverage and NvBlastReorderAssetDescChunks +NvBlastEnsureAssetExactSupportCoverage( chunkDescs.data(), chunkCount, scratch.data(), nullptr ); +std::vector<uint32_t> map(chunkCount); // Will be filled with a map from the original chunk descriptor order to the new one +NvBlastReorderAssetDescChunks( chunkDescs.data(), chunkDescs, bondDescs.data(), bondCount, map, scratch.data(), nullptr ); + +// Create the asset +scratch.resize( NvBlastGetRequiredScratchForCreateAsset( &assetDesc ) ); // Provide scratch memory for asset creation +void* mem = malloc( NvBlastGetAssetMemorySize( &assetDesc ) ); // Allocate memory for the asset object +NvBlastAsset* asset = NvBlastCreateAsset( mem, &assetDesc, scratch.data(), nullptr ); // the log function (last argument) is optional +\endcode + +<br> +It should be noted that the geometric information (centroid, volume, area, normal) in chunks and bonds is only used by damage +shader functions (see \ref pageextshaders). Depending on the shader, some, all, or none of the geometric information will be needed. +The user may write damage shader functions that interpret this data in any way they wish. + +<br> +\subsection asset_copying Cloning an Asset (Serialization and Deserialization) + +To clone an asset, or equivalently serialize and deserialize it (as long as the deserialized asset is being created on a host with the +same data version and endianness), one only needs to copy the memory associated with the NvBlastAsset. + +\code +uint32_t assetSize = NvBlastAssetGetSize( data ); + +NvBlastAsset* newAsset = (NvBlastAsset*)malloc(assetSize); // NOTE: the memory buffer <em> must <\em> be 16-byte aligned! +memcpy( newAsset, asset, assetSize ); // this data may be copied into a buffer, stored to a file, etc. +\endcode + +N.B. the comment after the malloc call above. NvBlastAsset memory must be 16-byte aligned. + +<br> +\subsection asset_releasing Releasing an Asset + +Blast&tm low-level does no internal allocation; since the memory is allocated by the user, one simply has to free the memory they've +allocated. The asset pointer returned by NvBlastCreateAsset has the same numerical value as the mem block passed in (if the function +is successful, or NULL otherwise). So releasing an asset done as follows: + +\code +free( asset ); +\endcode + +<br> +\section actors_and_families Creating Actors and Families + +Actors live within a family created from asset data. To create an actor, one must first create a family. This family is used by the initial actor created from +the asset, as well as all of the descendent actors created by recursively fracturing the initial actor. Like assets, family allocation is done by the user. + +To create a family, use: + +\code +// Allocate memory for the family object - this depends on the asset being represented by the family. +void* mem = malloc( NvBlastAssetGetFamilyMemorySize( &asset ) ); + +NvBlastFamily* family = NvBlastAssetCreateFamily( mem, &asset, nullptr ); +\endcode + +When an actor is first created from an asset, it represents the root of the chunk hierarchy, that is the unfractured object. To create this actor, use: + +\code +// Set the fields of the descriptor +NvBlastActorDesc actorDesc; +actorDesc.asset = asset; // point to a valid asset +actorDesc.initialBondHealth = 1.0f; // this health value will be given to all bonds +actorDesc.initialChunkHealth = 1.0f; // this health value will be given to all lower-support chunks + +// Provide scratch memory +std::vector<char> scratch( NvBlastFamilyGetRequiredScratchForCreateFirstActor( &actorDesc ) ); + +// Create the first actor +NvBlastActor* actor = NvBlastFamilyCreateFirstActor( family, &actorDesc, scratch.data(), nullptr ); // ready to be associated with physics and graphics by the user +\endcode + +<br> +\subsection actor_copying Copying Actors (Serialization and Deserialization) + +There are two forms of serialization: family serialization and single actor serialization. Family serialization is extremely fast as it only requires a single +memory copy. All actors in the family may be saved, loaded, or copied at once in this way. + +<br> +\subsection family_serialization Family Serialization + +To serialize a family, use the family pointer which may be retrieved +from any active actor in the family if needed, using the NvBlastActorGetFamily function: + +\code +const NvBlastFamily* family = NvBlastActorGetFamily( &actor, nullptr ); +\endcode + +Then the size of the family may be obtained using: + +\code +size_t size = NvBlastFamilyGetSize( family, nullptr ); +\endcode + +Now this memory may be copied, saved to disk, etc. To clone the family, for example, we can duplicate the memory: + +\code +std::vector<char> buffer( size ); +NvBlastFamily* family2 = reinterpret_cast<NvBlastFamily*>( buffer.data() ); +memcpy( family2, family, size ); +\endcode + +<B>N.B.</B> If this data has been serialized from an external source, the family will not contain a valid reference to its associated asset. +The user <em>must</em> set the family's asset. The family does however contain the asset's GUID, to help the user match the correct asset +to the family. So one way of restoring the asset to the family follows: + +\code +const NvBlastGUID guid = NvBlastFamilyGetAssetGUID( family2, nullptr ); +// ... here the user must retrieve the asset using the GUID or by some other means +NvBlastFamilySetAsset( family2, asset, nullptr ); +\endcode + +The data in family2 will contain the same actors as the original family. To access them, use: + +\code +uint32_t actorCount = NvBlastFamilyGetActorCount( family2, nullptr ); +std::vector<NvBlastActor*> actors( actorCount ); +uint32_t actorsWritten = NvBlastFamilyGetActors( actors.data(), actorCount, family2, nullptr ); +\endcode + +In the code above, actorsWritten should equal actorCount. + +<br> +\subsection single_actor_serialization Single Actor Serialization + +To perform single-actor serialization, first find the buffer size required to store the serialization data: + +\code +size_t bufferSize = NvBlastActorGetSerializationSize( actor, nullptr ); +\endcode + +If you want to use an upper bound which will be large enough for any actor in a family, you may use: + +\code +size_t bufferSize = NvBlastAssetGetActorSerializationSizeUpperBound( asset, nullptr ); +\endcode + +Then create a buffer of that size and use NvBlastActorSerialize to write to the buffer: + +\code +std::vector<char> buffer( bufferSize ); +size_t bytesWritten = NvBlastActorSerialize( buffer, bufferSize, actor, nullptr ); +\endcode + +To deserialize the buffer, an appropriate family must be created. It must not already hold a copy of the actor. It must be formed +using the correct asset (the one that originally created the actor): + +\code +NvBlastFamily* family = NvBlastAssetCreateFamily( asset, malloc, nullptr ); +\endcode + +Then deserialize into the family: + +\code +NvBlastActor* newActor = NvBlastFamilyDeserializeActor( family, buffer.data(), nullptr ); +\endcode + +If newActor is not NULL, then the actor was successfully deserialized. + +<br> +\section actor_deactivating Deactivating an Actor + +Actors may not be released in the usual sense of deallocation. This is because actors' memory is stored as a block within the owning family. The +memory is only released when the family is released. However, one may deactivate an actor using NvBlastActorDeactivate. +This clears the actor's chunk lists and marks it as invalid, effectively disassociating it from the family. The user should consider this actor +to be destroyed. + +\code +bool success = NvBlastActorDeactivate( actor ); // actor should always be a pointer, as it is an opaque type +\endcode + +<br> +\subsection family_releasing Releasing a family + +As mentioned above, releasing an actor does not actually do any deallocation; it simply invalidates the actor within its family. +To actually deallocate memory, you must deallocate the family. Note, this will invalidate all actors in the family. This is +a fast way to delete all actors that were created from repeated fracturing of a single instance. As with NvBlastAsse, memory is +allocated by the user, so to release the family simply free that memory: + +\code +free( family ); +\endcode + +The family will <em>not</em> be automatically released when all actors within it are invalidated using NvBlastActorDeactivate. However, the user may keep track +of the number of active actors in a family using + +\code +uint32_t actorCount = NvBlastFamilyGetActorCount( family, nullptr ); +\endcode + +The result of the call above, actually a reference count for the family, is accurate even if actors are created and deleted from different threads. + + +<br> +\section splitting Damage and Fracturing + +Damaging and fracturing is a staged process. +In a first step, a \ref NvBlastDamageProgram creates lists of Bonds and Chunks to damage - so called Fracture Commands. +The lists are created from input specific to the NvBlastDamageProgram.<br> +NvBlastDamagePrograms are composed of a \ref NvBlastGraphShaderFunction and a +\ref NvBlastSubgraphShaderFunction operating on support graphs (support chunks and bonds) and disconnected subsupport chunks respectively. +An implementer can freely define the shader functions and paramters. +Different functions can have the effect of emulating different physical materials.<br> +Blast&tm; provides example implementations of such functions in \ref pageextshaders, see also NvBlastExtDamageShaders.h. +The NvBlastDamageProgram is used through \ref NvBlastActorGenerateFracture that will provide the necessary internal data for the NvBlastActor being processed. +The shader functions see the internal data as \ref NvBlastGraphShaderActor and \ref NvBlastSubgraphShaderActor respectively. + +The second stage is carried out with \ref NvBlastActorApplyFracture. This function takes the previously generated Fracture Commands and applies them to the NvBlastActor. +The result of every applied command is reported as a respective Fracture Event if requested. + +Fracture Commands and Fracture Events both are represented by \ref NvBlastFractureBuffers. +The splitting of the actor into child actors is not done until the third stage, \ref NvBlastActorSplit, is called. +Fractures may be repeatedly applied to an actor before splitting. + +The \ref NvBlastActorGenerateFracture, \ref NvBlastActorApplyFracture and \ref NvBlastActorSplit functions are profiled in Profile configurations. +This is done through a pointer to a NvBlastTimers struct passed into the functions. +If this pointer is not NULL, then timing values will be accumulated in the referenced struct. + +The following example illustrates the process: + +\code +// Step one: Generate Fracture Commands + +// Damage programs (shader functions), material properties and damage description relate to each other. +// Together they define how actors will break by generating the desired set of Fracture Commands for Bonds and Chunks. +NvBlastDamageProgram damageProgram = { GraphShader, SubgraphShader }; +NvBlastProgramParams programParams = { damageDescs, damageDescCount, materialProperties }; + +// Generating the set of Fracture Commands does not modify the NvBlastActor. +NvBlastActorGenerateFracture(fractureCommands, actor, damageProgram, &programParams, logFn, &timers); + + +// Step two: Apply Fracture Commands + +// Applying Fracture Commands does modify the state of the NvBlastActor. +// The Fracture Events report the resulting state of each Bond or Chunk involved. +// Chunks fractured hard enough will also fracture their children, creating Fracture Events for each. +NvBlastActorApplyFracture(fractureEvents, actor, fractureCommands, logFn, &timers); + + +// Step three: Splitting + +// The Actor may be split into all its smallest pieces. +uint32_t maxNewActorCount = NvBlastActorSplitMaxActorCount(actor); +std::vector<NvBlastActor*> newActors(maxNewActorCount); + +// Make this memory available to NvBlastSplitEvent. +NvBlastActorSplitEvent splitEvent; +splitEvent.newActors = newActors.data(); + +// Some temporary memory is necessary as well. +std::vector<char> scratch(NvBlastActorGetRequiredScratchForSplit(actor)); + +// New actors created are reported in splitEvent.newActors. +// If newActorCount != 0, then the old actor is deleted and is reported in splitEvent.deletedActor. +size_t newActorCount = NvBlastActorSplit(&splitEvent, actor, maxNewActorCount, scratch.data(), logFn, &timers); +\endcode + +<br> +*/ |