Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Lucke <jacques@blender.org>2022-07-05 16:37:34 +0300
committerJacques Lucke <jacques@blender.org>2022-07-05 16:37:34 +0300
commitd4099465cddc2d3ec3653220f6b775ba3ffb3ea0 (patch)
tree614fae4caba9d16c9e784eb23eb7d2600d5bd665 /source/blender/editors/curves
parentb98d116257aee64f2e79490c89f4aa7bcca4a9cd (diff)
Cleanup: extract function to snap curves to surface
This makes it possible to use this function without having to call an operator. This is currently used by D14864.
Diffstat (limited to 'source/blender/editors/curves')
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc271
1 files changed, 143 insertions, 128 deletions
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index aca074a1d61..d9f207103ae 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -517,152 +517,167 @@ static bool snap_curves_to_surface_poll(bContext *C)
return true;
}
+static void snap_curves_to_surface_exec_object(Object &curves_ob,
+ const Object &surface_ob,
+ const AttachMode attach_mode,
+ bool *r_invalid_uvs,
+ bool *r_missing_uvs)
+{
+ Curves &curves_id = *static_cast<Curves *>(curves_ob.data);
+ CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
+
+ Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
+
+ MeshComponent surface_mesh_component;
+ surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly);
+
+ VArraySpan<float2> surface_uv_map;
+ if (curves_id.surface_uv_map != nullptr) {
+ surface_uv_map = surface_mesh_component
+ .attribute_try_get_for_read(
+ curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
+ .typed<float2>();
+ }
+
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
+
+ const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
+ BKE_mesh_runtime_looptri_len(&surface_mesh)};
+
+ const bke::CurvesSurfaceTransforms transforms{curves_ob, &surface_ob};
+
+ switch (attach_mode) {
+ case AttachMode::Nearest: {
+ BVHTreeFromMesh surface_bvh;
+ BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
+ BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+ const float3 old_first_point_pos_su = transforms.curves_to_surface *
+ old_first_point_pos_cu;
+
+ BVHTreeNearest nearest;
+ nearest.index = -1;
+ nearest.dist_sq = FLT_MAX;
+ BLI_bvhtree_find_nearest(surface_bvh.tree,
+ old_first_point_pos_su,
+ &nearest,
+ surface_bvh.nearest_callback,
+ &surface_bvh);
+ const int looptri_index = nearest.index;
+ if (looptri_index == -1) {
+ continue;
+ }
+
+ const float3 new_first_point_pos_su = nearest.co;
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
+ }
+
+ if (!surface_uv_map.is_empty()) {
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+ const int corner0 = looptri.tri[0];
+ const int corner1 = looptri.tri[1];
+ const int corner2 = looptri.tri[2];
+ const float2 &uv0 = surface_uv_map[corner0];
+ const float2 &uv1 = surface_uv_map[corner1];
+ const float2 &uv2 = surface_uv_map[corner2];
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
+ float3 bary_coords;
+ interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
+ const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
+ surface_uv_coords[curve_i] = uv;
+ }
+ }
+ });
+ break;
+ }
+ case AttachMode::Deform: {
+ if (surface_uv_map.is_empty()) {
+ *r_missing_uvs = true;
+ break;
+ }
+ using geometry::ReverseUVSampler;
+ ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
+
+ threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
+ for (const int curve_i : curves_range) {
+ const IndexRange points = curves.points_for_curve(curve_i);
+ const int first_point_i = points.first();
+ const float3 old_first_point_pos_cu = positions_cu[first_point_i];
+
+ const float2 uv = surface_uv_coords[curve_i];
+ ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
+ if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
+ *r_invalid_uvs = true;
+ continue;
+ }
+
+ const MLoopTri &looptri = *lookup_result.looptri;
+ const float3 &bary_coords = lookup_result.bary_weights;
+
+ const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
+ const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
+ const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
+
+ float3 new_first_point_pos_su;
+ interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
+ const float3 new_first_point_pos_cu = transforms.surface_to_curves *
+ new_first_point_pos_su;
+
+ const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
+ for (float3 &pos_cu : positions_cu.slice(points)) {
+ pos_cu += pos_diff_cu;
+ }
+ }
+ });
+ break;
+ }
+ }
+
+ DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+}
+
static int snap_curves_to_surface_exec(bContext *C, wmOperator *op)
{
const AttachMode attach_mode = static_cast<AttachMode>(RNA_enum_get(op->ptr, "attach_mode"));
- std::atomic<bool> found_invalid_uv = false;
+ bool found_invalid_uvs = false;
+ bool found_missing_uvs = false;
CTX_DATA_BEGIN (C, Object *, curves_ob, selected_objects) {
if (curves_ob->type != OB_CURVES) {
continue;
}
Curves &curves_id = *static_cast<Curves *>(curves_ob->data);
- CurvesGeometry &curves = CurvesGeometry::wrap(curves_id.geometry);
if (curves_id.surface == nullptr) {
continue;
}
- Object &surface_ob = *curves_id.surface;
- if (surface_ob.type != OB_MESH) {
+ if (curves_id.surface->type != OB_MESH) {
continue;
}
- Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
-
- MeshComponent surface_mesh_component;
- surface_mesh_component.replace(&surface_mesh, GeometryOwnershipType::ReadOnly);
-
- VArraySpan<float2> surface_uv_map;
- if (curves_id.surface_uv_map != nullptr) {
- surface_uv_map = surface_mesh_component
- .attribute_try_get_for_read(
- curves_id.surface_uv_map, ATTR_DOMAIN_CORNER, CD_PROP_FLOAT2)
- .typed<float2>();
- }
-
- MutableSpan<float3> positions_cu = curves.positions_for_write();
- MutableSpan<float2> surface_uv_coords = curves.surface_uv_coords_for_write();
-
- const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
- BKE_mesh_runtime_looptri_len(&surface_mesh)};
-
- const bke::CurvesSurfaceTransforms transforms{*curves_ob, &surface_ob};
-
- switch (attach_mode) {
- case AttachMode::Nearest: {
- BVHTreeFromMesh surface_bvh;
- BKE_bvhtree_from_mesh_get(&surface_bvh, &surface_mesh, BVHTREE_FROM_LOOPTRI, 2);
- BLI_SCOPED_DEFER([&]() { free_bvhtree_from_mesh(&surface_bvh); });
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
- const float3 old_first_point_pos_su = transforms.curves_to_surface *
- old_first_point_pos_cu;
-
- BVHTreeNearest nearest;
- nearest.index = -1;
- nearest.dist_sq = FLT_MAX;
- BLI_bvhtree_find_nearest(surface_bvh.tree,
- old_first_point_pos_su,
- &nearest,
- surface_bvh.nearest_callback,
- &surface_bvh);
- const int looptri_index = nearest.index;
- if (looptri_index == -1) {
- continue;
- }
-
- const float3 new_first_point_pos_su = nearest.co;
- const float3 new_first_point_pos_cu = transforms.surface_to_curves *
- new_first_point_pos_su;
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
-
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
-
- if (!surface_uv_map.is_empty()) {
- const MLoopTri &looptri = surface_looptris[looptri_index];
- const int corner0 = looptri.tri[0];
- const int corner1 = looptri.tri[1];
- const int corner2 = looptri.tri[2];
- const float2 &uv0 = surface_uv_map[corner0];
- const float2 &uv1 = surface_uv_map[corner1];
- const float2 &uv2 = surface_uv_map[corner2];
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[corner0].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[corner1].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[corner2].v].co;
- float3 bary_coords;
- interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
- const float2 uv = attribute_math::mix3(bary_coords, uv0, uv1, uv2);
- surface_uv_coords[curve_i] = uv;
- }
- }
- });
- break;
- }
- case AttachMode::Deform: {
- if (surface_uv_map.is_empty()) {
- BKE_report(op->reports,
- RPT_ERROR,
- "Curves do not have attachment information that can be used for deformation");
- break;
- }
- using geometry::ReverseUVSampler;
- ReverseUVSampler reverse_uv_sampler{surface_uv_map, surface_looptris};
-
- threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange curves_range) {
- for (const int curve_i : curves_range) {
- const IndexRange points = curves.points_for_curve(curve_i);
- const int first_point_i = points.first();
- const float3 old_first_point_pos_cu = positions_cu[first_point_i];
-
- const float2 uv = surface_uv_coords[curve_i];
- ReverseUVSampler::Result lookup_result = reverse_uv_sampler.sample(uv);
- if (lookup_result.type != ReverseUVSampler::ResultType::Ok) {
- found_invalid_uv = true;
- continue;
- }
-
- const MLoopTri &looptri = *lookup_result.looptri;
- const float3 &bary_coords = lookup_result.bary_weights;
-
- const float3 &p0_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[0]].v].co;
- const float3 &p1_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[1]].v].co;
- const float3 &p2_su = surface_mesh.mvert[surface_mesh.mloop[looptri.tri[2]].v].co;
-
- float3 new_first_point_pos_su;
- interp_v3_v3v3v3(new_first_point_pos_su, p0_su, p1_su, p2_su, bary_coords);
- const float3 new_first_point_pos_cu = transforms.surface_to_curves *
- new_first_point_pos_su;
-
- const float3 pos_diff_cu = new_first_point_pos_cu - old_first_point_pos_cu;
- for (float3 &pos_cu : positions_cu.slice(points)) {
- pos_cu += pos_diff_cu;
- }
- }
- });
- break;
- }
- }
-
- DEG_id_tag_update(&curves_id.id, ID_RECALC_GEOMETRY);
+ snap_curves_to_surface_exec_object(
+ *curves_ob, *curves_id.surface, attach_mode, &found_invalid_uvs, &found_missing_uvs);
}
CTX_DATA_END;
- if (found_invalid_uv) {
+ if (found_missing_uvs) {
+ BKE_report(op->reports,
+ RPT_ERROR,
+ "Curves do not have attachment information that can be used for deformation");
+ }
+ if (found_invalid_uvs) {
BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
}