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/editors/sculpt_paint | |
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/editors/sculpt_paint')
-rw-r--r-- | source/blender/editors/sculpt_paint/CMakeLists.txt | 1 | ||||
-rw-r--r-- | source/blender/editors/sculpt_paint/curves_sculpt_add.cc | 51 |
2 files changed, 41 insertions, 11 deletions
diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index dfd8f8b1bb9..9a9efc9e6cf 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -10,6 +10,7 @@ set(INC ../../depsgraph ../../draw ../../functions + ../../geometry ../../gpu ../../imbuf ../../makesdna diff --git a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc index 390f142ac0f..5f168bd4e05 100644 --- a/source/blender/editors/sculpt_paint/curves_sculpt_add.cc +++ b/source/blender/editors/sculpt_paint/curves_sculpt_add.cc @@ -19,6 +19,7 @@ #include "BKE_context.h" #include "BKE_curves.hh" #include "BKE_curves_utils.hh" +#include "BKE_geometry_set.hh" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_paint.h" @@ -95,6 +96,7 @@ struct AddOperationExecutor { Mesh *surface_ = nullptr; Span<MLoopTri> surface_looptris_; Span<float3> corner_normals_su_; + VArray_Span<float2> surface_uv_map_; const CurvesSculpt *curves_sculpt_ = nullptr; const Brush *brush_ = nullptr; @@ -114,6 +116,7 @@ struct AddOperationExecutor { /** Various matrices to convert between coordinate spaces. */ float4x4 curves_to_world_mat_; + float4x4 curves_to_surface_mat_; float4x4 world_to_curves_mat_; float4x4 world_to_surface_mat_; float4x4 surface_to_world_mat_; @@ -165,6 +168,7 @@ struct AddOperationExecutor { world_to_surface_mat_ = surface_to_world_mat_.inverted(); surface_to_curves_mat_ = world_to_curves_mat_ * surface_to_world_mat_; surface_to_curves_normal_mat_ = surface_to_curves_mat_.inverted().transposed(); + curves_to_surface_mat_ = curves_to_world_mat_ * world_to_surface_mat_; if (!CustomData_has_layer(&surface_->ldata, CD_NORMAL)) { BKE_mesh_calc_normals_split(surface_); @@ -208,6 +212,15 @@ struct AddOperationExecutor { surface_looptris_ = {BKE_mesh_runtime_looptri_ensure(surface_), BKE_mesh_runtime_looptri_len(surface_)}; + if (curves_id_->surface_uv_map != nullptr) { + MeshComponent surface_component; + surface_component.replace(surface_, GeometryOwnershipType::ReadOnly); + surface_uv_map_ = surface_component + .attribute_try_get_for_read(curves_id_->surface_uv_map, + ATTR_DOMAIN_CORNER) + .typed<float2>(); + } + /* Sample points on the surface using one of multiple strategies. */ AddedPoints added_points; if (add_amount_ == 1) { @@ -652,7 +665,9 @@ struct AddOperationExecutor { } Array<float3> new_normals_su = this->compute_normals_for_added_curves_su(added_points); - this->initialize_surface_attachment(added_points); + if (!surface_uv_map_.is_empty()) { + this->initialize_surface_attachment(added_points); + } this->fill_new_selection(); @@ -775,14 +790,18 @@ struct AddOperationExecutor { void initialize_surface_attachment(const AddedPoints &added_points) { - MutableSpan<int> surface_triangle_indices = curves_->surface_triangle_indices_for_write(); - MutableSpan<float2> surface_triangle_coords = curves_->surface_triangle_coords_for_write(); + MutableSpan<float2> surface_uv_coords = curves_->surface_uv_coords_for_write(); threading::parallel_for( added_points.bary_coords.index_range(), 1024, [&](const IndexRange range) { for (const int i : range) { const int curve_i = tot_old_curves_ + i; - surface_triangle_indices[curve_i] = added_points.looptri_indices[i]; - surface_triangle_coords[curve_i] = float2(added_points.bary_coords[i]); + const MLoopTri &looptri = surface_looptris_[added_points.looptri_indices[i]]; + const float2 &uv0 = surface_uv_map_[looptri.tri[0]]; + const float2 &uv1 = surface_uv_map_[looptri.tri[1]]; + const float2 &uv2 = surface_uv_map_[looptri.tri[2]]; + const float3 &bary_coords = added_points.bary_coords[i]; + const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2); + surface_uv_coords[curve_i] = uv; } }); } @@ -820,8 +839,6 @@ struct AddOperationExecutor { const Span<float> new_lengths_cu) { MutableSpan<float3> positions_cu = curves_->positions_for_write(); - const VArray_Span<int> surface_triangle_indices{curves_->surface_triangle_indices()}; - const Span<float2> surface_triangle_coords = curves_->surface_triangle_coords(); threading::parallel_for( added_points.bary_coords.index_range(), 256, [&](const IndexRange range) { @@ -846,10 +863,22 @@ struct AddOperationExecutor { for (const NeighborInfo &neighbor : neighbors) { const int neighbor_curve_i = neighbor.index; - const int neighbor_looptri_index = surface_triangle_indices[neighbor_curve_i]; - - float3 neighbor_bary_coord{surface_triangle_coords[neighbor_curve_i]}; - neighbor_bary_coord.z = 1.0f - neighbor_bary_coord.x - neighbor_bary_coord.y; + const float3 &neighbor_first_pos_cu = + positions_cu[curves_->offsets()[neighbor_curve_i]]; + const float3 neighbor_first_pos_su = curves_to_surface_mat_ * neighbor_first_pos_cu; + + BVHTreeNearest nearest; + nearest.dist_sq = FLT_MAX; + BLI_bvhtree_find_nearest(surface_bvh_.tree, + neighbor_first_pos_su, + &nearest, + surface_bvh_.nearest_callback, + &surface_bvh_); + const int neighbor_looptri_index = nearest.index; + const MLoopTri &neighbor_looptri = surface_looptris_[neighbor_looptri_index]; + + const float3 neighbor_bary_coord = this->get_bary_coords( + *surface_, neighbor_looptri, nearest.co); const float3 neighbor_normal_su = this->compute_point_normal_su( neighbor_looptri_index, neighbor_bary_coord); |