Blender  V3.3
node_geo_uv_unwrap.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
3 #include "GEO_uv_parametrizer.h"
4 
5 #include "DNA_mesh_types.h"
6 #include "DNA_meshdata_types.h"
7 
8 #include "UI_interface.h"
9 #include "UI_resources.h"
10 
11 #include "node_geometry_util.hh"
12 
14 
16 
18 {
19  b.add_input<decl::Bool>(N_("Selection"))
20  .default_value(true)
21  .hide_value()
22  .supports_field()
23  .description(N_("Faces to participate in the unwrap operation"));
24  b.add_input<decl::Bool>(N_("Seam"))
25  .hide_value()
26  .supports_field()
27  .description(N_("Edges to mark where the mesh is \"cut\" for the purposes of unwrapping"));
28  b.add_input<decl::Float>(N_("Margin"))
29  .default_value(0.001f)
30  .min(0.0f)
31  .max(1.0f)
32  .description(N_("Space between islands"));
33  b.add_input<decl::Bool>(N_("Fill Holes"))
34  .default_value(true)
35  .description(N_("Virtually fill holes in mesh before unwrapping, to better avoid overlaps "
36  "and preserve symmetry"));
37  b.add_output<decl::Vector>(N_("UV")).field_source().description(
38  N_("UV coordinates between 0 and 1 for each face corner in the selected faces"));
39 }
40 
41 static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
42 {
43  uiLayoutSetPropSep(layout, true);
44  uiLayoutSetPropDecorate(layout, false);
45  uiItemR(layout, ptr, "method", 0, "", ICON_NONE);
46 }
47 
49 {
50  NodeGeometryUVUnwrap *data = MEM_cnew<NodeGeometryUVUnwrap>(__func__);
52  node->storage = data;
53 }
54 
56  const Field<bool> selection_field,
57  const Field<bool> seam_field,
58  const bool fill_holes,
59  const float margin,
60  const GeometryNodeUVUnwrapMethod method,
61  const eAttrDomain domain)
62 {
63  const Mesh *mesh = component.get_for_read();
64  if (mesh == nullptr) {
65  return {};
66  }
67 
68  const int face_num = component.attribute_domain_size(ATTR_DOMAIN_FACE);
70  FieldEvaluator face_evaluator{face_context, face_num};
71  face_evaluator.add(selection_field);
72  face_evaluator.evaluate();
73  const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
74  if (selection.is_empty()) {
75  return {};
76  }
77 
78  const int edge_num = component.attribute_domain_size(ATTR_DOMAIN_EDGE);
80  FieldEvaluator edge_evaluator{edge_context, edge_num};
81  edge_evaluator.add(seam_field);
82  edge_evaluator.evaluate();
83  const IndexMask seam = edge_evaluator.get_evaluated_as_mask(0);
84 
86 
88  for (const int mp_index : selection) {
89  const MPoly &mp = mesh->mpoly[mp_index];
90  Array<ParamKey, 16> mp_vkeys(mp.totloop);
91  Array<bool, 16> mp_pin(mp.totloop);
92  Array<bool, 16> mp_select(mp.totloop);
94  Array<float *, 16> mp_uv(mp.totloop);
95  for (const int i : IndexRange(mp.totloop)) {
96  const MLoop &ml = mesh->mloop[mp.loopstart + i];
97  mp_vkeys[i] = ml.v;
98  mp_co[i] = mesh->mvert[ml.v].co;
99  mp_uv[i] = uv[mp.loopstart + i];
100  mp_pin[i] = false;
101  mp_select[i] = false;
102  }
104  mp_index,
105  mp.totloop,
106  mp_vkeys.data(),
107  mp_co.data(),
108  mp_uv.data(),
109  mp_pin.data(),
110  mp_select.data());
111  }
112  for (const int i : seam) {
113  const MEdge &edge = mesh->medge[i];
114  ParamKey vkeys[2]{edge.v1, edge.v2};
115  GEO_uv_parametrizer_edge_set_seam(handle, vkeys);
116  }
117  /* TODO: once field input nodes are able to emit warnings (T94039), emit a
118  * warning if we fail to solve an island. */
119  GEO_uv_parametrizer_construct_end(handle, fill_holes, false, nullptr);
120 
122  GEO_uv_parametrizer_lscm_solve(handle, nullptr, nullptr);
124  GEO_uv_parametrizer_average(handle, true, false, false);
125  GEO_uv_parametrizer_pack(handle, margin, true, true);
128 
129  return component.attributes()->adapt_domain<float3>(
130  VArray<float3>::ForContainer(std::move(uv)), ATTR_DOMAIN_CORNER, domain);
131 }
132 
134  private:
135  const Field<bool> selection;
136  const Field<bool> seam;
137  const bool fill_holes;
138  const float margin;
139  const GeometryNodeUVUnwrapMethod method;
140 
141  public:
142  UnwrapFieldInput(const Field<bool> selection,
143  const Field<bool> seam,
144  const bool fill_holes,
145  const float margin,
146  const GeometryNodeUVUnwrapMethod method)
147  : GeometryFieldInput(CPPType::get<float3>(), "UV Unwrap Field"),
148  selection(selection),
149  seam(seam),
150  fill_holes(fill_holes),
151  margin(margin),
152  method(method)
153  {
155  }
156 
158  const eAttrDomain domain,
159  IndexMask UNUSED(mask)) const final
160  {
161  if (component.type() == GEO_COMPONENT_TYPE_MESH) {
162  const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
163  return construct_uv_gvarray(
164  mesh_component, selection, seam, fill_holes, margin, method, domain);
165  }
166  return {};
167  }
168 };
169 
171 {
172  const NodeGeometryUVUnwrap &storage = node_storage(params.node());
174  const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
175  const Field<bool> seam_field = params.extract_input<Field<bool>>("Seam");
176  const bool fill_holes = params.extract_input<bool>("Fill Holes");
177  const float margin = params.extract_input<float>("Margin");
178  params.set_output("UV",
179  Field<float3>(std::make_shared<UnwrapFieldInput>(
180  selection_field, seam_field, fill_holes, margin, method)));
181 }
182 
183 } // namespace blender::nodes::node_geo_uv_unwrap_cc
184 
186 {
187  namespace file_ns = blender::nodes::node_geo_uv_unwrap_cc;
188 
189  static bNodeType ntype;
190 
194  &ntype, "NodeGeometryUVUnwrap", node_free_standard_storage, node_copy_standard_storage);
198  nodeRegisterType(&ntype);
199 }
eAttrDomain
Definition: BKE_attribute.h:25
@ ATTR_DOMAIN_FACE
Definition: BKE_attribute.h:29
@ ATTR_DOMAIN_CORNER
Definition: BKE_attribute.h:30
@ ATTR_DOMAIN_EDGE
Definition: BKE_attribute.h:28
@ GEO_COMPONENT_TYPE_MESH
#define NODE_CLASS_CONVERTER
Definition: BKE_node.h:351
#define NODE_STORAGE_FUNCS(StorageT)
Definition: BKE_node.h:1563
#define GEO_NODE_UV_UNWRAP
Definition: BKE_node.h:1506
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
Definition: node.cc:4390
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
#define final(a, b, c)
Definition: BLI_hash.h:21
#define UNUSED(x)
static uint8 component(Color32 c, uint i)
Definition: ColorBlock.cpp:108
GeometryNodeUVUnwrapMethod
@ GEO_NODE_UV_UNWRAP_METHOD_ANGLE_BASED
void GEO_uv_parametrizer_flush(ParamHandle *handle)
ParamHandle * GEO_uv_parametrizer_construct_begin(void)
void GEO_uv_parametrizer_lscm_end(ParamHandle *handle)
void GEO_uv_parametrizer_face_add(ParamHandle *handle, const ParamKey key, const int nverts, const ParamKey *vkeys, const float **co, float **uv, const bool *pin, const bool *select)
void GEO_uv_parametrizer_average(ParamHandle *handle, bool ignore_pinned, bool scale_uv, bool shear)
void GEO_uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
void GEO_uv_parametrizer_construct_end(ParamHandle *handle, bool fill, bool topology_from_uvs, int *count_fail)
void GEO_uv_parametrizer_lscm_solve(ParamHandle *handle, int *count_changed, int *count_failed)
void GEO_uv_parametrizer_delete(ParamHandle *handle)
void GEO_uv_parametrizer_edge_set_seam(ParamHandle *handle, ParamKey *vkeys)
intptr_t ParamKey
void GEO_uv_parametrizer_lscm_begin(ParamHandle *handle, bool live, bool abf)
void uiLayoutSetPropSep(uiLayout *layout, bool is_sep)
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep)
const T * data() const
Definition: BLI_array.hh:300
bool is_empty() const
static VArray ForContainer(ContainerT container)
int add(GField field, GVArray *varray_ptr)
Definition: field.cc:731
UnwrapFieldInput(const Field< bool > selection, const Field< bool > seam, const bool fill_holes, const float margin, const GeometryNodeUVUnwrapMethod method)
GVArray get_varray_for_context(const GeometryComponent &component, const eAttrDomain domain, IndexMask UNUSED(mask)) const final
OperationNode * node
void * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
ccl_device_inline float4 mask(const int4 &mask, const float4 &a)
Definition: math_float4.h:513
static VArray< float3 > construct_uv_gvarray(const MeshComponent &component, const Field< bool > selection_field, const Field< bool > seam_field, const bool fill_holes, const float margin, const GeometryNodeUVUnwrapMethod method, const eAttrDomain domain)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
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_uv_unwrap()
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
unsigned int v
float co[3]
struct MEdge * medge
struct MVert * mvert
struct MLoop * mloop
int totloop
struct MPoly * mpoly
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