Fix dependency in utility.h, move MeshBuilder to its own file, re-use vertex arrays

This commit is contained in:
Marc Gilleron 2019-04-21 01:14:28 +01:00
parent 35e03f7e77
commit 9bb81f9bb7
5 changed files with 121 additions and 92 deletions

63
dmc/mesh_builder.cpp Normal file
View File

@ -0,0 +1,63 @@
#include "mesh_builder.h"
namespace dmc {
Ref<ArrayMesh> MeshBuilder::commit(bool wireframe) {
if (_positions.size() == 0) {
return Ref<ArrayMesh>();
}
ERR_FAIL_COND_V(_indices.size() % 3 != 0, Ref<ArrayMesh>());
if (wireframe) {
// Debug purpose, no effort to be fast here
std::vector<int> wireframe_indices;
for (int i = 0; i < _indices.size(); i += 3) {
wireframe_indices.push_back(_indices[i]);
wireframe_indices.push_back(_indices[i + 1]);
wireframe_indices.push_back(_indices[i + 1]);
wireframe_indices.push_back(_indices[i + 2]);
wireframe_indices.push_back(_indices[i + 2]);
wireframe_indices.push_back(_indices[i]);
}
_indices = wireframe_indices;
}
PoolVector3Array positions;
PoolVector3Array normals;
PoolIntArray indices;
raw_copy_to(positions, _positions);
raw_copy_to(normals, _normals);
raw_copy_to(indices, _indices);
clear();
Array surface;
surface.resize(Mesh::ARRAY_MAX);
surface[Mesh::ARRAY_VERTEX] = positions;
surface[Mesh::ARRAY_NORMAL] = normals;
surface[Mesh::ARRAY_INDEX] = indices;
Ref<ArrayMesh> mesh;
mesh.instance();
mesh->add_surface_from_arrays(wireframe ? Mesh::PRIMITIVE_LINES : Mesh::PRIMITIVE_TRIANGLES, surface);
return mesh;
}
void MeshBuilder::clear() {
_positions.clear();
_normals.clear();
_indices.clear();
_position_to_index.clear();
}
} // namespace dmc

46
dmc/mesh_builder.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef MESH_BUILDER_H
#define MESH_BUILDER_H
#include "../utility.h"
#include <scene/resources/mesh.h>
#include <map>
#include <vector>
namespace dmc {
// Faster than SurfaceTool, only does what is needed
class MeshBuilder {
public:
inline void add_vertex(Vector3 position, Vector3 normal) {
int i = 0;
if (_position_to_index.find(position) != _position_to_index.end()) {
i = _position_to_index[position];
} else {
i = _positions.size();
_position_to_index[position] = i;
_positions.push_back(position);
_normals.push_back(normal);
}
_indices.push_back(i);
}
Ref<ArrayMesh> commit(bool wireframe);
void clear();
private:
std::vector<Vector3> _positions;
std::vector<Vector3> _normals;
std::vector<int> _indices;
std::map<Vector3, int> _position_to_index;
};
} // namespace dmc
#endif // MESH_BUILDER_H

View File

@ -1,9 +1,7 @@
#include "voxel_mesher_dmc.h" #include "voxel_mesher_dmc.h"
#include "../cube_tables.h" #include "../cube_tables.h"
#include "../utility.h"
#include "marching_cubes_tables.h" #include "marching_cubes_tables.h"
#include <map> #include "mesh_builder.h"
#include <vector>
// Algorithm taken from https://www.volume-gfx.com/volume-rendering/dual-marching-cubes/ // Algorithm taken from https://www.volume-gfx.com/volume-rendering/dual-marching-cubes/
@ -1118,87 +1116,7 @@ void node_proc(DualGrid &grid, OctreeNode *node) {
vert_proc(grid, children[0], children[1], children[2], children[3], children[4], children[5], children[6], children[7]); vert_proc(grid, children[0], children[1], children[2], children[3], children[4], children[5], children[6], children[7]);
} }
class MeshBuilder { Ref<ArrayMesh> polygonize_dual_grid(const DualGrid &grid, const VoxelBuffer &voxels, bool wireframe, MeshBuilder &mesh_builder) {
public:
void add_vertex(Vector3 position, Vector3 normal) {
int i = 0;
if (_position_to_index.find(position) != _position_to_index.end()) {
i = _position_to_index[position];
} else {
i = _positions.size();
_position_to_index[position] = i;
_positions.push_back(position);
_normals.push_back(normal);
}
_indices.push_back(i);
}
Ref<ArrayMesh> commit(bool wireframe) {
if (_positions.size() == 0) {
return Ref<ArrayMesh>();
}
ERR_FAIL_COND_V(_indices.size() % 3 != 0, Ref<ArrayMesh>());
if (wireframe) {
// Debug purpose, no effort to be fast here
std::vector<int> wireframe_indices;
for (int i = 0; i < _indices.size(); i += 3) {
wireframe_indices.push_back(_indices[i]);
wireframe_indices.push_back(_indices[i + 1]);
wireframe_indices.push_back(_indices[i + 1]);
wireframe_indices.push_back(_indices[i + 2]);
wireframe_indices.push_back(_indices[i + 2]);
wireframe_indices.push_back(_indices[i]);
}
_indices = wireframe_indices;
}
PoolVector3Array positions;
PoolVector3Array normals;
PoolIntArray indices;
raw_copy_to(positions, _positions);
raw_copy_to(normals, _normals);
raw_copy_to(indices, _indices);
Array surface;
surface.resize(Mesh::ARRAY_MAX);
surface[Mesh::ARRAY_VERTEX] = positions;
surface[Mesh::ARRAY_NORMAL] = normals;
surface[Mesh::ARRAY_INDEX] = indices;
Ref<ArrayMesh> mesh;
mesh.instance();
mesh->add_surface_from_arrays(wireframe ? Mesh::PRIMITIVE_LINES : Mesh::PRIMITIVE_TRIANGLES, surface);
return mesh;
}
private:
std::vector<Vector3> _positions;
std::vector<Vector3> _normals;
std::vector<int> _indices;
std::map<Vector3, int> _position_to_index;
};
Ref<ArrayMesh> polygonize_dual_grid(const DualGrid &grid, const VoxelBuffer &voxels, bool wireframe) {
MeshBuilder mesh_builder;
for (int dci = 0; dci < grid.cells.size(); ++dci) { for (int dci = 0; dci < grid.cells.size(); ++dci) {
@ -1287,7 +1205,7 @@ Ref<ArrayMesh> polygonize_dual_grid(const DualGrid &grid, const VoxelBuffer &vox
return mesh_builder.commit(wireframe); return mesh_builder.commit(wireframe);
} }
Ref<ArrayMesh> polygonize(const VoxelBuffer &voxels, float geometric_error, VoxelMesherDMC::Mode mode) { Ref<ArrayMesh> polygonize(const VoxelBuffer &voxels, float geometric_error, VoxelMesherDMC::Mode mode, MeshBuilder &mesh_builder) {
int padding = 1; int padding = 1;
int chunk_size = CHUNK_SIZE; int chunk_size = CHUNK_SIZE;
@ -1313,15 +1231,17 @@ Ref<ArrayMesh> polygonize(const VoxelBuffer &voxels, float geometric_error, Voxe
return generate_debug_dual_grid_mesh(grid); return generate_debug_dual_grid_mesh(grid);
} }
return polygonize_dual_grid(grid, voxels, mode == VoxelMesherDMC::MODE_WIREFRAME); Ref<ArrayMesh> mesh = polygonize_dual_grid(grid, voxels, mode == VoxelMesherDMC::MODE_WIREFRAME, mesh_builder);
// TODO Marching squares skirts // TODO Marching squares skirts
return mesh;
} }
} // namespace dmc } // namespace dmc
Ref<ArrayMesh> VoxelMesherDMC::build_mesh(Ref<VoxelBuffer> voxels, real_t geometric_error, Mode mode) { Ref<ArrayMesh> VoxelMesherDMC::build_mesh(Ref<VoxelBuffer> voxels, real_t geometric_error, Mode mode) {
ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>()); ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>());
return dmc::polygonize(**voxels, geometric_error, mode); return dmc::polygonize(**voxels, geometric_error, mode, _mesh_builder);
} }
void VoxelMesherDMC::_bind_methods() { void VoxelMesherDMC::_bind_methods() {

View File

@ -2,13 +2,9 @@
#define VOXEL_MESHER_DMC_H #define VOXEL_MESHER_DMC_H
#include "../voxel_buffer.h" #include "../voxel_buffer.h"
#include "mesh_builder.h"
#include "scene/resources/mesh.h" #include "scene/resources/mesh.h"
namespace dmc {
Ref<ArrayMesh> polygonize(const VoxelBuffer &voxels, float geometric_error);
}
class VoxelMesherDMC : public Reference { class VoxelMesherDMC : public Reference {
GDCLASS(VoxelMesherDMC, Reference) GDCLASS(VoxelMesherDMC, Reference)
public: public:
@ -23,6 +19,9 @@ public:
protected: protected:
static void _bind_methods(); static void _bind_methods();
private:
dmc::MeshBuilder _mesh_builder;
}; };
VARIANT_ENUM_CAST(VoxelMesherDMC::Mode) VARIANT_ENUM_CAST(VoxelMesherDMC::Mode)

View File

@ -2,6 +2,7 @@
#define HEADER_VOXEL_UTILITY_H #define HEADER_VOXEL_UTILITY_H
#include "vector3i.h" #include "vector3i.h"
#include <core/pool_vector.h>
#include <core/ustring.h> #include <core/ustring.h>
#include <core/vector.h> #include <core/vector.h>
#include <vector> #include <vector>