Sculpt dyntopo: Removed triangle limit for PBVH_BMESH

* PBVH_BMESH now supports faces other then triangles;

* Dyntopo triangulates faces as it finds them.
  - I looked into methods of preserving quads and failed to
    find anything that worked well in practice; it actually
    worked better to use topology rake to align triangles
    into quads and then mark diagonal edges for later dissolving
    then to try to preserve quads explicitly (I've not
    implementated that here, that was research code).
  - To avoid excessive cache-destroying loops over vertex-faces,
    DynTopo flags which verts have non-triangle faces.

* PBVHTriBuf now builds edge buffers so we can avoid drawing
  tesselation phantom edges.

* BMLog also now supports arbitrary faces.  It still does not
  support edges though.

TODO:

* Fix vcol cell shading mode
* Make sure indexed drawing works
This commit is contained in:
Joseph Eagar 2021-07-20 19:46:00 -07:00
parent 7cd74015f8
commit 70a4956020
8 changed files with 594 additions and 114 deletions

View File

@ -54,7 +54,9 @@ BLI_INLINE SculptFaceRef BKE_pbvh_make_fref(intptr_t i)
}
typedef struct PBVHTri {
int v[3]; // references into PBVHTriBuf->verts
int v[3]; // references into PBVHTriBuf->verts
intptr_t l[3]; // loops
int eflag; // bitmask of which edges in the tri are real edges in the mesh
float no[3];
SculptFaceRef f;
@ -63,8 +65,9 @@ typedef struct PBVHTri {
typedef struct PBVHTriBuf {
PBVHTri *tris;
SculptVertRef *verts;
int tottri, totvert;
int tris_size, verts_size;
int *edges;
int totvert, totedge, tottri;
int verts_size, edges_size, tris_size;
// private field
intptr_t *loops;
@ -736,6 +739,8 @@ PBVHNode *BKE_pbvh_node_from_index(PBVH *pbvh, int node_i);
struct BMesh *BKE_pbvh_reorder_bmesh(PBVH *pbvh);
void BKE_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, struct BMVert *v);
#define DYNTOPO_DYNAMIC_TESS
#ifdef __cplusplus
}
#endif

View File

@ -3,6 +3,7 @@
#include "DNA_customdata_types.h"
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_modifier_types.h"
#include "BLI_array.h"
#include "BLI_bitmap.h"
@ -12,6 +13,7 @@
#include "BLI_ghash.h"
#include "BLI_heap.h"
#include "BLI_heap_simple.h"
#include "BLI_linklist.h"
#include "BLI_math.h"
#include "BLI_memarena.h"
#include "BLI_rand.h"
@ -140,6 +142,9 @@ static void pbvh_bmesh_verify(PBVH *pbvh);
} \
((void)0)
static bool check_face_is_tri(PBVH *pbvh, BMFace *f);
static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v);
BLI_INLINE void surface_smooth_v_safe(PBVH *pbvh, BMVert *v)
{
float co[3];
@ -1440,6 +1445,122 @@ static void short_edge_queue_task_cb(void *__restrict userdata,
TGSET_ITER_END
}
ATTR_NO_OPT static bool check_face_is_tri(PBVH *pbvh, BMFace *f)
{
if (f->len == 3) {
return true;
}
if (f->len < 3) {
printf("pbvh had < 3 vert face!\n");
BKE_pbvh_bmesh_remove_face(pbvh, f, false);
return false;
}
BMFace **fs = NULL;
BMEdge **es = NULL;
LinkNode *dbl = NULL;
BLI_array_staticdeclare(fs, 32);
BLI_array_staticdeclare(es, 32);
BKE_pbvh_bmesh_remove_face(pbvh, f, true);
int len = (f->len - 2) * 3;
BLI_array_grow_items(fs, len);
BLI_array_grow_items(es, len);
int totface = 0;
int totedge = 0;
MemArena *arena = NULL;
struct Heap *heap = NULL;
if (f->len > 4) {
arena = BLI_memarena_new(512, "ngon arena");
heap = BLI_heap_new();
}
BM_face_triangulate(pbvh->bm,
f,
fs,
&totface,
es,
&totedge,
&dbl,
MOD_TRIANGULATE_QUAD_FIXED,
MOD_TRIANGULATE_NGON_BEAUTY,
false,
arena,
heap);
while (totface && dbl) {
BMFace *f = dbl->link;
LinkNode *next = dbl->next;
for (int i = 0; i < totface; i++) {
if (fs[i] == f) {
fs[i] = NULL;
}
}
BM_face_kill(pbvh->bm, dbl->link);
MEM_freeN(dbl);
dbl = next;
}
for (int i = 0; i < totface; i++) {
BMFace *f2 = fs[i];
if (!f2) {
continue;
}
BKE_pbvh_bmesh_add_face(pbvh, f2, true, true);
}
BKE_pbvh_bmesh_add_face(pbvh, f, true, true);
BLI_array_free(fs);
BLI_array_free(es);
if (arena) {
BLI_memarena_free(arena);
}
if (heap) {
BLI_heap_free(heap, NULL);
}
return false;
}
ATTR_NO_OPT static bool check_vert_fan_are_tris(PBVH *pbvh, BMVert *v)
{
BMFace **fs = NULL;
BLI_array_staticdeclare(fs, 32);
MDynTopoVert *mv = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, v);
if (!(mv->flag & DYNVERT_NEED_TRIANGULATE)) {
return true;
}
BMIter iter;
BMFace *f;
BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) {
BLI_array_append(fs, f);
}
mv->flag &= ~DYNVERT_NEED_TRIANGULATE;
for (int i = 0; i < BLI_array_len(fs); i++) {
check_face_is_tri(pbvh, fs[i]);
}
BLI_array_free(fs);
return false;
}
/* Create a priority queue containing vertex pairs connected by a long
* edge as defined by PBVH.bm_max_edge_len.
*
@ -1681,6 +1802,9 @@ static void pbvh_bmesh_split_edge(EdgeQueueContext *eq_ctx,
{
BMesh *bm = pbvh->bm;
check_vert_fan_are_tris(pbvh, e->v1);
check_vert_fan_are_tris(pbvh, e->v2);
float co_mid[3], no_mid[3];
MDynTopoVert *mv1 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v1);
MDynTopoVert *mv2 = BKE_PBVH_DYNVERT(pbvh->cd_dyn_vert, e->v2);
@ -1968,6 +2092,9 @@ static void pbvh_bmesh_collapse_edge(PBVH *pbvh,
{
BMVert *v_del, *v_conn;
check_vert_fan_are_tris(pbvh, e->v1);
check_vert_fan_are_tris(pbvh, e->v2);
// customdata interpolation
if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
for (int step = 0; step < 2; step++) {
@ -2409,6 +2536,8 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
continue;
}
check_vert_fan_are_tris(pbvh, v);
const int val = BM_vert_edge_count(v);
if (val != 4 && val != 3) {
continue;
@ -2519,8 +2648,40 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
modified = true;
if (!v->e) {
printf("mesh error!\n");
continue;
}
l = v->e->l;
bool flipped = false;
if (val == 4) {
// check which quad diagonal to use to split quad
// try to preserve hard edges
float n1[3], n2[3], th1, th2;
normal_tri_v3(n1, ls[0]->v->co, ls[1]->v->co, ls[2]->v->co);
normal_tri_v3(n2, ls[0]->v->co, ls[2]->v->co, ls[3]->v->co);
th1 = dot_v3v3(n1, n2);
normal_tri_v3(n1, ls[1]->v->co, ls[2]->v->co, ls[3]->v->co);
normal_tri_v3(n2, ls[1]->v->co, ls[3]->v->co, ls[0]->v->co);
th2 = dot_v3v3(n1, n2);
if (th1 > th2) {
flipped = true;
BMLoop *ls2[4] = {ls[0], ls[1], ls[2], ls[3]};
for (int j = 0; j < 4; j++) {
ls[j] = ls2[(j + 1) % 4];
}
}
}
vs[0] = ls[0]->v;
vs[1] = ls[1]->v;
vs[2] = ls[2]->v;
@ -2540,11 +2701,15 @@ ATTR_NO_OPT static bool cleanup_valence_3_4(PBVH *pbvh,
vs[1] = ls[2]->v;
vs[2] = ls[3]->v;
BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, v->e->l->f, false, false);
BMFace *example = NULL;
if (v->e && v->e->l) {
example = v->e->l->f;
}
BMFace *f2 = pbvh_bmesh_face_create(pbvh, n, vs, NULL, example, false, false);
CustomData_bmesh_swap_data_simple(
&pbvh->bm->ldata, &f2->l_first->prev->head.data, &ls[3]->head.data);
CustomData_bmesh_copy_data(
&pbvh->bm->ldata, &pbvh->bm->ldata, ls[0]->head.data, &f2->l_first->head.data);
CustomData_bmesh_copy_data(

View File

@ -1137,7 +1137,8 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
MDynTopoVert *mv = BKE_PBVH_DYNVERT(cd_dyn_vert, v);
BMEdge *e = v->e;
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY);
mv->flag &= ~(DYNVERT_BOUNDARY | DYNVERT_FSET_BOUNDARY | DYNVERT_NEED_BOUNDARY |
DYNVERT_NEED_TRIANGULATE);
if (!e) {
mv->flag |= DYNVERT_BOUNDARY;
@ -1155,6 +1156,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
mv->flag |= DYNVERT_FSET_BOUNDARY;
}
if (e->l->f->len > 3) {
mv->flag |= DYNVERT_NEED_TRIANGULATE;
}
lastfset = fset;
first = false;
@ -1163,6 +1168,10 @@ void bke_pbvh_update_vert_boundary(int cd_dyn_vert, int cd_faceset_offset, BMVer
if (e->l->radial_next != e->l) {
fset = abs(BM_ELEM_CD_GET_INT(e->l->radial_next->f, cd_faceset_offset));
if (e->l->radial_next->f->len > 3) {
mv->flag |= DYNVERT_NEED_TRIANGULATE;
}
if (fset != lastfset) {
mv->flag |= DYNVERT_FSET_BOUNDARY;
}
@ -1557,11 +1566,35 @@ BLI_INLINE void pbvh_tribuf_add_vert(PBVHTriBuf *tribuf, SculptVertRef vertex)
tribuf->verts[tribuf->totvert - 1] = vertex;
}
BLI_INLINE void pbvh_tribuf_add_edge(PBVHTriBuf *tribuf, int v1, int v2)
{
tribuf->totedge++;
if (tribuf->totedge >= tribuf->edges_size) {
size_t newsize = (size_t)32 + (size_t)(tribuf->edges_size << 1);
if (!tribuf->edges) {
tribuf->edges = MEM_mallocN(sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
}
else {
tribuf->edges = MEM_reallocN_id(
tribuf->edges, sizeof(*tribuf->edges) * 2ULL * newsize, "tribuf edges");
}
tribuf->edges_size = newsize;
}
int i = (tribuf->totedge - 1) * 2;
tribuf->edges[i] = v1;
tribuf->edges[i + 1] = v2;
}
/* In order to perform operations on the original node coordinates
* (currently just raycast), store the node's triangles and vertices.
*
* Skips triangles that are hidden. */
bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
ATTR_NO_OPT bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
{
BMesh *bm = pbvh->bm;
@ -1586,6 +1619,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
node->tribuf = MEM_callocN(sizeof(*node->tribuf), "node->tribuf");
}
BMLoop **loops = NULL;
uint(*loops_idx)[3] = NULL;
BLI_array_staticdeclare(loops, 128);
BLI_array_staticdeclare(loops_idx, 128);
PBVHTriBuf *tribufs = NULL; // material-specific tribuffers
BLI_array_declare(tribufs);
@ -1593,9 +1632,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
node->tribuf->tottri = 0;
node->tribuf->totvert = 0;
node->tribuf->totloop = 0;
node->tribuf->totedge = 0;
node->flag &= ~PBVH_UpdateTris;
const int edgeflag = BM_ELEM_TAG_ALT;
BMFace *f;
float min[3], max[3];
@ -1607,7 +1649,12 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
continue;
}
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
// clear edgeflag for building edge indices later
BMLoop *l = f->l_first;
do {
l->e->head.hflag &= ~edgeflag;
} while ((l = l->next) != f->l_first);
const int mat_nr = f->mat_nr;
if (mat_map[mat_nr] == -1) {
@ -1621,6 +1668,70 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
BLI_array_append(tribufs, _tribuf);
}
#ifdef DYNTOPO_DYNAMIC_TESS
const int tottri = (f->len - 2);
BLI_array_clear(loops);
BLI_array_clear(loops_idx);
BLI_array_grow_items(loops, f->len);
BLI_array_grow_items(loops_idx, tottri);
BM_face_calc_tessellation(f, true, loops, loops_idx);
for (int i = 0; i < tottri; i++) {
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
tri->eflag = mat_tri->eflag = 0;
for (int j = 0; j < 3; j++) {
BMLoop *l0 = loops[loops_idx[i][(j + 2) % 3]];
BMLoop *l = loops[loops_idx[i][j]];
BMLoop *l2 = loops[loops_idx[i][(j + 1) % 3]];
void **val = NULL;
bool has_edge = false;
if (BM_edge_exists(l->v, l2->v)) {
tri->eflag |= 1 << j;
mat_tri->eflag |= 1 << j;
}
if (!BLI_ghash_ensure_p(vmap, l->v, &val)) {
SculptVertRef sv = {(intptr_t)l->v};
minmax_v3v3_v3(min, max, l->v->co);
*val = (void *)node->tribuf->totvert;
pbvh_tribuf_add_vert(node->tribuf, sv);
}
tri->v[j] = (intptr_t)val[0];
tri->l[j] = (intptr_t)l;
val = NULL;
if (!BLI_ghash_ensure_p(mat_vmaps[mat_nr], l->v, &val)) {
SculptVertRef sv = {(intptr_t)l->v};
minmax_v3v3_v3(min, max, l->v->co);
*val = (void *)mat_tribuf->totvert;
pbvh_tribuf_add_vert(mat_tribuf, sv);
}
mat_tri->v[j] = (intptr_t)val[0];
mat_tri->l[j] = (intptr_t)l;
}
copy_v3_v3(tri->no, f->no);
copy_v3_v3(mat_tri->no, f->no);
tri->f.i = (intptr_t)f;
mat_tri->f.i = (intptr_t)f;
}
#else
PBVHTri *tri = pbvh_tribuf_add_tri(node->tribuf);
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
PBVHTri *mat_tri = pbvh_tribuf_add_tri(mat_tribuf);
@ -1640,6 +1751,7 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
}
tri->v[j] = (intptr_t)val[0];
tri->l[j] = (intptr_t)l;
val = NULL;
if (!BLI_ghash_ensure_p(mat_vmaps[mat_nr], l->v, &val)) {
@ -1652,6 +1764,7 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
}
mat_tri->v[j] = (intptr_t)val[0];
mat_tri->l[j] = (intptr_t)l;
j++;
@ -1664,9 +1777,42 @@ bool BKE_pbvh_bmesh_check_tris(PBVH *pbvh, PBVHNode *node)
copy_v3_v3(tri->no, f->no);
tri->f.i = (intptr_t)f;
#endif
}
TGSET_ITER_END
TGSET_ITER (f, node->bm_faces) {
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
int mat_nr = f->mat_nr;
PBVHTriBuf *mat_tribuf = tribufs + mat_map[mat_nr];
BMLoop *l = f->l_first;
do {
if (l->e->head.hflag & edgeflag) {
continue;
}
l->e->head.hflag |= edgeflag;
int v1 = (int)BLI_ghash_lookup(vmap, (void *)l->e->v1);
int v2 = (int)BLI_ghash_lookup(vmap, (void *)l->e->v2);
pbvh_tribuf_add_edge(node->tribuf, v1, v2);
v1 = (int)BLI_ghash_lookup(mat_vmaps[mat_nr], (void *)l->e->v1);
v2 = (int)BLI_ghash_lookup(mat_vmaps[mat_nr], (void *)l->e->v2);
pbvh_tribuf_add_edge(mat_tribuf, v1, v2);
} while ((l = l->next) != f->l_first);
}
TGSET_ITER_END
BLI_array_free(loops);
BLI_array_free(loops_idx);
bm->elem_index_dirty |= BM_VERT;
node->tri_buffers = tribufs;

View File

@ -141,13 +141,22 @@ typedef struct {
void *customdata;
} BMLogVert;
#define MAX_FACE_RESERVED 8
typedef struct {
uint v_ids[3];
uint l_ids[3];
uint *v_ids;
uint *l_ids;
void **customdata;
float no[3];
void *customdata[3];
void *customdata_f;
char hflag;
size_t len;
void *customdata_res[MAX_FACE_RESERVED];
uint v_ids_res[MAX_FACE_RESERVED];
uint l_ids_res[MAX_FACE_RESERVED];
} BMLogFace;
/************************* Get/set element IDs ************************/
@ -328,19 +337,16 @@ static void bm_log_face_customdata(BMesh *bm, BMLog *log, BMFace *f, BMLogFace *
// forcibly copy id
// bm_log_copy_id(&bm->pdata, (BMElem *)f, lf->customdata_f);
BMLoop *l1 = f->l_first;
BMLoop *l2 = f->l_first->next;
BMLoop *l3 = f->l_first->prev;
BMLoop *ls[3] = {l1, l2, l3};
for (int i = 0; i < 3; i++) {
BMLoop *l = f->l_first;
int i = 0;
do {
if (lf->customdata[i]) {
BLI_mempool_free(entry->ldata.pool, lf->customdata[i]);
lf->customdata[i] = NULL;
}
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
}
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, l->head.data, &lf->customdata[i]);
} while ((i++, l = l->next) != f->l_first);
#endif
}
@ -403,28 +409,40 @@ static BMLogFace *bm_log_face_alloc(BMLog *log, BMFace *f)
{
BMLogEntry *entry = log->current_entry;
BMLogFace *lf = BLI_mempool_alloc(entry->pool_faces);
BMVert *v[3];
lf->customdata_f = lf->customdata[0] = lf->customdata[1] = lf->customdata[2] = NULL;
BLI_assert(f->len == 3);
lf->len = (size_t)f->len;
// BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v, 3);
BM_face_as_array_vert_tri(f, v);
bool have_loop_ids = (log->bm->idmap.flag & BM_LOOP);
if (f->len > MAX_FACE_RESERVED) {
lf->v_ids = (int *)MEM_callocN(sizeof(*lf->v_ids) * lf->len, "lf->l_ids");
lf->l_ids = (int *)MEM_callocN(sizeof(*lf->l_ids) * lf->len, "lf->l_ids");
lf->customdata = (void **)MEM_callocN(sizeof(*lf->l_ids) * lf->len, "lf->l_ids");
}
else {
lf->v_ids = lf->v_ids_res;
lf->l_ids = lf->l_ids_res;
lf->customdata = lf->customdata_res;
}
lf->customdata_f = NULL;
copy_v3_v3(lf->no, f->no);
if (log->bm->idmap.flag & BM_LOOP) {
lf->l_ids[0] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first);
lf->l_ids[1] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first->next);
lf->l_ids[2] = (uint)BM_ELEM_GET_ID(log->bm, f->l_first->prev);
}
else {
lf->l_ids[0] = lf->l_ids[1] = lf->l_ids[2] = (uint)-1;
}
int i = 0;
BMLoop *l = f->l_first;
do {
if (have_loop_ids) {
lf->l_ids[i] = (uint)BM_ELEM_GET_ID(log->bm, l);
}
else {
lf->l_ids[i] = (uint)-1;
}
lf->v_ids[0] = bm_log_vert_id_get(log, v[0]);
lf->v_ids[1] = bm_log_vert_id_get(log, v[1]);
lf->v_ids[2] = bm_log_vert_id_get(log, v[2]);
lf->v_ids[i] = bm_log_vert_id_get(log, l->v);
lf->customdata[i] = NULL;
} while ((i++, l = l->next) != f->l_first);
lf->hflag = f->head.hflag;
return lf;
@ -482,6 +500,9 @@ static void bm_log_faces_unmake(
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
GHashIterator gh_iter;
BMEdge **e_tri = NULL;
BLI_array_staticdeclare(e_tri, 32);
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
@ -493,17 +514,23 @@ static void bm_log_faces_unmake(
continue;
}
BMEdge *e_tri[3];
BMLoop *l_iter;
BLI_array_clear(e_tri);
BMLoop *l;
int i;
l_iter = BM_FACE_FIRST_LOOP(f);
for (i = 0; i < 3; i++, l_iter = l_iter->next) {
e_tri[i] = l_iter->e;
}
// ensure we have final customdata for face in log
#ifdef CUSTOMDATA
l = f->l_first;
i = 0;
do {
if (lf->customdata[i]) {
CustomData_bmesh_copy_data(&bm->ldata, &entry->ldata, l->head.data, &lf->customdata[i]);
}
BLI_array_append(e_tri, l->e);
} while ((i++, l = l->next) != f->l_first);
if (lf->customdata_f) {
CustomData_bmesh_copy_data(&bm->pdata, &entry->pdata, f->head.data, &lf->customdata_f);
@ -511,16 +538,6 @@ static void bm_log_faces_unmake(
// bm_log_copy_id(&bm->pdata, (BMElem *)f, lf->customdata_f);
}
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
for (i = 0; i < 3; i++) {
if (lf->customdata[i]) {
CustomData_bmesh_copy_data(
&bm->ldata, &entry->ldata, ls[i]->head.data, &lf->customdata[i]);
}
}
#endif
if (callbacks) {
callbacks->on_face_kill(f, callbacks->userdata);
}
@ -528,12 +545,14 @@ static void bm_log_faces_unmake(
BM_face_kill(bm, f);
/* Remove any unused edges */
for (i = 0; i < 3; i++) {
for (i = 0; i < (int)lf->len; i++) {
if (BM_edge_is_wire(e_tri[i])) {
BM_edge_kill(bm, e_tri[i]);
}
}
}
BLI_array_free(e_tri);
}
static void bm_log_verts_restore(
@ -568,35 +587,53 @@ static void bm_log_faces_restore(
BMesh *bm, BMLog *log, GHash *faces, BMLogEntry *entry, BMLogCallbacks *callbacks)
{
GHashIterator gh_iter;
BMVert **vs_tmp = NULL;
BLI_array_staticdeclare(vs_tmp, 32);
bool have_loop_ids = (log->bm->idmap.flag & BM_LOOP);
GHASH_ITER (gh_iter, faces) {
void *key = BLI_ghashIterator_getKey(&gh_iter);
BMLogFace *lf = BLI_ghashIterator_getValue(&gh_iter);
BMVert *v[3] = {
bm_log_vert_from_id(log, lf->v_ids[0]),
bm_log_vert_from_id(log, lf->v_ids[1]),
bm_log_vert_from_id(log, lf->v_ids[2]),
};
BMFace *f;
if (!v[0] || !v[1] || !v[2]) {
BMIter iter;
BMVert *v2;
const int cd_id = bm->idmap.cd_id_off[BM_VERT];
BLI_array_clear(vs_tmp);
bool bad = false;
BM_ITER_MESH (v2, &iter, bm, BM_VERTS_OF_MESH) {
int id = BM_ELEM_CD_GET_INT(v2, cd_id);
for (int i = 0; i < (int)lf->len; i++) {
BMVert *v = bm_log_vert_from_id(log, lf->v_ids[i]);
for (int i = 0; i < 3; i++) {
if (!v[i] && lf->v_ids[i] == (uint)id) {
printf("found vertex\n");
if (!v) {
BMIter iter;
BMVert *v2;
const int cd_id = bm->idmap.cd_id_off[BM_VERT];
bad = true;
BM_ITER_MESH (v2, &iter, bm, BM_VERTS_OF_MESH) {
int id = BM_ELEM_CD_GET_INT(v2, cd_id);
if (lf->v_ids[i] == (uint)id) {
printf("found vertex %d\n", id);
bad = false;
v = v2;
break;
}
}
if (bad) {
printf("Undo error! %p %p %p\n", v[0], v[1], v[2]);
break;
}
}
printf("Undo error! %p %p %p\n", v[0], v[1], v[2]);
continue;
if (bad) {
continue;
}
BLI_array_append(vs_tmp, v);
}
f = BM_face_create_verts(bm, v, 3, NULL, BM_CREATE_SKIP_ID, true);
BMFace *f = BM_face_create_verts(bm, vs_tmp, (int)lf->len, NULL, BM_CREATE_SKIP_ID, true);
f->head.hflag = lf->hflag;
copy_v3_v3(f->no, lf->no);
@ -607,23 +644,25 @@ static void bm_log_faces_restore(
bm_assign_id(bm, (BMElem *)f, POINTER_AS_UINT(key));
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
BMLoop *l = f->l_first;
int j = 0;
for (int i = 0; i < 3; i++) {
if (lf->l_ids[i] != (uint)-1) {
bm_assign_id(bm, (BMElem *)ls[i], lf->l_ids[i]);
do {
if (have_loop_ids) {
bm_assign_id(bm, (BMElem *)l, lf->l_ids[j]);
}
if (lf->customdata[i]) {
CustomData_bmesh_copy_data(
&entry->ldata, &bm->ldata, lf->customdata[i], &ls[i]->head.data);
if (lf->customdata[j]) {
CustomData_bmesh_copy_data(&entry->ldata, &bm->ldata, lf->customdata[j], &l->head.data);
}
}
} while ((j++, l = l->next) != f->l_first);
if (callbacks) {
callbacks->on_face_add(f, callbacks->userdata);
}
}
BLI_array_free(vs_tmp);
}
static void bm_log_vert_values_swap(
@ -691,7 +730,6 @@ static void bm_log_face_values_swap(BMLog *log,
void *old_cdata = NULL;
#ifdef CUSTOMDATA
if (f->head.data) {
old_cdata = scratch;
memcpy(old_cdata, f->head.data, (size_t)log->bm->pdata.totsize);
@ -701,15 +739,15 @@ static void bm_log_face_values_swap(BMLog *log,
CustomData_bmesh_swap_data(&entry->pdata, &log->bm->pdata, lf->customdata_f, &f->head.data);
}
BMLoop *ls[3] = {f->l_first, f->l_first->next, f->l_first->prev};
int i = 0;
BMLoop *l = f->l_first;
for (int i = 0; i < 3; i++) {
do {
if (lf->customdata[i]) {
CustomData_bmesh_swap_data(
&entry->ldata, &log->bm->ldata, lf->customdata[i], &ls[i]->head.data);
&entry->ldata, &log->bm->ldata, lf->customdata[i], &l->head.data);
}
}
#endif
} while ((i++, l = l->next) != f->l_first);
if (callbacks) {
callbacks->on_face_change(f, callbacks->userdata, old_cdata);
@ -1545,9 +1583,6 @@ void BM_log_face_added(BMLog *log, BMFace *f)
uint f_id = (uint)BM_ELEM_GET_ID(log->bm, f);
void *key = POINTER_FROM_UINT(f_id);
/* Only triangles are supported for now */
BLI_assert(f->len == 3);
lf = bm_log_face_alloc(log, f);
log_ghash_insert(log, log->current_entry->added_faces, key, lf);

View File

@ -9462,8 +9462,9 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *op)
sd->symmetrize_direction,
dist,
true);
#ifndef DYNTOPO_DYNAMIC_TESS
SCULPT_dynamic_topology_triangulate(ss, ss->bm);
#endif
/* Bisect operator flags edges (keep tags clean for edge queue). */
BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false);
@ -9600,10 +9601,7 @@ void ED_object_sculptmode_enter_ex(Main *bmain,
MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob);
const char *message_unsupported = NULL;
if (me->totloop != me->totpoly * 3) {
message_unsupported = TIP_("non-triangle face");
}
else if (mmd != NULL) {
if (mmd != NULL) {
message_unsupported = TIP_("multi-res modifier");
}
else {

View File

@ -508,7 +508,10 @@ void SCULPT_dynamic_topology_enable_ex(Main *bmain, Depsgraph *depsgraph, Scene
.active_shapekey = ob->shapenr,
}));
#endif
#ifndef DYNTOPO_DYNAMIC_TESS
SCULPT_dynamic_topology_triangulate(ss, ss->bm);
#endif
SCULPT_dyntopo_node_layers_add(ss);
SCULPT_dyntopo_save_origverts(ss);

View File

@ -1749,19 +1749,19 @@ static void GPU_pbvh_bmesh_buffers_update_indexed(GPU_PBVH_Buffers *buffers,
/* Creates a vertex buffer (coordinate, normal, color) and, if smooth
* shading, an element index buffer.
* Threaded - do not call any functions that use OpenGL calls! */
void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
TableGSet *bm_faces,
TableGSet *bm_unique_verts,
TableGSet *bm_other_verts,
PBVHTriBuf *tribuf,
const int update_flags,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only,
short mat_nr)
ATTR_NO_OPT void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
BMesh *bm,
TableGSet *bm_faces,
TableGSet *bm_unique_verts,
TableGSet *bm_other_verts,
PBVHTriBuf *tribuf,
const int update_flags,
const int cd_vert_node_offset,
int face_sets_color_seed,
int face_sets_color_default,
bool flat_vcol,
bool active_vcol_only,
short mat_nr)
{
if (flat_vcol && CustomData_has_layer(&bm->vdata, CD_PROP_COLOR)) {
@ -1815,7 +1815,15 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
return;
}
tottri = gpu_bmesh_face_visible_count(bm_faces, mat_nr);
/* TODO, make mask layer optional for bmesh buffer */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
const int cd_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
bool default_face_set = true;
#ifdef DYNTOPO_DYNAMIC_TESS
tottri = tribuf->tottri;
totvert = tottri * 3;
if (!tottri) {
@ -1827,14 +1835,132 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
buffers->tot_tri = 0;
return;
}
/* Fill vertex buffer */
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
/* Memory map failed */
return;
}
/* TODO, make mask layer optional for bmesh buffer */
const int cd_vert_mask_offset = CustomData_get_offset(&bm->vdata, CD_PAINT_MASK);
const int cd_mcol_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPCOL);
const int cd_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
int v_index = 0;
bool default_face_set = true;
GPUIndexBufBuilder elb_lines;
GPU_indexbuf_init(&elb_lines, GPU_PRIM_LINES, tottri * 3, tottri * 3);
for (int i = 0; i < tribuf->tottri; i++) {
PBVHTri *tri = tribuf->tris + i;
BMFace *f = (BMFace *)tri->f.i;
BMLoop **l = (BMLoop **)tri->l;
BMVert *v[3];
if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) {
continue;
}
v[0] = l[0]->v;
v[1] = l[1]->v;
v[2] = l[2]->v;
float fmask = 0.0f;
int i;
/* Average mask value */
for (i = 0; i < 3; i++) {
fmask += BM_ELEM_CD_GET_FLOAT(v[i], cd_vert_mask_offset);
}
fmask /= 3.0f;
if (tri->eflag & 1) {
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 0, v_index + 1);
}
if (tri->eflag & 2) {
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 1, v_index + 2);
}
if (tri->eflag & 4) {
GPU_indexbuf_add_line_verts(&elb_lines, v_index + 2, v_index + 0);
}
uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX};
if (show_face_sets && cd_fset_offset >= 0) {
const int fset = BM_ELEM_CD_GET_INT(f, cd_fset_offset);
/* Skip for the default color Face Set to render it white. */
if (fset != face_sets_color_default) {
BKE_paint_face_set_overlay_color_get(fset, face_sets_color_seed, face_set_color);
default_face_set = false;
}
}
for (int j = 0; j < 3; j++) {
float *no = buffers->smooth ? v[j]->no : f->no;
gpu_bmesh_vert_to_buffer_copy(v[j],
buffers->vert_buf,
v_index,
no,
&fmask,
cd_vert_mask_offset,
cd_vert_node_offset,
show_mask,
false,
&empty_mask,
NULL,
0);
if (cd_vcol_count >= 0) {
for (int k = 0; k < cd_vcol_count; k++) {
MPropCol *mp = BM_ELEM_CD_GET_VOID_P(l[j]->v, cd_vcols[k]);
ushort vcol[4];
// printf(
// "%.2f %.2f %.2f %.2f\n", mp->color[0], mp->color[1], mp->color[2],
// mp->color[3]);
vcol[0] = unit_float_to_ushort_clamp(mp->color[0]);
vcol[1] = unit_float_to_ushort_clamp(mp->color[1]);
vcol[2] = unit_float_to_ushort_clamp(mp->color[2]);
vcol[3] = unit_float_to_ushort_clamp(mp->color[3]);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[k], v_index, vcol);
}
}
else if (cd_mcol_offset >= 0) {
ushort vcol[4];
MLoopCol *ml = BM_ELEM_CD_GET_VOID_P(l[j], cd_mcol_offset);
vcol[0] = ml->r * 257;
vcol[1] = ml->g * 257;
vcol[2] = ml->b * 257;
vcol[3] = ml->a * 257;
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.col[0], v_index, vcol);
}
if (have_uv) {
MLoopUV *mu = BM_ELEM_CD_GET_VOID_P(l[j], cd_uv_offset);
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.uv, v_index, mu->uv);
}
GPU_vertbuf_attr_set(buffers->vert_buf, g_vbo_id.fset, v_index, face_set_color);
v_index++;
}
}
#else
tottri = tribuf->tottri;
totvert = tottri * 3;
if (!tottri) {
/* empty node (i.e. not just hidden)? */
if (!BLI_table_gset_len(bm_faces) != 0) {
buffers->clear_bmesh_on_flush = true;
}
buffers->tot_tri = 0;
return;
}
/* Fill vertex buffer */
if (!gpu_pbvh_vert_buf_data_set(buffers, totvert)) {
/* Memory map failed */
@ -1940,6 +2066,7 @@ void GPU_pbvh_bmesh_buffers_update(GPU_PBVH_Buffers *buffers,
}
}
TGSET_ITER_END
#endif
buffers->index_lines_buf = GPU_indexbuf_build(&elb_lines);
buffers->tot_tri = tottri;

View File

@ -547,7 +547,8 @@ enum {
DYNVERT_BOUNDARY = (1 << 0),
DYNVERT_VERT_FSET_HIDDEN = (1 << 1),
DYNVERT_FSET_BOUNDARY = (1 << 2),
DYNVERT_NEED_BOUNDARY = (1 << 3)
DYNVERT_NEED_BOUNDARY = (1 << 3),
DYNVERT_NEED_TRIANGULATE = (1 << 4)
};
#ifdef __cplusplus