Robert White

robert.white

About Me

Connect

LOCATION
Not Specified
WEBSITE

Houdini Skills

Availability

Not Specified

Recent Forum Posts

HAPI_SetHeightFieldData Jan. 30, 2018, 2:45 p.m.

Thanks for that, sorry about responding so late, my trial license ran out and I was waiting to get our actual license.

So I was trying you're updated version with 3.1 and running into some errors.
Finally worked through them all, and thought I'd post the fixed version.

The big gotcha seemed to be that volume visualization node, is created from “volumevisualization” and not “sop/volumevisualization”.

Also for completeness I added a transform node to act as parent for the other nodes, plus it orients the field properly when you open the hip file.

#include <HAPI/HAPI.h>
#include <iostream>
#include <string>
#include <vector>
#include <random>


#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
    std::cout << "Failure at " << __FILE__ << ": " << __LINE__ << std::endl; \
    std::cout << getLastError() << std::endl; \
    exit( 1 ); \
}

static std::string getLastError();
static std::string getString(HAPI_StringHandle stringHandle);

int
main(int argc, char ** argv)
{

	HAPI_CookOptions cookOptions = HAPI_CookOptions_Create();

	HAPI_Session session;

	HAPI_CreateInProcessSession(&session);

	ENSURE_SUCCESS(HAPI_Initialize(&session, &cookOptions, true, -1, nullptr, nullptr, nullptr, nullptr, nullptr));

	// Create a transform node, so that the field is oriented properly.
	HAPI_NodeId transform_node_id = -1;
	HAPI_NodeInfo transform_info;
	ENSURE_SUCCESS(HAPI_CreateNode(&session, -1, "SOP/xform", "ZX", true, &transform_node_id));
	ENSURE_SUCCESS(HAPI_SetParmFloatValue(&session, transform_node_id, "rx", 0, -90.0f));
	ENSURE_SUCCESS(HAPI_SetParmFloatValue(&session, transform_node_id, "ry", 0, -90.0f));
	ENSURE_SUCCESS(HAPI_CookNode(&session, transform_node_id, nullptr));
	ENSURE_SUCCESS(HAPI_GetNodeInfo(&session, transform_node_id, &transform_info));


	// Create the height field visualization, and connect to the xform node.
	HAPI_NodeId volume_visualization_id = -1;
	ENSURE_SUCCESS(HAPI_CreateNode(&session, transform_info.parentId, "volumevisualization", "Volvis", false, &volume_visualization_id));
	ENSURE_SUCCESS(HAPI_ConnectNodeInput(&session, transform_node_id, 0, volume_visualization_id));
	ENSURE_SUCCESS(HAPI_SetParmIntValue(&session, volume_visualization_id, "vismode", 0, 2));

	// Hook up the height portion
	HAPI_ParmId density_id = -1;
	HAPI_ParmInfo density_info = HAPI_ParmInfo_Create();
	ENSURE_SUCCESS(HAPI_GetParmIdFromName(&session, volume_visualization_id, "densityfield", &density_id));
	ENSURE_SUCCESS(HAPI_GetParmInfo(&session, volume_visualization_id, density_id, &density_info));
	ENSURE_SUCCESS(HAPI_SetParmStringValue(&session, volume_visualization_id, "height", density_id, 0));

	// Hooking up the mask portion
	HAPI_ParmId cdfield_id = -1;
	HAPI_ParmInfo cdfield_info = HAPI_ParmInfo_Create();
	ENSURE_SUCCESS(HAPI_GetParmIdFromName(&session, volume_visualization_id, "cdfield", &cdfield_id));
	ENSURE_SUCCESS(HAPI_GetParmInfo(&session, volume_visualization_id, cdfield_id, &cdfield_info));
	ENSURE_SUCCESS(HAPI_SetParmStringValue(&session, volume_visualization_id, "height", cdfield_id, 0));

	ENSURE_SUCCESS(HAPI_CookNode(&session, volume_visualization_id, nullptr));


	// Create a merge node, and connect it to the visualization node.
	HAPI_NodeId merge_node_id = -1;
	ENSURE_SUCCESS(HAPI_CreateNode(&session, transform_info.parentId, "merge", "MergeNode", false, &merge_node_id));
	ENSURE_SUCCESS(HAPI_ConnectNodeInput(&session, volume_visualization_id, 0, merge_node_id));

	// Input data creation.

	// Create the part info for the height and mask input volumes.
	HAPI_PartId part_id = 0;
	HAPI_PartInfo part = HAPI_PartInfo_Create();

	part.nameSH = 0;
	part.id = part_id;
	part.attributeCounts[HAPI_ATTROWNER_POINT] = 0;
	part.attributeCounts[HAPI_ATTROWNER_PRIM] = 1;
	part.attributeCounts[HAPI_ATTROWNER_VERTEX] = 0;
	part.attributeCounts[HAPI_ATTROWNER_DETAIL] = 0;
	part.pointCount = 0;
	part.vertexCount = 0;
	part.faceCount = 1;
	part.type = HAPI_PARTTYPE_VOLUME;

	// Create the input volume transform.
	HAPI_Transform transform = HAPI_Transform_Create();

	transform.scale[0] = 1000.0f;
	transform.scale[1] = 1000.0f;
	transform.scale[2] = 1.0f;

	// Create the input volume info
	HAPI_VolumeInfo input_volume_info = HAPI_VolumeInfo_Create();

	input_volume_info.xLength = 500;
	input_volume_info.yLength = 500;
	input_volume_info.zLength = 1;

	input_volume_info.minX = 0;
	input_volume_info.minY = 0;
	input_volume_info.minZ = 0;

	input_volume_info.type = HAPI_VOLUMETYPE_HOUDINI;
	input_volume_info.storage = HAPI_STORAGETYPE_FLOAT;
	input_volume_info.tupleSize = 1;
	input_volume_info.tileSize = 1;

	input_volume_info.hasTaper = false;
	input_volume_info.xTaper = 0.0;
	input_volume_info.yTaper = 0.0;


	// Create the height volume
	char * name = "height";
	int start = 0;
	HAPI_NodeId volume_node_id = -1;
	HAPI_GeoInfo volume_geo_info = HAPI_GeoInfo_Create();


	ENSURE_SUCCESS(HAPI_CreateInputNode(&session, &volume_node_id, name));
	ENSURE_SUCCESS(HAPI_CookNode(&session, volume_node_id, nullptr));

	ENSURE_SUCCESS(HAPI_GetDisplayGeoInfo(&session, volume_node_id, &volume_geo_info));
	ENSURE_SUCCESS(HAPI_ConnectNodeInput(&session, merge_node_id, 0, volume_geo_info.nodeId));

	HAPI_VolumeInfo heightfield_volume_info = input_volume_info;
	heightfield_volume_info.transform = transform;

	const int totalsize = (heightfield_volume_info.xLength * heightfield_volume_info.yLength);
	std::vector< float > heightfieldData(totalsize);

	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_real_distribution<> dis(1, 2);
	for (int n = 0; n < totalsize; ++n)
	{
		heightfieldData[n] = (float)dis(gen);
	}

	ENSURE_SUCCESS(HAPI_SetPartInfo(&session, volume_geo_info.nodeId, part.id, &part));
	ENSURE_SUCCESS(HAPI_SetVolumeInfo(&session, volume_geo_info.nodeId, part.id, &heightfield_volume_info));

	ENSURE_SUCCESS(HAPI_SetHeightFieldData(&session, volume_geo_info.nodeId, part.id, name, heightfieldData.data(), start, totalsize));

	ENSURE_SUCCESS(HAPI_CommitGeo(&session, volume_geo_info.nodeId));
	ENSURE_SUCCESS(HAPI_CookNode(&session, volume_geo_info.nodeId, nullptr));

	// Creating the Mask input
	char * maskname = "mask";
	HAPI_NodeId mask_volume_node_id = -1;
	HAPI_GeoInfo mask_volume_geo_info = HAPI_GeoInfo_Create();


	// Create the input node, and connect it to the merge node
	ENSURE_SUCCESS(HAPI_CreateInputNode(&session, &mask_volume_node_id, maskname));
	ENSURE_SUCCESS(HAPI_CookNode(&session, mask_volume_node_id, nullptr));

	ENSURE_SUCCESS(HAPI_GetDisplayGeoInfo(&session, mask_volume_node_id, &mask_volume_geo_info));
	ENSURE_SUCCESS(HAPI_ConnectNodeInput(&session, merge_node_id, 1, mask_volume_geo_info.nodeId));

	HAPI_VolumeInfo mask_volume_info = input_volume_info;
	mask_volume_info.transform = transform;

	// fill the mask with zeros
	std::vector< float > maskData(totalsize);
	for (int n = 0; n < totalsize; ++n)
	{
		maskData[n] = 0.0f;
	}

	// we can reuse the height part info here
	ENSURE_SUCCESS(HAPI_SetPartInfo(&session, mask_volume_geo_info.nodeId, part.id, &part));
	ENSURE_SUCCESS(HAPI_SetVolumeInfo(&session, mask_volume_geo_info.nodeId, part.id, &mask_volume_info));

	ENSURE_SUCCESS(HAPI_SetHeightFieldData(&session, mask_volume_geo_info.nodeId, part.id, maskname, maskData.data(), 0, totalsize));

	ENSURE_SUCCESS(HAPI_CommitGeo(&session, mask_volume_geo_info.nodeId));
	ENSURE_SUCCESS(HAPI_CookNode(&session, mask_volume_geo_info.nodeId, nullptr));


	// Cook and save the node out to a .hip file to prove this works.
	ENSURE_SUCCESS(HAPI_CookNode(&session, volume_visualization_id, nullptr));
	ENSURE_SUCCESS(HAPI_SaveHIPFile(&session, "height_field.hip", false));

	HAPI_Cleanup(&session);
	return 0;
}

static std::string
getLastError()
{
	int bufferLength;
	HAPI_GetStatusStringBufLength(nullptr, HAPI_STATUS_CALL_RESULT, HAPI_STATUSVERBOSITY_ERRORS, &bufferLength);

	char * buffer = new char[bufferLength];

	HAPI_GetStatusString(nullptr, HAPI_STATUS_CALL_RESULT, buffer, bufferLength);

	std::string result(buffer);
	delete[] buffer;

	return result;
}
static std::string
getString(HAPI_StringHandle stringHandle)
{
	if (stringHandle == 0)
	{
		return "";
	}

	int bufferLength;
	HAPI_GetStringBufLength(nullptr,
		stringHandle,
		&bufferLength);

	char * buffer = new char[bufferLength];

	HAPI_GetString(nullptr, stringHandle, buffer, bufferLength);

	std::string result(buffer);
	delete[] buffer;

	return result;
}

HAPI_SetHeightFieldData Sept. 20, 2017, 6:54 p.m.

So I was finally able to get something that worked.

Instead of pushing the data into a sop/heightfield, I created a an input node and gave it a HAPI_PARTTYPE_VOLUME.
The other missing parts seemed to be that I needed a volume visualization node, and that my volume info transforms all had scales of 0, which kind of made it hard to visualize anything.

In case anyone else runs into a similar problem, this is what finally worked.

If there is a smarter / better way to do this please let me know. I'm kind of flailing in the dark with the current examples.

#include <HAPI/HAPI.h>
#include <iostream>
#include <string>
#include <vector>
#include <random>


#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
    std::cout << "Failure at " << __FILE__ << ": " << __LINE__ << std::endl; \
    std::cout << getLastError() << std::endl; \
    exit( 1 ); \
}

static std::string getLastError();
static std::string getString( HAPI_StringHandle stringHandle );

int
main( int argc, char ** argv )
{

	HAPI_CookOptions cookOptions = HAPI_CookOptions_Create();

	HAPI_Session session;

	HAPI_CreateInProcessSession( &session );

	ENSURE_SUCCESS( HAPI_Initialize( &session, &cookOptions, true, -1, nullptr, nullptr, nullptr, nullptr, nullptr ) );
	
	HAPI_NodeId volume_visualization_id = -1;
	HAPI_NodeId height_input_id = -1;
	HAPI_NodeId display_node_id = -1;
	HAPI_NodeInfo volume_visualization_info = HAPI_NodeInfo_Create();
	
	HAPI_ParmId vis_id = -1;
	HAPI_ParmId density_id = -1;
	HAPI_ParmInfo parm_info = HAPI_ParmInfo_Create();

	HAPI_NodeId merge_node_id = -1;
	
	ENSURE_SUCCESS( HAPI_CreateNode( &session, -1, "sop/volumevisualization", "MergeNode", false, &volume_visualization_id ) );

	ENSURE_SUCCESS( HAPI_SetParmIntValue( &session, volume_visualization_id, "vismode", 0, 2 ) );
	ENSURE_SUCCESS( HAPI_GetParmIdFromName( &session, volume_visualization_id, "densityfield", &density_id ) );
	ENSURE_SUCCESS( HAPI_GetParmInfo( &session, volume_visualization_id, density_id, &parm_info ) );
	ENSURE_SUCCESS( HAPI_SetParmStringValue( &session, volume_visualization_id, "height", density_id, 0 ) );
	
	ENSURE_SUCCESS( HAPI_CookNode( &session, volume_visualization_id, nullptr ) );

	display_node_id = volume_visualization_id;
	
	
	char * name = "height";
	int start = 0;
	HAPI_PartId part_id = 0;	
	HAPI_NodeId volume_node_id = -1;
	
	ENSURE_SUCCESS( HAPI_CreateInputNode( &session, &volume_node_id, name ) );
	ENSURE_SUCCESS( HAPI_CookNode( &session, volume_node_id, nullptr) );

	HAPI_GeoInfo volume_geo_info = HAPI_GeoInfo_Create();
	ENSURE_SUCCESS( HAPI_GetDisplayGeoInfo( &session, volume_node_id, &volume_geo_info ) );

	HAPI_Transform transform = HAPI_Transform_Create();

	transform.scale[0] = 1000.0f;
	transform.scale[1] = 1000.0f;
	transform.scale[2] = 1.0f;
	
	HAPI_VolumeInfo heightfield_volume_info = HAPI_VolumeInfo_Create();

	heightfield_volume_info.xLength = 500;
	heightfield_volume_info.yLength = 500;
	heightfield_volume_info.zLength = 1;
	
	heightfield_volume_info.minX = 0;
	heightfield_volume_info.minY = 0;
	heightfield_volume_info.minZ = 0;
	
	heightfield_volume_info.transform = transform;

	heightfield_volume_info.type = HAPI_VOLUMETYPE_HOUDINI;
	heightfield_volume_info.storage = HAPI_STORAGETYPE_FLOAT;
	heightfield_volume_info.tupleSize = 1;
	heightfield_volume_info.tileSize = 1;

	heightfield_volume_info.hasTaper = false;
	heightfield_volume_info.xTaper = 0.0;
	heightfield_volume_info.yTaper = 0.0;
	
	const int totalsize = ( heightfield_volume_info.xLength * heightfield_volume_info.yLength );
	std::vector< float > heightfieldData( totalsize );
	
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_real_distribution<> dis(1, 2);
	for (int n = 0; n < totalsize; ++n)
	{
		heightfieldData[n] = (float)dis(gen);
	}

	HAPI_PartInfo part = HAPI_PartInfo_Create();
	
	part.nameSH = 0;
	part.id = part_id;
	part.attributeCounts[HAPI_ATTROWNER_POINT]  = 0;
	part.attributeCounts[HAPI_ATTROWNER_PRIM]   = 1;
	part.attributeCounts[HAPI_ATTROWNER_VERTEX] = 0;
	part.attributeCounts[HAPI_ATTROWNER_DETAIL] = 0;
	part.pointCount = 0;
	part.vertexCount = 0;
	part.faceCount = 1;
	part.type = HAPI_PARTTYPE_VOLUME;

	ENSURE_SUCCESS( HAPI_SetPartInfo( &session, volume_geo_info.nodeId, part.id, &part ) );

	ENSURE_SUCCESS( HAPI_SetVolumeInfo( &session, volume_geo_info.nodeId, part.id, &heightfield_volume_info ) );

	ENSURE_SUCCESS( HAPI_SetHeightFieldData( &session, volume_geo_info.nodeId, part.id, heightfieldData.data(), start, totalsize, name ) );

	ENSURE_SUCCESS( HAPI_CommitGeo( &session, volume_geo_info.nodeId ) );
	ENSURE_SUCCESS( HAPI_CookNode( &session, volume_geo_info.nodeId, nullptr ) );
	
	// ENSURE_SUCCESS( HAPI_ConnectNodeInput( &session, merge_node_id, 0, volume_geo_info.nodeId ) );

	ENSURE_SUCCESS( HAPI_ConnectNodeInput( &session, volume_visualization_id, 0, volume_geo_info.nodeId ) );
	ENSURE_SUCCESS( HAPI_CookNode( &session, volume_visualization_id, nullptr ) );
	
	ENSURE_SUCCESS( HAPI_SaveHIPFile( &session, "height_field.hip", false ) );
	HAPI_Cleanup( &session );
	
	return 0;
}

static std::string
getLastError()
{
    int bufferLength;
    HAPI_GetStatusStringBufLength( nullptr, HAPI_STATUS_CALL_RESULT, HAPI_STATUSVERBOSITY_ERRORS, &bufferLength );

    char * buffer = new char[ bufferLength ];

    HAPI_GetStatusString( nullptr, HAPI_STATUS_CALL_RESULT, buffer, bufferLength );

    std::string result( buffer );
    delete [] buffer;

    return result;
}
static std::string
getString( HAPI_StringHandle stringHandle )
{
    if ( stringHandle == 0 )
    {
	return "";
    }

    int bufferLength;
    HAPI_GetStringBufLength( nullptr,
				   stringHandle,
				   &bufferLength );

    char * buffer = new char[ bufferLength ];

    HAPI_GetString ( nullptr, stringHandle, buffer, bufferLength );

    std::string result( buffer );
    delete [] buffer;

    return result;
}

HAPI_SetHeightFieldData Sept. 20, 2017, 2:01 p.m.

So I've been struggling with getting just a simple example of HAPI_SetHeightFieldData to work.

I've hacked together a simple example from the documentation, and the provided examples, and while I get a hip file, and it clearly has data in it (just around 1MB), when I open that file the heightfield node is locked and won't render. I also can't use it as an input into another height field nodes with out it triggering an error.

Am I missing a step? Is there no way to actually visualize the results when mucking about with height fields?
Are there any examples of generating a heightfield input from data?

#include <HAPI/HAPI.h>
#include <iostream>
#include <string>
#include <vector>
#include <random>


#define ENSURE_SUCCESS( result ) \
if ( (result) != HAPI_RESULT_SUCCESS ) \
{ \
    std::cout << "Failure at " << __FILE__ << ": " << __LINE__ << std::endl; \
    std::cout << getLastError() << std::endl; \
    exit( 1 ); \
}

static std::string getLastError();

int
main( int argc, char ** argv )
{

	HAPI_CookOptions cookOptions = HAPI_CookOptions_Create();

	HAPI_Session session;

	HAPI_CreateInProcessSession( &session );

	ENSURE_SUCCESS( HAPI_Initialize( &session, &cookOptions, true, -1, nullptr, nullptr, nullptr, nullptr, nullptr ) );
	
	int start = 0;
	int part_id = 0;
	HAPI_NodeId out_node_id = -1;
	ENSURE_SUCCESS( HAPI_CreateNode( &session, -1, "sop/heightfield", nullptr, true, &out_node_id ) );

	HAPI_GeoInfo out_geo_info = HAPI_GeoInfo_Create();
	ENSURE_SUCCESS( HAPI_GetDisplayGeoInfo( &session, out_node_id, &out_geo_info ) );
	
	HAPI_PartInfo out_part_info = HAPI_PartInfo_Create();
	ENSURE_SUCCESS( HAPI_GetPartInfo( &session, out_geo_info.nodeId, part_id, &out_part_info ) );
	
	HAPI_VolumeInfo height_volume_info = HAPI_VolumeInfo_Create();
	ENSURE_SUCCESS( HAPI_GetVolumeInfo( &session, out_geo_info.nodeId, part_id, &height_volume_info ) );

	const int totalsize = ( height_volume_info.xLength * height_volume_info.yLength );
	std::vector< float > heightfieldData( totalsize );
	
	std::random_device rd;
	std::mt19937 gen(rd());
	std::uniform_real_distribution<> dis(1, 2);
	for (int n = 0; n < totalsize; ++n) {
		heightfieldData[n] = (float)dis(gen);
	}
	
	height_volume_info.type = HAPI_VOLUMETYPE_HOUDINI;
	height_volume_info.storage = HAPI_STORAGETYPE_FLOAT;
	height_volume_info.tupleSize = 1;
	height_volume_info.tileSize = 1;
	height_volume_info.zLength = 1;
	height_volume_info.hasTaper = false;
	height_volume_info.xTaper = 0.0;
	height_volume_info.yTaper = 0.0;

	ENSURE_SUCCESS( HAPI_SetVolumeInfo( &session, out_geo_info.nodeId, 0, &height_volume_info ) );

	ENSURE_SUCCESS( HAPI_SetHeightFieldData( &session, out_geo_info.nodeId, 0, heightfieldData.data(), start, totalsize, "height" ) );
	
	ENSURE_SUCCESS( HAPI_CommitGeo( &session, out_geo_info.nodeId ) );
	ENSURE_SUCCESS( HAPI_CookNode( &session, out_geo_info.nodeId, nullptr ) );

	ENSURE_SUCCESS( HAPI_SaveHIPFile( &session, "height_field.hip", false ) );
	HAPI_Cleanup( &session );
	
	return 0;
}

static std::string
getLastError()
{
    int bufferLength;
    HAPI_GetStatusStringBufLength( nullptr, HAPI_STATUS_CALL_RESULT, HAPI_STATUSVERBOSITY_ERRORS, &bufferLength );

    char * buffer = new char[ bufferLength ];

    HAPI_GetStatusString( nullptr, HAPI_STATUS_CALL_RESULT, buffer, bufferLength );

    std::string result( buffer );
    delete [] buffer;

    return result;
}