diff --git a/cube_tables.cpp b/cube_tables.cpp new file mode 100644 index 0000000..2e2484e --- /dev/null +++ b/cube_tables.cpp @@ -0,0 +1,141 @@ +#include "cube_tables.h" + +namespace CubeTables { + +// The following tables respect the following conventions +// +// 7-------6 +// /| /| +// / | / | Corners +// 4-------5 | +// | 3----|--2 +// | / | / y z +// |/ |/ |/ +// 0-------1 o--x +// +// +// o---10----o +// /| /| +// 11 7 9 6 Edges +// / | / | +// o----8----o | +// | o---2-|---o +// 4 / 5 / +// | 3 | 1 +// |/ |/ +// o----0----o +// +// Sides are ordered according to the Voxel::Side enum. +// + +//static const unsigned int CORNER_COUNT = 8; +//static const unsigned int EDGE_COUNT = 12; + +// Order doesn't technically matter here, they are for reading convenience. +// If you need a special ordering, combine index with other tables +const Vector3 g_corner_position[CORNER_COUNT] = { + Vector3(0, 0, 0), + Vector3(1, 0, 0), + Vector3(1, 0, 1), + Vector3(0, 0, 1), + Vector3(0, 1, 0), + Vector3(1, 1, 0), + Vector3(1, 1, 1), + Vector3(0, 1, 1) +}; + +const int g_side_quad_triangles[Voxel::SIDE_COUNT][6] = { + // LEFT + { 0, 1, 2, 0, 2, 3 }, + // RIGHT + { 0, 1, 2, 0, 2, 3 }, + // BOTTOM + { 0, 1, 2, 0, 2, 3 }, + // TOP + { 0, 1, 2, 0, 2, 3 }, + // BACK + { 0, 1, 2, 0, 2, 3 }, + // FRONT + { 0, 1, 2, 0, 2, 3 }, +}; + +const unsigned int g_side_coord[Voxel::SIDE_COUNT] = { 0, 0, 1, 1, 2, 2 }; +const unsigned int g_side_sign[Voxel::SIDE_COUNT] = { 0, 1, 0, 1, 0, 1 }; + +const Vector3i g_side_normals[Voxel::SIDE_COUNT] = { + Vector3i(-1, 0, 0), + Vector3i(1, 0, 0), + Vector3i(0, -1, 0), + Vector3i(0, 1, 0), + Vector3i(0, 0, -1), + Vector3i(0, 0, 1), +}; + +// Corners have same winding, relative to the face's normal +const unsigned int g_side_corners[Voxel::SIDE_COUNT][4] = { + { 3, 0, 4, 7 }, + { 1, 2, 6, 5 }, + { 1, 0, 3, 2 }, + { 4, 5, 6, 7 }, + { 0, 1, 5, 4 }, + { 2, 3, 7, 6 } +}; + +const unsigned int g_side_edges[Voxel::SIDE_COUNT][4] = { + { 3, 7, 11, 4 }, + { 1, 6, 9, 5 }, + { 0, 1, 2, 3 }, + { 8, 9, 10, 11 }, + { 0, 5, 8, 4 }, + { 2, 6, 10, 7 } +}; + +// 3---2 +// | / | {0,1,2,0,2,3} +// 0---1 +//static const unsigned int g_vertex_to_corner[Voxel::SIDE_COUNT][6] = { +// { 0, 3, 7, 0, 7, 4 }, +// { 2, 1, 5, 2, 5, 6 }, +// { 0, 1, 2, 0, 2, 3 }, +// { 7, 6, 5, 7, 5, 4 }, +// { 1, 0, 4 ,1, 4, 5 }, +// { 3, 2, 6, 3, 6, 7 } +//}; + +const Vector3i g_corner_inormals[CORNER_COUNT] = { + Vector3i(-1, -1, -1), + Vector3i(1, -1, -1), + Vector3i(1, -1, 1), + Vector3i(-1, -1, 1), + + Vector3i(-1, 1, -1), + Vector3i(1, 1, -1), + Vector3i(1, 1, 1), + Vector3i(-1, 1, 1) +}; + +const Vector3i g_edge_inormals[EDGE_COUNT] = { + Vector3i(0, -1, -1), + Vector3i(1, -1, 0), + Vector3i(0, -1, 1), + Vector3i(-1, -1, 0), + + Vector3i(-1, 0, -1), + Vector3i(1, 0, -1), + Vector3i(1, 0, 1), + Vector3i(-1, 0, 1), + + Vector3i(0, 1, -1), + Vector3i(1, 1, 0), + Vector3i(0, 1, 1), + Vector3i(-1, 1, 0) +}; + +const unsigned int g_edge_corners[EDGE_COUNT][2] = { + { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, + { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, + { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 } +}; + +} // namespace CubeTables + diff --git a/cube_tables.h b/cube_tables.h new file mode 100644 index 0000000..88285b7 --- /dev/null +++ b/cube_tables.h @@ -0,0 +1,34 @@ +#ifndef CUBE_TABLES_H +#define CUBE_TABLES_H + +#include +#include "vector3i.h" +#include "voxel.h" + +namespace CubeTables { + +const unsigned int CORNER_COUNT = 8; +const unsigned int EDGE_COUNT = 12; + +extern const Vector3 g_corner_position[CORNER_COUNT]; + +extern const int g_side_quad_triangles[Voxel::SIDE_COUNT][6]; + +extern const unsigned int g_side_coord[Voxel::SIDE_COUNT]; +extern const unsigned int g_side_sign[Voxel::SIDE_COUNT]; + +extern const Vector3i g_side_normals[Voxel::SIDE_COUNT]; + +extern const unsigned int g_side_corners[Voxel::SIDE_COUNT][4]; +extern const unsigned int g_side_edges[Voxel::SIDE_COUNT][4]; + +extern const Vector3i g_corner_inormals[CORNER_COUNT]; + +extern const Vector3i g_edge_inormals[EDGE_COUNT]; + +extern const unsigned int g_edge_corners[EDGE_COUNT][2]; + +} // namespace CubeTables + + +#endif // CUBE_TABLES_H diff --git a/voxel.cpp b/voxel.cpp index 45aff1d..1c8a245 100644 --- a/voxel.cpp +++ b/voxel.cpp @@ -1,6 +1,7 @@ #include "voxel.h" #include "voxel_library.h" #include "voxel_mesher.h" +#include "cube_tables.h" #define STRLEN(x) (sizeof(x) / sizeof(x[0])) @@ -128,13 +129,17 @@ void Voxel::set_geometry_type(GeometryType type) { case GEOMETRY_NONE: { // Clear all geometry - _model_vertices.resize(0); + _model_positions.resize(0); _model_normals.resize(0); - _model_uv.resize(0); + _model_uvs.resize(0); + _model_indices.resize(0); + for (int side = 0; side < SIDE_COUNT; ++side) { - _model_side_vertices[side].resize(0); - _model_side_uv[side].resize(0); + _model_side_positions[side].resize(0); + _model_side_uvs[side].resize(0); + _model_side_indices[side].resize(0); } + } break; case GEOMETRY_CUBE: @@ -167,56 +172,27 @@ VoxelLibrary *Voxel::get_library() const { Ref Voxel::set_cube_geometry(float sy) { sy = 1.0 + sy; - const Vector3 vertices[SIDE_COUNT][6] = { - { // LEFT - Vector3(0, 0, 0), - Vector3(0, sy, 0), - Vector3(0, sy, 1), - Vector3(0, 0, 0), - Vector3(0, sy, 1), - Vector3(0, 0, 1) }, - { // RIGHT - Vector3(1, 0, 0), - Vector3(1, sy, 1), - Vector3(1, sy, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(1, sy, 1) }, - { // BOTTOM - Vector3(0, 0, 0), - Vector3(1, 0, 1), - Vector3(1, 0, 0), - Vector3(0, 0, 0), - Vector3(0, 0, 1), - Vector3(1, 0, 1) }, - { // TOP - Vector3(0, sy, 0), - Vector3(1, sy, 0), - Vector3(1, sy, 1), - Vector3(0, sy, 0), - Vector3(1, sy, 1), - Vector3(0, sy, 1) }, - { // BACK - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, sy, 0), - Vector3(0, 0, 0), - Vector3(1, sy, 0), - Vector3(0, sy, 0) }, - { // FRONT - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(1, sy, 1), - Vector3(0, 0, 1), - Vector3(0, sy, 1), - Vector3(1, sy, 1) } - }; for (unsigned int side = 0; side < SIDE_COUNT; ++side) { - _model_side_vertices[side].resize(6); - PoolVector::Write w = _model_side_vertices[side].write(); - for (unsigned int i = 0; i < 6; ++i) { - w[i] = vertices[side][i]; + + { + _model_side_positions[side].resize(4); + PoolVector::Write w = _model_side_positions[side].write(); + for (unsigned int i = 0; i < 4; ++i) { + int corner = CubeTables::g_side_corners[side][i]; + Vector3 p = CubeTables::g_corner_position[corner]; + if(p.y > 0.9) + p.y = sy; + w[i] = p; + } + } + + { + _model_side_indices[side].resize(6); + PoolVector::Write w = _model_side_indices[side].write(); + for (unsigned int i = 0; i < 6; ++i) { + w[i] = CubeTables::g_side_quad_triangles[side][i]; + } } } @@ -242,34 +218,17 @@ void Voxel::update_cube_uv_sides() { const Vector2 uv[4] = { Vector2(e, e), Vector2(1.f - e, e), - Vector2(e, 1.f - e), Vector2(1.f - e, 1.f - e), - }; - - // TODO The only reason why there are 6 entries per array is because SurfaceTool is used to access them. - // in the near future, there should be only 4, to account for one quad! - const int uv6[SIDE_COUNT][6] = { - // LEFT - { 2, 0, 1, 2, 1, 3 }, - // RIGHT - { 2, 1, 0, 2, 3, 1 }, - // BOTTOM - { 0, 3, 1, 0, 2, 3 }, - // TOP - { 0, 1, 3, 0, 3, 2 }, - // BACK - { 2, 3, 1, 2, 1, 0 }, - // FRONT - { 3, 2, 1, 2, 0, 1 } + Vector2(e, 1.f - e), }; float s = 1.0 / (float)library->get_atlas_size(); for (unsigned int side = 0; side < SIDE_COUNT; ++side) { - _model_side_uv[side].resize(6); - PoolVector::Write w = _model_side_uv[side].write(); - for (unsigned int i = 0; i < 6; ++i) { - w[i] = (_cube_tiles[side] + uv[uv6[side][i]]) * s; + _model_side_uvs[side].resize(4); + PoolVector::Write w = _model_side_uvs[side].write(); + for (unsigned int i = 0; i < 4; ++i) { + w[i] = (_cube_tiles[side] + uv[i]) * s; } } } diff --git a/voxel.h b/voxel.h index 157677e..99151ac 100644 --- a/voxel.h +++ b/voxel.h @@ -65,11 +65,14 @@ public: // Getters for native usage only - const PoolVector &get_model_vertices() const { return _model_vertices; } + const PoolVector &get_model_positions() const { return _model_positions; } const PoolVector &get_model_normals() const { return _model_normals; } - const PoolVector &get_model_uv() const { return _model_uv; } - const PoolVector &get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; } - const PoolVector &get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; } + const PoolVector &get_model_uv() const { return _model_uvs; } + const PoolVector &get_model_indices() const { return _model_indices; } + + const PoolVector &get_model_side_positions(unsigned int side) const { return _model_side_positions[side]; } + const PoolVector &get_model_side_uv(unsigned int side) const { return _model_side_uvs[side]; } + const PoolVector &get_model_side_indices(unsigned int side) const { return _model_side_indices[side]; } void set_library(Ref lib); @@ -104,13 +107,18 @@ private: Vector2 _cube_tiles[SIDE_COUNT]; // Model - PoolVector _model_vertices; + PoolVector _model_positions; PoolVector _model_normals; - PoolVector _model_uv; - PoolVector _model_side_vertices[SIDE_COUNT]; - PoolVector _model_side_uv[SIDE_COUNT]; + PoolVector _model_uvs; + PoolVector _model_indices; + // Model sides: + // They are separated because this way we can occlude them easily. + // Due to these defining cube side triangles, normals are known already. + PoolVector _model_side_positions[SIDE_COUNT]; + PoolVector _model_side_uvs[SIDE_COUNT]; + PoolVector _model_side_indices[SIDE_COUNT]; - // TODO Child voxel types + // TODO Child voxel types? }; VARIANT_ENUM_CAST(Voxel::ChannelMode) diff --git a/voxel_buffer.h b/voxel_buffer.h index 7b98e94..e0b76c4 100644 --- a/voxel_buffer.h +++ b/voxel_buffer.h @@ -45,8 +45,10 @@ public: int get_voxel(int x, int y, int z, unsigned int channel_index = 0) const; void set_voxel(int value, int x, int y, int z, unsigned int channel_index = 0); void set_voxel_v(int value, Vector3 pos, unsigned int channel_index = 0); + _FORCE_INLINE_ void set_voxel_iso(real_t value, int x, int y, int z, unsigned int channel_index = 0) { set_voxel(iso_to_byte(value), x, y, z, channel_index); } _FORCE_INLINE_ real_t get_voxel_iso(int x, int y, int z, unsigned int channel_index = 0) const { return byte_to_iso(get_voxel(x, y, z, channel_index)); } + _FORCE_INLINE_ int get_voxel(const Vector3i pos, unsigned int channel_index = 0) const { return get_voxel(pos.x, pos.y, pos.z, channel_index); } _FORCE_INLINE_ void set_voxel(int value, const Vector3i pos, unsigned int channel_index = 0) { set_voxel(value, pos.x, pos.y, pos.z, channel_index); } diff --git a/voxel_mesher.cpp b/voxel_mesher.cpp index 50ed99c..ceb1013 100644 --- a/voxel_mesher.cpp +++ b/voxel_mesher.cpp @@ -1,122 +1,20 @@ #include "voxel_mesher.h" #include "voxel_library.h" +#include "cube_tables.h" -// The following tables respect the following conventions -// -// 7-------6 -// /| /| -// / | / | Corners -// 4-------5 | -// | 3----|--2 -// | / | / y z -// |/ |/ |/ -// 0-------1 o--x -// -// -// o---10----o -// /| /| -// 11 7 9 6 Edges -// / | / | -// o----8----o | -// | o---2-|---o -// 4 / 5 / -// | 3 | 1 -// |/ |/ -// o----0----o -// -// Sides are ordered according to the Voxel::Side enum. -// -static const unsigned int CORNER_COUNT = 8; -static const unsigned int EDGE_COUNT = 12; +template +void copy_to(PoolVector &to, const Vector &from) { -static const Vector3 g_corner_position[CORNER_COUNT] = { - Vector3(0, 0, 0), - Vector3(1, 0, 0), - Vector3(1, 0, 1), - Vector3(0, 0, 1), - Vector3(0, 1, 0), - Vector3(1, 1, 0), - Vector3(1, 1, 1), - Vector3(0, 1, 1) -}; + to.resize(from.size()); -static const unsigned int g_side_coord[Voxel::SIDE_COUNT] = { 0, 0, 1, 1, 2, 2 }; -static const unsigned int g_side_sign[Voxel::SIDE_COUNT] = { 0, 1, 0, 1, 0, 1 }; + typename PoolVector::Write w = to.write(); -static const Vector3i g_side_normals[Voxel::SIDE_COUNT] = { - Vector3i(-1, 0, 0), - Vector3i(1, 0, 0), - Vector3i(0, -1, 0), - Vector3i(0, 1, 0), - Vector3i(0, 0, -1), - Vector3i(0, 0, 1), -}; + for (unsigned int i = 0; i < from.size(); ++i) { + w[i] = from[i]; + } +} -static const unsigned int g_side_corners[Voxel::SIDE_COUNT][4] = { - { 0, 3, 7, 4 }, - { 1, 2, 6, 5 }, - { 0, 1, 2, 3 }, - { 4, 5, 6, 7 }, - { 0, 1, 5, 4 }, - { 3, 2, 6, 7 } -}; - -static const unsigned int g_side_edges[Voxel::SIDE_COUNT][4] = { - { 3, 7, 11, 4 }, - { 1, 6, 9, 5 }, - { 0, 1, 2, 3 }, - { 8, 9, 10, 11 }, - { 0, 5, 8, 4 }, - { 2, 6, 10, 7 } -}; - -// 3---2 -// | / | {0,1,2,0,2,3} -// 0---1 -//static const unsigned int g_vertex_to_corner[Voxel::SIDE_COUNT][6] = { -// { 0, 3, 7, 0, 7, 4 }, -// { 2, 1, 5, 2, 5, 6 }, -// { 0, 1, 2, 0, 2, 3 }, -// { 7, 6, 5, 7, 5, 4 }, -// { 1, 0, 4 ,1, 4, 5 }, -// { 3, 2, 6, 3, 6, 7 } -//}; - -static const Vector3i g_corner_inormals[CORNER_COUNT] = { - Vector3i(-1, -1, -1), - Vector3i(1, -1, -1), - Vector3i(1, -1, 1), - Vector3i(-1, -1, 1), - - Vector3i(-1, 1, -1), - Vector3i(1, 1, -1), - Vector3i(1, 1, 1), - Vector3i(-1, 1, 1) -}; - -static const Vector3i g_edge_inormals[EDGE_COUNT] = { - Vector3i(0, -1, -1), - Vector3i(1, -1, 0), - Vector3i(0, -1, 1), - Vector3i(-1, -1, 0), - - Vector3i(-1, 0, -1), - Vector3i(1, 0, -1), - Vector3i(1, 0, 1), - Vector3i(-1, 0, 1), - - Vector3i(0, 1, -1), - Vector3i(1, 1, 0), - Vector3i(0, 1, 1), - Vector3i(-1, 1, 0) -}; - -static const unsigned int g_edge_corners[EDGE_COUNT][2] = { - { 0, 1 }, { 1, 2 }, { 2, 3 }, { 3, 0 }, - { 0, 4 }, { 1, 5 }, { 2, 6 }, { 3, 7 }, - { 4, 5 }, { 5, 6 }, { 6, 7 }, { 7, 4 } -}; VoxelMesher::VoxelMesher() : _baked_occlusion_darkness(0.75), @@ -182,8 +80,12 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe const VoxelLibrary &library = **_library; for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { - _surface_tool[i].begin(Mesh::PRIMITIVE_TRIANGLES); - _surface_tool[i].set_material(_materials[i]); + Arrays &a = _arrays[i]; + a.positions.clear(); + a.normals.clear(); + a.uvs.clear(); + a.colors.clear(); + a.indices.clear(); } float baked_occlusion_darkness; @@ -206,19 +108,23 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe min.clamp_to(pad, max); max.clamp_to(min, buffer.get_size() - pad); + int index_offset = 0; + // Iterate 3D padded data to extract voxel faces. // This is the most intensive job in this class, so all required data should be as fit as possible. for (unsigned int z = min.z; z < max.z; ++z) { for (unsigned int x = min.x; x < max.x; ++x) { for (unsigned int y = min.y; y < max.y; ++y) { + // TODO In this intensive routine, there is a way to make voxel access fastest by getting a pointer to the channel, + // and using offset lookup to get neighbors rather than going through get_voxel validations int voxel_id = buffer.get_voxel(x, y, z, 0); if (voxel_id != 0 && library.has_voxel(voxel_id)) { const Voxel &voxel = library.get_voxel_const(voxel_id); - SurfaceTool &st = _surface_tool[voxel.get_material_id()]; + Arrays &arrays = _arrays[voxel.get_material_id()]; // Hybrid approach: extract cube faces and decimate those that aren't visible, // and still allow voxels to have geometry that is not a cube @@ -226,10 +132,12 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe // Sides for (unsigned int side = 0; side < Voxel::SIDE_COUNT; ++side) { - const PoolVector &vertices = voxel.get_model_side_vertices(side); - if (vertices.size() != 0) { + const PoolVector &positions = voxel.get_model_side_positions(side); + int vertex_count = positions.size(); - Vector3i normal = g_side_normals[side]; + if (vertex_count != 0) { + + Vector3i normal = CubeTables::g_side_normals[side]; unsigned nx = x + normal.x; unsigned ny = y + normal.y; unsigned nz = z + normal.z; @@ -247,22 +155,22 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe // Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/ for (unsigned int j = 0; j < 4; ++j) { - unsigned int edge = g_side_edges[side][j]; - Vector3i edge_normal = g_edge_inormals[edge]; + unsigned int edge = CubeTables::g_side_edges[side][j]; + Vector3i edge_normal = CubeTables::g_edge_inormals[edge]; unsigned ex = x + edge_normal.x; unsigned ey = y + edge_normal.y; unsigned ez = z + edge_normal.z; if (!is_transparent(library, buffer.get_voxel(ex, ey, ez))) { - shaded_corner[g_edge_corners[edge][0]] += 1; - shaded_corner[g_edge_corners[edge][1]] += 1; + shaded_corner[CubeTables::g_edge_corners[edge][0]] += 1; + shaded_corner[CubeTables::g_edge_corners[edge][1]] += 1; } } for (unsigned int j = 0; j < 4; ++j) { - unsigned int corner = g_side_corners[side][j]; + unsigned int corner = CubeTables::g_side_corners[side][j]; if (shaded_corner[corner] == 2) { shaded_corner[corner] = 3; } else { - Vector3i corner_normal = g_corner_inormals[corner]; + Vector3i corner_normal = CubeTables::g_corner_inormals[corner]; unsigned int cx = x + corner_normal.x; unsigned int cy = y + corner_normal.y; unsigned int cz = z + corner_normal.z; @@ -273,11 +181,12 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe } } - PoolVector::Read rv = vertices.read(); + PoolVector::Read rv = positions.read(); PoolVector::Read rt = voxel.get_model_side_uv(side).read(); + Vector3 pos(x - 1, y - 1, z - 1); - for (unsigned int i = 0; i < vertices.size(); ++i) { + for (unsigned int i = 0; i < vertex_count; ++i) { Vector3 v = rv[i]; if (_bake_occlusion) { @@ -286,10 +195,10 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe // TODO Fix occlusion inconsistency caused by triangles orientation float shade = 0; for (unsigned int j = 0; j < 4; ++j) { - unsigned int corner = g_side_corners[side][j]; + unsigned int corner = CubeTables::g_side_corners[side][j]; if (shaded_corner[corner]) { float s = baked_occlusion_darkness * static_cast(shaded_corner[corner]); - float k = 1.0 - g_corner_position[corner].distance_to(v); + float k = 1.0 - CubeTables::g_corner_position[corner].distance_to(v); if (k < 0.0) k = 0.0; s *= k; @@ -298,31 +207,61 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe } } float gs = 1.0 - shade; - st.add_color(Color(gs, gs, gs)); + arrays.colors.push_back(Color(gs, gs, gs)); } - st.add_normal(Vector3(normal.x, normal.y, normal.z)); - st.add_uv(rt[i]); - st.add_vertex(v + pos); + // TODO Investigate wether those vectors can be replaced by a simpler, faster one for PODs + // TODO Resize beforehands rather than push_back (even if the vector is preallocated) + arrays.normals.push_back(Vector3(normal.x, normal.y, normal.z)); + arrays.uvs.push_back(rt[i]); + arrays.positions.push_back(v + pos); } + + const PoolVector &side_indices = voxel.get_model_side_indices(side); + PoolVector::Read ri = side_indices.read(); + unsigned int index_count = side_indices.size(); + + for(unsigned int i = 0; i < index_count; ++i) { + arrays.indices.push_back(index_offset + ri[i]); + } + + index_offset += vertex_count; } } } // Inside - if (voxel.get_model_vertices().size() != 0) { + if (voxel.get_model_positions().size() != 0) { - const PoolVector &vertices = voxel.get_model_vertices(); - PoolVector::Read rv = voxel.get_model_vertices().read(); + const PoolVector &vertices = voxel.get_model_positions(); + int vertex_count = vertices.size(); + + PoolVector::Read rv = vertices.read(); PoolVector::Read rn = voxel.get_model_normals().read(); PoolVector::Read rt = voxel.get_model_uv().read(); + Vector3 pos(x - 1, y - 1, z - 1); - for (unsigned int i = 0; i < vertices.size(); ++i) { - st.add_normal(rn[i]); - st.add_uv(rt[i]); - st.add_vertex(rv[i] + pos); + for (unsigned int i = 0; i < vertex_count; ++i) { + arrays.normals.push_back(rn[i]); + arrays.uvs.push_back(rt[i]); + arrays.positions.push_back(rv[i] + pos); } + + if(_bake_occlusion) { + // TODO handle ambient occlusion on inner parts + arrays.colors.push_back(Color(1,1,1)); + } + + const PoolVector &indices = voxel.get_model_indices(); + PoolVector::Read ri = indices.read(); + unsigned int index_count = indices.size(); + + for(unsigned int i = 0; i < index_count; ++i) { + arrays.indices.push_back(index_offset + ri[i]); + } + + index_offset += vertex_count; } } } @@ -337,22 +276,49 @@ Ref VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe if (mesh.is_null()) mesh_ref = Ref(memnew(ArrayMesh)); - for (unsigned int i = 0; i < MAX_MATERIALS; ++i) { - SurfaceTool &st = _surface_tool[i]; + VOXEL_PROFILE_BEGIN("mesher_add_surfaces") - // Index mesh to reduce memory usage and make upload to VRAM faster - // TODO actually, we could make it indexed from the ground up without using SurfaceTool, so we also save time! - // VOXEL_PROFILE_BEGIN("mesher_surfacetool_index") - // st.index(); - // VOXEL_PROFILE_END("mesher_surfacetool_index") +// print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size()) +// + String(", i: ") + String::num(_arrays[0].indices.size())); - VOXEL_PROFILE_BEGIN("mesher_surfacetool_commit") - mesh_ref = st.commit(mesh_ref); - VOXEL_PROFILE_END("mesher_surfacetool_commit") + int surface = 0; + for(int i = 0; i < MAX_MATERIALS; ++i) { - st.clear(); + const Arrays &arrays = _arrays[i]; + if(arrays.positions.size() != 0) { + + Array mesh_arrays; + mesh_arrays.resize(Mesh::ARRAY_MAX); + + { + PoolVector positions; + PoolVector uvs; + PoolVector normals; + PoolVector colors; + PoolVector indices; + + copy_to(positions, arrays.positions); + copy_to(uvs, arrays.uvs); + copy_to(normals, arrays.normals); + copy_to(colors, arrays.colors); + copy_to(indices, arrays.indices); + + mesh_arrays[Mesh::ARRAY_VERTEX] = positions; + mesh_arrays[Mesh::ARRAY_TEX_UV] = uvs; + mesh_arrays[Mesh::ARRAY_NORMAL] = normals; + mesh_arrays[Mesh::ARRAY_COLOR] = colors; + mesh_arrays[Mesh::ARRAY_INDEX] = indices; + } + + mesh_ref->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, mesh_arrays); + mesh_ref->surface_set_material(surface, _materials[i]); + + ++surface; + } } + VOXEL_PROFILE_END("mesher_add_surfaces") + return mesh_ref; } diff --git a/voxel_mesher.h b/voxel_mesher.h index c203223..0e6b832 100644 --- a/voxel_mesher.h +++ b/voxel_mesher.h @@ -7,7 +7,6 @@ #include "zprofiling.h" #include #include -#include // TODO Should be renamed VoxelMesherCubic or something like that class VoxelMesher : public Reference { @@ -37,9 +36,17 @@ protected: static void _bind_methods(); private: + struct Arrays { + Vector positions; + Vector normals; + Vector uvs; + Vector colors; + Vector indices; + }; + Ref _library; Ref _materials[MAX_MATERIALS]; - SurfaceTool _surface_tool[MAX_MATERIALS]; + Arrays _arrays[MAX_MATERIALS]; float _baked_occlusion_darkness; bool _bake_occlusion;