mirror of
https://github.com/Relintai/godot_voxel.git
synced 2024-11-11 20:35:08 +01:00
Got rid of SurfaceTool in the cubic mesher, moved cube tables in their own file, tweaked their winding
This commit is contained in:
parent
239eb11451
commit
cb6de49b96
141
cube_tables.cpp
Normal file
141
cube_tables.cpp
Normal file
@ -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
|
||||||
|
|
34
cube_tables.h
Normal file
34
cube_tables.h
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#ifndef CUBE_TABLES_H
|
||||||
|
#define CUBE_TABLES_H
|
||||||
|
|
||||||
|
#include <vector3.h>
|
||||||
|
#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
|
105
voxel.cpp
105
voxel.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "voxel.h"
|
#include "voxel.h"
|
||||||
#include "voxel_library.h"
|
#include "voxel_library.h"
|
||||||
#include "voxel_mesher.h"
|
#include "voxel_mesher.h"
|
||||||
|
#include "cube_tables.h"
|
||||||
|
|
||||||
#define STRLEN(x) (sizeof(x) / sizeof(x[0]))
|
#define STRLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||||
|
|
||||||
@ -128,13 +129,17 @@ void Voxel::set_geometry_type(GeometryType type) {
|
|||||||
|
|
||||||
case GEOMETRY_NONE: {
|
case GEOMETRY_NONE: {
|
||||||
// Clear all geometry
|
// Clear all geometry
|
||||||
_model_vertices.resize(0);
|
_model_positions.resize(0);
|
||||||
_model_normals.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) {
|
for (int side = 0; side < SIDE_COUNT; ++side) {
|
||||||
_model_side_vertices[side].resize(0);
|
_model_side_positions[side].resize(0);
|
||||||
_model_side_uv[side].resize(0);
|
_model_side_uvs[side].resize(0);
|
||||||
|
_model_side_indices[side].resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case GEOMETRY_CUBE:
|
case GEOMETRY_CUBE:
|
||||||
@ -167,56 +172,27 @@ VoxelLibrary *Voxel::get_library() const {
|
|||||||
|
|
||||||
Ref<Voxel> Voxel::set_cube_geometry(float sy) {
|
Ref<Voxel> Voxel::set_cube_geometry(float sy) {
|
||||||
sy = 1.0 + 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) {
|
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
|
||||||
_model_side_vertices[side].resize(6);
|
|
||||||
PoolVector<Vector3>::Write w = _model_side_vertices[side].write();
|
{
|
||||||
|
_model_side_positions[side].resize(4);
|
||||||
|
PoolVector<Vector3>::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<int>::Write w = _model_side_indices[side].write();
|
||||||
for (unsigned int i = 0; i < 6; ++i) {
|
for (unsigned int i = 0; i < 6; ++i) {
|
||||||
w[i] = vertices[side][i];
|
w[i] = CubeTables::g_side_quad_triangles[side][i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -242,34 +218,17 @@ void Voxel::update_cube_uv_sides() {
|
|||||||
const Vector2 uv[4] = {
|
const Vector2 uv[4] = {
|
||||||
Vector2(e, e),
|
Vector2(e, e),
|
||||||
Vector2(1.f - e, e),
|
Vector2(1.f - e, e),
|
||||||
Vector2(e, 1.f - e),
|
|
||||||
Vector2(1.f - e, 1.f - e),
|
Vector2(1.f - e, 1.f - e),
|
||||||
};
|
Vector2(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 }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
float s = 1.0 / (float)library->get_atlas_size();
|
float s = 1.0 / (float)library->get_atlas_size();
|
||||||
|
|
||||||
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
|
for (unsigned int side = 0; side < SIDE_COUNT; ++side) {
|
||||||
_model_side_uv[side].resize(6);
|
_model_side_uvs[side].resize(4);
|
||||||
PoolVector<Vector2>::Write w = _model_side_uv[side].write();
|
PoolVector<Vector2>::Write w = _model_side_uvs[side].write();
|
||||||
for (unsigned int i = 0; i < 6; ++i) {
|
for (unsigned int i = 0; i < 4; ++i) {
|
||||||
w[i] = (_cube_tiles[side] + uv[uv6[side][i]]) * s;
|
w[i] = (_cube_tiles[side] + uv[i]) * s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
26
voxel.h
26
voxel.h
@ -65,11 +65,14 @@ public:
|
|||||||
|
|
||||||
// Getters for native usage only
|
// Getters for native usage only
|
||||||
|
|
||||||
const PoolVector<Vector3> &get_model_vertices() const { return _model_vertices; }
|
const PoolVector<Vector3> &get_model_positions() const { return _model_positions; }
|
||||||
const PoolVector<Vector3> &get_model_normals() const { return _model_normals; }
|
const PoolVector<Vector3> &get_model_normals() const { return _model_normals; }
|
||||||
const PoolVector<Vector2> &get_model_uv() const { return _model_uv; }
|
const PoolVector<Vector2> &get_model_uv() const { return _model_uvs; }
|
||||||
const PoolVector<Vector3> &get_model_side_vertices(unsigned int side) const { return _model_side_vertices[side]; }
|
const PoolVector<int> &get_model_indices() const { return _model_indices; }
|
||||||
const PoolVector<Vector2> &get_model_side_uv(unsigned int side) const { return _model_side_uv[side]; }
|
|
||||||
|
const PoolVector<Vector3> &get_model_side_positions(unsigned int side) const { return _model_side_positions[side]; }
|
||||||
|
const PoolVector<Vector2> &get_model_side_uv(unsigned int side) const { return _model_side_uvs[side]; }
|
||||||
|
const PoolVector<int> &get_model_side_indices(unsigned int side) const { return _model_side_indices[side]; }
|
||||||
|
|
||||||
void set_library(Ref<VoxelLibrary> lib);
|
void set_library(Ref<VoxelLibrary> lib);
|
||||||
|
|
||||||
@ -104,13 +107,18 @@ private:
|
|||||||
Vector2 _cube_tiles[SIDE_COUNT];
|
Vector2 _cube_tiles[SIDE_COUNT];
|
||||||
|
|
||||||
// Model
|
// Model
|
||||||
PoolVector<Vector3> _model_vertices;
|
PoolVector<Vector3> _model_positions;
|
||||||
PoolVector<Vector3> _model_normals;
|
PoolVector<Vector3> _model_normals;
|
||||||
PoolVector<Vector2> _model_uv;
|
PoolVector<Vector2> _model_uvs;
|
||||||
PoolVector<Vector3> _model_side_vertices[SIDE_COUNT];
|
PoolVector<int> _model_indices;
|
||||||
PoolVector<Vector2> _model_side_uv[SIDE_COUNT];
|
// 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<Vector3> _model_side_positions[SIDE_COUNT];
|
||||||
|
PoolVector<Vector2> _model_side_uvs[SIDE_COUNT];
|
||||||
|
PoolVector<int> _model_side_indices[SIDE_COUNT];
|
||||||
|
|
||||||
// TODO Child voxel types
|
// TODO Child voxel types?
|
||||||
};
|
};
|
||||||
|
|
||||||
VARIANT_ENUM_CAST(Voxel::ChannelMode)
|
VARIANT_ENUM_CAST(Voxel::ChannelMode)
|
||||||
|
@ -45,8 +45,10 @@ public:
|
|||||||
int get_voxel(int x, int y, int z, unsigned int channel_index = 0) const;
|
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(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);
|
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_ 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_ 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_ 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); }
|
_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); }
|
||||||
|
|
||||||
|
264
voxel_mesher.cpp
264
voxel_mesher.cpp
@ -1,122 +1,20 @@
|
|||||||
#include "voxel_mesher.h"
|
#include "voxel_mesher.h"
|
||||||
#include "voxel_library.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;
|
template <typename T>
|
||||||
static const unsigned int EDGE_COUNT = 12;
|
void copy_to(PoolVector<T> &to, const Vector<T> &from) {
|
||||||
|
|
||||||
static const Vector3 g_corner_position[CORNER_COUNT] = {
|
to.resize(from.size());
|
||||||
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)
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned int g_side_coord[Voxel::SIDE_COUNT] = { 0, 0, 1, 1, 2, 2 };
|
typename PoolVector<T>::Write w = to.write();
|
||||||
static const unsigned int g_side_sign[Voxel::SIDE_COUNT] = { 0, 1, 0, 1, 0, 1 };
|
|
||||||
|
|
||||||
static const Vector3i g_side_normals[Voxel::SIDE_COUNT] = {
|
for (unsigned int i = 0; i < from.size(); ++i) {
|
||||||
Vector3i(-1, 0, 0),
|
w[i] = from[i];
|
||||||
Vector3i(1, 0, 0),
|
}
|
||||||
Vector3i(0, -1, 0),
|
}
|
||||||
Vector3i(0, 1, 0),
|
|
||||||
Vector3i(0, 0, -1),
|
|
||||||
Vector3i(0, 0, 1),
|
|
||||||
};
|
|
||||||
|
|
||||||
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()
|
VoxelMesher::VoxelMesher()
|
||||||
: _baked_occlusion_darkness(0.75),
|
: _baked_occlusion_darkness(0.75),
|
||||||
@ -182,8 +80,12 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
const VoxelLibrary &library = **_library;
|
const VoxelLibrary &library = **_library;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
|
for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
|
||||||
_surface_tool[i].begin(Mesh::PRIMITIVE_TRIANGLES);
|
Arrays &a = _arrays[i];
|
||||||
_surface_tool[i].set_material(_materials[i]);
|
a.positions.clear();
|
||||||
|
a.normals.clear();
|
||||||
|
a.uvs.clear();
|
||||||
|
a.colors.clear();
|
||||||
|
a.indices.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
float baked_occlusion_darkness;
|
float baked_occlusion_darkness;
|
||||||
@ -206,19 +108,23 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
min.clamp_to(pad, max);
|
min.clamp_to(pad, max);
|
||||||
max.clamp_to(min, buffer.get_size() - pad);
|
max.clamp_to(min, buffer.get_size() - pad);
|
||||||
|
|
||||||
|
int index_offset = 0;
|
||||||
|
|
||||||
// Iterate 3D padded data to extract voxel faces.
|
// 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.
|
// 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 z = min.z; z < max.z; ++z) {
|
||||||
for (unsigned int x = min.x; x < max.x; ++x) {
|
for (unsigned int x = min.x; x < max.x; ++x) {
|
||||||
for (unsigned int y = min.y; y < max.y; ++y) {
|
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);
|
int voxel_id = buffer.get_voxel(x, y, z, 0);
|
||||||
|
|
||||||
if (voxel_id != 0 && library.has_voxel(voxel_id)) {
|
if (voxel_id != 0 && library.has_voxel(voxel_id)) {
|
||||||
|
|
||||||
const Voxel &voxel = library.get_voxel_const(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,
|
// Hybrid approach: extract cube faces and decimate those that aren't visible,
|
||||||
// and still allow voxels to have geometry that is not a cube
|
// and still allow voxels to have geometry that is not a cube
|
||||||
@ -226,10 +132,12 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
// Sides
|
// Sides
|
||||||
for (unsigned int side = 0; side < Voxel::SIDE_COUNT; ++side) {
|
for (unsigned int side = 0; side < Voxel::SIDE_COUNT; ++side) {
|
||||||
|
|
||||||
const PoolVector<Vector3> &vertices = voxel.get_model_side_vertices(side);
|
const PoolVector<Vector3> &positions = voxel.get_model_side_positions(side);
|
||||||
if (vertices.size() != 0) {
|
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 nx = x + normal.x;
|
||||||
unsigned ny = y + normal.y;
|
unsigned ny = y + normal.y;
|
||||||
unsigned nz = z + normal.z;
|
unsigned nz = z + normal.z;
|
||||||
@ -247,22 +155,22 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
// Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/
|
// Combinatory solution for https://0fps.net/2013/07/03/ambient-occlusion-for-minecraft-like-worlds/
|
||||||
|
|
||||||
for (unsigned int j = 0; j < 4; ++j) {
|
for (unsigned int j = 0; j < 4; ++j) {
|
||||||
unsigned int edge = g_side_edges[side][j];
|
unsigned int edge = CubeTables::g_side_edges[side][j];
|
||||||
Vector3i edge_normal = g_edge_inormals[edge];
|
Vector3i edge_normal = CubeTables::g_edge_inormals[edge];
|
||||||
unsigned ex = x + edge_normal.x;
|
unsigned ex = x + edge_normal.x;
|
||||||
unsigned ey = y + edge_normal.y;
|
unsigned ey = y + edge_normal.y;
|
||||||
unsigned ez = z + edge_normal.z;
|
unsigned ez = z + edge_normal.z;
|
||||||
if (!is_transparent(library, buffer.get_voxel(ex, ey, ez))) {
|
if (!is_transparent(library, buffer.get_voxel(ex, ey, ez))) {
|
||||||
shaded_corner[g_edge_corners[edge][0]] += 1;
|
shaded_corner[CubeTables::g_edge_corners[edge][0]] += 1;
|
||||||
shaded_corner[g_edge_corners[edge][1]] += 1;
|
shaded_corner[CubeTables::g_edge_corners[edge][1]] += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (unsigned int j = 0; j < 4; ++j) {
|
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) {
|
if (shaded_corner[corner] == 2) {
|
||||||
shaded_corner[corner] = 3;
|
shaded_corner[corner] = 3;
|
||||||
} else {
|
} 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 cx = x + corner_normal.x;
|
||||||
unsigned int cy = y + corner_normal.y;
|
unsigned int cy = y + corner_normal.y;
|
||||||
unsigned int cz = z + corner_normal.z;
|
unsigned int cz = z + corner_normal.z;
|
||||||
@ -273,11 +181,12 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PoolVector<Vector3>::Read rv = vertices.read();
|
PoolVector<Vector3>::Read rv = positions.read();
|
||||||
PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read();
|
PoolVector<Vector2>::Read rt = voxel.get_model_side_uv(side).read();
|
||||||
|
|
||||||
Vector3 pos(x - 1, y - 1, z - 1);
|
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];
|
Vector3 v = rv[i];
|
||||||
|
|
||||||
if (_bake_occlusion) {
|
if (_bake_occlusion) {
|
||||||
@ -286,10 +195,10 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
// TODO Fix occlusion inconsistency caused by triangles orientation
|
// TODO Fix occlusion inconsistency caused by triangles orientation
|
||||||
float shade = 0;
|
float shade = 0;
|
||||||
for (unsigned int j = 0; j < 4; ++j) {
|
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]) {
|
if (shaded_corner[corner]) {
|
||||||
float s = baked_occlusion_darkness * static_cast<float>(shaded_corner[corner]);
|
float s = baked_occlusion_darkness * static_cast<float>(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)
|
if (k < 0.0)
|
||||||
k = 0.0;
|
k = 0.0;
|
||||||
s *= k;
|
s *= k;
|
||||||
@ -298,31 +207,61 @@ Ref<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
float gs = 1.0 - shade;
|
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));
|
// TODO Investigate wether those vectors can be replaced by a simpler, faster one for PODs
|
||||||
st.add_uv(rt[i]);
|
// TODO Resize beforehands rather than push_back (even if the vector is preallocated)
|
||||||
st.add_vertex(v + pos);
|
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<int> &side_indices = voxel.get_model_side_indices(side);
|
||||||
|
PoolVector<int>::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
|
// Inside
|
||||||
if (voxel.get_model_vertices().size() != 0) {
|
if (voxel.get_model_positions().size() != 0) {
|
||||||
|
|
||||||
const PoolVector<Vector3> &vertices = voxel.get_model_vertices();
|
const PoolVector<Vector3> &vertices = voxel.get_model_positions();
|
||||||
PoolVector<Vector3>::Read rv = voxel.get_model_vertices().read();
|
int vertex_count = vertices.size();
|
||||||
|
|
||||||
|
PoolVector<Vector3>::Read rv = vertices.read();
|
||||||
PoolVector<Vector3>::Read rn = voxel.get_model_normals().read();
|
PoolVector<Vector3>::Read rn = voxel.get_model_normals().read();
|
||||||
PoolVector<Vector2>::Read rt = voxel.get_model_uv().read();
|
PoolVector<Vector2>::Read rt = voxel.get_model_uv().read();
|
||||||
|
|
||||||
Vector3 pos(x - 1, y - 1, z - 1);
|
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) {
|
||||||
st.add_normal(rn[i]);
|
arrays.normals.push_back(rn[i]);
|
||||||
st.add_uv(rt[i]);
|
arrays.uvs.push_back(rt[i]);
|
||||||
st.add_vertex(rv[i] + pos);
|
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<int> &indices = voxel.get_model_indices();
|
||||||
|
PoolVector<int>::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<ArrayMesh> VoxelMesher::build(const VoxelBuffer &buffer, unsigned int channe
|
|||||||
if (mesh.is_null())
|
if (mesh.is_null())
|
||||||
mesh_ref = Ref<ArrayMesh>(memnew(ArrayMesh));
|
mesh_ref = Ref<ArrayMesh>(memnew(ArrayMesh));
|
||||||
|
|
||||||
for (unsigned int i = 0; i < MAX_MATERIALS; ++i) {
|
VOXEL_PROFILE_BEGIN("mesher_add_surfaces")
|
||||||
SurfaceTool &st = _surface_tool[i];
|
|
||||||
|
|
||||||
// Index mesh to reduce memory usage and make upload to VRAM faster
|
// print_line(String("Made mesh v: ") + String::num(_arrays[0].positions.size())
|
||||||
// TODO actually, we could make it indexed from the ground up without using SurfaceTool, so we also save time!
|
// + String(", i: ") + String::num(_arrays[0].indices.size()));
|
||||||
// VOXEL_PROFILE_BEGIN("mesher_surfacetool_index")
|
|
||||||
// st.index();
|
|
||||||
// VOXEL_PROFILE_END("mesher_surfacetool_index")
|
|
||||||
|
|
||||||
VOXEL_PROFILE_BEGIN("mesher_surfacetool_commit")
|
int surface = 0;
|
||||||
mesh_ref = st.commit(mesh_ref);
|
for(int i = 0; i < MAX_MATERIALS; ++i) {
|
||||||
VOXEL_PROFILE_END("mesher_surfacetool_commit")
|
|
||||||
|
|
||||||
st.clear();
|
const Arrays &arrays = _arrays[i];
|
||||||
|
if(arrays.positions.size() != 0) {
|
||||||
|
|
||||||
|
Array mesh_arrays;
|
||||||
|
mesh_arrays.resize(Mesh::ARRAY_MAX);
|
||||||
|
|
||||||
|
{
|
||||||
|
PoolVector<Vector3> positions;
|
||||||
|
PoolVector<Vector2> uvs;
|
||||||
|
PoolVector<Vector3> normals;
|
||||||
|
PoolVector<Color> colors;
|
||||||
|
PoolVector<int> 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;
|
return mesh_ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,7 +7,6 @@
|
|||||||
#include "zprofiling.h"
|
#include "zprofiling.h"
|
||||||
#include <reference.h>
|
#include <reference.h>
|
||||||
#include <scene/resources/mesh.h>
|
#include <scene/resources/mesh.h>
|
||||||
#include <scene/resources/surface_tool.h>
|
|
||||||
|
|
||||||
// TODO Should be renamed VoxelMesherCubic or something like that
|
// TODO Should be renamed VoxelMesherCubic or something like that
|
||||||
class VoxelMesher : public Reference {
|
class VoxelMesher : public Reference {
|
||||||
@ -37,9 +36,17 @@ protected:
|
|||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
struct Arrays {
|
||||||
|
Vector<Vector3> positions;
|
||||||
|
Vector<Vector3> normals;
|
||||||
|
Vector<Vector2> uvs;
|
||||||
|
Vector<Color> colors;
|
||||||
|
Vector<int> indices;
|
||||||
|
};
|
||||||
|
|
||||||
Ref<VoxelLibrary> _library;
|
Ref<VoxelLibrary> _library;
|
||||||
Ref<Material> _materials[MAX_MATERIALS];
|
Ref<Material> _materials[MAX_MATERIALS];
|
||||||
SurfaceTool _surface_tool[MAX_MATERIALS];
|
Arrays _arrays[MAX_MATERIALS];
|
||||||
float _baked_occlusion_darkness;
|
float _baked_occlusion_darkness;
|
||||||
bool _bake_occlusion;
|
bool _bake_occlusion;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user