Added OCTREE_NODE mode to disable adaptivity, effectively providing classic marching cubes

This commit is contained in:
Marc Gilleron 2019-04-23 23:37:26 +01:00
parent 19329efaa6
commit 9c3eb0e4b7
3 changed files with 153 additions and 85 deletions

View File

@ -54,6 +54,11 @@ inline HermiteValue get_interpolated_hermite_value(const VoxelBuffer &voxels, Ve
int z1 = static_cast<int>(Math::ceil(pos.z));
// TODO There are lots of hidden grid accesses here, could be optimized
//
// x x x: accessed once, only because of gradient computation
// x X X x X: accessed for both value and gradient, multiple times for gradient
// x X X x
// x x (and this, in 3D)
HermiteValue v0 = get_hermite_value(voxels, x0, y0, z0);
HermiteValue v1 = get_hermite_value(voxels, x1, y0, z0);

View File

@ -16,7 +16,7 @@ const float SURFACE_ISO_LEVEL = 0.0;
const float NEAR_SURFACE_FACTOR = 2.0;
const float SQRT3 = 1.7320508075688772;
// Helper to modify padded voxel data
// Helper to access padded voxel data
struct VoxelAccess {
const VoxelBuffer &buffer;
@ -1150,23 +1150,11 @@ inline Vector3 interpolate(const Vector3 &v0, const Vector3 &v1, const HermiteVa
return v0 + mu * (v1 - v0);
}
void polygonize_dual_grid(const DualGrid &grid, const VoxelAccess &voxels, MeshBuilder &mesh_builder) {
void polygonize_cell_marching_cubes(const Vector3 *corners, const HermiteValue *values, MeshBuilder &mesh_builder) {
for (int dci = 0; dci < grid.cells.size(); ++dci) {
const DualCell &cell = grid.cells[dci];
const Vector3 *corners = cell.corners;
// Polygonize using regular marching cubes
unsigned char case_index = 0;
HermiteValue values[8];
for (int i = 0; i < 8; ++i) {
if (cell.has_values) {
values[i] = cell.values[i];
} else {
values[i] = voxels.get_interpolated_hermite_value(corners[i]);
}
if (values[i].value >= SURFACE_ISO_LEVEL) {
case_index |= 1 << i;
}
@ -1176,7 +1164,7 @@ void polygonize_dual_grid(const DualGrid &grid, const VoxelAccess &voxels, MeshB
if (!edge) {
// Nothing intersects
continue;
return;
}
// Find the intersection vertices
@ -1234,6 +1222,70 @@ void polygonize_dual_grid(const DualGrid &grid, const VoxelAccess &voxels, MeshB
intersection_points[MarchingCubes::mc_triangles[case_index][i + 2]],
intersection_normals[MarchingCubes::mc_triangles[case_index][i + 2]]);
}
return;
}
void polygonize_dual_cell(const DualCell &cell, const VoxelAccess &voxels, MeshBuilder &mesh_builder) {
const Vector3 *corners = cell.corners;
HermiteValue values[8];
if (cell.has_values) {
memcpy(values, cell.values, 8 * sizeof(HermiteValue));
} else {
for (int i = 0; i < 8; ++i) {
values[i] = voxels.get_interpolated_hermite_value(corners[i]);
}
}
polygonize_cell_marching_cubes(corners, values, mesh_builder);
}
inline void polygonize_dual_grid(const DualGrid &grid, const VoxelAccess &voxels, MeshBuilder &mesh_builder) {
for (int i = 0; i < grid.cells.size(); ++i) {
polygonize_dual_cell(grid.cells[i], voxels, mesh_builder);
}
}
void polygonize_volume_directly(const VoxelBuffer &voxels, Vector3i min, Vector3i size, MeshBuilder &mesh_builder) {
Vector3 corners[8];
HermiteValue values[8];
const Vector3i max = min + size;
const Vector3 minf = min.to_vec3();
for (int z = min.z; z < max.z; ++z) {
for (int x = min.x; x < max.x; ++x) {
for (int y = min.y; y < max.y; ++y) {
values[0] = get_hermite_value(voxels, x, y, z);
values[1] = get_hermite_value(voxels, x + 1, y, z);
values[2] = get_hermite_value(voxels, x + 1, y, z + 1);
values[3] = get_hermite_value(voxels, x, y, z + 1);
values[4] = get_hermite_value(voxels, x, y + 1, z);
values[5] = get_hermite_value(voxels, x + 1, y + 1, z);
values[6] = get_hermite_value(voxels, x + 1, y + 1, z + 1);
values[7] = get_hermite_value(voxels, x, y + 1, z + 1);
corners[0] = Vector3(x, y, z);
corners[1] = Vector3(x + 1, y, z);
corners[2] = Vector3(x + 1, y, z + 1);
corners[3] = Vector3(x, y, z + 1);
corners[4] = Vector3(x, y + 1, z);
corners[5] = Vector3(x + 1, y + 1, z);
corners[6] = Vector3(x + 1, y + 1, z + 1);
corners[7] = Vector3(x, y + 1, z + 1);
for (int i = 0; i < 8; ++i) {
corners[i] -= minf;
}
polygonize_cell_marching_cubes(corners, values, mesh_builder);
}
}
}
}
@ -1313,13 +1365,13 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
// because all voxels are queried.
//
// TODO This option might disappear once I find a good enough solution
dmc::OctreeNode *root;
dmc::OctreeNode *root = nullptr;
if (_octree_mode == OCTREE_BOTTOM_UP) {
dmc::OctreeBuilderBottomUp octree_builder(voxels_access, _geometric_error, _octree_node_pool);
root = octree_builder.build(Vector3i(), chunk_size);
} else {
} else if (_octree_mode == OCTREE_TOP_DOWN) {
dmc::OctreeBuilderTopDown octree_builder(voxels_access, _geometric_error, _octree_node_pool);
root = octree_builder.build(Vector3i(), chunk_size);
@ -1352,18 +1404,27 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
time_before = OS::get_singleton()->get_ticks_usec();
dmc::polygonize_dual_grid(_dual_grid, voxels_access, _mesh_builder);
_stats.meshing_time = OS::get_singleton()->get_ticks_usec() - time_before;
time_before = OS::get_singleton()->get_ticks_usec();
mesh = _mesh_builder.commit(_mesh_mode == MESH_WIREFRAME);
_stats.commit_time = OS::get_singleton()->get_ticks_usec() - time_before;
}
_dual_grid.cells.clear();
}
root->recycle(_octree_node_pool);
} else if (_octree_mode == OCTREE_NONE) {
// We throw away adaptivity for meshing speed.
// This is essentially regular marching cubes.
time_before = OS::get_singleton()->get_ticks_usec();
dmc::polygonize_volume_directly(voxels, Vector3i(padding), Vector3i(chunk_size), _mesh_builder);
_stats.meshing_time = OS::get_singleton()->get_ticks_usec() - time_before;
}
time_before = OS::get_singleton()->get_ticks_usec();
mesh = _mesh_builder.commit(_mesh_mode == MESH_WIREFRAME);
_stats.commit_time = OS::get_singleton()->get_ticks_usec() - time_before;
// TODO Marching squares skirts
return mesh;
@ -1404,4 +1465,5 @@ void VoxelMesherDMC::_bind_methods() {
BIND_ENUM_CONSTANT(OCTREE_BOTTOM_UP);
BIND_ENUM_CONSTANT(OCTREE_TOP_DOWN);
BIND_ENUM_CONSTANT(OCTREE_NONE);
}

View File

@ -76,7 +76,8 @@ public:
enum OctreeMode {
OCTREE_BOTTOM_UP,
OCTREE_TOP_DOWN
OCTREE_TOP_DOWN,
OCTREE_NONE
};
VoxelMesherDMC();