public void GenerateLevel() { List <GameObject> tables = GetTablesInDescendingAreaOrder(); Debug.Log("GenerateLevel(): number of tables=" + tables.Capacity.ToString()); //TODO: check if empty and take corrective action if (tables.Capacity == 0) { // For now, place a big ugly gray cube if no tables found /* * GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); * cube.transform.parent = gameObject.transform; // level manager will be parent * cube.transform.localScale = new Vector3(0.5f, 0.5f, 0.5f); * cube.transform.position = new Vector3(0, 0, 2); * cube.GetComponent<Renderer>().material = m_flat_material; * cube.GetComponent<Renderer>().material.color = Color.grey; * cube.SetActive(true); */ return; } // Until we develop some real assets, just place cubes :) HoloToolkit.Unity.SurfacePlane city_plane = tables[0].GetComponent <HoloToolkit.Unity.SurfacePlane>(); Debug.Log("up=" + city_plane.transform.up.ToString("F2")); Debug.Log("forward=" + city_plane.transform.forward.ToString("F2")); Debug.Log("right=" + city_plane.transform.right.ToString("F2")); Debug.Log("normal=" + city_plane.Plane.Plane.normal.ToString("F2")); PlaceCube(0.25f, 0.75f, 0.25f, m_flat_material, Color.red, city_plane, -0.25f + 0.0f, 0.1f); PlaceCube(0.25f, 0.30f, 0.25f, m_flat_material, Color.green, city_plane, -0.50f - 0.1f, 0.1f); PlaceCube(0.25f, 0.40f, 0.25f, m_flat_material, Color.blue, city_plane, 0.0f + 0.1f, 0.25f + 0.1f); }
/// <summary> /// Gets all active planes of the specified type(s). /// </summary> /// <param name="planeTypes">A flag which includes all plane type(s) that should be returned.</param> /// <returns>A collection of planes that match the expected type(s).</returns> public List <GameObject> GetActivePlanes(PlaneTypes planeTypes) { List <GameObject> typePlanes = new List <GameObject>(); foreach (GameObject plane in ActivePlanes) { SurfacePlane surfacePlane = plane.GetComponent <SurfacePlane>(); if (surfacePlane != null) { if ((planeTypes & surfacePlane.PlaneType) == surfacePlane.PlaneType) { typePlanes.Add(plane); } } } return(typePlanes); }
/// <summary> /// Sets visibility of planes based on their type. /// </summary> /// <param name="surfacePlane"></param> private void SetPlaneVisibility(SurfacePlane surfacePlane) { surfacePlane.IsVisible = ((drawPlanesMask & surfacePlane.PlaneType) == surfacePlane.PlaneType); }
/// <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_METRO // 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. for (int i = 0; i < planes.Length; 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; } } 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; } } } // Create SurfacePlane objects to represent each plane found in the Spatial Mapping mesh. for (int index = 0; index < planes.Length; index++) { GameObject destPlane; 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) { destPlane = Instantiate(SurfacePlanePrefab); } else { destPlane = GameObject.CreatePrimitive(PrimitiveType.Cube); destPlane.AddComponent <SurfacePlane>(); destPlane.GetComponent <Renderer>().shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off; } destPlane.transform.parent = planesParent.transform; SurfacePlane surfacePlane = destPlane.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(destPlane); } else { // Set the plane to use the same layer as the SpatialMapping mesh. destPlane.layer = SpatialMappingManager.Instance.PhysicsLayer; ActivePlanes.Add(destPlane); } // 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; }
private void PlaceCube(float width, float height, float depth, Material material, Color color, HoloToolkit.Unity.SurfacePlane plane, float local_x, float local_z) { // // Plane coordinate system is different from Unity world convention: // x,y (right,up) -> plane surface // z (forward) -> perpendicular to plane surface // To further add to confusion, the forward direction is not necessarily // the same as the normal, and can be its inverse. We must test for this // situation and rotate 180 degrees about (local) x, y. // // World xz -> plane xy float x = local_x; float y = local_z; float size_x = width; float size_y = depth; float size_z = height; // Construct rotation from plane to world space Vector3 origin = plane.transform.position; Quaternion rotation = plane.transform.rotation; if (plane.transform.forward.y < 0) // plane is oriented upside down { rotation = Quaternion.LookRotation(-plane.transform.forward, plane.transform.up); } // Place object in plane-local coordinate system; rotate to world system GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.transform.parent = gameObject.transform; // level manager will be parent cube.transform.localScale = new Vector3(size_x, size_y, size_z); cube.transform.position = origin + rotation * new Vector3(x, y, 0.5f * size_z); cube.transform.transform.rotation = rotation; cube.GetComponent <Renderer>().material = material; cube.GetComponent <Renderer>().material.color = color; // equivalent to SetColor("_Color", color) cube.SetActive(true); }