From 469773a9fd44f6b9a4695784e96b5e51c35bee91 Mon Sep 17 00:00:00 2001 From: Relintai Date: Wed, 17 Jul 2019 17:01:12 +0200 Subject: [PATCH] Fixed the voxel mesher, and converted it to c++. Also small bugfixes, and binding improvements. ALso moved a few export variables from GDscript to bindings. --- meshers/cubic_mesher/voxel_cube_points.cpp | 17 ++++ meshers/cubic_mesher/voxel_cube_points.h | 5 +- meshers/cubic_mesher/voxel_mesher_cubic.cpp | 92 +++++++++++++++++++++ meshers/cubic_mesher/voxel_mesher_cubic.h | 13 +++ meshers/voxel_mesher.cpp | 45 +++++++--- meshers/voxel_mesher.h | 13 ++- world/voxel_buffer.cpp | 22 +++-- world/voxel_chunk.cpp | 24 +++++- world/voxel_chunk.h | 8 +- 9 files changed, 213 insertions(+), 26 deletions(-) diff --git a/meshers/cubic_mesher/voxel_cube_points.cpp b/meshers/cubic_mesher/voxel_cube_points.cpp index 7be5930..bdc0507 100644 --- a/meshers/cubic_mesher/voxel_cube_points.cpp +++ b/meshers/cubic_mesher/voxel_cube_points.cpp @@ -18,6 +18,15 @@ const unsigned int VoxelCubePoints::visibility_check_table[6] = { VOXEL_NEIGHBOUR_BOTTOM //VOXEL_FACE_BOTTOM 5 }; +const int VoxelCubePoints::face_light_direction_table[6][3] = { + { 0, 0, -1 }, //VOXEL_FACE_FRONT 0 + { -1, 0, 0 }, //VOXEL_FACE_RIGHT 1 + { 0, 0, 1 }, //VOXEL_FACE_BACK 2 + { 1, 0, 0 }, //VOXEL_FACE_LEFT 3 + { 0, -1, 0 }, //VOXEL_FACE_TOP 4 + { 0, 1, 0 } //VOXEL_FACE_BOTTOM 5 +}; + const float VoxelCubePoints::point_direction_table[8][3] = { { -0.5, -0.5, -0.5 }, //P000 { 0.5, -0.5, -0.5 }, //P100 @@ -615,6 +624,12 @@ Color VoxelCubePoints::get_face_point_color_mixed(int face, int index) { return _point_colors[indx] - Color(ao_value, ao_value, ao_value); } +Vector3 VoxelCubePoints::get_face_light_direction(int face) { + ERR_FAIL_INDEX_V(face, VOXEL_FACE_COUNT, Vector3()); + + return Vector3(face_light_direction_table[face][0], face_light_direction_table[face][1], face_light_direction_table[face][2]); +} + Vector3 VoxelCubePoints::get_point(int index) { ERR_FAIL_INDEX_V(index, POINT_COUNT, Vector3()); @@ -787,6 +802,8 @@ void VoxelCubePoints::_bind_methods() { ClassDB::bind_method(D_METHOD("get_face_point_light_color", "face", "index"), &VoxelCubePoints::get_face_point_light_color); ClassDB::bind_method(D_METHOD("get_face_point_color_mixed", "face", "index"), &VoxelCubePoints::get_face_point_color_mixed); + ClassDB::bind_method(D_METHOD("get_face_light_direction", "face"), &VoxelCubePoints::get_face_light_direction); + ClassDB::bind_method(D_METHOD("get_point", "index"), &VoxelCubePoints::get_point); ClassDB::bind_method(D_METHOD("get_top_left_point", "face"), &VoxelCubePoints::get_top_left_point); diff --git a/meshers/cubic_mesher/voxel_cube_points.h b/meshers/cubic_mesher/voxel_cube_points.h index 89233b4..b276ff5 100644 --- a/meshers/cubic_mesher/voxel_cube_points.h +++ b/meshers/cubic_mesher/voxel_cube_points.h @@ -113,13 +113,15 @@ public: int get_point_type(int index); int get_point_fill(int index); int get_point_neighbours(int index); - + int get_point_ao(int index); int get_face_point_ao(int face, int index); Color get_face_point_ao_color(int face, int index); Color get_face_point_light_color(int face, int index); Color get_face_point_color_mixed(int face, int index); + Vector3 get_face_light_direction(int face); + Vector3 get_point(int index); Vector3 get_top_left_point(int face); Vector3 get_top_right_point(int face); @@ -137,6 +139,7 @@ protected: static const unsigned int index_table[6][4]; static const unsigned int visibility_check_table[6]; + static const int face_light_direction_table[6][3]; static const float point_direction_table[8][3]; static const unsigned int point_direction_neighbour_table[8][3]; static const float uv_direction_table[8][4][2]; diff --git a/meshers/cubic_mesher/voxel_mesher_cubic.cpp b/meshers/cubic_mesher/voxel_mesher_cubic.cpp index 4b33814..6db8c4c 100644 --- a/meshers/cubic_mesher/voxel_mesher_cubic.cpp +++ b/meshers/cubic_mesher/voxel_mesher_cubic.cpp @@ -1,10 +1,102 @@ #include "voxel_mesher_cubic.h" +float VoxelMesherCubic::get_ao_strength() const { + return _ao_strength; +} +void VoxelMesherCubic::set_ao_strength(float value) { + _ao_strength = value; +} + +void VoxelMesherCubic::_add_buffer(Ref buffer) { + buffer->generate_ao(); + + Vector3i bfs = buffer->get_size(); + int x_size = bfs.x - 1; + int y_size = bfs.y - 1; + int z_size = bfs.z - 1; + + float lod_size = get_lod_size(); + float voxel_size = get_lod_size(); + float voxel_scale = get_voxel_scale(); + + Ref cube_points; + cube_points.instance(); + + float tile_uv_size = 1 / 4.0; + Color base_light(0.4, 0.4, 0.4); + + for (int y = lod_size; y < y_size - lod_size; y += lod_size) { + for (int z = lod_size; z < z_size - lod_size; z += lod_size) { + for (int x = lod_size; x < x_size - lod_size; x += lod_size) { + + cube_points->setup(buffer, x, y, z, lod_size); + + if (!cube_points->has_points()) + continue; + + for (int face = 0; face < VoxelCubePoints::VOXEL_FACE_COUNT; ++face) { + if (!cube_points->is_face_visible(face)) + continue; + + add_indices(get_vertex_count() + 2); + add_indices(get_vertex_count() + 1); + add_indices(get_vertex_count() + 0); + add_indices(get_vertex_count() + 3); + add_indices(get_vertex_count() + 2); + add_indices(get_vertex_count() + 0); + + Vector3 vertices[4] = { + cube_points->get_point_for_face(face, 0), + cube_points->get_point_for_face(face, 1), + cube_points->get_point_for_face(face, 2), + cube_points->get_point_for_face(face, 3) + }; + + Vector3 normals[4] = { + (vertices[3] - vertices[0]).cross(vertices[1] - vertices[0]), + (vertices[0] - vertices[1]).cross(vertices[2] - vertices[1]), + (vertices[1] - vertices[2]).cross(vertices[3] - vertices[2]), + (vertices[2] - vertices[3]).cross(vertices[0] - vertices[3]) + }; + + Vector3 face_light_direction = cube_points->get_face_light_direction(face); + + for (int i = 0; i < 4; ++i) { + Color light = cube_points->get_face_point_light_color(face, i); + light += base_light; + + float NdotL = CLAMP(normals[i].dot(face_light_direction), 0, 1.0); + + light *= NdotL; + + light -= cube_points->get_face_point_ao_color(face, i) * _ao_strength; + add_color(light); + + light.r = CLAMP(light.r, 0, 1.0); + light.g = CLAMP(light.g, 0, 1.0); + light.b = CLAMP(light.b, 0, 1.0); + + add_uv((cube_points->get_point_uv_direction(face, i) + Vector2(0.5, 0.5)) * Vector2(tile_uv_size, tile_uv_size)); + + add_vertex((vertices[i] * voxel_size + Vector3(x, y, z)) * voxel_scale); + } + } + } + } + } +} VoxelMesherCubic::VoxelMesherCubic() { + _ao_strength = 0.25; } +VoxelMesherCubic::~VoxelMesherCubic() { +} void VoxelMesherCubic::_bind_methods() { + ClassDB::bind_method(D_METHOD("_add_buffer", "buffer"), &VoxelMesherCubic::_add_buffer); + ClassDB::bind_method(D_METHOD("get_ao_strength"), &VoxelMesherCubic::get_ao_strength); + ClassDB::bind_method(D_METHOD("set_ao_strength", "value"), &VoxelMesherCubic::set_ao_strength); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "ao_strength"), "set_ao_strength", "get_ao_strength"); } diff --git a/meshers/cubic_mesher/voxel_mesher_cubic.h b/meshers/cubic_mesher/voxel_mesher_cubic.h index bb48bd7..3983f4c 100644 --- a/meshers/cubic_mesher/voxel_mesher_cubic.h +++ b/meshers/cubic_mesher/voxel_mesher_cubic.h @@ -1,18 +1,31 @@ #ifndef VOXEL_MESHER_CUBIC_H #define VOXEL_MESHER_CUBIC_H +#include "core/color.h" +#include "core/math/vector3.h" +#include "core/math/vector2.h" + #include "../voxel_mesher.h" +#include "voxel_cube_points.h" + class VoxelMesherCubic : public VoxelMesher { GDCLASS(VoxelMesherCubic, VoxelMesher); public: + float get_ao_strength() const; + void set_ao_strength(float value); + + void _add_buffer(Ref buffer); VoxelMesherCubic(); + ~VoxelMesherCubic(); protected: static void _bind_methods(); +private: + float _ao_strength; }; #endif diff --git a/meshers/voxel_mesher.cpp b/meshers/voxel_mesher.cpp index 2ba70d4..ba94a47 100644 --- a/meshers/voxel_mesher.cpp +++ b/meshers/voxel_mesher.cpp @@ -3,19 +3,18 @@ VoxelMesher::VoxelMesher(Ref library) { _library = library; - _debug_voxel_face = false; - size = (float)1; - vertexOffset = Vector3((float)0.5, (float)0.5, (float)0.5); + _voxel_scale = 1; + _lod_size = 1; - _surface_tool = memnew(SurfaceTool()); + _surface_tool.instance(); } VoxelMesher::VoxelMesher() { - _debug_voxel_face = false; - size = (float)1; - vertexOffset = Vector3((float)0.5, (float)0.5, (float)0.5); - _surface_tool = memnew(SurfaceTool()); + _voxel_scale = 1; + _lod_size = 1; + + _surface_tool.instance(); } VoxelMesher::~VoxelMesher() { @@ -26,7 +25,7 @@ VoxelMesher::~VoxelMesher() { _indices.clear(); _bones.clear(); - memdelete(_surface_tool); + _surface_tool.unref(); if (_library.is_valid()) { _library.unref(); @@ -59,7 +58,9 @@ Ref VoxelMesher::build_mesh() { _surface_tool->add_index(_indices.get(i)); } - _surface_tool->generate_normals(); + if (_normals.size() == 0) { + _surface_tool->generate_normals(); + } Ref m = _surface_tool->commit(); @@ -81,6 +82,20 @@ void VoxelMesher::add_buffer(Ref voxels) { call("_add_buffer", voxels); } +float VoxelMesher::get_voxel_scale() const { + return _voxel_scale; +} +void VoxelMesher::set_voxel_scale(const float voxel_scale) { + _voxel_scale = voxel_scale; +} + +int VoxelMesher::get_lod_size() const { + return _lod_size; +} +void VoxelMesher::set_lod_size(const int lod_size) { + _lod_size = lod_size; +} + void VoxelMesher::create_trimesh_shape(Ref shape) const { if (_vertices.size() == 0) return; @@ -89,8 +104,6 @@ void VoxelMesher::create_trimesh_shape(Ref shape) const { if (_indices.size() == 0) { - //face_points.resize(_vertices.size()); - int len = (_vertices.size() / 4); for (int i = 0; i < len; ++i) { @@ -310,6 +323,14 @@ void VoxelMesher::_bind_methods() { ClassDB::bind_method(D_METHOD("add_buffer", "buffer"), &VoxelMesher::add_buffer); + ClassDB::bind_method(D_METHOD("get_voxel_scale"), &VoxelMesher::get_voxel_scale); + ClassDB::bind_method(D_METHOD("set_voxel_scale", "value"), &VoxelMesher::set_voxel_scale); + ADD_PROPERTY(PropertyInfo(Variant::REAL, "voxel_scale"), "set_voxel_scale", "get_voxel_scale"); + + ClassDB::bind_method(D_METHOD("get_lod_size"), &VoxelMesher::get_lod_size); + ClassDB::bind_method(D_METHOD("set_lod_size", "value"), &VoxelMesher::set_lod_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_size"), "set_lod_size", "get_lod_size"); + ClassDB::bind_method(D_METHOD("get_library"), &VoxelMesher::get_library); ClassDB::bind_method(D_METHOD("set_library", "value"), &VoxelMesher::set_library); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library"), "set_library", "get_library"); diff --git a/meshers/voxel_mesher.h b/meshers/voxel_mesher.h index 4be4f5d..dbe57ff 100644 --- a/meshers/voxel_mesher.h +++ b/meshers/voxel_mesher.h @@ -36,6 +36,12 @@ public: void add_buffer(Ref voxels); + float get_voxel_scale() const; + void set_voxel_scale(const float voxel_scale); + + int get_lod_size() const; + void set_lod_size(const int lod_size); + void create_trimesh_shape(Ref shape) const; void bake_lights(MeshInstance *node, Vector > &lights); @@ -87,11 +93,10 @@ protected: Ref _library; - float size; - Vector3 vertexOffset; - bool _debug_voxel_face; + float _voxel_scale; + int _lod_size; - SurfaceTool *_surface_tool; + Ref _surface_tool; }; #endif diff --git a/world/voxel_buffer.cpp b/world/voxel_buffer.cpp index 2788d00..e03d841 100644 --- a/world/voxel_buffer.cpp +++ b/world/voxel_buffer.cpp @@ -323,9 +323,9 @@ void VoxelBuffer::add_light(int local_x, int local_y, int local_z, int size, Col int size_z = _size.z; float sizef = static_cast(size); - float rf = (color.r / sizef); - float gf = (color.g / sizef); - float bf = (color.b / sizef); + //float rf = (color.r / sizef); + //float gf = (color.g / sizef); + //float bf = (color.b / sizef); for (int y = local_y - size; y <= local_y + size; ++y) { if (y < 0 || y > size_y) @@ -339,11 +339,19 @@ void VoxelBuffer::add_light(int local_x, int local_y, int local_z, int size, Col if (x < 0 || x > size_x) continue; - float len = (Math::sqrt((real_t)x * x + y * y + z * z)) / sizef; + int lx = x - local_x; + int ly = y - local_y; + int lz = z - local_z; - int r = rf * len * 255.0; - int g = gf * len * 255.0; - int b = bf * len * 255.0; + float str = size - (((float)lx * lx + ly * ly + lz * lz)); + str /= size; + + if (str < 0) + continue; + + int r = color.r * str * 255.0; + int g = color.g * str * 255.0; + int b = color.b * str * 255.0; r += get_voxel(x, y, z, CHANNEL_LIGHT_COLOR_R); g += get_voxel(x, y, z, CHANNEL_LIGHT_COLOR_G); diff --git a/world/voxel_chunk.cpp b/world/voxel_chunk.cpp index 5d2bd98..9a05a8f 100644 --- a/world/voxel_chunk.cpp +++ b/world/voxel_chunk.cpp @@ -74,11 +74,26 @@ void VoxelChunk::set_library(Ref value) { _library = value; } +int VoxelChunk::get_lod_size() const { + return _lod_size; +} +void VoxelChunk::set_lod_size(const int lod_size) { + _lod_size = lod_size; + + if (_mesher.is_valid()) { + _mesher->set_lod_size(_lod_size); + } +} + float VoxelChunk::get_voxel_scale() const { return _voxel_scale; } void VoxelChunk::set_voxel_scale(float value) { _voxel_scale = value; + + if (_mesher.is_valid()) { + _mesher->set_voxel_scale(_voxel_scale); + } } Ref VoxelChunk::get_mesher() const { @@ -131,6 +146,9 @@ void VoxelChunk::build() { call("_create_mesher"); ERR_FAIL_COND(!_mesher.is_valid()); + + _mesher->set_lod_size(get_lod_size()); + _mesher->set_voxel_scale(get_voxel_scale()); } _mesher->set_library(_library); @@ -159,7 +177,7 @@ void VoxelChunk::build() { } void VoxelChunk::_create_mesher() { - _mesher = Ref(memnew(VoxelMesher())); + _mesher = Ref(memnew(VoxelMesherCubic())); } void VoxelChunk::finalize_mesh() { @@ -421,6 +439,10 @@ void VoxelChunk::_bind_methods() { ClassDB::bind_method(D_METHOD("set_library", "value"), &VoxelChunk::set_library); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "library", PROPERTY_HINT_RESOURCE_TYPE, "VoxelmanLibrary"), "set_library", "get_library"); + ClassDB::bind_method(D_METHOD("get_lod_size"), &VoxelChunk::get_lod_size); + ClassDB::bind_method(D_METHOD("set_lod_size", "value"), &VoxelChunk::set_lod_size); + ADD_PROPERTY(PropertyInfo(Variant::INT, "lod_size"), "set_lod_size", "get_lod_size"); + ClassDB::bind_method(D_METHOD("get_voxel_scale"), &VoxelChunk::get_voxel_scale); ClassDB::bind_method(D_METHOD("set_voxel_scale", "value"), &VoxelChunk::set_voxel_scale); ADD_PROPERTY(PropertyInfo(Variant::REAL, "voxel_scale"), "set_voxel_scale", "get_voxel_scale"); diff --git a/world/voxel_chunk.h b/world/voxel_chunk.h index 67f0470..1ecbc29 100644 --- a/world/voxel_chunk.h +++ b/world/voxel_chunk.h @@ -14,6 +14,7 @@ #include "../data/voxel_light.h" #include "../meshers/voxel_mesher.h" +#include "../meshers/cubic_mesher/voxel_mesher_cubic.h" #include "../library/voxel_surface.h" #include "../library/voxelman_library.h" @@ -51,6 +52,9 @@ public: Ref get_library(); void set_library(Ref value); + int get_lod_size() const; + void set_lod_size(int lod_size); + float get_voxel_scale() const; void set_voxel_scale(float value); @@ -97,7 +101,7 @@ public: StaticBody *create_trimesh_collision_node(); VoxelChunk(); - virtual ~VoxelChunk(); + ~VoxelChunk(); void draw_debug_voxels(int max, Color color = Color(1, 1, 1)); void draw_debug_voxel_lights(); @@ -114,6 +118,8 @@ protected: Ref _buffer; Vector > _voxel_lights; + + int _lod_size; float _voxel_scale; NodePath _library_path;