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:
Diffstat (limited to 'source/blender/editors/curves/intern/curves_ops.cc')
-rw-r--r--source/blender/editors/curves/intern/curves_ops.cc202
1 files changed, 202 insertions, 0 deletions
diff --git a/source/blender/editors/curves/intern/curves_ops.cc b/source/blender/editors/curves/intern/curves_ops.cc
index c6dd4508b5a..3a4dcd4f5f6 100644
--- a/source/blender/editors/curves/intern/curves_ops.cc
+++ b/source/blender/editors/curves/intern/curves_ops.cc
@@ -4,13 +4,17 @@
* \ingroup edcurves
*/
+#include <atomic>
+
#include "BLI_utildefines.h"
#include "ED_curves.h"
#include "ED_object.h"
+#include "ED_screen.h"
#include "WM_api.h"
+#include "BKE_bvhutils.h"
#include "BKE_context.h"
#include "BKE_curves.hh"
#include "BKE_layer.h"
@@ -18,6 +22,7 @@
#include "BKE_mesh_runtime.h"
#include "BKE_paint.h"
#include "BKE_particle.h"
+#include "BKE_report.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
@@ -28,6 +33,9 @@
#include "DEG_depsgraph.h"
+#include "RNA_access.h"
+#include "RNA_define.h"
+
/**
* The code below uses a suffix naming convention to indicate the coordinate space:
* `cu`: Local space of the curves object that is being edited.
@@ -283,10 +291,204 @@ static void CURVES_OT_convert_to_particle_system(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
}
+namespace snap_curves_to_surface {
+
+enum class AttachMode {
+ Nearest,
+ Deform,
+};
+
+static bool snap_curves_to_surface_poll(bContext *C)
+{
+ Object *ob = CTX_data_active_object(C);
+ if (ob == nullptr || ob->type != OB_CURVES) {
+ return false;
+ }
+ if (!ED_operator_object_active_editable_ex(C, ob)) {
+ return false;
+ }
+ Curves &curves = *static_cast<Curves *>(ob->data);
+ if (curves.surface == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+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_looptri_index = 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) {
+ continue;
+ }
+ Mesh &surface_mesh = *static_cast<Mesh *>(surface_ob.data);
+
+ MutableSpan<float3> positions_cu = curves.positions_for_write();
+ MutableSpan<int> surface_triangle_indices = curves.surface_triangle_indices_for_write();
+ MutableSpan<float2> surface_triangle_coords = curves.surface_triangle_coords_for_write();
+
+ const Span<MLoopTri> surface_looptris = {BKE_mesh_runtime_looptri_ensure(&surface_mesh),
+ BKE_mesh_runtime_looptri_len(&surface_mesh)};
+
+ const float4x4 curves_to_world_mat = curves_ob->obmat;
+ const float4x4 world_to_curves_mat = curves_to_world_mat.inverted();
+ const float4x4 surface_to_world_mat = surface_ob.obmat;
+ const float4x4 world_to_surface_mat = surface_to_world_mat.inverted();
+ const float4x4 curves_to_surface_mat = world_to_surface_mat * curves_to_world_mat;
+ const float4x4 surface_to_curves_mat = world_to_curves_mat * surface_to_world_mat;
+
+ 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 = curves_to_surface_mat * 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 = surface_to_curves_mat * 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;
+ }
+
+ surface_triangle_indices[curve_i] = looptri_index;
+
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+ 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 bary_coords;
+ interp_weights_tri_v3(bary_coords, p0_su, p1_su, p2_su, new_first_point_pos_su);
+ surface_triangle_coords[curve_i] = bke::curves::encode_surface_bary_coord(bary_coords);
+ }
+ });
+ break;
+ }
+ case AttachMode::Deform: {
+ 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 int looptri_index = surface_triangle_indices[curve_i];
+ if (!surface_looptris.index_range().contains(looptri_index)) {
+ found_invalid_looptri_index = true;
+ continue;
+ }
+
+ const MLoopTri &looptri = surface_looptris[looptri_index];
+
+ const float3 bary_coords = bke::curves::decode_surface_bary_coord(
+ surface_triangle_coords[curve_i]);
+
+ 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 = surface_to_curves_mat * 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);
+ }
+ CTX_DATA_END;
+
+ if (found_invalid_looptri_index) {
+ BKE_report(op->reports, RPT_INFO, "Could not snap some curves to the surface");
+ }
+
+ WM_main_add_notifier(NC_OBJECT | ND_DRAW, nullptr);
+
+ return OPERATOR_FINISHED;
+}
+
+} // namespace snap_curves_to_surface
+
+static void CURVES_OT_snap_curves_to_surface(wmOperatorType *ot)
+{
+ using namespace snap_curves_to_surface;
+
+ ot->name = "Snap Curves to Surface";
+ ot->idname = "CURVES_OT_snap_curves_to_surface";
+ ot->description = "Move curves so that the first point is exactly on the surface mesh";
+
+ ot->poll = snap_curves_to_surface_poll;
+ ot->exec = snap_curves_to_surface_exec;
+
+ ot->flag = OPTYPE_UNDO | OPTYPE_REGISTER;
+
+ static const EnumPropertyItem attach_mode_items[] = {
+ {static_cast<int>(AttachMode::Nearest),
+ "NEAREST",
+ 0,
+ "Nearest",
+ "Find the closest point on the surface for the root point of every curve and move the root "
+ "there"},
+ {static_cast<int>(AttachMode::Deform),
+ "DEFORM",
+ 0,
+ "Deform",
+ "Re-attach curves to a deformed surface using the existing attachment information. This "
+ "only works when the topology of the surface mesh has not changed"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_enum(ot->srna,
+ "attach_mode",
+ attach_mode_items,
+ static_cast<int>(AttachMode::Nearest),
+ "Attach Mode",
+ "How to find the point on the surface to attach to");
+}
+
} // namespace blender::ed::curves
void ED_operatortypes_curves()
{
using namespace blender::ed::curves;
WM_operatortype_append(CURVES_OT_convert_to_particle_system);
+ WM_operatortype_append(CURVES_OT_snap_curves_to_surface);
}