diff options
author | Jacques Lucke <jacques@blender.org> | 2022-06-05 13:14:13 +0300 |
---|---|---|
committer | Jacques Lucke <jacques@blender.org> | 2022-06-05 13:14:32 +0300 |
commit | 899ec8b6b8035bde44d49d228c30698499a87080 (patch) | |
tree | 1c0acb436e033eb5551531774ffb0ff9a57dd268 /source/blender/geometry | |
parent | 176d7bcc2eb47b9820861037f90a7fb26de8c9a0 (diff) |
Curves: use uv coordinates to attach curves to mesh
This implements the new way to attach curves to a mesh surface using
a uv map (based on the recent discussion in T95776).
The curves data block now not only stores a reference to the surface object
but also a name of a uv map on that object. Having a uv map is optional
for most operations, but it will be required later for animation (when the
curves are supposed to be deformed based on deformation of the surface).
The "Empty Hair" operator in the Add menu sets the uv map name automatically
if possible. It's possible to start working without a uv map and to attach the
curves to a uv map later on. It's also possible to reattach the curves to a new
uv map using the "Curves > Snap to Nearest Surface" operator in curves sculpt
mode.
Note, the implementation to do the reverse lookup from uv to a position on the
surface is trivial and inefficient now. A more efficient data structure will be
implemented separately soon.
Differential Revision: https://developer.blender.org/D15125
Diffstat (limited to 'source/blender/geometry')
-rw-r--r-- | source/blender/geometry/CMakeLists.txt | 2 | ||||
-rw-r--r-- | source/blender/geometry/GEO_reverse_uv_sampler.hh | 42 | ||||
-rw-r--r-- | source/blender/geometry/intern/reverse_uv_sampler.cc | 32 |
3 files changed, 76 insertions, 0 deletions
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt index 010c327d482..1916c5f91f3 100644 --- a/source/blender/geometry/CMakeLists.txt +++ b/source/blender/geometry/CMakeLists.txt @@ -21,6 +21,7 @@ set(SRC intern/point_merge_by_distance.cc intern/realize_instances.cc intern/resample_curves.cc + intern/reverse_uv_sampler.cc intern/uv_parametrizer.c GEO_mesh_merge_by_distance.hh @@ -29,6 +30,7 @@ set(SRC GEO_point_merge_by_distance.hh GEO_realize_instances.hh GEO_resample_curves.hh + GEO_reverse_uv_sampler.hh GEO_uv_parametrizer.h ) diff --git a/source/blender/geometry/GEO_reverse_uv_sampler.hh b/source/blender/geometry/GEO_reverse_uv_sampler.hh new file mode 100644 index 00000000000..d392b65eaf4 --- /dev/null +++ b/source/blender/geometry/GEO_reverse_uv_sampler.hh @@ -0,0 +1,42 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include <optional> + +#include "BLI_math_vector.hh" +#include "BLI_span.hh" + +#include "DNA_meshdata_types.h" + +namespace blender::geometry { + +/** + * Can find the polygon/triangle that maps to a specific uv coordinate. + * + * \note this uses a trivial implementation currently that has to be replaced. + */ +class ReverseUVSampler { + private: + const Span<float2> uv_map_; + const Span<MLoopTri> looptris_; + + public: + ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris); + + enum class ResultType { + None, + Ok, + Multiple, + }; + + struct Result { + ResultType type = ResultType::None; + const MLoopTri *looptri = nullptr; + float3 bary_weights; + }; + + Result sample(const float2 &query_uv) const; +}; + +} // namespace blender::geometry diff --git a/source/blender/geometry/intern/reverse_uv_sampler.cc b/source/blender/geometry/intern/reverse_uv_sampler.cc new file mode 100644 index 00000000000..9aa98895a86 --- /dev/null +++ b/source/blender/geometry/intern/reverse_uv_sampler.cc @@ -0,0 +1,32 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "GEO_reverse_uv_sampler.hh" + +#include "BLI_math_geom.h" + +namespace blender::geometry { + +ReverseUVSampler::ReverseUVSampler(const Span<float2> uv_map, const Span<MLoopTri> looptris) + : uv_map_(uv_map), looptris_(looptris) +{ +} + +ReverseUVSampler::Result ReverseUVSampler::sample(const float2 &query_uv) const +{ + for (const MLoopTri &looptri : looptris_) { + const float2 &uv0 = uv_map_[looptri.tri[0]]; + const float2 &uv1 = uv_map_[looptri.tri[1]]; + const float2 &uv2 = uv_map_[looptri.tri[2]]; + float3 bary_weights; + if (!barycentric_coords_v2(uv0, uv1, uv2, query_uv, bary_weights)) { + continue; + } + if (IN_RANGE_INCL(bary_weights.x, 0.0f, 1.0f) && IN_RANGE_INCL(bary_weights.y, 0.0f, 1.0f) && + IN_RANGE_INCL(bary_weights.z, 0.0f, 1.0f)) { + return Result{ResultType::Ok, &looptri, bary_weights}; + } + } + return Result{}; +} + +} // namespace blender::geometry |