[Bf-blender-cvs] [e96a809a68e] master: PBVH Pixel extractor.

Jeroen Bakker noreply at git.blender.org
Fri Apr 15 16:40:02 CEST 2022


Commit: e96a809a68ef40225d5eddfd790644538e171a8d
Author: Jeroen Bakker
Date:   Fri Apr 15 16:39:50 2022 +0200
Branches: master
https://developer.blender.org/rBe96a809a68ef40225d5eddfd790644538e171a8d

PBVH Pixel extractor.

This patch contains an initial pixel extractor for PBVH and an initial paint brush implementation.
PBVH is an accelleration structure blender uses internally to speed up 3d painting operations.
At this moment it is extensively used by sculpt, vertex painting and weight painting.

For the 3d texturing brush we will be using the PBVH for texture painting.
Currently PBVH is organized to work on geometry (vertices, polygons and triangles).
For texture painting this should be extended it to use pixels.

{F12995467}

Screen recording has been done on a Mac Mini with a 6 core 3.3 GHZ Intel processor.

# Scope

This patch only contains an extending uv seams to fix uv seams. This is not actually we want, but was easy to add
to make the brush usable.

Pixels are places in the PBVH_Leaf nodes. We want to introduce a special node for pixels, but that will be done
in a separate patch to keep the code review small. This reduces the painting performance when using
low and medium poly assets.

In workbench textures aren't forced to be shown. For now use Material/Rendered view.

# Rasterization process

The rasterization process will generate the pixel information for a leaf node. In the future those
leaf nodes will be split up into multiple leaf nodes to increase the performance when there
isn't enough geometry. For this patch this was left out of scope.

In order to do so every polygon should be uniquely assigned to a leaf node.

For each leaf node
   for each polygon
     If polygon not assigned
       assign polygon to node.

Polygons are to complicated to be used directly we have to split the polygons into triangles.

For each leaf node
  for each polygon
    extract triangles from polygon.

The list of triangles can be stored inside the leaf node. The list of polygons aren't needed anymore.
Each triangle has:

    poly_index.
    vert_indices
    delta barycentric coordinate between x steps.

Each triangle is rasterized in rows. Sequential pixels (in uv space) are stored in a single structure.

    image position
    barycentric coordinate of the first pixel
    number of pixels
    triangle index inside the leaf node.

During the performed experiments we used a fairly simple rasterization process by
finding the UV bounds of an triangle and calculate the barycentric coordinates per
pixel inside the bounds. Even for complex models and huge images this process is
normally finished within 0.5 second. It could be that we want to change this algorithm
to reduce hickups when nodes are initialized during a stroke.

Reviewed By: brecht

Maniphest Tasks: T96710

Differential Revision: https://developer.blender.org/D14504

===================================================================

M	source/blender/blenkernel/BKE_paint.h
M	source/blender/blenkernel/BKE_pbvh.h
A	source/blender/blenkernel/BKE_pbvh_pixels.hh
M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/material.c
M	source/blender/blenkernel/intern/paint.c
M	source/blender/blenkernel/intern/paint_canvas.cc
M	source/blender/blenkernel/intern/pbvh.c
M	source/blender/blenkernel/intern/pbvh_intern.h
A	source/blender/blenkernel/intern/pbvh_pixels.cc
M	source/blender/editors/include/ED_sculpt.h
M	source/blender/editors/sculpt_paint/CMakeLists.txt
M	source/blender/editors/sculpt_paint/sculpt.c
M	source/blender/editors/sculpt_paint/sculpt_intern.h
M	source/blender/editors/sculpt_paint/sculpt_paint_color.c
A	source/blender/editors/sculpt_paint/sculpt_paint_image.cc
M	source/blender/makesdna/DNA_material_types.h
M	source/blender/makesdna/DNA_scene_types.h

===================================================================

diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h
index db773d34cdc..4ae37095411 100644
--- a/source/blender/blenkernel/BKE_paint.h
+++ b/source/blender/blenkernel/BKE_paint.h
@@ -30,7 +30,9 @@ struct EdgeSet;
 struct EnumPropertyItem;
 struct GHash;
 struct GridPaintMask;
+struct Image;
 struct ImagePool;
+struct ImageUser;
 struct ListBase;
 struct MLoop;
 struct MLoopTri;
@@ -650,6 +652,11 @@ typedef struct SculptSession {
    */
   bool sticky_shading_color;
 
+  /**
+   * Last used painting canvas key.
+   */
+  char *last_paint_canvas_key;
+
 } SculptSession;
 
 void BKE_sculptsession_free(struct Object *ob);
@@ -727,8 +734,16 @@ enum {
 };
 
 /* paint_canvas.cc */
-struct Image *BKE_paint_canvas_image_get(const struct PaintModeSettings *settings,
-                                         struct Object *ob);
+/**
+ * Create a key that can be used to compare with previous ones to identify changes.
+ * The resulting 'string' is owned by the caller.
+ */
+char *BKE_paint_canvas_key_get(struct PaintModeSettings *settings, struct Object *ob);
+
+bool BKE_paint_canvas_image_get(struct PaintModeSettings *settings,
+                                struct Object *ob,
+                                struct Image **r_image,
+                                struct ImageUser **r_image_user);
 int BKE_paint_canvas_uvmap_layer_index_get(const struct PaintModeSettings *settings,
                                            struct Object *ob);
 
diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 775847f27f8..bb918fcfdcb 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -31,10 +31,13 @@ struct MLoopTri;
 struct MPoly;
 struct MVert;
 struct Mesh;
+struct MeshElemMap;
 struct PBVH;
 struct PBVHNode;
 struct SubdivCCG;
 struct TaskParallelSettings;
+struct Image;
+struct ImageUser;
 struct MeshElemMap;
 
 typedef struct PBVH PBVH;
@@ -48,6 +51,15 @@ typedef struct {
   float (*color)[4];
 } PBVHColorBufferNode;
 
+typedef struct PBVHPixelsNode {
+  /**
+   * Contains triangle/pixel data used during texture painting.
+   *
+   * Contains #blender::bke::pbvh::pixels::NodeData.
+   */
+  void *node_data;
+} PBVHPixelsNode;
+
 typedef enum {
   PBVH_Leaf = 1 << 0,
 
@@ -66,6 +78,8 @@ typedef enum {
 
   PBVH_UpdateTopology = 1 << 13,
   PBVH_UpdateColor = 1 << 14,
+  PBVH_RebuildPixels = 1 << 15,
+
 } PBVHNodeFlags;
 
 typedef struct PBVHFrustumPlanes {
@@ -127,6 +141,12 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
                           struct BMLog *log,
                           int cd_vert_node_offset,
                           int cd_face_node_offset);
+
+void BKE_pbvh_build_pixels(PBVH *pbvh,
+                           const struct MLoop *mloop,
+                           struct CustomData *ldata,
+                           struct Image *image,
+                           struct ImageUser *image_user);
 void BKE_pbvh_free(PBVH *pbvh);
 
 /* Hierarchical Search in the BVH, two methods:
@@ -287,6 +307,7 @@ bool BKE_pbvh_node_fully_masked_get(PBVHNode *node);
 void BKE_pbvh_node_fully_unmasked_set(PBVHNode *node, int fully_masked);
 bool BKE_pbvh_node_fully_unmasked_get(PBVHNode *node);
 
+void BKE_pbvh_mark_rebuild_pixels(PBVH *pbvh);
 void BKE_pbvh_vert_mark_update(PBVH *pbvh, int index);
 
 void BKE_pbvh_node_get_grids(PBVH *pbvh,
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
new file mode 100644
index 00000000000..35eb340d0a1
--- /dev/null
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -0,0 +1,184 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#pragma once
+
+#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_rect.h"
+#include "BLI_vector.hh"
+
+#include "DNA_image_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_image.h"
+#include "BKE_image_wrappers.hh"
+
+#include "IMB_imbuf_types.h"
+
+namespace blender::bke::pbvh::pixels {
+
+struct TrianglePaintInput {
+  int3 vert_indices;
+  /**
+   * Delta barycentric coordinates between 2 neighbouring UV's in the U direction.
+   *
+   * Only the first two coordinates are stored. The third should be recalculated
+   */
+  float2 delta_barycentric_coord_u;
+
+  /**
+   * Initially only the vert indices are known.
+   *
+   * delta_barycentric_coord_u is initialized in a later stage as it requires image tile
+   * dimensions.
+   */
+  TrianglePaintInput(const int3 vert_indices)
+      : vert_indices(vert_indices), delta_barycentric_coord_u(0.0f, 0.0f)
+  {
+  }
+};
+
+/**
+ * Data shared between pixels that belong to the same triangle.
+ *
+ * Data is stored as a list of structs, grouped by usage to improve performance (improves CPU
+ * cache prefetching).
+ */
+struct Triangles {
+  /** Data accessed by the inner loop of the painting brush. */
+  Vector<TrianglePaintInput> paint_input;
+
+ public:
+  void append(const int3 vert_indices)
+  {
+    this->paint_input.append(TrianglePaintInput(vert_indices));
+  }
+
+  TrianglePaintInput &get_paint_input(const int index)
+  {
+    return paint_input[index];
+  }
+
+  const TrianglePaintInput &get_paint_input(const int index) const
+  {
+    return paint_input[index];
+  }
+
+  void clear()
+  {
+    paint_input.clear();
+  }
+
+  uint64_t size() const
+  {
+    return paint_input.size();
+  }
+
+  uint64_t mem_size() const
+  {
+    return paint_input.size() * sizeof(TrianglePaintInput);
+  }
+};
+
+/**
+ * Encode sequential pixels to reduce memory footprint.
+ */
+struct PackedPixelRow {
+  /** Barycentric coordinate of the first pixel. */
+  float2 start_barycentric_coord;
+  /** Image coordinate starting of the first pixel. */
+  ushort2 start_image_coordinate;
+  /** Number of sequential pixels encoded in this package. */
+  ushort num_pixels;
+  /** Reference to the pbvh triangle index. */
+  ushort triangle_index;
+};
+
+/**
+ * Node pixel data containing the pixels for a single UDIM tile.
+ */
+struct UDIMTilePixels {
+  /** UDIM Tile number. */
+  short tile_number;
+
+  struct {
+    bool dirty : 1;
+  } flags;
+
+  /* Dirty region of the tile in image space. */
+  rcti dirty_region;
+
+  Vector<PackedPixelRow> pixel_rows;
+
+  UDIMTilePixels()
+  {
+    flags.dirty = false;
+    BLI_rcti_init_minmax(&dirty_region);
+  }
+
+  void mark_dirty(const PackedPixelRow &pixel_row)
+  {
+    int2 start_image_coord(pixel_row.start_image_coordinate.x, pixel_row.start_image_coordinate.y);
+    BLI_rcti_do_minmax_v(&dirty_region, start_image_coord);
+    BLI_rcti_do_minmax_v(&dirty_region, start_image_coord + int2(pixel_row.num_pixels + 1, 0));
+    flags.dirty = true;
+  }
+
+  void clear_dirty()
+  {
+    BLI_rcti_init_minmax(&dirty_region);
+    flags.dirty = false;
+  }
+};
+
+struct NodeData {
+  struct {
+    bool dirty : 1;
+  } flags;
+
+  Vector<UDIMTilePixels> tiles;
+  Triangles triangles;
+
+  NodeData()
+  {
+    flags.dirty = false;
+  }
+
+  UDIMTilePixels *find_tile_data(const image::ImageTileWrapper &image_tile)
+  {
+    for (UDIMTilePixels &tile : tiles) {
+      if (tile.tile_number == image_tile.get_tile_number()) {
+        return &tile;
+      }
+    }
+    return nullptr;
+  }
+
+  void mark_region(Image &image, const image::ImageTileWrapper &image_tile, ImBuf &image_buffer)
+  {
+    UDIMTilePixels *tile = find_tile_data(image_tile);
+    if (tile && tile->flags.dirty) {
+      BKE_image_partial_update_mark_region(
+          &image, image_tile.image_tile, &image_buffer, &tile->dirty_region);
+      tile->clear_dirty();
+    }
+  }
+
+  void clear_data()
+  {
+    tiles.clear();
+    triangles.clear();
+  }
+
+  static void free_func(void *instance)
+  {
+    NodeData *node_data = static_cast<NodeData *>(instance);
+    MEM_delete(node_data);
+  }
+};
+
+NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node);
+void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user);
+
+}  // namespace blender::bke::pbvh::pixels
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index ce4131a0627..710e2900d78 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -244,6 +244,7 @@ set(SRC
   intern/pbvh.cc
   intern/pbvh.c
   intern/pbvh_bmesh.c
+  intern/pbvh_pixels.cc
   intern/pointcache.c
   intern/pointcloud.cc
   intern/preferences.c
diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c
index bc569956f66..4caaf314888 100644
--- a/source/blender/blenkernel/intern/material.c
+++ b/source/blender/blenkernel/intern/material.c
@@ -1423,13 +1423,15 @@ static bool fill_texpaint_slots_cb(bNode *node, void *userdata)
     case SH_NODE_TEX_IMAGE: {
       TexPaintSlot *slot = &ma->texpaintslot[index];
       slot->ima = (Image *)node->id;
-      slot->interp = ((NodeTexImage *)node->storage)->interpolation;
+      NodeTexImage *storage = (NodeTexImage *)node->storage;
+      slot->interp = storage->interpolation;
+      slot->image_user = &storage->iuser;
       /* for new renderer, we need to traverse the treeback in search of a UV node */
       bNode *uvnode = nodetree_uv_node_recursive(node);
 
       if (uvnode) {
-        NodeShaderUVMap *storage = (NodeShaderUVMap *)uvnode->storage;
-        slot->uvname = storage->uv_map;
+        NodeShaderUVMap *uv_storage = (NodeShaderUVMap *)uvnode->storage;
+        slot->uvname = uv_storage->uv_map;
         /* set a value to index so UI knows that we have a valid pointer for the mesh */
         slot->valid = true;
       }
diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c
index eb3f47760fc..c0195e5abc8 100644
--- a/source/blender/blenkernel/intern/paint.c
+++ b/source/blender/blenkernel/intern/paint.c
@@ -1511,6 +1511,8 @@ void BKE_sculptsession_free(Object *ob)
 
     BKE_sculptsession_free_vwpaint_data(ob->sculpt);
 
+    MEM_SAFE_FREE(ss->last_paint_canvas_key);
+
     MEM_freeN(ss);
 
     ob->sculpt = NULL;
@@ -1771,6 +1773,24 @@ static void sculpt_update_object(Depsgraph *depsgraph,
     }
   }


@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list