Fix rare bug with vertex sharing causing long spiky artifacts
Basically we were checking case code of the ReuseCell to know if we can re-use a vertex from it, but sometimes the associated cell did not write a re-usable vertex, and we were not resetting such vertex indices. So in some cases, we were accessing a very old index. The case code doesn't need to be remembered, we just reset the first vertex. No need to check if the ReuseCell was empty, we can read the vertex directly, as it will be -1 anyways if it isn't re-usable. At least, this fixed the bug and did not reproduce after testing a lot of noise data sets.
This commit is contained in:
parent
ee8a70bc75
commit
d4986489cf
@ -294,10 +294,9 @@ void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned i
|
||||
case_code |= (sign(cell_samples[6]) << 6);
|
||||
case_code |= (sign(cell_samples[7]) << 7);
|
||||
|
||||
{
|
||||
ReuseCell &rc = get_reuse_cell(pos);
|
||||
rc.case_index = case_code;
|
||||
}
|
||||
ReuseCell ¤t_reuse_cell = get_reuse_cell(pos);
|
||||
// Mark as unusable for now
|
||||
current_reuse_cell.vertices[0] = -1;
|
||||
|
||||
if (case_code == 0 || case_code == 255) {
|
||||
// If the case_code is 0 or 255, there is no triangulation to do
|
||||
@ -398,15 +397,9 @@ void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned i
|
||||
if (present) {
|
||||
Vector3i cache_pos = pos + L::dir_to_prev_vec(reuse_dir);
|
||||
ReuseCell &prev_cell = get_reuse_cell(cache_pos);
|
||||
|
||||
if (prev_cell.case_index == 0 || prev_cell.case_index == 255) {
|
||||
// TODO I don't think this can happen for non-corner vertices.
|
||||
cell_vertex_indices[i] = -1;
|
||||
} else {
|
||||
// Will reuse a previous vertice
|
||||
cell_vertex_indices[i] = prev_cell.vertices[reuse_vertex_index];
|
||||
}
|
||||
}
|
||||
|
||||
if (!present || cell_vertex_indices[i] == -1) {
|
||||
// Going to create a new vertice
|
||||
@ -435,8 +428,7 @@ void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned i
|
||||
|
||||
if (reuse_dir & 8) {
|
||||
// Store the generated vertex so that other cells can reuse it.
|
||||
ReuseCell &rc = get_reuse_cell(pos);
|
||||
rc.vertices[reuse_vertex_index] = cell_vertex_indices[i];
|
||||
current_reuse_cell.vertices[reuse_vertex_index] = cell_vertex_indices[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -458,8 +450,7 @@ void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned i
|
||||
|
||||
cell_vertex_indices[i] = emit_vertex(primary, normal, border_mask, secondary);
|
||||
|
||||
ReuseCell &rc = get_reuse_cell(pos);
|
||||
rc.vertices[0] = cell_vertex_indices[i];
|
||||
current_reuse_cell.vertices[0] = cell_vertex_indices[i];
|
||||
|
||||
} else {
|
||||
// The vertex is either on p0 or p1
|
||||
@ -476,15 +467,8 @@ void VoxelMesherTransvoxel::build_internal(const VoxelBuffer &voxels, unsigned i
|
||||
if (present) {
|
||||
Vector3i cache_pos = pos + L::dir_to_prev_vec(reuse_dir);
|
||||
ReuseCell prev_cell = get_reuse_cell(cache_pos);
|
||||
|
||||
// The previous cell might not have any geometry, and we
|
||||
// might therefore have to create a new vertex anyway.
|
||||
if (prev_cell.case_index == 0 || prev_cell.case_index == 255) {
|
||||
cell_vertex_indices[i] = -1;
|
||||
} else {
|
||||
cell_vertex_indices[i] = prev_cell.vertices[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (!present || cell_vertex_indices[i] < 0) {
|
||||
|
||||
@ -747,6 +731,10 @@ void VoxelMesherTransvoxel::build_transition(const VoxelBuffer &p_voxels, unsign
|
||||
case_code |= (sign(cell_samples[3]) << 7);
|
||||
case_code |= (sign(cell_samples[4]) << 8);
|
||||
|
||||
ReuseTransitionCell ¤t_reuse_cell = get_reuse_cell_2d(fx, fy);
|
||||
// Mark current cell unused for now
|
||||
current_reuse_cell.vertices[0] = -1;
|
||||
|
||||
if (case_code == 0 || case_code == 511) {
|
||||
// The cell contains no triangles.
|
||||
continue;
|
||||
@ -754,8 +742,6 @@ void VoxelMesherTransvoxel::build_transition(const VoxelBuffer &p_voxels, unsign
|
||||
|
||||
CRASH_COND(case_code > 511);
|
||||
|
||||
get_reuse_cell_2d(fx, fy).case_index = case_code;
|
||||
|
||||
const uint8_t cell_class = Transvoxel::get_transition_cell_class(case_code);
|
||||
|
||||
CRASH_COND((cell_class & 0x7f) > 55);
|
||||
@ -813,17 +799,10 @@ void VoxelMesherTransvoxel::build_transition(const VoxelBuffer &p_voxels, unsign
|
||||
if (present) {
|
||||
// The previous cell is available. Retrieve the cached cell
|
||||
// from which to retrieve the reused vertex index from.
|
||||
|
||||
const ReuseTransitionCell &prev = get_reuse_cell_2d(fx - (reuse_direction & 1), fy - ((reuse_direction >> 1) & 1));
|
||||
|
||||
if (prev.case_index == 0 || prev.case_index == 511) {
|
||||
// Previous cell does not contain any geometry.
|
||||
cell_vertex_indices[i] = -1;
|
||||
} else {
|
||||
// Reuse the vertex index from the previous cell.
|
||||
cell_vertex_indices[i] = prev.vertices[vertex_index_to_reuse_or_create];
|
||||
}
|
||||
}
|
||||
|
||||
if (!present || cell_vertex_indices[i] == -1) {
|
||||
// Going to create a new vertex
|
||||
@ -878,18 +857,10 @@ void VoxelMesherTransvoxel::build_transition(const VoxelBuffer &p_voxels, unsign
|
||||
if (present) {
|
||||
// The previous cell is available. Retrieve the cached cell
|
||||
// from which to retrieve the reused vertex index from.
|
||||
|
||||
const ReuseTransitionCell &prev = get_reuse_cell_2d(fx - (reuse_direction & 1), fy - ((reuse_direction >> 1) & 1));
|
||||
|
||||
if (prev.case_index == 0 || prev.case_index == 511) {
|
||||
// Previous cell had no geometry
|
||||
cell_vertex_indices[i] = -1;
|
||||
|
||||
} else {
|
||||
// Reuse the vertex index from the previous cell.
|
||||
cell_vertex_indices[i] = prev.vertices[vertex_index_to_reuse_or_create];
|
||||
}
|
||||
}
|
||||
|
||||
if (!present || cell_vertex_indices[i] == -1) {
|
||||
// Going to create a new vertex
|
||||
@ -942,15 +913,21 @@ void VoxelMesherTransvoxel::reset_reuse_cells(Vector3i block_size) {
|
||||
_block_size = block_size;
|
||||
unsigned int deck_area = block_size.x * block_size.y;
|
||||
for (int i = 0; i < _cache.size(); ++i) {
|
||||
_cache[i].clear();
|
||||
_cache[i].resize(deck_area);
|
||||
std::vector<ReuseCell> &deck = _cache[i];
|
||||
deck.resize(deck_area);
|
||||
for (int j = 0; j < deck.size(); ++j) {
|
||||
deck[j].vertices.fill(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VoxelMesherTransvoxel::reset_reuse_cells_2d(Vector3i block_size) {
|
||||
for (int i = 0; i < _cache_2d.size(); ++i) {
|
||||
_cache_2d[i].clear();
|
||||
_cache_2d[i].resize(block_size.x);
|
||||
std::vector<ReuseTransitionCell> &row = _cache_2d[i];
|
||||
row.resize(block_size.x);
|
||||
for (int j = 0; j < row.size(); ++j) {
|
||||
row[j].vertices.fill(-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,18 +25,10 @@ protected:
|
||||
private:
|
||||
struct ReuseCell {
|
||||
FixedArray<int, 4> vertices;
|
||||
int case_index = 0;
|
||||
ReuseCell() {
|
||||
vertices.fill(-1);
|
||||
}
|
||||
};
|
||||
|
||||
struct ReuseTransitionCell {
|
||||
FixedArray<int, 12> vertices;
|
||||
int case_index = 0;
|
||||
ReuseTransitionCell() {
|
||||
vertices.fill(-1);
|
||||
}
|
||||
};
|
||||
|
||||
struct TransitionVoxels {
|
||||
|
Loading…
x
Reference in New Issue
Block a user