[Bf-blender-cvs] [5d13f2091e4] gpencil-new-data-proposal: Curves: support deforming curves on surface

Jacques Lucke noreply at git.blender.org
Fri Jul 8 17:57:53 CEST 2022


Commit: 5d13f2091e4a9e28bff12aedd7fd384af8da289a
Author: Jacques Lucke
Date:   Fri Jul 8 14:45:48 2022 +0200
Branches: gpencil-new-data-proposal
https://developer.blender.org/rB5d13f2091e4a9e28bff12aedd7fd384af8da289a

Curves: support deforming curves on surface

Curves that are attached to a surface can now follow the surface when
it is modified using shape keys or modifiers (but not when the original
surface is deformed in edit or sculpt mode).

The surface is allowed to be changed in any way that keeps uv maps
intact. So deformation is allowed, but also some topology changes like
subdivision.

The following features are added:
* A new `Deform Curves on Surface` node, which deforms curves with
  attachment information based on the surface object and uv map set
  in the properties panel.
* A new `Add Rest Position` checkbox in the shape keys panel. When checked,
  a new `rest_position` vector attribute is added to the mesh before shape
  keys and modifiers are applied. This is necessary to support proper
  deformation of the curves, but can also be used for other purposes.
* The `Add > Curve > Empty Hair` operator now sets up a simple geometry
  nodes setup that deforms the hair. It also makes sure that the rest
  position attribute is added to the surface.
* A new `Object (Attach Curves to Surface)` operator in the `Set Parent To`
  (ctrl+P) menu, which attaches existing curves to the surface and sets the
  surface object as parent.

Limitations:
* Sculpting the procedurally deformed curves will be implemented separately.
* The `Deform Curves on Surface` node is not generic and can only be used
  for one specific purpose currently. We plan to generalize this more in the
  future by adding support by exposing more inputs and/or by turning it into
  a node group.

Differential Revision: https://developer.blender.org/D14864

===================================================================

M	release/scripts/startup/bl_ui/properties_data_mesh.py
M	release/scripts/startup/nodeitems_builtins.py
M	source/blender/blenkernel/BKE_mesh.h
M	source/blender/blenkernel/BKE_node.h
M	source/blender/blenkernel/intern/DerivedMesh.cc
M	source/blender/blenkernel/intern/mesh.cc
M	source/blender/blenkernel/intern/node.cc
M	source/blender/editors/curves/intern/curves_add.cc
M	source/blender/editors/curves/intern/curves_ops.cc
M	source/blender/editors/include/ED_curves.h
M	source/blender/editors/object/object_add.cc
M	source/blender/editors/object/object_relations.c
M	source/blender/makesdna/DNA_object_types.h
M	source/blender/makesrna/intern/rna_object.c
M	source/blender/modifiers/intern/MOD_nodes.cc
M	source/blender/nodes/NOD_geometry.h
M	source/blender/nodes/NOD_static_types.h
M	source/blender/nodes/geometry/CMakeLists.txt
A	source/blender/nodes/geometry/nodes/node_geo_deform_curves_on_surface.cc

===================================================================

diff --git a/release/scripts/startup/bl_ui/properties_data_mesh.py b/release/scripts/startup/bl_ui/properties_data_mesh.py
index 0b043905713..2fc949f4aae 100644
--- a/release/scripts/startup/bl_ui/properties_data_mesh.py
+++ b/release/scripts/startup/bl_ui/properties_data_mesh.py
@@ -411,6 +411,8 @@ class DATA_PT_shape_keys(MeshButtonsPanel, Panel):
                 row.active = enable_edit_value
                 row.prop(key, "eval_time")
 
+        layout.prop(ob, "add_rest_position_attribute")
+
 
 class DATA_PT_uv_texture(MeshButtonsPanel, Panel):
     bl_label = "UV Maps"
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 3f49fb9fb58..e59c98163d7 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -73,6 +73,7 @@ def curve_node_items(context):
     yield NodeItem("GeometryNodeCurveLength")
     yield NodeItem("GeometryNodeCurveToMesh")
     yield NodeItem("GeometryNodeCurveToPoints")
+    yield NodeItem("GeometryNodeDeformCurvesWithSurface")
     yield NodeItem("GeometryNodeFillCurve")
     yield NodeItem("GeometryNodeFilletCurve")
     yield NodeItem("GeometryNodeResampleCurve")
diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h
index ff4f4a8dc9e..366083fee7f 100644
--- a/source/blender/blenkernel/BKE_mesh.h
+++ b/source/blender/blenkernel/BKE_mesh.h
@@ -692,7 +692,8 @@ void BKE_mesh_calc_normals_split(struct Mesh *mesh);
  * to split geometry along sharp edges.
  */
 void BKE_mesh_calc_normals_split_ex(struct Mesh *mesh,
-                                    struct MLoopNorSpaceArray *r_lnors_spacearr);
+                                    struct MLoopNorSpaceArray *r_lnors_spacearr,
+                                    float (*r_corner_normals)[3]);
 
 /**
  * Higher level functions hiding most of the code needed around call to
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index e13ac3180ec..b7962ade312 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1501,6 +1501,7 @@ struct TexResult;
 #define GEO_NODE_MESH_TO_VOLUME 1164
 #define GEO_NODE_UV_UNWRAP 1165
 #define GEO_NODE_UV_PACK_ISLANDS 1166
+#define GEO_NODE_DEFORM_CURVES_ON_SURFACE 1167
 
 /** \} */
 
diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc
index ffac89c15e6..c2ea01bcadf 100644
--- a/source/blender/blenkernel/intern/DerivedMesh.cc
+++ b/source/blender/blenkernel/intern/DerivedMesh.cc
@@ -66,6 +66,9 @@
 #  include "DNA_userdef_types.h"
 #endif
 
+using blender::float3;
+using blender::IndexRange;
+
 /* very slow! enable for testing only! */
 //#define USE_MODIFIER_VALIDATE
 
@@ -814,6 +817,25 @@ static void mesh_calc_modifiers(struct Depsgraph *depsgraph,
   /* Clear errors before evaluation. */
   BKE_modifiers_clear_errors(ob);
 
+  if (ob->modifier_flag & OB_MODIFIER_FLAG_ADD_REST_POSITION) {
+    if (mesh_final == nullptr) {
+      mesh_final = BKE_mesh_copy_for_eval(mesh_input, true);
+      ASSERT_IS_VALID_MESH(mesh_final);
+    }
+    float3 *rest_positions = static_cast<float3 *>(CustomData_add_layer_named(&mesh_final->vdata,
+                                                                              CD_PROP_FLOAT3,
+                                                                              CD_DEFAULT,
+                                                                              nullptr,
+                                                                              mesh_final->totvert,
+                                                                              "rest_position"));
+    blender::threading::parallel_for(
+        IndexRange(mesh_final->totvert), 1024, [&](const IndexRange range) {
+          for (const int i : range) {
+            rest_positions[i] = mesh_final->mvert[i].co;
+          }
+        });
+  }
+
   /* Apply all leading deform modifiers. */
   if (use_deform) {
     for (; md; md = md->next, md_datamask = md_datamask->next) {
diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc
index 98fa551590c..2a14370bf93 100644
--- a/source/blender/blenkernel/intern/mesh.cc
+++ b/source/blender/blenkernel/intern/mesh.cc
@@ -1848,9 +1848,25 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh,
   BKE_mesh_tag_coords_changed(mesh);
 }
 
-void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spacearr)
+static float (*ensure_corner_normal_layer(Mesh &mesh))[3]
 {
   float(*r_loopnors)[3];
+  if (CustomData_has_layer(&mesh.ldata, CD_NORMAL)) {
+    r_loopnors = (float(*)[3])CustomData_get_layer(&mesh.ldata, CD_NORMAL);
+    memset(r_loopnors, 0, sizeof(float[3]) * mesh.totloop);
+  }
+  else {
+    r_loopnors = (float(*)[3])CustomData_add_layer(
+        &mesh.ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh.totloop);
+    CustomData_set_layer_flag(&mesh.ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
+  }
+  return r_loopnors;
+}
+
+void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
+                                    MLoopNorSpaceArray *r_lnors_spacearr,
+                                    float (*r_corner_normals)[3])
+{
   short(*clnors)[2] = nullptr;
 
   /* Note that we enforce computing clnors when the clnor space array is requested by caller here.
@@ -1860,16 +1876,6 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
                                  ((mesh->flag & ME_AUTOSMOOTH) != 0);
   const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI;
 
-  if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) {
-    r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL);
-    memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop);
-  }
-  else {
-    r_loopnors = (float(*)[3])CustomData_add_layer(
-        &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop);
-    CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY);
-  }
-
   /* may be nullptr */
   clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
 
@@ -1879,7 +1885,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
                               mesh->medge,
                               mesh->totedge,
                               mesh->mloop,
-                              r_loopnors,
+                              r_corner_normals,
                               mesh->totloop,
                               mesh->mpoly,
                               BKE_mesh_poly_normals_ensure(mesh),
@@ -1895,7 +1901,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac
 
 void BKE_mesh_calc_normals_split(Mesh *mesh)
 {
-  BKE_mesh_calc_normals_split_ex(mesh, nullptr);
+  BKE_mesh_calc_normals_split_ex(mesh, nullptr, ensure_corner_normal_layer(*mesh));
 }
 
 /* Split faces helper functions. */
@@ -2114,7 +2120,7 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals)
 
   MLoopNorSpaceArray lnors_spacearr = {nullptr};
   /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */
-  BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr);
+  BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr, ensure_corner_normal_layer(*mesh));
   /* Stealing memarena from loop normals space array. */
   MemArena *memarena = lnors_spacearr.mem;
 
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index 5be912ffb2b..c6f140b9260 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -4749,6 +4749,7 @@ static void registerGeometryNodes()
   register_node_type_geo_curve_to_mesh();
   register_node_type_geo_curve_to_points();
   register_node_type_geo_curve_trim();
+  register_node_type_geo_deform_curves_on_surface();
   register_node_type_geo_delete_geometry();
   register_node_type_geo_duplicate_elements();
   register_node_type_geo_distribute_points_on_faces();
diff --git a/source/blender/editors/curves/intern/curves_add.cc b/source/blender/editors/curves/intern/curves_add.cc
index 552ef1d96c8..79916253207 100644
--- a/source/blender/editors/curves/intern/curves_add.cc
+++ b/source/blender/editors/curves/intern/curves_add.cc
@@ -6,12 +6,96 @@
 
 #include "BLI_rand.hh"
 
+#include "BKE_context.h"
 #include "BKE_curves.hh"
+#include "BKE_node.h"
+#include "BKE_node_runtime.hh"
 
 #include "ED_curves.h"
+#include "ED_node.h"
+#include "ED_object.h"
+
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
 
 namespace blender::ed::curves {
 
+static bool has_surface_deformation_node(const bNodeTree &ntree)
+{
+  LISTBASE_FOREACH (const bNode *, node, &ntree.nodes) {
+    if (node->type == GEO_NODE_DEFORM_CURVES_ON_SURFACE) {
+      return true;
+    }
+    if (node->type == NODE_GROUP) {
+      if (node->id != nullptr) {
+        if (has_surface_deformation_node(*reinterpret_cast<const bNodeTree *>(node->id))) {
+          return true;
+        }
+      }
+    }
+  }
+  return false;
+}
+
+static bool has_surface_deformation_node(const Object &curves_ob)
+{
+  LISTBASE_FOREACH (const ModifierData *, md, &curves_ob.modifiers) {
+    if (md->type != eModifierType_Nodes) {
+      continue;
+    }
+    const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+    if (nmd->node_group == nullptr) {
+      continue;
+    }
+    if (has_surface_deformation_node(*nmd->node_group)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+void ensure_surface_deformation_node_exists(bContext &C, Object &curves_ob)
+{
+  if (has_surface_deformation_node(curves_ob)) {
+    return;
+  }
+
+  Main *bmain = CTX_data_main(&C);
+  Scene *scene = CTX_data_scene(&C);
+
+  ModifierData *md = ED_object_modifier_add(
+      nullptr, bmain, scene, &curves_ob, "Surface Deform", eModifierType_Nodes);
+  NodesModifierData &nmd = *reinterpret_cast<NodesModifierData *>(md);
+  nmd.node_group = ntreeAddTree(bmain, "Surface Deform", "GeometryNodeTree");
+
+  bNodeTree *ntree = nmd.node_group;
+  ntree

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list