Refactor: Sculpt: Use static constructors for PBVH build

This commit is contained in:
Hans Goudey
2024-09-19 15:14:35 -04:00
parent c8ed2b695a
commit c2dd238ba1
4 changed files with 59 additions and 55 deletions

View File

@@ -199,12 +199,12 @@ class Tree {
friend Node;
Type type_;
public:
std::variant<Vector<MeshNode>, Vector<GridsNode>, Vector<BMeshNode>> nodes_;
/* Memory backing for Node.prim_indices. */
Array<int> prim_indices_;
public:
std::variant<Vector<MeshNode>, Vector<GridsNode>, Vector<BMeshNode>> nodes_;
/**
* If true, the bounds for the corresponding node index is out of date.
* \note Values are only meaningful for leaf nodes.
@@ -235,9 +235,19 @@ class Tree {
std::unique_ptr<DrawCache> draw_data;
public:
explicit Tree(Type type);
Tree(const Tree &other) = default;
Tree(Tree &&other) = default;
Tree &operator=(const Tree &other) = default;
Tree &operator=(Tree &&other) = default;
~Tree();
/** Build a BVH tree from base mesh triangles. */
static Tree from_mesh(const Mesh &mesh);
/** Build a BVH tree from grids geometry. */
static Tree from_grids(const Mesh &base_mesh, const SubdivCCG &subdiv_ccg);
/** Build a BVH tree from a triangle BMesh. */
static Tree from_bmesh(BMesh &bm);
int nodes_num() const;
template<typename NodeT> Span<NodeT> nodes() const;
template<typename NodeT> MutableSpan<NodeT> nodes();
@@ -272,6 +282,9 @@ class Tree {
* Tag nodes where generic attribute data has changed (not positions, masks, or face sets).
*/
void tag_attribute_changed(const IndexMask &node_mask, StringRef attribute_name);
private:
explicit Tree(Type type);
};
} // namespace blender::bke::pbvh
@@ -285,13 +298,6 @@ struct PBVHFrustumPlanes {
namespace blender::bke::pbvh {
/** Build a BVH tree from base mesh triangles. */
std::unique_ptr<Tree> build_mesh(const Mesh &mesh);
/** Build a BVH tree from grids geometry. */
std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv_ccg);
/** Build a BVH tree from a triangle BMesh. */
std::unique_ptr<Tree> build_bmesh(BMesh *bm);
void build_pixels(const Depsgraph &depsgraph, Object &object, Image &image, ImageUser &image_user);
/* Ray-cast

View File

@@ -2348,14 +2348,14 @@ static std::unique_ptr<pbvh::Tree> build_pbvh_for_dynamic_topology(Object *ob)
BM_data_layer_ensure_named(&bm, &bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
BM_data_layer_ensure_named(&bm, &bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
return pbvh::build_bmesh(&bm);
return std::make_unique<pbvh::Tree>(pbvh::Tree::from_bmesh(bm));
}
static std::unique_ptr<pbvh::Tree> build_pbvh_from_regular_mesh(Object *ob,
const Mesh *me_eval_deform)
{
const Mesh &mesh = *BKE_object_get_original_mesh(ob);
std::unique_ptr<pbvh::Tree> pbvh = pbvh::build_mesh(mesh);
std::unique_ptr<pbvh::Tree> pbvh = std::make_unique<pbvh::Tree>(pbvh::Tree::from_mesh(mesh));
const bool is_deformed = check_sculpt_object_deformed(ob, true);
if (is_deformed && me_eval_deform != nullptr) {
@@ -2370,7 +2370,7 @@ static std::unique_ptr<pbvh::Tree> build_pbvh_from_ccg(Object *ob, SubdivCCG &su
const Mesh &base_mesh = *BKE_mesh_from_object(ob);
BKE_sculpt_sync_face_visibility_to_grids(base_mesh, subdiv_ccg);
return pbvh::build_grids(base_mesh, subdiv_ccg);
return std::make_unique<pbvh::Tree>(pbvh::Tree::from_grids(base_mesh, subdiv_ccg));
}
} // namespace blender::bke

View File

@@ -227,12 +227,12 @@ inline Bounds<float3> calc_face_bounds(const Span<float3> vert_positions,
return bounds;
}
std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
Tree Tree::from_mesh(const Mesh &mesh)
{
#ifdef DEBUG_BUILD_TIME
SCOPED_TIMER_AVERAGED(__func__);
#endif
std::unique_ptr<Tree> pbvh = std::make_unique<Tree>(Type::Mesh);
Tree pbvh(Type::Mesh);
const Span<float3> vert_positions = mesh.vert_positions();
const OffsetIndices<int> faces = mesh.faces();
const Span<int> corner_verts = mesh.corner_verts();
@@ -264,25 +264,25 @@ std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
pbvh->prim_indices_.reinitialize(faces.size());
array_utils::fill_index_range<int>(pbvh->prim_indices_);
pbvh.prim_indices_.reinitialize(faces.size());
array_utils::fill_index_range<int>(pbvh.prim_indices_);
Vector<MeshNode> &nodes = std::get<Vector<MeshNode>>(pbvh->nodes_);
Vector<MeshNode> &nodes = std::get<Vector<MeshNode>>(pbvh.nodes_);
nodes.resize(1);
{
#ifdef DEBUG_BUILD_TIME
SCOPED_TIMER_AVERAGED("build_nodes_recursive_mesh");
#endif
build_nodes_recursive_mesh(
material_index, leaf_limit, 0, bounds, face_centers, 0, pbvh->prim_indices_, nodes);
material_index, leaf_limit, 0, bounds, face_centers, 0, pbvh.prim_indices_, nodes);
}
build_mesh_leaf_nodes(mesh.verts_num, faces, corner_verts, nodes);
pbvh->tag_positions_changed(nodes.index_range());
pbvh.tag_positions_changed(nodes.index_range());
update_bounds_mesh(vert_positions, *pbvh);
store_bounds_orig(*pbvh);
update_bounds_mesh(vert_positions, pbvh);
store_bounds_orig(pbvh);
if (!hide_vert.is_empty()) {
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
@@ -292,7 +292,7 @@ std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
});
}
update_mask_mesh(mesh, nodes.index_range(), *pbvh);
update_mask_mesh(mesh, nodes.index_range(), pbvh);
return pbvh;
}
@@ -382,13 +382,12 @@ static Bounds<float3> calc_face_grid_bounds(const OffsetIndices<int> faces,
return bounds;
}
std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv_ccg)
Tree Tree::from_grids(const Mesh &base_mesh, const SubdivCCG &subdiv_ccg)
{
#ifdef DEBUG_BUILD_TIME
SCOPED_TIMER_AVERAGED(__func__);
#endif
std::unique_ptr<Tree> pbvh = std::make_unique<Tree>(Type::Grids);
Tree pbvh(Type::Grids);
const OffsetIndices faces = base_mesh.faces();
if (faces.is_empty()) {
return pbvh;
@@ -424,7 +423,7 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
Array<int> face_indices(faces.size());
array_utils::fill_index_range<int>(face_indices);
Vector<GridsNode> &nodes = std::get<Vector<GridsNode>>(pbvh->nodes_);
Vector<GridsNode> &nodes = std::get<Vector<GridsNode>>(pbvh.nodes_);
nodes.resize(1);
{
#ifdef DEBUG_BUILD_TIME
@@ -435,12 +434,12 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
}
/* Convert face indices into grid indices. */
pbvh->prim_indices_.reinitialize(faces.total_size());
pbvh.prim_indices_.reinitialize(faces.total_size());
{
int offset = 0;
for (const int face : face_indices) {
for (const int corner : faces[face]) {
pbvh->prim_indices_[offset] = corner;
pbvh.prim_indices_[offset] = corner;
offset++;
}
}
@@ -458,14 +457,14 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
threading::parallel_for(nodes.index_range(), 512, [&](const IndexRange range) {
for (const int i : range) {
nodes[i].prim_indices_ = pbvh->prim_indices_.as_span().slice(node_grid_offsets[i]);
nodes[i].prim_indices_ = pbvh.prim_indices_.as_span().slice(node_grid_offsets[i]);
}
});
pbvh->tag_positions_changed(nodes.index_range());
pbvh.tag_positions_changed(nodes.index_range());
update_bounds_grids(key, positions, *pbvh);
store_bounds_orig(*pbvh);
update_bounds_grids(key, positions, pbvh);
store_bounds_orig(pbvh);
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
if (!grid_hidden.is_empty()) {
@@ -476,7 +475,7 @@ std::unique_ptr<Tree> build_grids(const Mesh &base_mesh, const SubdivCCG &subdiv
});
}
update_mask_grids(subdiv_ccg, nodes.index_range(), *pbvh);
update_mask_grids(subdiv_ccg, nodes.index_range(), pbvh);
return pbvh;
}

View File

@@ -2209,28 +2209,27 @@ static void pbvh_bmesh_create_nodes_fast_recursive(Vector<BMeshNode> &nodes,
/***************************** Public API *****************************/
std::unique_ptr<Tree> build_bmesh(BMesh *bm)
Tree Tree::from_bmesh(BMesh &bm)
{
std::unique_ptr<Tree> pbvh = std::make_unique<Tree>(Type::BMesh);
const int cd_vert_node_offset = CustomData_get_offset_named(
&bm->vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
const int cd_face_node_offset = CustomData_get_offset_named(
&bm->pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
if (bm->totface == 0) {
Tree pbvh(Type::BMesh);
if (bm.totface == 0) {
return pbvh;
}
const int cd_vert_node_offset = CustomData_get_offset_named(
&bm.vdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_vertex");
const int cd_face_node_offset = CustomData_get_offset_named(
&bm.pdata, CD_PROP_INT32, ".sculpt_dyntopo_node_id_face");
/* bounding box array of all faces, no need to recalculate every time. */
Array<Bounds<float3>> face_bounds(bm->totface);
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 Tree node storage");
BMIter iter;
BMFace *f;
int i;
BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
BM_ITER_MESH_INDEX (f, &iter, &bm, BM_FACES_OF_MESH, i) {
face_bounds[i] = negative_bounds();
BMLoop *l_first = BM_FACE_FIRST_LOOP(f);
@@ -2245,16 +2244,16 @@ std::unique_ptr<Tree> build_bmesh(BMesh *bm)
BM_ELEM_CD_SET_INT(f, cd_face_node_offset, DYNTOPO_NODE_NONE);
}
/* Likely this is already dirty. */
bm->elem_index_dirty |= BM_FACE;
bm.elem_index_dirty |= BM_FACE;
BMVert *v;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
BM_ITER_MESH (v, &iter, &bm, BM_VERTS_OF_MESH) {
BM_ELEM_CD_SET_INT(v, cd_vert_node_offset, DYNTOPO_NODE_NONE);
}
/* Set up root node. */
FastNodeBuildInfo rootnode = {0};
rootnode.totface = bm->totface;
rootnode.totface = bm.totface;
/* Start recursion, assign faces to nodes accordingly. */
pbvh_bmesh_node_limit_ensure_fast(nodeinfo, face_bounds, &rootnode, arena);
@@ -2264,14 +2263,14 @@ std::unique_ptr<Tree> build_bmesh(BMesh *bm)
/* Start with all faces in the root node. */
/* Take root node and visit and populate children recursively. */
Vector<BMeshNode> &nodes = std::get<Vector<BMeshNode>>(pbvh->nodes_);
Vector<BMeshNode> &nodes = std::get<Vector<BMeshNode>>(pbvh.nodes_);
nodes.resize(1);
pbvh_bmesh_create_nodes_fast_recursive(
nodes, cd_vert_node_offset, cd_face_node_offset, nodeinfo, face_bounds, &rootnode, 0);
pbvh->tag_positions_changed(nodes.index_range());
update_bounds_bmesh(*bm, *pbvh);
store_bounds_orig(*pbvh);
pbvh.tag_positions_changed(nodes.index_range());
update_bounds_bmesh(bm, pbvh);
store_bounds_orig(pbvh);
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
for (const int i : range) {
@@ -2285,7 +2284,7 @@ std::unique_ptr<Tree> build_bmesh(BMesh *bm)
}
});
update_mask_bmesh(*bm, nodes.index_range(), *pbvh);
update_mask_bmesh(bm, nodes.index_range(), pbvh);
BLI_memarena_free(arena);
return pbvh;