Fix T98239: During UV Unwrap, create unique indices for each pinned UV
Originally reported in T75007. Differential Revision: https://developer.blender.org/D15199
This commit is contained in:
parent
2804497312
commit
e6e9f1ac5a
Notes:
blender-bot
2023-02-14 05:28:01 +01:00
Referenced by commit 7a44f62bdb
, Fix T99156: UV parameterizer respects both Pins and Seams
Referenced by issue #99502, OBJ/MTL import: behavior changed for missing texture files
Referenced by issue #99156, Regression: UV Pins interfere with UV seams (regression)
Referenced by issue #99036, Add Color Attribute: hex colors don't work
Referenced by issue #98239, Unwrap and Live Unwrap can merge pinned UVs
Referenced by issue #75007, Live unwrap interaction changes unwrapping and ignores pinned vertices
|
@ -298,6 +298,44 @@ void ED_uvedit_get_aspect(Object *ob, float *r_aspx, float *r_aspy)
|
|||
ED_uvedit_get_aspect_from_material(ob, efa->mat_nr, r_aspx, r_aspy);
|
||||
}
|
||||
|
||||
static bool uvedit_is_face_affected(const Scene *scene,
|
||||
BMFace *efa,
|
||||
const UnwrapOptions *options,
|
||||
const int cd_loop_uv_offset)
|
||||
{
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options->only_selected_faces && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (options->topology_from_uvs && options->only_selected_uvs &&
|
||||
!uvedit_face_select_test(scene, efa, cd_loop_uv_offset)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Prepare unique indices for each unique pinned UV, even if it shares a BMVert.
|
||||
*/
|
||||
static void uvedit_prepare_pinned_indices(ParamHandle *handle,
|
||||
BMFace *efa,
|
||||
const int cd_loop_uv_offset)
|
||||
{
|
||||
BMIter liter;
|
||||
BMLoop *l;
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
if (luv->flag & MLOOPUV_PINNED) {
|
||||
int bmvertindex = BM_elem_index_get(l->v);
|
||||
GEO_uv_prepare_pin_index(handle, bmvertindex, luv->uv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void construct_param_handle_face_add(ParamHandle *handle,
|
||||
const Scene *scene,
|
||||
BMFace *efa,
|
||||
|
@ -319,7 +357,7 @@ static void construct_param_handle_face_add(ParamHandle *handle,
|
|||
BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
|
||||
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
|
||||
|
||||
vkeys[i] = (ParamKey)BM_elem_index_get(l->v);
|
||||
vkeys[i] = GEO_uv_find_pin_index(handle, BM_elem_index_get(l->v), luv->uv);
|
||||
co[i] = l->v->co;
|
||||
uv[i] = luv->uv;
|
||||
pin[i] = (luv->flag & MLOOPUV_PINNED) != 0;
|
||||
|
@ -337,13 +375,10 @@ static ParamHandle *construct_param_handle(const Scene *scene,
|
|||
UnwrapResultInfo *result_info)
|
||||
{
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
BMEdge *eed;
|
||||
BMIter iter, liter;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
|
||||
if (options->correct_aspect) {
|
||||
|
@ -359,30 +394,17 @@ static ParamHandle *construct_param_handle(const Scene *scene,
|
|||
/* we need the vert indices */
|
||||
BM_mesh_elem_index_ensure(bm, BM_VERT);
|
||||
|
||||
const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
|
||||
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
|
||||
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
|
||||
(options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
|
||||
continue;
|
||||
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
|
||||
uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (options->topology_from_uvs) {
|
||||
bool is_loopsel = false;
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (options->only_selected_uvs &&
|
||||
(uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
|
||||
continue;
|
||||
}
|
||||
is_loopsel = true;
|
||||
break;
|
||||
}
|
||||
if (is_loopsel == false) {
|
||||
continue;
|
||||
}
|
||||
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
|
||||
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
|
||||
construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
|
||||
}
|
||||
|
||||
construct_param_handle_face_add(handle, scene, efa, i, cd_loop_uv_offset);
|
||||
}
|
||||
|
||||
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
|
||||
|
@ -414,9 +436,8 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
|
|||
int *count_fail)
|
||||
{
|
||||
BMFace *efa;
|
||||
BMLoop *l;
|
||||
BMEdge *eed;
|
||||
BMIter iter, liter;
|
||||
BMIter iter;
|
||||
int i;
|
||||
|
||||
ParamHandle *handle = GEO_uv_parametrizer_construct_begin();
|
||||
|
@ -448,29 +469,15 @@ static ParamHandle *construct_param_handle_multi(const Scene *scene,
|
|||
}
|
||||
|
||||
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
|
||||
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN) ||
|
||||
(options->only_selected_faces && BM_elem_flag_test(efa, BM_ELEM_SELECT) == 0)) {
|
||||
continue;
|
||||
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
|
||||
uvedit_prepare_pinned_indices(handle, efa, cd_loop_uv_offset);
|
||||
}
|
||||
}
|
||||
|
||||
if (options->topology_from_uvs) {
|
||||
bool is_loopsel = false;
|
||||
|
||||
BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
|
||||
if (options->only_selected_uvs &&
|
||||
(uvedit_uv_select_test(scene, l, cd_loop_uv_offset) == false)) {
|
||||
continue;
|
||||
}
|
||||
is_loopsel = true;
|
||||
break;
|
||||
}
|
||||
if (is_loopsel == false) {
|
||||
continue;
|
||||
}
|
||||
BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) {
|
||||
if (uvedit_is_face_affected(scene, efa, options, cd_loop_uv_offset)) {
|
||||
construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
|
||||
}
|
||||
|
||||
construct_param_handle_face_add(handle, scene, efa, i + offset, cd_loop_uv_offset);
|
||||
}
|
||||
|
||||
if (!options->topology_from_uvs || options->topology_from_uvs_use_seams) {
|
||||
|
|
|
@ -14,6 +14,7 @@ extern "C" {
|
|||
|
||||
typedef struct ParamHandle ParamHandle; /* Handle to an array of charts. */
|
||||
typedef intptr_t ParamKey; /* Key (hash) for identifying verts and faces. */
|
||||
#define PARAM_KEY_MAX INTPTR_MAX
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Chart Construction:
|
||||
|
@ -34,6 +35,10 @@ ParamHandle *GEO_uv_parametrizer_construct_begin(void);
|
|||
|
||||
void GEO_uv_parametrizer_aspect_ratio(ParamHandle *handle, float aspx, float aspy);
|
||||
|
||||
void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2]);
|
||||
|
||||
void GEO_uv_parametrizer_face_add(ParamHandle *handle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "BLI_boxpack_2d.h"
|
||||
#include "BLI_convexhull_2d.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_heap.h"
|
||||
#include "BLI_math.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
@ -190,6 +191,9 @@ typedef struct ParamHandle {
|
|||
PHash *hash_edges;
|
||||
PHash *hash_faces;
|
||||
|
||||
struct GHash *pin_hash;
|
||||
int unique_pin_count;
|
||||
|
||||
PChart **charts;
|
||||
int ncharts;
|
||||
|
||||
|
@ -3817,8 +3821,11 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
|
|||
p_chart_delete(phandle->charts[i]);
|
||||
}
|
||||
|
||||
if (phandle->charts) {
|
||||
MEM_freeN(phandle->charts);
|
||||
MEM_SAFE_FREE(phandle->charts);
|
||||
|
||||
if (phandle->pin_hash) {
|
||||
BLI_ghash_free(phandle->pin_hash, NULL, NULL);
|
||||
phandle->pin_hash = NULL;
|
||||
}
|
||||
|
||||
if (phandle->construction_chart) {
|
||||
|
@ -3835,6 +3842,79 @@ void GEO_uv_parametrizer_delete(ParamHandle *phandle)
|
|||
MEM_freeN(phandle);
|
||||
}
|
||||
|
||||
typedef struct GeoUVPinIndex {
|
||||
struct GeoUVPinIndex *next;
|
||||
float uv[2];
|
||||
ParamKey reindex;
|
||||
} GeoUVPinIndex;
|
||||
|
||||
/* Find a (mostly) unique ParamKey given a BMVert index and UV co-ordinates.
|
||||
* For each unique pinned UVs, return a unique ParamKey, starting with
|
||||
* a very large number, and decreasing steadily from there.
|
||||
* For non-pinned UVs which share a BMVert with a pinned UV,
|
||||
* return the index corresponding to the closest pinned UV.
|
||||
* For everything else, just return the BMVert index.
|
||||
* Note that ParamKeys will eventually be hashed, so they don't need to be contiguous.
|
||||
*/
|
||||
ParamKey GEO_uv_find_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
{
|
||||
if (!handle->pin_hash) {
|
||||
return bmvertindex; /* No verts pinned. */
|
||||
}
|
||||
|
||||
GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, bmvertindex);
|
||||
if (!pinuvlist) {
|
||||
return bmvertindex; /* Vert not pinned. */
|
||||
}
|
||||
|
||||
/* At least one of the UVs associated with bmvertindex is pinned. Find the best one. */
|
||||
float bestdistsquared = len_squared_v2v2(pinuvlist->uv, uv);
|
||||
ParamKey bestkey = pinuvlist->reindex;
|
||||
pinuvlist = pinuvlist->next;
|
||||
while (pinuvlist) {
|
||||
const float distsquared = len_squared_v2v2(pinuvlist->uv, uv);
|
||||
if (bestdistsquared > distsquared) {
|
||||
bestdistsquared = distsquared;
|
||||
bestkey = pinuvlist->reindex;
|
||||
}
|
||||
pinuvlist = pinuvlist->next;
|
||||
}
|
||||
return bestkey;
|
||||
}
|
||||
|
||||
static GeoUVPinIndex *new_geo_uv_pinindex(ParamHandle *handle, const float uv[2])
|
||||
{
|
||||
GeoUVPinIndex *pinuv = BLI_memarena_alloc(handle->arena, sizeof(*pinuv));
|
||||
pinuv->next = NULL;
|
||||
copy_v2_v2(pinuv->uv, uv);
|
||||
pinuv->reindex = PARAM_KEY_MAX - (handle->unique_pin_count++);
|
||||
return pinuv;
|
||||
}
|
||||
|
||||
void GEO_uv_prepare_pin_index(ParamHandle *handle, const int bmvertindex, const float uv[2])
|
||||
{
|
||||
if (!handle->pin_hash) {
|
||||
handle->pin_hash = BLI_ghash_int_new("uv pin reindex");
|
||||
}
|
||||
|
||||
GeoUVPinIndex *pinuvlist = BLI_ghash_lookup(handle->pin_hash, bmvertindex);
|
||||
if (!pinuvlist) {
|
||||
BLI_ghash_insert(handle->pin_hash, bmvertindex, new_geo_uv_pinindex(handle, uv));
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (equals_v2v2(pinuvlist->uv, uv)) {
|
||||
return;
|
||||
}
|
||||
if (!pinuvlist->next) {
|
||||
pinuvlist->next = new_geo_uv_pinindex(handle, uv);
|
||||
return;
|
||||
}
|
||||
pinuvlist = pinuvlist->next;
|
||||
}
|
||||
}
|
||||
|
||||
static void p_add_ngon(ParamHandle *handle,
|
||||
const ParamKey key,
|
||||
const int nverts,
|
||||
|
|
Loading…
Reference in New Issue