[Bf-blender-cvs] [b6b6e47e1db] master: Sculpt: PBVH node splitting for texture paint

Joseph Eagar noreply at git.blender.org
Mon Jan 23 19:45:18 CET 2023


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(&region);
       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. @@



More information about the Bf-blender-cvs mailing list