Sculpt dyntopo: Add edge API

* Added a minimal edge API to query edge
  boundary states.
* This is necassary because the previous approximation,
  testing if two adjacent verts are boundaries, breaks
  for triangles.
This commit is contained in:
Joseph Eagar 2021-08-28 12:14:59 -07:00
parent b21595cdf9
commit 39b0e9df81
4 changed files with 215 additions and 21 deletions

View File

@ -37,6 +37,10 @@ typedef struct SculptVertRef {
intptr_t i;
} SculptVertRef;
typedef struct SculptEdgeRef {
intptr_t i;
} SculptEdgeRef;
typedef struct SculptFaceRef {
intptr_t i;
} SculptFaceRef;
@ -53,12 +57,20 @@ BLI_INLINE SculptVertRef BKE_pbvh_make_vref(intptr_t i)
return ret;
}
BLI_INLINE SculptEdgeRef BKE_pbvh_make_eref(intptr_t i)
{
SculptEdgeRef ret = {i};
return ret;
}
BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
{
SculptFaceRef ret = {i};
return ret;
}
#define SCULPT_REF_NONE ((intptr_t)-1)
typedef struct PBVHTri {
int v[3]; // references into PBVHTriBuf->verts
intptr_t l[3]; // loops

View File

@ -1322,10 +1322,11 @@ int SCULPT_face_set_next_available_get(SculptSession *ss)
static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
SculptVertRef neighbor,
SculptEdgeRef edge,
int neighbor_index)
{
for (int i = 0; i < iter->size; i++) {
if (iter->neighbors[i].i == neighbor.i) {
if (iter->neighbors[i].vertex.i == neighbor.i) {
return;
}
}
@ -1334,48 +1335,55 @@ static void sculpt_vertex_neighbor_add(SculptVertexNeighborIter *iter,
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
iter->neighbors = MEM_mallocN(iter->capacity * sizeof(SculptVertRef), "neighbor array");
iter->neighbors = MEM_mallocN(iter->capacity * sizeof(struct _SculptNeighborRef),
"neighbor array");
iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(SculptVertRef) * iter->size);
memcpy(
iter->neighbors, iter->neighbors_fixed, sizeof(struct _SculptNeighborRef) * iter->size);
memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size);
}
else {
iter->neighbors = MEM_reallocN_id(
iter->neighbors, iter->capacity * sizeof(SculptVertRef), "neighbor array");
iter->neighbors, iter->capacity * sizeof(struct _SculptNeighborRef), "neighbor array");
iter->neighbor_indices = MEM_reallocN_id(
iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array");
}
}
iter->neighbors[iter->size] = neighbor;
iter->neighbors[iter->size].vertex = neighbor;
iter->neighbors[iter->size].edge = edge;
iter->neighbor_indices[iter->size] = neighbor_index;
iter->size++;
}
static void sculpt_vertex_neighbor_add_nocheck(SculptVertexNeighborIter *iter,
SculptVertRef neighbor,
SculptEdgeRef edge,
int neighbor_index)
{
if (iter->size >= iter->capacity) {
iter->capacity += SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY;
if (iter->neighbors == iter->neighbors_fixed) {
iter->neighbors = MEM_mallocN(iter->capacity * sizeof(SculptVertRef), "neighbor array");
iter->neighbors = MEM_mallocN(iter->capacity * sizeof(struct _SculptNeighborRef),
"neighbor array");
iter->neighbor_indices = MEM_mallocN(iter->capacity * sizeof(int), "neighbor array");
memcpy(iter->neighbors, iter->neighbors_fixed, sizeof(SculptVertRef) * iter->size);
memcpy(
iter->neighbors, iter->neighbors_fixed, sizeof(struct _SculptNeighborRef) * iter->size);
memcpy(iter->neighbor_indices, iter->neighbor_indices_fixed, sizeof(int) * iter->size);
}
else {
iter->neighbors = MEM_reallocN_id(
iter->neighbors, iter->capacity * sizeof(SculptVertRef), "neighbor array");
iter->neighbors, iter->capacity * sizeof(struct _SculptNeighborRef), "neighbor array");
iter->neighbor_indices = MEM_reallocN_id(
iter->neighbor_indices, iter->capacity * sizeof(int), "neighbor array");
}
}
iter->neighbors[iter->size] = neighbor;
iter->neighbors[iter->size].vertex = neighbor;
iter->neighbors[iter->size].edge = edge;
iter->neighbor_indices[iter->size] = neighbor_index;
iter->size++;
}
@ -1416,12 +1424,27 @@ static void sculpt_vertex_neighbors_get_bmesh(const SculptSession *ss,
MDynTopoVert *mv = BKE_PBVH_DYNVERT(ss->cd_dyn_vert, v2);
e = e2;
if (!(mv->flag & DYNVERT_VERT_FSET_HIDDEN)) {
sculpt_vertex_neighbor_add_nocheck(
iter, BKE_pbvh_make_vref((intptr_t)v2), BM_elem_index_get(v2));
sculpt_vertex_neighbor_add_nocheck(iter,
BKE_pbvh_make_vref((intptr_t)v2),
BKE_pbvh_make_eref((intptr_t)e),
BM_elem_index_get(v2));
}
e = e2;
} while (e != v->e);
if (ss->fake_neighbors.use_fake_neighbors) {
int index = BM_elem_index_get(v);
BLI_assert(ss->fake_neighbors.fake_neighbor_index != NULL);
if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
sculpt_vertex_neighbor_add(iter,
ss->fake_neighbors.fake_neighbor_index[index],
BKE_pbvh_make_eref(SCULPT_REF_NONE),
ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
}
static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
@ -1447,8 +1470,21 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
uint f_adj_v[2];
if (poly_get_adj_loops_from_vert(p, ss->mloop, index, f_adj_v) != -1) {
for (int j = 0; j < ARRAY_SIZE(f_adj_v); j += 1) {
int e = 0;
if (f_adj_v[j] != index) {
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(f_adj_v[j]), f_adj_v[j]);
int loopidx = p->loopstart;
for (int k = 0; k < p->totloop; k++, loopidx++) {
const MEdge *e2 = &ss->medge[ss->mloop[loopidx].e];
if ((e2->v1 == index && e2->v2 == f_adj_v[j]) ||
(e2->v2 == index && e2->v1 == f_adj_v[j])) {
e = e2 - ss->medge;
}
}
sculpt_vertex_neighbor_add(
iter, BKE_pbvh_make_vref(f_adj_v[j]), BKE_pbvh_make_eref(e), f_adj_v[j]);
}
}
}
@ -1459,6 +1495,7 @@ static void sculpt_vertex_neighbors_get_faces(const SculptSession *ss,
if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
sculpt_vertex_neighbor_add(iter,
ss->fake_neighbors.fake_neighbor_index[index],
BKE_pbvh_make_eref(SCULPT_REF_NONE),
ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
@ -1488,7 +1525,8 @@ static void sculpt_vertex_neighbors_get_faces_vemap(const SculptSession *ss,
continue;
}
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(v), v);
sculpt_vertex_neighbor_add(
iter, BKE_pbvh_make_vref(v), BKE_pbvh_make_eref(vert_map->indices[i]), v);
}
if (ss->fake_neighbors.use_fake_neighbors) {
@ -1496,6 +1534,7 @@ static void sculpt_vertex_neighbors_get_faces_vemap(const SculptSession *ss,
if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
sculpt_vertex_neighbor_add(iter,
ss->fake_neighbors.fake_neighbor_index[index],
BKE_pbvh_make_eref(SCULPT_REF_NONE),
ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
@ -1534,7 +1573,8 @@ static void sculpt_vertex_neighbors_get_grids(const SculptSession *ss,
int idx = neighbors.coords[i].grid_index * key->grid_area +
neighbors.coords[i].y * key->grid_size + neighbors.coords[i].x;
sculpt_vertex_neighbor_add(iter, BKE_pbvh_make_vref(idx), idx);
sculpt_vertex_neighbor_add(
iter, BKE_pbvh_make_vref(idx), BKE_pbvh_make_eref(SCULPT_REF_NONE), idx);
}
if (ss->fake_neighbors.use_fake_neighbors) {
@ -1542,6 +1582,7 @@ static void sculpt_vertex_neighbors_get_grids(const SculptSession *ss,
if (ss->fake_neighbors.fake_neighbor_index[index].i != FAKE_NEIGHBOR_NONE) {
sculpt_vertex_neighbor_add(iter,
ss->fake_neighbors.fake_neighbor_index[index],
BKE_pbvh_make_eref(SCULPT_REF_NONE),
ss->fake_neighbors.fake_neighbor_index[index].i);
}
}
@ -1575,6 +1616,110 @@ void SCULPT_vertex_neighbors_get(const SculptSession *ss,
}
}
SculptBoundaryType SCULPT_edge_is_boundary(const SculptSession *ss,
const SculptEdgeRef edge,
SculptBoundaryType typemask)
{
int ret = 0;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMEdge *e = (BMEdge *)edge.i;
if (typemask & SCULPT_BOUNDARY_MESH) {
ret |= (!e->l || e->l == e->l->radial_next) ? SCULPT_BOUNDARY_MESH : 0;
}
if ((typemask & SCULPT_BOUNDARY_FACE_SET) && e->l && e->l != e->l->radial_next) {
int fset1 = BM_ELEM_CD_GET_INT(e->l->f, ss->cd_faceset_offset);
int fset2 = BM_ELEM_CD_GET_INT(e->l->f, ss->cd_faceset_offset);
bool ok = (fset1 < 0) != (fset2 < 0);
ok = ok || fset1 != fset2;
ret |= ok ? SCULPT_BOUNDARY_FACE_SET : 0;
}
if (typemask & SCULPT_BOUNDARY_SHARP) {
ret |= !BM_elem_flag_test(e, BM_ELEM_SMOOTH) ? SCULPT_BOUNDARY_SHARP : 0;
}
if (typemask & SCULPT_BOUNDARY_SEAM) {
ret |= BM_elem_flag_test(e, BM_ELEM_SEAM) ? SCULPT_BOUNDARY_SEAM : 0;
}
break;
}
case PBVH_FACES: {
int mask = typemask & (SCULPT_BOUNDARY_MESH | SCULPT_BOUNDARY_FACE_SET);
SculptVertRef v1, v2;
SCULPT_edge_get_verts(ss, edge, &v1, &v2);
if (mask) { // use less accurate approximation for now
SculptBoundaryType a = SCULPT_vertex_is_boundary(ss, v1, mask);
SculptBoundaryType b = SCULPT_vertex_is_boundary(ss, v2, mask);
ret |= a & b;
}
if (typemask & SCULPT_BOUNDARY_SHARP) {
ret |= ss->medge[edge.i].flag & ME_SHARP ? SCULPT_BOUNDARY_SHARP : 0;
}
if (typemask & SCULPT_BOUNDARY_SEAM) {
ret |= ss->medge[edge.i].flag & ME_SEAM ? SCULPT_BOUNDARY_SEAM : 0;
}
break;
}
case PBVH_GRIDS: {
// not implemented
break;
}
}
return (SculptBoundaryType)ret;
}
void SCULPT_edge_get_verts(const SculptSession *ss,
const SculptEdgeRef edge,
SculptVertRef *r_v1,
SculptVertRef *r_v2)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
BMEdge *e = (BMEdge *)edge.i;
r_v1->i = (intptr_t)e->v1;
r_v2->i = (intptr_t)e->v2;
break;
}
case PBVH_FACES: {
r_v1->i = (intptr_t)ss->medge[edge.i].v1;
r_v2->i = (intptr_t)ss->medge[edge.i].v2;
break;
}
case PBVH_GRIDS:
// not supported yet
r_v1->i = r_v2->i = SCULPT_REF_NONE;
break;
}
}
SculptVertRef SCULPT_edge_other_vertex(const SculptSession *ss,
const SculptEdgeRef edge,
const SculptVertRef vertex)
{
SculptVertRef v1, v2;
SCULPT_edge_get_verts(ss, edge, &v1, &v2);
return v1.i == vertex.i ? v2 : v1;
}
static bool sculpt_check_boundary_vertex_in_base_mesh(const SculptSession *ss,
const SculptVertRef index)
{

View File

@ -150,15 +150,20 @@ float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss,
const int deform_target,
PBVHVertexIter *iter);
struct _SculptNeighborRef {
SculptVertRef vertex;
SculptEdgeRef edge;
};
#define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256
typedef struct SculptVertexNeighborIter {
/* Storage */
SculptVertRef *neighbors;
struct _SculptNeighborRef *neighbors;
int *neighbor_indices;
int size;
int capacity;
SculptVertRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
struct _SculptNeighborRef neighbors_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
int neighbor_indices_fixed[SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY];
/* Internal iterator. */
@ -167,7 +172,9 @@ typedef struct SculptVertexNeighborIter {
/* Public */
SculptVertRef vertex;
SculptEdgeRef edge;
int index;
bool has_edge; // does this iteration step have an edge, fake neighbors do not
bool is_duplicate;
} SculptVertexNeighborIter;
@ -181,7 +188,10 @@ void SCULPT_vertex_neighbors_get(const struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \
for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \
neighbor_iterator.i++) { \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i];
/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come
@ -190,7 +200,10 @@ void SCULPT_vertex_neighbors_get(const struct SculptSession *ss,
SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \
for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \
neighbor_iterator.i--) { \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i]; \
neighbor_iterator.has_edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge.i != \
SCULPT_REF_NONE; \
neighbor_iterator.vertex = neighbor_iterator.neighbors[neighbor_iterator.i].vertex; \
neighbor_iterator.edge = neighbor_iterator.neighbors[neighbor_iterator.i].edge; \
neighbor_iterator.index = neighbor_iterator.neighbor_indices[neighbor_iterator.i]; \
neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \
neighbor_iterator.size - neighbor_iterator.num_duplicates);
@ -1639,3 +1652,16 @@ char SCULPT_mesh_fset_boundary_symmetry_get(struct Object *object);
// exponent to make boundary_smooth_factor more user-friendly
#define BOUNDARY_SMOOTH_EXP 2.0
// edges
SculptBoundaryType SCULPT_edge_is_boundary(const SculptSession *ss,
const SculptEdgeRef edge,
SculptBoundaryType typemask);
void SCULPT_edge_get_verts(const SculptSession *ss,
const SculptEdgeRef edge,
SculptVertRef *r_v1,
SculptVertRef *r_v2);
SculptVertRef SCULPT_edge_other_vertex(const SculptSession *ss,
const SculptEdgeRef edge,
const SculptVertRef vertex);

View File

@ -137,9 +137,20 @@ void SCULPT_neighbor_coords_average_interior(SculptSession *ss,
w = 1.0f;
}
if (is_boundary) {
/*use the new edge api if edges are available, if not estimate boundary
from verts*/
if (is_boundary || ni.has_edge) {
bool is_boundary2;
if (ni.has_edge) {
is_boundary2 = SCULPT_edge_is_boundary(ss, ni.edge, bflag);
}
else {
is_boundary2 = SCULPT_vertex_is_boundary(ss, ni.vertex, bflag);
}
/* Boundary vertices use only other boundary vertices. */
if (SCULPT_vertex_is_boundary(ss, ni.vertex, bflag)) {
if (is_boundary2 || !is_boundary) {
copy_v3_v3(tmp, SCULPT_vertex_co_get(ss, ni.vertex));
ok = true;
}