示例#1
0
		public static bool SetMeshVertexFloatAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string attrName,
			int tupleSize, float[] data, int[] indices, ref HAPI_PartInfo partInfo)
		{
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_VERTEX;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT;
			attrInfo.count = partInfo.vertexCount;
			attrInfo.tupleSize = tupleSize;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			float[] attrValues = new float[partInfo.vertexCount * tupleSize];

			if (session.AddAttribute(geoID, 0, attrName, ref attrInfo))
			{
				for (int i = 0; i < partInfo.vertexCount; ++i)
				{
					for (int j = 0; j < tupleSize; ++j)
					{
						attrValues[i * tupleSize + j] = data[indices[i] * tupleSize + j];
					}
				}
			}

			return HEU_GeneralUtility.SetAttributeArray(geoID, partID, attrName, ref attrInfo, attrValues, session.SetAttributeFloatData, partInfo.vertexCount);
		}
        /// <summary>
        /// Writes out the TerrainLayer file path as a string attribute (primitive-owned) for the specified heightfield volume.
        /// </summary>
        /// <param name="session">Current Houdini session</param>
        /// <param name="geoNodeID">Geometry object ID</param>
        /// <param name="partID">Part ID (volume)</param>
        /// <param name="terrainLayer">The TerrainLayer's file path is set as attribute</param>
        /// <returns>True if successfully added the attribute.</returns>
        public bool SetTerrainLayerAttributesToHeightField(HEU_SessionBase session, HAPI_NodeId geoNodeID, HAPI_PartId partID, TerrainLayer terrainLayer)
        {
            string assetPath = HEU_AssetDatabase.GetAssetPath(terrainLayer);

            if (string.IsNullOrEmpty(assetPath))
            {
                return(false);
            }

            HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();

            attrInfo.exists        = true;
            attrInfo.owner         = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
            attrInfo.storage       = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
            attrInfo.count         = 1;
            attrInfo.tupleSize     = 1;
            attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

            if (!session.AddAttribute(geoNodeID, partID, HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINLAYER_FILE_ATTR, ref attrInfo))
            {
                Debug.LogError("Failed to add TerrainLayer file attribute to input heightfield.");
                return(false);
            }

            string[] pathData = new string[] { assetPath };
            if (!session.SetAttributeStringData(geoNodeID, partID, HEU_Defines.DEFAULT_UNITY_HEIGHTFIELD_TERRAINLAYER_FILE_ATTR, ref attrInfo, pathData, 0, 1))
            {
                Debug.LogError("Failed to set TerrainLayer file name to input heightfield");
                return(false);
            }

            return(true);
        }
示例#3
0
		public static bool SetMeshPointAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string attrName,
			int tupleSize, Vector3[] data, ref HAPI_PartInfo partInfo, bool bConvertToHoudiniCoordinateSystem)
		{
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT;
			attrInfo.count = partInfo.pointCount;
			attrInfo.tupleSize = tupleSize;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			float[] attrValues = new float[partInfo.pointCount * tupleSize];

			if (session.AddAttribute(geoID, 0, attrName, ref attrInfo))
			{
				float conversionMultiplier = bConvertToHoudiniCoordinateSystem ? -1f : 1f;

				for (int i = 0; i < partInfo.pointCount; ++i)
				{
					attrValues[i * tupleSize + 0] = conversionMultiplier * data[i][0];

					for (int j = 1; j < tupleSize; ++j)
					{
						attrValues[i * tupleSize + j] = data[i][j];
					}
				}
			}

			return HEU_GeneralUtility.SetAttributeArray(geoID, partID, attrName, ref attrInfo, attrValues, session.SetAttributeFloatData, partInfo.pointCount);
		}
示例#4
0
        //Set int point attributes
        public static bool SetMeshPointAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string attrName,
                                                 int tupleSize, Vector3Int[] data, ref HAPI_PartInfo partInfo)
        {
            HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();

            attrInfo.exists        = true;
            attrInfo.owner         = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;
            attrInfo.storage       = HAPI_StorageType.HAPI_STORAGETYPE_INT;
            attrInfo.count         = partInfo.pointCount;
            attrInfo.tupleSize     = tupleSize;
            attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

            int[] attrValues = new int[partInfo.pointCount * tupleSize];

            if (session.AddAttribute(geoID, 0, attrName, ref attrInfo))
            {
                for (int i = 0; i < partInfo.pointCount; ++i)
                {
                    attrValues[i * tupleSize + 0] = data[i][0];

                    for (int j = 1; j < tupleSize; ++j)
                    {
                        attrValues[i * tupleSize + j] = data[i][j];
                    }
                }
            }

            return(HEU_GeneralUtility.SetAttributeArray(geoID, partID, attrName, ref attrInfo, attrValues, session.SetAttributeIntData, partInfo.pointCount));
        }
	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;
	}
示例#6
0
		private void UpdateAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, HEU_AttributeData attributeData)
		{
			int attrCount = attributeData._attributeInfo.count;

			// Presuming we are working with point attributes
			HAPI_AttributeInfo newAttrInfo = new HAPI_AttributeInfo();
			newAttrInfo.exists = true;
			newAttrInfo.owner = attributeData._attributeInfo.owner;
			newAttrInfo.storage = attributeData._attributeInfo.storage;
			newAttrInfo.count = attributeData._attributeInfo.count;
			newAttrInfo.tupleSize = attributeData._attributeInfo.tupleSize;
			newAttrInfo.originalOwner = attributeData._attributeInfo.originalOwner;

			if (!session.AddAttribute(geoID, partID, attributeData._name, ref newAttrInfo))
			{
				Debug.LogErrorFormat("Failed to add attribute: {0}", attributeData._name);
				return;
			}

			if (newAttrInfo.storage == HAPI_StorageType.HAPI_STORAGETYPE_INT)
			{
				int[] pointData = new int[attrCount * newAttrInfo.tupleSize];
				for (int j = 0; j < attrCount; ++j)
				{
					for (int tuple = 0; tuple < newAttrInfo.tupleSize; ++tuple)
					{
						pointData[j * newAttrInfo.tupleSize + tuple] = attributeData._intValues[j * newAttrInfo.tupleSize + tuple];
					}
				}
				HEU_GeneralUtility.SetAttributeArray(geoID, partID, attributeData._name, ref newAttrInfo, pointData, session.SetAttributeIntData, attrCount);
			}
			else if (newAttrInfo.storage == HAPI_StorageType.HAPI_STORAGETYPE_FLOAT)
			{
				float[] pointData = new float[attrCount * newAttrInfo.tupleSize];
				for (int j = 0; j < attrCount; ++j)
				{
					for (int tuple = 0; tuple < newAttrInfo.tupleSize; ++tuple)
					{
						pointData[j * newAttrInfo.tupleSize + tuple] = attributeData._floatValues[j * newAttrInfo.tupleSize + tuple];
					}
				}
				HEU_GeneralUtility.SetAttributeArray(geoID, partID, attributeData._name, ref newAttrInfo, pointData, session.SetAttributeFloatData, attrCount);
			}
			else if (newAttrInfo.storage == HAPI_StorageType.HAPI_STORAGETYPE_STRING)
			{
				string[] pointData = new string[attrCount * newAttrInfo.tupleSize];
				for (int j = 0; j < attrCount; ++j)
				{
					for (int tuple = 0; tuple < newAttrInfo.tupleSize; ++tuple)
					{
						pointData[j * newAttrInfo.tupleSize + tuple] = attributeData._stringValues[j * newAttrInfo.tupleSize + tuple];
					}
				}
				HEU_GeneralUtility.SetAttributeArray(geoID, partID, attributeData._name, ref newAttrInfo, pointData, session.SetAttributeStringData, attrCount);
			}
		}
        /// <summary>
        /// Set the given TerrainData's TreePrototyes as attributes on the given part.
        /// The TreePrototypes as stored a string attributes where the name is HEU_Defines.HEIGHTFIELD_TREEPROTOTYPE + index.
        /// The string value is the tree prefab's file path comme-separated with the bend factor:
        /// e.g: Assets/Trees/redtree.prefab,0.9
        /// This does nothing if the given TerrainData doesn't have TreePrototype.
        /// </summary>
        /// <param name="session">Houdini Engine session</param>
        /// <param name="geoNodeID">Geometry object ID</param>
        /// <param name="partID">Part ID</param>
        /// <param name="terrainData">The TerrainData containing TreePrototypes.</param>
        public void SetTreePrototypes(HEU_SessionBase session, HAPI_NodeId geoNodeID, HAPI_PartId partID, TerrainData terrainData)
        {
            TreePrototype[] treePrototypes = terrainData.treePrototypes;
            if (treePrototypes == null || treePrototypes.Length == 0)
            {
                return;
            }

            // For each prototype, fill up a string attribute owned by primtive.
            // The string format is: tree_prefab_path,bend_factor
            string prefabPath;
            float  bendFactor;

            for (int i = 0; i < treePrototypes.Length; ++i)
            {
                if (treePrototypes[i] == null)
                {
                    continue;
                }

                prefabPath = HEU_AssetDatabase.GetAssetPath(treePrototypes[i].prefab);
                if (prefabPath == null)
                {
                    continue;
                }

                bendFactor = treePrototypes[i].bendFactor;

                HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
                attrInfo.exists        = true;
                attrInfo.owner         = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
                attrInfo.storage       = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
                attrInfo.count         = 1;
                attrInfo.tupleSize     = 1;
                attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

                string attrName = HEU_Defines.HEIGHTFIELD_TREEPROTOTYPE + i.ToString();
                if (!session.AddAttribute(geoNodeID, partID, attrName, ref attrInfo))
                {
                    Debug.LogError("Failed to add TreePrototype string attribute to input heightfield.");
                    return;
                }

                string[] pathData = new string[] { string.Format("{0},{1}", prefabPath, bendFactor) };
                if (!session.SetAttributeStringData(geoNodeID, partID, attrName, ref attrInfo, pathData, 0, 1))
                {
                    Debug.LogError("Failed to set TreePrototype string value to input heightfield.");
                    return;
                }
            }
        }
示例#8
0
        //Set string point attributes
        public static bool SetMeshPointAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string attrName, string[] data, ref HAPI_PartInfo partInfo)
        {
            HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
            attrInfo.exists = true;
            attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_POINT;
            attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
            attrInfo.count = partInfo.pointCount;
            attrInfo.tupleSize = 1;
            attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

            if (!session.AddAttribute(geoID, 0, attrName, ref attrInfo))
            {
                Debug.Log("Could not create attribute named: " + attrName);
                return false;
            }
            return HEU_GeneralUtility.SetAttributeArray(geoID, partID, attrName, ref attrInfo, data, session.SetAttributeStringData, partInfo.pointCount);
        }
示例#9
0
        //Set float detail attribute
        public static bool SetMeshDetailAttribute(HEU_SessionBase session, HAPI_NodeId geoID, HAPI_PartId partID, string attrName, int tupleSize, Vector3 data, ref HAPI_PartInfo partInfo)
        {
            HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
            attrInfo.exists = true;
            attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_DETAIL;
            attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_FLOAT;
            attrInfo.count = 1;
            attrInfo.tupleSize = tupleSize;
            attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

            float[] attrValues = new float[tupleSize];
            if (session.AddAttribute(geoID, 0, attrName, ref attrInfo))
            {
                for (int j = 0; j < tupleSize; ++j)
                {
                    attrValues[j] = data[j];
                }
            }

            return HEU_GeneralUtility.SetAttributeArray(geoID, partID, attrName, ref attrInfo, attrValues, session.SetAttributeFloatData, 1);
        }
示例#10
0
		/// <summary>
		/// Upload the inputData (mesh geometry) into the input node with inputNodeID.
		/// </summary>
		/// <param name="session">Session that the input node exists in</param>
		/// <param name="inputNodeID">ID of the input node</param>
		/// <param name="inputData">Container of the mesh geometry</param>
		/// <returns>True if successfully uploaded data</returns>
		public bool UploadData(HEU_SessionBase session, HAPI_NodeId inputNodeID, HEU_InputData inputData)
		{
			HEU_InputDataMeshes inputDataMeshes = inputData as HEU_InputDataMeshes;
			if (inputDataMeshes == null)
			{
				Debug.LogError("Expected HEU_InputDataMeshes type for inputData, but received unsupported type.");
				return false;
			}

			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			List<Color> colors = new List<Color>();

			List<int> pointIndexList = new List<int>();
			List<int> vertIndexList = new List<int>();

			int numMaterials = 0;

			int numMeshes = inputDataMeshes._inputMeshes.Count;

			// Get the parent's world transform, so when there are multiple child meshes,
			// can merge and apply their local transform after subtracting their parent's world transform
			Matrix4x4 rootInvertTransformMatrix = Matrix4x4.identity;
			if (numMeshes > 1)
			{
				rootInvertTransformMatrix = inputDataMeshes._inputObject.transform.worldToLocalMatrix;
			}

			// For all meshes:
			// Accumulate vertices, normals, uvs, colors, and indices.
			// Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
			// Find shared vertices, and use unique set of vertices to use as point positions.
			// Need to reindex indices for both unique vertices, as well as vertex attributes.
			for (int i = 0; i < numMeshes; ++i)
			{
				Vector3[] meshVertices = inputDataMeshes._inputMeshes[i]._mesh.vertices;
				Matrix4x4 localToWorld = inputDataMeshes._inputMeshes[i]._transform.localToWorldMatrix * rootInvertTransformMatrix;

				List<Vector3> uniqueVertices = new List<Vector3>();

				// Keep track of old vertex positions (old vertex slot points to new unique vertex slot)
				int[] reindexVertices = new int[meshVertices.Length];

				for (int j = 0; j < meshVertices.Length; ++j)
				{
					reindexVertices[j] = -1;
				}

				// For each vertex, check against subsequent vertices for shared positions.
				for (int a = 0; a < meshVertices.Length; ++a)
				{
					Vector3 va = meshVertices[a];

					if (reindexVertices[a] == -1)
					{
						if (numMeshes > 1 && !inputDataMeshes._hasLOD)
						{
							// For multiple meshes that are not LODs, apply local transform on vertices to get the merged mesh.
							uniqueVertices.Add(localToWorld.MultiplyPoint(va));
						}
						else
						{
							uniqueVertices.Add(va);
						}

						// Reindex to point to unique vertex slot
						reindexVertices[a] = uniqueVertices.Count - 1;
					}

					for (int b = a + 1; b < meshVertices.Length; ++b)
					{
						if (va == meshVertices[b])
						{
							// Shared vertex -> reindex to point to unique vertex slot
							reindexVertices[b] = reindexVertices[a];
						}
					}
				}

				int vertexOffset = vertices.Count;
				vertices.AddRange(uniqueVertices);

				Vector3[] meshNormals = inputDataMeshes._inputMeshes[i]._mesh.normals;
				Vector2[] meshUVs = inputDataMeshes._inputMeshes[i]._mesh.uv;
				Color[] meshColors = inputDataMeshes._inputMeshes[i]._mesh.colors;

				inputDataMeshes._inputMeshes[i]._indexStart = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];
				inputDataMeshes._inputMeshes[i]._indexCount = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];

				// For each submesh:
				// Generate face to point index -> pointIndexList
				// Generate face to vertex attribute index -> vertIndexList
				for (int j = 0; j < inputDataMeshes._inputMeshes[i]._numSubMeshes; ++j)
				{
					int indexStart = pointIndexList.Count;
					int vertIndexStart = vertIndexList.Count;

					// Indices have to be re-indexed with our own offset
					int[] meshIndices = inputDataMeshes._inputMeshes[i]._mesh.GetTriangles(j);
					int numIndices = meshIndices.Length;
					for (int k = 0; k < numIndices; ++k)
					{
						int originalIndex = meshIndices[k];
						meshIndices[k] = reindexVertices[originalIndex];

						pointIndexList.Add(vertexOffset + meshIndices[k]);
						vertIndexList.Add(vertIndexStart + k);

						if (meshNormals != null && (originalIndex < meshNormals.Length))
						{
							normals.Add(meshNormals[originalIndex]);
						}

						if (meshUVs != null && (originalIndex < meshUVs.Length))
						{
							uvs.Add(meshUVs[originalIndex]);
						}

						if (meshColors != null && (originalIndex < meshColors.Length))
						{
							colors.Add(meshColors[originalIndex]);
						}
					}

					inputDataMeshes._inputMeshes[i]._indexStart[j] = (uint)indexStart;
					inputDataMeshes._inputMeshes[i]._indexCount[j] = (uint)(pointIndexList.Count) - inputDataMeshes._inputMeshes[i]._indexStart[j];
				}

				numMaterials += inputDataMeshes._inputMeshes[i]._materials != null ? inputDataMeshes._inputMeshes[i]._materials.Length : 0;
			}

			// It is possible for some meshes to not have normals/uvs/colors while others do.
			// In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
			// partial attribute data.
			int totalAllVertexCount = vertIndexList.Count;
			if (normals.Count != totalAllVertexCount)
			{
				normals = null;
			}

			if (uvs.Count != totalAllVertexCount)
			{
				uvs = null;
			}

			if (colors.Count != totalAllVertexCount)
			{
				colors = null;
			}

			HAPI_PartInfo partInfo = new HAPI_PartInfo();
			partInfo.faceCount = vertIndexList.Count / 3;
			partInfo.vertexCount = vertIndexList.Count;
			partInfo.pointCount = vertices.Count;
			partInfo.pointAttributeCount = 1;
			partInfo.vertexAttributeCount = 0;
			partInfo.primitiveAttributeCount = 0;
			partInfo.detailAttributeCount = 0;

			if (normals != null && normals.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (uvs != null && uvs.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (colors != null && colors.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (numMaterials > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (numMeshes > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (inputDataMeshes._hasLOD)
			{
				partInfo.primitiveAttributeCount++;
				partInfo.detailAttributeCount++;
			}

			HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
			if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
			{
				return false;
			}

			HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

			if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
			{
				Debug.LogError("Failed to set input part info. ");
				return false;
			}

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

			int[] triIndices = pointIndexList.ToArray();

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
			{
				Debug.LogError("Failed to set input geometry face counts.");
				return false;
			}

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, triIndices, 0, partInfo.vertexCount))
			{
				Debug.LogError("Failed to set input geometry indices.");
				return false;
			}

			if (!HEU_InputMeshUtility.SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
			{
				Debug.LogError("Failed to set input geometry position.");
				return false;
			}

			int[] vertIndices = vertIndexList.ToArray();

			//if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), ref partInfo, true))
			if (normals != null && !HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), vertIndices, ref partInfo, true))
			{
				Debug.LogError("Failed to set input geometry normals.");
				return false;
			}

			if (uvs != null && uvs.Count > 0)
			{
				Vector3[] uvs3 = new Vector3[uvs.Count];
				for (int i = 0; i < uvs.Count; ++i)
				{
					uvs3[i][0] = uvs[i][0];
					uvs3[i][1] = uvs[i][1];
					uvs3[i][2] = 0;
				}
				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, vertIndices, ref partInfo, false))
				{
					Debug.LogError("Failed to set input geometry UVs.");
					return false;
				}
			}

			if (colors != null && colors.Count > 0)
			{
				Vector3[] rgb = new Vector3[colors.Count];
				float[] alpha = new float[colors.Count];
				for (int i = 0; i < colors.Count; ++i)
				{
					rgb[i][0] = colors[i].r;
					rgb[i][1] = colors[i].g;
					rgb[i][2] = colors[i].b;

					alpha[i] = colors[i].a;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, vertIndices, ref partInfo, false))
				{
					Debug.LogError("Failed to set input geometry colors.");
					return false;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
				if (!HEU_InputMeshUtility.SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, vertIndices, ref partInfo))
				{
					Debug.LogError("Failed to set input geometry color alpha.");
					return false;
				}
			}

			// Set material names for round-trip perservation of material assignment
			// Each HEU_UploadMeshData might have a list of submeshes and materials
			// These are all combined into a single mesh, with group names
			if (numMaterials > 0)
			{
				bool bFoundAtleastOneValidMaterial = false;

				string[] materialIDs = new string[partInfo.faceCount];
				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					if (inputDataMeshes._inputMeshes[g]._numSubMeshes != inputDataMeshes._inputMeshes[g]._materials.Length)
					{
						// Number of submeshes should equal number of materials since materials determine submeshes
						continue;
					}

					for (int i = 0; i < inputDataMeshes._inputMeshes[g]._materials.Length; ++i)
					{
						string materialName = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(inputDataMeshes._inputMeshes[g]._materials[i]);
						if (materialName == null)
						{
							materialName = "";
						}
						else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
						{
							materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(inputDataMeshes._inputMeshes[g]._materials[i]);
						}

						bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							materialIDs[m] = materialName;
						}
					}
				}

				if (bFoundAtleastOneValidMaterial)
				{
					HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
					materialIDAttrInfo.exists = true;
					materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
					materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
					materialIDAttrInfo.count = partInfo.faceCount;
					materialIDAttrInfo.tupleSize = 1;
					materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

					if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
					{
						Debug.LogError("Failed to add input geometry unity material name attribute.");
						return false;
					}

					if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, session.SetAttributeStringData, partInfo.faceCount))
					{
						Debug.LogError("Failed to set input geometry unity material name.");
						return false;
					}
				}
			}

			// Set mesh name attribute
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
			attrInfo.count = partInfo.faceCount;
			attrInfo.tupleSize = 1;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
			{
				string[] primitiveNameAttr = new string[partInfo.faceCount];

				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					for (int i = 0; i < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++i)
					{
						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							primitiveNameAttr[m] = inputDataMeshes._inputMeshes[g]._meshPath;
						}
					}
				}

				if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, session.SetAttributeStringData, partInfo.faceCount))
				{
					Debug.LogError("Failed to set input geometry unity mesh name.");
					return false;
				}
			}
			else
			{
				return false;
			}

			// Set LOD group membership
			if (inputDataMeshes._hasLOD)
			{
				int[] membership = new int[partInfo.faceCount];

				for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
				{
					if (g > 0)
					{
						// Clear array
						for (int m = 0; m < partInfo.faceCount; ++m)
						{
							membership[m] = 0;
						}
					}

					// Set 1 for faces belonging to this group
					for (int s = 0; s < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++s)
					{
						int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[s] / 3;
						int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[s] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							membership[m] = 1;
						}
					}

					if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName))
					{
						Debug.LogError("Failed to add input geometry LOD group name.");
						return false;
					}

					if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName, membership, 0, partInfo.faceCount))
					{
						Debug.LogError("Failed to set input geometry LOD group name.");
						return false;
					}
				}
			}

			return session.CommitGeo(displayNodeID);
		}
示例#11
0
		/// <summary>
		/// Upload the given list of mesh data in uploadMeshes into node with inputNodeID.
		/// If the source was a LOD group, then group names are assigned to the geometry.
		/// </summary>
		/// <param name="session">Session to upload to</param>
		/// <param name="inputNodeID">The ID of the input node to upload into</param>
		/// <param name="uploadMeshes">List of mesh data</param>
		/// <param name="bHasLODGroup">Whether the source was a LOD group and therefore treat it specially</param>
		/// <returns></returns>
		public static bool UploadInputMeshData(HEU_SessionBase session, HAPI_NodeId inputNodeID, List<HEU_UploadMeshData> uploadMeshes, bool bHasLODGroup)
		{
			List<Vector3> vertices = new List<Vector3>();
			List<Vector3> normals = new List<Vector3>();
			List<Vector2> uvs = new List<Vector2>();
			List<Color> colors = new List<Color>();

			List<int> triIndexList = new List<int>();

			int numMaterials = 0;

			// Accumulate vertices, normals, uvs, colors, and indices.
			// Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
			// Indices need to be reindexed with vertex offset as we accumulate vertices.
			int numMeshes = uploadMeshes.Count;
			for (int i = 0; i < numMeshes; ++i)
			{
				int vertexOffset = vertices.Count;
				vertices.AddRange(uploadMeshes[i]._mesh.vertices);

				normals.AddRange(uploadMeshes[i]._mesh.normals);
				uvs.AddRange(uploadMeshes[i]._mesh.uv);
				colors.AddRange(uploadMeshes[i]._mesh.colors);

				uploadMeshes[i]._indexStart = new uint[uploadMeshes[i]._numSubMeshes];
				uploadMeshes[i]._indexCount = new uint[uploadMeshes[i]._numSubMeshes];

				for (int j = 0; j < uploadMeshes[i]._numSubMeshes; ++j)
				{
					int indexStart = triIndexList.Count;

					// Indices have to be re-indexed with our own offset
					int[] meshIndices = uploadMeshes[i]._mesh.GetTriangles(j);
					int numIndices = meshIndices.Length;
					for (int k = 0; k < numIndices; ++k)
					{
						triIndexList.Add(vertexOffset + meshIndices[k]);
					}

					uploadMeshes[i]._indexStart[j] = (uint)indexStart;
					uploadMeshes[i]._indexCount[j] = (uint)(triIndexList.Count) - uploadMeshes[i]._indexStart[j];
				}

				numMaterials += uploadMeshes[i]._materials != null ? uploadMeshes[i]._materials.Length : 0;
			}

			// It is possible for some meshes to not have normals/uvs/colors while others do.
			// In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
			// partial attribute data.
			int numVertices = vertices.Count;
			if (normals.Count != numVertices)
			{
				normals = null;
			}

			if (uvs.Count != numVertices)
			{
				uvs = null;
			}

			if (colors.Count != numVertices)
			{
				colors = null;
			}

			HAPI_PartInfo partInfo = new HAPI_PartInfo();
			partInfo.faceCount = triIndexList.Count / 3;
			partInfo.vertexCount = triIndexList.Count;
			partInfo.pointCount = vertices.Count;
			partInfo.pointAttributeCount = 1;
			partInfo.vertexAttributeCount = 0;
			partInfo.primitiveAttributeCount = 0;
			partInfo.detailAttributeCount = 0;

			if (normals != null && normals.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (uvs != null && uvs.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (colors != null && colors.Count > 0)
			{
				partInfo.vertexAttributeCount++;
			}

			if (numMaterials > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (numMeshes > 0)
			{
				partInfo.primitiveAttributeCount++;
			}

			if (bHasLODGroup)
			{
				partInfo.primitiveAttributeCount++;
				partInfo.detailAttributeCount++;
			}

			HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
			if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
			{
				return false;
			}

			HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

			if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
			{
				return false;
			}

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

			int[] triIndices = triIndexList.ToArray();

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
			{
				return false;
			}

			if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, triIndices, 0, partInfo.vertexCount))
			{
				return false;
			}

			if (!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
			{
				return false;
			}

			//if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals, ref partInfo, true))
			if (normals != null && !SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), triIndices, ref partInfo, true))
			{
				return false;
			}

			if (uvs != null && uvs.Count > 0)
			{
				Vector3[] uvs3 = new Vector3[uvs.Count];
				for (int i = 0; i < uvs.Count; ++i)
				{
					uvs3[i][0] = uvs[i][0];
					uvs3[i][1] = uvs[i][1];
					uvs3[i][2] = 0;
				}
				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, ref partInfo, false))
				if (!SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_UV, 3, uvs3, triIndices, ref partInfo, false))
				{
					return false;
				}
			}

			if (colors != null && colors.Count > 0)
			{
				Vector3[] rgb = new Vector3[colors.Count];
				float[] alpha = new float[colors.Count];
				for (int i = 0; i < colors.Count; ++i)
				{
					rgb[i][0] = colors[i].r;
					rgb[i][1] = colors[i].g;
					rgb[i][2] = colors[i].b;

					alpha[i] = colors[i].a;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
				if (!SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, triIndices, ref partInfo, false))
				{
					return false;
				}

				//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
				if (!SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, triIndices, ref partInfo))
				{
					return false;
				}
			}

			// Set material names for round-trip perservation of material assignment
			// Each HEU_UploadMeshData might have a list of submeshes and materials
			// These are all combined into a single mesh, with group names
			if (numMaterials > 0)
			{
				bool bFoundAtleastOneValidMaterial = false;

				string[] materialIDs = new string[partInfo.faceCount];
				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					if (uploadMeshes[g]._numSubMeshes != uploadMeshes[g]._materials.Length)
					{
						// Number of submeshes should equal number of materials since materials determine submeshes
						continue;
					}

					for (int i = 0; i < uploadMeshes[g]._materials.Length; ++i)
					{
						string materialName = HEU_AssetDatabase.GetAssetPath(uploadMeshes[g]._materials[i]);
						if (materialName == null)
						{
							materialName = "";
						}
						else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
						{
							materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(uploadMeshes[g]._materials[i]);
						}

						bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

						int faceStart = (int)uploadMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							materialIDs[m] = materialName;
						}
					}
				}

				if (bFoundAtleastOneValidMaterial)
				{
					HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
					materialIDAttrInfo.exists = true;
					materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
					materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
					materialIDAttrInfo.count = partInfo.faceCount;
					materialIDAttrInfo.tupleSize = 1;
					materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

					if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
					{
						return false;
					}

					if (!session.SetAttributeStringData(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, 0, partInfo.faceCount))
					{
						return false;
					}
				}
			}

			// Set mesh name attribute
			HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
			attrInfo.exists = true;
			attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
			attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
			attrInfo.count = partInfo.faceCount;
			attrInfo.tupleSize = 1;
			attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

			if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
			{
				string[] primitiveNameAttr = new string[partInfo.faceCount];

				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					for (int i = 0; i < uploadMeshes[g]._numSubMeshes; ++i)
					{
						int faceStart = (int)uploadMeshes[g]._indexStart[i] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[i] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							primitiveNameAttr[m] = uploadMeshes[g]._meshPath;
						}
					}
				}

				if (!session.SetAttributeStringData(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, 0, partInfo.faceCount))
				{
					return false;
				}
			}
			else
			{
				return false;
			}

			// Set LOD group membership
			if (bHasLODGroup)
			{
				int[] membership = new int[partInfo.faceCount];

				for (int g = 0; g < uploadMeshes.Count; ++g)
				{
					if (g > 0)
					{
						// Clear array
						for (int m = 0; m < partInfo.faceCount; ++m)
						{
							membership[m] = 0;
						}
					}

					// Set 1 for faces belonging to this group
					for (int s = 0; s < uploadMeshes[g]._numSubMeshes; ++s)
					{
						int faceStart = (int)uploadMeshes[g]._indexStart[s] / 3;
						int faceEnd = faceStart + ((int)uploadMeshes[g]._indexCount[s] / 3);
						for (int m = faceStart; m < faceEnd; ++m)
						{
							membership[m] = 1;
						}
					}

					if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, uploadMeshes[g]._meshName))
					{
						return false;
					}

					if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, uploadMeshes[g]._meshName, membership, 0, partInfo.faceCount))
					{
						return false;
					}
				}
			}

			return session.CommitGeo(displayNodeID);
		}
示例#12
0
	/// <summary>
	/// Upload the inputData (mesh geometry) into the input node with inputNodeID.
	/// </summary>
	/// <param name="session">Session that the input node exists in</param>
	/// <param name="inputNodeID">ID of the input node</param>
	/// <param name="inputData">Container of the mesh geometry</param>
	/// <returns>True if successfully uploaded data</returns>
	public bool UploadData(HEU_SessionBase session, HAPI_NodeId inputNodeID, HEU_InputData inputData)
	{
	    HEU_InputDataMeshes inputDataMeshes = inputData as HEU_InputDataMeshes;
	    if (inputDataMeshes == null)
	    {
		Debug.LogError("Expected HEU_InputDataMeshes type for inputData, but received unsupported type.");
		return false;
	    }

	    List<Vector3> vertices = new List<Vector3>();
	    List<Vector3> normals = new List<Vector3>();
	    List<Color> colors = new List<Color>();

#if UNITY_2018_2_OR_NEWER
	    const int NumUVSets = 8;
#else
	    const int NumUVSets = 4;
#endif
	    List<Vector3>[] uvs = new List<Vector3>[NumUVSets];
	    for (int u = 0; u < NumUVSets; ++u)
	    {
		uvs[u] = new List<Vector3>();
	    }

	    // Use tempUVs to help with reindexing
	    List<Vector3>[] tempUVs = new List<Vector3>[NumUVSets];
	    for (int u = 0; u < NumUVSets; ++u)
	    {
		tempUVs[u] = new List<Vector3>();
	    }

	    List<int> pointIndexList = new List<int>();
	    List<int> vertIndexList = new List<int>();

	    int numMaterials = 0;

	    int numMeshes = inputDataMeshes._inputMeshes.Count;

	    // Get the parent's world transform, so when there are multiple child meshes,
	    // can merge and apply their local transform after subtracting their parent's world transform
	    Matrix4x4 rootInvertTransformMatrix = Matrix4x4.identity;
	    if (numMeshes > 1)
	    {
		rootInvertTransformMatrix = inputDataMeshes._inputObject.transform.worldToLocalMatrix;
	    }

	    // Always using the first submesh topology. This doesn't support mixed topology (triangles and quads).
	    MeshTopology meshTopology = inputDataMeshes._inputMeshes[0]._mesh.GetTopology(0);

	    int numVertsPerFace = 3;
	    if (meshTopology == MeshTopology.Quads)
	    {
		numVertsPerFace = 4;
	    }

	    // For all meshes:
	    // Accumulate vertices, normals, uvs, colors, and indices.
	    // Keep track of indices start and count for each mesh for later when uploading material assignments and groups.
	    // Find shared vertices, and use unique set of vertices to use as point positions.
	    // Need to reindex indices for both unique vertices, as well as vertex attributes.
	    for (int i = 0; i < numMeshes; ++i)
	    {
		Vector3[] meshVertices = inputDataMeshes._inputMeshes[i]._mesh.vertices;
		Matrix4x4 localToWorld = rootInvertTransformMatrix * inputDataMeshes._inputMeshes[i]._transform.localToWorldMatrix;

		List<Vector3> uniqueVertices = new List<Vector3>();

		// Keep track of old vertex positions (old vertex slot points to new unique vertex slot)
		int[] reindexVertices = new int[meshVertices.Length];
		Dictionary<Vector3, int> reindexMap = new Dictionary<Vector3, int>();

		// For each vertex, check against subsequent vertices for shared positions.
		for (int a = 0; a < meshVertices.Length; ++a)
		{
		    Vector3 va = meshVertices[a];

		    if (!reindexMap.ContainsKey(va))
		    {
			if (numMeshes > 1 && !inputDataMeshes._hasLOD)
			{
			    // For multiple meshes that are not LODs, apply local transform on vertices to get the merged mesh.
			    uniqueVertices.Add(localToWorld.MultiplyPoint(va));
			}
			else
			{
			    uniqueVertices.Add(va);
			}

			// Reindex to point to unique vertex slot
			reindexVertices[a] = uniqueVertices.Count - 1;
			reindexMap[va] = uniqueVertices.Count - 1;
		    }
		    else
		    {
			reindexVertices[a] = reindexMap[va];
		    }
		}

		int vertexOffset = vertices.Count;
		vertices.AddRange(uniqueVertices);

		Vector3[] meshNormals = inputDataMeshes._inputMeshes[i]._mesh.normals;
		Color[] meshColors = inputDataMeshes._inputMeshes[i]._mesh.colors;

		// This is really silly. mesh.GetUVs gives uvs regardless if they exist or not (makes duplicates of
		// first uv if they don't exist), but mesh.uv* gives correct UVs, but in Vector2 format.
		// Since we need to convert to Vector3 later, this checks mesh.uv*, then uses mesh.GetUVs to get in Vector3.
		// Note skipping uv1 as its internally used (i.e. the 2nd uv set is uv2)
		int uindex = 0;
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv, tempUVs[0], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv2, tempUVs[1], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv3, tempUVs[2], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv4, tempUVs[3], uindex++);
#if UNITY_2018_2_OR_NEWER
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv5, tempUVs[4], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv6, tempUVs[5], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv7, tempUVs[6], uindex++);
		GetUVsFromMesh(inputDataMeshes._inputMeshes[i]._mesh, inputDataMeshes._inputMeshes[i]._mesh.uv8, tempUVs[7], uindex++);
#endif

		inputDataMeshes._inputMeshes[i]._indexStart = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];
		inputDataMeshes._inputMeshes[i]._indexCount = new uint[inputDataMeshes._inputMeshes[i]._numSubMeshes];

		// For each submesh:
		// Generate face to point index -> pointIndexList
		// Generate face to vertex attribute index -> vertIndexList
		for (int j = 0; j < inputDataMeshes._inputMeshes[i]._numSubMeshes; ++j)
		{
		    int indexStart = pointIndexList.Count;
		    int vertIndexStart = vertIndexList.Count;

		    // Indices have to be re-indexed with our own offset 
		    // (using GetIndices to generalize triangles and quad indices)
		    int[] meshIndices = inputDataMeshes._inputMeshes[i]._mesh.GetIndices(j);
		    int numIndices = meshIndices.Length;
		    for (int k = 0; k < numIndices; ++k)
		    {
			int originalIndex = meshIndices[k];
			meshIndices[k] = reindexVertices[originalIndex];

			pointIndexList.Add(vertexOffset + meshIndices[k]);
			vertIndexList.Add(vertIndexStart + k);

			if (meshNormals != null && (originalIndex < meshNormals.Length))
			{
			    normals.Add(meshNormals[originalIndex]);
			}

			for (int u = 0; u < NumUVSets; ++u)
			{
			    if (tempUVs[u].Count > 0)
			    {
				uvs[u].Add(tempUVs[u][originalIndex]);
			    }
			}

			if (meshColors != null && (originalIndex < meshColors.Length))
			{
			    colors.Add(meshColors[originalIndex]);
			}
		    }

		    inputDataMeshes._inputMeshes[i]._indexStart[j] = (uint)indexStart;
		    inputDataMeshes._inputMeshes[i]._indexCount[j] = (uint)(pointIndexList.Count) - inputDataMeshes._inputMeshes[i]._indexStart[j];
		}

		numMaterials += inputDataMeshes._inputMeshes[i]._materials != null ? inputDataMeshes._inputMeshes[i]._materials.Length : 0;
	    }

	    // It is possible for some meshes to not have normals/uvs/colors while others do.
	    // In the case where an attribute is missing on some meshes, we clear out those attributes so we don't upload
	    // partial attribute data.
	    int totalAllVertexCount = vertIndexList.Count;
	    if (normals.Count != totalAllVertexCount)
	    {
		normals = null;
	    }

	    if (colors.Count != totalAllVertexCount)
	    {
		colors = null;
	    }

	    HAPI_PartInfo partInfo = new HAPI_PartInfo();
	    partInfo.faceCount = vertIndexList.Count / numVertsPerFace;
	    partInfo.vertexCount = vertIndexList.Count;
	    partInfo.pointCount = vertices.Count;
	    partInfo.pointAttributeCount = 1;
	    partInfo.vertexAttributeCount = 0;
	    partInfo.primitiveAttributeCount = 0;
	    partInfo.detailAttributeCount = 0;

	    //Debug.LogFormat("Faces: {0}; Vertices: {1}; Verts/Face: {2}", partInfo.faceCount, partInfo.vertexCount, numVertsPerFace);

	    if (normals != null && normals.Count > 0)
	    {
		partInfo.vertexAttributeCount++;
	    }

	    for (int u = 0; u < NumUVSets; ++u)
	    {
		if (uvs[u].Count > 0 && uvs[u].Count == totalAllVertexCount)
		{
		    partInfo.vertexAttributeCount++;
		}
		else
		{
		    uvs[u].Clear();
		}
	    }

	    if (colors != null && colors.Count > 0)
	    {
		partInfo.vertexAttributeCount++;
	    }

	    if (numMaterials > 0)
	    {
		partInfo.primitiveAttributeCount++;
	    }

	    if (numMeshes > 0)
	    {
		partInfo.primitiveAttributeCount++;
	    }

	    if (inputDataMeshes._hasLOD)
	    {
		partInfo.primitiveAttributeCount++;
		partInfo.detailAttributeCount++;
	    }

	    HAPI_GeoInfo displayGeoInfo = new HAPI_GeoInfo();
	    if (!session.GetDisplayGeoInfo(inputNodeID, ref displayGeoInfo))
	    {
		return false;
	    }

	    HAPI_NodeId displayNodeID = displayGeoInfo.nodeId;

	    if (!session.SetPartInfo(displayNodeID, 0, ref partInfo))
	    {
		Debug.LogError("Failed to set input part info. ");
		return false;
	    }

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

	    int[] faceIndices = pointIndexList.ToArray();

	    if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetFaceCount, faceCounts, 0, partInfo.faceCount))
	    {
		Debug.LogError("Failed to set input geometry face counts.");
		return false;
	    }

	    if (!HEU_GeneralUtility.SetArray2Arg(displayNodeID, 0, session.SetVertexList, faceIndices, 0, partInfo.vertexCount))
	    {
		Debug.LogError("Failed to set input geometry indices.");
		return false;
	    }

	    if (!HEU_InputMeshUtility.SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_POSITION, 3, vertices.ToArray(), ref partInfo, true))
	    {
		Debug.LogError("Failed to set input geometry position.");
		return false;
	    }

	    int[] vertIndices = vertIndexList.ToArray();

	    //if(normals != null && !SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), ref partInfo, true))
	    if (normals != null && !HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_NORMAL, 3, normals.ToArray(), vertIndices, ref partInfo, true))
	    {
		Debug.LogError("Failed to set input geometry normals.");
		return false;
	    }

	    for (int u = 0; u < NumUVSets; ++u)
	    {
		if (uvs[u].Count > 0)
		{
		    // Skip uv1 as its used internally. So it goes: uv, uv2, ..., uv8
		    string uvName = u == 0 ? HEU_Defines.HAPI_ATTRIB_UV : string.Format("{0}{1}", HEU_Defines.HAPI_ATTRIB_UV, u + 1);
		    if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, uvName, 3, uvs[u].ToArray(), vertIndices, ref partInfo, false))
		    {
			Debug.LogError("Failed to set input geometry UV" + u);
			return false;
		    }
		}
	    }

	    if (colors != null && colors.Count > 0)
	    {
		Vector3[] rgb = new Vector3[colors.Count];
		float[] alpha = new float[colors.Count];
		for (int i = 0; i < colors.Count; ++i)
		{
		    rgb[i][0] = colors[i].r;
		    rgb[i][1] = colors[i].g;
		    rgb[i][2] = colors[i].b;

		    alpha[i] = colors[i].a;
		}

		//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, ref partInfo, false))
		if (!HEU_InputMeshUtility.SetMeshVertexAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_COLOR, 3, rgb, vertIndices, ref partInfo, false))
		{
		    Debug.LogError("Failed to set input geometry colors.");
		    return false;
		}

		//if(!SetMeshPointAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, ref partInfo, false))
		if (!HEU_InputMeshUtility.SetMeshVertexFloatAttribute(session, displayNodeID, 0, HEU_Defines.HAPI_ATTRIB_ALPHA, 1, alpha, vertIndices, ref partInfo))
		{
		    Debug.LogError("Failed to set input geometry color alpha.");
		    return false;
		}
	    }

	    // Set material names for round-trip perservation of material assignment
	    // Each HEU_UploadMeshData might have a list of submeshes and materials
	    // These are all combined into a single mesh, with group names
	    if (numMaterials > 0)
	    {
		bool bFoundAtleastOneValidMaterial = false;

		string[] materialIDs = new string[partInfo.faceCount];
		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    if (inputDataMeshes._inputMeshes[g]._numSubMeshes != inputDataMeshes._inputMeshes[g]._materials.Length)
		    {
			// Number of submeshes should equal number of materials since materials determine submeshes
			continue;
		    }

		    for (int i = 0; i < inputDataMeshes._inputMeshes[g]._materials.Length; ++i)
		    {
			string materialName = HEU_AssetDatabase.GetAssetPathWithSubAssetSupport(inputDataMeshes._inputMeshes[g]._materials[i]);
			if (materialName == null)
			{
			    materialName = "";
			}
			else if (materialName.StartsWith(HEU_Defines.DEFAULT_UNITY_BUILTIN_RESOURCES))
			{
			    materialName = HEU_AssetDatabase.GetUniqueAssetPathForUnityAsset(inputDataMeshes._inputMeshes[g]._materials[i]);
			}

			bFoundAtleastOneValidMaterial |= !string.IsNullOrEmpty(materialName);

			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    materialIDs[m] = materialName;
			}
		    }
		}

		if (bFoundAtleastOneValidMaterial)
		{
		    HAPI_AttributeInfo materialIDAttrInfo = new HAPI_AttributeInfo();
		    materialIDAttrInfo.exists = true;
		    materialIDAttrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
		    materialIDAttrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
		    materialIDAttrInfo.count = partInfo.faceCount;
		    materialIDAttrInfo.tupleSize = 1;
		    materialIDAttrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

		    if (!session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo))
		    {
			Debug.LogError("Failed to add input geometry unity material name attribute.");
			return false;
		    }

		    if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityMaterialAttribName, ref materialIDAttrInfo, materialIDs, session.SetAttributeStringData, partInfo.faceCount))
		    {
			Debug.LogError("Failed to set input geometry unity material name.");
			return false;
		    }
		}
	    }

	    // Set mesh name attribute
	    HAPI_AttributeInfo attrInfo = new HAPI_AttributeInfo();
	    attrInfo.exists = true;
	    attrInfo.owner = HAPI_AttributeOwner.HAPI_ATTROWNER_PRIM;
	    attrInfo.storage = HAPI_StorageType.HAPI_STORAGETYPE_STRING;
	    attrInfo.count = partInfo.faceCount;
	    attrInfo.tupleSize = 1;
	    attrInfo.originalOwner = HAPI_AttributeOwner.HAPI_ATTROWNER_INVALID;

	    if (session.AddAttribute(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo))
	    {
		string[] primitiveNameAttr = new string[partInfo.faceCount];

		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    for (int i = 0; i < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++i)
		    {
			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[i] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[i] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    primitiveNameAttr[m] = inputDataMeshes._inputMeshes[g]._meshPath;
			}
		    }
		}

		if (!HEU_GeneralUtility.SetAttributeArray(displayNodeID, 0, HEU_PluginSettings.UnityInputMeshAttr, ref attrInfo, primitiveNameAttr, session.SetAttributeStringData, partInfo.faceCount))
		{
		    Debug.LogError("Failed to set input geometry unity mesh name.");
		    return false;
		}
	    }
	    else
	    {
		return false;
	    }

	    // Set LOD group membership
	    if (inputDataMeshes._hasLOD)
	    {
		int[] membership = new int[partInfo.faceCount];

		for (int g = 0; g < inputDataMeshes._inputMeshes.Count; ++g)
		{
		    if (g > 0)
		    {
			// Clear array
			for (int m = 0; m < partInfo.faceCount; ++m)
			{
			    membership[m] = 0;
			}
		    }

		    // Set 1 for faces belonging to this group
		    for (int s = 0; s < inputDataMeshes._inputMeshes[g]._numSubMeshes; ++s)
		    {
			int faceStart = (int)inputDataMeshes._inputMeshes[g]._indexStart[s] / numVertsPerFace;
			int faceEnd = faceStart + ((int)inputDataMeshes._inputMeshes[g]._indexCount[s] / numVertsPerFace);
			for (int m = faceStart; m < faceEnd; ++m)
			{
			    membership[m] = 1;
			}
		    }

		    if (!session.AddGroup(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName))
		    {
			Debug.LogError("Failed to add input geometry LOD group name.");
			return false;
		    }

		    if (!session.SetGroupMembership(displayNodeID, 0, HAPI_GroupType.HAPI_GROUPTYPE_PRIM, inputDataMeshes._inputMeshes[g]._meshName, membership, 0, partInfo.faceCount))
		    {
			Debug.LogError("Failed to set input geometry LOD group name.");
			return false;
		    }
		}
	    }

	    return session.CommitGeo(displayNodeID);
	}