Houdini Engine 6.2
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
Groups

About Houdini Groups

Houdini groups can contain primitives, points, and edges. Primitives can be whole polygon meshes, single polygons, volumes, curves, spheres, and so on. It is possible, for example, to have a single group contain some of the polygons from one mesh, some of the polygons from another mesh, a volume, and a curve, all at the same time.

It is up to the asset maker to use groups as they see fit but the most common use case for primitive groups is assigning multiple textures to the same polygon mesh. This is the reason why we by default split polygon meshes by group. See Parts for more information on this splitting.

Query Group Information

Get Group Names

You query information on groups by first getting a list of group names per Geo and per HAPI_GroupType, using HAPI_GetGroupNames(). The number of groups on a geo can be found by calling HAPI_GeoInfo_GetGroupCountByType() on its HAPI_GeoInfo or directly from:

Here's an example of getting group names:

// Load the library from file.
HAPI_AssetLibraryId library_id = -1;
HAPI_Result result =
hapiTestSession, "HAPI_Test_Groups_AllTypes.otl",
false, &library_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Instantiate the asset.
HAPI_NodeId node_id = -1;
result = HAPI_CreateNode(
hapiTestSession, -1, "Object/HAPI_Test_Groups_AllTypes",
nullptr, true, &node_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
{ // Point Groups
// Get our object info.
HAPI_ObjectInfo object_info;
HAPI_TEST_ASSERT( HAPIgetObjectInfoOnNode(
node_id, "PointsOnly", &object_info ) );
// Get geo info.
HAPI_GeoInfo geo_info;
hapiTestSession, object_info.nodeId, &geo_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get group names.
std::vector< HAPI_StringHandle > group_names(
geo_info.pointGroupCount );
hapiTestSession,
geo_info.nodeId,
group_names.data(),
geo_info.pointGroupCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Test them.
bool foundX = false;
bool foundZ = false;
for ( auto name : group_names )
{
if ( HAPItestGetString( name ) == "positiveX" )
foundX = true;
if ( HAPItestGetString( name ) == "positiveZ" )
foundZ = true;
}
HAPI_TEST_ASSERT( foundX );
HAPI_TEST_ASSERT( foundZ );
}
{ // Primitive Groups
// Get our object info.
HAPI_ObjectInfo object_info;
HAPI_TEST_ASSERT( HAPIgetObjectInfoOnNode(
node_id, "PrimitivesAndPoints", &object_info ) );
// Get geo info.
HAPI_GeoInfo geo_info;
hapiTestSession, object_info.nodeId, &geo_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get group names.
std::vector< HAPI_StringHandle > group_names(
geo_info.primitiveGroupCount );
hapiTestSession,
geo_info.nodeId,
group_names.data(),
geo_info.primitiveGroupCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Test them.
bool found = false;
for ( auto name : group_names )
if ( HAPItestGetString( name ) == "positiveZprim" )
{
found = true;
break;
}
HAPI_TEST_ASSERT( found );
}

Get Group Membership

You then get the membership information for the groups you're interested in, per Part this time, using HAPI_GetGroupMembership(). The membership information is a list of integers, one for each element (according to HAPI_GroupType), where 1 means the element is contained in the group while 0 means the element is not contained in the group. The size of this array is the same as HAPI_PartInfo_GetElementCountByGroupType() given the HAPI_PartInfo of the part you queried and the HAPI_GroupType.

As a helper flag, you can pass a bool pointer membership_array_all_equal to HAPI_GetGroupMembership() to see whether all the membership values are 1 or all of them are 0 without checking each one yourself.

Here's an example of getting group membership:

// Load the library from file.
HAPI_AssetLibraryId library_id = -1;
HAPI_Result result =
hapiTestSession, "HAPI_Test_Groups_AllTypes.otl",
false, &library_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Instantiate the asset.
HAPI_NodeId node_id = -1;
result = HAPI_CreateNode(
hapiTestSession, -1, "Object/HAPI_Test_Groups_AllTypes",
nullptr, true, &node_id );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
{ // Point Groups
// Get our object info.
HAPI_ObjectInfo object_info;
HAPI_TEST_ASSERT( HAPIgetObjectInfoOnNode(
node_id, "PointsOnly", &object_info ) );
// Get display sop.
HAPI_GeoInfo geo_info;
hapiTestSession, object_info.nodeId, &geo_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get part info.
HAPI_PartInfo part_info;
result = HAPI_GetPartInfo(
hapiTestSession, geo_info.nodeId, 0, &part_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get group partial membership.
std::vector< int > partial_group_membership( part_info.pointCount );
bool membership_array_all_equal = true;
hapiTestSession, geo_info.nodeId, 0,
HAPI_GROUPTYPE_POINT, "positiveX",
&membership_array_all_equal,
partial_group_membership.data(),
0, part_info.pointCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( membership_array_all_equal == false );
// Check membership.
for ( int i = 0; i < partial_group_membership.size(); ++i )
{
if ( i == 2 || i == 3 || i == 6 || i == 7 ||
i == 10 || i == 11 || i == 14 || i == 15 )
{
HAPI_TEST_ASSERT( partial_group_membership[ i ] == 1 );
}
else
HAPI_TEST_ASSERT( partial_group_membership[ i ] == 0 );
}
// Get group full membership.
std::vector< int > full_group_membership( part_info.pointCount );
membership_array_all_equal = false;
hapiTestSession, geo_info.nodeId, 0,
HAPI_GROUPTYPE_POINT, "pointsAll",
&membership_array_all_equal,
full_group_membership.data(),
0, part_info.pointCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( membership_array_all_equal == true );
// Check membership.
for ( auto m : full_group_membership )
HAPI_TEST_ASSERT( m == 1 );
}
{ // Primitive Groups
// Get our object info.
HAPI_ObjectInfo object_info;
HAPI_TEST_ASSERT( HAPIgetObjectInfoOnNode(
node_id, "PrimitivesAndPoints", &object_info ) );
// Get display sop.
HAPI_GeoInfo geo_info;
hapiTestSession, object_info.nodeId, &geo_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get part info.
HAPI_PartInfo part_info;
result = HAPI_GetPartInfo(
hapiTestSession, geo_info.nodeId, 0, &part_info );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
// Get group partial membership.
std::vector< int > partial_group_membership( part_info.faceCount );
bool membership_array_all_equal = true;
hapiTestSession, geo_info.nodeId, 0,
HAPI_GROUPTYPE_PRIM, "positiveZprim",
&membership_array_all_equal,
partial_group_membership.data(),
0, part_info.faceCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( membership_array_all_equal == false );
// Check membership.
for ( int i = 0; i < partial_group_membership.size(); ++i )
{
if ( i == 7 || i == 9 || i >= 11 )
HAPI_TEST_ASSERT( partial_group_membership[ i ] == 1 );
else
HAPI_TEST_ASSERT( partial_group_membership[ i ] == 0 );
}
// Get group full membership.
std::vector< int > full_group_membership( part_info.faceCount );
membership_array_all_equal = false;
hapiTestSession, geo_info.nodeId, 0,
HAPI_GROUPTYPE_PRIM, "primAll",
&membership_array_all_equal,
full_group_membership.data(),
0, part_info.faceCount );
HAPI_TEST_ASSERT( result == HAPI_RESULT_SUCCESS );
HAPI_TEST_ASSERT( membership_array_all_equal == true );
// Check membership.
for ( auto m : full_group_membership )
HAPI_TEST_ASSERT( m == 1 );
}

Adding Groups

You can only add groups and set group memberships on input nodes. See Marshalling Geometry Into Houdini.

To add a group to an input node call HAPI_AddGroup() and give it the desired HAPI_GroupType and group name. Then, set the group's membership using HAPI_SetGroupMembership(), with the same HAPI_GroupType and group name as well as an integer array containing the memberships. This array should be the size given by HAPI_PartInfo_GetElementCountByGroupType() on the HAPI_PartInfo you used with HAPI_SetPartInfo() and your HAPI_GroupType.

Edge Groups

Houdini does not provide an explicit edge representation to the user. Instead, edges in Houdini are implicitly defined by pairs of points. Because of this, interacting with edge groups through HAPI differs in some respects from how you would interact with point and primitive groups.

Just like point and primitive groups, you can query information on edge groups by first getting a list of edge group names per Geo using HAPI_GetGroupNames(). The number of edge groups on a geo can be found by calling HAPI_GeoInfo_GetGroupCountByType() on its HAPI_GeoInfo or directly from:

Note that if you're getting the edge group count of input geometry, the number of edges will not be available until after the geometry has been committed by HAPI_CommitGeo().

Before you can query the edge group membership information, you must first get the number of edges in the edge group by calling HAPI_GetEdgeCountOfEdgeGroup(). This method returns the number of edges in the group. When you are allocating the array to hold the edge group membership, its size must be twice the edge count in order to hold a point pair for each edge. You can get the edges using the HAPI_GetGroupMembership() method. This method will fill the membership array with pairs of points that represent the edges that belong to the edge group.

The same process for adding and setting point and primitive groups can be used for edge groups. HAPI_AddGroup() is used to add the group and HAPI_SetGroupMembership() is used to send the point pairs defining each edge in the group.