Geometry Nodes: Add Shape Method parameter to Pack UV Islands node
Adds a Shape Method parameter to the UV Pack Islands node, enabling artists to choose between faster packing and more efficient space utilization. Those are the three shape method options: * Bounding Box: Fastest, less efficient space usage * Convex Hull: Balanced performance and efficiency * Exact Shape: Optimal packing, higher computational cost This change consolidates arguments in `uv_parametrizer_pack()`. Now it accept ` UVPackIsland_Params` instead of many different separate options. This also makes it easier to expose more options in the future. Pull Request: https://projects.blender.org/blender/blender/pulls/139110
This commit is contained in:
parent
30644d20a8
commit
aced349e3d
@ -10,6 +10,10 @@ namespace slim {
|
||||
struct MatrixTransfer;
|
||||
}
|
||||
|
||||
namespace blender::geometry {
|
||||
class UVPackIsland_Params;
|
||||
}
|
||||
|
||||
/** \file
|
||||
* \ingroup geo
|
||||
*/
|
||||
@ -166,7 +170,7 @@ void uv_parametrizer_stretch_end(ParamHandle *handle);
|
||||
/** \name Packing
|
||||
* \{ */
|
||||
|
||||
void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned);
|
||||
void uv_parametrizer_pack(ParamHandle *handle, const UVPackIsland_Params ¶ms);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
@ -4176,7 +4176,7 @@ void uv_parametrizer_stretch_end(ParamHandle *phandle)
|
||||
phandle->state = PHANDLE_STATE_CONSTRUCTED;
|
||||
}
|
||||
|
||||
void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, bool ignore_pinned)
|
||||
void uv_parametrizer_pack(ParamHandle *handle, const UVPackIsland_Params ¶ms)
|
||||
{
|
||||
if (handle->ncharts == 0) {
|
||||
return;
|
||||
@ -4186,14 +4186,9 @@ void uv_parametrizer_pack(ParamHandle *handle, float margin, bool do_rotate, boo
|
||||
|
||||
Vector<PackIsland *> pack_island_vector;
|
||||
|
||||
UVPackIsland_Params params;
|
||||
params.rotate_method = do_rotate ? ED_UVPACK_ROTATION_ANY : ED_UVPACK_ROTATION_NONE;
|
||||
params.margin = margin;
|
||||
params.margin_method = ED_UVPACK_MARGIN_SCALED;
|
||||
|
||||
for (int i = 0; i < handle->ncharts; i++) {
|
||||
PChart *chart = handle->charts[i];
|
||||
if (ignore_pinned && chart->has_pins) {
|
||||
if (params.pin_method == ED_UVPACK_PIN_NONE && chart->has_pins) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2,16 +2,45 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GEO_uv_pack.hh"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "node_geometry_util.hh"
|
||||
|
||||
#include "NOD_rna_define.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
|
||||
namespace blender::nodes::node_geo_uv_pack_islands_cc {
|
||||
|
||||
/** Local node enum that maps to eUVPackIsland_ShapeMethod in GEO_uv_pack.hh. */
|
||||
enum class ShapeMethod : int16_t {
|
||||
Aabb = 0,
|
||||
Convex = 1,
|
||||
Concave = 2,
|
||||
};
|
||||
|
||||
static eUVPackIsland_ShapeMethod convert_shape_method(const ShapeMethod method)
|
||||
{
|
||||
switch (method) {
|
||||
case ShapeMethod::Aabb:
|
||||
return ED_UVPACK_SHAPE_AABB;
|
||||
case ShapeMethod::Convex:
|
||||
return ED_UVPACK_SHAPE_CONVEX;
|
||||
case ShapeMethod::Concave:
|
||||
return ED_UVPACK_SHAPE_CONCAVE;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return ED_UVPACK_SHAPE_AABB;
|
||||
}
|
||||
|
||||
static void node_declare(NodeDeclarationBuilder &b)
|
||||
{
|
||||
b.use_custom_socket_order();
|
||||
b.allow_any_socket_order();
|
||||
b.add_default_layout();
|
||||
b.add_input<decl::Vector>("UV").hide_value().supports_field();
|
||||
b.add_input<decl::Bool>("Selection")
|
||||
.default_value(true)
|
||||
@ -24,11 +53,22 @@ static void node_declare(NodeDeclarationBuilder &b)
|
||||
b.add_output<decl::Vector>("UV").field_source_reference_all();
|
||||
}
|
||||
|
||||
static void node_layout(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr)
|
||||
{
|
||||
layout->prop(ptr, "shape_method", UI_ITEM_NONE, "", ICON_NONE);
|
||||
}
|
||||
|
||||
static void node_init(bNodeTree * /*tree*/, bNode *node)
|
||||
{
|
||||
node->custom1 = int16_t(ShapeMethod::Aabb);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
const Span<float3> positions = mesh.vert_positions();
|
||||
@ -79,7 +119,12 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
||||
});
|
||||
geometry::uv_parametrizer_construct_end(handle, true, true, nullptr);
|
||||
|
||||
geometry::uv_parametrizer_pack(handle, margin, rotate, true);
|
||||
blender::geometry::UVPackIsland_Params params;
|
||||
params.shape_method = shape_method;
|
||||
params.rotate_method = rotate ? ED_UVPACK_ROTATION_ANY : ED_UVPACK_ROTATION_NONE;
|
||||
params.margin = margin;
|
||||
|
||||
geometry::uv_parametrizer_pack(handle, params);
|
||||
geometry::uv_parametrizer_flush(handle);
|
||||
delete (handle);
|
||||
|
||||
@ -93,17 +138,20 @@ class PackIslandsFieldInput final : public bke::MeshFieldInput {
|
||||
const Field<float3> uv_field_;
|
||||
const bool rotate_;
|
||||
const float margin_;
|
||||
const eUVPackIsland_ShapeMethod shape_method_;
|
||||
|
||||
public:
|
||||
PackIslandsFieldInput(const Field<bool> selection_field,
|
||||
const Field<float3> uv_field,
|
||||
const bool rotate,
|
||||
const float margin)
|
||||
const float margin,
|
||||
const eUVPackIsland_ShapeMethod shape_method)
|
||||
: bke::MeshFieldInput(CPPType::get<float3>(), "Pack UV Islands Field"),
|
||||
selection_field_(selection_field),
|
||||
uv_field_(uv_field),
|
||||
rotate_(rotate),
|
||||
margin_(margin)
|
||||
margin_(margin),
|
||||
shape_method_(shape_method)
|
||||
{
|
||||
category_ = Category::Generated;
|
||||
}
|
||||
@ -112,7 +160,8 @@ class PackIslandsFieldInput final : public bke::MeshFieldInput {
|
||||
const AttrDomain domain,
|
||||
const IndexMask & /*mask*/) const final
|
||||
{
|
||||
return construct_uv_gvarray(mesh, selection_field_, uv_field_, rotate_, margin_, domain);
|
||||
return construct_uv_gvarray(
|
||||
mesh, selection_field_, uv_field_, rotate_, margin_, shape_method_, domain);
|
||||
}
|
||||
|
||||
void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
|
||||
@ -129,13 +178,47 @@ class PackIslandsFieldInput final : public bke::MeshFieldInput {
|
||||
|
||||
static void node_geo_exec(GeoNodeExecParams params)
|
||||
{
|
||||
const bNode &node = params.node();
|
||||
const ShapeMethod local_shape_method = ShapeMethod(node.custom1);
|
||||
const eUVPackIsland_ShapeMethod shape_method = convert_shape_method(local_shape_method);
|
||||
|
||||
const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection");
|
||||
const Field<float3> uv_field = params.extract_input<Field<float3>>("UV");
|
||||
const bool rotate = params.extract_input<bool>("Rotate");
|
||||
const float margin = params.extract_input<float>("Margin");
|
||||
params.set_output("UV",
|
||||
Field<float3>(std::make_shared<PackIslandsFieldInput>(
|
||||
selection_field, uv_field, rotate, margin)));
|
||||
selection_field, uv_field, rotate, margin, shape_method)));
|
||||
}
|
||||
|
||||
static void node_rna(StructRNA *srna)
|
||||
{
|
||||
static const EnumPropertyItem shape_method_items[] = {
|
||||
{int(ShapeMethod::Aabb),
|
||||
"AABB",
|
||||
0,
|
||||
"Bounding Box",
|
||||
"Use axis-aligned bounding boxes for packing (fastest, least space efficient)"},
|
||||
{int(ShapeMethod::Convex),
|
||||
"CONVEX",
|
||||
0,
|
||||
"Convex Hull",
|
||||
"Use convex hull approximation of islands (good balance of speed and space efficiency)"},
|
||||
{int(ShapeMethod::Concave),
|
||||
"CONCAVE",
|
||||
0,
|
||||
"Exact Shape",
|
||||
"Use exact geometry for most efficient packing (slowest)"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
RNA_def_node_enum(srna,
|
||||
"shape_method",
|
||||
"Shape Method",
|
||||
"Method used for packing UV islands",
|
||||
shape_method_items,
|
||||
NOD_inline_enum_accessors(custom1),
|
||||
int(ShapeMethod::Aabb));
|
||||
}
|
||||
|
||||
static void node_register()
|
||||
@ -148,9 +231,13 @@ static void node_register()
|
||||
"Scale islands of a UV map and move them so they fill the UV space as much as possible";
|
||||
ntype.enum_name_legacy = "UV_PACK_ISLANDS";
|
||||
ntype.nclass = NODE_CLASS_CONVERTER;
|
||||
ntype.initfunc = node_init;
|
||||
ntype.declare = node_declare;
|
||||
ntype.geometry_node_execute = node_geo_exec;
|
||||
ntype.draw_buttons = node_layout;
|
||||
blender::bke::node_register_type(ntype);
|
||||
|
||||
node_rna(ntype.rna_ext.srna);
|
||||
}
|
||||
NOD_REGISTER_NODE(node_register)
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "GEO_uv_pack.hh"
|
||||
#include "GEO_uv_parametrizer.hh"
|
||||
|
||||
#include "UI_interface.hh"
|
||||
@ -114,6 +115,10 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
||||
geometry::uv_parametrizer_edge_set_seam(handle, vkeys);
|
||||
});
|
||||
|
||||
blender::geometry::UVPackIsland_Params params;
|
||||
params.margin = margin;
|
||||
params.rotate_method = ED_UVPACK_ROTATION_ANY;
|
||||
|
||||
/* TODO: once field input nodes are able to emit warnings (#94039), emit a
|
||||
* warning if we fail to solve an island. */
|
||||
geometry::uv_parametrizer_construct_end(handle, fill_holes, false, nullptr);
|
||||
@ -123,7 +128,7 @@ static VArray<float3> construct_uv_gvarray(const Mesh &mesh,
|
||||
geometry::uv_parametrizer_lscm_solve(handle, nullptr, nullptr);
|
||||
geometry::uv_parametrizer_lscm_end(handle);
|
||||
geometry::uv_parametrizer_average(handle, true, false, false);
|
||||
geometry::uv_parametrizer_pack(handle, margin, true, true);
|
||||
geometry::uv_parametrizer_pack(handle, params);
|
||||
geometry::uv_parametrizer_flush(handle);
|
||||
delete (handle);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user