Commit: b6b6e47e1dbc2e4a175fb1a257e50dc0f51b2fc6 Author: Joseph Eagar Date: Mon Jan 23 10:29:40 2023 -0800 Branches: master https://developer.blender.org/rBb6b6e47e1dbc2e4a175fb1a257e50dc0f51b2fc6
Sculpt: PBVH node splitting for texture paint `PBVH_Leaf` nodes are now split into a new `PBVH_TexLeaf` node type when using the paint brush. These nodes are split by image pixels, not triangles. This greatly increases performance when working with large textures on low-poly meshes. Reviewed By: Jeroen Bakker Differential Revision: https://developer.blender.org/D14900 Ref: D14900 =================================================================== M source/blender/blenkernel/BKE_pbvh.h M source/blender/blenkernel/BKE_pbvh_pixels.hh M source/blender/blenkernel/intern/pbvh.c M source/blender/blenkernel/intern/pbvh_intern.h M source/blender/blenkernel/intern/pbvh_pixels.cc M source/blender/draw/engines/basic/basic_engine.c M source/blender/draw/engines/eevee/eevee_materials.c M source/blender/draw/intern/DRW_render.h M source/blender/draw/intern/draw_manager_data.cc M source/blender/draw/intern/draw_shader_shared.h M source/blender/editors/sculpt_paint/sculpt.cc M source/blender/editors/sculpt_paint/sculpt_intern.h M source/blender/editors/sculpt_paint/sculpt_paint_color.c M source/blender/editors/sculpt_paint/sculpt_paint_image.cc M source/blender/editors/sculpt_paint/sculpt_undo.cc =================================================================== diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 5a63b9bb126..7153f05c0c3 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -163,7 +163,8 @@ typedef enum { PBVH_UpdateTopology = 1 << 13, PBVH_UpdateColor = 1 << 14, PBVH_RebuildPixels = 1 << 15, - PBVH_TopologyUpdated = 1 << 16, /* Used internally by pbvh_bmesh.c */ + PBVH_TexLeaf = 1 << 16, + PBVH_TopologyUpdated = 1 << 17, /* Used internally by pbvh_bmesh.c */ } PBVHNodeFlags; @@ -337,7 +338,12 @@ void BKE_pbvh_search_callback(PBVH *pbvh, void BKE_pbvh_search_gather( PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***array, int *tot); - +void BKE_pbvh_search_gather_ex(PBVH *pbvh, + BKE_pbvh_SearchCallback scb, + void *search_data, + PBVHNode ***r_array, + int *r_tot, + PBVHNodeFlags leaf_flag); /* Ray-cast * the hit callback is called for all leaf nodes intersecting the ray; * it's up to the callback to find the primitive within the leaves that is diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh index b6e006805ec..31dbad0abe1 100644 --- a/source/blender/blenkernel/BKE_pbvh_pixels.hh +++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh @@ -200,6 +200,10 @@ struct NodeData { { undo_regions.clear(); for (UDIMTilePixels &tile : tiles) { + if (tile.pixel_rows.size() == 0) { + continue; + } + rcti region; BLI_rcti_init_minmax(®ion); for (PackedPixelRow &pixel_row : tile.pixel_rows) { diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index d18ef62c20c..e9461350448 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -1020,7 +1020,9 @@ void BKE_pbvh_free(PBVH *pbvh) if (node->bm_other_verts) { BLI_gset_free(node->bm_other_verts, NULL); } + } + if (node->flag & (PBVH_Leaf | PBVH_TexLeaf)) { pbvh_node_pixels_free(node); } } @@ -1094,7 +1096,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting) iter->stacksize++; } -static PBVHNode *pbvh_iter_next(PBVHIter *iter) +static PBVHNode *pbvh_iter_next(PBVHIter *iter, PBVHNodeFlags leaf_flag) { /* purpose here is to traverse tree, visiting child nodes before their * parents, this order is necessary for e.g. computing bounding boxes */ @@ -1121,7 +1123,7 @@ static PBVHNode *pbvh_iter_next(PBVHIter *iter) continue; /* don't traverse, outside of search zone */ } - if (node->flag & PBVH_Leaf) { + if (node->flag & leaf_flag) { /* immediately hit leaf node */ return node; } @@ -1166,8 +1168,12 @@ static PBVHNode *pbvh_iter_next_occluded(PBVHIter *iter) return NULL; } -void BKE_pbvh_search_gather( - PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot) +void BKE_pbvh_search_gather_ex(PBVH *pbvh, + BKE_pbvh_SearchCallback scb, + void *search_data, + PBVHNode ***r_array, + int *r_tot, + PBVHNodeFlags leaf_flag) { PBVHIter iter; PBVHNode **array = NULL, *node; @@ -1175,8 +1181,8 @@ void BKE_pbvh_search_gather( pbvh_iter_begin(&iter, pbvh, scb, search_data); - while ((node = pbvh_iter_next(&iter))) { - if (node->flag & PBVH_Leaf) { + while ((node = pbvh_iter_next(&iter, leaf_flag))) { + if (node->flag & leaf_flag) { if (UNLIKELY(tot == space)) { /* resize array if needed */ space = (tot == 0) ? 32 : space * 2; @@ -1199,6 +1205,12 @@ void BKE_pbvh_search_gather( *r_tot = tot; } +void BKE_pbvh_search_gather( + PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, PBVHNode ***r_array, int *r_tot) +{ + BKE_pbvh_search_gather_ex(pbvh, scb, search_data, r_array, r_tot, PBVH_Leaf); +} + void BKE_pbvh_search_callback(PBVH *pbvh, BKE_pbvh_SearchCallback scb, void *search_data, @@ -1210,7 +1222,7 @@ void BKE_pbvh_search_callback(PBVH *pbvh, pbvh_iter_begin(&iter, pbvh, scb, search_data); - while ((node = pbvh_iter_next(&iter))) { + while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) { if (node->flag & PBVH_Leaf) { hcb(node, hit_data); } @@ -1946,7 +1958,7 @@ void BKE_pbvh_redraw_BB(PBVH *pbvh, float bb_min[3], float bb_max[3]) pbvh_iter_begin(&iter, pbvh, NULL, NULL); - while ((node = pbvh_iter_next(&iter))) { + while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) { if (node->flag & PBVH_UpdateRedraw) { BB_expand_with_bb(&bb, &node->vb); } @@ -1966,7 +1978,7 @@ void BKE_pbvh_get_grid_updates(PBVH *pbvh, bool clear, void ***r_gridfaces, int pbvh_iter_begin(&iter, pbvh, NULL, NULL); - while ((node = pbvh_iter_next(&iter))) { + while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) { if (node->flag & PBVH_UpdateNormals) { for (uint i = 0; i < node->totprim; i++) { void *face = pbvh->gridfaces[node->prim_indices[i]]; @@ -3147,9 +3159,24 @@ void BKE_pbvh_draw_debug_cb(PBVH *pbvh, PBVHNodeFlags flag), void *user_data) { + PBVHNodeFlags flag = PBVH_Leaf; + for (int a = 0; a < pbvh->totnode; a++) { PBVHNode *node = &pbvh->nodes[a]; + if (node->flag & PBVH_TexLeaf) { + flag = PBVH_TexLeaf; + break; + } + } + + for (int a = 0; a < pbvh->totnode; a++) { + PBVHNode *node = &pbvh->nodes[a]; + + if (!(node->flag & flag)) { + continue; + } + draw_fn(node, user_data, node->vb.bmin, node->vb.bmax, node->flag); } } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index d3db65137de..4666504e94f 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -150,6 +150,8 @@ struct PBVH { int faces_num; /* Do not use directly, use BKE_pbvh_num_faces. */ int leaf_limit; + int pixel_leaf_limit; + int depth_limit; /* Mesh data */ struct Mesh *mesh; diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc index b1d635f566e..ed87631ffe9 100644 --- a/source/blender/blenkernel/intern/pbvh_pixels.cc +++ b/source/blender/blenkernel/intern/pbvh_pixels.cc @@ -15,7 +15,9 @@ #include "BLI_math.h" #include "BLI_task.h" +#include "PIL_time.h" +#include "BKE_global.h" #include "BKE_image_wrappers.hh" #include "bmesh.h" @@ -25,12 +27,6 @@ namespace blender::bke::pbvh::pixels { -/** - * During debugging this check could be enabled. - * It will write to each image pixel that is covered by the PBVH. - */ -constexpr bool USE_WATERTIGHT_CHECK = false; - /** * Calculate the delta of two neighbor UV coordinates in the given image buffer. */ @@ -57,6 +53,315 @@ static float2 calc_barycentric_delta_x(const ImBuf *image_buffer, return calc_barycentric_delta(uvs, start_uv, end_uv); } +static int count_node_pixels(PBVHNode &node) +{ + if (!node.pixels.node_data) { + return 0; + } + + NodeData &data = BKE_pbvh_pixels_node_data_get(node); + + int totpixel = 0; + + for (UDIMTilePixels &tile : data.tiles) { + for (PackedPixelRow &row : tile.pixel_rows) { + totpixel += row.num_pixels; + } + } + + return totpixel; +} + +struct SplitQueueData { + ThreadQueue *new_nodes; + TaskPool *pool; + + PBVH *pbvh; + Mesh *mesh; + Image *image; + ImageUser *image_user; +}; + +struct SplitNodePair { + SplitNodePair *parent; + PBVHNode node; + int children_offset = 0; + int depth = 0; + int source_index = -1; + bool is_old = false; + SplitQueueData *tdata; + + SplitNodePair(SplitNodePair *node_parent = nullptr) : parent(node_parent) + { + memset(static_cast<void *>(&node), 0, sizeof(PBVHNode)); + } +}; + +static void split_thread_job(TaskPool *__restrict pool, void *taskdata); + +static void split_pixel_node(PBVH *pbvh, + SplitNodePair *split, + Mesh *mesh, + Image *image, + ImageUser *image_user, + SplitQueueData *tdata) +{ + BB cb; + PBVHNode *node = &split->node; + + cb = node->vb; + + if (count_node_pixels(*node) <= pbvh->pixel_leaf_limit || split->depth >= pbvh->depth_limit) { + BKE_pbvh_pixels_node_data_get(split->node).rebuild_undo_regions(); + return; + } + + /* Find widest axis and its midpoint */ + const int axis = BB_widest_axis(&cb); + const float mid = (cb.bmax[axis] + cb.bmin[axis]) * 0.5f; + + node->flag = (PBVHNodeFlags)((int)node->flag & (int)~PBVH_TexLeaf); + + SplitNodePair *split1 = MEM_new<SplitNodePair>("split_pixel_node split1", split); + SplitNodePair *split2 = MEM_new<SplitNodePair>("split_pixel_node split1", split); + + split1->depth = split->depth + 1; + split2->depth = split->depth + 1; + + PBVHNode *child1 = &split1->node; + PBVHNode *child2 = &split2->node; + + child1->flag = PBVH_TexLeaf; + child2->flag = PBVH_TexLeaf; + + child1->vb = cb; + child1->vb.bmax[axis] = mid; + + child2->vb = cb; + child2->vb.bmin[axis] = mid; + + NodeData &data = BKE_pbvh_pixels_node_data_get(split->node); + + NodeData *data1 = MEM_new<NodeData>(__func__); + NodeData *data2 = MEM_new<NodeData>(__func__); + child1->pixels.node_data = static_cast<void *>(data1); + child2->pixels.node_data = static_cast<void *>(data2); + + data1->uv_primitives = data.uv_primitives; + data2->uv_primitives = data.uv_primitives; + + data1->tiles.resize(data.tiles.size()); + data2->tiles.resize(data.tiles.size()); + + for (int i : IndexRange(data.tiles.size())) { + UDIMTilePixels &tile = data.tiles[i]; + UDIMTilePixels &tile1 = data1->tiles[i]; + UDIMTilePixels &tile2 = data2->tiles[i]; + + tile1.tile_number = t @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs