/// <summary> /// Handles the SurfaceObserver's OnSurfaceChanged event. /// </summary> /// <param name="id">The identifier assigned to the surface which has changed.</param> /// <param name="changeType">The type of change that occurred on the surface.</param> /// <param name="bounds">The bounds of the surface.</param> /// <param name="updateTime">The date and time at which the change occurred.</param> private void SurfaceObserver_OnSurfaceChanged(SurfaceId id, SurfaceChange changeType, Bounds bounds, DateTime updateTime) { var soundManager = GameObject.Find("Audio Source"); HoloToolkit.Unity.TextToSpeech t2s = soundManager.GetComponent <HoloToolkit.Unity.TextToSpeech>(); t2s.Voice = HoloToolkit.Unity.TextToSpeechVoice.Zira; t2s.StartSpeaking("Observer 1"); // Verify that the client of the Surface Observer is expecting updates. if (ObserverState != ObserverStates.Running) { return; } switch (changeType) { case SurfaceChange.Added: case SurfaceChange.Updated: surfaceWorkQueue.Enqueue(id); break; case SurfaceChange.Removed: SurfaceObject?removedSurface = RemoveSurfaceIfFound(id.handle, destroyGameObject: false); if (removedSurface != null) { ReclaimSurface(removedSurface.Value); } break; default: Debug.LogErrorFormat("Unexpected {0} value: {1}.", changeType.GetType(), changeType); break; } }
/// <summary> /// Iterator block, analyzes surface meshes to find planes and create new 3D cubes to represent each plane. /// </summary> /// <returns>Yield result.</returns> private IEnumerator MakePlanesRoutine() { // Remove any previously existing planes, as they may no longer be valid. for (int index = 0; index < ActivePlanes.Count; index++) { Destroy(ActivePlanes[index]); } // Pause our work, and continue on the next frame. yield return(null); float start = Time.realtimeSinceStartup; ActivePlanes.Clear(); // Get the latest Mesh data from the Spatial Mapping Manager. List <PlaneFinding.MeshData> meshData = new List <PlaneFinding.MeshData>(); List <MeshFilter> filters = SpatialMappingManager.Instance.GetMeshFilters(); for (int index = 0; index < filters.Count; index++) { MeshFilter filter = filters[index]; if (filter != null && filter.sharedMesh != null) { // fix surface mesh normals so we can get correct plane orientation. filter.mesh.RecalculateNormals(); meshData.Add(new PlaneFinding.MeshData(filter)); } if ((Time.realtimeSinceStartup - start) > FrameTime) { // Pause our work, and continue to make more PlaneFinding objects on the next frame. yield return(null); start = Time.realtimeSinceStartup; } } // Pause our work, and continue on the next frame. yield return(null); #if !UNITY_EDITOR && UNITY_WSA // When not in the unity editor we can use a cool background task to help manage FindPlanes(). Task <BoundedPlane[]> planeTask = Task.Run(() => PlaneFinding.FindPlanes(meshData, snapToGravityThreshold, MinArea)); while (planeTask.IsCompleted == false) { yield return(null); } BoundedPlane[] planes = planeTask.Result; #else // In the unity editor, the task class isn't available, but perf is usually good, so we'll just wait for FindPlanes to complete. BoundedPlane[] planes = PlaneFinding.FindPlanes(meshData, snapToGravityThreshold, MinArea); #endif // Pause our work here, and continue on the next frame. yield return(null); start = Time.realtimeSinceStartup; float maxFloorArea = 0.0f; float maxCeilingArea = 0.0f; FloorYPosition = 0.0f; CeilingYPosition = 0.0f; float upNormalThreshold = 0.9f; if (SurfacePlanePrefab != null && SurfacePlanePrefab.GetComponent <SurfacePlane>() != null) { upNormalThreshold = SurfacePlanePrefab.GetComponent <SurfacePlane>().UpNormalThreshold; } // Find the floor and ceiling. // We classify the floor as the maximum horizontal surface below the user's head. // We classify the ceiling as the maximum horizontal surface above the user's head. var soundManager = GameObject.Find("Audio Source"); HoloToolkit.Unity.TextToSpeech t2s = soundManager.GetComponent <HoloToolkit.Unity.TextToSpeech>(); t2s.Voice = HoloToolkit.Unity.TextToSpeechVoice.Zira; t2s.StartSpeaking(planes.Length + "planes have been found"); for (int i = 0; i < planes.Length; i++) { t2s.StartSpeaking("found plane " + i); BoundedPlane boundedPlane = planes[i]; if (boundedPlane.Bounds.Center.y < 0 && boundedPlane.Plane.normal.y >= upNormalThreshold) { maxFloorArea = Mathf.Max(maxFloorArea, boundedPlane.Area); if (maxFloorArea == boundedPlane.Area) { FloorYPosition = boundedPlane.Bounds.Center.y; t2s.StartSpeaking("found floor"); } } else if (boundedPlane.Bounds.Center.y > 0 && boundedPlane.Plane.normal.y <= -(upNormalThreshold)) { maxCeilingArea = Mathf.Max(maxCeilingArea, boundedPlane.Area); if (maxCeilingArea == boundedPlane.Area) { CeilingYPosition = boundedPlane.Bounds.Center.y; } } } t2s.StartSpeaking("finished finding floor"); GameObject[] walls = GameObject.FindGameObjectsWithTag("staticWall"); for (int i = 0; i < walls.Length; i++) { walls[i].transform.position.Set(walls[i].transform.position.x, FloorYPosition + 15.0f, walls[i].transform.position.z); } t2s.StartSpeaking("walls should be done"); // Create SurfacePlane objects to represent each plane found in the Spatial Mapping mesh. for (int index = 0; index < planes.Length; index++) { GameObject destinationPlane; BoundedPlane boundedPlane = planes[index]; // Instantiate a SurfacePlane object, which will have the same bounds as our BoundedPlane object. if (SurfacePlanePrefab != null && SurfacePlanePrefab.GetComponent <SurfacePlane>() != null) { destinationPlane = Instantiate(SurfacePlanePrefab); } else { destinationPlane = GameObject.CreatePrimitive(PrimitiveType.Cube); destinationPlane.AddComponent <SurfacePlane>(); destinationPlane.GetComponent <Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } destinationPlane.transform.parent = planesParent.transform; var surfacePlane = destinationPlane.GetComponent <SurfacePlane>(); // Set the Plane property to adjust transform position/scale/rotation and determine plane type. surfacePlane.Plane = boundedPlane; SetPlaneVisibility(surfacePlane); if ((destroyPlanesMask & surfacePlane.PlaneType) == surfacePlane.PlaneType) { DestroyImmediate(destinationPlane); } else { // Set the plane to use the same layer as the SpatialMapping mesh. destinationPlane.layer = SpatialMappingManager.Instance.PhysicsLayer; ActivePlanes.Add(destinationPlane); } // 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 making additional planes on the next frame. yield return(null); start = Time.realtimeSinceStartup; } } Debug.Log("Finished making planes."); // We are done creating planes, trigger an event. EventHandler handler = MakePlanesComplete; if (handler != null) { handler(this, EventArgs.Empty); } makingPlanes = false; }