//Creates VoxelGrids and saves them in the HashMap. //Always creates a grid with size (block_generator_radius*2+1)^3 public void GenerateDenseVoxelGrids(Vector3Int gridcoords) { for (int z = gridcoords.z - generation_radius; z <= gridcoords.z + generation_radius; z++) { for (int y = gridcoords.y - generation_radius; y <= gridcoords.y + generation_radius; y++) { for (int x = gridcoords.x - generation_radius; x <= gridcoords.x + generation_radius; x++) { Vector3Int position = new Vector3Int(x, y, z); if (!voxelblock_hash_table.ContainsKey(ToKey(position))) { GameObject g = Instantiate(dense_voxel_grid); g.transform.parent = this.transform; g.transform.localScale = new Vector3(1, 1, 1); g.transform.localRotation = Quaternion.identity; g.transform.localPosition = new Vector3(x, y, z); g.name = "Dense_" + x + "_" + y + "_" + z; DenseVoxelGrid dvg = g.GetComponent <DenseVoxelGrid>(); dvg.Render(); voxelblock_hash_table.Add(ToKey(position), g); } } } } }
//Function to update each voxel within a voxel grid public void UpdateDenseVoxelGrid(DenseVoxelGrid dvg, int current_update_frame) { //Only update if voxelgrid was not updated this frame if (current_update_frame == dvg.last_update_frame) { return; } //Do for every voxel in the Grid: for (int z = 0; z < dvg.grid_size.z; z++) { for (int y = 0; y < dvg.grid_size.y; y++) { for (int x = 0; x < dvg.grid_size.x; x++) { //Convert voxelgrid coordinates to world coordinates Vector3 worldcoord = dvg.DenseGridCoordToWorldCoord(x, y, z); //Retrieve corresponding pixel coordinates Vector2Int pixelcoord = GetPixelFromCoords(worldcoord); //Check if pixel is within camera image if (pixelcoord.x >= 0 && pixelcoord.y >= 0 && pixelcoord.x < interface_.differenceImage.width && pixelcoord.y < interface_.differenceImage.height) { //Retrieve VoxelType from pixelcoords VoxelType vt = GetVoxelType(pixelcoord); //Only update value if it is green/red in the image if (vt != VoxelType.EMPTY) { //Calculate the exact distance btw the camera and the voxel float dist_exact = GetDistanceToCameraScreen(worldcoord); //Calculate the measured distance btw the camera and the voxel float dist_measured = GetMeasuredDistance(vt, pixelcoord); bool out_of_range = false; //Calculate the TSDF value of this voxel float tsdf = GetTSDFValue(dist_exact, dist_measured, out out_of_range); //If the voxel is out of range (last part of the tsdf), truncate, else update the voxel if (!out_of_range) { dvg.active_count += UpdateVoxel(ref dvg.grid[x, y, z], tsdf, vt); } } } } } } //Render the updated block dvg.Render(); //Set current update frame in voxelgrid dvg.last_update_frame = current_update_frame; }
//Main Method to Update Voxel Value. //Input: //value - calculated from the TSD Function. //x, y, z - grid coordinates of Voxel to update //current_update_frame - this ensures that voxels only get updated once //Main Method Called From Reconstruction Button or via online update public void ReconstructScene() { Debug.Log("Reconstruction"); //Used to measure reconstruction time var watch = System.Diagnostics.Stopwatch.StartNew(); //Step 1: Choose Pixels at Random and Project Point to 3D View int width = interface_.differenceImage.width; int height = interface_.differenceImage.height; int ind = 0; for (int i = 0; i < number_of_samples; i++) { VoxelType vt = VoxelType.EMPTY; //1.1 Draw a Random Pixel from difference Image Vector2Int pixel = new Vector2Int(); int overflow = 0; //1.2 Check if pixel is not empty and repeat if necessary while (vt == VoxelType.EMPTY && overflow < 1000) { pixel.x = (int)(Random.value * width); pixel.y = (int)(Random.value * height); vt = GetVoxelType(pixel); overflow++; } //1.3 Calculate coordinates of voxel from pixel depth value Vector3 voxelcoords = GetCoordsFromPixel(vt, pixel); //1.4 Recieve DenseVoxelGrid at this position or create a new one if necessary DenseVoxelGrid dvg = SVG.GetDenseVoxelGrid(voxelcoords); //1.5 Update DenseVoxelGrid at this position by backprojecting all voxels UpdateDenseVoxelGrid(dvg, update_frame); ind++; } Debug.Log(ind + " Pixels found a surface"); //Step 3: Look for empty voxel blocks and remove them SVG.RemoveEmptyVoxelGrids(); update_frame++; //Display elapsed time watch.Stop(); var elapsedMs = watch.ElapsedMilliseconds; Debug.Log("Reconstruction took " + elapsedMs + "Milliseconds"); }
//Does not have to be called every time, can also run in background //Removes all voxel Grids that do not contain any active voxels public void RemoveEmptyVoxelGrids() { List <string> toRemove = new List <string>(); foreach (DictionaryEntry de in voxelblock_hash_table) { GameObject g = de.Value as GameObject; DenseVoxelGrid dvg = g.GetComponent <DenseVoxelGrid>(); if (dvg.active_count == 0) { toRemove.Add(de.Key as string); Destroy(g); } } foreach (string s in toRemove) { voxelblock_hash_table.Remove(s); } }