Skip to content

Commit

Permalink
Added option to clamp transvoxel edge vertices distance to corners
Browse files Browse the repository at this point in the history
  • Loading branch information
Zylann committed Jun 2, 2024
1 parent 6a3f753 commit 501907b
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 27 deletions.
3 changes: 3 additions & 0 deletions doc/classes/VoxelMesherTransvoxel.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
<members>
<member name="deep_sampling_enabled" type="bool" setter="set_deep_sampling_enabled" getter="is_deep_sampling_enabled" default="false">
</member>
<member name="edge_clamp_margin" type="float" setter="set_edge_clamp_margin" getter="get_edge_clamp_margin" default="0.02">
When a marching cube cell is computed, vertices may be placed anywhere on edges of the cell, including very close to corners. This can lead to very thin or small triangles, which can be a problem notably for some physics engines. this margin is the minimum distance from corners, below which vertices will be clamped to it. Increasing this value might reduce quality of the mesh introducing small ridges.
</member>
<member name="mesh_optimization_enabled" type="bool" setter="set_mesh_optimization_enabled" getter="is_mesh_optimization_enabled" default="false">
</member>
<member name="mesh_optimization_error_threshold" type="float" setter="set_mesh_optimization_error_threshold" getter="get_mesh_optimization_error_threshold" default="0.005">
Expand Down
3 changes: 3 additions & 0 deletions doc/source/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ Semver is not yet in place, so each version can have breaking changes, although
-----------------------------------------

- Added project setting `voxel/ownership_checks` to turn off sanity checks done by certain virtual functions that pass an object (such as `_generate_block`). Relevant for C#, where the garbage collection model prevents such checks from working properly.
- `VoxelMesherTransvoxel`:
- added `edge_clamp_margin` property to prevent triangles from becoming too small, at the cost of slightly lower fidelity
- reverted removal of degenerate triangles
- `VoxelViewer`: added `view_distance_vertical_ratio` to use different vertical view distance proportionally to the horizontal distance

- Fixes
Expand Down
56 changes: 35 additions & 21 deletions meshers/transvoxel/transvoxel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
#include "../../util/godot/core/sort_array.h"
#include "../../util/math/conv.h"
#include "../../util/math/funcs.h"
#include "../../util/math/triangle.h"
#include "../../util/profiling.h"
#include "transvoxel_tables.cpp"

Expand Down Expand Up @@ -366,10 +365,13 @@ void build_regular_mesh(
Cache &cache,
MeshArrays &output,
const IDeepSDFSampler *deep_sdf_sampler,
StdVector<CellInfo> *cell_info
StdVector<CellInfo> *cell_info,
const float edge_clamp_margin
) {
ZN_PROFILE_SCOPE();

const float edge_clamp_margin_max = 1.f - edge_clamp_margin;

// This function has some comments as quotes from the Transvoxel paper.

const Vector3i block_size = block_size_with_padding - Vector3iUtil::create(MIN_PADDING + MAX_PADDING);
Expand Down Expand Up @@ -552,7 +554,8 @@ void build_regular_mesh(
// We use an 8-bit fraction, allowing the new vertex to be located at one of 257 possible
// positions along the edge when both endpoints are included.
// const int t = (sample1 << 8) / (sample1 - sample0);
const float t = sample1 / (sample1 - sample0);
const float t =
math::clamp(sample1 / (sample1 - sample0), edge_clamp_margin, edge_clamp_margin_max);

const Vector3i p0 = corner_positions[v0];
const Vector3i p1 = corner_positions[v1];
Expand Down Expand Up @@ -740,7 +743,7 @@ void build_regular_mesh(

} // for each cell vertex

uint32_t effective_triangle_count = triangle_count;
const uint32_t effective_triangle_count = triangle_count;

for (int t = 0; t < triangle_count; ++t) {
const int t0 = t * 3;
Expand Down Expand Up @@ -780,13 +783,13 @@ void build_regular_mesh(
// About Jolt re-indexing meshes, see PR (abandoned?):
// https://github.com/godotengine/godot/pull/72868
//
const Vector3f p0 = output.vertices[i0];
const Vector3f p1 = output.vertices[i1];
const Vector3f p2 = output.vertices[i2];
if (math::is_triangle_degenerate_approx(p0, p1, p2, 0.000001f)) {
--effective_triangle_count;
continue;
}
// const Vector3f p0 = output.vertices[i0];
// const Vector3f p1 = output.vertices[i1];
// const Vector3f p2 = output.vertices[i2];
// if (math::is_triangle_degenerate_approx(p0, p1, p2, 0.000001f)) {
// --effective_triangle_count;
// continue;
// }
}

output.indices.push_back(i0);
Expand Down Expand Up @@ -915,11 +918,14 @@ void build_transition_mesh(
const int lod_index,
TexturingMode texturing_mode,
Cache &cache,
MeshArrays &output
MeshArrays &output,
const float edge_clamp_margin
) {
// From this point, we expect the buffer to contain allocated data.
// This function has some comments as quotes from the Transvoxel paper.

const float edge_clamp_margin_max = 1.f - edge_clamp_margin;

const Vector3i block_size_without_padding =
block_size_with_padding - Vector3iUtil::create(MIN_PADDING + MAX_PADDING);
const Vector3i block_size_scaled = block_size_without_padding << lod_index;
Expand Down Expand Up @@ -1180,7 +1186,7 @@ void build_transition_mesh(
// We use an 8-bit fraction, allowing the new vertex to be located at one of 257 possible
// positions along the edge when both endpoints are included.
// const int t = (sample_b << 8) / (sample_b - sample_a);
const float t = sample_b / (sample_b - sample_a);
const float t = math::clamp(sample_b / (sample_b - sample_a), edge_clamp_margin, edge_clamp_margin_max);

const float t0 = t; // static_cast<float>(t) / 256.f;
const float t1 = 1.f - t; // static_cast<float>(0x100 - t) / 256.f;
Expand Down Expand Up @@ -1486,7 +1492,8 @@ DefaultTextureIndicesData build_regular_mesh(
Cache &cache,
MeshArrays &output,
const IDeepSDFSampler *deep_sdf_sampler,
StdVector<CellInfo> *cell_infos
StdVector<CellInfo> *cell_infos,
const float edge_clamp_margin
) {
ZN_PROFILE_SCOPE();
// From this point, we expect the buffer to contain allocated data in the relevant channels.
Expand Down Expand Up @@ -1542,7 +1549,8 @@ DefaultTextureIndicesData build_regular_mesh(
cache,
output,
deep_sdf_sampler,
cell_infos
cell_infos,
edge_clamp_margin
);
} break;

Expand All @@ -1558,7 +1566,8 @@ DefaultTextureIndicesData build_regular_mesh(
cache,
output,
deep_sdf_sampler,
cell_infos
cell_infos,
edge_clamp_margin
);
} break;

Expand All @@ -1577,7 +1586,8 @@ DefaultTextureIndicesData build_regular_mesh(
cache,
output,
deep_sdf_sampler,
cell_infos
cell_infos,
edge_clamp_margin
);
} break;

Expand All @@ -1602,7 +1612,8 @@ void build_transition_mesh(
const TexturingMode texturing_mode,
Cache &cache,
MeshArrays &output,
DefaultTextureIndicesData default_texture_indices_data
DefaultTextureIndicesData default_texture_indices_data,
const float edge_clamp_margin
) {
ZN_PROFILE_SCOPE();
// From this point, we expect the buffer to contain allocated data in the relevant channels.
Expand Down Expand Up @@ -1666,7 +1677,8 @@ void build_transition_mesh(
lod_index,
texturing_mode,
cache,
output
output,
edge_clamp_margin
);
} break;

Expand All @@ -1681,7 +1693,8 @@ void build_transition_mesh(
lod_index,
texturing_mode,
cache,
output
output,
edge_clamp_margin
);
} break;

Expand All @@ -1696,7 +1709,8 @@ void build_transition_mesh(
lod_index,
texturing_mode,
cache,
output
output,
edge_clamp_margin
);
} break;

Expand Down
6 changes: 4 additions & 2 deletions meshers/transvoxel/transvoxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,8 @@ DefaultTextureIndicesData build_regular_mesh(
Cache &cache,
MeshArrays &output,
const IDeepSDFSampler *deep_sdf_sampler,
StdVector<CellInfo> *cell_infos
StdVector<CellInfo> *cell_infos,
const float edge_clamp_margin
);

void build_transition_mesh(
Expand All @@ -183,7 +184,8 @@ void build_transition_mesh(
const TexturingMode texturing_mode,
Cache &cache,
MeshArrays &output,
DefaultTextureIndicesData default_texture_indices_data
DefaultTextureIndicesData default_texture_indices_data,
const float edge_clamp_margin
);

} // namespace zylann::voxel::transvoxel
Expand Down
25 changes: 21 additions & 4 deletions meshers/transvoxel/voxel_mesher_transvoxel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher
tls_cache,
mesh_arrays,
&ds,
cell_infos
cell_infos,
_edge_clamp_margin
);
} else {
default_texture_indices_data = transvoxel::build_regular_mesh(
Expand All @@ -300,7 +301,8 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher
tls_cache,
mesh_arrays,
nullptr,
cell_infos
cell_infos,
_edge_clamp_margin
);
}

Expand Down Expand Up @@ -347,7 +349,8 @@ void VoxelMesherTransvoxel::build(VoxelMesher::Output &output, const VoxelMesher
static_cast<transvoxel::TexturingMode>(_texture_mode),
tls_cache,
*combined_mesh_arrays,
default_texture_indices_data
default_texture_indices_data,
_edge_clamp_margin
);
}
}
Expand Down Expand Up @@ -394,7 +397,8 @@ Ref<ArrayMesh> VoxelMesherTransvoxel::build_transition_mesh(Ref<godot::VoxelBuff
static_cast<transvoxel::TexturingMode>(_texture_mode),
s_cache,
s_mesh_arrays,
default_texture_indices_data
default_texture_indices_data,
_edge_clamp_margin
);

Ref<ArrayMesh> mesh;
Expand Down Expand Up @@ -465,6 +469,14 @@ Ref<ShaderMaterial> VoxelMesherTransvoxel::get_default_lod_material() const {
return g_minimal_shader_material;
}

void VoxelMesherTransvoxel::set_edge_clamp_margin(float margin) {
_edge_clamp_margin = math::clamp(margin, 0.f, 0.5f);
}

float VoxelMesherTransvoxel::get_edge_clamp_margin() const {
return _edge_clamp_margin;
}

void VoxelMesherTransvoxel::_bind_methods() {
using Self = VoxelMesherTransvoxel;

Expand Down Expand Up @@ -494,6 +506,9 @@ void VoxelMesherTransvoxel::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_transitions_enabled", "enabled"), &Self::set_transitions_enabled);
ClassDB::bind_method(D_METHOD("get_transitions_enabled"), &Self::get_transitions_enabled);

ClassDB::bind_method(D_METHOD("get_edge_clamp_margin"), &Self::get_edge_clamp_margin);
ClassDB::bind_method(D_METHOD("set_edge_clamp_margin", "margin"), &Self::set_edge_clamp_margin);

ADD_PROPERTY(
PropertyInfo(Variant::INT, "texturing_mode", PROPERTY_HINT_ENUM, "None,4-blend over 16 textures (4 bits)"),
"set_texturing_mode",
Expand Down Expand Up @@ -529,6 +544,8 @@ void VoxelMesherTransvoxel::_bind_methods() {
PropertyInfo(Variant::BOOL, "transitions_enabled"), "set_transitions_enabled", "get_transitions_enabled"
);

ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "edge_clamp_margin"), "set_edge_clamp_margin", "get_edge_clamp_margin");

BIND_ENUM_CONSTANT(TEXTURES_NONE);
// TODO Rename MIXEL
BIND_ENUM_CONSTANT(TEXTURES_BLEND_4_OVER_16);
Expand Down
9 changes: 9 additions & 0 deletions meshers/transvoxel/voxel_mesher_transvoxel.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ class VoxelMesherTransvoxel : public VoxelMesher {
void set_transitions_enabled(bool enable);
bool get_transitions_enabled() const;

void set_edge_clamp_margin(float margin);
float get_edge_clamp_margin() const;

Ref<ShaderMaterial> get_default_lod_material() const override;

// Internal
Expand Down Expand Up @@ -93,6 +96,12 @@ class VoxelMesherTransvoxel : public VoxelMesher {
// because voxel data shared between threads will have to be accessed randomly over denser data sets.
bool _deep_sampling_enabled = false;

// When a marching cube cell is computed, vertices may be placed anywhere on edges of the cell, including very close
// to corners. This can lead to very thin or small triangles, which can be a problem notably for collision. this
// margin is the minimum distance from corners, below which vertices will be clamped to it. Increasing this value
// reduces quality of the mesh.
float _edge_clamp_margin = 0.02f;

bool _transitions_enabled = true;
};

Expand Down

0 comments on commit 501907b

Please sign in to comment.