/// <summary> /// Save the tango dynamic mesh. /// /// Process the mesh in 3 steps. /// 1. Extract the whole mesh from tango 3D Reconstruction. /// 2. Convert to a serializable format. /// 3. Serialize with XML on to the SD card. /// </summary> /// <returns>The coroutine IEnumerator.</returns> private IEnumerator _DoSaveTangoDynamicMesh() { m_savingText.gameObject.SetActive(true); m_savingText.text = "Extracting Whole Mesh..."; // Each list is filled out with values from extracting the whole mesh. List <Vector3> vertices = new List <Vector3>(); List <int> triangles = new List <int>(); Tango3DReconstruction.Status status = m_tangoApplication.Tango3DRExtractWholeMesh(vertices, null, null, triangles); if (status != Tango3DReconstruction.Status.SUCCESS) { Debug.Log("Tango3DRExtractWholeMesh failed, status code = " + status); yield break; } Debug.Log("Tango3DRExtractWholeMesh finished"); Mesh extractedMesh = new Mesh(); extractedMesh.vertices = vertices.ToArray(); extractedMesh.triangles = triangles.ToArray(); // Save the generated unity mesh. m_savingText.text = "Saving Area Description Mesh..."; AreaDescriptionMesh mesh = _UnityMeshToAreaDescriptionMesh(m_savedUUID, extractedMesh); _SerializeAreaDescriptionMesh(mesh); // Restart scene after completion. #pragma warning disable 618 Application.LoadLevel(Application.loadedLevel); #pragma warning restore 618 }
/// <summary> /// Save the tango dynamic mesh. /// /// Process the mesh in 3 steps. /// 1. Extract the whole mesh from tango 3D Reconstruction. /// 2. Convert to a serializable format. /// 3. Serialize with XML on to the SD card. /// </summary> /// <returns>The coroutine IEnumerator.</returns> private IEnumerator _DoSaveTangoDynamicMesh() { m_savingText.gameObject.SetActive(true); m_savingText.text = "Extracting Whole Mesh..."; Tango3DReconstruction.Status status = Tango3DReconstruction.Status.INVALID; bool needsToGrow = false; float growthFactor = 1.5f; // Each list is filled out with values from extracting the whole mesh. Vector3[] vertices = new Vector3[100]; int[] triangles = new int[99]; while (status != Tango3DReconstruction.Status.SUCCESS) { yield return(null); // Last frame the mesh needed more space. Give it more room now. if (needsToGrow) { int newVertexSize = (int)(vertices.Length * growthFactor); int newTriangleSize = (int)(triangles.Length * growthFactor); newTriangleSize -= newTriangleSize % 3; vertices = new Vector3[newVertexSize]; triangles = new int[newTriangleSize]; needsToGrow = false; } int numVertices; int numTriangles; status = m_tangoApplication.Tango3DRExtractWholeMesh(vertices, null, null, triangles, out numVertices, out numTriangles); if (status != Tango3DReconstruction.Status.INSUFFICIENT_SPACE && status != Tango3DReconstruction.Status.SUCCESS) { Debug.Log("Tango3DRExtractWholeMesh failed, status code = " + status); break; } else if (status == Tango3DReconstruction.Status.INSUFFICIENT_SPACE) { // After exceeding allocated space for vertices and triangles, continue extraction next frame. Debug.Log(string.Format("Tango3DRExtractWholeMesh ran out of space with room for {0} vertexes, {1} indexes.", vertices.Length, triangles.Length)); needsToGrow = true; } // Make any leftover triangles degenerate. for (int triangleIt = numTriangles * 3; triangleIt < triangles.Length; ++triangleIt) { triangles[triangleIt] = 0; } } Debug.Log("Tango3DRExtractWholeMesh finished"); Mesh extractedMesh = new Mesh(); extractedMesh.vertices = vertices; extractedMesh.triangles = triangles; // Save the generated unity mesh. m_savingText.text = "Saving Area Description Mesh..."; AreaDescriptionMesh mesh = _UnityMeshToAreaDescriptionMesh(m_savedUUID, extractedMesh); _SerializeAreaDescriptionMesh(mesh); // Restart scene after completion. #pragma warning disable 618 Application.LoadLevel(Application.loadedLevel); #pragma warning restore 618 }
/// <summary> /// Unity Update callback. /// </summary> public void Update() { List <Tango3DReconstruction.GridIndex> needsResize = new List <Tango3DReconstruction.GridIndex>(); int it; int startTimeMS = (int)(Time.realtimeSinceStartup * 1000); for (it = 0; it < m_gridIndexToUpdate.Count; ++it) { Tango3DReconstruction.GridIndex gridIndex = m_gridIndexToUpdate[it]; if ((Time.realtimeSinceStartup * 1000) - startTimeMS > TIME_BUDGET_MS) { Debug.Log(string.Format( "TangoDynamicMesh.Update() ran over budget with {0}/{1} grid indexes processed.", it, m_gridIndexToUpdate.Count)); break; } TangoSingleDynamicMesh dynamicMesh; if (!m_meshes.TryGetValue(gridIndex, out dynamicMesh)) { // build a dynamic mesh as a child of this game object. GameObject newObj = new GameObject(); newObj.transform.parent = transform; newObj.name = string.Format("{0},{1},{2}", gridIndex.x, gridIndex.y, gridIndex.z); dynamicMesh = newObj.AddComponent <TangoSingleDynamicMesh>(); dynamicMesh.m_vertices = new Vector3[INITIAL_VERTEX_COUNT]; if (m_tangoApplication.m_3drGenerateTexCoord) { dynamicMesh.m_uv = new Vector2[INITIAL_VERTEX_COUNT]; } if (m_tangoApplication.m_3drGenerateColor) { dynamicMesh.m_colors = new Color32[INITIAL_VERTEX_COUNT]; } dynamicMesh.m_triangles = new int[INITIAL_INDEX_COUNT]; // Update debug info too. m_debugTotalVertices = dynamicMesh.m_vertices.Length; m_debugTotalTriangles = dynamicMesh.m_triangles.Length; // Add the other necessary objects MeshFilter meshFilter = newObj.AddComponent <MeshFilter>(); dynamicMesh.m_mesh = meshFilter.mesh; if (m_meshRenderer != null) { MeshRenderer meshRenderer = newObj.AddComponent <MeshRenderer>(); #if UNITY_5 meshRenderer.shadowCastingMode = m_meshRenderer.shadowCastingMode; meshRenderer.receiveShadows = m_meshRenderer.receiveShadows; meshRenderer.sharedMaterials = m_meshRenderer.sharedMaterials; meshRenderer.useLightProbes = m_meshRenderer.useLightProbes; meshRenderer.reflectionProbeUsage = m_meshRenderer.reflectionProbeUsage; meshRenderer.probeAnchor = m_meshRenderer.probeAnchor; #elif UNITY_4_6 meshRenderer.castShadows = m_meshRenderer.castShadows; meshRenderer.receiveShadows = m_meshRenderer.receiveShadows; meshRenderer.sharedMaterials = m_meshRenderer.sharedMaterials; meshRenderer.useLightProbes = m_meshRenderer.useLightProbes; meshRenderer.lightProbeAnchor = m_meshRenderer.lightProbeAnchor; #endif } if (m_meshCollider != null) { MeshCollider meshCollider = newObj.AddComponent <MeshCollider>(); meshCollider.convex = m_meshCollider.convex; meshCollider.isTrigger = m_meshCollider.isTrigger; meshCollider.sharedMaterial = m_meshCollider.sharedMaterial; meshCollider.sharedMesh = dynamicMesh.m_mesh; dynamicMesh.m_meshCollider = meshCollider; } m_meshes.Add(gridIndex, dynamicMesh); } // Last frame the mesh needed more space. Give it more room now. if (dynamicMesh.m_needsToGrow) { int newVertexSize = (int)(dynamicMesh.m_vertices.Length * GROWTH_FACTOR); int newTriangleSize = (int)(dynamicMesh.m_triangles.Length * GROWTH_FACTOR); newTriangleSize -= newTriangleSize % 3; // Remove the old size, add the new size. m_debugTotalVertices += newVertexSize - dynamicMesh.m_vertices.Length; m_debugTotalTriangles += newTriangleSize - dynamicMesh.m_triangles.Length; dynamicMesh.m_vertices = new Vector3[newVertexSize]; if (m_tangoApplication.m_3drGenerateTexCoord) { dynamicMesh.m_uv = new Vector2[newVertexSize]; } if (m_tangoApplication.m_3drGenerateColor) { dynamicMesh.m_colors = new Color32[newVertexSize]; } dynamicMesh.m_triangles = new int[newTriangleSize]; dynamicMesh.m_needsToGrow = false; } int numVertices; int numTriangles; Tango3DReconstruction.Status status = m_tangoApplication.Tango3DRExtractMeshSegment( gridIndex, dynamicMesh.m_vertices, null, dynamicMesh.m_colors, dynamicMesh.m_triangles, out numVertices, out numTriangles); if (status != Tango3DReconstruction.Status.INSUFFICIENT_SPACE && status != Tango3DReconstruction.Status.SUCCESS) { Debug.Log("Tango3DR extraction failed, status code = " + status + Environment.StackTrace); continue; } else if (status == Tango3DReconstruction.Status.INSUFFICIENT_SPACE) { // We already spent the time extracting this mesh, let's not spend any more time this frame // to extract the mesh. Debug.Log(string.Format( "TangoDynamicMesh.Update() extraction ran out of space with room for {0} vertexes, {1} indexes.", dynamicMesh.m_vertices.Length, dynamicMesh.m_triangles.Length)); dynamicMesh.m_needsToGrow = true; needsResize.Add(gridIndex); } // Make any leftover triangles degenerate. for (int triangleIt = numTriangles * 3; triangleIt < dynamicMesh.m_triangles.Length; ++triangleIt) { dynamicMesh.m_triangles[triangleIt] = 0; } if (dynamicMesh.m_uv != null) { // Add texture coordinates. for (int vertexIt = 0; vertexIt < numVertices; ++vertexIt) { Vector3 vertex = dynamicMesh.m_vertices[vertexIt]; dynamicMesh.m_uv[vertexIt].x = vertex.x * UV_PER_METERS; dynamicMesh.m_uv[vertexIt].y = (vertex.z + vertex.y) * UV_PER_METERS; } } dynamicMesh.m_mesh.Clear(); dynamicMesh.m_mesh.vertices = dynamicMesh.m_vertices; dynamicMesh.m_mesh.uv = dynamicMesh.m_uv; dynamicMesh.m_mesh.colors32 = dynamicMesh.m_colors; dynamicMesh.m_mesh.triangles = dynamicMesh.m_triangles; if (m_tangoApplication.m_3drGenerateNormal) { dynamicMesh.m_mesh.RecalculateNormals(); } if (dynamicMesh.m_meshCollider != null) { // Force the mesh collider to update too. dynamicMesh.m_meshCollider.sharedMesh = null; dynamicMesh.m_meshCollider.sharedMesh = dynamicMesh.m_mesh; } } m_debugRemeshingTime = Time.realtimeSinceStartup - (startTimeMS * 0.001f); m_debugRemeshingCount = it; // Any leftover grid indices also need to get processed next frame. while (it < m_gridIndexToUpdate.Count) { needsResize.Add(m_gridIndexToUpdate[it]); ++it; } m_gridIndexToUpdate = needsResize; }
/// <summary> /// Extract and update (or create, if it doesn't exist) the mesh at the given grid index. /// </summary> /// <param name="gridIndex">Grid index.</param> /// <param name="needsResize">List to which indices needing a future resize will be added.</param> private void _UpdateMeshAtGridIndex(Tango3DReconstruction.GridIndex gridIndex, List <Tango3DReconstruction.GridIndex> needsResize) { TangoSingleDynamicMesh dynamicMesh; if (!m_meshes.TryGetValue(gridIndex, out dynamicMesh)) { // build a dynamic mesh as a child of this game object. GameObject newObj = new GameObject(); newObj.transform.parent = transform; newObj.name = string.Format("{0},{1},{2}", gridIndex.x, gridIndex.y, gridIndex.z); newObj.layer = gameObject.layer; dynamicMesh = newObj.AddComponent <TangoSingleDynamicMesh>(); dynamicMesh.m_vertices = new Vector3[INITIAL_VERTEX_COUNT]; dynamicMesh.boxes = new GameObject[INITIAL_VERTEX_COUNT]; if (m_tangoApplication.m_3drGenerateTexCoord) { dynamicMesh.m_uv = new Vector2[INITIAL_VERTEX_COUNT]; } if (m_tangoApplication.m_3drGenerateColor) { dynamicMesh.m_colors = new Color32[INITIAL_VERTEX_COUNT]; } dynamicMesh.m_triangles = new int[INITIAL_INDEX_COUNT]; // Update debug info too. m_debugTotalVertices = dynamicMesh.m_vertices.Length; m_debugTotalTriangles = dynamicMesh.m_triangles.Length; // Add the other necessary objects MeshFilter meshFilter = newObj.AddComponent <MeshFilter>(); dynamicMesh.m_mesh = meshFilter.mesh; if (m_meshRenderer != null) { MeshRenderer meshRenderer = newObj.AddComponent <MeshRenderer>(); #if UNITY_5 meshRenderer.shadowCastingMode = m_meshRenderer.shadowCastingMode; meshRenderer.receiveShadows = m_meshRenderer.receiveShadows; meshRenderer.sharedMaterials = m_meshRenderer.sharedMaterials; meshRenderer.useLightProbes = m_meshRenderer.useLightProbes; meshRenderer.reflectionProbeUsage = m_meshRenderer.reflectionProbeUsage; meshRenderer.probeAnchor = m_meshRenderer.probeAnchor; #elif UNITY_4_6 meshRenderer.castShadows = m_meshRenderer.castShadows; meshRenderer.receiveShadows = m_meshRenderer.receiveShadows; meshRenderer.sharedMaterials = m_meshRenderer.sharedMaterials; meshRenderer.useLightProbes = m_meshRenderer.useLightProbes; meshRenderer.lightProbeAnchor = m_meshRenderer.lightProbeAnchor; #endif } if (m_meshCollider != null) { MeshCollider meshCollider = newObj.AddComponent <MeshCollider>(); meshCollider.convex = m_meshCollider.convex; meshCollider.isTrigger = m_meshCollider.isTrigger; meshCollider.sharedMaterial = m_meshCollider.sharedMaterial; meshCollider.sharedMesh = dynamicMesh.m_mesh; dynamicMesh.m_meshCollider = meshCollider; } m_meshes.Add(gridIndex, dynamicMesh); _UpdateBounds(gridIndex); } // Skip updating this grid index if it is considered completed. if (m_enableSelectiveMeshing) { if (dynamicMesh.m_completed) { return; } _ObserveGridIndex(gridIndex, dynamicMesh); } // Last frame the mesh needed more space. Give it more room now. if (dynamicMesh.m_needsToGrow) { int newVertexSize = (int)(dynamicMesh.m_vertices.Length * GROWTH_FACTOR); int newTriangleSize = (int)(dynamicMesh.m_triangles.Length * GROWTH_FACTOR); newTriangleSize -= newTriangleSize % 3; // Remove the old size, add the new size. m_debugTotalVertices += newVertexSize - dynamicMesh.m_vertices.Length; m_debugTotalTriangles += newTriangleSize - dynamicMesh.m_triangles.Length; dynamicMesh.m_vertices = new Vector3[newVertexSize]; dynamicMesh.boxes = new GameObject[newVertexSize]; if (m_tangoApplication.m_3drGenerateTexCoord) { dynamicMesh.m_uv = new Vector2[newVertexSize]; } if (m_tangoApplication.m_3drGenerateColor) { dynamicMesh.m_colors = new Color32[newVertexSize]; } dynamicMesh.m_triangles = new int[newTriangleSize]; dynamicMesh.m_needsToGrow = false; } int numVertices; int numTriangles; Tango3DReconstruction.Status status = m_tangoApplication.Tango3DRExtractMeshSegment( gridIndex, dynamicMesh.m_vertices, null, dynamicMesh.m_colors, dynamicMesh.m_triangles, out numVertices, out numTriangles); if (status != Tango3DReconstruction.Status.INSUFFICIENT_SPACE && status != Tango3DReconstruction.Status.SUCCESS) { Debug.Log("Tango3DR extraction failed, status code = " + status + Environment.StackTrace); return; } else if (status == Tango3DReconstruction.Status.INSUFFICIENT_SPACE) { // We already spent the time extracting this mesh, let's not spend any more time this frame // to extract the mesh. Debug.Log(string.Format( "TangoDynamicMesh.Update() extraction ran out of space with room for {0} vertexes, {1} indexes.", dynamicMesh.m_vertices.Length, dynamicMesh.m_triangles.Length)); dynamicMesh.m_needsToGrow = true; needsResize.Add(gridIndex); } // Make any leftover triangles degenerate. for (int triangleIt = numTriangles * 3; triangleIt < dynamicMesh.m_triangles.Length; ++triangleIt) { dynamicMesh.m_triangles[triangleIt] = 0; } if (dynamicMesh.m_uv != null) { // Add texture coordinates. for (int vertexIt = 0; vertexIt < numVertices; ++vertexIt) { Vector3 vertex = dynamicMesh.m_vertices[vertexIt]; dynamicMesh.m_uv[vertexIt].x = vertex.x * UV_PER_METERS; dynamicMesh.m_uv[vertexIt].y = (vertex.z + vertex.y) * UV_PER_METERS; } } for (int k = 0; k < dynamicMesh.m_vertices.Length; k++) { if (dynamicMesh.boxes [k] != null) { Destroy(dynamicMesh.boxes [k]); } dynamicMesh.boxes [k] = GameObject.CreatePrimitive(PrimitiveType.Cube); dynamicMesh.boxes [k].transform.position = dynamicMesh.m_vertices [k]; dynamicMesh.boxes [k].transform.localScale = new Vector3(0.02f, 0.02f, 0.02f); Color ObjectColor = Color.green; Material materialColored = new Material(Shader.Find("Diffuse")); materialColored.color = ObjectColor; dynamicMesh.boxes [k].GetComponent <Renderer> ().material = materialColored; } dynamicMesh.m_mesh.Clear(); dynamicMesh.m_mesh.vertices = dynamicMesh.m_vertices; dynamicMesh.m_mesh.uv = dynamicMesh.m_uv; dynamicMesh.m_mesh.colors32 = dynamicMesh.m_colors; dynamicMesh.m_mesh.triangles = dynamicMesh.m_triangles; if (m_tangoApplication.m_3drGenerateNormal) { dynamicMesh.m_mesh.RecalculateNormals(); } if (dynamicMesh.m_meshCollider != null) { // Force the mesh collider to update too. dynamicMesh.m_meshCollider.sharedMesh = null; dynamicMesh.m_meshCollider.sharedMesh = dynamicMesh.m_mesh; } }