// Create a dictionary of load buffers to their IDs. This speeds up the instancer look up.
	protected virtual void BuildBufferIDsMap(HEU_LoadData loadData)
	{
	    loadData._idBuffersMap = new Dictionary<HAPI_NodeId, HEU_LoadBufferBase>();

	    int numObjects = loadData._loadedObjects.Count;
	    for (int i = 0; i < numObjects; ++i)
	    {
		HEU_LoadObject obj = loadData._loadedObjects[i];

		if (obj._meshBuffers != null)
		{
		    foreach (HEU_LoadBufferBase buffer in obj._meshBuffers)
		    {
			loadData._idBuffersMap[buffer._id] = buffer;
		    }
		}

		if (obj._terrainBuffers != null)
		{
		    foreach (HEU_LoadBufferBase buffer in obj._terrainBuffers)
		    {
			loadData._idBuffersMap[buffer._id] = buffer;
		    }
		}

		if (obj._instancerBuffers != null)
		{
		    foreach (HEU_LoadBufferBase buffer in obj._instancerBuffers)
		    {
			loadData._idBuffersMap[buffer._id] = buffer;
		    }
		}
	    }
	}
	protected virtual bool LoadNodeBuffer(HEU_SessionBase session, HAPI_NodeId nodeID, HEU_LoadObject loadObject)
	{
	    // Note that object instancing is not supported. Instancers currently supported are
	    // part and point instancing.

	    // Get the various types of geometry (parts) from the display node
	    List<HAPI_PartInfo> meshParts = new List<HAPI_PartInfo>();
	    List<HAPI_PartInfo> volumeParts = new List<HAPI_PartInfo>();
	    List<HAPI_PartInfo> instancerParts = new List<HAPI_PartInfo>();
	    List<HAPI_PartInfo> curveParts = new List<HAPI_PartInfo>();
	    List<HAPI_PartInfo> scatterInstancerParts = new List<HAPI_PartInfo>();
	    if (!QueryParts(nodeID, ref meshParts, ref volumeParts, ref instancerParts, ref curveParts, ref scatterInstancerParts))
	    {
		AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to query parts on node."));
		return false;
	    }

	    // Create Unity mesh buffers
	    if (!GenerateMeshBuffers(_session, nodeID, meshParts, _generateOptions._splitPoints, _generateOptions._useLODGroups,
				_generateOptions._generateUVs, _generateOptions._generateTangents, _generateOptions._generateNormals, loadObject,
				out loadObject._meshBuffers))
	    {
		AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to generate mesh data from parts."));
		return false;
	    }

	    // Create Unity terrain buffers
	    if (!GenerateTerrainBuffers(_session, nodeID, volumeParts, scatterInstancerParts, out loadObject._terrainBuffers))
	    {
		AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to generate terrain data from volume parts."));
		return false;
	    }

	    // Create instancers (should come after normal geometry has been generated above)
	    if (!GenerateInstancerBuffers(_session, nodeID, instancerParts, out loadObject._instancerBuffers))
	    {
		AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Unable to generate data from instancer parts."));
		return false;
	    }

	    return true;
	}
	protected virtual bool LoadObjectBuffers(HEU_SessionBase session, ref HAPI_ObjectInfo objectInfo)
	{
	    // Get display SOP geo info and cook the node
	    HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
	    if (!_session.GetDisplayGeoInfo(objectInfo.nodeId, ref displayGeoInfo))
	    {
		return false;
	    }

	    if (!CookNode(session, displayGeoInfo.nodeId))
	    {
		return false;
	    }

	    bool bResult = true;
	    bool bHasInstancer = false;

	    HEU_LoadObject obj = new HEU_LoadObject();
	    obj._objectNodeID = objectInfo.nodeId;
	    obj._displayNodeID = displayGeoInfo.nodeId;

	    if (LoadNodeBuffer(session, obj._displayNodeID, obj))
	    {
		_loadData._loadedObjects.Add(obj);
		
		if (!bHasInstancer && obj._instancerBuffers != null && obj._instancerBuffers.Count > 0)
		{
		    bHasInstancer = true;
		}
	    }
	    else
	    {
		bResult = false;
	    }

	    if (bResult && bHasInstancer)
	    {
		BuildBufferIDsMap(_loadData);
	    }

	    return bResult;
	}
	public bool GenerateMeshBuffers(HEU_SessionBase session, HAPI_NodeId nodeID, List<HAPI_PartInfo> meshParts,
		bool bSplitPoints, bool bUseLODGroups, bool bGenerateUVs, bool bGenerateTangents, bool bGenerateNormals, HEU_LoadObject loadObject,
		out List<HEU_LoadBufferMesh> meshBuffers)
	{
	    meshBuffers = null;
	    if (meshParts.Count == 0)
	    {
		return true;
	    }

	    bool bSuccess = true;
	    string assetCacheFolderPath = _assetCachePath;

	    meshBuffers = new List<HEU_LoadBufferMesh>();

	    foreach (HAPI_PartInfo partInfo in meshParts)
	    {
		HAPI_NodeId geoID = nodeID;
		int partID = partInfo.id;
		string partName = HEU_SessionManager.GetString(partInfo.nameSH, session);
		bool bPartInstanced = partInfo.isInstanced;

		if (partInfo.type == HAPI_PartType.HAPI_PARTTYPE_MESH)
		{
		    List<HEU_MaterialData> materialCache = new List<HEU_MaterialData>();

		    int assetId = loadObject != null ? loadObject._displayNodeID : -1;

		    HEU_GenerateGeoCache geoCache = HEU_GenerateGeoCache.GetPopulatedGeoCache(session, assetId, geoID, partID, bUseLODGroups,
			    materialCache, assetCacheFolderPath);
		    if (geoCache == null)
		    {
			// Failed to get necessary info for generating geometry.
			AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Failed to generate geometry cache for part: {0}", partName));
			continue;
		    }

		    geoCache._materialCache = materialCache;

		    // Build the GeoGroup using points or vertices
		    bool bResult = false;
		    List<HEU_GeoGroup> LODGroupMeshes = null;
		    int defaultMaterialKey = 0;
		    if (bSplitPoints)
		    {
			bResult = HEU_GenerateGeoCache.GenerateGeoGroupUsingGeoCachePoints(session, geoCache, bGenerateUVs, bGenerateTangents, bGenerateNormals, bUseLODGroups, bPartInstanced,
				out LODGroupMeshes, out defaultMaterialKey);
		    }
		    else
		    {
			bResult = HEU_GenerateGeoCache.GenerateGeoGroupUsingGeoCacheVertices(session, geoCache, bGenerateUVs, bGenerateTangents, bGenerateNormals, bUseLODGroups, bPartInstanced,
				out LODGroupMeshes, out defaultMaterialKey);
		    }

		    if (bResult)
		    {
			HEU_LoadBufferMesh meshBuffer = new HEU_LoadBufferMesh();
			meshBuffer.InitializeBuffer(partID, partName, partInfo.isInstanced, false);

			meshBuffer._geoCache = geoCache;
			meshBuffer._LODGroupMeshes = LODGroupMeshes;
			meshBuffer._defaultMaterialKey = defaultMaterialKey;

			meshBuffer._bGenerateUVs = bGenerateUVs;
			meshBuffer._bGenerateTangents = bGenerateTangents;
			meshBuffer._bGenerateNormals = bGenerateNormals;
			meshBuffer._bPartInstanced = partInfo.isInstanced;

			meshBuffers.Add(meshBuffer);
		    }
		    else
		    {
			AppendLog(HEU_LoadData.LoadStatus.ERROR, string.Format("Failed to generated geometry for part: {0}", partName));
		    }
		}
	    }

	    return bSuccess;
	}