/// <summary> /// Returns best placement position in local space to the plane /// </summary> /// <param name="plane">The <see cref="SpatialAwarenessMeshObject"/> who's plane will be used for placement</param> /// <param name="objExtents">Total width and height of object to be placed in meters.</param> /// <param name="placementPosOnPlane">Base position on plane in local space.</param> /// <returns>returns <see cref="false"/> if API returns null.</returns> public bool TryFindCentermostPlacement(Guid quadGuid, Vector2 objExtents, out Vector3 placementPosOnPlane) { Tuple <SceneQuad, SceneObject> result; if (!cachedSceneQuads.TryGetValue(quadGuid, out result)) { placementPosOnPlane = Vector2.zero; return(false); } SceneQuad quad = result.Item1; SceneObject sceneObject = result.Item2; System.Numerics.Vector2 ext = new System.Numerics.Vector2(objExtents.x, objExtents.y); System.Numerics.Vector2 centerPosition = new System.Numerics.Vector2(); quad.FindCentermostPlacement(ext, out centerPosition); // best placement origin is top left (2d sheet of paper) centerPosition -= quad.Extents / new System.Numerics.Vector2(2.0f); var centerUnity = new Vector3(centerPosition.X, centerPosition.Y, 0); placementPosOnPlane = (sceneObject.GetLocationAsMatrix() * sceneToWorldXformSystem * correctOrientation).ToUnity().MultiplyPoint(centerUnity); return(true); }
/// <summary> /// Orients the root game object, such that the Scene Understanding floor lies on the Unity world's X-Z plane. /// The floor type with the largest area is choosen as the reference. /// If no floor is found....??? /// </summary> /// <param name="scene">Scene Understanding scene.</param> private System.Numerics.Vector3 ToUpFromBiggestFloor(IReadOnlyList <SceneObject> sasos) { float areaForlargestFloorSoFar = 0; SceneObject floorSceneObject = null; SceneQuad floorQuad = null; var result = System.Numerics.Vector3.Zero; // Find the largest floor quad. var count = sasos.Count; for (var i = 0; i < count; ++i) { if (sasos[i].Kind == SceneObjectKind.Floor) { var quads = sasos[i].Quads; Assert.IsNotNull(quads); var qcount = quads.Count; for (int j = 0; j < qcount; j++) { float quadArea = quads[j].Extents.X * quads[j].Extents.Y; if (quadArea > areaForlargestFloorSoFar) { areaForlargestFloorSoFar = quadArea; floorSceneObject = sasos[i]; floorQuad = quads[j]; } } } } if (floorQuad != null) { // Compute the floor quad's normal. float halfWidthMeters = floorQuad.Extents.X * .5f; float halfHeightMeters = floorQuad.Extents.Y * .5f; System.Numerics.Vector3 point1 = new System.Numerics.Vector3(-halfWidthMeters, -halfHeightMeters, 0); System.Numerics.Vector3 point2 = new System.Numerics.Vector3(halfWidthMeters, -halfHeightMeters, 0); System.Numerics.Vector3 point3 = new System.Numerics.Vector3(-halfWidthMeters, halfHeightMeters, 0); System.Numerics.Matrix4x4 objectToSceneOrigin = floorSceneObject.GetLocationAsMatrix(); objectToSceneOrigin = RightToLeftHanded(objectToSceneOrigin); System.Numerics.Vector3 tPoint1 = System.Numerics.Vector3.Transform(point1, objectToSceneOrigin); System.Numerics.Vector3 tPoint2 = System.Numerics.Vector3.Transform(point2, objectToSceneOrigin); System.Numerics.Vector3 tPoint3 = System.Numerics.Vector3.Transform(point3, objectToSceneOrigin); System.Numerics.Vector3 p21 = tPoint2 - tPoint1; System.Numerics.Vector3 p31 = tPoint3 - tPoint1; result = System.Numerics.Vector3.Cross(p21, p31); } return(result); }
/// <summary> /// Apply Region mask to a Scene Object /// </summary> private void ApplyQuadRegionMask(SceneQuad quad, GameObject gameobject, Color color) { if (quad == null || gameobject == null) { Debug.LogWarning("SceneUnderstandingManager.ApplyQuadRegionMask: One or more arguments are null."); return; } // Resolution of the mask. ushort width = 256; ushort height = 256; byte[] mask = new byte[width * height]; quad.GetSurfaceMask(width, height, mask); MeshRenderer meshRenderer = gameobject.GetComponent <MeshRenderer>(); if (meshRenderer == null || meshRenderer.sharedMaterial == null || meshRenderer.sharedMaterial.HasProperty("_MainTex") == false) { Debug.LogWarning("SceneUnderstandingManager.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) { byte value = mask[i]; if (value == (byte)SceneRegionSurfaceKind.NotSurface) { pixels[i] = Color.clear; } else { pixels[i] = color; } } texture.SetPixels(pixels); texture.Apply(true); // Set the texture on the material. meshRenderer.sharedMaterial.mainTexture = texture; }
private GameObject CreateOrUpdateQuad(Transform sceneObjectTransform, SceneQuad quad) { GameObject quadObj; if (sceneGeometries.ContainsKey(quad.Id)) { quadObj = sceneGeometries[quad.Id]; } else { quadObj = GameObject.CreatePrimitive(PrimitiveType.Quad); quadObj.transform.SetParent(sceneObjectTransform, false); quadObj.name = $"Quad-{quad.Id}"; sceneGeometries.Add(quad.Id, quadObj); } quadObj.transform.localScale = new Vector3(quad.Extents.X, quad.Extents.Y, 1); return(quadObj); }
/// <summary> /// Create a Unity Mesh from a Scene Understanding Quad /// </summary> /// <param name="suQuad">The Scene Understanding quad to generate in Unity</param> private Mesh GenerateUnityMeshFromSceneObjectQuad(SceneQuad suQuad) { if (suQuad == null) { Debug.LogWarning("SceneUnderstandingManager.GenerateUnityMeshForSceneObjectQuad: Quad is null."); return(null); } float widthInMeters = suQuad.Extents.X; float heightInMeters = suQuad.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); }
public bool TryGetOcclusionMask(Guid quadId, ushort textureWidth, ushort textureHeight, out byte[] mask) { Tuple <SceneQuad, SceneObject> result; if (!cachedSceneQuads.TryGetValue(quadId, out result)) { mask = null; return(false); } SceneQuad quad = result.Item1; SceneObject sceneObject = result.Item2; var maskResult = new byte[textureWidth * textureHeight]; quad.GetSurfaceMask(textureWidth, textureHeight, maskResult); mask = maskResult; return(true); }
private SpatialAwarenessSceneObject ConvertSceneObject(SceneObject sceneObject) { int quadCount = sceneObject.Quads.Count; int meshCount = sceneObject.Meshes.Count; List <SpatialAwarenessSceneObject.Quad> quads = new List <SpatialAwarenessSceneObject.Quad>(quadCount); List <SpatialAwarenessSceneObject.MeshData> meshes = new List <SpatialAwarenessSceneObject.MeshData>(meshCount); if (RequestPlaneData) { SceneQuad sceneQuad = null; for (int i = 0; i < quadCount; ++i) { sceneQuad = sceneObject.Quads[i]; var quadIdKey = sceneQuad.Id; byte[] occlusionMaskBytes = null; if (RequestOcclusionMask) { occlusionMaskBytes = new byte[OcclusionMaskResolution.x * OcclusionMaskResolution.y]; sceneQuad.GetSurfaceMask((ushort)OcclusionMaskResolution.x, (ushort)OcclusionMaskResolution.y, occlusionMaskBytes); } var extents = new UnityEngine.Vector2(sceneQuad.Extents.X, sceneQuad.Extents.Y); var quad = new SpatialAwarenessSceneObject.Quad(quadIdKey, extents, occlusionMaskBytes); quads.Add(quad); // Store a cache so we can retrieve best position on plane later. if (!cachedSceneQuads.ContainsKey(quadIdKey)) { cachedSceneQuads.Add(quadIdKey, new Tuple <SceneQuad, SceneObject>(sceneQuad, sceneObject)); } } } if (RequestMeshData) { SceneMesh sceneMesh = null; for (int i = 0; i < meshCount; ++i) { sceneMesh = sceneObject.Meshes[i]; var meshData = MeshData(sceneMesh); meshes.Add(meshData); } } // World space conversion System.Numerics.Matrix4x4 worldXformSystem = sceneObject.GetLocationAsMatrix() * sceneToWorldXformSystem * correctOrientation; System.Numerics.Vector3 worldTranslationSystem; System.Numerics.Quaternion worldRotationSytem; System.Numerics.Vector3 localScale; System.Numerics.Matrix4x4.Decompose(worldXformSystem, out localScale, out worldRotationSytem, out worldTranslationSystem); var result = new SpatialAwarenessSceneObject( sceneObject.Id, SpatialAwarenessSurfaceType(sceneObject.Kind), worldTranslationSystem.ToUnityVector3(), worldRotationSytem.ToUnityQuaternion(), quads, meshes); return(result); }