From b0cd02a2ef82e116b89a5494a57e7af6c3b40f31 Mon Sep 17 00:00:00 2001 From: Marc Gilleron Date: Sun, 7 Aug 2022 23:03:45 +0100 Subject: [PATCH] Support modifiers in distance normalmaps --- meshers/transvoxel/distance_normalmaps.cpp | 37 +++++++++++++++--- meshers/transvoxel/distance_normalmaps.h | 3 +- .../transvoxel/voxel_mesher_transvoxel.cpp | 2 +- storage/modifiers.cpp | 39 +++++++++++++++++++ storage/modifiers.h | 7 ++++ 5 files changed, 80 insertions(+), 8 deletions(-) diff --git a/meshers/transvoxel/distance_normalmaps.cpp b/meshers/transvoxel/distance_normalmaps.cpp index 60a9c3ea..839ed70b 100644 --- a/meshers/transvoxel/distance_normalmaps.cpp +++ b/meshers/transvoxel/distance_normalmaps.cpp @@ -1,5 +1,6 @@ #include "distance_normalmaps.h" #include "../../generators/voxel_generator.h" +#include "../../storage/voxel_data_map.h" #include "../../util/math/conv.h" #include "../../util/math/triangle.h" #include "../../util/profiling.h" @@ -166,7 +167,8 @@ inline Vector3f encode_normal_xyz(const Vector3f n) { // Sample voxels inside the cell to compute a tile of world space normals from the SDF. void compute_normalmap(Span cell_infos, const transvoxel::MeshArrays &mesh, NormalMapData &normal_map_data, unsigned int tile_resolution, VoxelGenerator &generator, - Vector3i origin_in_voxels, unsigned int lod_index, bool octahedral_encoding) { + const VoxelDataLodMap *voxel_data, Vector3i origin_in_voxels, unsigned int lod_index, + bool octahedral_encoding) { ZN_PROFILE_SCOPE(); ZN_ASSERT_RETURN(generator.supports_series_generation()); @@ -289,11 +291,34 @@ void compute_normalmap(Span cell_infos, const transv tls_sdf_buffer.resize(tls_x_buffer.size()); // Query voxel data - // TODO Support edited voxels - // TODO Support modifiers - generator.generate_series(to_span(tls_x_buffer), to_span(tls_y_buffer), to_span(tls_z_buffer), - VoxelBufferInternal::CHANNEL_SDF, to_span(tls_sdf_buffer), cell_origin_world, - cell_origin_world + Vector3f(cell_size)); + { + const Vector3f query_min_pos = cell_origin_world; + const Vector3f query_max_pos = cell_origin_world + Vector3f(cell_size); + + generator.generate_series(to_span(tls_x_buffer), to_span(tls_y_buffer), to_span(tls_z_buffer), + VoxelBufferInternal::CHANNEL_SDF, to_span(tls_sdf_buffer), query_min_pos, query_max_pos); + + if (voxel_data != nullptr) { + voxel_data->modifiers.apply(to_span(tls_x_buffer), to_span(tls_y_buffer), to_span(tls_z_buffer), + to_span(tls_sdf_buffer), query_min_pos, query_max_pos); + + // TODO Support edited voxels + // Naive method: + // Do 4 single sample queries for every pixel. In each sample, check if there is edited data. If yes, + // interpolate linearly it with 8 neighbors. Neighbors are obtained through single queries too. If the + // sample is not edited, use the generator and modifiers. + // It seems extremely slow though... + + // const Vector3i query_min_pos_i = math::floor_to_int(query_min_pos); + // const Vector3i query_max_pos_i = math::ceil_to_int(query_max_pos); + // VoxelDataGrid grid; + // { + // const VoxelDataLodMap::Lod &lod0 = voxel_data->lods[0]; + // RWLockRead rlock(lod0.map_lock); + // grid.reference_area(lod0.map, Box3i::from_min_max(query_min_pos_i, query_max_pos_i)); + // } + } + } static thread_local std::vector tls_tile_normals; tls_tile_normals.clear(); diff --git a/meshers/transvoxel/distance_normalmaps.h b/meshers/transvoxel/distance_normalmaps.h index b5da8b28..c5de1521 100644 --- a/meshers/transvoxel/distance_normalmaps.h +++ b/meshers/transvoxel/distance_normalmaps.h @@ -14,6 +14,7 @@ class Image; namespace zylann::voxel { class VoxelGenerator; +struct VoxelDataLodMap; // TODO This system could be extended to more than just normals (texturing) @@ -43,7 +44,7 @@ struct NormalMapData { // Sample voxels inside the cell to compute a tile of world space normals from the SDF. void compute_normalmap(Span cell_infos, const transvoxel::MeshArrays &mesh, NormalMapData &normal_map_data, unsigned int tile_resolution, VoxelGenerator &generator, - Vector3i origin_in_voxels, unsigned int lod_index, bool octahedral_encoding); + const VoxelDataLodMap *voxel_data, Vector3i origin_in_voxels, unsigned int lod_index, bool octahedral_encoding); struct NormalMapImages { Vector> atlas_images; diff --git a/meshers/transvoxel/voxel_mesher_transvoxel.cpp b/meshers/transvoxel/voxel_mesher_transvoxel.cpp index 1f8d725a..c131a331 100644 --- a/meshers/transvoxel/voxel_mesher_transvoxel.cpp +++ b/meshers/transvoxel/voxel_mesher_transvoxel.cpp @@ -281,7 +281,7 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher // - So the mesh can be obtained sooner // - And we can prevent it from updating as frequently as the mesh if repeatedly modified compute_normalmap(to_span(*cell_infos), tls_mesh_arrays, tls_normalmap_data, tile_resolution, *input.generator, - input.origin_in_voxels + offset, input.lod, settings.octahedral_encoding_enabled); + input.data, input.origin_in_voxels + offset, input.lod, settings.octahedral_encoding_enabled); const Vector3i block_size = input.voxels.get_size() - Vector3iUtil::create(get_minimum_padding() + get_maximum_padding()); diff --git a/storage/modifiers.cpp b/storage/modifiers.cpp index 65910f0f..8e6b6d33 100644 --- a/storage/modifiers.cpp +++ b/storage/modifiers.cpp @@ -31,6 +31,20 @@ Span get_positions_temporary(Vector3i buffer_size, Vector3 origin return positions; } +Span get_positions_temporary( + Span x_buffer, Span y_buffer, Span z_buffer) { + ZN_ASSERT(x_buffer.size() == z_buffer.size() && y_buffer.size() == z_buffer.size()); + + tls_positions.resize(x_buffer.size()); + Span positions = to_span(tls_positions); + + for (unsigned int i = 0; i < x_buffer.size(); ++i) { + positions[i] = Vector3(x_buffer[i], y_buffer[i], z_buffer[i]); + } + + return positions; +} + Span decompress_sdf_to_temporary(VoxelBufferInternal &voxels) { ZN_DSTACK(); const Vector3i bs = voxels.get_size(); @@ -246,6 +260,31 @@ void VoxelModifierStack::apply(float &sdf, Vector3 position) const { } } +void VoxelModifierStack::apply(Span x_buffer, Span y_buffer, Span z_buffer, + Span sdf_buffer, Vector3f min_pos, Vector3f max_pos) const { + ZN_PROFILE_SCOPE(); + RWLockRead lock(_stack_lock); + + if (_stack.size() == 0) { + return; + } + + VoxelModifierContext ctx; + ctx.positions = get_positions_temporary(x_buffer, y_buffer, z_buffer); + ctx.sdf = sdf_buffer; + + const AABB aabb(to_vec3(min_pos), to_vec3(max_pos - min_pos)); + + for (unsigned int i = 0; i < _stack.size(); ++i) { + const VoxelModifier *modifier = _stack[i]; + ZN_ASSERT(modifier != nullptr); + + if (modifier->get_aabb().intersects(aabb)) { + modifier->apply(ctx); + } + } +} + void VoxelModifierStack::clear() { RWLockWrite lock(_stack_lock); _stack.clear(); diff --git a/storage/modifiers.h b/storage/modifiers.h index 1b6728c0..677cdf60 100644 --- a/storage/modifiers.h +++ b/storage/modifiers.h @@ -140,6 +140,11 @@ private: float _isolevel; }; +// TODO Capsule +// TODO Box +// TODO Heightmap +// TODO Graph (using generator graph as a brush?) + //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// class VoxelModifierStack { @@ -167,6 +172,8 @@ public: VoxelModifier *get_modifier(uint32_t id) const; void apply(VoxelBufferInternal &voxels, AABB aabb) const; void apply(float &sdf, Vector3 position) const; + void apply(Span x_buffer, Span y_buffer, Span z_buffer, + Span sdf_buffer, Vector3f min_pos, Vector3f max_pos) const; void clear(); private: