static void smooth(DenseGrid3f grid, DenseGrid3f tmp, float alpha, int iters, int min_j = 1) { if (tmp == null) { tmp = new DenseGrid3f(grid); } int ni = grid.ni, nj = grid.nj, nk = grid.nk; for (int iter = 0; iter < iters; ++iter) { for (int j = min_j; j < nj - 1; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { float avg = 0; foreach (Vector3i o in gIndices.GridOffsets26) { int xi = i + o.x, yi = j + o.y, zi = k + o.z; float f = grid[xi, yi, zi]; avg += f; } avg /= 26.0f; tmp[i, j, k] = (1 - alpha) * grid[i, j, k] + (alpha) * avg; } } } grid.swap(tmp); } }
void process_version1(DenseGrid3f supportGrid, DenseGridTrilinearImplicit distanceField) { int ni = supportGrid.ni, nj = supportGrid.nj, nk = supportGrid.nk; float dx = (float)CellSize; Vector3f origin = this.GridOrigin; // sweep values down, column by column for (int k = 0; k < nk; ++k) { for (int i = 0; i < ni; ++i) { bool in_support = false; for (int j = nj - 1; j >= 0; j--) { float fcur = supportGrid[i, j, k]; if (fcur >= 0) { Vector3d cell_center = new Vector3f(i * dx, j * dx, k * dx) + origin; if (in_support) { bool is_inside = distanceField.Value(ref cell_center) < 0; if (is_inside) { supportGrid[i, j, k] = -3; in_support = false; } else { supportGrid[i, j, k] = -1; } } } else { in_support = true; } } } } // skeletonize each layer // todo: would be nice to skeletonize the 3D volume.. ? DenseGrid3i binary = new DenseGrid3i(ni, nj, nk, 0); foreach (Vector3i idx in binary.Indices()) { binary[idx] = (supportGrid[idx] < 0) ? 1 : 0; } for (int j = 0; j < nj; ++j) { skeletonize_layer(binary, j); } // debug thing //VoxelSurfaceGenerator voxgen = new VoxelSurfaceGenerator() { // Voxels = binary.get_bitmap() //}; //voxgen.Generate(); //Util.WriteDebugMesh(voxgen.makemesh(), "c:\\scratch\\binary.obj"); // for skeleton voxels, we add some power for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { if (binary[i, j, k] > 0) { supportGrid[i, j, k] = -3; } //else // supportGrid[i, j, k] = 1; // clear non-skeleton voxels } } } // power up the ground-plane voxels for (int k = 0; k < nk; ++k) { for (int i = 0; i < ni; ++i) { if (supportGrid[i, 0, k] < 0) { supportGrid[i, 0, k] = -5; } } } #if true DenseGrid3f smoothed = new DenseGrid3f(supportGrid); float nbr_weight = 0.5f; for (int iter = 0; iter < 15; ++iter) { // add some mass to skeleton voxels for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { if (binary[i, j, k] > 0) { supportGrid[i, j, k] = supportGrid[i, j, k] - nbr_weight / 25.0f; } } } } for (int j = 0; j < nj; ++j) { for (int k = 1; k < nk - 1; ++k) { for (int i = 1; i < ni - 1; ++i) { int neg = 0; float avg = 0, w = 0; for (int n = 0; n < 8; ++n) { int xi = i + gIndices.GridOffsets8[n].x; int zi = k + gIndices.GridOffsets8[n].y; float f = supportGrid[xi, j, zi]; if (f < 0) { neg++; } avg += nbr_weight * f; w += nbr_weight; } if (neg > -1) { avg += supportGrid[i, j, k]; w += 1.0f; smoothed[i, j, k] = avg / w; } else { smoothed[i, j, k] = supportGrid[i, j, k]; } } } } supportGrid.swap(smoothed); } #endif // hard-enforce that skeleton voxels stay inside //for (int j = 0; j < nj; ++j) { // for (int k = 1; k < nk - 1; ++k) { // for (int i = 1; i < ni - 1; ++i) { // if (binary[i, j, k] > 0) // supportGrid[i, j, k] = Math.Min(supportGrid[i, j, k], - 1); // } // } //} }