Fix #138447: Invalid voxel size due to arbitrary threshold

OpenVDB has a voxel size limit defined by the determinant of the grid
transform, which is equivalent to a uniform voxel size of
`sqrt3(3e-15) ~= 1.44e-5`.
The `mesh_to_density_grid` function was using an arbitrary threshold of
`1.0e-5` for the uniform voxel size.
In this case the voxel size is `~1.343e-5` so it passes the Blender
threshold but crashes in OpenVDB.

This fix adds some convenience functions to check for valid grid voxel
size and transform based on the same determinant metric. This is now
employed consistently in the mesh_to_density_grid, mesh_to_sdf_grid, and
points_to_sdf_grid functions to avoid exceptions in OpenVDB.

MOD_volume_to_mesh, node_geo_volume_to_mesh, BKE_mesh_remesh_voxel have
not been modified, since they have their own error checks with larger
thresholds.

Pull Request: https://projects.blender.org/blender/blender/pulls/138481
This commit is contained in:
Lukas Tönne
2025-05-06 16:08:24 +02:00
parent ff240d9117
commit ce8f30f92c
7 changed files with 22 additions and 7 deletions

View File

@@ -13,6 +13,7 @@
#include <optional>
#include "BLI_bounds_types.hh"
#include "BLI_math_matrix_types.hh"
#include "BLI_math_vector_types.hh"
#include "BLI_memory_counter_fwd.hh"
#include "BLI_string_ref.hh"
@@ -118,6 +119,8 @@ void BKE_volume_grid_add(Volume *volume, const blender::bke::VolumeGridData &gri
* OpenVDB crashes when the determinant of the transform matrix becomes too small.
*/
bool BKE_volume_grid_determinant_valid(double determinant);
bool BKE_volume_voxel_size_valid(const blender::float3 &voxel_size);
bool BKE_volume_grid_transform_valid(const blender::float4x4 &transform);
/* Simplify */
int BKE_volume_simplify_level(const Depsgraph *depsgraph);

View File

@@ -1029,6 +1029,16 @@ bool BKE_volume_grid_determinant_valid(const double determinant)
#endif
}
bool BKE_volume_voxel_size_valid(const float3 &voxel_size)
{
return BKE_volume_grid_determinant_valid(voxel_size[0] * voxel_size[1] * voxel_size[2]);
}
bool BKE_volume_grid_transform_valid(const float4x4 &transform)
{
return BKE_volume_grid_determinant_valid(blender::math::determinant(transform));
}
int BKE_volume_simplify_level(const Depsgraph *depsgraph)
{
if (DEG_get_mode(depsgraph) != DAG_EVAL_RENDER) {

View File

@@ -119,7 +119,7 @@ static openvdb::FloatGrid::Ptr mesh_to_density_grid_impl(
const float interior_band_width,
const float density)
{
if (voxel_size < 1e-5f) {
if (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
return nullptr;
}
@@ -174,7 +174,7 @@ bke::VolumeGrid<float> mesh_to_sdf_grid(const Span<float3> positions,
const float voxel_size,
const float half_band_width)
{
if (voxel_size <= 0.0f || half_band_width <= 0.0f) {
if (!BKE_volume_voxel_size_valid(float3(voxel_size)) || half_band_width <= 0.0f) {
return {};
}

View File

@@ -60,6 +60,10 @@ static openvdb::FloatGrid::Ptr points_to_sdf_grid_impl(const Span<float3> positi
const Span<float> radii,
const float voxel_size)
{
if (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
return nullptr;
}
/* Create a new grid that will be filled. #ParticlesToLevelSet requires
* the background value to be positive */
openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f);

View File

@@ -61,8 +61,7 @@ static bke::VolumeGrid<float> points_to_grid(const GeometrySet &geometry_set,
const Field<float> &radius_field,
const float voxel_size)
{
const double determinant = std::pow(double(voxel_size), 3.0);
if (!BKE_volume_grid_determinant_valid(determinant)) {
if (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
return {};
}

View File

@@ -108,8 +108,7 @@ static void initialize_volume_component_from_points(GeoNodeExecParams &params,
BLI_assert_msg(0, "Unknown volume resolution mode");
}
const double determinant = std::pow(double(voxel_size), 3.0);
if (!BKE_volume_grid_determinant_valid(determinant)) {
if (!BKE_volume_voxel_size_valid(float3(voxel_size))) {
return;
}

View File

@@ -136,7 +136,7 @@ static void node_geo_exec(GeoNodeExecParams params)
}
const double3 scale_fac = double3(bounds_max - bounds_min) / double3(resolution - 1);
if (!BKE_volume_grid_determinant_valid(scale_fac.x * scale_fac.y * scale_fac.z)) {
if (!BKE_volume_voxel_size_valid(float3(scale_fac))) {
params.error_message_add(NodeWarningType::Warning,
TIP_("Volume scale is lower than permitted by OpenVDB"));
params.set_default_remaining_outputs();