Blender  V3.3
node_geo_subdivision_surface.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "BLI_task.hh"
4 
5 #include "DNA_mesh_types.h"
6 #include "DNA_meshdata_types.h"
7 #include "DNA_modifier_types.h"
8 
9 #include "BKE_attribute.hh"
10 #include "BKE_mesh.h"
11 #include "BKE_subdiv.h"
12 #include "BKE_subdiv_mesh.h"
13 
14 #include "UI_interface.h"
15 #include "UI_resources.h"
16 
17 #include "node_geometry_util.hh"
18 
20 
22 
24 {
25  b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH);
26  b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6);
27  b.add_input<decl::Float>(N_("Edge Crease"))
28  .default_value(0.0f)
29  .min(0.0f)
30  .max(1.0f)
31  .supports_field()
32  .subtype(PROP_FACTOR);
33  b.add_input<decl::Float>(N_("Vertex Crease"))
34  .default_value(0.0f)
35  .min(0.0f)
36  .max(1.0f)
37  .supports_field()
38  .subtype(PROP_FACTOR);
39  b.add_output<decl::Geometry>(N_("Mesh"));
40 }
41 
42 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
43 {
44  uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE);
45  uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE);
46 }
47 
49 {
50  NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__);
52  data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL;
53  node->storage = data;
54 }
55 
56 #ifdef WITH_OPENSUBDIV
57 static void materialize_and_clamp_creases(const VArray<float> &crease_varray,
58  MutableSpan<float> creases)
59 {
60  threading::parallel_for(creases.index_range(), 1024, [&](IndexRange range) {
61  crease_varray.materialize(range, creases);
62  for (const int i : range) {
63  creases[i] = std::clamp(creases[i], 0.0f, 1.0f);
64  }
65  });
66 }
67 
68 static void write_vertex_creases(Mesh &mesh, const VArray<float> &crease_varray)
69 {
70  float *crease;
72  crease = static_cast<float *>(CustomData_get_layer(&mesh.vdata, CD_CREASE));
73  }
74  else {
75  crease = static_cast<float *>(
77  }
78  materialize_and_clamp_creases(crease_varray, {crease, mesh.totvert});
79 }
80 
81 static void write_edge_creases(MeshComponent &mesh, const VArray<float> &crease_varray)
82 {
83  bke::SpanAttributeWriter<float> attribute =
84  mesh.attributes_for_write()->lookup_or_add_for_write_only_span<float>("crease",
86  materialize_and_clamp_creases(crease_varray, attribute.span);
87  attribute.finish();
88 }
89 
90 static bool varray_is_nonzero(const VArray<float> &varray)
91 {
92  return !(varray.is_single() && varray.get_internal_single() == 0.0f);
93 }
94 #endif
95 
97 {
98  GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
99 #ifndef WITH_OPENSUBDIV
100  params.error_message_add(NodeWarningType::Error,
101  TIP_("Disabled, Blender was compiled without OpenSubdiv"));
102 #else
103  Field<float> edge_crease_field = params.extract_input<Field<float>>("Edge Crease");
104  Field<float> vertex_crease_field = params.extract_input<Field<float>>("Vertex Crease");
105 
106  const NodeGeometrySubdivisionSurface &storage = node_storage(params.node());
107  const int uv_smooth = storage.uv_smooth;
108  const int boundary_smooth = storage.boundary_smooth;
109  const int subdiv_level = clamp_i(params.extract_input<int>("Level"), 0, 30);
110 
111  /* Only process subdivision if level is greater than 0. */
112  if (subdiv_level == 0) {
113  params.set_output("Mesh", std::move(geometry_set));
114  return;
115  }
116 
117  geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) {
118  if (!geometry_set.has_mesh()) {
119  return;
120  }
121 
122  const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>();
123  const int verts_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
124  const int edges_num = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
125  if (verts_num == 0 || edges_num == 0) {
126  return;
127  }
128 
129  GeometryComponentFieldContext point_context{mesh_component, ATTR_DOMAIN_POINT};
130  FieldEvaluator point_evaluator(point_context, verts_num);
131  point_evaluator.add(vertex_crease_field);
132  point_evaluator.evaluate();
133  const VArray<float> vertex_creases = point_evaluator.get_evaluated<float>(0);
134 
135  GeometryComponentFieldContext edge_context{mesh_component, ATTR_DOMAIN_EDGE};
136  FieldEvaluator edge_evaluator(edge_context, edges_num);
137  edge_evaluator.add(edge_crease_field);
138  edge_evaluator.evaluate();
139  const VArray<float> edge_creases = edge_evaluator.get_evaluated<float>(0);
140 
141  const bool use_creases = varray_is_nonzero(vertex_creases) || varray_is_nonzero(edge_creases);
142 
143  if (use_creases) {
144  write_vertex_creases(*geometry_set.get_mesh_for_write(), vertex_creases);
145  write_edge_creases(geometry_set.get_component_for_write<MeshComponent>(), edge_creases);
146  }
147 
148  /* Initialize mesh settings. */
149  SubdivToMeshSettings mesh_settings;
150  mesh_settings.resolution = (1 << subdiv_level) + 1;
151  mesh_settings.use_optimal_display = false;
152 
153  /* Initialize subdivision settings. */
154  SubdivSettings subdiv_settings;
155  subdiv_settings.is_simple = false;
156  subdiv_settings.is_adaptive = false;
157  subdiv_settings.use_creases = use_creases;
158  subdiv_settings.level = subdiv_level;
159 
160  subdiv_settings.vtx_boundary_interpolation =
163  uv_smooth);
164 
165  const Mesh &mesh_in = *geometry_set.get_mesh_for_read();
166 
167  /* Apply subdivision to mesh. */
168  Subdiv *subdiv = BKE_subdiv_update_from_mesh(nullptr, &subdiv_settings, &mesh_in);
169 
170  /* In case of bad topology, skip to input mesh. */
171  if (subdiv == nullptr) {
172  return;
173  }
174 
175  Mesh *mesh_out = BKE_subdiv_to_mesh(subdiv, &mesh_settings, &mesh_in);
176 
177  geometry_set.replace_mesh(mesh_out);
178 
179  BKE_subdiv_free(subdiv);
180  });
181 #endif
182  params.set_output("Mesh", std::move(geometry_set));
183 }
184 
185 } // namespace blender::nodes::node_geo_subdivision_surface_cc
186 
188 {
190 
191  static bNodeType ntype;
192 
194  &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY);
200  node_type_storage(&ntype,
201  "NodeGeometrySubdivisionSurface",
204  nodeRegisterType(&ntype);
205 }
@ ATTR_DOMAIN_POINT
Definition: BKE_attribute.h:27
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:28
@ CD_DEFAULT
bool CustomData_has_layer(const struct CustomData *data, int type)
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
@ GEO_COMPONENT_TYPE_MESH
#define GEO_NODE_SUBDIVISION_SURFACE
Definition: BKE_node.h:1468
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
void node_type_size_preset(struct bNodeType *ntype, eNodeSizePreset size)
Definition: node.cc:4408
#define NODE_CLASS_GEOMETRY
Definition: BKE_node.h:359
void node_type_storage(struct bNodeType *ntype, const char *storagename, void(*freefunc)(struct bNode *node), void(*copyfunc)(struct bNodeTree *dest_ntree, struct bNode *dest_node, const struct bNode *src_node))
Definition: node.cc:4426
void nodeRegisterType(struct bNodeType *ntype)
Definition: node.cc:1357
@ NODE_SIZE_MIDDLE
Definition: BKE_node.h:366
eSubdivVtxBoundaryInterpolation BKE_subdiv_vtx_boundary_interpolation_from_subsurf(int boundary_smooth)
Definition: subdiv.c:66
void BKE_subdiv_free(Subdiv *subdiv)
Definition: subdiv.c:184
Subdiv * BKE_subdiv_update_from_mesh(Subdiv *subdiv, const SubdivSettings *settings, const struct Mesh *mesh)
eSubdivFVarLinearInterpolation BKE_subdiv_fvar_interpolation_from_uv_smooth(int uv_smooth)
Definition: subdiv.c:46
struct Mesh * BKE_subdiv_to_mesh(struct Subdiv *subdiv, const SubdivToMeshSettings *settings, const struct Mesh *coarse_mesh)
MINLINE int clamp_i(int value, int min, int max)
#define UNUSED(x)
#define TIP_(msgid)
@ SUBSURF_BOUNDARY_SMOOTH_ALL
@ SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
@ PROP_FACTOR
Definition: RNA_types.h:144
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
int attribute_domain_size(eAttrDomain domain) const
Definition: geometry_set.cc:63
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
int add(GField field, GVArray *varray_ptr)
Definition: field.cc:731
const GVArray & get_evaluated(const int field_index) const
Definition: FN_field.hh:431
OperationNode * node
bNodeTree * ntree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_init(bNodeTree *UNUSED(ntree), bNode *node)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
Definition: node.cc:1082
void register_node_type_geo_subdivision_surface()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
void node_copy_standard_storage(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node)
Definition: node_util.c:55
void node_free_standard_storage(bNode *node)
Definition: node_util.c:43
void replace_mesh(Mesh *mesh, GeometryOwnershipType ownership=GeometryOwnershipType::Owned)
GeometryComponent & get_component_for_write(GeometryComponentType component_type)
const GeometryComponent * get_component_for_read(GeometryComponentType component_type) const
const Mesh * get_mesh_for_read() const
Mesh * get_mesh_for_write()
void modify_geometry_sets(ForeachSubGeometryCallback callback)
bool has_mesh() const
CustomData vdata
int totvert
bool is_adaptive
Definition: BKE_subdiv.h:60
eSubdivFVarLinearInterpolation fvar_linear_interpolation
Definition: BKE_subdiv.h:71
bool use_creases
Definition: BKE_subdiv.h:68
eSubdivVtxBoundaryInterpolation vtx_boundary_interpolation
Definition: BKE_subdiv.h:70
Defines a node type.
Definition: BKE_node.h:226
NodeGeometryExecFunction geometry_node_execute
Definition: BKE_node.h:316
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
Definition: BKE_node.h:244
NodeDeclareFunction declare
Definition: BKE_node.h:324
#define N_(msgid)
PointerRNA * ptr
Definition: wm_files.c:3480