Add base class to all meshers, gather common things in it

This commit is contained in:
Marc Gilleron 2019-04-28 20:48:59 +01:00
parent 12a97cca5a
commit faefde721a
14 changed files with 167 additions and 157 deletions

1
SCsub
View File

@ -4,6 +4,7 @@ env.add_source_files(env.modules_sources, "*.cpp")
env.add_source_files(env.modules_sources, "meshers/blocky/*.cpp") env.add_source_files(env.modules_sources, "meshers/blocky/*.cpp")
env.add_source_files(env.modules_sources, "meshers/transvoxel/*.cpp") env.add_source_files(env.modules_sources, "meshers/transvoxel/*.cpp")
env.add_source_files(env.modules_sources, "meshers/dmc/*.cpp") env.add_source_files(env.modules_sources, "meshers/dmc/*.cpp")
env.add_source_files(env.modules_sources, "meshers/*.cpp")
env.add_source_files(env.modules_sources, "providers/*.cpp") env.add_source_files(env.modules_sources, "providers/*.cpp")
env.add_source_files(env.modules_sources, "util/*.cpp") env.add_source_files(env.modules_sources, "util/*.cpp")
env.add_source_files(env.modules_sources, "terrain/*.cpp") env.add_source_files(env.modules_sources, "terrain/*.cpp")

View File

@ -4,6 +4,8 @@
#include "../../voxel_library.h" #include "../../voxel_library.h"
#include <core/os/os.h> #include <core/os/os.h>
namespace {
template <typename T> template <typename T>
void raw_copy_to(PoolVector<T> &to, const Vector<T> &from) { void raw_copy_to(PoolVector<T> &to, const Vector<T> &from) {
to.resize(from.size()); to.resize(from.size());
@ -11,26 +13,6 @@ void raw_copy_to(PoolVector<T> &to, const Vector<T> &from) {
memcpy(w.ptr(), from.ptr(), from.size() * sizeof(T)); memcpy(w.ptr(), from.ptr(), from.size() * sizeof(T));
} }
VoxelMesherBlocky::VoxelMesherBlocky() :
_baked_occlusion_darkness(0.8),
_bake_occlusion(true) {}
void VoxelMesherBlocky::set_library(Ref<VoxelLibrary> library) {
_library = library;
}
void VoxelMesherBlocky::set_occlusion_darkness(float darkness) {
_baked_occlusion_darkness = darkness;
if (_baked_occlusion_darkness < 0.0)
_baked_occlusion_darkness = 0.0;
else if (_baked_occlusion_darkness >= 1.0)
_baked_occlusion_darkness = 1.0;
}
void VoxelMesherBlocky::set_occlusion_enabled(bool enable) {
_bake_occlusion = enable;
}
inline Color Color_greyscale(float c) { inline Color Color_greyscale(float c) {
return Color(c, c, c); return Color(c, c, c);
} }
@ -51,36 +33,35 @@ inline bool is_transparent(const VoxelLibrary &lib, int voxel_id) {
return true; return true;
} }
Ref<ArrayMesh> VoxelMesherBlocky::build_mesh(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Array materials, Ref<ArrayMesh> mesh) { } // namespace
ERR_FAIL_COND_V(buffer_ref.is_null(), Ref<ArrayMesh>());
VoxelBuffer &buffer = **buffer_ref; VoxelMesherBlocky::VoxelMesherBlocky() :
Array surfaces = build(buffer, channel, MINIMUM_PADDING); _baked_occlusion_darkness(0.8),
_bake_occlusion(true) {}
if (mesh.is_null()) void VoxelMesherBlocky::set_library(Ref<VoxelLibrary> library) {
mesh.instance(); _library = library;
int surface = mesh->get_surface_count();
for (int i = 0; i < surfaces.size(); ++i) {
Array arrays = surfaces[i];
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
Ref<Material> material = materials[i];
if (material.is_valid()) {
mesh->surface_set_material(surface, material);
}
}
return mesh;
} }
Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel, int padding) { void VoxelMesherBlocky::set_occlusion_darkness(float darkness) {
_baked_occlusion_darkness = darkness;
if (_baked_occlusion_darkness < 0.0)
_baked_occlusion_darkness = 0.0;
else if (_baked_occlusion_darkness >= 1.0)
_baked_occlusion_darkness = 1.0;
}
void VoxelMesherBlocky::set_occlusion_enabled(bool enable) {
_bake_occlusion = enable;
}
void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelBuffer &buffer, int padding) {
//uint64_t time_before = OS::get_singleton()->get_ticks_usec(); //uint64_t time_before = OS::get_singleton()->get_ticks_usec();
ERR_FAIL_COND_V(_library.is_null(), Array()); ERR_FAIL_COND(_library.is_null());
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array()); ERR_FAIL_COND(padding < MINIMUM_PADDING);
ERR_FAIL_COND_V(padding < MINIMUM_PADDING, Array());
const int channel = VoxelBuffer::CHANNEL_TYPE;
const VoxelLibrary &library = **_library; const VoxelLibrary &library = **_library;
@ -118,7 +99,7 @@ Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel,
// That means we can use raw pointers to voxel data inside instead of using the higher-level getters, // That means we can use raw pointers to voxel data inside instead of using the higher-level getters,
// and then save a lot of time. // and then save a lot of time.
uint8_t *type_buffer = buffer.get_channel_raw(Voxel::CHANNEL_TYPE); uint8_t *type_buffer = buffer.get_channel_raw(channel);
// _ // _
// | \ // | \
// /\ \\ // /\ \\
@ -132,7 +113,7 @@ Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel,
// No data to read, the channel is probably uniform // No data to read, the channel is probably uniform
// TODO This is an invalid behavior IF sending a full block of uniformly opaque cubes, // TODO This is an invalid behavior IF sending a full block of uniformly opaque cubes,
// however not likely for terrains because with neighbor padding, such a case means no face would be generated anyways // however not likely for terrains because with neighbor padding, such a case means no face would be generated anyways
return Array(); return;
} }
//CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t)); //CRASH_COND(memarr_len(type_buffer) != buffer.get_volume() * sizeof(uint8_t));
@ -367,8 +348,6 @@ Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel,
// print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size()) // print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size())
// + String(", i: ") + String::num(_arrays[0].indices.size())); // + String(", i: ") + String::num(_arrays[0].indices.size()));
Array surfaces;
// TODO We could return a single byte array and use Mesh::add_surface down the line? // TODO We could return a single byte array and use Mesh::add_surface down the line?
for (int i = 0; i < MAX_MATERIALS; ++i) { for (int i = 0; i < MAX_MATERIALS; ++i) {
@ -407,15 +386,19 @@ Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel,
mesh_arrays[Mesh::ARRAY_INDEX] = indices; mesh_arrays[Mesh::ARRAY_INDEX] = indices;
} }
surfaces.append(mesh_arrays); output.surfaces.push_back(mesh_arrays);
} }
} }
output.primitive_type = Mesh::PRIMITIVE_TRIANGLES;
//uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before; //uint64_t time_commit = OS::get_singleton()->get_ticks_usec() - time_before;
//print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit))); //print_line(String("P: {0}, M: {1}, C: {2}").format(varray(time_prep, time_meshing, time_commit)));
}
return surfaces; int VoxelMesherBlocky::get_minimum_padding() const {
return MINIMUM_PADDING;
} }
void VoxelMesherBlocky::_bind_methods() { void VoxelMesherBlocky::_bind_methods() {
@ -429,8 +412,6 @@ void VoxelMesherBlocky::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_occlusion_darkness", "value"), &VoxelMesherBlocky::set_occlusion_darkness); ClassDB::bind_method(D_METHOD("set_occlusion_darkness", "value"), &VoxelMesherBlocky::set_occlusion_darkness);
ClassDB::bind_method(D_METHOD("get_occlusion_darkness"), &VoxelMesherBlocky::get_occlusion_darkness); ClassDB::bind_method(D_METHOD("get_occlusion_darkness"), &VoxelMesherBlocky::get_occlusion_darkness);
ClassDB::bind_method(D_METHOD("build_mesh", "voxel_buffer", "channel", "materials", "existing_mesh"), &VoxelMesherBlocky::build_mesh);
#ifdef VOXEL_PROFILING #ifdef VOXEL_PROFILING
ClassDB::bind_method(D_METHOD("get_profiling_info"), &VoxelMesherBlocky::get_profiling_info); ClassDB::bind_method(D_METHOD("get_profiling_info"), &VoxelMesherBlocky::get_profiling_info);
#endif #endif

View File

@ -3,14 +3,13 @@
#include "../../util/zprofiling.h" #include "../../util/zprofiling.h"
#include "../../voxel.h" #include "../../voxel.h"
#include "../../voxel_buffer.h"
#include "../../voxel_library.h" #include "../../voxel_library.h"
#include "../voxel_mesher.h"
#include <core/reference.h> #include <core/reference.h>
#include <scene/resources/mesh.h> #include <scene/resources/mesh.h>
// TODO Should be renamed VoxelMesherBlocky or something like that class VoxelMesherBlocky : public VoxelMesher {
class VoxelMesherBlocky : public Reference { GDCLASS(VoxelMesherBlocky, VoxelMesher)
GDCLASS(VoxelMesherBlocky, Reference)
public: public:
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed. static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
@ -27,13 +26,14 @@ public:
void set_occlusion_enabled(bool enable); void set_occlusion_enabled(bool enable);
bool get_occlusion_enabled() const { return _bake_occlusion; } bool get_occlusion_enabled() const { return _bake_occlusion; }
Array build(const VoxelBuffer &buffer_ref, unsigned int channel, int padding); void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Array materials, Ref<ArrayMesh> mesh = Ref<ArrayMesh>()); int get_minimum_padding() const override;
protected: protected:
static void _bind_methods(); static void _bind_methods();
private: private:
// TODO Replace those with std::vector, it's faster
struct Arrays { struct Arrays {
Vector<Vector3> positions; Vector<Vector3> positions;
Vector<Vector3> normals; Vector<Vector3> normals;

View File

@ -1317,7 +1317,7 @@ float VoxelMesherDMC::get_geometric_error() const {
return _geometric_error; return _geometric_error;
} }
Array VoxelMesherDMC::build(const VoxelBuffer &voxels) { void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) {
// Requirements: // Requirements:
// - Voxel data must be padded // - Voxel data must be padded
@ -1328,17 +1328,18 @@ Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
if (voxels.is_uniform(VoxelBuffer::CHANNEL_ISOLEVEL)) { if (voxels.is_uniform(VoxelBuffer::CHANNEL_ISOLEVEL)) {
// That won't produce any polygon // That won't produce any polygon
return Array(); return;
} }
int padding = 2; ERR_FAIL_COND(padding < MINIMUM_PADDING);
const Vector3i buffer_size = voxels.get_size(); const Vector3i buffer_size = voxels.get_size();
// 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, Array()); ERR_FAIL_COND(voxels.get_size().x < chunk_size + padding * 2);
ERR_FAIL_COND_V(voxels.get_size().y < chunk_size + padding * 2, Array()); ERR_FAIL_COND(voxels.get_size().y < chunk_size + padding * 2);
ERR_FAIL_COND_V(voxels.get_size().z < chunk_size + padding * 2, Array()); ERR_FAIL_COND(voxels.get_size().z < chunk_size + padding * 2);
// 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));
@ -1427,33 +1428,17 @@ Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
// TODO Marching squares skirts // TODO Marching squares skirts
// surfaces[material][array_type], for now single material // surfaces[material][array_type], for now single material
Array surfaces; output.surfaces.push_back(surface);
surfaces.append(surface);
return surfaces; if (_mesh_mode == MESH_NORMAL) {
output.primitive_type = Mesh::PRIMITIVE_TRIANGLES;
} else {
output.primitive_type = Mesh::PRIMITIVE_LINES;
}
} }
Ref<ArrayMesh> VoxelMesherDMC::build_mesh(Ref<VoxelBuffer> voxels) { int VoxelMesherDMC::get_minimum_padding() const {
return MINIMUM_PADDING;
ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>());
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 {
@ -1476,7 +1461,6 @@ 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);
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

@ -1,7 +1,7 @@
#ifndef VOXEL_MESHER_DMC_H #ifndef VOXEL_MESHER_DMC_H
#define VOXEL_MESHER_DMC_H #define VOXEL_MESHER_DMC_H
#include "../../voxel_buffer.h" #include "../voxel_mesher.h"
#include "hermite_value.h" #include "hermite_value.h"
#include "mesh_builder.h" #include "mesh_builder.h"
#include "object_pool.h" #include "object_pool.h"
@ -64,9 +64,11 @@ struct DualGrid {
} // namespace dmc } // namespace dmc
class VoxelMesherDMC : public Reference { class VoxelMesherDMC : public VoxelMesher {
GDCLASS(VoxelMesherDMC, Reference) GDCLASS(VoxelMesherDMC, VoxelMesher)
public: public:
static const int MINIMUM_PADDING = 2;
enum MeshMode { enum MeshMode {
MESH_NORMAL, MESH_NORMAL,
MESH_WIREFRAME, MESH_WIREFRAME,
@ -91,8 +93,8 @@ 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;
Array build(const VoxelBuffer &voxels); void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> voxels); int get_minimum_padding() const override;
Dictionary get_stats() const; Dictionary get_stats() const;

View File

@ -3,6 +3,8 @@
#include "transvoxel_tables.cpp" #include "transvoxel_tables.cpp"
#include <core/os/os.h> #include <core/os/os.h>
namespace {
inline float tof(int8_t v) { inline float tof(int8_t v) {
return static_cast<float>(v) / 256.f; return static_cast<float>(v) / 256.f;
} }
@ -58,6 +60,8 @@ void copy_to(PoolVector<T> &to, Vector<T> &from) {
} }
} }
} // namespace
VoxelMesherTransvoxel::ReuseCell::ReuseCell() { VoxelMesherTransvoxel::ReuseCell::ReuseCell() {
case_index = 0; case_index = 0;
for (unsigned int i = 0; i < 4; ++i) { for (unsigned int i = 0; i < 4; ++i) {
@ -65,32 +69,15 @@ VoxelMesherTransvoxel::ReuseCell::ReuseCell() {
} }
} }
VoxelMesherTransvoxel::VoxelMesherTransvoxel() { int VoxelMesherTransvoxel::get_minimum_padding() const {
return MINIMUM_PADDING;
} }
Ref<ArrayMesh> VoxelMesherTransvoxel::build_mesh(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh) { void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) {
ERR_FAIL_COND_V(voxels_ref.is_null(), Ref<ArrayMesh>()); ERR_FAIL_COND(padding < MINIMUM_PADDING);
VoxelBuffer &buffer = **voxels_ref; int channel = VoxelBuffer::CHANNEL_ISOLEVEL;
Array surfaces = build(buffer, channel);
if (mesh.is_null())
mesh.instance();
//int surface = mesh->get_surface_count();
for (int i = 0; i < surfaces.size(); ++i) {
Array arrays = surfaces[i];
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, arrays);
//mesh->surface_set_material(surface, _materials[i]);
}
return mesh;
}
Array VoxelMesherTransvoxel::build(const VoxelBuffer &voxels, unsigned int channel) {
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array());
// Initialize dynamic memory: // Initialize dynamic memory:
// These vectors are re-used. // These vectors are re-used.
@ -109,7 +96,7 @@ Array VoxelMesherTransvoxel::build(const VoxelBuffer &voxels, unsigned int chann
if (m_output_vertices.size() == 0) { if (m_output_vertices.size() == 0) {
// The mesh can be empty // The mesh can be empty
return Array(); return;
} }
PoolVector<Vector3> vertices; PoolVector<Vector3> vertices;
@ -128,10 +115,8 @@ Array VoxelMesherTransvoxel::build(const VoxelBuffer &voxels, unsigned int chann
} }
arrays[Mesh::ARRAY_INDEX] = indices; arrays[Mesh::ARRAY_INDEX] = indices;
Array surfaces; output.surfaces.push_back(arrays);
surfaces.append(arrays); output.primitive_type = Mesh::PRIMITIVE_TRIANGLES;
return surfaces;
} }
void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned int channel) { void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned int channel) {
@ -393,6 +378,4 @@ void VoxelMesherTransvoxel::emit_vertex(Vector3 primary, Vector3 normal) {
} }
void VoxelMesherTransvoxel::_bind_methods() { void VoxelMesherTransvoxel::_bind_methods() {
ClassDB::bind_method(D_METHOD("build", "voxels", "channel", "existing_mesh"), &VoxelMesherTransvoxel::build_mesh, DEFVAL(Variant()));
} }

View File

@ -1,17 +1,17 @@
#ifndef VOXEL_MESHER_SMOOTH_H #ifndef VOXEL_MESHER_SMOOTH_H
#define VOXEL_MESHER_SMOOTH_H #define VOXEL_MESHER_SMOOTH_H
#include "../../voxel_buffer.h" #include "../voxel_mesher.h"
#include <scene/resources/mesh.h> #include <scene/resources/mesh.h>
class VoxelMesherTransvoxel : public Reference { class VoxelMesherTransvoxel : public VoxelMesher {
GDCLASS(VoxelMesherTransvoxel, Reference) GDCLASS(VoxelMesherTransvoxel, VoxelMesher)
public: public:
VoxelMesherTransvoxel(); static const int MINIMUM_PADDING = 2;
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh = Ref<ArrayMesh>()); void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
Array build(const VoxelBuffer &voxels, unsigned int channel); int get_minimum_padding() const override;
protected: protected:
static void _bind_methods(); static void _bind_methods();

36
meshers/voxel_mesher.cpp Normal file
View File

@ -0,0 +1,36 @@
#include "voxel_mesher.h"
Ref<Mesh> VoxelMesher::build_mesh(Ref<VoxelBuffer> voxels) {
ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>());
Output output;
build(output, **voxels, get_minimum_padding());
if (output.surfaces.empty()) {
return Ref<ArrayMesh>();
}
Ref<ArrayMesh> mesh;
mesh.instance();
for (int i = 0; i < output.surfaces.size(); ++i) {
mesh->add_surface_from_arrays(output.primitive_type, output.surfaces[i]);
}
return mesh;
}
void VoxelMesher::build(Output &output, const VoxelBuffer &voxels, int padding) {
}
int VoxelMesher::get_minimum_padding() const {
return 0;
}
void VoxelMesher::_bind_methods() {
// Shortcut if you want to generate a mesh directly from a fixed grid of voxels.
// Useful for testing the different meshers.
ClassDB::bind_method(D_METHOD("build_mesh", "voxel_buffer"), &VoxelMesher::build_mesh);
}

24
meshers/voxel_mesher.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef VOXEL_MESHER_H
#define VOXEL_MESHER_H
#include "../voxel_buffer.h"
#include <scene/resources/mesh.h>
class VoxelMesher : public Reference {
GDCLASS(VoxelMesher, Reference)
public:
struct Output {
Vector<Array> surfaces;
Mesh::PrimitiveType primitive_type;
};
virtual void build(Output &output, const VoxelBuffer &voxels, int padding);
virtual int get_minimum_padding() const;
Ref<Mesh> build_mesh(Ref<VoxelBuffer> voxels);
protected:
static void _bind_methods();
};
#endif // VOXEL_MESHER_H

View File

@ -34,6 +34,7 @@ void register_voxel_types() {
ClassDB::register_class<VoxelIsoSurfaceTool>(); ClassDB::register_class<VoxelIsoSurfaceTool>();
// Meshers // Meshers
ClassDB::register_class<VoxelMesher>();
ClassDB::register_class<VoxelMesherBlocky>(); ClassDB::register_class<VoxelMesherBlocky>();
ClassDB::register_class<VoxelMesherTransvoxel>(); ClassDB::register_class<VoxelMesherTransvoxel>();
ClassDB::register_class<VoxelMesherDMC>(); ClassDB::register_class<VoxelMesherDMC>();

View File

@ -107,6 +107,17 @@ void VoxelMeshUpdater::pop(Output &output) {
_shared_output.blocks.clear(); _shared_output.blocks.clear();
} }
int VoxelMeshUpdater::get_required_padding() const {
int padding = _blocky_mesher->get_minimum_padding();
if (_dmc_mesher.is_valid()) {
padding = max(padding, _dmc_mesher->get_minimum_padding());
}
return padding;
}
void VoxelMeshUpdater::_thread_func(void *p_self) { void VoxelMeshUpdater::_thread_func(void *p_self) {
VoxelMeshUpdater *self = reinterpret_cast<VoxelMeshUpdater *>(p_self); VoxelMeshUpdater *self = reinterpret_cast<VoxelMeshUpdater *>(p_self);
self->thread_func(); self->thread_func();
@ -181,17 +192,12 @@ void VoxelMeshUpdater::process_block(const InputBlock &block, OutputBlock &outpu
CRASH_COND(block.voxels.is_null()); CRASH_COND(block.voxels.is_null());
int padding = 1; int padding = get_required_padding();
if (_dmc_mesher.is_valid()) {
padding = 2;
}
// Build cubic parts of the mesh _blocky_mesher->build(output.blocky_surfaces, **block.voxels, padding);
output.model_surfaces = _blocky_mesher->build(**block.voxels, Voxel::CHANNEL_TYPE, padding);
if (_dmc_mesher.is_valid()) { if (_dmc_mesher.is_valid()) {
// Build smooth parts of the mesh _dmc_mesher->build(output.smooth_surfaces, **block.voxels, padding);
output.smooth_surfaces = _dmc_mesher->build(**block.voxels);
} }
output.position = block.position; output.position = block.position;

View File

@ -26,8 +26,8 @@ public:
}; };
struct OutputBlock { struct OutputBlock {
Array model_surfaces; VoxelMesher::Output blocky_surfaces;
Array smooth_surfaces; VoxelMesher::Output smooth_surfaces;
Vector3i position; Vector3i position;
}; };
@ -66,6 +66,8 @@ public:
void push(const Input &input); void push(const Input &input);
void pop(Output &output); void pop(Output &output);
int get_required_padding() const;
private: private:
static void _thread_func(void *p_self); static void _thread_func(void *p_self);
void thread_func(); void thread_func();

View File

@ -286,15 +286,6 @@ void VoxelTerrain::reset_updater() {
_block_updater = memnew(VoxelMeshUpdater(_library, params)); _block_updater = memnew(VoxelMeshUpdater(_library, params));
} }
int VoxelTerrain::get_block_padding() const {
// How many neighbor voxels we should pad for mesh updates to be seamless
// TODO Generalize padding retrieval, or split terrain systems because blocky and smooth are two different beasts
// - Blocky needs padding of 1
// - Transvoxel needs padding of 2
// - DMC needs padding of 2
return _smooth_meshing_enabled ? 2 : 1;
}
inline int get_border_index(int x, int max) { inline int get_border_index(int x, int max) {
return x == 0 ? 0 : x != max ? 1 : 2; return x == 0 ? 0 : x != max ? 1 : 2;
} }
@ -757,7 +748,7 @@ void VoxelTerrain::_process() {
// TODO Make the buffer re-usable // TODO Make the buffer re-usable
unsigned int block_size = _map->get_block_size(); unsigned int block_size = _map->get_block_size();
unsigned int padding = get_block_padding(); unsigned int padding = _block_updater->get_required_padding();
nbuffer->create(block_size + 2 * padding, block_size + 2 * padding, block_size + 2 * padding); nbuffer->create(block_size + 2 * padding, block_size + 2 * padding, block_size + 2 * padding);
unsigned int channels_mask = (1 << VoxelBuffer::CHANNEL_TYPE) | (1 << VoxelBuffer::CHANNEL_ISOLEVEL); unsigned int channels_mask = (1 << VoxelBuffer::CHANNEL_TYPE) | (1 << VoxelBuffer::CHANNEL_ISOLEVEL);
@ -820,30 +811,30 @@ void VoxelTerrain::_process() {
mesh.instance(); mesh.instance();
int surface_index = 0; int surface_index = 0;
for (int i = 0; i < ob.model_surfaces.size(); ++i) { for (int i = 0; i < ob.blocky_surfaces.surfaces.size(); ++i) {
Array surface = ob.model_surfaces[i]; Array surface = ob.blocky_surfaces.surfaces[i];
if (surface.empty()) { if (surface.empty()) {
continue; continue;
} }
CRASH_COND(surface.size() != Mesh::ARRAY_MAX); CRASH_COND(surface.size() != Mesh::ARRAY_MAX);
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, surface); mesh->add_surface_from_arrays(ob.blocky_surfaces.primitive_type, surface);
mesh->surface_set_material(surface_index, _materials[i]); mesh->surface_set_material(surface_index, _materials[i]);
++surface_index; ++surface_index;
} }
for (int i = 0; i < ob.smooth_surfaces.size(); ++i) { for (int i = 0; i < ob.smooth_surfaces.surfaces.size(); ++i) {
Array surface = ob.smooth_surfaces[i]; Array surface = ob.smooth_surfaces.surfaces[i];
if (surface.empty()) { if (surface.empty()) {
continue; continue;
} }
CRASH_COND(surface.size() != Mesh::ARRAY_MAX); 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 // 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(ob.smooth_surfaces.primitive_type, surface);
mesh->surface_set_material(surface_index, _materials[i]); mesh->surface_set_material(surface_index, _materials[i]);
// No material supported yet // No material supported yet
++surface_index; ++surface_index;

View File

@ -98,7 +98,6 @@ private:
void make_all_view_dirty_deferred(); void make_all_view_dirty_deferred();
void reset_updater(); void reset_updater();
int get_block_padding() const;
Spatial *get_viewer(NodePath path) const; Spatial *get_viewer(NodePath path) const;