Sculpt-dev: dyntopo now detects uv island

boundaries, independently of
	    edge seams.
This commit is contained in:
Joseph Eagar 2021-11-17 16:42:56 -08:00
parent 7d870c75fb
commit e5394e962a
10 changed files with 165 additions and 39 deletions

View File

@ -719,6 +719,8 @@ typedef struct SculptSession {
int cd_faceset_offset;
int cd_face_areas;
int totuv;
bool bm_smooth_shading;
/* Undo/redo log for dynamic topology sculpting */
struct BMLog *bm_log;

View File

@ -121,6 +121,7 @@ struct BMesh;
struct BMVert;
struct BMEdge;
struct BMFace;
struct Scene;
struct CCGElem;
struct MeshElemMap;
struct CCGKey;
@ -429,10 +430,13 @@ void BKE_pbvh_draw_cb(PBVH *pbvh,
void (*draw_fn)(void *user_data, struct GPU_PBVH_Buffers *buffers),
void *user_data);
void BKE_pbvh_draw_debug_cb(
PBVH *pbvh,
void (*draw_fn)(void *user_data, const float bmin[3], const float bmax[3], PBVHNodeFlags flag, int depth),
void *user_data);
void BKE_pbvh_draw_debug_cb(PBVH *pbvh,
void (*draw_fn)(void *user_data,
const float bmin[3],
const float bmax[3],
PBVHNodeFlags flag,
int depth),
void *user_data);
/* PBVH Access */
typedef enum {
@ -854,7 +858,9 @@ void BKE_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_face_node_offset,
int cd_vcol,
struct BMVert *v,
int symmetry);
int bound_symmetry,
const CustomData *ldata,
const int totuv);
#define DYNTOPO_DYNAMIC_TESS

View File

@ -41,14 +41,16 @@
#define SCULPTVERT_SMOOTH_BOUNDARY \
(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_SHARP_BOUNDARY | \
SCULPTVERT_SEAM_BOUNDARY)
SCULPTVERT_SEAM_BOUNDARY | SCULPTVERT_UV_BOUNDARY)
#define SCULPTVERT_ALL_BOUNDARY \
(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_SHARP_BOUNDARY | \
SCULPTVERT_SEAM_BOUNDARY)
SCULPTVERT_SEAM_BOUNDARY | SCULPTVERT_UV_BOUNDARY)
#define SCULPTVERT_SMOOTH_CORNER \
(SCULPTVERT_CORNER | SCULPTVERT_FSET_CORNER | SCULPTVERT_SHARP_CORNER | SCULPTVERT_SEAM_CORNER)
(SCULPTVERT_CORNER | SCULPTVERT_FSET_CORNER | SCULPTVERT_SHARP_CORNER | \
SCULPTVERT_SEAM_CORNER | SCULPTVERT_UV_CORNER)
#define SCULPTVERT_ALL_CORNER \
(SCULPTVERT_CORNER | SCULPTVERT_FSET_CORNER | SCULPTVERT_SHARP_CORNER | SCULPTVERT_SEAM_CORNER)
(SCULPTVERT_CORNER | SCULPTVERT_FSET_CORNER | SCULPTVERT_SHARP_CORNER | \
SCULPTVERT_SEAM_CORNER | SCULPTVERT_UV_CORNER)
#define DYNTOPO_MAX_ITER 4096
@ -3637,7 +3639,7 @@ static BMVert *pbvh_bmesh_collapse_edge(PBVH *pbvh,
} while ((e2 = BM_DISK_EDGE_NEXT(e2, v)) != v->e);
}
float (*uv)[2] = BLI_array_alloca(uv, 4*totuv);
float(*uv)[2] = BLI_array_alloca(uv, 4 * totuv);
do {
const void *ls2[2] = {l->head.data, l->next->head.data};

View File

@ -3317,4 +3317,11 @@ void BKE_sculptsession_update_attr_refs(Object *ob)
ss->vcol = layer->data;
}
}
if (ss->bm) {
ss->totuv = CustomData_number_of_layers(&ss->bm->ldata, CD_MLOOPUV);
}
else {
ss->totuv = ss->ldata ? CustomData_number_of_layers(ss->ldata, CD_MLOOPUV) : 0;
}
}

View File

@ -1717,7 +1717,9 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
int bound_symmetry,
const CustomData *ldata,
const int totuv)
{
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);
@ -1727,7 +1729,8 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
mv->flag &= ~(SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_NEED_BOUNDARY |
SCULPTVERT_NEED_TRIANGULATE | SCULPTVERT_FSET_CORNER | SCULPTVERT_CORNER |
SCULPTVERT_NEED_VALENCE | SCULPTVERT_SEAM_BOUNDARY | SCULPTVERT_SHARP_BOUNDARY |
SCULPTVERT_SEAM_CORNER | SCULPTVERT_SHARP_CORNER | SCULPTVERT_PBVH_BOUNDARY);
SCULPTVERT_SEAM_CORNER | SCULPTVERT_SHARP_CORNER | SCULPTVERT_PBVH_BOUNDARY |
SCULPTVERT_UV_BOUNDARY | SCULPTVERT_UV_CORNER);
if (!e) {
mv->flag |= SCULPTVERT_BOUNDARY;
@ -1757,6 +1760,20 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int *fsets = NULL;
BLI_array_staticdeclare(fsets, 16);
float(*lastuv)[2] = BLI_array_alloca(lastuv, totuv);
float(*lastuv2)[2] = BLI_array_alloca(lastuv2, totuv);
int *disjount_uv_count = BLI_array_alloca(disjount_uv_count, totuv);
int *cd_uvs = BLI_array_alloca(cd_uvs, totuv);
int base_uv_idx = ldata->typemap[CD_MLOOPUV];
bool uv_first = true;
for (int i = 0; i < totuv; i++) {
CustomDataLayer *layer = ldata->layers + base_uv_idx + i;
cd_uvs[i] = layer->offset;
disjount_uv_count[i] = 0;
}
do {
BMVert *v2 = v == e->v1 ? e->v2 : e->v1;
@ -1812,6 +1829,49 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
}
if (e->l) {
/* deal with uv island boundaries */
if (totuv) {
BMLoop *l_iter = e->l;
do {
BMLoop *l = l_iter->v != v ? l_iter->next : l_iter;
for (int i = 0; i < totuv; i++) {
MLoopUV *luv = BM_ELEM_CD_GET_VOID_P(l, cd_uvs[i]);
if (uv_first) {
copy_v2_v2(lastuv[i], luv->uv);
copy_v2_v2(lastuv2[i], luv->uv);
continue;
}
const float uv_snap_limit = 0.01f * 0.01f;
float dist = len_squared_v2v2(luv->uv, lastuv[i]);
bool same = dist <= uv_snap_limit;
bool corner = len_squared_v2v2(lastuv[i], lastuv2[i]) > uv_snap_limit &&
len_squared_v2v2(lastuv[i], luv->uv) > uv_snap_limit &&
len_squared_v2v2(lastuv2[i], luv->uv) > uv_snap_limit;
if (!same) {
mv->flag |= SCULPTVERT_UV_BOUNDARY;
}
if (corner) {
mv->flag |= SCULPTVERT_UV_CORNER;
}
if (!same) {
copy_v2_v2(lastuv2[i], lastuv[i]);
copy_v2_v2(lastuv[i], luv->uv);
}
}
uv_first = false;
} while ((l_iter = l_iter->next) != e->l);
}
if (BM_ELEM_CD_GET_INT(e->l->f, cd_face_node_offset) != ni) {
mv->flag |= SCULPTVERT_PBVH_BOUNDARY;
}
@ -1942,7 +2002,9 @@ void BKE_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_face_node_offset,
int cd_vcol,
BMVert *v,
int bound_symmetry)
int bound_symmetry,
const CustomData *ldata,
const int totuv)
{
bke_pbvh_update_vert_boundary(cd_sculpt_vert,
cd_faceset_offset,
@ -1950,7 +2012,9 @@ void BKE_pbvh_update_vert_boundary(int cd_sculpt_vert,
cd_face_node_offset,
cd_vcol,
v,
bound_symmetry);
bound_symmetry,
ldata,
totuv);
}
/*Used by symmetrize to update boundary flags*/
@ -1966,7 +2030,9 @@ void BKE_pbvh_recalc_bmesh_boundary(PBVH *pbvh)
pbvh->cd_face_node_offset,
pbvh->cd_vcol_offset,
v,
pbvh->boundary_symmetry);
pbvh->boundary_symmetry,
&pbvh->bm->ldata,
pbvh->totuv);
}
}
@ -2198,6 +2264,8 @@ void BKE_pbvh_update_sculpt_verts(BMesh *bm,
BMVert *v;
BMIter iter;
int totuv = CustomData_number_of_layers(&bm->ldata, CD_MLOOPUV);
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
MSculptVert *mv = BKE_PBVH_SCULPTVERT(cd_sculpt_vert, v);
@ -2209,7 +2277,9 @@ void BKE_pbvh_update_sculpt_verts(BMesh *bm,
cd_face_node_offset,
-1,
v,
boundary_symmetry);
boundary_symmetry,
&bm->ldata,
totuv);
BKE_pbvh_bmesh_update_valence(cd_sculpt_vert, (SculptVertRef){(intptr_t)v});
@ -3938,6 +4008,8 @@ void BKE_pbvh_update_offsets(PBVH *pbvh,
pbvh->cd_vert_mask_offset = CustomData_get_offset(&pbvh->bm->vdata, CD_PAINT_MASK);
pbvh->cd_sculpt_vert = cd_sculpt_vert;
pbvh->cd_faceset_offset = CustomData_get_offset(&pbvh->bm->pdata, CD_SCULPT_FACE_SETS);
pbvh->totuv = CustomData_number_of_layers(&pbvh->bm->ldata, CD_MLOOPUV);
}
static void scan_edge_split(BMesh *bm, BMEdge **edges, int totedge)

View File

@ -27,6 +27,7 @@
* \ingroup bke
*/
struct MSculptVert;
struct CustomData;
/* Axis-aligned bounding box */
typedef struct {
@ -207,6 +208,8 @@ struct PBVH {
int cd_face_area;
int cd_vcol_offset;
int totuv;
int vcol_type;
int vcol_domain;
@ -356,7 +359,9 @@ void bke_pbvh_update_vert_boundary(int cd_sculpt_vert,
int cd_face_node_offset,
int cd_vcol_offset,
BMVert *v,
int bound_symmetry);
int bound_symmetry,
const struct CustomData *ldata,
const int totuv);
BLI_INLINE bool pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v)
{
@ -369,7 +374,9 @@ BLI_INLINE bool pbvh_check_vert_boundary(PBVH *pbvh, struct BMVert *v)
pbvh->cd_face_node_offset,
pbvh->cd_vcol_offset,
v,
pbvh->boundary_symmetry);
pbvh->boundary_symmetry,
&pbvh->bm->ldata,
pbvh->totuv);
return true;
}

View File

@ -2121,9 +2121,7 @@ static bool neighbor_cache_begin(const SculptSession *ss)
ncache->totvert = totvert;
atomic_cas_ptr((void **)&ss->cache->ncache, NULL, ncache);
if (ss->cache->ncache != ncache) {
if (atomic_cas_ptr((void **)&ss->cache->ncache, NULL, ncache) != NULL) {
// another thread got here first?
neighbor_cache_free(ncache);
@ -2143,7 +2141,13 @@ static NeighborCacheItem *neighbor_cache_get(const SculptSession *ss,
NeighborCache *ncache = ss->cache->ncache;
if (include_duplicates && !ncache->duplicates) {
ncache->duplicates = MEM_calloc_arrayN(ncache->totvert, sizeof(void *), "ncache->duplicages");
NeighborCacheItem **duplicates = MEM_calloc_arrayN(
ncache->totvert, sizeof(void *), "ncache->duplicages");
if (atomic_cas_ptr(&ncache->duplicates, NULL, duplicates) != NULL) {
/* some other thread got here first */
MEM_freeN(duplicates);
}
}
NeighborCacheItem **cache = include_duplicates ? ncache->duplicates : ncache->cache;
@ -2264,7 +2268,8 @@ SculptBoundaryType SCULPT_edge_is_boundary(const SculptSession *ss,
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, e->v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, e->v2);
return (mv1->flag & SCULPTVERT_FSET_BOUNDARY) && (mv2->flag & SCULPTVERT_FSET_BOUNDARY);
bool ok = (mv1->flag & SCULPTVERT_FSET_BOUNDARY) && (mv2->flag & SCULPTVERT_FSET_BOUNDARY);
ret |= ok ? SCULPT_BOUNDARY_FACE_SET : 0;
}
else {
int fset1 = BM_ELEM_CD_GET_INT(e->l->f, ss->cd_faceset_offset);
@ -2278,6 +2283,14 @@ SculptBoundaryType SCULPT_edge_is_boundary(const SculptSession *ss,
}
}
if (typemask & SCULPT_BOUNDARY_UV) {
MSculptVert *mv1 = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, e->v1);
MSculptVert *mv2 = BKE_PBVH_SCULPTVERT(ss->cd_sculpt_vert, e->v2);
bool ok = (mv1->flag & SCULPTVERT_UV_BOUNDARY) && (mv2->flag & SCULPTVERT_UV_BOUNDARY);
ret |= ok ? SCULPT_BOUNDARY_UV : 0;
}
if (typemask & SCULPT_BOUNDARY_SHARP) {
ret |= !BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? SCULPT_BOUNDARY_SHARP : 0;
}
@ -2462,7 +2475,9 @@ SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
ss->cd_face_node_offset,
-1,
(BMVert *)vertex.i,
ss->boundary_symmetry);
ss->boundary_symmetry,
&ss->bm->ldata,
ss->totuv);
}
break;
@ -2498,6 +2513,9 @@ SculptCornerType SCULPT_vertex_is_corner(const SculptSession *ss,
if (cornertype & SCULPT_CORNER_SHARP) {
ret |= (mv->flag & SCULPTVERT_SHARP_CORNER) ? SCULPT_CORNER_SHARP : 0;
}
if (cornertype & SCULPT_CORNER_UV) {
ret |= (mv->flag & SCULPTVERT_UV_CORNER) ? SCULPT_CORNER_UV : 0;
}
return ret;
}
@ -2519,7 +2537,9 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
ss->cd_face_node_offset,
-1,
(BMVert *)vertex.i,
ss->boundary_symmetry);
ss->boundary_symmetry,
&ss->bm->ldata,
ss->totuv);
}
break;
@ -2574,6 +2594,9 @@ SculptBoundaryType SCULPT_vertex_is_boundary(const SculptSession *ss,
if (boundary_types & SCULPT_BOUNDARY_SEAM) {
flag |= (mv->flag & SCULPTVERT_SEAM_BOUNDARY) ? SCULPT_BOUNDARY_SEAM : 0;
}
if (boundary_types & SCULPT_BOUNDARY_UV) {
flag |= (mv->flag & SCULPTVERT_UV_BOUNDARY) ? SCULPT_BOUNDARY_UV : 0;
}
return flag;
return 0;

View File

@ -256,7 +256,8 @@ typedef enum SculptCornerType {
SCULPT_CORNER_MESH = 1 << 0,
SCULPT_CORNER_FACE_SET = 1 << 1,
SCULPT_CORNER_SEAM = 1 << 2,
SCULPT_CORNER_SHARP = 1 << 3
SCULPT_CORNER_SHARP = 1 << 3,
SCULPT_CORNER_UV = 1 << 4,
} SculptCornerType;
int SCULPT_get_tool(const SculptSession *ss, const struct Brush *br);
@ -303,8 +304,9 @@ typedef enum SculptBoundaryType {
SCULPT_BOUNDARY_FACE_SET = 1 << 1,
SCULPT_BOUNDARY_SEAM = 1 << 2,
SCULPT_BOUNDARY_SHARP = 1 << 3,
SCULPT_BOUNDARY_ALL = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3),
SCULPT_BOUNDARY_DEFAULT = (1 << 0) | (1 << 3) // mesh and sharp
SCULPT_BOUNDARY_UV = 1 << 4,
SCULPT_BOUNDARY_ALL = (1 << 0) | (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4),
SCULPT_BOUNDARY_DEFAULT = (1 << 0) | (1 << 3) | (1 << 4) // mesh and sharp
} SculptBoundaryType;
/* Boundary Info needs to be initialized in order to use this function. */

View File

@ -368,7 +368,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
slide_fset = MAX2(slide_fset, bound_smooth);
if (check_fsets) {
bflag |= SCULPT_BOUNDARY_FACE_SET | SCULPT_BOUNDARY_SEAM;
bflag |= SCULPT_BOUNDARY_FACE_SET | SCULPT_BOUNDARY_SEAM | SCULPT_BOUNDARY_UV;
}
const SculptBoundaryType is_boundary = SCULPT_vertex_is_boundary(ss, vertex, bflag);
@ -396,7 +396,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
SculptCornerType ctype = SCULPT_CORNER_MESH | SCULPT_CORNER_SHARP;
if (check_fsets) {
ctype |= SCULPT_CORNER_FACE_SET | SCULPT_CORNER_SEAM;
ctype |= SCULPT_CORNER_FACE_SET | SCULPT_CORNER_SEAM | SCULPT_CORNER_UV;
}
// bool have_bmesh = ss->bm;
@ -512,7 +512,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
*/
bool slide = (slide_fset > 0.0f &&
(is_boundary & (SCULPT_BOUNDARY_FACE_SET | SCULPT_BOUNDARY_SEAM))) ||
(is_boundary & (SCULPT_BOUNDARY_FACE_SET | SCULPT_BOUNDARY_SEAM | SCULPT_BOUNDARY_UV))) ||
bound_smooth > 0.0f;
slide = slide && !final_boundary;
@ -719,7 +719,7 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
return;
}
if (c & (SCULPT_CORNER_FACE_SET | SCULPT_CORNER_SEAM)) {
if (c & (SCULPT_CORNER_FACE_SET | SCULPT_CORNER_SEAM | SCULPT_CORNER_UV)) {
corner_smooth = MAX2(slide_fset, bound_smooth);
}
else {
@ -890,7 +890,7 @@ void SCULPT_bmesh_four_neighbor_average(SculptSession *ss,
// (SCULPTVERT_BOUNDARY | SCULPTVERT_FSET_BOUNDARY | SCULPTVERT_SHARP_BOUNDARY));
SculptBoundaryType bflag = SCULPT_BOUNDARY_FACE_SET | SCULPT_BOUNDARY_MESH |
SCULPT_BOUNDARY_SHARP | SCULPT_BOUNDARY_SEAM;
SCULPT_BOUNDARY_SHARP | SCULPT_BOUNDARY_SEAM | SCULPT_BOUNDARY_UV;
int bound = SCULPT_edge_is_boundary(ss, (SculptEdgeRef){.i = (intptr_t)e}, bflag);
float dirw = 1.0f;

View File

@ -526,7 +526,14 @@ typedef struct MRecast {
/** \} */
typedef struct MSculptVert {
unsigned short flag, valence;
unsigned short valence;
/* id of current stroke, used to detect
if vertex original data needs to be updated.
*/
short stroke_id;
int flag;
/**original coordinates*/
float origco[3], origno[3];
@ -542,10 +549,6 @@ typedef struct MSculptVert {
/* curvature_dir parallels a principle curvature direction */
float curvature_dir[3];
/* id of current stroke, used to detect
if vertex original data needs to be updated*/
int stroke_id;
} MSculptVert;
/* MSculptVert->flag */
@ -564,7 +567,9 @@ enum {
SCULPTVERT_SEAM_CORNER = (1 << 11),
SCULPTVERT_SHARP_CORNER = (1 << 12),
SCULPTVERT_SPLIT_TEMP = (1 << 13),
SCULPTVERT_PBVH_BOUNDARY = (1 << 14)
SCULPTVERT_PBVH_BOUNDARY = (1 << 14),
SCULPTVERT_UV_BOUNDARY = (1<<15),
SCULPTVERT_UV_CORNER = (1<<16)
};
/* for internal bmesh toolflags api */