/// <summary> /// Applies the quad region mask on the passed in game object. /// </summary> /// <param name="quad">Scene Understanding quad.</param> /// <param name="go">Game object associated with the quad.</param> /// <param name="color">Color to use for the valid regions.</param> public void ApplyQuadRegionMask(SceneUnderstanding.SceneQuad quad, GameObject go, Color?color) { if (quad == null || go == null) { Logger.LogWarning("SceneUnderstandingUtils.ApplyQuadRegionMask: One or more arguments are null."); return; } // If no color has been provided, paint it red. color = color == null ? Color.red : color.Value; // Resolution of the mask. ushort width = 256; ushort height = 256; byte[] mask = new byte[width * height]; quad.GetSurfaceMask(width, height, mask); MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>(); if (meshRenderer == null || meshRenderer.material == null || meshRenderer.material.HasProperty("_MainTex") == false) { Logger.LogWarning("SceneUnderstandingUtils.ApplyQuadRegionMask: Mesh renderer component is null or does not have a valid material."); return; } // Create a new texture. Texture2D texture = new Texture2D(width, height); texture.filterMode = FilterMode.Bilinear; texture.wrapMode = TextureWrapMode.Clamp; // Transfer the invalidation mask onto the texture. Color[] pixels = texture.GetPixels(); for (int i = 0; i < pixels.Length; ++i) { var value = mask[i]; if (value == (byte)SceneUnderstanding.SceneRegionSurfaceKind.NotSurface) { pixels[i] = Color.clear; } else { pixels[i] = color.Value; } } texture.SetPixels(pixels); texture.Apply(true); // Set the texture on the material. meshRenderer.material.mainTexture = texture; }
/// <summary> /// Generates and returns a Unity mesh for a Scene Understanding quad. /// </summary> /// <param name="quad">Scene Understanding quad.</param> /// <returns>Unity mesh.</returns> public Mesh GenerateUnityMeshForSceneObjectQuad(SceneUnderstanding.SceneQuad quad) { if (quad == null) { Logger.LogWarning("SceneUnderstandingUtils.GenerateUnityMeshForSceneObjectQuad: Quad is null."); return(null); } float widthInMeters = quad.Extents.X; float heightInMeters = quad.Extents.Y; // Bounds of the quad. List <Vector3> vertices = new List <Vector3>() { new Vector3(-widthInMeters / 2, -heightInMeters / 2, 0), new Vector3(widthInMeters / 2, -heightInMeters / 2, 0), new Vector3(-widthInMeters / 2, heightInMeters / 2, 0), new Vector3(widthInMeters / 2, heightInMeters / 2, 0) }; List <int> triangles = new List <int>() { 1, 3, 0, 3, 2, 0 }; List <Vector2> uvs = new List <Vector2>() { new Vector2(0, 0), new Vector2(1, 0), new Vector2(0, 1), new Vector2(1, 1) }; Mesh unityMesh = new Mesh(); unityMesh.SetVertices(vertices); unityMesh.SetIndices(triangles.ToArray(), MeshTopology.Triangles, 0); unityMesh.SetUVs(0, uvs); return(unityMesh); }
/// <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; } }