mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-19 02:47:18 +01:00
Added OCTREE_NODE mode to disable adaptivity, effectively providing classic marching cubes
This commit is contained in:
parent
19329efaa6
commit
9c3eb0e4b7
@ -54,6 +54,11 @@ inline HermiteValue get_interpolated_hermite_value(const VoxelBuffer &voxels, Ve
|
|||||||
int z1 = static_cast<int>(Math::ceil(pos.z));
|
int z1 = static_cast<int>(Math::ceil(pos.z));
|
||||||
|
|
||||||
// TODO There are lots of hidden grid accesses here, could be optimized
|
// 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 v0 = get_hermite_value(voxels, x0, y0, z0);
|
||||||
HermiteValue v1 = get_hermite_value(voxels, x1, y0, z0);
|
HermiteValue v1 = get_hermite_value(voxels, x1, y0, z0);
|
||||||
|
@ -16,7 +16,7 @@ const float SURFACE_ISO_LEVEL = 0.0;
|
|||||||
const float NEAR_SURFACE_FACTOR = 2.0;
|
const float NEAR_SURFACE_FACTOR = 2.0;
|
||||||
const float SQRT3 = 1.7320508075688772;
|
const float SQRT3 = 1.7320508075688772;
|
||||||
|
|
||||||
// Helper to modify padded voxel data
|
// Helper to access padded voxel data
|
||||||
struct VoxelAccess {
|
struct VoxelAccess {
|
||||||
|
|
||||||
const VoxelBuffer &buffer;
|
const VoxelBuffer &buffer;
|
||||||
@ -1150,89 +1150,141 @@ inline Vector3 interpolate(const Vector3 &v0, const Vector3 &v1, const HermiteVa
|
|||||||
return v0 + mu * (v1 - v0);
|
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) {
|
unsigned char case_index = 0;
|
||||||
|
|
||||||
const DualCell &cell = grid.cells[dci];
|
for (int i = 0; i < 8; ++i) {
|
||||||
const Vector3 *corners = cell.corners;
|
if (values[i].value >= SURFACE_ISO_LEVEL) {
|
||||||
|
case_index |= 1 << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Polygonize using regular marching cubes
|
int edge = MarchingCubes::mc_edges[case_index];
|
||||||
unsigned char case_index = 0;
|
|
||||||
HermiteValue values[8];
|
|
||||||
|
|
||||||
|
if (!edge) {
|
||||||
|
// Nothing intersects
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the intersection vertices
|
||||||
|
Vector3 intersection_points[12];
|
||||||
|
Vector3 intersection_normals[12];
|
||||||
|
if (edge & 1) {
|
||||||
|
intersection_points[0] = interpolate(corners[0], corners[1], values[0], values[1], intersection_normals[0]);
|
||||||
|
}
|
||||||
|
if (edge & 2) {
|
||||||
|
intersection_points[1] = interpolate(corners[1], corners[2], values[1], values[2], intersection_normals[1]);
|
||||||
|
}
|
||||||
|
if (edge & 4) {
|
||||||
|
intersection_points[2] = interpolate(corners[2], corners[3], values[2], values[3], intersection_normals[2]);
|
||||||
|
}
|
||||||
|
if (edge & 8) {
|
||||||
|
intersection_points[3] = interpolate(corners[3], corners[0], values[3], values[0], intersection_normals[3]);
|
||||||
|
}
|
||||||
|
if (edge & 16) {
|
||||||
|
intersection_points[4] = interpolate(corners[4], corners[5], values[4], values[5], intersection_normals[4]);
|
||||||
|
}
|
||||||
|
if (edge & 32) {
|
||||||
|
intersection_points[5] = interpolate(corners[5], corners[6], values[5], values[6], intersection_normals[5]);
|
||||||
|
}
|
||||||
|
if (edge & 64) {
|
||||||
|
intersection_points[6] = interpolate(corners[6], corners[7], values[6], values[7], intersection_normals[6]);
|
||||||
|
}
|
||||||
|
if (edge & 128) {
|
||||||
|
intersection_points[7] = interpolate(corners[7], corners[4], values[7], values[4], intersection_normals[7]);
|
||||||
|
}
|
||||||
|
if (edge & 256) {
|
||||||
|
intersection_points[8] = interpolate(corners[0], corners[4], values[0], values[4], intersection_normals[8]);
|
||||||
|
}
|
||||||
|
if (edge & 512) {
|
||||||
|
intersection_points[9] = interpolate(corners[1], corners[5], values[1], values[5], intersection_normals[9]);
|
||||||
|
}
|
||||||
|
if (edge & 1024) {
|
||||||
|
intersection_points[10] = interpolate(corners[2], corners[6], values[2], values[6], intersection_normals[10]);
|
||||||
|
}
|
||||||
|
if (edge & 2048) {
|
||||||
|
intersection_points[11] = interpolate(corners[3], corners[7], values[3], values[7], intersection_normals[11]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the triangles according to the table.
|
||||||
|
for (int i = 0; MarchingCubes::mc_triangles[case_index][i] != -1; i += 3) {
|
||||||
|
|
||||||
|
mesh_builder.add_vertex(
|
||||||
|
intersection_points[MarchingCubes::mc_triangles[case_index][i]],
|
||||||
|
intersection_normals[MarchingCubes::mc_triangles[case_index][i]]);
|
||||||
|
|
||||||
|
mesh_builder.add_vertex(
|
||||||
|
intersection_points[MarchingCubes::mc_triangles[case_index][i + 1]],
|
||||||
|
intersection_normals[MarchingCubes::mc_triangles[case_index][i + 1]]);
|
||||||
|
|
||||||
|
mesh_builder.add_vertex(
|
||||||
|
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) {
|
for (int i = 0; i < 8; ++i) {
|
||||||
if (cell.has_values) {
|
values[i] = voxels.get_interpolated_hermite_value(corners[i]);
|
||||||
values[i] = cell.values[i];
|
}
|
||||||
} else {
|
}
|
||||||
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);
|
||||||
}
|
}
|
||||||
if (values[i].value >= SURFACE_ISO_LEVEL) {
|
|
||||||
case_index |= 1 << i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int edge = MarchingCubes::mc_edges[case_index];
|
|
||||||
|
|
||||||
if (!edge) {
|
|
||||||
// Nothing intersects
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Find the intersection vertices
|
|
||||||
Vector3 intersection_points[12];
|
|
||||||
Vector3 intersection_normals[12];
|
|
||||||
if (edge & 1) {
|
|
||||||
intersection_points[0] = interpolate(corners[0], corners[1], values[0], values[1], intersection_normals[0]);
|
|
||||||
}
|
|
||||||
if (edge & 2) {
|
|
||||||
intersection_points[1] = interpolate(corners[1], corners[2], values[1], values[2], intersection_normals[1]);
|
|
||||||
}
|
|
||||||
if (edge & 4) {
|
|
||||||
intersection_points[2] = interpolate(corners[2], corners[3], values[2], values[3], intersection_normals[2]);
|
|
||||||
}
|
|
||||||
if (edge & 8) {
|
|
||||||
intersection_points[3] = interpolate(corners[3], corners[0], values[3], values[0], intersection_normals[3]);
|
|
||||||
}
|
|
||||||
if (edge & 16) {
|
|
||||||
intersection_points[4] = interpolate(corners[4], corners[5], values[4], values[5], intersection_normals[4]);
|
|
||||||
}
|
|
||||||
if (edge & 32) {
|
|
||||||
intersection_points[5] = interpolate(corners[5], corners[6], values[5], values[6], intersection_normals[5]);
|
|
||||||
}
|
|
||||||
if (edge & 64) {
|
|
||||||
intersection_points[6] = interpolate(corners[6], corners[7], values[6], values[7], intersection_normals[6]);
|
|
||||||
}
|
|
||||||
if (edge & 128) {
|
|
||||||
intersection_points[7] = interpolate(corners[7], corners[4], values[7], values[4], intersection_normals[7]);
|
|
||||||
}
|
|
||||||
if (edge & 256) {
|
|
||||||
intersection_points[8] = interpolate(corners[0], corners[4], values[0], values[4], intersection_normals[8]);
|
|
||||||
}
|
|
||||||
if (edge & 512) {
|
|
||||||
intersection_points[9] = interpolate(corners[1], corners[5], values[1], values[5], intersection_normals[9]);
|
|
||||||
}
|
|
||||||
if (edge & 1024) {
|
|
||||||
intersection_points[10] = interpolate(corners[2], corners[6], values[2], values[6], intersection_normals[10]);
|
|
||||||
}
|
|
||||||
if (edge & 2048) {
|
|
||||||
intersection_points[11] = interpolate(corners[3], corners[7], values[3], values[7], intersection_normals[11]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the triangles according to the table.
|
|
||||||
for (int i = 0; MarchingCubes::mc_triangles[case_index][i] != -1; i += 3) {
|
|
||||||
|
|
||||||
mesh_builder.add_vertex(
|
|
||||||
intersection_points[MarchingCubes::mc_triangles[case_index][i]],
|
|
||||||
intersection_normals[MarchingCubes::mc_triangles[case_index][i]]);
|
|
||||||
|
|
||||||
mesh_builder.add_vertex(
|
|
||||||
intersection_points[MarchingCubes::mc_triangles[case_index][i + 1]],
|
|
||||||
intersection_normals[MarchingCubes::mc_triangles[case_index][i + 1]]);
|
|
||||||
|
|
||||||
mesh_builder.add_vertex(
|
|
||||||
intersection_points[MarchingCubes::mc_triangles[case_index][i + 2]],
|
|
||||||
intersection_normals[MarchingCubes::mc_triangles[case_index][i + 2]]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1313,13 +1365,13 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
|
|||||||
// because all voxels are queried.
|
// because all voxels are queried.
|
||||||
//
|
//
|
||||||
// TODO This option might disappear once I find a good enough solution
|
// 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) {
|
if (_octree_mode == OCTREE_BOTTOM_UP) {
|
||||||
|
|
||||||
dmc::OctreeBuilderBottomUp octree_builder(voxels_access, _geometric_error, _octree_node_pool);
|
dmc::OctreeBuilderBottomUp octree_builder(voxels_access, _geometric_error, _octree_node_pool);
|
||||||
root = octree_builder.build(Vector3i(), chunk_size);
|
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);
|
dmc::OctreeBuilderTopDown octree_builder(voxels_access, _geometric_error, _octree_node_pool);
|
||||||
root = octree_builder.build(Vector3i(), chunk_size);
|
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();
|
time_before = OS::get_singleton()->get_ticks_usec();
|
||||||
dmc::polygonize_dual_grid(_dual_grid, voxels_access, _mesh_builder);
|
dmc::polygonize_dual_grid(_dual_grid, voxels_access, _mesh_builder);
|
||||||
_stats.meshing_time = OS::get_singleton()->get_ticks_usec() - time_before;
|
_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();
|
_dual_grid.cells.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
root->recycle(_octree_node_pool);
|
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
|
// TODO Marching squares skirts
|
||||||
|
|
||||||
return mesh;
|
return mesh;
|
||||||
@ -1404,4 +1465,5 @@ void VoxelMesherDMC::_bind_methods() {
|
|||||||
|
|
||||||
BIND_ENUM_CONSTANT(OCTREE_BOTTOM_UP);
|
BIND_ENUM_CONSTANT(OCTREE_BOTTOM_UP);
|
||||||
BIND_ENUM_CONSTANT(OCTREE_TOP_DOWN);
|
BIND_ENUM_CONSTANT(OCTREE_TOP_DOWN);
|
||||||
|
BIND_ENUM_CONSTANT(OCTREE_NONE);
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,8 @@ public:
|
|||||||
|
|
||||||
enum OctreeMode {
|
enum OctreeMode {
|
||||||
OCTREE_BOTTOM_UP,
|
OCTREE_BOTTOM_UP,
|
||||||
OCTREE_TOP_DOWN
|
OCTREE_TOP_DOWN,
|
||||||
|
OCTREE_NONE
|
||||||
};
|
};
|
||||||
|
|
||||||
VoxelMesherDMC();
|
VoxelMesherDMC();
|
||||||
|
Loading…
Reference in New Issue
Block a user