mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-19 02:47:18 +01:00
Add base class to all meshers, gather common things in it
This commit is contained in:
parent
12a97cca5a
commit
faefde721a
1
SCsub
1
SCsub
@ -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/transvoxel/*.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, "util/*.cpp")
|
||||
env.add_source_files(env.modules_sources, "terrain/*.cpp")
|
||||
|
@ -4,6 +4,8 @@
|
||||
#include "../../voxel_library.h"
|
||||
#include <core/os/os.h>
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename T>
|
||||
void raw_copy_to(PoolVector<T> &to, const Vector<T> &from) {
|
||||
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));
|
||||
}
|
||||
|
||||
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) {
|
||||
return Color(c, c, c);
|
||||
}
|
||||
@ -51,36 +33,35 @@ inline bool is_transparent(const VoxelLibrary &lib, int voxel_id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Ref<ArrayMesh> VoxelMesherBlocky::build_mesh(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Array materials, Ref<ArrayMesh> mesh) {
|
||||
ERR_FAIL_COND_V(buffer_ref.is_null(), Ref<ArrayMesh>());
|
||||
} // namespace
|
||||
|
||||
VoxelBuffer &buffer = **buffer_ref;
|
||||
Array surfaces = build(buffer, channel, MINIMUM_PADDING);
|
||||
VoxelMesherBlocky::VoxelMesherBlocky() :
|
||||
_baked_occlusion_darkness(0.8),
|
||||
_bake_occlusion(true) {}
|
||||
|
||||
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);
|
||||
|
||||
Ref<Material> material = materials[i];
|
||||
if (material.is_valid()) {
|
||||
mesh->surface_set_material(surface, material);
|
||||
}
|
||||
void VoxelMesherBlocky::set_library(Ref<VoxelLibrary> library) {
|
||||
_library = library;
|
||||
}
|
||||
|
||||
return mesh;
|
||||
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;
|
||||
}
|
||||
|
||||
Array VoxelMesherBlocky::build(const VoxelBuffer &buffer, unsigned int channel, int padding) {
|
||||
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();
|
||||
|
||||
ERR_FAIL_COND_V(_library.is_null(), Array());
|
||||
ERR_FAIL_COND_V(channel >= VoxelBuffer::MAX_CHANNELS, Array());
|
||||
ERR_FAIL_COND_V(padding < MINIMUM_PADDING, Array());
|
||||
ERR_FAIL_COND(_library.is_null());
|
||||
ERR_FAIL_COND(padding < MINIMUM_PADDING);
|
||||
|
||||
const int channel = VoxelBuffer::CHANNEL_TYPE;
|
||||
|
||||
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,
|
||||
// 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
|
||||
// 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
|
||||
return Array();
|
||||
return;
|
||||
}
|
||||
|
||||
//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())
|
||||
// + 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?
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//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() {
|
||||
@ -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("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
|
||||
ClassDB::bind_method(D_METHOD("get_profiling_info"), &VoxelMesherBlocky::get_profiling_info);
|
||||
#endif
|
||||
|
@ -3,14 +3,13 @@
|
||||
|
||||
#include "../../util/zprofiling.h"
|
||||
#include "../../voxel.h"
|
||||
#include "../../voxel_buffer.h"
|
||||
#include "../../voxel_library.h"
|
||||
#include "../voxel_mesher.h"
|
||||
#include <core/reference.h>
|
||||
#include <scene/resources/mesh.h>
|
||||
|
||||
// TODO Should be renamed VoxelMesherBlocky or something like that
|
||||
class VoxelMesherBlocky : public Reference {
|
||||
GDCLASS(VoxelMesherBlocky, Reference)
|
||||
class VoxelMesherBlocky : public VoxelMesher {
|
||||
GDCLASS(VoxelMesherBlocky, VoxelMesher)
|
||||
|
||||
public:
|
||||
static const unsigned int MAX_MATERIALS = 8; // Arbitrary. Tweak if needed.
|
||||
@ -27,13 +26,14 @@ public:
|
||||
void set_occlusion_enabled(bool enable);
|
||||
bool get_occlusion_enabled() const { return _bake_occlusion; }
|
||||
|
||||
Array build(const VoxelBuffer &buffer_ref, unsigned int channel, int padding);
|
||||
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> buffer_ref, unsigned int channel, Array materials, Ref<ArrayMesh> mesh = Ref<ArrayMesh>());
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
|
||||
int get_minimum_padding() const override;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
||||
private:
|
||||
// TODO Replace those with std::vector, it's faster
|
||||
struct Arrays {
|
||||
Vector<Vector3> positions;
|
||||
Vector<Vector3> normals;
|
||||
|
@ -1317,7 +1317,7 @@ float VoxelMesherDMC::get_geometric_error() const {
|
||||
return _geometric_error;
|
||||
}
|
||||
|
||||
Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
|
||||
void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) {
|
||||
|
||||
// Requirements:
|
||||
// - Voxel data must be padded
|
||||
@ -1328,17 +1328,18 @@ Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
|
||||
|
||||
if (voxels.is_uniform(VoxelBuffer::CHANNEL_ISOLEVEL)) {
|
||||
// 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();
|
||||
// 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));
|
||||
|
||||
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, Array());
|
||||
ERR_FAIL_COND_V(voxels.get_size().z < chunk_size + padding * 2, Array());
|
||||
ERR_FAIL_COND(voxels.get_size().x < chunk_size + padding * 2);
|
||||
ERR_FAIL_COND(voxels.get_size().y < chunk_size + padding * 2);
|
||||
ERR_FAIL_COND(voxels.get_size().z < chunk_size + padding * 2);
|
||||
|
||||
// Construct an intermediate to handle padding transparently
|
||||
dmc::VoxelAccess voxels_access(voxels, Vector3i(padding));
|
||||
@ -1427,33 +1428,17 @@ Array VoxelMesherDMC::build(const VoxelBuffer &voxels) {
|
||||
// TODO Marching squares skirts
|
||||
|
||||
// surfaces[material][array_type], for now single material
|
||||
Array surfaces;
|
||||
surfaces.append(surface);
|
||||
return surfaces;
|
||||
}
|
||||
output.surfaces.push_back(surface);
|
||||
|
||||
Ref<ArrayMesh> VoxelMesherDMC::build_mesh(Ref<VoxelBuffer> voxels) {
|
||||
|
||||
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]);
|
||||
output.primitive_type = Mesh::PRIMITIVE_TRIANGLES;
|
||||
} else {
|
||||
mesh->add_surface_from_arrays(Mesh::PRIMITIVE_LINES, surfaces[i]);
|
||||
output.primitive_type = Mesh::PRIMITIVE_LINES;
|
||||
}
|
||||
}
|
||||
|
||||
return mesh;
|
||||
int VoxelMesherDMC::get_minimum_padding() const {
|
||||
return MINIMUM_PADDING;
|
||||
}
|
||||
|
||||
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("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);
|
||||
|
||||
BIND_ENUM_CONSTANT(MESH_NORMAL);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef VOXEL_MESHER_DMC_H
|
||||
#define VOXEL_MESHER_DMC_H
|
||||
|
||||
#include "../../voxel_buffer.h"
|
||||
#include "../voxel_mesher.h"
|
||||
#include "hermite_value.h"
|
||||
#include "mesh_builder.h"
|
||||
#include "object_pool.h"
|
||||
@ -64,9 +64,11 @@ struct DualGrid {
|
||||
|
||||
} // namespace dmc
|
||||
|
||||
class VoxelMesherDMC : public Reference {
|
||||
GDCLASS(VoxelMesherDMC, Reference)
|
||||
class VoxelMesherDMC : public VoxelMesher {
|
||||
GDCLASS(VoxelMesherDMC, VoxelMesher)
|
||||
public:
|
||||
static const int MINIMUM_PADDING = 2;
|
||||
|
||||
enum MeshMode {
|
||||
MESH_NORMAL,
|
||||
MESH_WIREFRAME,
|
||||
@ -91,8 +93,8 @@ public:
|
||||
void set_geometric_error(real_t geometric_error);
|
||||
float get_geometric_error() const;
|
||||
|
||||
Array build(const VoxelBuffer &voxels);
|
||||
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> voxels);
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
|
||||
int get_minimum_padding() const override;
|
||||
|
||||
Dictionary get_stats() const;
|
||||
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include "transvoxel_tables.cpp"
|
||||
#include <core/os/os.h>
|
||||
|
||||
namespace {
|
||||
|
||||
inline float tof(int8_t v) {
|
||||
return static_cast<float>(v) / 256.f;
|
||||
}
|
||||
@ -58,6 +60,8 @@ void copy_to(PoolVector<T> &to, Vector<T> &from) {
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
VoxelMesherTransvoxel::ReuseCell::ReuseCell() {
|
||||
case_index = 0;
|
||||
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;
|
||||
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());
|
||||
int channel = VoxelBuffer::CHANNEL_ISOLEVEL;
|
||||
|
||||
// Initialize dynamic memory:
|
||||
// These vectors are re-used.
|
||||
@ -109,7 +96,7 @@ Array VoxelMesherTransvoxel::build(const VoxelBuffer &voxels, unsigned int chann
|
||||
|
||||
if (m_output_vertices.size() == 0) {
|
||||
// The mesh can be empty
|
||||
return Array();
|
||||
return;
|
||||
}
|
||||
|
||||
PoolVector<Vector3> vertices;
|
||||
@ -128,10 +115,8 @@ Array VoxelMesherTransvoxel::build(const VoxelBuffer &voxels, unsigned int chann
|
||||
}
|
||||
arrays[Mesh::ARRAY_INDEX] = indices;
|
||||
|
||||
Array surfaces;
|
||||
surfaces.append(arrays);
|
||||
|
||||
return surfaces;
|
||||
output.surfaces.push_back(arrays);
|
||||
output.primitive_type = Mesh::PRIMITIVE_TRIANGLES;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
||||
ClassDB::bind_method(D_METHOD("build", "voxels", "channel", "existing_mesh"), &VoxelMesherTransvoxel::build_mesh, DEFVAL(Variant()));
|
||||
}
|
||||
|
@ -1,17 +1,17 @@
|
||||
#ifndef VOXEL_MESHER_SMOOTH_H
|
||||
#define VOXEL_MESHER_SMOOTH_H
|
||||
|
||||
#include "../../voxel_buffer.h"
|
||||
#include "../voxel_mesher.h"
|
||||
#include <scene/resources/mesh.h>
|
||||
|
||||
class VoxelMesherTransvoxel : public Reference {
|
||||
GDCLASS(VoxelMesherTransvoxel, Reference)
|
||||
class VoxelMesherTransvoxel : public VoxelMesher {
|
||||
GDCLASS(VoxelMesherTransvoxel, VoxelMesher)
|
||||
|
||||
public:
|
||||
VoxelMesherTransvoxel();
|
||||
static const int MINIMUM_PADDING = 2;
|
||||
|
||||
Ref<ArrayMesh> build_mesh(Ref<VoxelBuffer> voxels_ref, unsigned int channel, Ref<ArrayMesh> mesh = Ref<ArrayMesh>());
|
||||
Array build(const VoxelBuffer &voxels, unsigned int channel);
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels, int padding) override;
|
||||
int get_minimum_padding() const override;
|
||||
|
||||
protected:
|
||||
static void _bind_methods();
|
||||
|
36
meshers/voxel_mesher.cpp
Normal file
36
meshers/voxel_mesher.cpp
Normal 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
24
meshers/voxel_mesher.h
Normal 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
|
@ -34,6 +34,7 @@ void register_voxel_types() {
|
||||
ClassDB::register_class<VoxelIsoSurfaceTool>();
|
||||
|
||||
// Meshers
|
||||
ClassDB::register_class<VoxelMesher>();
|
||||
ClassDB::register_class<VoxelMesherBlocky>();
|
||||
ClassDB::register_class<VoxelMesherTransvoxel>();
|
||||
ClassDB::register_class<VoxelMesherDMC>();
|
||||
|
@ -107,6 +107,17 @@ void VoxelMeshUpdater::pop(Output &output) {
|
||||
_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) {
|
||||
VoxelMeshUpdater *self = reinterpret_cast<VoxelMeshUpdater *>(p_self);
|
||||
self->thread_func();
|
||||
@ -181,17 +192,12 @@ void VoxelMeshUpdater::process_block(const InputBlock &block, OutputBlock &outpu
|
||||
|
||||
CRASH_COND(block.voxels.is_null());
|
||||
|
||||
int padding = 1;
|
||||
if (_dmc_mesher.is_valid()) {
|
||||
padding = 2;
|
||||
}
|
||||
int padding = get_required_padding();
|
||||
|
||||
// Build cubic parts of the mesh
|
||||
output.model_surfaces = _blocky_mesher->build(**block.voxels, Voxel::CHANNEL_TYPE, padding);
|
||||
_blocky_mesher->build(output.blocky_surfaces, **block.voxels, padding);
|
||||
|
||||
if (_dmc_mesher.is_valid()) {
|
||||
// Build smooth parts of the mesh
|
||||
output.smooth_surfaces = _dmc_mesher->build(**block.voxels);
|
||||
_dmc_mesher->build(output.smooth_surfaces, **block.voxels, padding);
|
||||
}
|
||||
|
||||
output.position = block.position;
|
||||
|
@ -26,8 +26,8 @@ public:
|
||||
};
|
||||
|
||||
struct OutputBlock {
|
||||
Array model_surfaces;
|
||||
Array smooth_surfaces;
|
||||
VoxelMesher::Output blocky_surfaces;
|
||||
VoxelMesher::Output smooth_surfaces;
|
||||
Vector3i position;
|
||||
};
|
||||
|
||||
@ -66,6 +66,8 @@ public:
|
||||
void push(const Input &input);
|
||||
void pop(Output &output);
|
||||
|
||||
int get_required_padding() const;
|
||||
|
||||
private:
|
||||
static void _thread_func(void *p_self);
|
||||
void thread_func();
|
||||
|
@ -286,15 +286,6 @@ void VoxelTerrain::reset_updater() {
|
||||
_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) {
|
||||
return x == 0 ? 0 : x != max ? 1 : 2;
|
||||
}
|
||||
@ -757,7 +748,7 @@ void VoxelTerrain::_process() {
|
||||
|
||||
// TODO Make the buffer re-usable
|
||||
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);
|
||||
|
||||
unsigned int channels_mask = (1 << VoxelBuffer::CHANNEL_TYPE) | (1 << VoxelBuffer::CHANNEL_ISOLEVEL);
|
||||
@ -820,30 +811,30 @@ void VoxelTerrain::_process() {
|
||||
mesh.instance();
|
||||
|
||||
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()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
++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()) {
|
||||
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(ob.smooth_surfaces.primitive_type, surface);
|
||||
mesh->surface_set_material(surface_index, _materials[i]);
|
||||
// No material supported yet
|
||||
++surface_index;
|
||||
|
@ -98,7 +98,6 @@ private:
|
||||
|
||||
void make_all_view_dirty_deferred();
|
||||
void reset_updater();
|
||||
int get_block_padding() const;
|
||||
|
||||
Spatial *get_viewer(NodePath path) const;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user