Blender  V3.3
node_geo_deform_curves_on_surface.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BKE_attribute_math.hh"
4 #include "BKE_curves.hh"
5 #include "BKE_editmesh.h"
6 #include "BKE_lib_id.h"
7 #include "BKE_mesh.h"
8 #include "BKE_mesh_runtime.h"
9 #include "BKE_mesh_wrapper.h"
10 #include "BKE_modifier.h"
11 #include "BKE_type_conversions.hh"
12 
13 #include "BLI_float3x3.hh"
14 #include "BLI_task.hh"
15 
16 #include "UI_interface.h"
17 #include "UI_resources.h"
18 
19 #include "DNA_mesh_types.h"
20 #include "DNA_meshdata_types.h"
21 
23 
25 
26 #include "DEG_depsgraph_query.h"
27 
28 #include "node_geometry_util.hh"
29 
31 
35 
37 
39 {
40  b.add_input<decl::Geometry>(N_("Curves")).supported_type(GEO_COMPONENT_TYPE_CURVE);
41  b.add_output<decl::Geometry>(N_("Curves"));
42 }
43 
44 static void deform_curves(const CurvesGeometry &curves,
45  const Mesh &surface_mesh_old,
46  const Mesh &surface_mesh_new,
47  const Span<float2> curve_attachment_uvs,
48  const ReverseUVSampler &reverse_uv_sampler_old,
49  const ReverseUVSampler &reverse_uv_sampler_new,
50  const Span<float3> corner_normals_old,
51  const Span<float3> corner_normals_new,
52  const Span<float3> rest_positions,
53  const float4x4 &surface_to_curves,
54  MutableSpan<float3> r_positions,
55  MutableSpan<float3x3> r_rotations,
56  std::atomic<int> &r_invalid_uv_count)
57 {
58  /* Find attachment points on old and new mesh. */
59  const int curves_num = curves.curves_num();
60  Array<ReverseUVSampler::Result> surface_samples_old(curves_num);
61  Array<ReverseUVSampler::Result> surface_samples_new(curves_num);
63  1024 < curves_num,
64  [&]() { reverse_uv_sampler_old.sample_many(curve_attachment_uvs, surface_samples_old); },
65  [&]() { reverse_uv_sampler_new.sample_many(curve_attachment_uvs, surface_samples_new); });
66 
67  const float4x4 curves_to_surface = surface_to_curves.inverted();
68 
69  threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) {
70  for (const int curve_i : range) {
71  const ReverseUVSampler::Result &surface_sample_old = surface_samples_old[curve_i];
72  if (surface_sample_old.type != ReverseUVSampler::ResultType::Ok) {
73  r_invalid_uv_count++;
74  continue;
75  }
76  const ReverseUVSampler::Result &surface_sample_new = surface_samples_new[curve_i];
77  if (surface_sample_new.type != ReverseUVSampler::ResultType::Ok) {
78  r_invalid_uv_count++;
79  continue;
80  }
81 
82  const MLoopTri &looptri_old = *surface_sample_old.looptri;
83  const MLoopTri &looptri_new = *surface_sample_new.looptri;
84  const float3 &bary_weights_old = surface_sample_old.bary_weights;
85  const float3 &bary_weights_new = surface_sample_new.bary_weights;
86 
87  const int corner_0_old = looptri_old.tri[0];
88  const int corner_1_old = looptri_old.tri[1];
89  const int corner_2_old = looptri_old.tri[2];
90 
91  const int corner_0_new = looptri_new.tri[0];
92  const int corner_1_new = looptri_new.tri[1];
93  const int corner_2_new = looptri_new.tri[2];
94 
95  const int vert_0_old = surface_mesh_old.mloop[corner_0_old].v;
96  const int vert_1_old = surface_mesh_old.mloop[corner_1_old].v;
97  const int vert_2_old = surface_mesh_old.mloop[corner_2_old].v;
98 
99  const int vert_0_new = surface_mesh_new.mloop[corner_0_new].v;
100  const int vert_1_new = surface_mesh_new.mloop[corner_1_new].v;
101  const int vert_2_new = surface_mesh_new.mloop[corner_2_new].v;
102 
103  const float3 &normal_0_old = corner_normals_old[corner_0_old];
104  const float3 &normal_1_old = corner_normals_old[corner_1_old];
105  const float3 &normal_2_old = corner_normals_old[corner_2_old];
106  const float3 normal_old = math::normalize(
107  mix3(bary_weights_old, normal_0_old, normal_1_old, normal_2_old));
108 
109  const float3 &normal_0_new = corner_normals_new[corner_0_new];
110  const float3 &normal_1_new = corner_normals_new[corner_1_new];
111  const float3 &normal_2_new = corner_normals_new[corner_2_new];
112  const float3 normal_new = math::normalize(
113  mix3(bary_weights_new, normal_0_new, normal_1_new, normal_2_new));
114 
115  const float3 &pos_0_old = surface_mesh_old.mvert[vert_0_old].co;
116  const float3 &pos_1_old = surface_mesh_old.mvert[vert_1_old].co;
117  const float3 &pos_2_old = surface_mesh_old.mvert[vert_2_old].co;
118  const float3 pos_old = mix3(bary_weights_old, pos_0_old, pos_1_old, pos_2_old);
119 
120  const float3 &pos_0_new = surface_mesh_new.mvert[vert_0_new].co;
121  const float3 &pos_1_new = surface_mesh_new.mvert[vert_1_new].co;
122  const float3 &pos_2_new = surface_mesh_new.mvert[vert_2_new].co;
123  const float3 pos_new = mix3(bary_weights_new, pos_0_new, pos_1_new, pos_2_new);
124 
125  /* The translation is just the difference between the old and new position on the surface. */
126  const float3 translation = pos_new - pos_old;
127 
128  const float3 &rest_pos_0 = rest_positions[vert_0_new];
129  const float3 &rest_pos_1 = rest_positions[vert_1_new];
130 
131  /* The tangent reference direction is used to determine the rotation of the surface point
132  * around its normal axis. It's important that the old and new tangent reference are computed
133  * in a consistent way. If the surface has not been rotated, the old and new tangent
134  * reference have to have the same direction. For that reason, the old tangent reference is
135  * computed based on the rest position attribute instead of positions on the old mesh. This
136  * way the old and new tangent reference use the same topology.
137  *
138  * TODO: Figure out if this can be smoothly interpolated across the surface as well.
139  * Currently, this is a source of discontinuity in the deformation, because the vector
140  * changes instantly from one triangle to the next. */
141  const float3 tangent_reference_dir_old = rest_pos_1 - rest_pos_0;
142  const float3 tangent_reference_dir_new = pos_1_new - pos_0_new;
143 
144  /* Compute first local tangent based on the (potentially smoothed) normal and the tangent
145  * reference. */
146  const float3 tangent_x_old = math::normalize(
147  math::cross(normal_old, tangent_reference_dir_old));
148  const float3 tangent_x_new = math::normalize(
149  math::cross(normal_new, tangent_reference_dir_new));
150 
151  /* The second tangent defined by the normal and first tangent. */
152  const float3 tangent_y_old = math::normalize(math::cross(normal_old, tangent_x_old));
153  const float3 tangent_y_new = math::normalize(math::cross(normal_new, tangent_x_new));
154 
155  /* Construct rotation matrix that encodes the orientation of the old surface position. */
156  float3x3 rotation_old;
157  copy_v3_v3(rotation_old.values[0], tangent_x_old);
158  copy_v3_v3(rotation_old.values[1], tangent_y_old);
159  copy_v3_v3(rotation_old.values[2], normal_old);
160 
161  /* Construct rotation matrix that encodes the orientation of the new surface position. */
162  float3x3 rotation_new;
163  copy_v3_v3(rotation_new.values[0], tangent_x_new);
164  copy_v3_v3(rotation_new.values[1], tangent_y_new);
165  copy_v3_v3(rotation_new.values[2], normal_new);
166 
167  /* Can use transpose instead of inverse because the matrix is orthonormal. In the case of
168  * zero-area triangles, the matrix would not be orthonormal, but in this case, none of this
169  * works anyway. */
170  const float3x3 rotation_old_inv = rotation_old.transposed();
171 
172  /* Compute a rotation matrix that rotates points from the old to the new surface
173  * orientation. */
174  const float3x3 rotation = rotation_new * rotation_old_inv;
175  float4x4 rotation_4x4;
176  copy_m4_m3(rotation_4x4.values, rotation.values);
177 
178  /* Construction transformation matrix for this surface position that includes rotation and
179  * translation. */
180  float4x4 surface_transform = float4x4::identity();
181  /* Subtract and add #pos_old, so that the rotation origin is the position on the surface. */
182  sub_v3_v3(surface_transform.values[3], pos_old);
183  mul_m4_m4_pre(surface_transform.values, rotation_4x4.values);
184  add_v3_v3(surface_transform.values[3], pos_old);
185  add_v3_v3(surface_transform.values[3], translation);
186 
187  /* Change the basis of the transformation so to that it can be applied in the local space of
188  * the curves. */
189  const float4x4 curve_transform = surface_to_curves * surface_transform * curves_to_surface;
190 
191  /* Actually transform all points. */
192  const IndexRange points = curves.points_for_curve(curve_i);
193  for (const int point_i : points) {
194  const float3 old_point_pos = r_positions[point_i];
195  const float3 new_point_pos = curve_transform * old_point_pos;
196  r_positions[point_i] = new_point_pos;
197  }
198 
199  if (!r_rotations.is_empty()) {
200  for (const int point_i : points) {
201  r_rotations[point_i] = rotation * r_rotations[point_i];
202  }
203  }
204  }
205  });
206 }
207 
209 {
210  GeometrySet curves_geometry = params.extract_input<GeometrySet>("Curves");
211 
212  Mesh *surface_mesh_orig = nullptr;
213  bool free_suface_mesh_orig = false;
214  BLI_SCOPED_DEFER([&]() {
215  if (free_suface_mesh_orig) {
216  BKE_id_free(nullptr, surface_mesh_orig);
217  }
218  });
219 
220  auto pass_through_input = [&]() { params.set_output("Curves", std::move(curves_geometry)); };
221 
222  const Object *self_ob_eval = params.self_object();
223  if (self_ob_eval == nullptr || self_ob_eval->type != OB_CURVES) {
224  pass_through_input();
225  params.error_message_add(NodeWarningType::Error, TIP_("Node only works for curves objects"));
226  return;
227  }
228  const Curves *self_curves_eval = static_cast<const Curves *>(self_ob_eval->data);
229  if (self_curves_eval->surface_uv_map == nullptr || self_curves_eval->surface_uv_map[0] == '\0') {
230  pass_through_input();
231  params.error_message_add(NodeWarningType::Error, TIP_("Surface UV map not defined"));
232  return;
233  }
234  /* Take surface information from self-object. */
235  Object *surface_ob_eval = self_curves_eval->surface;
236  const StringRefNull uv_map_name = self_curves_eval->surface_uv_map;
237  const StringRefNull rest_position_name = "rest_position";
238 
239  if (!curves_geometry.has_curves()) {
240  pass_through_input();
241  return;
242  }
243  if (surface_ob_eval == nullptr || surface_ob_eval->type != OB_MESH) {
244  pass_through_input();
245  params.error_message_add(NodeWarningType::Error, TIP_("Curves not attached to a surface"));
246  return;
247  }
248  Object *surface_ob_orig = DEG_get_original_object(surface_ob_eval);
249  Mesh &surface_object_data = *static_cast<Mesh *>(surface_ob_orig->data);
250 
251  if (BMEditMesh *em = surface_object_data.edit_mesh) {
252  surface_mesh_orig = BKE_mesh_from_bmesh_for_eval_nomain(em->bm, NULL, &surface_object_data);
253  free_suface_mesh_orig = true;
254  }
255  else {
256  surface_mesh_orig = &surface_object_data;
257  }
258  Mesh *surface_mesh_eval = BKE_modifier_get_evaluated_mesh_from_evaluated_object(surface_ob_eval);
259  if (surface_mesh_eval == nullptr) {
260  pass_through_input();
261  params.error_message_add(NodeWarningType::Error, TIP_("Surface has no mesh"));
262  return;
263  }
264 
265  BKE_mesh_wrapper_ensure_mdata(surface_mesh_eval);
266 
267  const AttributeAccessor mesh_attributes_eval = bke::mesh_attributes(*surface_mesh_eval);
268  const AttributeAccessor mesh_attributes_orig = bke::mesh_attributes(*surface_mesh_orig);
269 
270  Curves &curves_id = *curves_geometry.get_curves_for_write();
272 
273  if (!mesh_attributes_eval.contains(uv_map_name)) {
274  pass_through_input();
275  char *message = BLI_sprintfN(TIP_("Evaluated surface missing UV map: \"%s\""),
276  uv_map_name.c_str());
277  params.error_message_add(NodeWarningType::Error, message);
278  MEM_freeN(message);
279  return;
280  }
281  if (!mesh_attributes_orig.contains(uv_map_name)) {
282  pass_through_input();
283  char *message = BLI_sprintfN(TIP_("Original surface missing UV map: \"%s\""),
284  uv_map_name.c_str());
285  params.error_message_add(NodeWarningType::Error, message);
286  MEM_freeN(message);
287  return;
288  }
289  if (!mesh_attributes_eval.contains(rest_position_name)) {
290  pass_through_input();
291  params.error_message_add(NodeWarningType::Error,
292  TIP_("Evaluated surface missing attribute: \"rest_position\""));
293  return;
294  }
295  if (curves.surface_uv_coords().is_empty() && curves.curves_num() > 0) {
296  pass_through_input();
297  params.error_message_add(NodeWarningType::Error,
298  TIP_("Curves are not attached to any UV map"));
299  return;
300  }
301  const VArraySpan<float2> uv_map_orig = mesh_attributes_orig.lookup<float2>(uv_map_name,
303  const VArraySpan<float2> uv_map_eval = mesh_attributes_eval.lookup<float2>(uv_map_name,
305  const VArraySpan<float3> rest_positions = mesh_attributes_eval.lookup<float3>(rest_position_name,
307  const Span<float2> surface_uv_coords = curves.surface_uv_coords();
308 
309  const Span<MLoopTri> looptris_orig{BKE_mesh_runtime_looptri_ensure(surface_mesh_orig),
310  BKE_mesh_runtime_looptri_len(surface_mesh_orig)};
311  const Span<MLoopTri> looptris_eval{BKE_mesh_runtime_looptri_ensure(surface_mesh_eval),
312  BKE_mesh_runtime_looptri_len(surface_mesh_eval)};
313  const ReverseUVSampler reverse_uv_sampler_orig{uv_map_orig, looptris_orig};
314  const ReverseUVSampler reverse_uv_sampler_eval{uv_map_eval, looptris_eval};
315 
316  /* Retrieve face corner normals from each mesh. It's necessary to use face corner normals
317  * because face normals or vertex normals may lose information (custom normals, auto smooth) in
318  * some cases. It isn't yet possible to retrieve lazily calculated face corner normals from a
319  * const mesh, so they are calculated here every time. */
320  Array<float3> corner_normals_orig(surface_mesh_orig->totloop);
321  Array<float3> corner_normals_eval(surface_mesh_eval->totloop);
323  surface_mesh_orig, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_orig.data()));
325  surface_mesh_eval, nullptr, reinterpret_cast<float(*)[3]>(corner_normals_eval.data()));
326 
327  std::atomic<int> invalid_uv_count = 0;
328 
329  const bke::CurvesSurfaceTransforms transforms{*self_ob_eval, surface_ob_eval};
330 
331  bke::CurvesEditHints *edit_hints = curves_geometry.get_curve_edit_hints_for_write();
332  MutableSpan<float3> edit_hint_positions;
333  MutableSpan<float3x3> edit_hint_rotations;
334  if (edit_hints != nullptr) {
335  if (edit_hints->positions.has_value()) {
336  edit_hint_positions = *edit_hints->positions;
337  }
338  if (!edit_hints->deform_mats.has_value()) {
339  edit_hints->deform_mats.emplace(edit_hints->curves_id_orig.geometry.point_num,
340  float3x3::identity());
341  edit_hints->deform_mats->fill(float3x3::identity());
342  }
343  edit_hint_rotations = *edit_hints->deform_mats;
344  }
345 
346  if (edit_hint_positions.is_empty()) {
348  *surface_mesh_orig,
349  *surface_mesh_eval,
350  surface_uv_coords,
351  reverse_uv_sampler_orig,
352  reverse_uv_sampler_eval,
353  corner_normals_orig,
354  corner_normals_eval,
355  rest_positions,
356  transforms.surface_to_curves,
357  curves.positions_for_write(),
358  edit_hint_rotations,
359  invalid_uv_count);
360  }
361  else {
362  /* First deform the actual curves in the input geometry. */
364  *surface_mesh_orig,
365  *surface_mesh_eval,
366  surface_uv_coords,
367  reverse_uv_sampler_orig,
368  reverse_uv_sampler_eval,
369  corner_normals_orig,
370  corner_normals_eval,
371  rest_positions,
372  transforms.surface_to_curves,
373  curves.positions_for_write(),
374  {},
375  invalid_uv_count);
376  /* Then also deform edit curve information for use in sculpt mode. */
377  const CurvesGeometry &curves_orig = CurvesGeometry::wrap(edit_hints->curves_id_orig.geometry);
378  deform_curves(curves_orig,
379  *surface_mesh_orig,
380  *surface_mesh_eval,
381  surface_uv_coords,
382  reverse_uv_sampler_orig,
383  reverse_uv_sampler_eval,
384  corner_normals_orig,
385  corner_normals_eval,
386  rest_positions,
387  transforms.surface_to_curves,
388  edit_hint_positions,
389  edit_hint_rotations,
390  invalid_uv_count);
391  }
392 
393  curves.tag_positions_changed();
394 
395  if (invalid_uv_count) {
396  char *message = BLI_sprintfN(TIP_("Invalid surface UVs on %d curves"),
397  invalid_uv_count.load());
398  params.error_message_add(NodeWarningType::Warning, message);
399  MEM_freeN(message);
400  }
401 
402  params.set_output("Curves", curves_geometry);
403 }
404 
405 } // namespace blender::nodes::node_geo_deform_curves_on_surface_cc
406 
408 {
410 
411  static bNodeType ntype;
413  &ntype, GEO_NODE_DEFORM_CURVES_ON_SURFACE, "Deform Curves on Surface", NODE_CLASS_GEOMETRY);
416  node_type_size(&ntype, 170, 120, 700);
417  nodeRegisterType(&ntype);
418 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
Low-level operations for curves.
@ GEO_COMPONENT_TYPE_CURVE
void BKE_id_free(struct Main *bmain, void *idv)
struct Mesh * BKE_mesh_from_bmesh_for_eval_nomain(struct BMesh *bm, const struct CustomData_MeshMasks *cd_mask_extra, const struct Mesh *me_settings)
void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh, struct MLoopNorSpaceArray *r_lnors_spacearr, float(*r_corner_normals)[3])
Definition: mesh.cc:1875
const struct MLoopTri * BKE_mesh_runtime_looptri_ensure(const struct Mesh *mesh)
int BKE_mesh_runtime_looptri_len(const struct Mesh *mesh)
void BKE_mesh_wrapper_ensure_mdata(struct Mesh *me)
Definition: mesh_wrapper.cc:94
struct Mesh * BKE_modifier_get_evaluated_mesh_from_evaluated_object(struct Object *ob_eval)
void node_type_size(struct bNodeType *ntype, int width, int minwidth, int maxwidth)
Definition: node.cc:4396
#define GEO_NODE_DEFORM_CURVES_ON_SURFACE
Definition: BKE_node.h:1508
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
#define BLI_SCOPED_DEFER(function_to_defer)
size_t size_t char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
#define TIP_(msgid)
struct Object * DEG_get_original_object(struct Object *object)
struct CurvesGeometry CurvesGeometry
@ OB_MESH
@ OB_CURVES
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to curves
const T * data() const
Definition: BLI_array.hh:300
constexpr bool is_empty() const
Definition: BLI_span.hh:519
constexpr const char * c_str() const
bool contains(const AttributeIDRef &attribute_id) const
GAttributeReader lookup(const AttributeIDRef &attribute_id) const
std::optional< Array< float3 > > positions
Definition: BKE_curves.hh:434
std::optional< Array< float3x3 > > deform_mats
Definition: BKE_curves.hh:439
void sample_many(Span< float2 > query_uvs, MutableSpan< Result > r_results) const
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
T mix3(const float3 &weights, const T &v0, const T &v1, const T &v2)
static struct PartialUpdateUser * wrap(PartialUpdateUserImpl *user)
AttributeAccessor mesh_attributes(const Mesh &mesh)
static void deform_curves(const CurvesGeometry &curves, const Mesh &surface_mesh_old, const Mesh &surface_mesh_new, const Span< float2 > curve_attachment_uvs, const ReverseUVSampler &reverse_uv_sampler_old, const ReverseUVSampler &reverse_uv_sampler_new, const Span< float3 > corner_normals_old, const Span< float3 > corner_normals_new, const Span< float3 > rest_positions, const float4x4 &surface_to_curves, MutableSpan< float3 > r_positions, MutableSpan< float3x3 > r_rotations, std::atomic< int > &r_invalid_uv_count)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
void parallel_invoke(Functions &&...functions)
Definition: BLI_task.hh:99
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
void register_node_type_geo_deform_curves_on_surface()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
CurvesGeometry geometry
struct Object * surface
char * surface_uv_map
Curves * get_curves_for_write()
blender::bke::CurvesEditHints * get_curve_edit_hints_for_write()
bool has_curves() const
struct BMEditMesh * edit_mesh
int totloop
void * data
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
NodeDeclareFunction declare
Definition: BKE_node.h:324
float4x4 inverted() const
#define N_(msgid)