private static void TestSimplePlane(int dimension, Vector3 bounds, Matrix4x4 vertDataTransform, Matrix4x4 meshTransform) { List <PlaneFinding.MeshData> meshes = new List <PlaneFinding.MeshData>(); meshes.Add(Util.CreateSimpleMesh(dimension, bounds, vertDataTransform, meshTransform)); BoundedPlane[] planes = PlaneFinding.FindPlanes(meshes, 0.0f, 0.0f); Assert.AreEqual(1, planes.Length); AssertExpectedPlane(planes[0], bounds, vertDataTransform, meshTransform); }
private void Update() { // Grab the necessary mesh data from the current set of surfaces that we want to run // PlaneFinding against. This must be done on the main UI thread. meshData.Clear(); foreach (MeshFilter mesh in GetComponentsInChildren <MeshFilter>()) { meshData.Add(new PlaneFinding.MeshData(mesh)); } // Now call FindPlanes(). NOTE: In a real application, this MUST be executed on a // background thread (i.e.: via ThreadPool.QueueUserWorkItem) so that it doesn't stall the // rendering thread while running plane finding. Maintaining a solid 60fps is crucial // to a good user experience. planes = (VisualizeSubPlanes) ? PlaneFinding.FindSubPlanes(meshData, SnapToGravityThreshold) : PlaneFinding.FindPlanes(meshData, SnapToGravityThreshold, MinArea); }
static void Main(string[] args) { List <PlaneFinding.MeshData> meshes = new List <PlaneFinding.MeshData>(); meshes.Add(Util.CreateSimpleMesh(10, new Vector3(5, 5, 0))); BoundedPlane[] planes = PlaneFinding.FindPlanes(meshes, 0.0f, 0.0f); Console.WriteLine("Found {0} meshes", planes.Length); for (int i = 0; i < planes.Length; ++i) { Console.WriteLine("{0}:", i); Console.WriteLine(" Area: {0}", planes[i].Area.ToString("0.000")); Console.WriteLine(" Center: {0}", planes[i].Bounds.Center.ToString("0.000")); Console.WriteLine(" Extents: {0}", planes[i].Bounds.Extents.ToString("0.000")); Console.WriteLine(" Normal: {0}", planes[i].Plane.normal.ToString("0.000")); Console.WriteLine(); } }
static void Main() { List <PlaneFinding.MeshData> meshes = new List <PlaneFinding.MeshData> { Util.CreateSimpleMesh(10, new Vector3(5, 5, 0)) }; BoundedPlane[] planes = PlaneFinding.FindPlanes(meshes, 0.0f, 0.0f); Console.WriteLine($"Found {planes.Length} plane{(planes.Length != 1 ? "s" : "")}"); for (int i = 0; i < planes.Length; ++i) { Console.WriteLine("{0}:", i); Console.WriteLine(" Area: {0}", planes[i].Area.ToString("0.000")); Console.WriteLine(" Center: {0}", planes[i].Bounds.Center.ToString("0.000")); Console.WriteLine(" Extents: {0}", planes[i].Bounds.Extents.ToString("0.000")); Console.WriteLine(" Normal: {0}", planes[i].Plane.normal.ToString("0.000")); Console.WriteLine(); } Console.ReadKey(); }
private void FindMergedPlanes() { Vector3 hlWorldPosition = MixedRealityCamera.transform.position; Quaternion hlWorldRotation = MixedRealityCamera.transform.rotation; // Should not run plane finding on main Unity thread var planeFindingProcess = Task.Run(() => { m_mergedBoundingPlanes = PlaneFinding.FindPlanes(m_collectedMeshData, snapToGravityThreshold, MinimumPlaneArea).ToList(); if (m_mergedBoundingPlanes.Count > 0) { m_PlaneFindingSuccess.Set(); } else { m_PlaneFindingFailed.Set(); } // Update Dictionary ParseRawPlaneData(hlWorldPosition); }); }
//----------------------------------------------------------------------------------------------- #region Private Functions /// <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(List <HoloToolkit.Unity.SpatialMapping.PlaneFinding.MeshData> meshData) { MakingPlanes = true; #if UNITY_WSA && !UNITY_EDITOR // 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, m_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, m_MinArea); #endif // Pause our work here, and continue on the next frame. yield return(null); float start = Time.realtimeSinceStartup; float maxFloorArea = 0.0f; float maxCeilingArea = 0.0f; FloorYPosition = 0.0f; CeilingYPosition = 0.0f; // 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. for (int i = 0; i < planes.Length; i++) { BoundedPlane boundedPlane = planes[i]; if (boundedPlane.Bounds.Center.y < 0 && boundedPlane.Plane.normal.y >= m_UpNormalThreshold) { maxFloorArea = Mathf.Max(maxFloorArea, boundedPlane.Area); if (maxFloorArea == boundedPlane.Area) { FloorYPosition = boundedPlane.Bounds.Center.y; } } else if (boundedPlane.Bounds.Center.y > 0 && boundedPlane.Plane.normal.y <= -(m_UpNormalThreshold)) { maxCeilingArea = Mathf.Max(maxCeilingArea, boundedPlane.Area); if (maxCeilingArea == boundedPlane.Area) { CeilingYPosition = boundedPlane.Bounds.Center.y; } } } int newPlanes = 0; List <SurfacePlane> oldPlanes = new List <SurfacePlane>(m_ActivePlanes); // Create SurfacePlane objects to represent each plane found in the Spatial Mapping mesh. for (int index = 0; index < planes.Length; index++) { BoundedPlane boundedPlane = planes[index]; boundedPlane.Bounds.Extents.z = m_PlaneThickness / 2.0f; SurfacePlane plane = CheckForExistingPlane(oldPlanes, boundedPlane); bool planeExisted = plane != null; if (plane == null) { newPlanes++; // This is a new plane. GameObject newPlaneObj = GameObject.CreatePrimitive(PrimitiveType.Cube); plane = newPlaneObj.AddComponent <SurfacePlane>(); newPlaneObj.GetComponent <Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; newPlaneObj.transform.parent = planesParent.transform; newPlaneObj.name = "Plane " + m_PlaneId; m_PlaneId++; plane.PlaneType = GetPlaneType(boundedPlane); SetPlaneMaterial(plane); } else { oldPlanes.Remove(plane); } // Set the Plane property to adjust transform position/scale/rotation and determine plane type. plane.PlaneThickness = m_PlaneThickness; plane.Plane = boundedPlane; // Set the plane to use the same layer as the SpatialMapping mesh. Do this every time incase the layer has changed. plane.gameObject.layer = SpatialMappingManager.Instance.PhysicsLayer; SetPlaneVisibility(plane); if ((m_DestroyPlanesMask & plane.PlaneType) == plane.PlaneType) { DestroyImmediate(plane.gameObject); } else if (!planeExisted) { AddPlane(plane); } // 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; } } for (int index = 0; index < oldPlanes.Count; index++) { RemovePlane(oldPlanes[index]); Destroy(oldPlanes[index].gameObject); } // We are done creating planes, trigger an event. EventHandler handler = MakePlanesComplete; if (handler != null) { handler(this, EventArgs.Empty); } MakingPlanes = false; }