Blender V5.0
node_geo_uv_pack_islands.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "GEO_uv_pack.hh"
7
8#include "DNA_mesh_types.h"
9
10#include "node_geometry_util.hh"
11
13
15enum class ShapeMethod : int16_t {
16 Aabb = 0,
17 Convex = 1,
19};
20
23 "AABB",
24 0,
25 N_("Bounding Box"),
26 N_("Use axis-aligned bounding boxes for packing (fastest, least space efficient)")},
28 "CONVEX",
29 0,
30 N_("Convex Hull"),
31 N_("Use convex hull approximation of islands (good balance of speed and space efficiency)")},
33 "CONCAVE",
34 0,
35 N_("Exact Shape"),
36 N_("Use exact geometry for most efficient packing (slowest)")},
37 {0, nullptr, 0, nullptr, nullptr},
38};
39
53
55{
56 b.use_custom_socket_order();
57 b.allow_any_socket_order();
58 b.add_input<decl::Vector>("UV").hide_value().supports_field();
59 b.add_output<decl::Vector>("UV").field_source_reference_all().align_with_previous();
60 b.add_input<decl::Bool>("Selection")
61 .default_value(true)
62 .hide_value()
63 .supports_field()
64 .description("Faces to consider when packing islands");
65 b.add_input<decl::Float>("Margin").default_value(0.001f).min(0.0f).max(1.0f).description(
66 "Space between islands");
67 b.add_input<decl::Bool>("Rotate").default_value(true).description("Rotate islands for best fit");
68 b.add_input<decl::Menu>("Method")
69 .static_items(shape_method_items)
71 .optional_label()
72 .description("Method used for packing UV islands");
73}
74
76 const Field<bool> selection_field,
77 const Field<float3> uv_field,
78 const bool rotate,
79 const float margin,
80 const eUVPackIsland_ShapeMethod shape_method,
81 const AttrDomain domain)
82{
83 const Span<float3> positions = mesh.vert_positions();
84 const OffsetIndices faces = mesh.faces();
85 const Span<int> corner_verts = mesh.corner_verts();
86
87 const bke::MeshFieldContext face_context{mesh, AttrDomain::Face};
88 FieldEvaluator face_evaluator{face_context, faces.size()};
89 face_evaluator.add(selection_field);
90 face_evaluator.evaluate();
91 const IndexMask selection = face_evaluator.get_evaluated_as_mask(0);
92 if (selection.is_empty()) {
93 return {};
94 }
95
96 const bke::MeshFieldContext corner_context{mesh, AttrDomain::Corner};
97 FieldEvaluator evaluator{corner_context, mesh.corners_num};
99 evaluator.add_with_destination(uv_field, uv.as_mutable_span());
100 evaluator.evaluate();
101
103 selection.foreach_index([&](const int face_index) {
104 const IndexRange face = faces[face_index];
105 Array<geometry::ParamKey, 16> mp_vkeys(face.size());
106 Array<bool, 16> mp_pin(face.size());
107 Array<bool, 16> mp_select(face.size());
108 Array<const float *, 16> mp_co(face.size());
109 Array<float *, 16> mp_uv(face.size());
110 for (const int i : IndexRange(face.size())) {
111 const int corner = face[i];
112 const int vert = corner_verts[corner];
113 mp_vkeys[i] = vert;
114 mp_co[i] = positions[vert];
115 mp_uv[i] = uv[corner];
116 mp_pin[i] = false;
117 mp_select[i] = false;
118 }
120 face_index,
121 face.size(),
122 mp_vkeys.data(),
123 mp_co.data(),
124 mp_uv.data(),
125 nullptr,
126 mp_pin.data(),
127 mp_select.data());
128 });
129 geometry::uv_parametrizer_construct_end(handle, true, true, nullptr);
130
132 params.shape_method = shape_method;
134 params.margin = margin;
135
138 delete (handle);
139
140 return mesh.attributes().adapt_domain<float3>(
141 VArray<float3>::from_container(std::move(uv)), AttrDomain::Corner, domain);
142}
143
145 private:
146 const Field<bool> selection_field_;
147 const Field<float3> uv_field_;
148 const bool rotate_;
149 const float margin_;
150 const eUVPackIsland_ShapeMethod shape_method_;
151
152 public:
153 PackIslandsFieldInput(const Field<bool> selection_field,
154 const Field<float3> uv_field,
155 const bool rotate,
156 const float margin,
157 const eUVPackIsland_ShapeMethod shape_method)
158 : bke::MeshFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
159 selection_field_(selection_field),
160 uv_field_(uv_field),
161 rotate_(rotate),
162 margin_(margin),
163 shape_method_(shape_method)
164 {
166 }
167
169 const AttrDomain domain,
170 const IndexMask & /*mask*/) const final
171 {
173 mesh, selection_field_, uv_field_, rotate_, margin_, shape_method_, domain);
174 }
175
176 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
177 {
178 selection_field_.node().for_each_field_input_recursive(fn);
179 uv_field_.node().for_each_field_input_recursive(fn);
180 }
181
182 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
183 {
184 return AttrDomain::Corner;
185 }
186};
187
189{
190 const ShapeMethod local_shape_method = params.get_input<ShapeMethod>("Method");
191 const eUVPackIsland_ShapeMethod shape_method = convert_shape_method(local_shape_method);
192
193 const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
194 const Field<float3> uv_field = params.extract_input<Field<float3>>("UV");
195 const bool rotate = params.extract_input<bool>("Rotate");
196 const float margin = params.extract_input<float>("Margin");
197 params.set_output("UV",
198 Field<float3>(std::make_shared<PackIslandsFieldInput>(
199 selection_field, uv_field, rotate, margin, shape_method)));
200}
201
202static void node_register()
203{
204 static blender::bke::bNodeType ntype;
205
206 geo_node_type_base(&ntype, "GeometryNodeUVPackIslands", GEO_NODE_UV_PACK_ISLANDS);
207 ntype.ui_name = "Pack UV Islands";
208 ntype.ui_description =
209 "Scale islands of a UV map and move them so they fill the UV space as much as possible";
210 ntype.enum_name_legacy = "UV_PACK_ISLANDS";
212 ntype.declare = node_declare;
215}
217
218} // namespace blender::nodes::node_geo_uv_pack_islands_cc
#define NODE_CLASS_CONVERTER
Definition BKE_node.hh:453
#define GEO_NODE_UV_PACK_ISLANDS
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define final(a, b, c)
Definition BLI_hash.h:19
eUVPackIsland_ShapeMethod
@ ED_UVPACK_SHAPE_AABB
@ ED_UVPACK_SHAPE_CONCAVE
@ ED_UVPACK_SHAPE_CONVEX
@ ED_UVPACK_ROTATION_ANY
@ ED_UVPACK_ROTATION_NONE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
AttributeSet attributes
MutableSpan< T > as_mutable_span()
Definition BLI_array.hh:248
const T * data() const
Definition BLI_array.hh:312
constexpr int64_t size() const
static VArray from_container(ContainerT container)
FieldInput(const CPPType &type, std::string debug_name="")
Definition field.cc:677
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
IndexMask get_evaluated_as_mask(int field_index)
Definition field.cc:804
int add_with_destination(GField field, GVMutableArray dst)
Definition field.cc:738
void foreach_index(Fn &&fn) const
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &) const final
PackIslandsFieldInput(const Field< bool > selection_field, const Field< float3 > uv_field, const bool rotate, const float margin, const eUVPackIsland_ShapeMethod shape_method)
std::optional< AttrDomain > preferred_domain(const Mesh &) const override
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
static char faces[256]
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
void uv_parametrizer_construct_end(ParamHandle *phandle, bool fill_holes, bool topology_from_uvs, int *r_count_failed=nullptr)
void uv_parametrizer_flush(ParamHandle *handle)
void uv_parametrizer_pack(ParamHandle *handle, const UVPackIsland_Params &params)
void uv_parametrizer_face_add(ParamHandle *handle, const ParamKey key, const int nverts, const ParamKey *vkeys, const float **co, float **uv, const float *weight, const bool *pin, const bool *select)
static void node_geo_exec(GeoNodeExecParams params)
static void node_declare(NodeDeclarationBuilder &b)
static VArray< float3 > construct_uv_gvarray(const Mesh &mesh, const Field< bool > selection_field, const Field< float3 > uv_field, const bool rotate, const float margin, const eUVPackIsland_ShapeMethod shape_method, const AttrDomain domain)
static eUVPackIsland_ShapeMethod convert_shape_method(const ShapeMethod method)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
static void rotate(float new_co[3], float a, const float ax[3], const float co[3])
int corners_num
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362
i
Definition text_draw.cc:230
#define N_(msgid)