Update DMC mesher to the API required to integrate to VoxelTerrain

This commit is contained in:
Marc Gilleron 2019-04-25 01:00:58 +01:00
parent 101f83234a
commit beace8709b
7 changed files with 81 additions and 54 deletions

View File

@ -2,13 +2,13 @@
namespace dmc { namespace dmc {
Ref<ArrayMesh> MeshBuilder::commit(bool wireframe) { Array MeshBuilder::commit(bool wireframe) {
if (_positions.size() == 0) { if (_positions.size() == 0) {
return Ref<ArrayMesh>(); return Array();
} }
ERR_FAIL_COND_V(_indices.size() % 3 != 0, Ref<ArrayMesh>()); ERR_FAIL_COND_V(_indices.size() % 3 != 0, Array());
if (wireframe) { if (wireframe) {
@ -46,11 +46,7 @@ Ref<ArrayMesh> MeshBuilder::commit(bool wireframe) {
surface[Mesh::ARRAY_NORMAL] = normals; surface[Mesh::ARRAY_NORMAL] = normals;
surface[Mesh::ARRAY_INDEX] = indices; surface[Mesh::ARRAY_INDEX] = indices;
Ref<ArrayMesh> mesh; return surface;
mesh.instance();
mesh->add_surface_from_arrays(wireframe ? Mesh::PRIMITIVE_LINES : Mesh::PRIMITIVE_TRIANGLES, surface);
return mesh;
} }
void MeshBuilder::clear() { void MeshBuilder::clear() {

View File

@ -37,7 +37,7 @@ public:
_indices.push_back(i); _indices.push_back(i);
} }
Ref<ArrayMesh> commit(bool wireframe); Array commit(bool wireframe);
void clear(); void clear();
int get_reused_vertex_count() const { return _reused_vertices; } int get_reused_vertex_count() const { return _reused_vertices; }

View File

@ -287,7 +287,7 @@ void foreach_node(OctreeNode *root, Action_T &a, int depth = 0) {
} }
} }
Ref<ArrayMesh> generate_debug_octree_mesh(OctreeNode *root) { Array generate_debug_octree_mesh(OctreeNode *root) {
struct GetMaxDepth { struct GetMaxDepth {
int max_depth; int max_depth;
@ -340,7 +340,7 @@ Ref<ArrayMesh> generate_debug_octree_mesh(OctreeNode *root) {
foreach_node(root, add_cube); foreach_node(root, add_cube);
if (arrays.positions.size() == 0) { if (arrays.positions.size() == 0) {
return Ref<ArrayMesh>(); return Array();
} }
Array surface; Array surface;
@ -349,14 +349,10 @@ Ref<ArrayMesh> generate_debug_octree_mesh(OctreeNode *root) {
surface[Mesh::ARRAY_COLOR] = arrays.colors; surface[Mesh::ARRAY_COLOR] = arrays.colors;
surface[Mesh::ARRAY_INDEX] = arrays.indices; surface[Mesh::ARRAY_INDEX] = arrays.indices;
Ref<ArrayMesh> mesh; return surface;
mesh.instance();
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, surface);
return mesh;
} }
Ref<ArrayMesh> generate_debug_dual_grid_mesh(const DualGrid &grid) { Array generate_debug_dual_grid_mesh(const DualGrid &grid) {
PoolVector3Array positions; PoolVector3Array positions;
PoolIntArray indices; PoolIntArray indices;
@ -380,7 +376,7 @@ Ref<ArrayMesh> generate_debug_dual_grid_mesh(const DualGrid &grid) {
} }
if (positions.size() == 0) { if (positions.size() == 0) {
return Ref<ArrayMesh>(); return Array();
} }
Array surface; Array surface;
@ -388,11 +384,7 @@ Ref<ArrayMesh> generate_debug_dual_grid_mesh(const DualGrid &grid) {
surface[Mesh::ARRAY_VERTEX] = positions; surface[Mesh::ARRAY_VERTEX] = positions;
surface[Mesh::ARRAY_INDEX] = indices; surface[Mesh::ARRAY_INDEX] = indices;
Ref<ArrayMesh> mesh; return surface;
mesh.instance();
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, surface);
return mesh;
} }
inline bool is_border_left(const OctreeNode *node) { inline bool is_border_left(const OctreeNode *node) {
@ -1325,7 +1317,7 @@ float VoxelMesherDMC::get_geometric_error() const {
return _geometric_error; return _geometric_error;
} }
Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) { Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
// Requirements: // Requirements:
// - Voxel data must be padded // - Voxel data must be padded
@ -1339,9 +1331,9 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
// Taking previous power of two because the algorithm uses an integer cubic octree, and data should be padded // Taking previous power of two because the algorithm uses an integer cubic octree, and data should be padded
int chunk_size = previous_power_of_2(MIN(MIN(buffer_size.x, buffer_size.y), buffer_size.z)); int chunk_size = previous_power_of_2(MIN(MIN(buffer_size.x, buffer_size.y), buffer_size.z));
ERR_FAIL_COND_V(voxels.get_size().x < chunk_size + padding * 2, Ref<ArrayMesh>()); ERR_FAIL_COND_V(voxels.get_size().x < chunk_size + padding * 2, Array());
ERR_FAIL_COND_V(voxels.get_size().y < chunk_size + padding * 2, Ref<ArrayMesh>()); ERR_FAIL_COND_V(voxels.get_size().y < chunk_size + padding * 2, Array());
ERR_FAIL_COND_V(voxels.get_size().z < chunk_size + padding * 2, Ref<ArrayMesh>()); ERR_FAIL_COND_V(voxels.get_size().z < chunk_size + padding * 2, Array());
// Construct an intermediate to handle padding transparently // Construct an intermediate to handle padding transparently
dmc::VoxelAccess voxels_access(voxels, Vector3i(padding)); dmc::VoxelAccess voxels_access(voxels, Vector3i(padding));
@ -1379,12 +1371,12 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
_stats.octree_build_time = OS::get_singleton()->get_ticks_usec() - time_before; _stats.octree_build_time = OS::get_singleton()->get_ticks_usec() - time_before;
Ref<ArrayMesh> mesh; Array surface;
if (root != nullptr) { if (root != nullptr) {
if (_mesh_mode == MESH_DEBUG_OCTREE) { if (_mesh_mode == MESH_DEBUG_OCTREE) {
mesh = dmc::generate_debug_octree_mesh(root); surface = dmc::generate_debug_octree_mesh(root);
} else { } else {
@ -1397,7 +1389,7 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
_stats.dualgrid_derivation_time = OS::get_singleton()->get_ticks_usec() - time_before; _stats.dualgrid_derivation_time = OS::get_singleton()->get_ticks_usec() - time_before;
if (_mesh_mode == MESH_DEBUG_DUAL_GRID) { if (_mesh_mode == MESH_DEBUG_DUAL_GRID) {
mesh = dmc::generate_debug_dual_grid_mesh(_dual_grid); surface = dmc::generate_debug_dual_grid_mesh(_dual_grid);
} else { } else {
@ -1421,18 +1413,42 @@ Ref<ArrayMesh> VoxelMesherDMC::build_mesh(const VoxelBuffer &voxels) {
_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(); if (surface.empty()) {
mesh = _mesh_builder.commit(_mesh_mode == MESH_WIREFRAME); time_before = OS::get_singleton()->get_ticks_usec();
_stats.commit_time = OS::get_singleton()->get_ticks_usec() - time_before; surface = _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; // surfaces[material][array_type], for now single material
Array surfaces;
surfaces.append(surface);
return surfaces;
} }
Ref<ArrayMesh> VoxelMesherDMC::_build_mesh_b(Ref<VoxelBuffer> voxels) { Ref<ArrayMesh> VoxelMesherDMC::build_mesh(Ref<VoxelBuffer> voxels) {
ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>()); ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>());
return build_mesh(**voxels);
Array surfaces = build(**voxels);
if (surfaces.empty()) {
return Ref<ArrayMesh>();
}
Ref<ArrayMesh> mesh;
mesh.instance();
for (int i = 0; i < surfaces.size(); ++i) {
if (_mesh_mode == MESH_NORMAL) {
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surfaces[i]);
} else {
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, surfaces[i]);
}
}
return mesh;
} }
Dictionary VoxelMesherDMC::get_stats() const { Dictionary VoxelMesherDMC::get_stats() const {
@ -1455,7 +1471,7 @@ void VoxelMesherDMC::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_geometric_error", "error"), &VoxelMesherDMC::set_geometric_error); ClassDB::bind_method(D_METHOD("set_geometric_error", "error"), &VoxelMesherDMC::set_geometric_error);
ClassDB::bind_method(D_METHOD("get_geometric_error"), &VoxelMesherDMC::get_geometric_error); ClassDB::bind_method(D_METHOD("get_geometric_error"), &VoxelMesherDMC::get_geometric_error);
ClassDB::bind_method(D_METHOD("build_mesh", "voxel_buffer"), &VoxelMesherDMC::_build_mesh_b); ClassDB::bind_method(D_METHOD("build_mesh", "voxel_buffer"), &VoxelMesherDMC::build_mesh);
ClassDB::bind_method(D_METHOD("get_stats"), &VoxelMesherDMC::get_stats); ClassDB::bind_method(D_METHOD("get_stats"), &VoxelMesherDMC::get_stats);
BIND_ENUM_CONSTANT(MESH_NORMAL); BIND_ENUM_CONSTANT(MESH_NORMAL);

View File

@ -91,12 +91,13 @@ public:
void set_geometric_error(real_t geometric_error); void set_geometric_error(real_t geometric_error);
float get_geometric_error() const; float get_geometric_error() const;
Ref<ArrayMesh> build_mesh(const VoxelBuffer &voxels); Array build(const VoxelBuffer &voxels);
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> voxels);
Dictionary get_stats() const; Dictionary get_stats() const;
protected: protected:
static void _bind_methods(); static void _bind_methods();
Ref<ArrayMesh> _build_mesh_b(Ref<VoxelBuffer> voxels);
private: private:
dmc::MeshBuilder _mesh_builder; dmc::MeshBuilder _mesh_builder;

View File

@ -7,12 +7,14 @@ VoxelMeshUpdater::VoxelMeshUpdater(Ref<VoxelLibrary> library, MeshingParams para
CRASH_COND(library.is_null()); CRASH_COND(library.is_null());
//CRASH_COND(params.materials.size() == 0); //CRASH_COND(params.materials.size() == 0);
_model_mesher.instance(); _blocky_mesher.instance();
_model_mesher->set_library(library); _blocky_mesher->set_library(library);
_model_mesher->set_occlusion_enabled(params.baked_ao); _blocky_mesher->set_occlusion_enabled(params.baked_ao);
_model_mesher->set_occlusion_darkness(params.baked_ao_darkness); _blocky_mesher->set_occlusion_darkness(params.baked_ao_darkness);
_smooth_mesher.instance(); _dmc_mesher.instance();
_dmc_mesher->set_geometric_error(0.05);
_dmc_mesher->set_octree_mode(VoxelMesherDMC::OCTREE_NONE);
_input_mutex = Mutex::create(); _input_mutex = Mutex::create();
_output_mutex = Mutex::create(); _output_mutex = Mutex::create();
@ -176,9 +178,9 @@ void VoxelMeshUpdater::process_block(const InputBlock &block, OutputBlock &outpu
CRASH_COND(block.voxels.is_null()); CRASH_COND(block.voxels.is_null());
// Build cubic parts of the mesh // Build cubic parts of the mesh
output.model_surfaces = _model_mesher->build(**block.voxels, Voxel::CHANNEL_TYPE, Vector3i(0, 0, 0), block.voxels->get_size() - Vector3(1, 1, 1)); output.model_surfaces = _blocky_mesher->build(**block.voxels, Voxel::CHANNEL_TYPE, Vector3i(0, 0, 0), block.voxels->get_size() - Vector3(1, 1, 1));
// Build smooth parts of the mesh // Build smooth parts of the mesh
output.smooth_surfaces = _smooth_mesher->build(**block.voxels, Voxel::CHANNEL_ISOLEVEL); output.smooth_surfaces = _dmc_mesher->build(**block.voxels);
output.position = block.position; output.position = block.position;
} }

View File

@ -5,7 +5,7 @@
#include <core/os/thread.h> #include <core/os/thread.h>
#include <core/vector.h> #include <core/vector.h>
#include "transvoxel/voxel_mesher_transvoxel.h" #include "dmc/voxel_mesher_dmc.h"
#include "voxel_buffer.h" #include "voxel_buffer.h"
#include "voxel_mesher.h" #include "voxel_mesher.h"
@ -81,8 +81,8 @@ private:
Output _shared_output; Output _shared_output;
Mutex *_output_mutex; Mutex *_output_mutex;
Ref<VoxelMesher> _model_mesher; Ref<VoxelMesher> _blocky_mesher;
Ref<VoxelMesherTransvoxel> _smooth_mesher; Ref<VoxelMesherDMC> _dmc_mesher;
Input _input; Input _input;
Output _output; Output _output;

View File

@ -536,6 +536,7 @@ void VoxelTerrain::_process() {
// TODO Use editor's camera here // TODO Use editor's camera here
viewer_block_pos = Vector3i(); viewer_block_pos = Vector3i();
} else { } else {
// TODO Use viewport camera, much easier
Spatial *viewer = get_viewer(_viewer_path); Spatial *viewer = get_viewer(_viewer_path);
if (viewer) if (viewer)
viewer_block_pos = _map->voxel_to_block(viewer->get_translation()); viewer_block_pos = _map->voxel_to_block(viewer->get_translation());
@ -699,7 +700,10 @@ void VoxelTerrain::_process() {
CRASH_COND(*block_state != BLOCK_UPDATE_NOT_SENT); CRASH_COND(*block_state != BLOCK_UPDATE_NOT_SENT);
int air_type = 0; int air_type = 0;
if (block->voxels->is_uniform(Voxel::CHANNEL_TYPE) && block->voxels->get_voxel(0, 0, 0, Voxel::CHANNEL_TYPE) == air_type) { if (
block->voxels->is_uniform(Voxel::CHANNEL_TYPE) &&
block->voxels->is_uniform(Voxel::CHANNEL_ISOLEVEL) &&
block->voxels->get_voxel(0, 0, 0, Voxel::CHANNEL_TYPE) == air_type) {
// The block contains empty voxels // The block contains empty voxels
block->set_mesh(Ref<Mesh>(), Ref<World>()); block->set_mesh(Ref<Mesh>(), Ref<World>());
@ -718,7 +722,8 @@ void VoxelTerrain::_process() {
// TODO Padding set to 3 at the moment because Transvoxel works on 2x2 cells. // TODO Padding set to 3 at the moment because Transvoxel works on 2x2 cells.
// It should change for a smarter padding (if smooth isn't used for example). // It should change for a smarter padding (if smooth isn't used for example).
unsigned int block_size = _map->get_block_size(); unsigned int block_size = _map->get_block_size();
nbuffer->create(block_size + 3, block_size + 3, block_size + 3); //nbuffer->create(block_size + 3, block_size + 3, block_size + 3);
nbuffer->create(block_size + 2, block_size + 2, block_size + 2);
_map->get_buffer_copy(_map->block_to_voxel(block_pos) - Vector3i(1, 1, 1), **nbuffer, 0x3); _map->get_buffer_copy(_map->block_to_voxel(block_pos) - Vector3i(1, 1, 1), **nbuffer, 0x3);
@ -782,9 +787,11 @@ void VoxelTerrain::_process() {
for (int i = 0; i < ob.model_surfaces.size(); ++i) { for (int i = 0; i < ob.model_surfaces.size(); ++i) {
Array surface = ob.model_surfaces[i]; Array surface = ob.model_surfaces[i];
if (surface.empty()) if (surface.empty()) {
continue; continue;
}
CRASH_COND(surface.size() != Mesh::ARRAY_MAX);
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface); mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface);
mesh->surface_set_material(surface_index, _materials[i]); mesh->surface_set_material(surface_index, _materials[i]);
@ -794,16 +801,21 @@ void VoxelTerrain::_process() {
for (int i = 0; i < ob.smooth_surfaces.size(); ++i) { for (int i = 0; i < ob.smooth_surfaces.size(); ++i) {
Array surface = ob.smooth_surfaces[i]; Array surface = ob.smooth_surfaces[i];
if (surface.empty()) if (surface.empty()) {
continue; continue;
}
CRASH_COND(surface.size() != Mesh::ARRAY_MAX);
// TODO Problem here, the mesher could be configured to output wireframe! Need to output some MeshData struct instead
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface); mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface);
mesh->surface_set_material(surface_index, _materials[i]);
// No material supported yet // No material supported yet
++surface_index; ++surface_index;
} }
if (is_mesh_empty(mesh)) if (is_mesh_empty(mesh)) {
mesh = Ref<Mesh>(); mesh = Ref<Mesh>();
}
block->set_mesh(mesh, world); block->set_mesh(mesh, world);
} }