/// <summary> /// Adds new bounding objects to the end of the Queue. /// </summary> /// <param name="boundingObjects">Collection of GameObjects which define the bounds where spatial mesh vertices should be removed.</param> private void AddBoundingObjectsToQueue(IEnumerable <GameObject> boundingObjects, bool createMesh) { foreach (GameObject item in boundingObjects) { Bounds bounds = new Bounds(); Collider boundingCollider = item.GetComponent <Collider>(); if (boundingCollider != null) { bounds = boundingCollider.bounds; // Expand the bounds, if requested. if (BoundsExpansion > 0.0f) { bounds.Expand(BoundsExpansion); } BoundsContainer container = new BoundsContainer(); container.bounds = bounds; container.createMesh = createMesh; boundingObjectsQueue.Enqueue(container); } } }
/// <summary> /// Iterator block, analyzes surface meshes to find vertices existing within the bounds of any boundingObject and removes them. /// </summary> /// <returns>Yield result.</returns> private IEnumerator RemoveSurfaceVerticesWithinBoundsRoutine() { List <MeshFilter> meshFilters = SpatialMappingManager.Instance.GetMeshFilters(); float start = Time.realtimeSinceStartup; List <Vector3> removedObjectVertices = new List <Vector3>(); List <Vector3> removedObjectNormals = new List <Vector3>(); List <int> removedObjectIndices = new List <int>(); while (boundingObjectsQueue.Count > 0) { // Get the current boundingObject. BoundsContainer container = boundingObjectsQueue.Dequeue(); Bounds bounds = container.bounds; foreach (MeshFilter filter in meshFilters) { // Since this is amortized across frames, the filter can be destroyed by the time // we get here. if (filter == null) { continue; } Mesh mesh = filter.sharedMesh; MeshRenderer renderer = filter.GetComponent <MeshRenderer>(); // The mesh renderer bounds are in world space. // If the mesh is null there is nothing to process // If the renderer is null we can't get the renderer bounds // If the renderer's bounds aren't contained inside of the current // bounds from the bounds queue there is no reason to process // If any of the above conditions are met, then we should go to the next meshfilter. if (mesh == null || renderer == null || !renderer.bounds.Intersects(bounds)) { continue; } // Remove vertices from any mesh that intersects with the bounds. Vector3[] verts = mesh.vertices; List <int> vertsToRemove = new List <int>(); // Find which mesh vertices are within the bounds. for (int i = 0; i < verts.Length; ++i) { if (bounds.Contains(filter.transform.TransformPoint(verts[i]))) { // These vertices are within bounds, so mark them for removal. vertsToRemove.Add(i); } // If too much time has passed, we need to return control to the main game loop. if ((Time.realtimeSinceStartup - start) > FrameTime) { // Pause our work here, and continue finding vertices to remove on the next frame. yield return(null); start = Time.realtimeSinceStartup; } } // If we did not find any vertices to remove, continue to the next mesh. if (vertsToRemove.Count == 0) { continue; } // We found vertices to remove, so now we need to remove any triangles that reference these vertices. int[] indices = mesh.GetTriangles(0); List <int> updatedIndices = new List <int>(); List <int> removedIndices = new List <int>(); List <int> boundaryVertices = new List <int>(); for (int index = 0; index < indices.Length; index += 3) { // Each triangle utilizes three slots in the index buffer, check to see if any of the // triangle indices contain a vertex that should be removed. int indexA = indices[index]; int indexB = indices[index + 1]; int indexC = indices[index + 2]; bool containsA = vertsToRemove.Contains(indexA); bool containsB = vertsToRemove.Contains(indexB); bool containsC = vertsToRemove.Contains(indexC); if (containsA || containsB || containsC) { // Do nothing, we don't want to save this triangle... // Instead, keep track of it for the removed mesh removedIndices.Add(indexA); removedIndices.Add(indexB); removedIndices.Add(indexC); // Also add any vertices that will be needed to reproduce the triangles in the removed mesh if (!containsA && !boundaryVertices.Contains(indexA)) { boundaryVertices.Add(indexA); } if (!containsB && !boundaryVertices.Contains(indexB)) { boundaryVertices.Add(indexB); } if (!containsC && !boundaryVertices.Contains(indexC)) { boundaryVertices.Add(indexC); } } else { // Every vertex in this triangle is good, so let's save it. updatedIndices.Add(indexA); updatedIndices.Add(indexB); updatedIndices.Add(indexC); } // If too much time has passed, we need to return control to the main game loop. if ((Time.realtimeSinceStartup - start) > FrameTime) { // Pause our work, and continue making additional planes on the next frame. yield return(null); start = Time.realtimeSinceStartup; } } // If none of the verts to remove were being referenced in the triangle list, continue if (indices.Length == updatedIndices.Count) { continue; } // Update mesh to use the new triangles. mesh.SetTriangles(updatedIndices.ToArray(), 0); mesh.RecalculateBounds(); yield return(null); start = Time.realtimeSinceStartup; if (container.createMesh) { /* SETUP BUFFERS FOR REMOVED MESH */ SortedDictionary <int, int> vertexMap = new SortedDictionary <int, int>(); //List<int> remappedIndices = new List<int>(); vertsToRemove.AddRange(boundaryVertices); vertsToRemove.Sort(); // Use a dictionary to allow faster remapping of indices for (int k = 0; k < vertsToRemove.Count; k++) { int index = vertsToRemove[k]; vertexMap.Add(index, k + removedObjectVertices.Count); } // Add vertices to removed mesh for (int k = 0; k < vertsToRemove.Count; k++) { int index = vertsToRemove[k]; Vector3 vertex = filter.transform.localToWorldMatrix.MultiplyPoint(verts[index]); removedObjectVertices.Add(vertex); Vector3 normal = mesh.normals[index]; removedObjectNormals.Add(normal); } // Add remapped indices to removed mesh for (int k = 0; k < removedIndices.Count; k++) { int oldIndex = removedIndices[k]; int newIndex = vertexMap[oldIndex]; removedObjectIndices.Add(newIndex); } yield return(null); start = Time.realtimeSinceStartup; } // Reset the mesh collider to fit the new mesh. MeshCollider collider = filter.gameObject.GetComponent <MeshCollider>(); if (collider != null) { collider.sharedMesh = null; collider.sharedMesh = mesh; } } if (container.createMesh) { // Create a GameObject from the removed vertices createRemovedObject(removedObjectVertices, removedObjectNormals, removedObjectIndices); } } Debug.Log("Finished removing vertices."); // We are done removing vertices, trigger an event. EventHandler handler = RemoveVerticesComplete; if (handler != null) { handler(this, EventArgs.Empty); } removingVerts = false; }