/// <summary> /// /// Meshes /// /// Parse mesh data /// Function decides if we are updating an already existing mesh or creating a new one. /// If a new mesh has been created this function will go through stored mesh instances /// and check if it can create new mesh instances. /// </summary> public static void ParseMeshData(System.IntPtr meshDataPtr) { try { var meshData = (MeshData)System.Runtime.InteropServices.Marshal.PtrToStructure(meshDataPtr, typeof(MeshData)); // Convert unmanaged to managed memory ManagedMeshData managedMeshData = MeshHandler.ManageMeshMemory(meshData); // If all dependants are here, create or update the mesh bool dependencySuccess = MeshHandler.DependencyCheck(managedMeshData, meshData.entityToken); if (dependencySuccess) { ParseMeshData(meshData, managedMeshData); // Delete the data ImportMenu.stpUnityDeleteMeshData(meshDataPtr); } else { // If we are not able to create or update store the mesh data and try later meshDataStore.Add(meshDataPtr); } } catch (System.Exception e) { Debug.LogException(e); // Delete the data ImportMenu.stpUnityDeleteMeshData(meshDataPtr); } }
/// <summary> /// Create mesh /// Function that goes through the process of creating new mesh items. /// </summary> public static bool CreateMesh(MeshData meshData, ManagedMeshData managedMeshData) { Debug.LogFormat("Mesh - Token:{0}, Parent:{1}, {2} positions, {3} facesets", meshData.entityToken, meshData.entityParentToken, meshData.positionsNum, meshData.facesetsNum); // Get the index format of the mesh UnityEngine.Rendering.IndexFormat indexFormat; int maxVertexLimitSplit; GetIndexBufferConfiguration( managedMeshData.positions.Length, out indexFormat, out maxVertexLimitSplit); // Check if we need to split the mesh if (maxVertexLimitSplit == 0) { // Create simple mesh asset, create it's prefab object // and add it to the package mapper Mesh newMesh = new Mesh(); UpdateMeshData( managedMeshData.positions, managedMeshData.normals, managedMeshData.uvs, managedMeshData.facesetNum, managedMeshData.indices, indexFormat, ref newMesh ); CreateSimpleMeshAsset( meshData.entityToken, meshData.entityParentToken, meshData.displayName, managedMeshData.facesetNum, managedMeshData.materials, newMesh); } else { // Create split mesh assets, create hierarchy of prefabs // and add the root prefab to the package mapper List <Mesh> meshList = CreateSplitMeshes( meshData.entityToken, meshData.displayName, managedMeshData ); CreateSplitMeshAsset( meshData.entityToken, meshData.displayName, meshData.entityParentToken, managedMeshData.facesetNum, managedMeshData.materials, meshList); } return(true); }
/// <summary> /// Dependency check /// Checks if all of the dependencies of the mesh are available in Unity /// </summary> public static bool DependencyCheck(ManagedMeshData meshData, string entityToken) { // Check if we have materials available for (var i = 0; i < meshData.facesetNum; ++i) { if (!System.String.IsNullOrEmpty(meshData.materials[i])) { // Check if we have a material instance or material definition ready for this mesh if (!PackageMapper.GetMaterialFromToken(meshData.materials[i])) { // TODO: messages slow down the recieve mechanism and spam the log //Debug.LogWarningFormat("Material '{0}' for '{1}' has not yet been created!", // meshData.materials[i], // entityToken); return(false); } } } return(true); }
// Iterate through mesh store that were missing dependants and check if we can create new mesh objects // or update existing mesh objects public static void IterateMeshStore() { for (int i = meshDataStore.Count - 1; i >= 0; i--) { MeshData meshData = (MeshData)System.Runtime.InteropServices.Marshal.PtrToStructure(meshDataStore[i], typeof(MeshData)); // Convert unmanaged to managed memory ManagedMeshData managedMeshData = MeshHandler.ManageMeshMemory(meshData); // If all dependants are here, create or update the mesh if (MeshHandler.DependencyCheck(managedMeshData, meshData.entityToken)) { ParseMeshData(meshData, managedMeshData); // Delete the data ImportMenu.stpUnityDeleteMeshData(meshDataStore[i]); // Remove from the store meshDataStore.RemoveAt(i); } } }
/// <summary> /// Manage mesh memory /// Converts the marshaled unmanaged mesh memory to managed /// </summary> public static ManagedMeshData ManageMeshMemory(MeshData meshData) { ManagedMeshData managedMeshData = new ManagedMeshData(); managedMeshData.positions = MarshallPositions((int)meshData.positionsNum, meshData.positions); managedMeshData.normals = ((int)meshData.normalsNum > 0) ? MarshallNormals((int)meshData.normalsNum, meshData.normals) : null; managedMeshData.materials = new StringCollection(); managedMeshData.indices = new List <int[]>(); var facesetdataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(FacesetData)); var currentReadPtr = meshData.facesets; for (var i = 0; i < (int)meshData.facesetsNum; ++i) { FacesetData fs = (FacesetData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(FacesetData)); managedMeshData.materials.Add(fs.materialName); managedMeshData.indices.Add(MarshallTriangleIndices((int)fs.indicesNum, fs.indices)); currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, facesetdataSize); } managedMeshData.facesetNum = (int)meshData.facesetsNum; managedMeshData.uvs = new List <List <Vector2> >(); currentReadPtr = meshData.uvSets; var uvSetDataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(UVData)); for (var i = 0; i < (int)meshData.uvSetNum; ++i) { UVData uvData = (UVData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(UVData)); // Note: Not currently using triangle indices //managedMeshData.indices.Add(MarshallTriangleIndices((int)uvData.indicesNum, uvData.indices)); managedMeshData.uvs.Add(MarshallUVData((int)uvData.uvsNum, uvData.uvs)); currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, uvSetDataSize); } managedMeshData.uvNum = (int)meshData.uvSetNum; return(managedMeshData); }
private static void ParseMeshData(MeshData meshData, ManagedMeshData managedMeshData) { // Check if the mesh already exists in the package mapper if (PackageMapper.TokenExistsInCache(meshData.entityToken)) { // If mesh exists try to update it MeshHandler.UpdateMesh(meshData, managedMeshData); } else { // Create a new mesh object in Unity MeshHandler.CreateMesh(meshData, managedMeshData); // This loop starts over if we created a parent and a child is waiting in the store bool newItemCreated = true; while (newItemCreated) { // Iterate through mesh instance store and try to create or update // mesh instances that this mesh is a dependent of IterateMeshInstanceStore(out newItemCreated); } } }
UpdateSimpleMeshAsset( string entityToken, string displayName, ManagedMeshData managedMeshData, Mesh mesh, GameObject meshPrefab) { // Update the mesh renderer Material[] materials = GetMeshMaterials(managedMeshData.facesetNum, managedMeshData.materials, entityToken); var meshRenderer = meshPrefab.GetComponent <MeshRenderer>(); if (meshRenderer) { meshRenderer.materials = materials; } // Update mesh name mesh.name = displayName; AssetDatabase.SaveAssets(); return(true); }
CreateSplitMeshes( string entityToken, string displayName, ManagedMeshData managedMeshData) { List <Mesh> meshList = new List <Mesh>(); int max_vertex_limit_split; UnityEngine.Rendering.IndexFormat indexFormat; GetIndexBufferConfiguration( managedMeshData.positions.Length, out indexFormat, out max_vertex_limit_split); // now split the geometry into N meshes, as children of this new game object, and the identity transform var current_offset = 0; var remaining_vertices = managedMeshData.positions.Length; var split_index = 0; while (remaining_vertices > 0) { var segment_size = System.Math.Min(remaining_vertices, max_vertex_limit_split); var positionSegment = CopyArraySegment(managedMeshData.positions, current_offset, segment_size); var normalSegment = CopyArraySegment(managedMeshData.normals, current_offset, segment_size); if (positionSegment == null || normalSegment == null) { throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index))); } var indicesSegment = new List <int[]>(); for (var i = 0; i < managedMeshData.indices.Count; ++i) { var segment = CopyArraySegmentAndRebase(managedMeshData.indices[i], current_offset, segment_size); if (segment == null) { throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index))); } indicesSegment.Add(segment); } var uvSegment = new List <List <Vector2> >(); for (var i = 0; i < managedMeshData.uvNum; ++i) { uvSegment.Add(CopyListSegment(managedMeshData.uvs[i], current_offset, segment_size)); } Mesh mesh = new Mesh(); UpdateMeshData( positionSegment, normalSegment, uvSegment, managedMeshData.facesetNum, indicesSegment, indexFormat, ref mesh); if (!mesh) { throw new System.Exception(System.String.Format("Unindexed mesh creation failure! Token:{0} Name:{1} Part:{2}", entityToken, displayName, System.String.Format("Split_{0}", split_index))); } meshList.Add(mesh); current_offset += segment_size; remaining_vertices -= segment_size; ++split_index; } return(meshList); }
/// <summary> /// Update mesh /// Function that goes through the process of updating existing mesh item. /// Checking for unindexed or indexed meshes. /// </summary> public static bool UpdateMesh(MeshData meshData, ManagedMeshData managedMeshData) { Debug.LogFormat("Mesh Update - Token:{0}, Parent:{1}, {2} positions, {3} facesets", meshData.entityToken, meshData.entityParentToken, meshData.positionsNum, meshData.facesetsNum); // Find existing mesh Mesh mesh = PackageMapper.GetMeshFromToken(meshData.entityToken); if (!mesh) { return(false); } // Get the index format of the mesh UnityEngine.Rendering.IndexFormat indexFormat; int maxVertexLimitSplit; GetIndexBufferConfiguration( managedMeshData.positions.Length, out indexFormat, out maxVertexLimitSplit); // Get the prefab object GameObject prefab = PackageMapper.GetObjectFromToken(meshData.entityToken) as GameObject; // Check if we need to split the mesh if (maxVertexLimitSplit == 0) { // Update existing mesh UpdateMeshData( managedMeshData.positions, managedMeshData.normals, managedMeshData.uvs, managedMeshData.facesetNum, managedMeshData.indices, indexFormat, ref mesh ); UpdateSimpleMeshAsset( meshData.entityToken, meshData.displayName, managedMeshData, mesh, prefab ); } else { // Delete prefab first AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(prefab)); // Create split mesh assets, create hierarchy of prefabs // and add the root prefab to the package mapper List <Mesh> meshList = CreateSplitMeshes( meshData.entityToken, meshData.displayName, managedMeshData ); CreateSplitMeshAsset( meshData.entityToken, meshData.displayName, meshData.entityParentToken, managedMeshData.facesetNum, managedMeshData.materials, meshList); } mesh.UploadMeshData(false); return(true); }