/// <summary> /// Coroutine that spreads the work of displaying scene objects across multiple frames. /// </summary> /// <returns>IEnumerator.</returns> private IEnumerator DisplayData() { StatusText.Clear(); StatusText.Append("About to display the latest set of scene objects."); StatusText.Append(string.Format("Current Settings:-\n\tRenderSceneObjects: {0}; SceneObjectVisualizationMode: {1}; RenderInferredRegions: {2};\n\tRenderPlatform: {3}; RenderBackground: {4}; RenderUnknown: {5}; RenderCompletelyInferred: {6};\n\tRenderWorldMesh: {7}; WorldMeshLOD: {8};\n\tBoundingSphereRadiusInMeters: {9};", RenderSceneObjects, SceneObjectVisualizationMode.ToString(), SUDataProvider.RequestInferredRegions, RenderPlatformSceneObjects, RenderBackgroundSceneObjects, RenderUnknownSceneObjects, RenderCompletelyInferredSceneObjects, RenderWorldMesh, SUDataProvider.WorldMeshLOD.ToString(), SUDataProvider.BoundingSphereRadiusInMeters)); // First, get the latest scene from the data provider. Tuple <Guid, byte[]> latestSceneData = SUDataProvider.GetLatestSerializedScene(); byte[] serializedScene = latestSceneData.Item2; if (serializedScene != null) { // Then, deserialize the scene. SceneUnderstanding.Scene scene = SceneUnderstanding.Scene.Deserialize(serializedScene); if (scene != null) { // This will destroy all game objects under root. SUUtils.DestroyAllGameObjectsUnderParent(SceneRoot.transform); // Return to account for the destruction of the game objects at the end of the frame. yield return(null); // Retrieve the Scene to Unity world transform. System.Numerics.Matrix4x4?sceneToUnityTransform = TransformUtils.GetSceneToUnityTransform(scene.OriginSpatialGraphNodeId, SUDataProvider.RunOnDevice); if (sceneToUnityTransform != null) { // This will place the root object that represents the scene in the right place. TransformUtils.SetUnityTransformFromMatrix4x4(sceneToUnityTransform.Value, SceneRoot.transform); // Retrieve all the scene objects, associated with this scene. IEnumerable <SceneUnderstanding.SceneObject> sceneObjects = scene.SceneObjects; int i = 0; foreach (SceneUnderstanding.SceneObject sceneObject in sceneObjects) { if (DisplaySceneObject(sceneObject)) { ++i; if (i % 5 == 0) { yield return(null); } } } } // When running on PC, orient the main camera such that the floor is on the Unity world's X-Z plane. if (SUDataProvider.RunOnDevice == false) { SUUtils.OrientSceneRootForPC(SceneRoot, scene); } } } StatusText.Append("SceneUnderstandingDisplayManager.DisplayData: Display completed."); _displayInProgress = false; _lastDisplayedSceneGuid = latestSceneData.Item1; }
/// <summary> /// Saves a serialized scene from Scene Understanding to disk as obj files. One obj file is saved per class, i.e. one file for walls, one file for ceilings, etc. /// </summary> /// <param name="serializedScene">Serialized scene.</param> /// <returns>Task.</returns> public static async Task SaveObjsToDiskAsync(byte[] serializedScene) { if (serializedScene == null) { Logger.LogWarning("SceneUnderstandingSaveDataUtils.SaveObjsToDisk: Nothing to save."); return; } // Deserialize the scene. SceneUnderstanding.Scene scene = SceneUnderstanding.Scene.Deserialize(serializedScene); // List of all SceneObjectKind enum values. List <SceneUnderstanding.SceneObjectKind> sceneObjectKinds = Enum.GetValues(typeof(SceneUnderstanding.SceneObjectKind)).Cast <SceneUnderstanding.SceneObjectKind>().ToList(); List <Task> tasks = new List <Task>(); foreach (SceneUnderstanding.SceneObjectKind soKind in sceneObjectKinds) { tasks.Add(SaveSceneObjectsAsObjAsync( scene.SceneObjects.Where <SceneUnderstanding.SceneObject>(so => so.Kind == soKind), SceneUnderstandingUtils.GetColorForLabel(soKind) == null ? Color.black : SceneUnderstandingUtils.GetColorForLabel(soKind).Value, string.Format("{0}_{1}", GetDefaultFileName(), soKind.ToString()))); } await Task.WhenAll(tasks); }
/// <summary> /// Orients the root game object, such that the Scene Understanding floor lies on the Unity world's X-Z plane. /// </summary> /// <param name="sceneRoot">Root game object.</param> /// <param name="scene">Scene Understanding scene.</param> public void OrientSceneRootForPC(GameObject sceneRoot, SceneUnderstanding.Scene scene) { if (scene == null) { Logger.LogWarning("SceneUnderstandingUtils.OrientSceneRootForPC: Scene is null."); return; } IEnumerable <SceneUnderstanding.SceneObject> sceneObjects = scene.SceneObjects; float areaForlargestFloorSoFar = 0; SceneUnderstanding.SceneObject floorSceneObject = null; SceneUnderstanding.SceneQuad floorQuad = null; // Find the largest floor quad. foreach (SceneUnderstanding.SceneObject so in sceneObjects) { if (so.Kind == SceneUnderstanding.SceneObjectKind.Floor) { IEnumerable <SceneUnderstanding.SceneQuad> quads = so.Quads; if (quads != null) { foreach (SceneUnderstanding.SceneQuad quad in quads) { float quadArea = quad.Extents.X * quad.Extents.Y; if (quadArea > areaForlargestFloorSoFar) { areaForlargestFloorSoFar = quadArea; floorSceneObject = so; floorQuad = quad; } } } } } if (floorQuad != null) { // Compute the floor quad's normal. float widthInMeters = floorQuad.Extents.X; float heightInMeters = floorQuad.Extents.Y; System.Numerics.Vector3 point1 = new System.Numerics.Vector3(-widthInMeters / 2, -heightInMeters / 2, 0); System.Numerics.Vector3 point2 = new System.Numerics.Vector3(widthInMeters / 2, -heightInMeters / 2, 0); System.Numerics.Vector3 point3 = new System.Numerics.Vector3(-widthInMeters / 2, heightInMeters / 2, 0); System.Numerics.Matrix4x4 floorTransform = floorSceneObject.GetLocationAsMatrix(); floorTransform = TransformUtils.ConvertRightHandedMatrix4x4ToLeftHanded(floorTransform); System.Numerics.Vector3 tPoint1 = System.Numerics.Vector3.Transform(point1, floorTransform); System.Numerics.Vector3 tPoint2 = System.Numerics.Vector3.Transform(point2, floorTransform); System.Numerics.Vector3 tPoint3 = System.Numerics.Vector3.Transform(point3, floorTransform); System.Numerics.Vector3 p21 = tPoint2 - tPoint1; System.Numerics.Vector3 p31 = tPoint3 - tPoint1; System.Numerics.Vector3 floorNormal = System.Numerics.Vector3.Cross(p31, p21); // Numerics to Unity conversion. Vector3 floorNormalUnity = new Vector3(floorNormal.X, floorNormal.Y, floorNormal.Z); // Get the rotation between the floor normal and Unity world's up vector. Quaternion rotation = Quaternion.FromToRotation(floorNormalUnity, Vector3.up); // Apply the rotation to the root, so that the floor is on the Camera's x-z plane. sceneRoot.transform.rotation = rotation; } }