diff options
author | Jacques Lucke <jacques@blender.org> | 2022-08-31 11:28:35 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-08-31 11:28:35 +0300 |
commit | 6177d9f0c8981837491f5153e3aab4ec0d04db44 (patch) | |
tree | 23c5807698103ad908ec3b63f280ba5f47b2fe27 /source/blender/geometry/intern/reverse_uv_sampler.cc | |
parent | e2deee73abf3fe5885aefa131c337f3b0d6762d6 (diff) |
Fix: reverse uv lookup fails due to floating point accuracy issues
The case when the query uv is almost on an edge but outside of any
triangle was handled before. Now the case where the query uv is
almost on an edge but inside more than one triangle is handled as well.
Diffstat (limited to 'source/blender/geometry/intern/reverse_uv_sampler.cc')
-rw-r--r-- | source/blender/geometry/intern/reverse_uv_sampler.cc | 18 |
1 files changed, 14 insertions, 4 deletions
diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc index 39fec40333c..f66e4a3ac2e 100644 --- a/source/blender/geometry/intern/reverse_uv_sampler.cc +++ b/source/blender/geometry/intern/reverse_uv_sampler.cc @@ -50,6 +50,11 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const float3 best_bary_weights; const MLoopTri *best_looptri; + /* The distance to an edge that is allowed to be inside or outside the triangle. Without this, + * the lookup can fail for floating point accuracy reasons when the uv is almost exact on an + * edge. */ + const float edge_epsilon = 0.00001f; + for (const int looptri_index : looptri_indices) { const MLoopTri &looptri = looptris_[looptri_index]; const float2 &uv_0 = uv_map_[looptri.tri[0]]; @@ -68,8 +73,12 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const const float dist = MAX3(x_dist, y_dist, z_dist); if (dist <= 0.0f && best_dist <= 0.0f) { - /* The uv sample is in multiple triangles. */ - return Result{ResultType::Multiple}; + const float worse_dist = std::max(dist, best_dist); + /* Allow ignoring multiple triangle intersections if the uv is almost exactly on an edge. */ + if (worse_dist < -edge_epsilon) { + /* The uv sample is in multiple triangles. */ + return Result{ResultType::Multiple}; + } } if (dist < best_dist) { @@ -79,8 +88,9 @@ ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const } } - /* Allow for a small epsilon in case the uv is on th edge. */ - if (best_dist < 0.00001f) { + /* Allow using the closest (but not intersecting) triangle if the uv is almost exactly on an + * edge. */ + if (best_dist < edge_epsilon) { return Result{ResultType::Ok, best_looptri, math::clamp(best_bary_weights, 0.0f, 1.0f)}; } |