mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-19 02:47:18 +01:00
Update DMC mesher to the API required to integrate to VoxelTerrain
This commit is contained in:
parent
101f83234a
commit
beace8709b
@ -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() {
|
||||||
|
@ -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; }
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user