[Bf-blender-cvs] [f8c06edf478] temp-T101739-fix-seam-bleeding-non-manifold: Merge branch 'master' into temp-T101739-fix-seam-bleeding-non-manifold

Jeroen Bakker noreply at git.blender.org
Thu Jan 12 14:35:11 CET 2023


Commit: f8c06edf47861e8ce6bccd55ed56ff4702618f9a
Author: Jeroen Bakker
Date:   Thu Jan 12 10:48:11 2023 +0100
Branches: temp-T101739-fix-seam-bleeding-non-manifold
https://developer.blender.org/rBf8c06edf47861e8ce6bccd55ed56ff4702618f9a

Merge branch 'master' into temp-T101739-fix-seam-bleeding-non-manifold

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



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

diff --cc release/scripts/addons
index 5a774a6dad4,a9d4443c244..bf49eeaa14c
--- a/release/scripts/addons
+++ b/release/scripts/addons
@@@ -1,1 -1,1 +1,1 @@@
- Subproject commit 5a774a6dad4378f173ec7fdcdcd406048fcc9a29
 -Subproject commit a9d4443c244f89399ec4bcc427e05a07950528cc
++Subproject commit bf49eeaa14c445d3c53068203fdf91bff568fe64
diff --cc source/blender/blenkernel/intern/pbvh_pixels_copy.cc
index 30da7c64cca,00000000000..57ebed1a8d8
mode 100644,000000..100644
--- a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc
+++ b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc
@@@ -1,546 -1,0 +1,531 @@@
 +/* SPDX-License-Identifier: GPL-2.0-or-later
 + * Copyright 2022 Blender Foundation. All rights reserved. */
 +
 +#include "BLI_array.hh"
 +#include "BLI_bit_vector.hh"
 +#include "BLI_math.h"
 +#include "BLI_math_vector.hh"
 +#include "BLI_vector.hh"
 +
 +#include "IMB_imbuf.h"
 +#include "IMB_imbuf_types.h"
 +
 +#include "BKE_image_wrappers.hh"
 +#include "BKE_pbvh.h"
 +#include "BKE_pbvh_pixels.hh"
 +
 +#include "pbvh_intern.h"
 +#include "pbvh_pixels_copy.hh"
 +#include "pbvh_uv_islands.hh"
 +
 +namespace blender::bke::pbvh::pixels {
 +
 +enum class CoordSpace {
 +  UV,
 +  Tile,
 +};
 +
 +template<CoordSpace Space> struct Vertex {
 +  float2 co;
 +};
 +
 +template<CoordSpace Space> struct Edge {
 +  Vertex<Space> v1;
 +  Vertex<Space> v2;
 +};
 +
 +rcti get_bounds(const Edge<CoordSpace::Tile> &tile_edge)
 +{
 +  rcti bounds;
 +  BLI_rcti_init_minmax(&bounds);
 +  BLI_rcti_do_minmax_v(&bounds, int2(tile_edge.v1.co));
 +  BLI_rcti_do_minmax_v(&bounds, int2(tile_edge.v2.co));
 +  return bounds;
 +}
 +
 +void add_margin(rcti &bounds, int margin)
 +{
 +  bounds.xmin -= margin;
 +  bounds.xmax += margin;
 +  bounds.ymin -= margin;
 +  bounds.ymax += margin;
 +}
 +
 +void clamp(rcti &bounds, int2 resolution)
 +{
 +  rcti clamping_bounds;
 +  int2 xy;
 +  BLI_rcti_init(&clamping_bounds, 0, resolution.x - 1, 0, resolution.y - 1);
 +  BLI_rcti_clamp(&bounds, &clamping_bounds, xy);
 +}
 +
 +const Vertex<CoordSpace::Tile> convert_coord_space(const Vertex<CoordSpace::UV> &uv_vertex,
 +                                                   const image::ImageTileWrapper image_tile,
 +                                                   const int2 tile_resolution)
 +{
 +  return Vertex<CoordSpace::Tile>{(uv_vertex.co - float2(image_tile.get_tile_offset())) *
 +                                  float2(tile_resolution)};
 +}
 +
 +const Edge<CoordSpace::Tile> convert_coord_space(const Edge<CoordSpace::UV> &uv_edge,
 +                                                 const image::ImageTileWrapper image_tile,
 +                                                 const int2 tile_resolution)
 +{
 +  return Edge<CoordSpace::Tile>{
 +      convert_coord_space(uv_edge.v1, image_tile, tile_resolution),
 +      convert_coord_space(uv_edge.v2, image_tile, tile_resolution),
 +  };
 +}
 +
 +class NonManifoldTileEdges : public Vector<Edge<CoordSpace::Tile>> {};
 +
 +class NonManifoldUVEdges : public Vector<Edge<CoordSpace::UV>> {
 + public:
 +  NonManifoldUVEdges(const uv_islands::MeshData &mesh_data)
 +  {
 +    reserve(count_non_manifold_edges(mesh_data));
- 
-     for (const uv_islands::MeshPrimitive &mesh_primitive : mesh_data.primitives) {
-       for (int i = 0; i < 3; i++) {
-         const uv_islands::MeshEdge &mesh_edge = *mesh_primitive.edges[i];
-         if (is_manifold(mesh_edge)) {
++    for (const int primitive_id : mesh_data.looptris.index_range()) {
++      for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) {
++        if (is_manifold(mesh_data, edge_id)) {
 +          continue;
 +        }
++        const uv_islands::MeshEdge &mesh_edge = mesh_data.edges[edge_id];
 +        Edge<CoordSpace::UV> edge;
-         edge.v1.co = find_uv_vert(mesh_primitive, mesh_edge.vert1).uv;
-         edge.v2.co = find_uv_vert(mesh_primitive, mesh_edge.vert2).uv;
++        edge.v1.co = mesh_data.uv_map[mesh_edge.vert1];
++        edge.v2.co = mesh_data.uv_map[mesh_edge.vert2];
 +        append(edge);
 +      }
 +    }
 +  }
 +
 +  NonManifoldTileEdges extract_tile_edges(const image::ImageTileWrapper image_tile,
 +                                          const int2 tile_resolution) const
 +  {
 +    NonManifoldTileEdges result;
 +    // TODO: Only add edges that intersects with the given tile.
 +    // TODO: Clamp edges to tile bounds.
 +
 +    for (const Edge<CoordSpace::UV> &uv_edge : *this) {
 +      const Edge<CoordSpace::Tile> tile_edge = convert_coord_space(
 +          uv_edge, image_tile, tile_resolution);
 +      result.append(tile_edge);
 +    }
 +    return result;
 +  }
 +
 + private:
 +  static int64_t count_non_manifold_edges(const uv_islands::MeshData &mesh_data)
 +  {
 +    int64_t result = 0;
-     for (const uv_islands::MeshPrimitive &mesh_primitive : mesh_data.primitives) {
-       for (int i = 0; i < 3; i++) {
-         const uv_islands::MeshEdge &mesh_edge = *mesh_primitive.edges[i];
-         if (is_manifold(mesh_edge)) {
++    for (const int primitive_id : mesh_data.looptris.index_range()) {
++      for (const int edge_id : mesh_data.primitive_to_edge_map[primitive_id]) {
++        if (is_manifold(mesh_data, edge_id)) {
 +          continue;
 +        }
 +        result += 1;
 +      }
 +    }
 +    return result;
 +  }
 +
-   static const uv_islands::MeshUVVert &find_uv_vert(
-       const uv_islands::MeshPrimitive &mesh_primitive, const uv_islands::MeshVertex *mesh_vertex)
-   {
-     for (const uv_islands::MeshUVVert &uv_vertex : mesh_primitive.vertices) {
-       if (uv_vertex.vertex == mesh_vertex) {
-         return uv_vertex;
-       }
-     }
-     // TODO: Use cleaner interface.
-     BLI_assert_unreachable();
-     static uv_islands::MeshUVVert dummy;
-     return dummy;
-   }
-   static bool is_manifold(const uv_islands::MeshEdge mesh_edge)
++  static bool is_manifold(const uv_islands::MeshData &mesh_data, const int edge_id)
 +  {
-     return mesh_edge.primitives.size() == 2;
++    return mesh_data.edge_to_primitive_map[edge_id].size() == 2;
 +  }
 +};
 +
 +class PixelNodesTileData : public Vector<std::reference_wrapper<UDIMTilePixels>> {
 + public:
 +  PixelNodesTileData(PBVH &pbvh, const image::ImageTileWrapper &image_tile)
 +  {
 +    reserve(count_nodes(pbvh, image_tile));
 +
 +    for (PBVHNode &node : MutableSpan(pbvh.nodes, pbvh.totnode)) {
 +      if (should_add_node(node, image_tile)) {
 +        NodeData &node_data = *static_cast<NodeData *>(node.pixels.node_data);
 +        UDIMTilePixels &tile_pixels = *node_data.find_tile_data(image_tile);
 +        append(tile_pixels);
 +      }
 +    }
 +  }
 +
 + private:
 +  static bool should_add_node(PBVHNode &node, const image::ImageTileWrapper &image_tile)
 +  {
 +    if ((node.flag & PBVH_Leaf) == 0) {
 +      return false;
 +    }
 +    if (node.pixels.node_data == nullptr) {
 +      return false;
 +    }
 +    NodeData &node_data = *static_cast<NodeData *>(node.pixels.node_data);
 +    if (node_data.find_tile_data(image_tile) == nullptr) {
 +      return false;
 +    }
 +    return true;
 +  }
 +
 +  static int64_t count_nodes(PBVH &pbvh, const image::ImageTileWrapper &image_tile)
 +  {
 +    int64_t result = 0;
 +    for (PBVHNode &node : MutableSpan(pbvh.nodes, pbvh.totnode)) {
 +      if (should_add_node(node, image_tile)) {
 +        result++;
 +      }
 +    }
 +    return result;
 +  }
 +};
 +
 +/**
 + * Row contains intermediate data per pixel for a single image row. It is used during updating to
 + * encode pixels.
 + */
 +
 +struct Rows {
 +  struct Row {
 +    enum class PixelType {
 +      Undecided,
 +      /** This pixel is directly affected by a brush and doesn't need to be solved. */
 +      Brush,
 +      /** This pixel will be copid from another pixel to solve non-manifold edge bleeding. */
 +      CopyFromClosestEdge,
 +      Selected,
 +    };
 +
 +    struct Elem {
 +      PixelType type = PixelType::Undecided;
 +      /**
 +       * Distance to the closest edge that can be sourced to fix an edge bleed.
 +       * A distance of 0.0 means that the pixel is being drawn on directly and
 +       * doesn't need to be checked.
 +       */
 +      float distance = std::numeric_limits<float>::max();
 +      PixelCopyCommand copy_command;
 +
 +      Elem() = default;
 +
 +      Elem(int2 co)
 +      {
 +        copy_command.destination = co;
 +        copy_command.source_1 = co;
 +        copy_command.source_2 = co;
 +        copy_command.mix_factor = 0.0f;
 +      }
 +    };
 +
 +    int row_number = 0;
 +    Array<Elem> pixels;
 +    Row() = delete;
 +    Row(int64_t width) : pixels(width)
 +    {
 +    }
 +
 +    void reinit(int y)
 +    {
 +      row_number = y;
 +      for (int x = 0; x < pixels.size(); x++) {
 +        pixels[x] = Elem(int2(x, y));
 +      }
 +    }
 +
 +    void mask_brush_pixels(const PixelNodesTileData &nodes_tile_pixels)
 +    {
 +      for (const UDIMTilePixels &tile_pixels : nodes_tile_pixels) {
 +        for (const PackedPixelRow &encoded_pixels : tile_pixels.pixel_rows) {
 +          if (encoded_pixels.start_image_coordinate.y != row_number) {
 +            continue;
 +          }
 +          for (int x = encoded_pixels.start_image_coordinate.x;
 +               x < encoded_pixels.start_image_coordinate.x + encoded_pixels.num_pixels;
 +               x++) {
 +            pixels[x].type = PixelType::Brush;
 +            pixels[x].distance = 0.0f;
 +          }
 +        }
 +      }
 +    }
 +
 +    void mark_for_evaluation(const Rows &rows, const NonManifoldTileEdges &tile_edges)
 +    {
 +      for (const Edge<CoordSpace::Tile> &tile_edge : tile_edges) {
 +        rcti edge_bounds = get_bounds(tile_edge);
 +        add_margin(edge_bounds, rows.margin);
 +        clamp(edge_bounds, rows.resolution);
 +
 +        if (edge_bounds.ymax < row_number) {
 +          continue;
 +        }
 +        if (edge_bounds.ymin > row_number) {
 +          continue;
 +        }
 +
 +        for (const int x : IndexRange(edge_bounds.xmin, edge_bounds.xmax - edge_bounds.xmin)) {
 +          Elem &pixel = pixels[x];
 +          switch (pixel.type) {
 +            case PixelType::Brush: {
 +              break;
 +            }
 +            ca

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list