/// <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); }
/// <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); }