[Bf-blender-cvs] [4ed649352f4] master: 3D Texturing: Fix seam bleeding.

Jeroen Bakker noreply at git.blender.org
Mon Nov 28 08:32:30 CET 2022


Commit: 4ed649352f410b8511054c86dd7fb89a862f577a
Author: Jeroen Bakker
Date:   Mon Nov 28 08:31:24 2022 +0100
Branches: master
https://developer.blender.org/rB4ed649352f410b8511054c86dd7fb89a862f577a

3D Texturing: Fix seam bleeding.

{F13294314}
# Process

In the pixel extraction process a larger domain will be extracted then the input mesh.
The borders of uv islands are extended with connected geometry of the input mesh.
The extended mesh is then fed into the pixel extraction process.
A mask is used to limit the extraction so UV islands will not overlap.

Input UV islands.
{F13206401}

Extended UV Island (only one showing).
{F13288764}

This patch doesn't include fixing uv seams at non-manifold edges (like suzannes eyes) as that
would require a different approach (edge extending or pixel copy-ing). The later has already been
implemented in D14702, but should be revisited to only use do the non-manifold edge fixing.

This patch supports fixing UV seams across UDIM textures.
There might be an issue when using a single texture on multiple uv maps.

Reviewed By: brecht, joeedh, JulienKaspar

Maniphest Tasks: T97352

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

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

M	source/blender/blenkernel/BKE_pbvh.h
M	source/blender/blenkernel/BKE_pbvh_pixels.hh
A	source/blender/blenkernel/BKE_uv_islands.hh
M	source/blender/blenkernel/CMakeLists.txt
M	source/blender/blenkernel/intern/paint_canvas.cc
M	source/blender/blenkernel/intern/pbvh.c
M	source/blender/blenkernel/intern/pbvh_intern.h
M	source/blender/blenkernel/intern/pbvh_pixels.cc
A	source/blender/blenkernel/intern/pbvh_uv_islands.cc
A	source/blender/blenkernel/intern/pbvh_uv_islands.hh
M	source/blender/blenlib/BLI_vector.hh
A	source/blender/blenlib/BLI_vector_list.hh
M	source/blender/blenlib/CMakeLists.txt
M	source/blender/blenloader/intern/versioning_300.cc
M	source/blender/editors/sculpt_paint/sculpt_paint_image.cc
M	source/blender/editors/space_image/image_buttons.c
M	source/blender/makesdna/DNA_image_defaults.h
M	source/blender/makesdna/DNA_image_types.h
M	source/blender/makesrna/intern/rna_image.c

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

diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h
index 5b6e5d9b455..139b6ff6bbe 100644
--- a/source/blender/blenkernel/BKE_pbvh.h
+++ b/source/blender/blenkernel/BKE_pbvh.h
@@ -99,6 +99,15 @@ typedef struct {
   float (*color)[4];
 } PBVHColorBufferNode;
 
+typedef struct PBVHPixels {
+  /**
+   * Storage for texture painting on PBVH level.
+   *
+   * Contains #blender::bke::pbvh::pixels::PBVHData
+   */
+  void *data;
+} PBVHPixels;
+
 typedef struct PBVHPixelsNode {
   /**
    * Contains triangle/pixel data used during texture painting.
diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh
index 38bce0b400f..1b0d51fd37d 100644
--- a/source/blender/blenkernel/BKE_pbvh_pixels.hh
+++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh
@@ -18,8 +18,46 @@
 
 namespace blender::bke::pbvh::pixels {
 
-struct TrianglePaintInput {
-  int3 vert_indices;
+/**
+ * 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 PaintGeometryPrimitives {
+  /** Data accessed by the inner loop of the painting brush. */
+  Vector<int3> vert_indices;
+
+ public:
+  void append(const int3 vert_indices)
+  {
+    this->vert_indices.append(vert_indices);
+  }
+
+  const int3 &get_vert_indices(const int index) const
+  {
+    return vert_indices[index];
+  }
+
+  void clear()
+  {
+    vert_indices.clear();
+  }
+
+  int64_t size() const
+  {
+    return vert_indices.size();
+  }
+
+  int64_t mem_size() const
+  {
+    return size() * sizeof(int3);
+  }
+};
+
+struct UVPrimitivePaintInput {
+  /** Corresponding index into PaintGeometryPrimitives */
+  int64_t geometry_primitive_index;
   /**
    * Delta barycentric coordinates between 2 neighboring UV's in the U direction.
    *
@@ -33,34 +71,27 @@ struct TrianglePaintInput {
    * 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)
+  UVPrimitivePaintInput(int64_t geometry_primitive_index)
+      : geometry_primitive_index(geometry_primitive_index), 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 {
+struct PaintUVPrimitives {
   /** Data accessed by the inner loop of the painting brush. */
-  Vector<TrianglePaintInput> paint_input;
+  Vector<UVPrimitivePaintInput> paint_input;
 
- public:
-  void append(const int3 vert_indices)
+  void append(int64_t geometry_primitive_index)
   {
-    this->paint_input.append(TrianglePaintInput(vert_indices));
+    this->paint_input.append(UVPrimitivePaintInput(geometry_primitive_index));
   }
 
-  TrianglePaintInput &get_paint_input(const int index)
+  UVPrimitivePaintInput &last()
   {
-    return paint_input[index];
+    return paint_input.last();
   }
 
-  const TrianglePaintInput &get_paint_input(const int index) const
+  const UVPrimitivePaintInput &get_paint_input(uint64_t index) const
   {
     return paint_input[index];
   }
@@ -77,7 +108,7 @@ struct Triangles {
 
   int64_t mem_size() const
   {
-    return paint_input.size() * sizeof(TrianglePaintInput);
+    return size() * sizeof(UVPrimitivePaintInput);
   }
 };
 
@@ -92,7 +123,7 @@ struct PackedPixelRow {
   /** Number of sequential pixels encoded in this package. */
   ushort num_pixels;
   /** Reference to the pbvh triangle index. */
-  ushort triangle_index;
+  ushort uv_primitive_index;
 };
 
 /**
@@ -148,7 +179,7 @@ struct NodeData {
 
   Vector<UDIMTilePixels> tiles;
   Vector<UDIMTileUndo> undo_regions;
-  Triangles triangles;
+  PaintUVPrimitives uv_primitives;
 
   NodeData()
   {
@@ -201,7 +232,7 @@ struct NodeData {
   void clear_data()
   {
     tiles.clear();
-    triangles.clear();
+    uv_primitives.clear();
   }
 
   static void free_func(void *instance)
@@ -211,7 +242,18 @@ struct NodeData {
   }
 };
 
+struct PBVHData {
+  /* Per UVPRimitive contains the paint data. */
+  PaintGeometryPrimitives geom_primitives;
+
+  void clear_data()
+  {
+    geom_primitives.clear();
+  }
+};
+
 NodeData &BKE_pbvh_pixels_node_data_get(PBVHNode &node);
 void BKE_pbvh_pixels_mark_image_dirty(PBVHNode &node, Image &image, ImageUser &image_user);
+PBVHData &BKE_pbvh_pixels_data_get(PBVH &pbvh);
 
 }  // namespace blender::bke::pbvh::pixels
diff --git a/source/blender/blenkernel/BKE_uv_islands.hh b/source/blender/blenkernel/BKE_uv_islands.hh
new file mode 100644
index 00000000000..cf274e415b9
--- /dev/null
+++ b/source/blender/blenkernel/BKE_uv_islands.hh
@@ -0,0 +1,747 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include <fstream>
+#include <optional>
+
+#include "BLI_array.hh"
+#include "BLI_edgehash.h"
+#include "BLI_float3x3.hh"
+#include "BLI_map.hh"
+#include "BLI_math.h"
+#include "BLI_math_vec_types.hh"
+#include "BLI_rect.h"
+#include "BLI_vector.hh"
+#include "BLI_vector_list.hh"
+
+#include "DNA_meshdata_types.h"
+
+
+namespace blender::bke::uv_islands {
+
+struct MeshEdge;
+struct MeshPrimitive;
+struct UVBorder;
+struct UVEdge;
+struct UVIslands;
+struct UVIslandsMask;
+struct UVPrimitive;
+struct UVPrimitiveEdge;
+struct UVVertex;
+
+struct MeshVertex {
+  int64_t v;
+  Vector<MeshEdge *> edges;
+};
+
+struct MeshUVVert {
+  MeshVertex *vertex;
+  float2 uv;
+  int64_t loop;
+};
+
+struct MeshEdge {
+  MeshVertex *vert1;
+  MeshVertex *vert2;
+  Vector<MeshPrimitive *> primitives;
+};
+
+/** Represents a triangle in 3d space (MLoopTri) */
+struct MeshPrimitive {
+  int64_t index;
+  int64_t poly;
+  Vector<MeshEdge *, 3> edges;
+  Vector<MeshUVVert, 3> vertices;
+
+  /**
+   * UV island this primitive belongs to. This is used to speed up the initial uv island
+   * extraction, but should not be used when extending uv islands.
+   */
+  int64_t uv_island_id;
+
+  MeshUVVert *get_other_uv_vertex(const MeshVertex *v1, const MeshVertex *v2)
+  {
+    BLI_assert(vertices[0].vertex == v1 || vertices[1].vertex == v1 || vertices[2].vertex == v1);
+    BLI_assert(vertices[0].vertex == v2 || vertices[1].vertex == v2 || vertices[2].vertex == v2);
+    for (MeshUVVert &uv_vertex : vertices) {
+      if (uv_vertex.vertex != v1 && uv_vertex.vertex != v2) {
+        return &uv_vertex;
+      }
+    }
+    return nullptr;
+  }
+
+  rctf uv_bounds() const;
+
+  bool has_shared_uv_edge(const MeshPrimitive *other) const
+  {
+    int shared_uv_verts = 0;
+    for (const MeshUVVert &vert : vertices) {
+      for (const MeshUVVert &other_vert : other->vertices) {
+        if (vert.uv == other_vert.uv) {
+          shared_uv_verts += 1;
+        }
+      }
+    }
+    return shared_uv_verts >= 2;
+  }
+};
+
+/**
+ * MeshData contains input geometry data converted in a list of primitives, edges and vertices for
+ * quick access for both local space and uv space.
+ */
+struct MeshData {
+ public:
+  const MLoopTri *looptri;
+  const int64_t looptri_len;
+  const int64_t vert_len;
+  const MLoop *mloop;
+  const MLoopUV *mloopuv;
+
+ public:
+  Vector<MeshPrimitive> primitives;
+  Vector<MeshEdge> edges;
+  Vector<MeshVertex> vertices;
+  /** Total number of uv islands detected. */
+  int64_t uv_island_len;
+
+  explicit MeshData(const MLoopTri *looptri,
+                    const int64_t looptri_len,
+                    const int64_t vert_len,
+                    const MLoop *mloop,
+                    const MLoopUV *mloopuv)
+      : looptri(looptri),
+        looptri_len(looptri_len),
+        vert_len(vert_len),
+        mloop(mloop),
+        mloopuv(mloopuv)
+  {
+    init_vertices();
+    init_primitives();
+    init_edges();
+    init_primitive_uv_island_ids();
+  }
+
+  void init_vertices()
+  {
+    vertices.reserve(vert_len);
+    for (int64_t i = 0; i < vert_len; i++) {
+      MeshVertex vert;
+      vert.v = i;
+      vertices.append(vert);
+    }
+  }
+
+  void init_primitives()
+  {
+    primitives.reserve(looptri_len);
+    for (int64_t i = 0; i < looptri_len; i++) {
+      const MLoopTri &tri = looptri[i];
+      MeshPrimitive primitive;
+      primitive.index = i;
+      primitive.poly = tri.poly;
+
+      for (int j = 0; j < 3; j++) {
+        MeshUVVert uv_vert;
+        uv_vert.loop = tri.tri[j];
+        uv_vert.vertex = &vertices[mloop[uv_vert.loop].v];
+        uv_vert.uv = mloopuv[uv_vert.loop].uv;
+        primitive.vertices.append(uv_vert);
+      }
+      primitives.append(primitive);
+    }
+  }
+
+  void init_edges()
+  {
+    edges.reserve(looptri_len * 2);
+    EdgeHash *eh = BLI_edgehash_new_ex(__func__, looptri_len * 3);
+    for (int64_t i = 0; i < looptri_len; i++) {
+      const MLoopTri &tri = looptri[i];
+      MeshPrimitive &primitive = primitives[i];
+      for (int j = 0; j < 3; j++) {
+        int v1 = mloop[tri.tri[j]].v;
+        int v2 = mloop[tri.tri[(j + 1) % 3]].v;
+        /* TODO: Use lookup_ptr to be able to store edge 0. */
+        void *v = BLI_edgehash_lookup(eh, v1, v2);
+        int64_t edge_index;
+        if (v == nullptr) {
+          edge_index = edges.size();
+          BLI_edgehash_insert(eh, v1, v2, POINTER_FROM_INT(edge_index + 1));
+          MeshEdge edge;
+          edge.vert1 = &vertices[v1];
+          edge.vert2 = &vertices[v2];
+          edges.append(edge);
+          MeshEdge *edge_ptr = &edges.last();
+          vertices[v1].edges.append(edge_ptr);
+          vertices[v2].edges.append(edge_ptr);
+        }
+        else {
+          edge_index = POINTER_AS_INT(v) - 1;
+        }
+
+        MeshEdge *edge = &edges[edge_index];
+        edge->primitives.append(&primitive);
+        primitive.edges.append(edge);
+      }
+    }
+    BLI_edgehash_free(eh, nullptr);
+  }
+
+  static const int64_t INVALID_UV_ISLAND_ID = -1;
+  /**
+   * NOTE: doesn't support weird topology where unconnected mesh primitives share the same uv
+   * island. For a accurate implementation we should use implement an uv_prim_lookup.
+   */
+  

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list