[Bf-blender-cvs] [f879c20f72d] master: Geometry Nodes: output uv map from primitive nodes as anonymous attributes

Jacques Lucke noreply at git.blender.org
Wed Dec 14 18:18:17 CET 2022


Commit: f879c20f72d9ce58a2e0ed26dc15557116d5961f
Author: Jacques Lucke
Date:   Wed Dec 14 18:05:31 2022 +0100
Branches: master
https://developer.blender.org/rBf879c20f72d9ce58a2e0ed26dc15557116d5961f

Geometry Nodes: output uv map from primitive nodes as anonymous attributes

This is essentially a left-over from the initial transition to fields where this was
forgotten. The mesh primitive nodes used to create a named uv map attribute
with a hard-coded name. The standard way to deal with that in geometry nodes
now is to output the attribute as a socket instead. The user can then decide
to store it as a named attribute or not.

The benefits of not always storing the named attribute in the node are:
* Improved performance and lower memory usage when the uv map is not
  used.
* It's more obvious that there actually is a uv map.
* The hard-coded name was inconsistent.

The versioning code inserts a new Store Named Attribute node that
stores the uv map immediatly. In many cases, users can probably just
remove this node without affecting their final result, but we can't
detect that.

There is one behavior change which is that the stored uv map will be
a 3d vector instead of a 2d vector which is what the nodes originally created.
We could store the uv map as 2d vector inthe Store Named Attribute node,
but that has the problem that older Blender versions don't support this
and would crash immediately. Users can just change this to 2d vector
manually if they don't care about forward compatibility.

There is a plan to support 2d vectors more natively in geometry nodes: T92765.

This change breaks forward compatibility in the case when the uv map
was used.

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

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

M	source/blender/blenkernel/BKE_blender_version.h
M	source/blender/blenkernel/intern/node.cc
M	source/blender/blenloader/intern/versioning_300.cc
M	source/blender/nodes/geometry/node_geometry_util.hh
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
M	source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc

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

diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index abf9d67370b..91a458e347f 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -25,13 +25,13 @@ extern "C" {
 
 /* Blender file format version. */
 #define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 4
 
 /* Minimum Blender version that supports reading file written with the current
  * version. Older Blender versions will test this and show a warning if the file
  * was written with too new a version. */
 #define BLENDER_FILE_MIN_VERSION 305
-#define BLENDER_FILE_MIN_SUBVERSION 3
+#define BLENDER_FILE_MIN_SUBVERSION 4
 
 /** User readable version string. */
 const char *BKE_blender_version_string(void);
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index c98a9f67bbc..9bc42879d78 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -1130,7 +1130,7 @@ static void node_init(const bContext *C, bNodeTree *ntree, bNode *node)
     ntype->initfunc(ntree, node);
   }
 
-  if (ntree->typeinfo->node_add_init != nullptr) {
+  if (ntree->typeinfo && ntree->typeinfo->node_add_init) {
     ntree->typeinfo->node_add_init(ntree, node);
   }
 
diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc
index a90a8cfd753..c22c74ac237 100644
--- a/source/blender/blenloader/intern/versioning_300.cc
+++ b/source/blender/blenloader/intern/versioning_300.cc
@@ -823,6 +823,99 @@ static void version_geometry_nodes_replace_transfer_attribute_node(bNodeTree *nt
   }
 }
 
+/**
+ * The mesh primitive nodes created a uv map with a hardcoded name. Now they are outputting the uv
+ * map as a socket instead. The versioning just inserts a Store Named Attribute node after
+ * primitive nodes.
+ */
+static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree)
+{
+  blender::Vector<bNode *> new_nodes;
+  LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) {
+    if (!ELEM(node->type,
+              GEO_NODE_MESH_PRIMITIVE_CONE,
+              GEO_NODE_MESH_PRIMITIVE_CUBE,
+              GEO_NODE_MESH_PRIMITIVE_CYLINDER,
+              GEO_NODE_MESH_PRIMITIVE_GRID,
+              GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE,
+              GEO_NODE_MESH_PRIMITIVE_UV_SPHERE)) {
+      continue;
+    }
+    bNodeSocket *primitive_output_socket = nullptr;
+    bNodeSocket *uv_map_output_socket = nullptr;
+    LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) {
+      if (STREQ(socket->name, "UV Map")) {
+        uv_map_output_socket = socket;
+      }
+      if (socket->type == SOCK_GEOMETRY) {
+        primitive_output_socket = socket;
+      }
+    }
+    if (uv_map_output_socket != nullptr) {
+      continue;
+    }
+    uv_map_output_socket = nodeAddStaticSocket(
+        &ntree, node, SOCK_OUT, SOCK_VECTOR, PROP_NONE, "UV Map", "UV Map");
+
+    bNode *store_attribute_node = nodeAddStaticNode(
+        nullptr, &ntree, GEO_NODE_STORE_NAMED_ATTRIBUTE);
+    new_nodes.append(store_attribute_node);
+    store_attribute_node->parent = node->parent;
+    store_attribute_node->locx = node->locx + 25;
+    store_attribute_node->locy = node->locy;
+    store_attribute_node->offsetx = node->offsetx;
+    store_attribute_node->offsety = node->offsety;
+    NodeGeometryStoreNamedAttribute &storage = *static_cast<NodeGeometryStoreNamedAttribute *>(
+        store_attribute_node->storage);
+    storage.domain = ATTR_DOMAIN_CORNER;
+    /* Intentionally use 3D instead of 2D vectors, because 2D vectors did not exist in older
+     * releases and would make the file crash when trying to open it. */
+    storage.data_type = CD_PROP_FLOAT3;
+
+    bNodeSocket *store_attribute_geometry_input = static_cast<bNodeSocket *>(
+        store_attribute_node->inputs.first);
+    bNodeSocket *store_attribute_name_input = store_attribute_geometry_input->next;
+    bNodeSocket *store_attribute_value_input = nullptr;
+    LISTBASE_FOREACH (bNodeSocket *, socket, &store_attribute_node->inputs) {
+      if (socket->type == SOCK_VECTOR) {
+        store_attribute_value_input = socket;
+        break;
+      }
+    }
+    bNodeSocket *store_attribute_geometry_output = static_cast<bNodeSocket *>(
+        store_attribute_node->outputs.first);
+    LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) {
+      if (link->fromsock == primitive_output_socket) {
+        link->fromnode = store_attribute_node;
+        link->fromsock = store_attribute_geometry_output;
+      }
+    }
+
+    bNodeSocketValueString *name_value = static_cast<bNodeSocketValueString *>(
+        store_attribute_name_input->default_value);
+    const char *uv_map_name = node->type == GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE ? "UVMap" :
+                                                                                 "uv_map";
+    BLI_strncpy(name_value->value, uv_map_name, sizeof(name_value->value));
+
+    nodeAddLink(&ntree,
+                node,
+                primitive_output_socket,
+                store_attribute_node,
+                store_attribute_geometry_input);
+    nodeAddLink(
+        &ntree, node, uv_map_output_socket, store_attribute_node, store_attribute_value_input);
+  }
+
+  /* Move nodes to the front so that they are drawn behind existing nodes. */
+  for (bNode *node : new_nodes) {
+    BLI_remlink(&ntree.nodes, node);
+    BLI_addhead(&ntree.nodes, node);
+  }
+  if (!new_nodes.is_empty()) {
+    nodeRebuildIDVector(&ntree);
+  }
+}
+
 void do_versions_after_linking_300(Main *bmain, ReportList * /*reports*/)
 {
   if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) {
@@ -3708,18 +3801,7 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
     }
   }
 
-  /**
-   * Versioning code until next subversion bump goes here.
-   *
-   * \note Be sure to check when bumping the version:
-   * - "versioning_userdef.c", #blo_do_versions_userdef
-   * - "versioning_userdef.c", #do_versions_theme
-   *
-   * \note Keep this message at the bottom of the function.
-   */
-  {
-    /* Keep this block, even when empty. */
-
+  if (!MAIN_VERSION_ATLEAST(bmain, 305, 4)) {
     LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
       if (ntree->type == NTREE_GEOMETRY) {
         version_node_socket_name(ntree, GEO_NODE_COLLECTION_INFO, "Geometry", "Instances");
@@ -3732,5 +3814,24 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain)
         image->seam_margin = 8;
       }
     }
+
+    LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) {
+      if (ntree->type == NTREE_GEOMETRY) {
+        version_geometry_nodes_primitive_uv_maps(*ntree);
+      }
+    }
+  }
+
+  /**
+   * Versioning code until next subversion bump goes here.
+   *
+   * \note Be sure to check when bumping the version:
+   * - "versioning_userdef.c", #blo_do_versions_userdef
+   * - "versioning_userdef.c", #do_versions_theme
+   *
+   * \note Keep this message at the bottom of the function.
+   */
+  {
+    /* Keep this block, even when empty. */
   }
 }
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 1b75d13a1aa..d1aeff2cd7a 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -46,12 +46,14 @@ void transform_geometry_set(GeoNodeExecParams &params,
 
 Mesh *create_line_mesh(const float3 start, const float3 delta, int count);
 
-Mesh *create_grid_mesh(int verts_x, int verts_y, float size_x, float size_y);
+Mesh *create_grid_mesh(
+    int verts_x, int verts_y, float size_x, float size_y, const AttributeIDRef &uv_map_id);
 
 struct ConeAttributeOutputs {
   StrongAnonymousAttributeID top_id;
   StrongAnonymousAttributeID bottom_id;
   StrongAnonymousAttributeID side_id;
+  StrongAnonymousAttributeID uv_map_id;
 };
 
 Mesh *create_cylinder_or_cone_mesh(float radius_top,
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index e89a27a68c6..13c7c6a7a24 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -536,12 +536,14 @@ static void calculate_selection_outputs(const ConeConfig &config,
  * If the mesh is a truncated cone or a cylinder, the side faces are unwrapped into
  * a rectangle that fills the top half of the UV (or the entire UV, if there are no fills).
  */
-static void calculate_cone_uvs(Mesh *mesh, const ConeConfig &config)
+static void calculate_cone_uvs(const ConeConfig &config,
+                               Mesh *mesh,
+                               const AttributeIDRef &uv_map_id)
 {
   MutableAttributeAccessor attributes = mesh->attributes_for_write();
 
   SpanAttributeWriter<float2> uv_attribute = attributes.lookup_or_add_for_write_only_span<float2>(
-      "uv_map", ATTR_DOMAIN_CORNER);
+      uv_map_id, ATTR_DOMAIN_CORNER);
   MutableSpan<float2> uvs = uv_attribute.span;
 
   Array<float2> circle(config.circle_segments);
@@ -698,7 +700,9 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
   calculate_cone_verts(config, verts);
   calculate_cone_edges(config, edges);
   calculate_cone_faces(config, loops, polys);
-  calculate_cone_uvs(mesh, config);
+  if (attribute_outputs.uv_map_id) {
+    calculate_cone_uvs(config, mesh, attribute_outputs.uv_map_id.get());
+  }
   calculate_selection_outputs(config, attribute_outputs, mesh->attributes_for_write());
 
   mesh->loose_edges_tag_none();
@@ -747,6 +751,7 @@ static void node_declare(NodeDeclarationBuilder &b)
   b.add_output<decl::Bool>(N_("Top")).field_source();
   b.add_output<decl::Bool>(N_("Bottom")).field_source();
   b.add_output<decl::Bool>(N_("Side")).field_source();
+  b.add_output<decl::Vector>(N_("UV Map")).field_source();
 }
 
 static void node_init(bNodeTree * /*tree*/, bNode *node)
@@ -818,6 +823,9 @@ static void node_geo_exec(GeoNodeExecParams pa

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list