Cleanup: simplify uv packing api

Part of a wider set of changes to migrate UV packing from
uv_parametrizer.cc to uvedit_islands.cc.

This allows UV packing improvements including margin calculation,
correctness fixes such as support for non-manifold geometry,
and new packing algorithms including speed and quality improvements.

See for example c2256bf7f7, T82637

This change migrates UV.unwrap and Live UV Unwrap.

Differential Revision: https://developer.blender.org/D16296
This commit is contained in:
Chris Blackbourn 2022-10-20 12:35:17 +13:00
parent 21a1c332b0
commit e3075f3cf7
Notes: blender-bot 2023-02-14 07:40:56 +01:00
Referenced by commit 6672b5373f, Fix T103971: uv packing wasn't ignoring uv islands on hidden faces
Referenced by commit 143e74c0b8, Fix (unreported) uv unwrap selected was splitting selection
Referenced by commit 0ce18561bc, Fix (unreported) uv unwrap selected was splitting selection
Referenced by issue #103971, Regression: Live unwrapping wraps hidden faces
3 changed files with 62 additions and 41 deletions

View File

@ -345,12 +345,14 @@ typedef enum {
ED_UVPACK_MARGIN_FRACTION, /* Specify a precise fraction of final UV output. */
} eUVPackIsland_MarginMethod;
/** See also #UnwrapOptions. */
struct UVPackIsland_Params {
uint rotate : 1;
uint only_selected_uvs : 1;
uint only_selected_faces : 1;
uint use_seams : 1;
uint correct_aspect : 1;
bool ignore_pinned; /* Ignore islands which have any pinned UVs. */
eUVPackIsland_MarginMethod margin_method; /* Which formula to use when scaling island margin. */
float margin; /* Additional space to add around each island. */
};

View File

@ -600,6 +600,22 @@ static BoxPack *pack_islands_params(const blender::Vector<FaceIsland *> &island_
return box_array;
}
static bool island_has_pins(FaceIsland *island)
{
BMLoop *l;
BMIter iter;
const int cd_loop_uv_offset = island->cd_loop_uv_offset;
for (int i = 0; i < island->faces_len; i++) {
BM_ITER_ELEM (l, &iter, island->faces[i], BM_LOOPS_OF_FACE) {
MLoopUV *luv = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset));
if (luv->flag & MLOOPUV_PINNED) {
return true;
}
}
}
return false;
}
/* -------------------------------------------------------------------- */
/** \name Public UV Island Packing
*
@ -651,8 +667,14 @@ void ED_uvedit_pack_islands_multi(const Scene *scene,
aspect_y,
cd_loop_uv_offset);
int index;
LISTBASE_FOREACH_INDEX (struct FaceIsland *, island, &island_list, index) {
/* Remove from linked list and append to blender::Vector. */
LISTBASE_FOREACH_MUTABLE (struct FaceIsland *, island, &island_list) {
BLI_remlink(&island_list, island);
if (params->ignore_pinned && island_has_pins(island)) {
MEM_freeN(island->faces);
MEM_freeN(island);
continue;
}
island_vector.append(island);
}
}

View File

@ -1050,31 +1050,6 @@ void UV_OT_minimize_stretch(wmOperatorType *ot)
/** \name Pack UV Islands Operator
* \{ */
/**
* \warning Since this uses #ParamHandle it doesn't work with non-manifold meshes (see T82637).
* Use #ED_uvedit_pack_islands_multi for a more general solution.
*
* TODO: remove this function, in favor of #ED_uvedit_pack_islands_multi.
*/
static void uvedit_pack_islands_multi(const Scene *scene,
Object **objects,
const uint objects_len,
const UnwrapOptions *options,
bool rotate,
bool ignore_pinned)
{
ParamHandle *handle = construct_param_handle_multi(scene, objects, objects_len, options);
GEO_uv_parametrizer_pack(handle, scene->toolsettings->uvcalc_margin, rotate, ignore_pinned);
GEO_uv_parametrizer_flush(handle);
GEO_uv_parametrizer_delete(handle);
for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
Object *obedit = objects[ob_index];
DEG_id_tag_update(obedit->data, ID_RECALC_GEOMETRY);
WM_main_add_notifier(NC_GEOM | ND_DATA, obedit->data);
}
}
/* Packing targets. */
enum {
PACK_UDIM_SRC_CLOSEST = 0,
@ -1119,16 +1094,22 @@ static int pack_islands_exec(bContext *C, wmOperator *op)
const bool use_udim_params = ED_uvedit_udim_params_from_image_space(
sima, use_active, &udim_params);
struct UVPackIsland_Params params = {
const struct UVPackIsland_Params pack_island_params = {
.rotate = RNA_boolean_get(op->ptr, "rotate"),
.only_selected_uvs = true,
.only_selected_faces = true,
.correct_aspect = true,
.only_selected_uvs = options.only_selected_uvs,
.only_selected_faces = options.only_selected_faces,
.use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
.correct_aspect = options.correct_aspect,
.ignore_pinned = false,
.margin_method = RNA_enum_get(op->ptr, "margin_method"),
.margin = RNA_float_get(op->ptr, "margin"),
};
ED_uvedit_pack_islands_multi(
scene, objects, objects_len, NULL, use_udim_params ? &udim_params : NULL, &params);
ED_uvedit_pack_islands_multi(scene,
objects,
objects_len,
NULL,
use_udim_params ? &udim_params : NULL,
&pack_island_params);
MEM_freeN(objects);
return OPERATOR_FINISHED;
@ -1889,12 +1870,19 @@ void ED_uvedit_live_unwrap(const Scene *scene, Object **objects, int objects_len
.fill_holes = (scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES) != 0,
.correct_aspect = (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT) == 0,
};
bool rotate = true;
bool ignore_pinned = true;
uvedit_unwrap_multi(scene, objects, objects_len, &options, NULL);
uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
const struct UVPackIsland_Params pack_island_params = {
.rotate = true,
.only_selected_uvs = options.only_selected_uvs,
.only_selected_faces = options.only_selected_faces,
.use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
.correct_aspect = options.correct_aspect,
.ignore_pinned = true,
.margin_method = ED_UVPACK_MARGIN_SCALED,
.margin = scene->toolsettings->uvcalc_margin,
};
ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params);
}
}
@ -1926,8 +1914,6 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.correct_aspect = RNA_boolean_get(op->ptr, "correct_aspect"),
};
bool rotate = true;
bool ignore_pinned = true;
if (CTX_wm_space_image(C)) {
/* Inside the UV Editor, only unwrap selected UVs. */
options.only_selected_uvs = true;
@ -2032,7 +2018,18 @@ static int unwrap_exec(bContext *C, wmOperator *op)
.count_failed = 0,
};
uvedit_unwrap_multi(scene, objects, objects_len, &options, &result_info);
uvedit_pack_islands_multi(scene, objects, objects_len, &options, rotate, ignore_pinned);
const struct UVPackIsland_Params pack_island_params = {
.rotate = true,
.only_selected_uvs = options.only_selected_uvs,
.only_selected_faces = options.only_selected_faces,
.use_seams = !options.topology_from_uvs || options.topology_from_uvs_use_seams,
.correct_aspect = options.correct_aspect,
.ignore_pinned = true,
.margin_method = RNA_enum_get(op->ptr, "margin_method"),
.margin = RNA_float_get(op->ptr, "margin"),
};
ED_uvedit_pack_islands_multi(scene, objects, objects_len, NULL, NULL, &pack_island_params);
MEM_freeN(objects);