Houdini Engine 1.9
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
Asset Inputs Samples

For documentation on the asset inputs APIs, see Asset Inputs.

Marshalling Geometry Into Houdini

For documentation on marshalling geometry into Houdini, see Marshalling Geometry Into Houdini.

Below is a code snippet that marshals in the simplest of geometry - a triangle - then proceeds attach some string attrbutes onto each point of the triangle, and finally dump the resulting scene into a hip file so it can be opened and viewed in Houdini.

#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int
main( int argc, char **argv )
{
HAPI_CookOptions_Init( &cookOptions );
ENSURE_SUCCESS ( HAPI_Initialize( NULL, NULL, &cookOptions, true, -1 ) );
HAPI_AssetId geoCreatorId;
ENSURE_SUCCESS( HAPI_CreateInputAsset( &geoCreatorId, NULL ) );
ENSURE_SUCCESS( HAPI_CookAsset( geoCreatorId, NULL ) );
wait_for_cook();
newPart.vertexCount = 3;
newPart.pointCount = 3;
newPart.faceCount = 1;
newPart.isCurve = false;
ENSURE_SUCCESS( HAPI_SetPartInfo( geoCreatorId, 0, 0, &newPart ) );
pointInfo.count = 3; // 3 points
pointInfo.tupleSize = 3; // 3 floats per point (x, y, z)
pointInfo.exists = true;
ENSURE_SUCCESS( HAPI_AddAttribute( geoCreatorId, 0, 0, "P", &pointInfo ) );
float positions[ 9 ] = { 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f };
ENSURE_SUCCESS( HAPI_SetAttributeFloatData(
geoCreatorId, 0, 0, "P", &pointInfo, positions, 0, 3 ) );
int vertices[ 3 ] = { 0, 1, 2 };
ENSURE_SUCCESS( HAPI_SetVertexList( geoCreatorId, 0, 0, vertices, 0, 3 ) );
int face_counts[ 1 ] = { 3 }; // 3 edges for the first face (the only face)
ENSURE_SUCCESS( HAPI_SetFaceCounts( geoCreatorId, 0, 0, face_counts, 0, 1 ) );
char** strs = new char*[3];
strs[ 0 ] = _strdup( "str1" );
strs[ 1 ] = _strdup( "str2" );
strs[ 2 ] = _strdup( "str3" );
pointInfo.count = 3; // 3 points
pointInfo.tupleSize = 1;
pointInfo.exists = true;
ENSURE_SUCCESS( HAPI_AddAttribute( geoCreatorId, 0, 0, "strData", &pointInfo ) );
HAPI_AttributeInfo attributeInfo;
attributeInfo.exists = true;
attributeInfo.owner = HAPI_ATTROWNER_POINT;
attributeInfo.count = 3;
attributeInfo.tupleSize = 1;
ENSURE_SUCCESS( HAPI_SetAttributeStringData( geoCreatorId, 0, 0, "strData", &attributeInfo, (const char**) strs, 0, 3 ) );
ENSURE_SUCCESS( HAPI_CommitGeo( geoCreatorId, 0, 0 ) );
ENSURE_SUCCESS( HAPI_SaveHIPFile( "testoutput.hip" ) );
return 0;
}
static void
wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static std::string
get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string
get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static void dump_asset_materials( int asset_id, const HAPI_AssetInfo &asset_info );
static void dump_part_diffuse_texturemap(
int asset_id, int object_id, int geo_id, int part_id );
static void dump_part_mantra_render(
int asset_id, int object_id, int geo_id, int part_id );
static void extract_image_planes( int asset_id,
const HAPI_MaterialInfo & material_info,
const char * base_file_name );
static std::string get_string( HAPI_StringHandle string_handle );
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int main( int argc, char **argv )
{
const char *otl_file = argc == 2 ? argv[ 1 ] : "C:/test/SideFX__spaceship.otl";
ENSURE_SUCCESS( HAPI_Initialize(
NULL,
/*dso_search_path=*/ NULL,
&cook_options,
/*use_cooking_thread=*/ true,
/*cooking_thread_max_size=*/ -1 ) );
int library_id;
int asset_id;
otl_file,
true,
&library_id ) != HAPI_RESULT_SUCCESS )
{
cout << "Could not load " << otl_file << endl;
exit( 1 );
}
HAPI_StringHandle asset_name_sh;
ENSURE_SUCCESS( HAPI_GetAvailableAssets( library_id, &asset_name_sh, 1 ) );
std::string asset_name = get_string( asset_name_sh );
asset_name.c_str(),
/* cook_on_load */ true,
&asset_id ) != HAPI_RESULT_SUCCESS )
{
cout << "Could not instantiate asset " << asset_name << endl;
exit( 1 );
}
wait_for_cook();
// Retrieve information about the asset.
HAPI_AssetInfo asset_info;
ENSURE_SUCCESS( HAPI_GetAssetInfo( asset_id, &asset_info ) );
// Print information about the geometry contained inside the asset.
dump_asset_materials( asset_id, asset_info );
ENSURE_SUCCESS( HAPI_Cleanup() );
return 0;
}
static void wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static void dump_asset_materials( int asset_id, const HAPI_AssetInfo &asset_info )
{
HAPI_ObjectInfo * object_infos =
new HAPI_ObjectInfo[ asset_info.objectCount ];
ENSURE_SUCCESS( HAPI_GetObjects(
asset_id, object_infos, /*start=*/ 0, asset_info.objectCount ) );
for ( int object_index = 0; object_index < asset_info.objectCount;
++object_index )
{
HAPI_ObjectInfo &object_info = object_infos[object_index];
for ( int geo_index = 0; geo_index < object_info.geoCount;
++geo_index )
{
HAPI_GeoInfo geo_info;
ENSURE_SUCCESS( HAPI_GetGeoInfo(
asset_id, object_info.id, geo_index, &geo_info ) );
for ( int part_index = 0; part_index < geo_info.partCount;
++part_index )
{
dump_part_diffuse_texturemap(
asset_id, object_info.id, geo_info.id, part_index );
dump_part_mantra_render(
asset_id, object_info.id, geo_info.id, part_index );
}
}
}
delete [] object_infos;
}
static int find_parm_index( HAPI_NodeInfo & node_info, HAPI_ParmInfo *parm_infos, const char * parm_name_in )
{
int parm_index = -1;
for ( int i=0; i < node_info.parmCount; ++i )
{
std::string parm_name = get_string( parm_infos[ i ].nameSH );
if ( parm_name == parm_name_in )
{
parm_index = i;
break;
}
}
return parm_index;
}
static void extract_image_planes( int asset_id,
const HAPI_MaterialInfo & material_info,
const char * base_file_name )
{
HAPI_ImageInfo image_info;
ENSURE_SUCCESS( HAPI_GetImageInfo( asset_id, material_info.id, & image_info ) );
std::string image_format_name = get_string( image_info.imageFileFormatNameSH );
cout << "Image width=" << image_info.xRes << " height=" << image_info.yRes <<
" Format:" << image_format_name << endl;
int num_image_planes;
ENSURE_SUCCESS( HAPI_GetImagePlaneCount( asset_id, material_info.id, &num_image_planes ) );
cout << "Number of image planes" << num_image_planes << endl;
int * image_planes = new int[ num_image_planes ];
HAPI_GetImagePlanes( asset_id, material_info.id, image_planes, num_image_planes );
for( int ii = 0; ii < num_image_planes; ii++ )
{
std::string image_plane_name = get_string( image_planes[ii] );
cout << "Imange plane [" << ii << "] = " << image_plane_name << endl;
int destination_file_path;
std::string file_name = base_file_name + image_plane_name;
HAPI_ExtractImageToFile( asset_id, material_info.id,
image_plane_name.c_str(),
"C:/test",
file_name.c_str(),
&destination_file_path );
std::string destination_file_path_str = get_string( destination_file_path );
cout << "File written to " << destination_file_path_str << endl;
}
delete[] image_planes;
}
static void dump_part_mantra_render(
int asset_id, int object_id, int geo_id, int part_id )
{
cout << "object " << object_id << ", geo " << geo_id
<< ", part " << part_id << endl;
HAPI_PartInfo part_info;
ENSURE_SUCCESS( HAPI_GetPartInfo(
asset_id, object_id, geo_id, part_id, &part_info ) );
HAPI_MaterialId material_id = -1;
HAPI_MaterialInfo material_info;
asset_id, object_id, geo_id, part_id, NULL, &material_id, 0, 1 );
HAPI_GetMaterialInfo( asset_id, material_id, &material_info );
if( !material_info.exists )
{
cout << "No material found:" << "object " << object_id << ", geo " << geo_id
<< ", part " << part_id << endl;
return;
}
HAPI_GlobalNodes global_nodes;
HAPI_GetGlobalNodes( &global_nodes );
HAPI_NodeInfo node_info;
ENSURE_SUCCESS( HAPI_GetNodeInfo( global_nodes.mantraRenderer, &node_info ) );
// Get information about all the parameters.
HAPI_ParmInfo *parm_infos = new HAPI_ParmInfo[ node_info.parmCount ];
ENSURE_SUCCESS( HAPI_GetParameters(
global_nodes.mantraRenderer, parm_infos, /*start=*/ 0, node_info.parmCount ) );
int gamma_parm_index = find_parm_index( node_info, parm_infos, "vm_gamma" );
if( gamma_parm_index >=0 )
{
float gamma_value = 2.2f;
&gamma_value,
parm_infos[gamma_parm_index].floatValuesIndex,
1 );
}
HAPI_RenderMaterialToImage( asset_id, material_info.id, HAPI_SHADER_MANTRA );
extract_image_planes( asset_id, material_info, "spaceship_normal_" );
}
static void dump_part_diffuse_texturemap(
int asset_id, int object_id, int geo_id, int part_id )
{
cout << "object " << object_id << ", geo " << geo_id
<< ", part " << part_id << endl;
HAPI_PartInfo part_info;
ENSURE_SUCCESS( HAPI_GetPartInfo(
asset_id, object_id, geo_id, part_id, &part_info ) );
HAPI_MaterialId material_id = -1;
HAPI_MaterialInfo material_info;
asset_id, object_id, geo_id, part_id, NULL, &material_id, 0, 1 );
HAPI_GetMaterialInfo( asset_id, material_id, &material_info );
if( !material_info.exists )
{
cout << "No material found:" << "object " << object_id << ", geo " << geo_id
<< ", part " << part_id << endl;
return;
}
HAPI_NodeInfo node_info;
ENSURE_SUCCESS( HAPI_GetNodeInfo( material_info.nodeId, &node_info ) );
// Get information about all the parameters.
HAPI_ParmInfo *parm_infos = new HAPI_ParmInfo[ node_info.parmCount ];
ENSURE_SUCCESS( HAPI_GetParameters(
material_info.nodeId, parm_infos, /*start=*/ 0, node_info.parmCount ) );
int base_color_map_parm_index = find_parm_index( node_info, parm_infos, "baseColorMap" );
if( base_color_map_parm_index < 0 )
{
cout << "Could not find parameter for diffuse texture map" << endl;
return;
}
ENSURE_SUCCESS( HAPI_RenderTextureToImage(
asset_id, material_info.id,
parm_infos[ base_color_map_parm_index ].id ) );
extract_image_planes( asset_id, material_info, "spaceship_baseColorMap_" );
}
static std::string get_string( HAPI_StringHandle string_handle )
{
// A string handle of 0 means an invalid string handle -- similar to
// a null pointer. Since we can't return NULL, though, return an empty
// string.
if ( string_handle == 0 )
return "";
int buffer_length;
ENSURE_SUCCESS( HAPI_GetStringBufLength( string_handle, &buffer_length ) );
char * buf = new char[ buffer_length ];
ENSURE_SUCCESS( HAPI_GetString( string_handle, buf, buffer_length ) );
std::string result( buf );
delete[] buf;
return result;
}
static std::string get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}

Marshalling Point Clouds

For documentation on marshalling point clouds into Houdini, see Marshalling Point Clouds.

The following sample showscases marshalling of a point cloud into Houdini Engine:

#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int
main( int argc, char **argv )
{
HAPI_CookOptions_Init( &cookOptions );
cookOptions.maxVerticesPerPrimitive = 4;
ENSURE_SUCCESS( HAPI_Initialize( NULL, NULL, &cookOptions, true, -1 ) );
HAPI_AssetId geoCreatorId;
ENSURE_SUCCESS( HAPI_CreateInputAsset( &geoCreatorId, NULL ) );
ENSURE_SUCCESS( HAPI_CookAsset( geoCreatorId, NULL ) );
wait_for_cook();
newPart.vertexCount = 0;
newPart.pointCount = 8;
newPart.faceCount = 0;
newPart.isCurve = false;
ENSURE_SUCCESS( HAPI_SetPartInfo( geoCreatorId, 0, 0, &newPart ) );
pointInfo.count = 8; // 8 points
pointInfo.tupleSize = 3; // 3 floats per point (x, y, z)
pointInfo.exists = true;
ENSURE_SUCCESS (HAPI_AddAttribute( geoCreatorId, 0, 0, "P", &pointInfo ) );
float positions[ 24 ] = { 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f
};
ENSURE_SUCCESS( HAPI_SetAttributeFloatData( geoCreatorId, 0, 0, "P", &pointInfo, positions, 0, 8 ) );
ENSURE_SUCCESS( HAPI_CommitGeo( geoCreatorId, 0, 0 ) );
ENSURE_SUCCESS( HAPI_SaveHIPFile( "C:\\test\\testoutput.hip" ) );
return 0;
}
static void
wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static std::string
get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string
get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}

Connecting Assets

For documentation on connecting assets, see Connecting Assets.

The sample below marshals a cube into Houdini Engine, then proceeds to connect that cube to the subdivde node in Houdini. Note that the subdivide node is a standard Houdini node, we did not need to first load its definition from file with HAPI_LoadAssetLibraryFromFile(). The result is then dumped to a file so it can be viewed in Houdini:

#include <HAPI/HAPI.h>
#include <stdlib.h>
#include <iostream>
#include <string>
#include <vector>
using namespace std;
#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_error() << endl; \
exit( 1 ); \
}
#define ENSURE_COOK_SUCCESS( result ) \
if ( (result) != HAPI_STATE_READY ) \
{ \
cout << "failure at " << __FILE__ << ":" << __LINE__ << endl; \
cout << get_last_cook_error() << endl; \
exit( 1 ); \
}
static std::string get_last_error();
static std::string get_last_cook_error();
static void wait_for_cook();
int
main( int argc, char **argv )
{
HAPI_CookOptions_Init( &cookOptions );
cookOptions.maxVerticesPerPrimitive = 4;
ENSURE_SUCCESS( HAPI_Initialize( NULL, NULL, &cookOptions, true, -1 ) );
HAPI_AssetId geoCreatorId;
ENSURE_SUCCESS( HAPI_CreateInputAsset( &geoCreatorId, NULL ) );
ENSURE_SUCCESS( HAPI_CookAsset( geoCreatorId, NULL ) );
wait_for_cook();
newPart.vertexCount = 24;
newPart.pointCount = 8;
newPart.faceCount = 6;
newPart.isCurve = false;
ENSURE_SUCCESS( HAPI_SetPartInfo( geoCreatorId, 0, 0, &newPart ) );
pointInfo.count = 8; // 8 points
pointInfo.tupleSize = 3; // 3 floats per point (x, y, z)
pointInfo.exists = true;
ENSURE_SUCCESS( HAPI_AddAttribute( geoCreatorId, 0, 0, "P", &pointInfo ) );
float positions[ 24 ] = { 0.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f,
1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f
};
ENSURE_SUCCESS( HAPI_SetAttributeFloatData(
geoCreatorId, 0, 0, "P", &pointInfo, positions, 0, 8 ) );
int vertices[ 24 ] = { 0, 2, 6, 4,
2, 3, 7, 6,
2, 0, 1, 3,
1, 5, 7, 3,
5, 4, 6, 7,
0, 4, 5, 1,
};
ENSURE_SUCCESS( HAPI_SetVertexList( geoCreatorId, 0, 0, vertices, 0, 24 ) );
int face_counts[ 6 ] = { 4, 4, 4, 4, 4, 4 }; // 4 verts for each face (quads)
HAPI_SetFaceCounts( geoCreatorId, 0, 0, face_counts, 0, 6 );
ENSURE_SUCCESS( HAPI_CommitGeo( geoCreatorId, 0, 0 ) );
HAPI_AssetId subdivideAssetId = -1;
ENSURE_SUCCESS( HAPI_InstantiateAsset( "Sop/subdivide", true, &subdivideAssetId ) );
ENSURE_SUCCESS( HAPI_ConnectAssetGeometry( geoCreatorId, 0, subdivideAssetId, 0 ) );
ENSURE_SUCCESS( HAPI_SaveHIPFile( "C:\\test\\testoutput.hip" ) );
return 0;
}
static void
wait_for_cook()
{
int status;
do
{
}
while ( status > HAPI_STATE_MAX_READY_STATE );
ENSURE_COOK_SUCCESS( status );
}
static std::string
get_last_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}
static std::string
get_last_cook_error()
{
int buffer_length;
char * buf = new char[ buffer_length ];
std::string result( buf );
delete[] buf;
return result;
}

The result of the hip file is shown below. We see the input asset we created, as well as the subdivide asset. The "GlobalNodes" is something that HAPI creates automatically when a new Houdini Engine session is started:

HAPI_AssetInputs_Result_of_Connecting1.png

Diving into the subdivide asset, we see that a subdivide SOP node was created, but with an object merge node automatically created by HAPI feeding into it, with the path of the object merge being set to the Input node:

HAPI_AssetInputs_Result_of_Connecting2.png

Finally, the result of the connected asset is seen:

HAPI_AssetInputs_Result_of_Connecting3.png