Sculpt: Improve mesh normals update performance #116209

Merged
Hans Goudey merged 14 commits from HooglyBoogly/blender:pbvh-mesh-normals-full-node into main 2024-01-08 18:49:36 +01:00
12 changed files with 172 additions and 287 deletions
Showing only changes of commit b52bf95d47 - Show all commits

View File

@ -769,7 +769,7 @@ size_t blf_font_width_to_rstrlen(
i_tmp = i;
g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
for (width_new = pen_x = 0; (s != nullptr);
for (width_new = pen_x = 0; (s != nullptr && i > 0);
i = i_prev, s = s_prev, g = g_prev, g_prev = nullptr, width_new = pen_x)
{
s_prev = BLI_str_find_prev_char_utf8(s, str);

View File

@ -809,27 +809,6 @@ BLI_INLINE void *BKE_sculpt_vertex_attr_get(const PBVHVertRef vertex, const Scul
return NULL;
}
BLI_INLINE void *BKE_sculpt_face_attr_get(const PBVHFaceRef vertex, const SculptAttribute *attr)
{
if (attr->data) {
char *p = (char *)attr->data;
int idx = (int)vertex.i;
if (attr->data_for_bmesh) {
BMElem *v = (BMElem *)vertex.i;
idx = v->head.index;
}
return p + attr->elem_size * (int)idx;
}
else {
BMElem *v = (BMElem *)vertex.i;
return BM_ELEM_CD_GET_VOID_P(v, attr->bmesh_cd_offset);
}
return NULL;
}
/**
* Create new color layer on object if it doesn't have one and if experimental feature set has
* sculpt vertex color enabled. Returns truth if new layer has been added, false otherwise.

View File

@ -65,20 +65,6 @@ struct PBVHVertRef {
PBVH_REF_CXX_METHODS(PBVHVertRef)
};
/* NOTE: edges in PBVH_GRIDS are always pulled from the base mesh. */
struct PBVHEdgeRef {
intptr_t i;
PBVH_REF_CXX_METHODS(PBVHVertRef)
};
/* NOTE: faces in PBVH_GRIDS are always puled from the base mesh. */
struct PBVHFaceRef {
intptr_t i;
PBVH_REF_CXX_METHODS(PBVHVertRef)
};
#define PBVH_REF_NONE -1LL
/* Public members of PBVH, used for inlined functions. */

View File

@ -111,18 +111,6 @@ BLI_INLINE PBVHVertRef BKE_pbvh_make_vref(intptr_t i)
return ret;
}
BLI_INLINE PBVHEdgeRef BKE_pbvh_make_eref(intptr_t i)
{
PBVHEdgeRef ret = {i};
return ret;
}
BLI_INLINE PBVHFaceRef BKE_pbvh_make_fref(intptr_t i)
{
PBVHFaceRef ret = {i};
return ret;
}
BLI_INLINE int BKE_pbvh_vertex_to_index(PBVH *pbvh, PBVHVertRef v)
{
return (BKE_pbvh_type(pbvh) == PBVH_BMESH && v.i != PBVH_REF_NONE ?
@ -143,46 +131,6 @@ BLI_INLINE PBVHVertRef BKE_pbvh_index_to_vertex(PBVH *pbvh, int index)
return BKE_pbvh_make_vref(PBVH_REF_NONE);
}
BLI_INLINE int BKE_pbvh_edge_to_index(PBVH *pbvh, PBVHEdgeRef e)
{
return (BKE_pbvh_type(pbvh) == PBVH_BMESH && e.i != PBVH_REF_NONE ?
BM_elem_index_get((BMEdge *)(e.i)) :
(e.i));
}
BLI_INLINE PBVHEdgeRef BKE_pbvh_index_to_edge(PBVH *pbvh, int index)
{
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
return BKE_pbvh_make_eref(index);
case PBVH_BMESH:
return BKE_pbvh_make_eref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->etable[index]);
}
return BKE_pbvh_make_eref(PBVH_REF_NONE);
}
BLI_INLINE int BKE_pbvh_face_to_index(PBVH *pbvh, PBVHFaceRef f)
{
return (BKE_pbvh_type(pbvh) == PBVH_BMESH && f.i != PBVH_REF_NONE ?
BM_elem_index_get((BMFace *)(f.i)) :
(f.i));
}
BLI_INLINE PBVHFaceRef BKE_pbvh_index_to_face(PBVH *pbvh, int index)
{
switch (BKE_pbvh_type(pbvh)) {
case PBVH_FACES:
case PBVH_GRIDS:
return BKE_pbvh_make_fref(index);
case PBVH_BMESH:
return BKE_pbvh_make_fref((intptr_t)BKE_pbvh_get_bmesh(pbvh)->ftable[index]);
}
return BKE_pbvh_make_fref(PBVH_REF_NONE);
}
/* Callbacks */
/**
@ -193,24 +141,23 @@ using BKE_pbvh_HitCallback = void (*)(PBVHNode *node, void *data);
using BKE_pbvh_HitOccludedCallback = void (*)(PBVHNode *node, void *data, float *tmin);
using BKE_pbvh_SearchNearestCallback = void (*)(PBVHNode *node, void *data, float *tmin);
/* Building */
PBVH *BKE_pbvh_new(PBVHType type);
namespace blender::bke::pbvh {
/**
* Do a full rebuild with on Mesh data structure.
*/
void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh);
void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh);
PBVH *build_mesh(Mesh *mesh);
void update_mesh_pointers(PBVH *pbvh, Mesh *mesh);
/**
* Do a full rebuild with on Grids data structure.
*/
void BKE_pbvh_build_grids(PBVH *pbvh, const CCGKey *key, Mesh *mesh, SubdivCCG *subdiv_ccg);
PBVH *build_grids(const CCGKey *key, Mesh *mesh, SubdivCCG *subdiv_ccg);
/**
* Build a PBVH from a BMesh.
*/
void BKE_pbvh_build_bmesh(
PBVH *pbvh, BMesh *bm, BMLog *log, int cd_vert_node_offset, int cd_face_node_offset);
PBVH *build_bmesh(BMesh *bm, BMLog *log, int cd_vert_node_offset, int cd_face_node_offset);
} // namespace blender::bke::pbvh
void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_face_node_offset);
@ -314,14 +261,17 @@ blender::Bounds<blender::float3> BKE_pbvh_bounding_box(const PBVH *pbvh);
void BKE_pbvh_sync_visibility_from_verts(PBVH *pbvh, Mesh *mesh);
namespace blender::bke::pbvh {
/**
* Returns the number of visible quads in the nodes' grids.
*/
int BKE_pbvh_count_grid_quads(const blender::BitGroupVector<> &grid_visibility,
const int *grid_indices,
int totgrid,
int gridsize,
int display_gridsize);
int count_grid_quads(const BitGroupVector<> &grid_visibility,
Span<int> grid_indices,
int gridsize,
int display_gridsize);
} // namespace blender::bke::pbvh
/**
* Multi-res level, only valid for type == #PBVH_GRIDS.

View File

@ -2106,26 +2106,22 @@ void BKE_sculpt_sync_face_visibility_to_grids(Mesh *mesh, SubdivCCG *subdiv_ccg)
});
}
namespace blender::bke {
static PBVH *build_pbvh_for_dynamic_topology(Object *ob)
{
PBVH *pbvh = ob->sculpt->pbvh = BKE_pbvh_new(PBVH_BMESH);
sculptsession_bmesh_add_layers(ob);
BKE_pbvh_build_bmesh(pbvh,
ob->sculpt->bm,
ob->sculpt->bm_log,
ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset,
ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset);
return pbvh;
return pbvh::build_bmesh(ob->sculpt->bm,
ob->sculpt->bm_log,
ob->sculpt->attrs.dyntopo_node_id_vertex->bmesh_cd_offset,
ob->sculpt->attrs.dyntopo_node_id_face->bmesh_cd_offset);
}
static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
{
Mesh *mesh = BKE_object_get_original_mesh(ob);
PBVH *pbvh = BKE_pbvh_new(PBVH_FACES);
BKE_pbvh_build_mesh(pbvh, mesh);
PBVH *pbvh = pbvh::build_mesh(mesh);
const bool is_deformed = check_sculpt_object_deformed(ob, true);
if (is_deformed && me_eval_deform != nullptr) {
@ -2138,17 +2134,17 @@ static PBVH *build_pbvh_from_regular_mesh(Object *ob, Mesh *me_eval_deform)
static PBVH *build_pbvh_from_ccg(Object *ob, SubdivCCG *subdiv_ccg)
{
const CCGKey key = BKE_subdiv_ccg_key_top_level(*subdiv_ccg);
PBVH *pbvh = BKE_pbvh_new(PBVH_GRIDS);
Mesh *base_mesh = BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_visibility_to_grids(base_mesh, subdiv_ccg);
BKE_pbvh_build_grids(pbvh, &key, base_mesh, subdiv_ccg);
return pbvh;
return pbvh::build_grids(&key, base_mesh, subdiv_ccg);
}
} // namespace blender::bke
PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
{
using namespace blender::bke;
if (ob->sculpt == nullptr) {
return nullptr;
}
@ -2160,7 +2156,7 @@ PBVH *BKE_sculpt_object_pbvh_ensure(Depsgraph *depsgraph, Object *ob)
const PBVHType pbvh_type = BKE_pbvh_type(pbvh);
switch (pbvh_type) {
case PBVH_FACES: {
BKE_pbvh_update_mesh_pointers(pbvh, BKE_object_get_original_mesh(ob));
pbvh::update_mesh_pointers(pbvh, BKE_object_get_original_mesh(ob));
break;
}
case PBVH_GRIDS: {
@ -2264,16 +2260,13 @@ void BKE_paint_face_set_overlay_color_get(const int face_set, const int seed, uc
int BKE_sculptsession_vertex_count(const SculptSession *ss)
{
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_FACES:
return ss->totvert;
case PBVH_BMESH:
return BM_mesh_elem_count(ss->bm, BM_VERT);
case PBVH_GRIDS:
return BKE_pbvh_get_grid_num_verts(ss->pbvh);
if (ss->bm) {
return ss->bm->totvert;
}
return 0;
if (ss->subdiv_ccg) {
return ss->subdiv_ccg->grids.size() * BKE_subdiv_ccg_key_top_level(*ss->subdiv_ccg).grid_area;
}
return ss->totvert;
}
/**
@ -2390,79 +2383,67 @@ static bool sculpt_attribute_create(SculptSession *ss,
out->simple_array = false;
switch (BKE_pbvh_type(ss->pbvh)) {
case PBVH_BMESH: {
CustomData *cdata = nullptr;
out->data_for_bmesh = true;
if (BMesh *bm = ss->bm) {
CustomData *cdata = nullptr;
out->data_for_bmesh = true;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &ss->bm->vdata;
break;
case ATTR_DOMAIN_FACE:
cdata = &ss->bm->pdata;
break;
default:
out->used = false;
return false;
}
BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
BM_data_layer_add_named(ss->bm, cdata, proptype, name);
int index = CustomData_get_named_layer_index(cdata, proptype, name);
if (!permanent) {
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
out->data = nullptr;
out->layer = cdata->layers + index;
out->bmesh_cd_offset = out->layer->offset;
out->elem_size = CustomData_sizeof(proptype);
break;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &bm->vdata;
break;
case ATTR_DOMAIN_FACE:
cdata = &bm->pdata;
break;
default:
out->used = false;
return false;
}
case PBVH_FACES: {
CustomData *cdata = nullptr;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &mesh->vert_data;
break;
case ATTR_DOMAIN_FACE:
cdata = &mesh->face_data;
break;
default:
out->used = false;
return false;
}
BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
BM_data_layer_add_named(bm, cdata, proptype, name);
int index = CustomData_get_named_layer_index(cdata, proptype, name);
CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, totelem, name);
int index = CustomData_get_named_layer_index(cdata, proptype, name);
if (!permanent) {
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
out->layer = cdata->layers + index;
out->data = out->layer->data;
out->data_for_bmesh = false;
out->bmesh_cd_offset = -1;
out->elem_size = CustomData_get_elem_size(out->layer);
break;
if (!permanent) {
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
case PBVH_GRIDS: {
/* GRIDS should have been handled as simple arrays. */
BLI_assert_unreachable();
break;
}
default:
BLI_assert_unreachable();
break;
out->data = nullptr;
out->layer = cdata->layers + index;
out->bmesh_cd_offset = out->layer->offset;
out->elem_size = CustomData_sizeof(proptype);
}
else {
CustomData *cdata = nullptr;
switch (domain) {
case ATTR_DOMAIN_POINT:
cdata = &mesh->vert_data;
break;
case ATTR_DOMAIN_FACE:
cdata = &mesh->face_data;
break;
default:
out->used = false;
return false;
}
BLI_assert(CustomData_get_named_layer_index(cdata, proptype, name) == -1);
CustomData_add_layer_named(cdata, proptype, CD_SET_DEFAULT, totelem, name);
int index = CustomData_get_named_layer_index(cdata, proptype, name);
if (!permanent) {
cdata->layers[index].flag |= CD_FLAG_TEMPORARY | CD_FLAG_NOCOPY;
}
out->layer = cdata->layers + index;
out->data = out->layer->data;
out->data_for_bmesh = false;
out->bmesh_cd_offset = -1;
out->elem_size = CustomData_get_elem_size(out->layer);
}
/* GRIDS should have been handled as simple arrays. */
out->used = true;
out->elem_num = totelem;

View File

@ -146,8 +146,6 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node)
}
}
} // namespace blender::bke::pbvh
static bool face_materials_match(const Span<int> material_indices,
const Span<bool> sharp_faces,
const int a,
@ -168,7 +166,7 @@ static bool face_materials_match(const Span<int> material_indices,
/* Adapted from BLI_kdopbvh.c */
/* Returns the index of the first element on the right of the partition */
static int partition_prim_indices(blender::MutableSpan<int> prim_indices,
static int partition_prim_indices(MutableSpan<int> prim_indices,
int *prim_scratch,
int lo,
int hi,
@ -177,7 +175,6 @@ static int partition_prim_indices(blender::MutableSpan<int> prim_indices,
const Span<Bounds<float3>> prim_bounds,
const Span<int> prim_to_face_map)
{
using namespace blender;
for (int i = lo; i < hi; i++) {
prim_scratch[i - lo] = prim_indices[i];
}
@ -231,14 +228,9 @@ static int partition_indices_material_faces(MutableSpan<int> indices,
}
}
void pbvh_grow_nodes(PBVH *pbvh, int totnode)
{
pbvh->nodes.resize(totnode);
}
/* Add a vertex to the map, with a positive value for unique vertices and
* a negative value for additional vertices */
static int map_insert_vert(blender::Map<int, int> &map,
static int map_insert_vert(Map<int, int> &map,
MutableSpan<bool> vert_bitmap,
int *face_verts,
int *uniq_verts,
@ -271,7 +263,7 @@ static void build_mesh_leaf_node(const Span<int> corner_verts,
const Span<int> prim_indices = node->prim_indices;
/* reserve size is rough guess */
blender::Map<int, int> map;
Map<int, int> map;
map.reserve(prim_indices.size());
node->face_vert_indices.reinitialize(prim_indices.size());
@ -287,7 +279,7 @@ static void build_mesh_leaf_node(const Span<int> corner_verts,
node->vert_indices.reinitialize(node->uniq_verts + node->face_verts);
/* Build the vertex list, unique verts first */
for (const blender::MapItem<int, int> item : map.items()) {
for (const MapItem<int, int> item : map.items()) {
int value = item.value;
if (value < 0) {
value = -value + node->uniq_verts - 1;
@ -319,7 +311,6 @@ static void update_vb(const Span<int> prim_indices,
int offset,
int count)
{
using namespace blender;
node->vb = prim_bounds[prim_indices[offset]];
for (const int i : IndexRange(offset, count).drop_front(1)) {
node->vb = bounds::merge(node->vb, prim_bounds[prim_indices[i]]);
@ -327,15 +318,14 @@ static void update_vb(const Span<int> prim_indices,
node->orig_vb = node->vb;
}
int BKE_pbvh_count_grid_quads(const BitGroupVector<> &grid_hidden,
const int *grid_indices,
int totgrid,
int gridsize,
int display_gridsize)
int count_grid_quads(const BitGroupVector<> &grid_hidden,
const Span<int> grid_indices,
int gridsize,
int display_gridsize)
{
const int gridarea = (gridsize - 1) * (gridsize - 1);
if (grid_hidden.is_empty()) {
return gridarea * totgrid;
return gridarea * grid_indices.size();
}
/* grid hidden layer is present, so have to check each grid for
@ -347,8 +337,8 @@ int BKE_pbvh_count_grid_quads(const BitGroupVector<> &grid_hidden,
int skip = depth2 < depth1 ? 1 << (depth1 - depth2 - 1) : 1;
int totquad = 0;
for (int i = 0; i < totgrid; i++) {
const blender::BoundedBitSpan gh = grid_hidden[grid_indices[i]];
for (const int grid : grid_indices) {
const blender::BoundedBitSpan gh = grid_hidden[grid];
/* grid hidden are present, have to check each element */
for (int y = 0; y < gridsize - skip; y += skip) {
for (int x = 0; x < gridsize - skip; x += skip) {
@ -364,11 +354,10 @@ int BKE_pbvh_count_grid_quads(const BitGroupVector<> &grid_hidden,
static void build_grid_leaf_node(PBVH *pbvh, PBVHNode *node)
{
int totquads = BKE_pbvh_count_grid_quads(pbvh->subdiv_ccg->grid_hidden,
node->prim_indices.data(),
node->prim_indices.size(),
pbvh->gridkey.grid_size,
pbvh->gridkey.grid_size);
int totquads = count_grid_quads(pbvh->subdiv_ccg->grid_hidden,
node->prim_indices,
pbvh->gridkey.grid_size,
pbvh->gridkey.grid_size);
BKE_pbvh_node_fully_hidden_set(node, (totquads == 0));
BKE_pbvh_node_mark_rebuild_draw(node);
}
@ -499,7 +488,6 @@ static void build_sub(PBVH *pbvh,
int *prim_scratch,
int depth)
{
using namespace blender;
const Span<int> prim_to_face_map = pbvh->header.type == PBVH_FACES ?
looptri_faces :
pbvh->subdiv_ccg->grid_to_face_map;
@ -536,7 +524,7 @@ static void build_sub(PBVH *pbvh,
/* Add two child nodes */
pbvh->nodes[node_index].children_offset = pbvh->nodes.size();
pbvh_grow_nodes(pbvh, pbvh->nodes.size() + 2);
pbvh->nodes.resize(pbvh->nodes.size() + 2);
/* Update parent node bounding box */
update_vb(pbvh->prim_indices, &pbvh->nodes[node_index], prim_bounds, offset, count);
@ -629,7 +617,7 @@ static void pbvh_build(PBVH *pbvh,
pbvh->nodes.clear_and_shrink();
pbvh->prim_indices.reinitialize(totprim);
blender::array_utils::fill_index_range<int>(pbvh->prim_indices);
array_utils::fill_index_range<int>(pbvh->prim_indices);
}
pbvh->nodes.resize(1);
@ -718,7 +706,7 @@ static void pbvh_validate_node_prims(PBVH *pbvh, const Span<int> looptri_faces)
}
#endif
void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
void update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
{
BLI_assert(pbvh->header.type == PBVH_FACES);
pbvh->faces = mesh->faces();
@ -733,24 +721,24 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh)
}
}
void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh)
PBVH *build_mesh(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
std::unique_ptr<PBVH> pbvh = std::make_unique<PBVH>();
pbvh->header.type = PBVH_FACES;
const int totvert = mesh->totvert;
const int looptris_num = poly_to_tri_count(mesh->faces_num, mesh->totloop);
MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
const blender::OffsetIndices<int> faces = mesh->faces();
const OffsetIndices<int> faces = mesh->faces();
const Span<int> corner_verts = mesh->corner_verts();
pbvh->looptris.reinitialize(looptris_num);
blender::bke::mesh::looptris_calc(vert_positions, faces, corner_verts, pbvh->looptris);
mesh::looptris_calc(vert_positions, faces, corner_verts, pbvh->looptris);
const Span<MLoopTri> looptris = pbvh->looptris;
pbvh->mesh = mesh;
pbvh->header.type = PBVH_FACES;
BKE_pbvh_update_mesh_pointers(pbvh, mesh);
update_mesh_pointers(pbvh.get(), mesh);
const Span<int> looptri_faces = pbvh->looptri_faces;
Array<bool> vert_bitmap(totvert, false);
@ -793,7 +781,7 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh)
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", ATTR_DOMAIN_FACE);
const VArraySpan material_index = *attributes.lookup<int>("material_index", ATTR_DOMAIN_FACE);
const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", ATTR_DOMAIN_FACE);
pbvh_build(pbvh,
pbvh_build(pbvh.get(),
corner_verts,
looptris,
looptri_faces,
@ -810,37 +798,38 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, Mesh *mesh)
#endif
}
BKE_pbvh_update_active_vcol(pbvh, mesh);
BKE_pbvh_update_active_vcol(pbvh.get(), mesh);
#ifdef VALIDATE_UNIQUE_NODE_FACES
pbvh_validate_node_prims(pbvh);
#endif
return pbvh.release();
}
void BKE_pbvh_build_grids(PBVH *pbvh, const CCGKey *key, Mesh *mesh, SubdivCCG *subdiv_ccg)
PBVH *build_grids(const CCGKey *key, Mesh *mesh, SubdivCCG *subdiv_ccg)
{
using namespace blender;
using namespace blender::bke;
const int gridsize = key->grid_size;
const Span<CCGElem *> grids = subdiv_ccg->grids;
std::unique_ptr<PBVH> pbvh = std::make_unique<PBVH>();
pbvh->header.type = PBVH_GRIDS;
pbvh->gridkey = *key;
pbvh->subdiv_ccg = subdiv_ccg;
pbvh->faces_num = mesh->faces_num;
/* Find maximum number of grids per face. */
int max_grids = 1;
const blender::OffsetIndices faces = mesh->faces();
const OffsetIndices faces = mesh->faces();
for (const int i : faces.index_range()) {
max_grids = max_ii(max_grids, faces[i].size());
}
const Span<CCGElem *> grids = subdiv_ccg->grids;
/* Ensure leaf limit is at least 4 so there's room
* to split at original face boundaries.
* Fixes #102209.
*/
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (gridsize * gridsize), max_grids);
pbvh->leaf_limit = max_ii(LEAF_LIMIT / (key->grid_area), max_grids);
/* We also need the base mesh for PBVH draw. */
pbvh->mesh = mesh;
@ -871,8 +860,17 @@ void BKE_pbvh_build_grids(PBVH *pbvh, const CCGKey *key, Mesh *mesh, SubdivCCG *
const AttributeAccessor attributes = mesh->attributes();
const VArraySpan material_index = *attributes.lookup<int>("material_index", ATTR_DOMAIN_FACE);
const VArraySpan sharp_face = *attributes.lookup<bool>("sharp_face", ATTR_DOMAIN_FACE);
pbvh_build(
pbvh, {}, {}, {}, {}, material_index, sharp_face, {}, &cb, prim_bounds, grids.size());
pbvh_build(pbvh.get(),
{},
{},
{},
{},
material_index,
sharp_face,
{},
&cb,
prim_bounds,
grids.size());
#ifdef TEST_PBVH_FACE_SPLIT
test_face_boundaries(pbvh);
@ -882,20 +880,11 @@ void BKE_pbvh_build_grids(PBVH *pbvh, const CCGKey *key, Mesh *mesh, SubdivCCG *
#ifdef VALIDATE_UNIQUE_NODE_FACES
pbvh_validate_node_prims(pbvh);
#endif
return pbvh.release();
}
PBVH *BKE_pbvh_new(PBVHType type)
{
PBVH *pbvh = MEM_new<PBVH>(__func__);
pbvh->draw_cache_invalid = true;
pbvh->header.type = type;
/* Initialize this to true, instead of waiting for a draw engine
* to set it. Prevents a crash in draw manager instancing code.
*/
pbvh->is_drawing = true;
return pbvh;
}
} // namespace blender::bke::pbvh
void BKE_pbvh_free(PBVH *pbvh)
{
@ -913,7 +902,7 @@ void BKE_pbvh_free(PBVH *pbvh)
pbvh_pixels_free(pbvh);
MEM_delete(pbvh);
delete pbvh;
}
static void pbvh_iter_begin(PBVHIter *iter, PBVH *pbvh, blender::FunctionRef<bool(PBVHNode &)> scb)

View File

@ -291,7 +291,7 @@ static void pbvh_bmesh_node_split(PBVH *pbvh,
/* Add two new child nodes. */
const int children = pbvh->nodes.size();
n->children_offset = children;
pbvh_grow_nodes(pbvh, pbvh->nodes.size() + 2);
pbvh->nodes.resize(pbvh->nodes.size() + 2);
/* Array reallocated, update current node pointer. */
n = &pbvh->nodes[node_index];
@ -2078,7 +2078,7 @@ static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *pbvh,
int children_offset = pbvh->nodes.size();
n->children_offset = children_offset;
pbvh_grow_nodes(pbvh, pbvh->nodes.size() + 2);
pbvh->nodes.resize(pbvh->nodes.size() + 2);
pbvh_bmesh_create_nodes_fast_recursive(
pbvh, nodeinfo, face_bounds, node->child1, children_offset);
pbvh_bmesh_create_nodes_fast_recursive(
@ -2158,16 +2158,19 @@ void BKE_pbvh_update_bmesh_offsets(PBVH *pbvh, int cd_vert_node_offset, int cd_f
pbvh->cd_face_node_offset = cd_face_node_offset;
}
void BKE_pbvh_build_bmesh(PBVH *pbvh,
BMesh *bm,
BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset)
namespace blender::bke::pbvh {
PBVH *build_bmesh(BMesh *bm,
BMLog *log,
const int cd_vert_node_offset,
const int cd_face_node_offset)
{
using namespace blender;
std::unique_ptr<PBVH> pbvh = std::make_unique<PBVH>();
pbvh->header.type = PBVH_BMESH;
pbvh->header.bm = bm;
BKE_pbvh_bmesh_detail_size_set(pbvh, 0.75);
BKE_pbvh_bmesh_detail_size_set(pbvh.get(), 0.75);
pbvh->header.type = PBVH_BMESH;
pbvh->bm_log = log;
@ -2175,15 +2178,15 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
/* TODO: choose leaf limit better. */
pbvh->leaf_limit = 400;
BKE_pbvh_update_bmesh_offsets(pbvh, cd_vert_node_offset, cd_face_node_offset);
BKE_pbvh_update_bmesh_offsets(pbvh.get(), cd_vert_node_offset, cd_face_node_offset);
if (bm->totface == 0) {
return;
return {};
}
/* bounding box array of all faces, no need to recalculate every time. */
blender::Array<Bounds<float3>> face_bounds(bm->totface);
blender::Array<BMFace *> nodeinfo(bm->totface);
Array<Bounds<float3>> face_bounds(bm->totface);
Array<BMFace *> nodeinfo(bm->totface);
MemArena *arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "fast PBVH node storage");
BMIter iter;
@ -2216,7 +2219,7 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
rootnode.totface = bm->totface;
/* Start recursion, assign faces to nodes accordingly. */
pbvh_bmesh_node_limit_ensure_fast(pbvh, nodeinfo, face_bounds, &rootnode, arena);
pbvh_bmesh_node_limit_ensure_fast(pbvh.get(), nodeinfo, face_bounds, &rootnode, arena);
/* We now have all faces assigned to a node,
* next we need to assign those to the gsets of the nodes. */
@ -2225,11 +2228,14 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
pbvh->nodes.append({});
/* Take root node and visit and populate children recursively. */
pbvh_bmesh_create_nodes_fast_recursive(pbvh, nodeinfo, face_bounds, &rootnode, 0);
pbvh_bmesh_create_nodes_fast_recursive(pbvh.get(), nodeinfo, face_bounds, &rootnode, 0);
BLI_memarena_free(arena);
return pbvh.release();
}
} // namespace blender::bke::pbvh
bool BKE_pbvh_bmesh_update_topology(PBVH *pbvh,
PBVHTopologyUpdateMode mode,
const float center[3],

View File

@ -193,10 +193,13 @@ struct PBVH {
CustomDataLayer *color_layer;
eAttrDomain color_domain;
bool is_drawing;
/* Initialize this to true, instead of waiting for a draw engine
* to set it. Prevents a crash in draw manager instancing code.
* TODO: This is fragile, another solution should be found. */
bool is_drawing = true;
/* Used by DynTopo to invalidate the draw cache. */
bool draw_cache_invalid;
bool draw_cache_invalid = true;
PBVHGPUFormat *vbo_id;
@ -205,7 +208,6 @@ struct PBVH {
/* pbvh.cc */
void pbvh_grow_nodes(PBVH *bvh, int totnode);
bool ray_face_intersection_quad(const float ray_start[3],
IsectRayPrecalc *isect_precalc,
const float t0[3],

View File

@ -285,7 +285,7 @@ static void split_flush_final_nodes(SplitQueueData *tdata)
if (!newsplit->parent->children_offset) {
newsplit->parent->children_offset = pbvh->nodes.size();
pbvh_grow_nodes(pbvh, pbvh->nodes.size() + 2);
pbvh->nodes.resize(pbvh->nodes.size() + 2);
newsplit->source_index = newsplit->parent->children_offset;
}
else {

View File

@ -351,11 +351,10 @@ struct PBVHBatches {
break;
}
case PBVH_GRIDS: {
count = BKE_pbvh_count_grid_quads(args.subdiv_ccg->grid_hidden,
args.grid_indices.data(),
args.grid_indices.size(),
args.ccg_key.grid_size,
args.ccg_key.grid_size);
count = bke::pbvh::count_grid_quads(args.subdiv_ccg->grid_hidden,
args.grid_indices,
args.ccg_key.grid_size,
args.ccg_key.grid_size);
break;
}
@ -1163,8 +1162,8 @@ struct PBVHBatches {
const CCGKey *key = &args.ccg_key;
uint visible_quad_len = BKE_pbvh_count_grid_quads(
grid_hidden, args.grid_indices.data(), totgrid, key->grid_size, display_gridsize);
uint visible_quad_len = bke::pbvh::count_grid_quads(
grid_hidden, args.grid_indices, key->grid_size, display_gridsize);
GPU_indexbuf_init(&elb, GPU_PRIM_TRIS, 2 * visible_quad_len, INT_MAX);
GPU_indexbuf_init(&elb_lines,

View File

@ -1886,4 +1886,3 @@ int SCULPT_vertex_island_get(const SculptSession *ss, PBVHVertRef vertex);
/* Make SCULPT_ alias to a few blenkernel sculpt methods. */
#define SCULPT_vertex_attr_get BKE_sculpt_vertex_attr_get
#define SCULPT_face_attr_get BKE_sculpt_face_attr_get

View File

@ -159,7 +159,6 @@ struct SculptUndoStep {
};
static UndoSculpt *get_nodes();
static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b);
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr);
static UndoSculpt *sculpt_undosys_step_get_nodes(UndoStep *us_p);
@ -1597,11 +1596,6 @@ Node *push_node(Object *ob, PBVHNode *node, Type type)
return unode;
}
static bool sculpt_attribute_ref_equals(SculptAttrRef *a, SculptAttrRef *b)
{
return a->domain == b->domain && a->type == b->type && STREQ(a->name, b->name);
}
static void sculpt_save_active_attribute(Object *ob, SculptAttrRef *attr)
{
Mesh *mesh = BKE_object_get_original_mesh(ob);