Fix transition meshes not being scaled with LOD, provide LOD in mesher API
This commit is contained in:
parent
716b820599
commit
8056f7e679
@ -56,7 +56,7 @@ void VoxelMesherBlocky::set_occlusion_enabled(bool enable) {
|
||||
_bake_occlusion = enable;
|
||||
}
|
||||
|
||||
void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelBuffer &buffer) {
|
||||
void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
|
||||
//uint64_t time_before = OS::get_singleton()->get_ticks_usec();
|
||||
|
||||
const int channel = VoxelBuffer::CHANNEL_TYPE;
|
||||
@ -86,9 +86,16 @@ void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelBuffer &bu
|
||||
// - Slower
|
||||
// => Could be implemented in a separate class?
|
||||
|
||||
const VoxelBuffer &voxels = input.voxels;
|
||||
#ifdef TOOLS_ENABLED
|
||||
if (input.lod != 0) {
|
||||
WARN_PRINT("VoxelMesherBlocky received lod != 0, it is not supported");
|
||||
}
|
||||
#endif
|
||||
|
||||
// Data must be padded, hence the off-by-one
|
||||
Vector3i min = Vector3i(get_minimum_padding());
|
||||
Vector3i max = buffer.get_size() - Vector3i(get_maximum_padding());
|
||||
Vector3i max = voxels.get_size() - Vector3i(get_maximum_padding());
|
||||
|
||||
int index_offsets[MAX_MATERIALS] = { 0 };
|
||||
|
||||
@ -99,7 +106,7 @@ void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelBuffer &bu
|
||||
// That means we can use raw pointers to voxel data inside instead of using the higher-level getters,
|
||||
// and then save a lot of time.
|
||||
|
||||
uint8_t *type_buffer = buffer.get_channel_raw(channel);
|
||||
uint8_t *type_buffer = voxels.get_channel_raw(channel);
|
||||
/* _
|
||||
// | \
|
||||
// /\ \\
|
||||
@ -122,8 +129,8 @@ void VoxelMesherBlocky::build(VoxelMesher::Output &output, const VoxelBuffer &bu
|
||||
// Build lookup tables so to speed up voxel access.
|
||||
// These are values to add to an address in order to get given neighbor.
|
||||
|
||||
int row_size = buffer.get_size().y;
|
||||
int deck_size = buffer.get_size().x * row_size;
|
||||
int row_size = voxels.get_size().y;
|
||||
int deck_size = voxels.get_size().x * row_size;
|
||||
|
||||
int side_neighbor_lut[Cube::SIDE_COUNT];
|
||||
side_neighbor_lut[Cube::SIDE_LEFT] = row_size;
|
||||
|
@ -27,7 +27,7 @@ public:
|
||||
void set_occlusion_enabled(bool enable);
|
||||
bool get_occlusion_enabled() const { return _bake_occlusion; }
|
||||
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels) override;
|
||||
void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
|
||||
|
||||
VoxelMesher *clone() override;
|
||||
|
||||
|
@ -49,6 +49,12 @@ Array MeshBuilder::commit(bool wireframe) {
|
||||
return surface;
|
||||
}
|
||||
|
||||
void MeshBuilder::scale(float scale) {
|
||||
for (auto it = _positions.begin(); it != _positions.end(); ++it) {
|
||||
*it *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
void MeshBuilder::clear() {
|
||||
_positions.clear();
|
||||
_normals.clear();
|
||||
|
@ -37,6 +37,7 @@ public:
|
||||
_indices.push_back(i);
|
||||
}
|
||||
|
||||
void scale(float scale);
|
||||
Array commit(bool wireframe);
|
||||
void clear();
|
||||
|
||||
|
@ -288,7 +288,15 @@ void foreach_node(OctreeNode *root, Action_T &a, int depth = 0) {
|
||||
}
|
||||
}
|
||||
|
||||
Array generate_debug_octree_mesh(OctreeNode *root) {
|
||||
inline void scale_positions(PoolVector3Array &positions, float scale) {
|
||||
PoolVector3Array::Write w = positions.write();
|
||||
const uint32_t size = positions.size();
|
||||
for (unsigned int i = 0; i < size; ++i) {
|
||||
w[i] *= scale;
|
||||
}
|
||||
}
|
||||
|
||||
Array generate_debug_octree_mesh(OctreeNode *root, int scale) {
|
||||
|
||||
struct GetMaxDepth {
|
||||
int max_depth;
|
||||
@ -344,6 +352,10 @@ Array generate_debug_octree_mesh(OctreeNode *root) {
|
||||
return Array();
|
||||
}
|
||||
|
||||
if (scale != 1) {
|
||||
scale_positions(arrays.positions, scale);
|
||||
}
|
||||
|
||||
Array surface;
|
||||
surface.resize(Mesh::ARRAY_MAX);
|
||||
surface[Mesh::ARRAY_VERTEX] = arrays.positions;
|
||||
@ -353,7 +365,7 @@ Array generate_debug_octree_mesh(OctreeNode *root) {
|
||||
return surface;
|
||||
}
|
||||
|
||||
Array generate_debug_dual_grid_mesh(const DualGrid &grid) {
|
||||
Array generate_debug_dual_grid_mesh(const DualGrid &grid, int scale) {
|
||||
|
||||
PoolVector3Array positions;
|
||||
PoolIntArray indices;
|
||||
@ -380,6 +392,10 @@ Array generate_debug_dual_grid_mesh(const DualGrid &grid) {
|
||||
return Array();
|
||||
}
|
||||
|
||||
if (scale != 1) {
|
||||
scale_positions(positions, scale);
|
||||
}
|
||||
|
||||
Array surface;
|
||||
surface.resize(Mesh::ARRAY_MAX);
|
||||
surface[Mesh::ARRAY_VERTEX] = positions;
|
||||
@ -1464,7 +1480,7 @@ VoxelMesherDMC::SeamMode VoxelMesherDMC::get_seam_mode() const {
|
||||
return _seam_mode;
|
||||
}
|
||||
|
||||
void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels) {
|
||||
void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
|
||||
|
||||
// Requirements:
|
||||
// - Voxel data must be padded
|
||||
@ -1472,6 +1488,8 @@ void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxel
|
||||
|
||||
_stats = {};
|
||||
|
||||
const VoxelBuffer &voxels = input.voxels;
|
||||
|
||||
if (voxels.is_uniform(VoxelBuffer::CHANNEL_SDF)) {
|
||||
// That won't produce any polygon
|
||||
return;
|
||||
@ -1537,7 +1555,7 @@ void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxel
|
||||
if (root != nullptr) {
|
||||
|
||||
if (_mesh_mode == MESH_DEBUG_OCTREE) {
|
||||
surface = dmc::generate_debug_octree_mesh(root);
|
||||
surface = dmc::generate_debug_octree_mesh(root, 1 << input.lod);
|
||||
|
||||
} else {
|
||||
|
||||
@ -1550,7 +1568,7 @@ void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxel
|
||||
_stats.dualgrid_derivation_time = OS::get_singleton()->get_ticks_usec() - time_before;
|
||||
|
||||
if (_mesh_mode == MESH_DEBUG_DUAL_GRID) {
|
||||
surface = dmc::generate_debug_dual_grid_mesh(_dual_grid);
|
||||
surface = dmc::generate_debug_dual_grid_mesh(_dual_grid, 1 << input.lod);
|
||||
|
||||
} else {
|
||||
|
||||
@ -1576,6 +1594,9 @@ void VoxelMesherDMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxel
|
||||
|
||||
if (surface.empty()) {
|
||||
time_before = OS::get_singleton()->get_ticks_usec();
|
||||
if (input.lod > 0) {
|
||||
_mesh_builder.scale(1 << input.lod);
|
||||
}
|
||||
surface = _mesh_builder.commit(_mesh_mode == MESH_WIREFRAME);
|
||||
_stats.commit_time = OS::get_singleton()->get_ticks_usec() - time_before;
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ public:
|
||||
void set_seam_mode(SeamMode mode);
|
||||
SeamMode get_seam_mode() const;
|
||||
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels) override;
|
||||
void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
|
||||
|
||||
Dictionary get_statistics() const;
|
||||
|
||||
|
@ -73,7 +73,7 @@ VoxelMesherMC::VoxelMesherMC() {
|
||||
set_padding(MIN_PADDING, MAX_PADDING);
|
||||
}
|
||||
|
||||
void VoxelMesherMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels) {
|
||||
void VoxelMesherMC::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
|
||||
|
||||
int channel = VoxelBuffer::CHANNEL_SDF;
|
||||
|
||||
@ -85,6 +85,7 @@ void VoxelMesherMC::build(VoxelMesher::Output &output, const VoxelBuffer &voxels
|
||||
_output_normals.clear();
|
||||
_output_indices.clear();
|
||||
|
||||
const VoxelBuffer &voxels = input.voxels;
|
||||
build_internal(voxels, channel);
|
||||
// OS::get_singleton()->print("vertices: %i, normals: %i, indices: %i\n",
|
||||
// m_output_vertices.size(),
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "../voxel_mesher.h"
|
||||
|
||||
// TODO Remove it.
|
||||
// Simple marching cubes.
|
||||
// Implementation is simplified from old Transvoxel code.
|
||||
class VoxelMesherMC : public VoxelMesher {
|
||||
@ -19,7 +20,7 @@ public:
|
||||
|
||||
VoxelMesherMC();
|
||||
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels) override;
|
||||
void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
|
||||
|
||||
void set_seam_mode(SeamMode mode);
|
||||
SeamMode get_seam_mode() const;
|
||||
|
@ -155,7 +155,20 @@ void VoxelMesherTransvoxel::fill_surface_arrays(Array &arrays) {
|
||||
arrays[Mesh::ARRAY_INDEX] = indices;
|
||||
}
|
||||
|
||||
void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelBuffer &voxels) {
|
||||
void VoxelMesherTransvoxel::scale_output(float factor) {
|
||||
|
||||
for (auto it = _output_vertices.begin(); it != _output_vertices.end(); ++it) {
|
||||
*it *= factor;
|
||||
}
|
||||
for (auto it = _output_extra.begin(); it != _output_extra.end(); ++it) {
|
||||
Color &c = *it;
|
||||
c.r *= factor;
|
||||
c.g *= factor;
|
||||
c.b *= factor;
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher::Input &input) {
|
||||
|
||||
int channel = VoxelBuffer::CHANNEL_SDF;
|
||||
|
||||
@ -165,6 +178,7 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelBuffer
|
||||
// Once capacity is big enough, no more memory should be allocated
|
||||
clear_output();
|
||||
|
||||
const VoxelBuffer &voxels = input.voxels;
|
||||
build_internal(voxels, channel);
|
||||
|
||||
if (_output_vertices.size() == 0) {
|
||||
@ -173,6 +187,10 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelBuffer
|
||||
}
|
||||
|
||||
Array regular_arrays;
|
||||
// TODO Bake LOD into the algorithm. It wasn't so far because it wasn't in the API
|
||||
if (input.lod > 0) {
|
||||
scale_output(1 << input.lod);
|
||||
}
|
||||
fill_surface_arrays(regular_arrays);
|
||||
output.surfaces.push_back(regular_arrays);
|
||||
|
||||
@ -187,6 +205,10 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelBuffer
|
||||
}
|
||||
|
||||
Array transition_arrays;
|
||||
scale_output(lod_scale);
|
||||
if (input.lod > 0) {
|
||||
scale_output(1 << input.lod);
|
||||
}
|
||||
fill_surface_arrays(transition_arrays);
|
||||
output.transition_surfaces[dir].push_back(transition_arrays);
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
|
||||
VoxelMesherTransvoxel();
|
||||
|
||||
void build(VoxelMesher::Output &output, const VoxelBuffer &voxels) override;
|
||||
void build(VoxelMesher::Output &output, const VoxelMesher::Input &input) override;
|
||||
|
||||
VoxelMesher *clone() override;
|
||||
|
||||
@ -46,6 +46,7 @@ private:
|
||||
int emit_vertex(Vector3 primary, Vector3 normal, uint16_t border_mask, Vector3 secondary);
|
||||
void clear_output();
|
||||
void fill_surface_arrays(Array &arrays);
|
||||
void scale_output(float factor);
|
||||
|
||||
private:
|
||||
FixedArray<std::vector<ReuseCell>, 2> _cache;
|
||||
|
@ -5,7 +5,8 @@ Ref<Mesh> VoxelMesher::build_mesh(Ref<VoxelBuffer> voxels) {
|
||||
ERR_FAIL_COND_V(voxels.is_null(), Ref<ArrayMesh>());
|
||||
|
||||
Output output;
|
||||
build(output, **voxels);
|
||||
Input input = { **voxels, 0 };
|
||||
build(output, input);
|
||||
|
||||
if (output.surfaces.empty()) {
|
||||
return Ref<ArrayMesh>();
|
||||
@ -21,7 +22,7 @@ Ref<Mesh> VoxelMesher::build_mesh(Ref<VoxelBuffer> voxels) {
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void VoxelMesher::build(Output &output, const VoxelBuffer &voxels) {
|
||||
void VoxelMesher::build(Output &output, const Input &input) {
|
||||
|
||||
ERR_PRINT("Not implemented");
|
||||
}
|
||||
|
@ -9,6 +9,11 @@
|
||||
class VoxelMesher : public Reference {
|
||||
GDCLASS(VoxelMesher, Reference)
|
||||
public:
|
||||
struct Input {
|
||||
const VoxelBuffer &voxels;
|
||||
int lod = 0;
|
||||
};
|
||||
|
||||
struct Output {
|
||||
// Each surface correspond to a different material
|
||||
Vector<Array> surfaces;
|
||||
@ -17,7 +22,7 @@ public:
|
||||
unsigned int compression_flags = Mesh::ARRAY_COMPRESS_DEFAULT;
|
||||
};
|
||||
|
||||
virtual void build(Output &output, const VoxelBuffer &voxels);
|
||||
virtual void build(Output &output, const Input &voxels);
|
||||
|
||||
// Get how many neighbor voxels need to be accessed around the meshed area.
|
||||
// If this is not respected, the mesher might produce seams at the edges, or an error
|
||||
|
@ -263,6 +263,7 @@ void VoxelBlock::set_transition_mask(uint8_t m) {
|
||||
tm |= bits[Cube::SIDE_NEGATIVE_Z] << 4;
|
||||
tm |= bits[Cube::SIDE_POSITIVE_Z] << 5;
|
||||
|
||||
// TODO Use a StringName, VoxelStringNames
|
||||
_shader_material->set_shader_param("u_transition_mask", tm);
|
||||
}
|
||||
for (int dir = 0; dir < Cube::SIDE_COUNT; ++dir) {
|
||||
|
@ -4,34 +4,6 @@
|
||||
#include "voxel_lod_terrain.h"
|
||||
#include <core/os/os.h>
|
||||
|
||||
static void scale_mesh_data(Vector<Array> &surfaces, float factor) {
|
||||
|
||||
for (int i = 0; i < surfaces.size(); ++i) {
|
||||
Array &surface = surfaces.write[i]; // There is COW here too but should not happen, hopefully
|
||||
|
||||
if (surface.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
PoolVector3Array positions = surface[Mesh::ARRAY_VERTEX]; // Array of Variants here, implicit cast going on
|
||||
|
||||
// Now dear COW, let's make sure there is only ONE ref to that PoolVector,
|
||||
// so you won't trash performance with pointless allocations
|
||||
surface[Mesh::ARRAY_VERTEX] = Variant();
|
||||
|
||||
{
|
||||
PoolVector3Array::Write w = positions.write();
|
||||
int len = positions.size();
|
||||
for (int j = 0; j < len; ++j) {
|
||||
w[j] = w[j] * factor;
|
||||
}
|
||||
}
|
||||
|
||||
// Thank you
|
||||
surface[Mesh::ARRAY_VERTEX] = positions;
|
||||
}
|
||||
}
|
||||
|
||||
VoxelMeshUpdater::VoxelMeshUpdater(unsigned int thread_count, MeshingParams params) {
|
||||
|
||||
print_line("Constructing VoxelMeshUpdater");
|
||||
@ -103,21 +75,13 @@ void VoxelMeshUpdater::process_blocks_thread_func(
|
||||
|
||||
CRASH_COND(block.voxels.is_null());
|
||||
|
||||
VoxelMesher::Input input = { **block.voxels, ib.lod };
|
||||
|
||||
if (blocky_mesher.is_valid()) {
|
||||
blocky_mesher->build(output.blocky_surfaces, **block.voxels);
|
||||
blocky_mesher->build(output.blocky_surfaces, input);
|
||||
}
|
||||
if (smooth_mesher.is_valid()) {
|
||||
smooth_mesher->build(output.smooth_surfaces, **block.voxels);
|
||||
}
|
||||
|
||||
if (ib.lod > 0) {
|
||||
// TODO Make this optional if the mesher can factor in the upscale already
|
||||
float factor = 1 << ib.lod;
|
||||
scale_mesh_data(output.blocky_surfaces.surfaces, factor);
|
||||
scale_mesh_data(output.smooth_surfaces.surfaces, factor);
|
||||
for (int i = 0; i < output.smooth_surfaces.transition_surfaces.size(); ++i) {
|
||||
scale_mesh_data(output.smooth_surfaces.transition_surfaces[i], factor);
|
||||
}
|
||||
smooth_mesher->build(output.smooth_surfaces, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user