Add dynamic topology support to the PBVH

* Add BLI_pbvh_build_bmesh(), similar to the other PBVH builders but
  specialized for BMesh. Whereas the PBVH leaf nodes for mesh and
  grids only store a start-index and count into the primitive indices
  array, the BMesh version uses GHashes to store the full set of faces
  and vertices in leaf nodes

* Update PBVH iterator to handle BMesh

* Make some of the pbvh.c functions non-static so they can be used by
  the new pbvh_bmesh code

* The BLI_pbvh_bmesh_update_topology() function is the main reason for
  adding BMesh support to the PBVH. This function is used during a
  sculpt stroke to dynamically collapse edges that are particular
  short and subdivide edges that are particularly long.
This commit is contained in:
Nicholas Bishop
2012-12-30 18:28:36 +00:00
parent 2c9d22fe31
commit 2e69b0cd0b
5 changed files with 1582 additions and 22 deletions

View File

@@ -27,13 +27,18 @@
*/
#include "BLI_bitmap.h"
#include "BLI_ghash.h"
#include "BLI_utildefines.h"
/* Needed for BMesh functions used in the PBVH iterator macro */
#include "bmesh.h"
struct CCGElem;
struct CCGKey;
struct CustomData;
struct DMFlagMat;
struct DMGridAdjacency;
struct ListBase;
struct GHash;
struct MFace;
struct MVert;
struct PBVH;
@@ -63,6 +68,9 @@ void BLI_pbvh_build_grids(PBVH *bvh, struct CCGElem **grid_elems,
struct DMGridAdjacency *gridadj, int totgrid,
struct CCGKey *key, void **gridfaces, struct DMFlagMat *flagmats,
unsigned int **grid_hidden);
void BLI_pbvh_build_bmesh(PBVH *bvh, struct BMesh *bm, int smooth_shading,
struct BMLog *log);
void BLI_pbvh_free(PBVH *bvh);
/* Hierarchical Search in the BVH, two methods:
@@ -86,7 +94,7 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
const float ray_start[3], const float ray_normal[3],
int original);
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco,
const float ray_start[3], const float ray_normal[3],
float *dist);
@@ -100,6 +108,7 @@ void BLI_pbvh_draw(PBVH *bvh, float (*planes)[4], float (*face_nors)[3],
typedef enum {
PBVH_FACES,
PBVH_GRIDS,
PBVH_BMESH
} PBVHType;
PBVHType BLI_pbvh_type(const PBVH *bvh);
@@ -110,6 +119,17 @@ unsigned int **BLI_pbvh_grid_hidden(const PBVH *bvh);
/* multires level, only valid for type == PBVH_GRIDS */
void BLI_pbvh_get_grid_key(const PBVH *pbvh, struct CCGKey *key);
/* Only valid for type == PBVH_BMESH */
BMesh *BLI_pbvh_get_bmesh(PBVH *pbvh);
void BLI_pbvh_bmesh_detail_size_set(PBVH *pbvh, float detail_size);
typedef enum {
PBVH_Subdivide = 1,
PBVH_Collapse = 2,
} PBVHTopologyUpdateMode;
int BLI_pbvh_bmesh_update_topology(PBVH *bvh, PBVHTopologyUpdateMode mode,
const float center[3], float radius);
/* Node Access */
typedef enum {
@@ -122,12 +142,15 @@ typedef enum {
PBVH_UpdateRedraw = 32,
PBVH_RebuildDrawBuffers = 64,
PBVH_FullyHidden = 128
PBVH_FullyHidden = 128,
PBVH_UpdateTopology = 256,
} PBVHNodeFlags;
void BLI_pbvh_node_mark_update(PBVHNode *node);
void BLI_pbvh_node_mark_rebuild_draw(PBVHNode *node);
void BLI_pbvh_node_fully_hidden_set(PBVHNode *node, int fully_hidden);
void BLI_pbvh_node_mark_topology_update(PBVHNode *node);
void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node,
int **grid_indices, int *totgrid, int *maxgrid, int *gridsize,
@@ -147,6 +170,11 @@ int BLI_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data);
/* test if AABB is at least partially outside the planes' volume */
int BLI_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data);
struct GHash *BLI_pbvh_bmesh_node_unique_verts(PBVHNode *node);
struct GHash *BLI_pbvh_bmesh_node_other_verts(PBVHNode *node);
void BLI_pbvh_bmesh_node_save_orig(PBVHNode *node);
void BLI_pbvh_bmesh_after_stroke(PBVH *bvh);
/* Update Normals/Bounding Box/Draw Buffers/Redraw and clear flags */
void BLI_pbvh_update(PBVH *bvh, int flags, float (*face_nors)[3]);
@@ -169,7 +197,6 @@ float (*BLI_pbvh_get_vertCos(struct PBVH *pbvh))[3];
void BLI_pbvh_apply_vertCos(struct PBVH *pbvh, float (*vertCos)[3]);
int BLI_pbvh_isDeformed(struct PBVH *pbvh);
/* Vertex Iterator */
/* this iterator has quite a lot of code, but it's designed to:
@@ -205,9 +232,15 @@ typedef struct PBVHVertexIter {
int *vert_indices;
float *vmask;
/* bmesh */
struct GHashIterator bm_unique_verts;
struct GHashIterator bm_other_verts;
struct CustomData *bm_vdata;
/* result: these are all computed in the macro, but we assume
* that compiler optimization's will skip the ones we don't use */
struct MVert *mvert;
struct BMVert *bm_vert;
float *co;
short *no;
float *fno;
@@ -249,7 +282,7 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
continue; \
} \
} \
else { \
else if (vi.mverts) { \
vi.mvert = &vi.mverts[vi.vert_indices[vi.gx]]; \
if (mode == PBVH_ITER_UNIQUE && vi.mvert->flag & ME_HIDE) \
continue; \
@@ -258,6 +291,24 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
if (vi.vmask) \
vi.mask = &vi.vmask[vi.vert_indices[vi.gx]]; \
} \
else { \
if (!BLI_ghashIterator_isDone(&vi.bm_unique_verts)) {\
vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_unique_verts); \
BLI_ghashIterator_step(&vi.bm_unique_verts); \
} \
else { \
vi.bm_vert = BLI_ghashIterator_getKey(&vi.bm_other_verts); \
BLI_ghashIterator_step(&vi.bm_other_verts); \
} \
if (mode == PBVH_ITER_UNIQUE && \
BM_elem_flag_test(vi.bm_vert, BM_ELEM_HIDDEN)) \
continue; \
vi.co = vi.bm_vert->co; \
vi.fno = vi.bm_vert->no; \
vi.mask = CustomData_bmesh_get(vi.bm_vdata, \
vi.bm_vert->head.data, \
CD_PAINT_MASK); \
}
#define BLI_pbvh_vertex_iter_end \
} \

View File

@@ -124,6 +124,7 @@ set(SRC
intern/particle.c
intern/particle_system.c
intern/pbvh.c
intern/pbvh_bmesh.c
intern/pointcache.c
intern/property.c
intern/report.c

View File

@@ -66,14 +66,14 @@ typedef struct PBVHIter {
int stackspace;
} PBVHIter;
static void BB_reset(BB *bb)
void BB_reset(BB *bb)
{
bb->bmin[0] = bb->bmin[1] = bb->bmin[2] = FLT_MAX;
bb->bmax[0] = bb->bmax[1] = bb->bmax[2] = -FLT_MAX;
}
/* Expand the bounding box to include a new coordinate */
static void BB_expand(BB *bb, float co[3])
void BB_expand(BB *bb, const float co[3])
{
int i;
for (i = 0; i < 3; ++i) {
@@ -83,7 +83,7 @@ static void BB_expand(BB *bb, float co[3])
}
/* Expand the bounding box to include another bounding box */
static void BB_expand_with_bb(BB *bb, BB *bb2)
void BB_expand_with_bb(BB *bb, BB *bb2)
{
int i;
for (i = 0; i < 3; ++i) {
@@ -93,7 +93,7 @@ static void BB_expand_with_bb(BB *bb, BB *bb2)
}
/* Return 0, 1, or 2 to indicate the widest axis of the bounding box */
static int BB_widest_axis(BB *bb)
int BB_widest_axis(const BB *bb)
{
float dim[3];
int i;
@@ -115,7 +115,7 @@ static int BB_widest_axis(BB *bb)
}
}
static void BBC_update_centroid(BBC *bbc)
void BBC_update_centroid(BBC *bbc)
{
int i;
for (i = 0; i < 3; ++i)
@@ -220,7 +220,7 @@ static int partition_indices_material(PBVH *bvh, int lo, int hi)
}
}
static void grow_nodes(PBVH *bvh, int totnode)
void pbvh_grow_nodes(PBVH *bvh, int totnode)
{
if (totnode > bvh->node_mem_count) {
PBVHNode *prev = bvh->nodes;
@@ -433,7 +433,7 @@ static void build_sub(PBVH *bvh, int node_index, BB *cb, BBC *prim_bbc,
/* Add two child nodes */
bvh->nodes[node_index].children_offset = bvh->totnode;
grow_nodes(bvh, bvh->totnode + 2);
pbvh_grow_nodes(bvh, bvh->totnode + 2);
/* Update parent node bounding box */
update_vb(bvh, &bvh->nodes[node_index], prim_bbc, offset, count);
@@ -601,6 +601,13 @@ void BLI_pbvh_free(PBVH *bvh)
if (node->face_vert_indices)
MEM_freeN(node->face_vert_indices);
BLI_pbvh_node_layer_disp_free(node);
if (node->bm_faces)
BLI_ghash_free(node->bm_faces, NULL, NULL);
if (node->bm_unique_verts)
BLI_ghash_free(node->bm_unique_verts, NULL, NULL);
if (node->bm_other_verts)
BLI_ghash_free(node->bm_other_verts, NULL, NULL);
}
}
@@ -620,6 +627,11 @@ void BLI_pbvh_free(PBVH *bvh)
if (bvh->prim_indices)
MEM_freeN(bvh->prim_indices);
if (bvh->bm_vert_to_node)
BLI_ghash_free(bvh->bm_vert_to_node, NULL, NULL);
if (bvh->bm_face_to_node)
BLI_ghash_free(bvh->bm_face_to_node, NULL, NULL);
MEM_freeN(bvh);
}
@@ -900,6 +912,11 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
float (*vnor)[3];
int n;
if (bvh->type == PBVH_BMESH) {
pbvh_bmesh_normals_update(nodes, totnode);
return;
}
if (bvh->type != PBVH_FACES)
return;
@@ -993,8 +1010,7 @@ static void pbvh_update_normals(PBVH *bvh, PBVHNode **nodes,
MEM_freeN(vnor);
}
static void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes,
int totnode, int flag)
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag)
{
int n;
@@ -1041,6 +1057,11 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->prim_indices,
node->totprim);
break;
case PBVH_BMESH:
node->draw_buffers =
GPU_build_bmesh_buffers(bvh->flags &
PBVH_DYNTOPO_SMOOTH_SHADING);
break;
}
node->flag &= ~PBVH_RebuildDrawBuffers;
@@ -1068,6 +1089,13 @@ static void pbvh_update_draw_buffers(PBVH *bvh, PBVHNode **nodes, int totnode)
node->face_vert_indices,
bvh->show_diffuse_color);
break;
case PBVH_BMESH:
GPU_update_bmesh_buffers(node->draw_buffers,
bvh->bm,
node->bm_faces,
node->bm_unique_verts,
node->bm_other_verts);
break;
}
node->flag &= ~PBVH_UpdateDrawBuffers;
@@ -1222,6 +1250,12 @@ void BLI_pbvh_get_grid_key(const PBVH *bvh, CCGKey *key)
*key = bvh->gridkey;
}
BMesh *BLI_pbvh_get_bmesh(PBVH *bvh)
{
BLI_assert(bvh->type == PBVH_BMESH);
return bvh->bm;
}
/***************************** Node Access ***********************************/
void BLI_pbvh_node_mark_update(PBVHNode *node)
@@ -1264,6 +1298,11 @@ void BLI_pbvh_node_num_verts(PBVH *bvh, PBVHNode *node, int *uniquevert, int *to
if (totvert) *totvert = node->uniq_verts + node->face_verts;
if (uniquevert) *uniquevert = node->uniq_verts;
break;
case PBVH_BMESH:
tot = BLI_ghash_size(node->bm_unique_verts);
if (totvert) *totvert = tot + BLI_ghash_size(node->bm_other_verts);
if (uniquevert) *uniquevert = tot;
break;
}
}
@@ -1279,6 +1318,7 @@ void BLI_pbvh_node_get_grids(PBVH *bvh, PBVHNode *node, int **grid_indices, int
if (gridadj) *gridadj = bvh->gridadj;
break;
case PBVH_FACES:
case PBVH_BMESH:
if (grid_indices) *grid_indices = NULL;
if (totgrid) *totgrid = 0;
if (maxgrid) *maxgrid = 0;
@@ -1345,11 +1385,11 @@ void BLI_pbvh_raycast(PBVH *bvh, BLI_pbvh_HitOccludedCallback cb, void *data,
BLI_pbvh_search_callback_occluded(bvh, ray_aabb_intersect, &rcd, cb, data);
}
static int ray_face_intersection(const float ray_start[3],
const float ray_normal[3],
const float *t0, const float *t1,
const float *t2, const float *t3,
float *fdist)
int ray_face_intersection(const float ray_start[3],
const float ray_normal[3],
const float *t0, const float *t1,
const float *t2, const float *t3,
float *fdist)
{
float dist;
@@ -1455,7 +1495,7 @@ static int pbvh_grids_node_raycast(PBVH *bvh, PBVHNode *node,
return hit;
}
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3], int use_origco,
const float ray_start[3], const float ray_normal[3],
float *dist)
{
@@ -1473,6 +1513,9 @@ int BLI_pbvh_node_raycast(PBVH *bvh, PBVHNode *node, float (*origco)[3],
hit |= pbvh_grids_node_raycast(bvh, node, origco,
ray_start, ray_normal, dist);
break;
case PBVH_BMESH:
hit = pbvh_bmesh_node_raycast(node, ray_start, ray_normal, dist, use_origco);
break;
}
return hit;
@@ -1803,12 +1846,18 @@ void pbvh_vertex_iter_init(PBVH *bvh, PBVHNode *node,
vi->vert_indices = vert_indices;
vi->mverts = verts;
if (bvh->type == PBVH_BMESH) {
BLI_ghashIterator_init(&vi->bm_unique_verts, node->bm_unique_verts);
BLI_ghashIterator_init(&vi->bm_other_verts, node->bm_other_verts);
vi->bm_vdata = &bvh->bm->vdata;
}
vi->gh = NULL;
if (vi->grids && mode == PBVH_ITER_UNIQUE)
vi->grid_hidden = bvh->grid_hidden;
vi->mask = NULL;
if (!vi->grids)
if (bvh->type == PBVH_FACES)
vi->vmask = CustomData_get_layer(bvh->vdata, CD_PAINT_MASK);
}

File diff suppressed because it is too large Load Diff

View File

@@ -31,6 +31,8 @@ typedef struct {
float bmin[3], bmax[3], bcentroid[3];
} BBC;
/* Note: this structure is getting large, might want to split it into
* union'd structs */
struct PBVHNode {
/* Opaque handle for drawing code */
GPU_Buffers *draw_buffers;
@@ -86,7 +88,7 @@ struct PBVHNode {
/* Indicates whether this node is a leaf or not; also used for
* marking various updates that need to be applied. */
PBVHNodeFlags flag : 8;
PBVHNodeFlags flag : 16;
/* Used for raycasting: how close bb is to the ray point. */
float tmin;
@@ -96,10 +98,25 @@ struct PBVHNode {
int proxy_count;
PBVHProxyNode *proxies;
/* Dyntopo */
GHash *bm_faces;
GHash *bm_unique_verts;
GHash *bm_other_verts;
float (*bm_orco)[3];
int (*bm_ortri)[3];
int bm_tot_ortri;
};
typedef enum {
PBVH_DYNTOPO_SMOOTH_SHADING = 1
} PBVHFlags;
typedef struct PBVHBMeshLog PBVHBMeshLog;
struct PBVH {
PBVHType type;
PBVHFlags flags;
PBVHNode *nodes;
int node_mem_count, totnode;
@@ -136,6 +153,34 @@ struct PBVH {
int deformed;
int show_diffuse_color;
/* Dynamic topology */
BMesh *bm;
GHash *bm_face_to_node;
GHash *bm_vert_to_node;
float bm_max_edge_len;
float bm_min_edge_len;
struct BMLog *bm_log;
};
/* pbvh.c */
void BB_reset(BB *bb);
void BB_expand(BB *bb, const float co[3]);
void BB_expand_with_bb(BB *bb, BB *bb2);
void BBC_update_centroid(BBC *bbc);
int BB_widest_axis(const BB *bb);
void pbvh_grow_nodes(PBVH *bvh, int totnode);
int ray_face_intersection(const float ray_start[3], const float ray_normal[3],
const float *t0, const float *t1, const float *t2,
const float *t3, float *fdist);
void pbvh_update_BB_redraw(PBVH *bvh, PBVHNode **nodes, int totnode, int flag);
/* pbvh_bmesh.c */
int pbvh_bmesh_node_raycast(PBVHNode *node, const float ray_start[3],
const float ray_normal[3], float *dist,
int use_original);
void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode);
#endif