[Bf-blender-cvs] [0e4ec7d9d31] temp-T97352-3d-texturing-seam-bleeding: Seam bleeding.

Jeroen Bakker noreply at git.blender.org
Tue Apr 19 11:02:45 CEST 2022


Commit: 0e4ec7d9d319f63381b12b56b729568aa6441019
Author: Jeroen Bakker
Date:   Fri Apr 15 16:31:14 2022 +0200
Branches: temp-T97352-3d-texturing-seam-bleeding
https://developer.blender.org/rB0e4ec7d9d319f63381b12b56b729568aa6441019

Seam bleeding.

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

M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/BKE_pbvh_pixels.hh
M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/pbvh_pixels.cc
A	source/blender/blenkernel/intern/pbvh_pixels_seams.cc
M	source/blender/editors/sculpt_paint/sculpt.c

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

diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index bb918fcfdcb..978e52d8003 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -143,8 +143,7 @@ void BKE_pbvh_build_bmesh(PBVH *pbvh,
                           int cd_face_node_offset);
 
 void BKE_pbvh_build_pixels(PBVH *pbvh,
-                           const struct MLoop *mloop,
-                           struct CustomData *ldata,
+                           struct Mesh *mesh,
                            struct Image *image,
                            struct ImageUser *image_user);
 void BKE_pbvh_free(PBVH *pbvh);
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index 35eb340d0a1..4e37f13d916 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -181,4 +181,7 @@ struct NodeData {
 NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node);
 void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user);
 
+void BKE_pbvh_pixels_rebuild_seams(
+    PBVH *pbvh, Mesh *me, Image *image, ImageUser *image_user, int cd_loop_uv_offset);
+
 }  // namespace blender::bke::pbvh::pixels
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0444fd33302..1dd270ab591 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -245,6 +245,7 @@ set(SRC
   intern/pbvh.c
   intern/pbvh_bmesh.c
   intern/pbvh_pixels.cc
+  intern/pbvh_pixels_seams.cc
   intern/pointcache.c
   intern/pointcloud.cc
   intern/preferences.c
diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc
index d8dd2f4b382..a568a7ae08c 100644
--- a/source/blender/blenkernel/intern/pbvh_pixels.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels.cc
@@ -274,8 +274,7 @@ static void apply_watertight_check(PBVH *pbvh, Image *image, ImageUser *image_us
 }
 
 static void update_pixels(PBVH *pbvh,
-                          const struct MLoop *mloop,
-                          struct CustomData *ldata,
+                          Mesh *mesh,
                           struct Image *image,
                           struct ImageUser *image_user)
 {
@@ -285,14 +284,15 @@ static void update_pixels(PBVH *pbvh,
     return;
   }
 
-  MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(ldata, CD_MLOOPUV));
+  MLoopUV *ldata_uv = static_cast<MLoopUV *>(CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
   if (ldata_uv == nullptr) {
     return;
   }
+  int cd_loop_uv_offset = CustomData_get_offset(&mesh->ldata, CD_MLOOPUV);
 
   for (PBVHNode *node : nodes_to_update) {
     NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
-    init_triangles(pbvh, node, node_data, mloop);
+    init_triangles(pbvh, node, node_data, mesh->mloop);
   }
 
   EncodePixelsUserData user_data;
@@ -308,6 +308,7 @@ static void update_pixels(PBVH *pbvh,
   if (USE_WATERTIGHT_CHECK) {
     apply_watertight_check(pbvh, image, image_user);
   }
+  BKE_pbvh_pixels_rebuild_seams(pbvh, mesh, image, image_user, cd_loop_uv_offset);
 
   /* Clear the UpdatePixels flag. */
   for (PBVHNode *node : nodes_to_update) {
@@ -376,12 +377,11 @@ extern "C" {
 using namespace blender::bke::pbvh::pixels;
 
 void BKE_pbvh_build_pixels(PBVH *pbvh,
-                           const struct MLoop *mloop,
-                           struct CustomData *ldata,
+                           struct Mesh *mesh,
                            struct Image *image,
                            struct ImageUser *image_user)
 {
-  update_pixels(pbvh, mloop, ldata, image, image_user);
+  update_pixels(pbvh, mesh, image, image_user);
 }
 
 void pbvh_pixels_free(PBVHNode *node)
diff --git a/source/blender/blenkernel/intern/pbvh_pixels_seams.cc b/source/blender/blenkernel/intern/pbvh_pixels_seams.cc
new file mode 100644
index 00000000000..c5a27c9e470
--- /dev/null
+++ b/source/blender/blenkernel/intern/pbvh_pixels_seams.cc
@@ -0,0 +1,238 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright 2022 Blender Foundation. All rights reserved. */
+
+#include "BKE_image.h"
+#include "BKE_image_wrappers.hh"
+#include "BKE_pbvh.h"
+#include "BKE_pbvh_pixels.hh"
+
+#include "IMB_imbuf_types.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_object_types.h"
+
+#include "BLI_vector.hh"
+
+#include "bmesh.h"
+
+#include "pbvh_intern.h"
+
+using BMLoopPair = std::pair<BMLoop *, BMLoop *>;
+
+namespace blender::bke::pbvh::pixels {
+
+/**
+ * Find loops that are connected in 3d space, but not in uv space. Or loops that don't have any
+ * connection at all.
+ *
+ * TODO better name would be to find loops that need uv seam fixes.
+ */
+Vector<BMLoopPair> find_connected_loops(BMesh *bm, int cd_loop_uv_offset)
+{
+  Vector<BMLoopPair> pairs;
+
+  BMEdge *e;
+  BMIter eiter;
+  BMLoop *l;
+  BMIter liter;
+  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+    bool first = true;
+    bool connection_found = false;
+    BMLoop *l_first;
+
+    BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
+      if (first) {
+        l_first = l;
+        first = false;
+      }
+      else {
+        connection_found = true;
+        if (!BM_loop_uv_share_edge_check(l_first, l, cd_loop_uv_offset)) {
+          // This is an edge which is connected in 3d space, but not connected in uv space so fixes
+          // are needed.
+
+          pairs.append(BMLoopPair(l_first, l));
+          break;
+        }
+      }
+    }
+    if (!connection_found) {
+      pairs.append(BMLoopPair(l_first, nullptr));
+    }
+  }
+  return pairs;
+}
+
+struct PixelInfo {
+  const static uint32_t IS_EXTRACTED = 1 << 0;
+  const static uint32_t IS_SEAM_FIX = 1 << 1;
+
+  uint32_t node = 0;
+  PixelInfo() = default;
+  PixelInfo(const PixelInfo &other) = default;
+
+  static PixelInfo from_node(int node_index)
+  {
+    PixelInfo result;
+    result.node = node_index << 2 | PixelInfo::IS_EXTRACTED;
+    return result;
+  }
+
+  uint32_t get_node_index() const
+  {
+    return node >> 2;
+  }
+
+  bool is_extracted() const
+  {
+    return (node & PixelInfo::IS_EXTRACTED) != 0;
+  }
+  bool is_seam_fix() const
+  {
+    return (node & PixelInfo::IS_SEAM_FIX) != 0;
+  }
+  bool is_empty_space() const
+  {
+    return !(is_extracted() || is_seam_fix());
+  }
+};
+
+struct Bitmap {
+  image::ImageTileWrapper image_tile;
+  Vector<PixelInfo> bitmap;
+  int2 resolution;
+
+  Bitmap(image::ImageTileWrapper &image_tile, Vector<PixelInfo> bitmap, int2 resolution)
+      : image_tile(image_tile), bitmap(bitmap), resolution(resolution)
+  {
+  }
+};
+
+struct Bitmaps {
+  Vector<Bitmap> bitmaps;
+};
+
+Vector<PixelInfo> create_tile_bitmap(const PBVH &pbvh,
+                                     image::ImageTileWrapper &image_tile,
+                                     ImBuf &image_buffer)
+{
+  Vector<PixelInfo> result(image_buffer.x * image_buffer.y);
+
+  for (int n = 0; n < pbvh.totnode; n++) {
+    PBVHNode *node = &pbvh.nodes[n];
+    if ((node->flag & PBVH_Leaf) == 0) {
+      continue;
+    }
+    NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data);
+    UDIMTilePixels *tile_node_data = node_data->find_tile_data(image_tile);
+    if (tile_node_data == nullptr) {
+      continue;
+    }
+
+    for (PackedPixelRow &pixel_row : tile_node_data->pixel_rows) {
+      int pixel_offset = pixel_row.start_image_coordinate.y * image_buffer.x +
+                         pixel_row.start_image_coordinate.x;
+      for (int x = 0; x < pixel_row.num_pixels; x++) {
+        result[pixel_offset] = PixelInfo::from_node(n);
+        pixel_offset += 1;
+      }
+    }
+  }
+  return result;
+}
+
+Bitmaps create_tile_bitmap(const PBVH &pbvh, Image &image, ImageUser &image_user)
+{
+  Bitmaps result;
+  ImageUser watertight = image_user;
+  LISTBASE_FOREACH (ImageTile *, tile_data, &image.tiles) {
+    image::ImageTileWrapper image_tile(tile_data);
+    watertight.tile = image_tile.get_tile_number();
+    ImBuf *image_buffer = BKE_image_acquire_ibuf(&image, &watertight, nullptr);
+    if (image_buffer == nullptr) {
+      continue;
+    }
+
+    Vector<PixelInfo> bitmap = create_tile_bitmap(pbvh, image_tile, *image_buffer);
+    result.bitmaps.append(Bitmap(image_tile, bitmap, int2(image_buffer->x, image_buffer->y)));
+
+    BKE_image_release_ibuf(&image, image_buffer, nullptr);
+  }
+  return result;
+}
+
+void BKE_pbvh_pixels_rebuild_seams(
+    PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image_user, int cd_loop_uv_offset)
+{
+  const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh);
+
+  BMeshCreateParams bmesh_create_params{};
+  bmesh_create_params.use_toolflags = true;
+  BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params);
+
+  BMeshFromMeshParams from_mesh_params{};
+  from_mesh_params.calc_face_normal = false;
+  from_mesh_params.calc_vert_normal = false;
+  BM_mesh_bm_from_me(bm, mesh, &from_mesh_params);
+
+  // find seams.
+  // for each edge
+  Vector<BMLoopPair> pairs = find_connected_loops(bm, cd_loop_uv_offset);
+  printf("found %lld pairs\n", pairs.size());
+
+  // Make a bitmap per tile indicating pixels that have already been assigned to a PBVHNode.
+  // to we could also loop over each node/tile/packed pixels, but that might take to much time.
+  Bitmaps bitmaps = create_tile_bitmap(*pbvh, *image, *image_user);
+
+  for (BMLoopPair &pair : pairs) {
+    // determine bounding rect in uv space + margin of 1;
+    rctf uvbounds;
+    BLI_rctf_init_minmax(&uvbounds);
+    MLoopUV *luv_1 = static_cast<MLoopUV *>(BM_ELEM_CD_GET_VOID_P(pair.first, cd_loop_uv_offset));
+    MLoopUV *luv_2 = static_cast<MLoopUV *>(
+        BM_ELEM_CD_GET_VOID_P(pair.first->next, cd_loop_uv_offset));
+    BLI_rctf_do_minmax_v(&uvbounds, luv_1->uv);
+    BLI_rctf_do_minmax_v(&uvbounds, luv_2->uv);
+
+    for (Bitmap &bitmap : bitmaps.bitmaps) {
+      rcti uvbounds_i;
+      const int MARGIN = 1;
+      uvbounds_i.xmin = (uvbounds.xmin - bitmap.image_tile.get_tile_x_offset()) *
+                            bitmap.resolution[0] -
+                        MARGIN;
+      uvbounds_

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list