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:
parent
b21595cdf9
commit
39b0e9df81
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue