Houdini Engine 7.0
|
The most common way to load assets is by first loading an asset library file (one of: .otl, .otllc, .hda, or .hdalc). This library file can contain multiple Houdini assets (HDAs).
The first thing to do is call HAPI_LoadAssetLibraryFromFile(). This will give you back a HAPI_AssetLibraryId which is a handle to the library that was just loaded. Keep it safe. You can also use the equivalent memory based function, HAPI_LoadAssetLibraryFromMemory(). Keep in mind that this memory variant will still produce a file on disk somewhere so the performance benefits are minor at this time. It is purely here as a convenience.
allow_overwrite
parameter on either HAPI_LoadAssetLibraryFromFile() or HAPI_LoadAssetLibraryFromMemory() to control whether you want to allow overwriting asset definitions that have already been loaded from a different asset library file. If this flag is true and a clash is detected the function will return with a HAPI_RESULT_ASSET_DEF_ALREADY_LOADED result code.Next, query how many assets there are in the just-loaded library using HAPI_GetAvailableAssetCount(). Use the count to allocate an array of HAPI_StringHandle's and feed that into HAPI_GetAvailableAssets() to get the actual asset names.
Finally, feed any asset's name into HAPI_CreateNode(), exactly as given by HAPI_GetAvailableAssets(), to actually create your asset node in the underlying Houdini scene. Pass -1
for the parent_node_id
argument. It will figure out the parent node from the name.
Once HAPI_CreateNode() returns successfully, you will have a HAPI_NodeId (a typedefed int
) which is a handle to the underlying asset node. Hang on to this handle as it's the only way to talk to HAPI about the node you just created.
If the cook_on_creation
argument is true
, HAPI_CreateNode() will return immediately even in threaded mode (that is, use_cooking_thread
was set to true in HAPI_Initialize()). HAPI will create the node and cook it so that it is ready to use. This is really just calling HAPI_CookNode() for you. See Cooking on how to check progress.
If you choose to set cook_on_creation
to false you'll need to call HAPI_CookNode() first, before attempting to use the asset - see Cooking. However, you can still get some information about the instantiated asset via HAPI_GetAssetInfo() and you can use the asset node's HAPI_NodeId to change parameters on the asset before the first cook. To see if an asset node has ever been cooked there's a flag, HAPI_AssetInfo::hasEverCooked.
This HAPI_GetAssetInfo() function takes the HAPI_NodeId from the call to HAPI_CreateNode(), and fills in a HAPI_AssetInfo struct on successful return. HAPI_AssetInfo gives you basic, high level information about your asset such as the name of the asset, the asset label as defined in Houdini, the number of handles, and so on.
To get the node information, as a HAPI_NodeInfo, of the asset node, call HAPI_GetNodeInfo(). For asset nodes, you will probably want to look into the HAPI_NodeInfo::uniqueHoudiniNodeId member. The idea here is that in saving a session in the host application, one might just serialize all the data structures pertaining to HAPI, such as the HAPI_AssetInfo and HAPI_NodeInfo structs. On reloading of the saved file, there might not be a session of Houdini Engine currently running, or, even if there is, it might have different things loaded in it. We then need to establish whether the asset that has just been reloaded has a corresponding valid entry on the Houdini Engine side. The HAPI_NodeInfo::id is not sufficient in this case, as it may clash with other nodes across different sessions. Here is where the HAPI_NodeInfo::uniqueHoudiniNodeId comes in handy. Whenever any node is instantiated, Houdini Engine will also pass back Houdini's globally unique node id, which can be used later to determine whether the saved asset node has a valid conterpart on the Houdini Engine side. If not, then asset node needs to be re-instantiated.
Once an asset node is create, it needs to be cooked before its results are ready to be used. This is done by calling HAPI_CookNode().
In threaded mode, this cook happens asynchronously. Your next call should be to HAPI_GetStatus(), with HAPI_STATUS_COOK_STATE as the status_type
, which will return to you the current state of that cook. Keep calling HAPI_GetStatus() until it returns one of the READY
states - a state less than or equal to HAPI_STATE_MAX_READY_STATE. Here's what the different READY
states mean:
You can get even better information on cook progress using HAPI_GetStatusStringBufLength() followed by HAPI_GetStatusString() for current cook step descriptions and HAPI_GetCookingCurrentCount() / HAPI_GetCookingTotalCount() for an idea of percentage completion.
Here is a code snippet to show the status update loop in threaded mode:
Where each of ENSURE_SUCCESS
and ENSURE_COOK_SUCCESS
are macros:
In single threaded mode, the cook happens inside of HAPI_CookNode(), and HAPI_GetStatus() will immediately return HAPI_STATE_READY.
In both cases, even if you completely omit calling HAPI_GetStatus(), the next API method that you call that relies on the cooked results will block until the cook is finished.
It is generally important to check the return codes and error messages of all API calls but with HAPI_CookNode it is especially important. This is because if anything bad happened during the cook it means most if not all proceeding API calls on this node will fail or cause other problems. See Return Codes and Error Strings for details.
For all OBJ asset nodes there are two sets of transforms. First, there is the transform in the host environment, describing where asset sits in the host. Underneath the covers, however, there is another transform, which indicates where this asset OBJ node sits inside Houdini Engine (the underlying Houdini scene). Usually, these won't match up. For example a user could drag the asset to any location in the host but not have it move in the Houdini scene.
It is important to make sure that the two sets of transforms - the one in the host and the corresponding transform in the Houdini scene - match up. To this end, we have two functions:
The first of these queries where an asset OBJ node is in the Houdini scene and the second sets the location of the asset in the Houdini scene. When using these functions, please remember to account for the differences in axis orientation and handedness between your host application and Houdini. See Utility Functions.
All this is explained in more detail under: Object Transforms