Esempio n. 1
0
        public static bool CreateAndCookCurveAsset(HEU_SessionBase session, string assetName, bool bCookTemplatedGeos, out HAPI_NodeId newAssetID)
        {
            newAssetID = HEU_Defines.HEU_INVALID_NODE_ID;
            if (!session.CreateNode(HEU_Defines.HEU_INVALID_NODE_ID, "SOP/curve", "Curve", true, out newAssetID))
            {
                return(false);
            }

            // Make sure cooking is successfull before proceeding. Any licensing or file data issues will be caught here.
            if (!HEU_HAPIUtility.ProcessHoudiniCookStatus(session, assetName))
            {
                return(false);
            }

            // In case the cooking wasn't done previously, force it now.
            bool bResult = HEU_HAPIUtility.CookNodeInHoudini(session, newAssetID, bCookTemplatedGeos, assetName);

            if (!bResult)
            {
                // When cook failed, delete the node created earlier
                session.DeleteNode(newAssetID);
                newAssetID = HEU_Defines.HEU_INVALID_NODE_ID;
                return(false);
            }

            return(true);
        }
Esempio n. 2
0
		public static bool CreateInputNodeWithMultiObjects(HEU_SessionBase session, HAPI_NodeId assetID,
			ref HAPI_NodeId connectedAssetID, ref List<HEU_InputObjectInfo> inputObjects, ref List<HAPI_NodeId> inputObjectsConnectedAssetIDs, bool bKeepWorldTransform)
		{
			// Create the merge SOP node.
			if (!session.CreateNode(-1, "SOP/merge", null, true, out connectedAssetID))
			{
				Debug.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
				return false;
			}

			int numObjects = inputObjects.Count;
			for (int i = 0; i < numObjects; ++i)
			{
				HAPI_NodeId meshNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
				inputObjectsConnectedAssetIDs.Add(meshNodeID);

				// Skipping null gameobjects. Though if this causes issues, can always let it continue
				// to create input node, but not upload mesh data
				if (inputObjects[i]._gameObject == null)
				{
					continue;
				}

				bool bResult = CreateInputNodeWithGeoData(session, assetID, inputObjects[i]._gameObject, out meshNodeID);
				if (!bResult || meshNodeID == HEU_Defines.HEU_INVALID_NODE_ID)
				{
					string errorMsg = string.Format("Input at index {0} is not valid", i);
					if (inputObjects[i]._gameObject.GetComponent<HEU_HoudiniAssetRoot>() != null)
					{
						errorMsg += " because it is an HDA. Change the Input Type to HDA.";
					}
					else if (inputObjects[i]._gameObject.GetComponent<MeshFilter>() == null || inputObjects[i]._gameObject.GetComponent<MeshFilter>().sharedMesh == null)
					{
						errorMsg += " because it does not have a valid Mesh. Make sure the GameObject has a MeshFilter component with a valid mesh.";
					}
					else
					{
						errorMsg += ". Unable to create input node.";
					}

					Debug.LogErrorFormat(errorMsg);

					// Skipping this and continuing input processing since this isn't a deal breaker
					continue;
				}

				inputObjectsConnectedAssetIDs[i] = meshNodeID;

				if (!session.ConnectNodeInput(connectedAssetID, i, meshNodeID))
				{
					Debug.LogErrorFormat("Unable to connect input nodes!");
					return false;
				}

				UploadInputObjectTransform(session, inputObjects[i], meshNodeID, bKeepWorldTransform);
			}

			return true;
		}
	internal bool CreateInputNodeForCollider(HEU_SessionBase session, out HAPI_NodeId outNodeID, HAPI_NodeId parentNodeId, int colliderIndex, string colliderName, float[] colliderVertices, int[] colliderIndices)
	{
	    outNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    HAPI_NodeId colliderNodeId = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!session.CreateNode(parentNodeId, "null", colliderName, false, out colliderNodeId))
		return false;

	    HAPI_PartInfo partInfo = new HAPI_PartInfo();
	    partInfo.init();
	    partInfo.id = 0;
	    partInfo.nameSH = 0;
	    partInfo.attributeCounts[(int)HAPI_AttributeOwner.HAPI_ATTROWNER_POINT] = 0;
	    partInfo.attributeCounts[(int)HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM] = 0;
	    partInfo.attributeCounts[(int)HAPI_AttributeOwner.HAPI_ATTROWNER_VERTEX] = 0;
	    partInfo.attributeCounts[(int)HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL] = 0;
	    partInfo.vertexCount = colliderIndices.Length;
	    partInfo.faceCount = colliderIndices.Length / 3;
	    partInfo.pointCount = colliderVertices.Length / 3;
	    partInfo.type = HAPI_PartType.HAPI_PARTTYPE_MESH;

	    if (!session.SetPartInfo(colliderNodeId, 0, ref partInfo)) return false;

	    HAPI_AttributeInfo attributeInfoPoint = new HAPI_AttributeInfo();
	    attributeInfoPoint.count = colliderVertices.Length / 3;
	    attributeInfoPoint.tupleSize = 3;
	    attributeInfoPoint.exists = true;
	    attributeInfoPoint.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;
	    attributeInfoPoint.storage = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT;
	    attributeInfoPoint.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

	    if (!session.AddAttribute(colliderNodeId, 0, HEU_HAPIConstants.HAPI_ATTRIB_POSITION, ref attributeInfoPoint))
		return false;

	    if (!session.SetAttributeFloatData(colliderNodeId, 0, HEU_HAPIConstants.HAPI_ATTRIB_POSITION, ref attributeInfoPoint, colliderVertices, 0, attributeInfoPoint.count))
		return false;

	    if (!session.SetVertexList(colliderNodeId, 0, colliderIndices, 0, colliderIndices.Length))
		return false;

	    int[] faceCounts = new int[partInfo.faceCount];
	    for (int i = 0; i < faceCounts.Length; i++)
	    {
		faceCounts[i] = 3;
	    }

	    if (!session.SetFaceCount(colliderNodeId, 0, faceCounts, 0, faceCounts.Length))
		return false;

	    if (!session.CommitGeo(colliderNodeId))
		return false;

	    outNodeID = colliderNodeId;

	    return true;
	}
Esempio n. 4
0
	internal static bool CreateInputNodeWithMultiAssets(HEU_SessionBase session, HEU_HoudiniAsset parentAsset,
		ref HAPI_NodeId connectMergeID, ref List<HEU_InputHDAInfo> inputAssetInfos,
		 bool bKeepWorldTransform, HAPI_NodeId mergeParentID = -1)
	{
	    // Create the merge SOP node that the input nodes are going to connect to.
	    if (!session.CreateNode(mergeParentID, "SOP/merge", null, true, out connectMergeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return false;
	    }

	    int numInputs = inputAssetInfos.Count;
	    for (int i = 0; i < numInputs; ++i)
	    {
		inputAssetInfos[i]._connectedInputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

		if (inputAssetInfos[i]._pendingGO == null)
		{
		    continue;
		}

		// ID of the asset that will be connected
		HAPI_NodeId inputAssetID = HEU_Defines.HEU_INVALID_NODE_ID;

		HEU_HoudiniAssetRoot inputAssetRoot = inputAssetInfos[i]._pendingGO.GetComponent<HEU_HoudiniAssetRoot>();
		if (inputAssetRoot != null && inputAssetRoot._houdiniAsset != null)
		{
		    if (!inputAssetRoot._houdiniAsset.IsAssetValidInHoudini(session))
		    {
			// Force a recook if its not valid (in case it hasn't been loaded into the session)
			inputAssetRoot._houdiniAsset.RequestCook(true, false, true, true);
		    }

		    inputAssetID = inputAssetRoot._houdiniAsset.AssetID;
		}

		if (inputAssetID == HEU_Defines.HEU_INVALID_NODE_ID)
		{
		    continue;
		}

		if (!session.ConnectNodeInput(connectMergeID, i, inputAssetID))
		{
		    HEU_Logger.LogErrorFormat("Unable to connect input nodes!");
		    return false;
		}

		inputAssetInfos[i]._connectedInputNodeID = inputAssetID;
		inputAssetInfos[i]._connectedGO = inputAssetInfos[i]._pendingGO;
		inputAssetInfos[i]._connectedMergeNodeID = connectMergeID;

		parentAsset.ConnectToUpstream(inputAssetRoot._houdiniAsset);
	    }

	    return true;
	}
Esempio n. 5
0
	public static void CreateNodeSync(HEU_SessionBase session, string opName, string nodeNabel)
	{
	    if (session == null)
	    {
		session = HEU_SessionManager.GetDefaultSession();
	    }
	    if (session == null || !session.IsSessionValid())
	    {
		return;
	    }

	    HAPI_NodeId newNodeID = -1;
	    HAPI_NodeId parentNodeId = -1;

	    if (!session.CreateNode(parentNodeId, opName, nodeNabel, true, out newNodeID))
	    {
		Debug.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return;
	    }

	    if (parentNodeId == -1)
	    {
		// When creating a node without a parent, for SOP nodes, a container
		// geometry object will have been created by HAPI.
		// In all cases we want to use the node ID of that object container
		// so the below code sets the parent's node ID.

		// But for SOP/subnet we actually do want the subnet SOP node ID
		// hence the useSOPNodeID argument here is to override it.
		bool useSOPNodeID = opName.Equals("SOP/subnet");

		HAPI_NodeInfo nodeInfo = new HAPI_NodeInfo();
		if (!session.GetNodeInfo(newNodeID, ref nodeInfo))
		{
		    return;
		}

		if (nodeInfo.type == HAPI_NodeType.HAPI_NODETYPE_SOP)
		{
		    if (!useSOPNodeID)
		    {
			newNodeID = nodeInfo.parentId;
		    }
		}
		else if (nodeInfo.type != HAPI_NodeType.HAPI_NODETYPE_OBJ)
		{
		    Debug.LogErrorFormat("Unsupported node type {0}", nodeInfo.type);
		    return;
		}
	    }

	    GameObject newGO = new GameObject(nodeNabel);

	    HEU_NodeSync nodeSync = newGO.AddComponent<HEU_NodeSync>();
	    nodeSync.InitializeFromHoudini(session, newNodeID, nodeNabel, "");
	}
Esempio n. 6
0
	/// <summary>
	/// Create an input node network and upload the given set of input objects.
	/// This creates a SOP/merge node, and input nodes for each object in inputObjects
	/// which are then connected to the merge node.
	/// It finds the input interface that supports each object in inputObjects for creating
	/// the input node and uploading the data based on the type of data.
	/// </summary>
	/// <param name="session">Session to create the input node in</param>
	/// <param name="assetID">Main asset ID</param>
	/// <param name="connectMergeID">Created SOP/merge node ID</param>
	/// <param name="inputObjects">List of input objects to upload</param>
	/// <param name="inputObjectsConnectedAssetIDs">List of input node IDs for the input nodes created</param>
	/// <param name="bKeepWorldTransform">Whether to use world transform for the input nodes</param>
	/// <returns>True if successfully uploading input nodes</returns>
	public static bool CreateInputNodeWithMultiObjects(HEU_SessionBase session, HAPI_NodeId assetID,
		ref HAPI_NodeId connectMergeID, ref List<HEU_InputObjectInfo> inputObjects, ref List<HAPI_NodeId> inputObjectsConnectedAssetIDs, bool bKeepWorldTransform)
	{
	    // Create the merge SOP node that the input nodes are going to connect to.
	    if (!session.CreateNode(-1, "SOP/merge", null, true, out connectMergeID))
	    {
		Debug.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return false;
	    }

	    int numObjects = inputObjects.Count;
	    for (int i = 0; i < numObjects; ++i)
	    {
		HAPI_NodeId newConnectInputID = HEU_Defines.HEU_INVALID_NODE_ID;
		inputObjectsConnectedAssetIDs.Add(newConnectInputID);

		// Skipping null gameobjects. Though if this causes issues, can always let it continue
		// to create input node, but not upload mesh data
		if (inputObjects[i]._gameObject == null)
		{
		    continue;
		}

		HEU_InputInterface inputInterface = GetInputInterface(inputObjects[i]);
		if (inputInterface == null)
		{
		    Debug.LogWarningFormat("No input interface found for gameobject: {0}. Skipping upload!", inputObjects[i]._gameObject.name);
		    continue;
		}

		bool bResult = inputInterface.CreateInputNodeWithDataUpload(session, connectMergeID, inputObjects[i]._gameObject, out newConnectInputID);
		if (!bResult || newConnectInputID == HEU_Defines.HEU_INVALID_NODE_ID)
		{
		    Debug.LogError("Failed to upload input.");
		    continue;
		}

		inputObjectsConnectedAssetIDs[i] = newConnectInputID;

		if (!session.ConnectNodeInput(connectMergeID, i, newConnectInputID))
		{
		    Debug.LogErrorFormat("Unable to connect input nodes!");
		    return false;
		}

		UploadInputObjectTransform(session, inputObjects[i], newConnectInputID, bKeepWorldTransform);
	    }

	    return true;
	}
Esempio n. 7
0
        public static bool CreateAndCookAssetNode(HEU_SessionBase session, string assetName, bool bCookTemplatedGeos, out HAPI_NodeId newAssetID)
        {
            newAssetID = HEU_Defines.HEU_INVALID_NODE_ID;

            // Create top level node. Note that CreateNode will cook the node if HAPI was initialized with threaded cook setting on.
            bool bResult = session.CreateNode(-1, assetName, "", false, out newAssetID);

            if (!bResult)
            {
                return(false);
            }

            // Make sure cooking is successfull before proceeding. Any licensing or file data issues will be caught here.
            if (!ProcessHoudiniCookStatus(session, assetName))
            {
                return(false);
            }

            // In case the cooking wasn't done previously, force it now.
            bResult = CookNodeInHoudini(session, newAssetID, bCookTemplatedGeos, assetName);
            if (!bResult)
            {
                // When cook failed, deleted the node created earlier
                session.DeleteNode(newAssetID);
                newAssetID = HEU_Defines.HEU_INVALID_NODE_ID;
                return(false);
            }

            // Get the asset ID
            HAPI_AssetInfo assetInfo = new HAPI_AssetInfo();

            bResult = session.GetAssetInfo(newAssetID, ref assetInfo);
            if (bResult)
            {
                // Check for any errors
                HAPI_ErrorCodeBits errors = session.CheckForSpecificErrors(newAssetID, (HAPI_ErrorCodeBits)HAPI_ErrorCode.HAPI_ERRORCODE_ASSET_DEF_NOT_FOUND);
                if (errors > 0)
                {
                    // TODO: revisit for UI improvement
                    HEU_EditorUtility.DisplayDialog("Asset Missing Sub-asset Definitions",
                                                    "There are undefined nodes. This is due to not being able to find specific " +
                                                    "asset definitions.", "Ok");
                    return(false);
                }
            }

            return(true);
        }
	/// <summary>
	/// Creates a mesh input node and uploads the mesh data from inputObject.
	/// </summary>
	/// <param name="session">Session that connectNodeID exists in</param>
	/// <param name="connectNodeID">The node to connect the network to. Most likely a SOP/merge node</param>
	/// <param name="inputObject">The gameobject containing the mesh components</param>
	/// <param name="inputNodeID">The created input node ID</param>
	/// <returns>True if created network and uploaded mesh data.</returns>
	public override bool CreateInputNodeWithDataUpload(HEU_SessionBase session, HAPI_NodeId connectNodeID, GameObject inputObject, out HAPI_NodeId inputNodeID)
	{
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    // Create input node, cook it, then upload the geometry data

	    if (!HEU_HAPIUtility.IsNodeValidInHoudini(session, connectNodeID))
	    {
		HEU_Logger.LogError("Connection node is invalid.");
		return false;
	    }

	    bool bExportColliders = settings != null && settings.ExportColliders == true;

	    // Get upload meshes from input object
	    HEU_InputDataMeshes inputMeshes = GenerateMeshDatasFromGameObject(inputObject, bExportColliders);
	    if (inputMeshes == null || inputMeshes._inputMeshes == null || inputMeshes._inputMeshes.Count == 0)
	    {
		HEU_Logger.LogError("No valid meshes found on input objects.");
		return false;
	    }

	    string inputName = null;
	    HAPI_NodeId newNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    session.CreateInputNode(out newNodeID, inputName);
	    if (newNodeID == HEU_Defines.HEU_INVALID_NODE_ID || !HEU_HAPIUtility.IsNodeValidInHoudini(session, newNodeID))
	    {
		HEU_Logger.LogError("Failed to create new input node in Houdini session!");
		return false;
	    }

	    inputNodeID = newNodeID;

	    if (!UploadData(session, inputNodeID, inputMeshes))
	    {
		if (!session.CookNode(inputNodeID, false))
		{
		    HEU_Logger.LogError("New input node failed to cook!");
		    return false;
		}

		return false;
	    }

	    bool createMergeNode = false;
	    HAPI_NodeId mergeNodeId = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (bExportColliders)
	    {
		createMergeNode = true;
	    }

	    if (!createMergeNode)
	    {
		return true;
	    }

	    HAPI_NodeId parentId = HEU_HAPIUtility.GetParentNodeID(session, newNodeID);

	    if (!session.CreateNode(parentId, "merge", null, false, out mergeNodeId))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge SOP node for connecting input assets.");
		return false;
	    }

	    if (!session.ConnectNodeInput(mergeNodeId, 0, newNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to connect to input node!");
		return false;
	    }

	    if (!session.SetNodeDisplay(mergeNodeId, 1))
	    {
		HEU_Logger.LogWarningFormat("Unable to set display flag!");
	    }

	    inputNodeID = mergeNodeId;

	    if (bExportColliders)
	    {
		if (!UploadColliderData(session, mergeNodeId, inputMeshes, parentId))
		{
		    return false;
		}
	    }

	    if (!session.CookNode(inputNodeID, false))
	    {
	        HEU_Logger.LogError("New input node failed to cook!");
	        return false;
	    }
	    return true;
	}
	internal bool UploadCapsuleColliderData(HEU_SessionBase session, CapsuleCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID)
	{
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!collider) return false;

	    // Copied from Unreal FKSphylElem::GetElemSolid because exact Unity capsule source code is not available
	    Vector3 sphereCenter = collider.center;
	    float sphereRadius = collider.radius;
	    float sphereLength = collider.height;
	    // Height in Unreal is only the line segment. Height in Unity is the total length, so to get the line length, subtract 2 * rad
	    sphereLength = Mathf.Max(sphereLength - 2 * sphereRadius, 0);

	    int direction = collider.direction; // 0 = X, 1 = Y, 2 = Z. Default is Y

	    // Unreal Y -> Unity X, Unreal Z -> Unity Y
	    int numSides = 6;
	    int numRings = (numSides / 2) + 1;

	    int numVerts = (numSides + 1) * (numRings + 1);

	    // Calculate the vertices for one arc
	    Vector3[] arcVertices = new Vector3[numRings + 1];
	    for (int ringIdx = 0; ringIdx < numRings + 1; ringIdx++)
	    {
		float angle;
		float zOffset;
		if (ringIdx <= numSides / 4)
		{
		    angle = ((float) ringIdx / (numRings - 1)) * Mathf.PI;
		    zOffset = 0.5f * sphereLength;
		}
		else
		{
		    angle = ((float)(ringIdx - 1) / (numRings - 1) ) * Mathf.PI;
		    zOffset = -0.5f * sphereLength;
		}

		// Note- unit sphere, so position always has mag of one. We can just use it for normal!
		Vector3 spherePos = new Vector3();
		spherePos.x = sphereRadius * Mathf.Sin(angle);
		spherePos.y = sphereRadius * Mathf.Cos(angle);
		spherePos.z = 0;

		arcVertices[ringIdx] = spherePos + new Vector3(0, zOffset, 0);
	    }

	    Vector3 directionRotationEuler = Vector3.zero;
	    if (direction == 1)
	    {
		// Y axis - This is the default after Unity unit conversion
		directionRotationEuler = Vector3.zero;
	    }
	    else if (direction == 0)
	    {
		// X axis - Rotate around Z
		directionRotationEuler = new Vector3(0, 0, 90);
	    }
	    else if (direction == 2)
	    {
		// Z axis - Rotate around X
		directionRotationEuler = new Vector3(90, 0, 0);
	    }

	    Quaternion directionRotation = Quaternion.Euler(directionRotationEuler);

	    // Get the transform matrix for the rotation
	    // Get the capsule vertices by rotating the arc NumSides+1 times

	    float[] vertices = new float[numVerts * 3];
	    for (int sideIdx = 0; sideIdx < numSides + 1; sideIdx++)
	    {
		Vector3 arcEuler = new Vector3(0, 360.0f *((float)sideIdx / (float)numSides), 0);
		Quaternion arcRot = Quaternion.Euler(arcEuler);

		for (int vertIdx = 0; vertIdx < numRings + 1; vertIdx++)
		{
		    int vIx = (numRings + 1) * sideIdx + vertIdx;
		    Vector3 arcVertex = arcRot * arcVertices[vertIdx];
		    arcVertex = directionRotation * arcVertex;

		    Vector3 curPosition = sphereCenter + arcVertex;
		    HEU_HAPIUtility.ConvertPositionUnityToHoudini(curPosition, out vertices[vIx * 3 + 0], out vertices[vIx * 3 + 1], out vertices[vIx * 3 + 2]);
		}
	    }

	    int numIndices = numSides * numRings * 6;
	    int[] indices = new int[numIndices];
	    int curIndex = 0;

	    for (int sideIdx = 0; sideIdx < numSides; sideIdx++)
	    {
		int a0start = (sideIdx + 0) * (numRings + 1);
		int a1start = (sideIdx + 1) * (numRings + 1);
		for (int ringIdx = 0; ringIdx < numRings; ringIdx++)
		{
		    // First tri (reverse winding)
		    indices[curIndex+0] = a0start + ringIdx + 0;
		    indices[curIndex+2] = a1start + ringIdx + 0;
		    indices[curIndex+1] = a0start + ringIdx + 1;
		    curIndex += 3;

		    // Second Tri (reverse winding)
		    indices[curIndex+0] = a1start + ringIdx + 0;
		    indices[curIndex+2] = a1start + ringIdx + 1;
		    indices[curIndex+1] = a0start + ringIdx + 1;
		    curIndex += 3;
		}
	    }

	    HAPI_NodeId sphereNodeID = -1;
	    string sphereName = string.Format("Sphyl{0}", inputIndex);

	    if (!CreateInputNodeForCollider(session, out sphereNodeID, parentNodeID, inputIndex, sphereName, vertices, indices))
		return false;

	    if (!session.CookNode(sphereNodeID, false)) return false;

	    HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    string groupName = string.Format("group{0}", inputIndex);

	    if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets.");
		return false;
	    }

	    HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID)
		return false;

	    string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true);
	    string groupNameStr = string.Format("{0}_capsule{1}", baseGroupName, inputIndex);

	    if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0))
		return false;

	    if (!session.ConnectNodeInput(groupNodeID, 0, sphereNodeID))
		return false;

	    inputNodeID = groupNodeID;

	    return true;
	}
	internal bool UploadSphereColliderData(HEU_SessionBase session, SphereCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID)
	{
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!collider) return false;

	    Vector3 center = HEU_HAPIUtility.ConvertPositionUnityToHoudini(collider.center);
	    float radius = collider.radius;

	    HAPI_NodeId sphereNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    string name = string.Format("Sphere{0}", inputIndex);

	    if (!session.CreateNode(parentNodeID, "sphere", null, false, out sphereNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge box node for connecting input assets.");
		return false;
	    }

	    string radParamName = "rad";
	    if (!session.SetParamFloatValue(sphereNodeID, radParamName, 0, radius))
		return false;
	    if (!session.SetParamFloatValue(sphereNodeID, radParamName, 1, radius))
		return false;
	    if (!session.SetParamFloatValue(sphereNodeID, radParamName, 2, radius))
		return false;

	    string transformParamName = "t";
	    if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 0, center.x))
		return false;
	    if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 1, center.y))
		return false;
	    if (!session.SetParamFloatValue(sphereNodeID, transformParamName, 2, center.z))
		return false;

	    string typeParamName = "type";
	    if (!session.SetParamIntValue(sphereNodeID, typeParamName, 0, 1))
		return false;

	    if (!session.CookNode(sphereNodeID, false))
		return false;

	    HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    string groupName = string.Format("group{0}", inputIndex);

	    if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets.");
		return false;
	    }

	    HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false;

	    string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true);
	    string groupNameStr = string.Format("{0}_sphere{1}", baseGroupName, inputIndex);
	    if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0))
		return false;

	    if (!session.ConnectNodeInput(groupNodeID, 0, sphereNodeID))
		return false;

	    inputNodeID = groupNodeID;

	    return true;
	}
	internal bool UploadBoxColliderData(HEU_SessionBase session, BoxCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID)
	{
	    
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!collider) return false;

	    HAPI_NodeId boxNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    string name = string.Format("Box{0}", inputIndex);

	    Vector3 center = HEU_HAPIUtility.ConvertPositionUnityToHoudini(collider.center);
	    Vector3 size = HEU_HAPIUtility.ConvertScaleUnityToHoudini(collider.size);

	    if (!session.CreateNode(parentNodeID, "box", null, false, out boxNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create merge box node for connecting input assets.");
		return false;
	    }

	    string sizeParamName = "size";
	    if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 0, size.x))
		return false;
	    if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 1, size.y))
		return false;
	    if (!session.SetParamFloatValue(boxNodeID, sizeParamName, 2, size.z))
		return false;

	    string transformParamName = "t";
	    if (!session.SetParamFloatValue(boxNodeID, transformParamName, 0, center.x))
		return false;
	    if (!session.SetParamFloatValue(boxNodeID, transformParamName, 1, center.y))
		return false;
	    if (!session.SetParamFloatValue(boxNodeID, transformParamName, 2, center.z))
		return false;

	    if (!session.CookNode(boxNodeID, false))
		return false;

	    HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    string groupName = string.Format("group{0}", inputIndex);

	    if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets.");
		return false;
	    }

	    HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID) return false;

	    string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: false, bIsSimple: true);
	    string groupNameStr = string.Format("{0}_box{1}", baseGroupName, inputIndex);

	    if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0))
		return false;

	    if (!session.ConnectNodeInput(groupNodeID, 0, boxNodeID))
		return false;

	    inputNodeID = groupNodeID;

	    return true;
	}
	internal bool UploadMeshColliderData(HEU_SessionBase session, MeshCollider collider, int inputIndex, HAPI_NodeId parentNodeID, out HAPI_NodeId inputNodeID)
	{
	    inputNodeID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!collider) return false;


	    Mesh mesh = collider.sharedMesh;
	    Vector3[] vertices = mesh.vertices;

	    int numSubmeshes = mesh.subMeshCount;
	    List<int> indices = new List<int>();
	    for (int i = 0; i < numSubmeshes; i++)
	    {
		int[] indicesForSubmesh = mesh.GetIndices(i);
		indices.AddRange(indicesForSubmesh);
	    }

	    int[] indicesArr = indices.ToArray();

	    float[] verticesArr = new float[vertices.Length * 3];
	    for (int i = 0; i < vertices.Length; i++)
	    {
		HEU_HAPIUtility.ConvertPositionUnityToHoudini(vertices[i], out verticesArr[i * 3 + 0], out verticesArr[i * 3 + 1], out verticesArr[i * 3 + 2]);
	    }

	    HAPI_NodeId meshNodeID = -1;
	    string meshName = string.Format("MeshCollider{0}", inputIndex);

	    if (!CreateInputNodeForCollider(session, out meshNodeID, parentNodeID, inputIndex, meshName, verticesArr, indicesArr))
		return false;

	    if (!session.CookNode(meshNodeID, false)) return false;

	    HAPI_NodeId groupNodeID = HEU_Defines.HEU_INVALID_NODE_ID;
	    string groupName = string.Format("group{0}", inputIndex);

	    if (!session.CreateNode(parentNodeID, "groupcreate", groupName, false, out groupNodeID))
	    {
		HEU_Logger.LogErrorFormat("Unable to create group SOP node for connecting input assets.");
		return false;
	    }

	    HAPI_NodeId groupParmID = HEU_Defines.HEU_INVALID_NODE_ID;

	    if (!session.GetParmIDFromName(groupNodeID, "groupname", out groupParmID) || groupParmID == HEU_Defines.HEU_INVALID_NODE_ID)
		return false;

	    bool isConvex = collider.convex;
	    string baseGroupName = GetColliderGroupBaseName(collider, bIsConvex: isConvex, bIsSimple: false);

	    string groupNameStr = string.Format("{0}_mesh{1}", baseGroupName, inputIndex);
	    if (!session.SetParamStringValue(groupNodeID, groupNameStr, groupParmID, 0))
		return false;

	    if (!session.ConnectNodeInput(groupNodeID, 0, meshNodeID))
		return false;

	    inputNodeID = groupNodeID;

	    return true;
	}