Commit: a017d653a9c3d16034801c3ad8a878a1fa4ab8b7 Author: Jeroen Bakker Date: Fri Jan 6 10:52:52 2023 +0100 Branches: temp-T101739-fix-seam-bleeding-non-manifold https://developer.blender.org/rBa017d653a9c3d16034801c3ad8a878a1fa4ab8b7
Extract non manifold edges. =================================================================== M source/blender/blenkernel/BKE_pbvh_pixels.hh M source/blender/blenkernel/intern/pbvh_pixels.cc M source/blender/blenkernel/intern/pbvh_pixels_copy.cc A source/blender/blenkernel/intern/pbvh_pixels_copy.hh =================================================================== diff --git a/source/blender/blenkernel/BKE_pbvh_pixels.hh b/source/blender/blenkernel/BKE_pbvh_pixels.hh index 28e02dbef8e..2d7d3df4ac3 100644 --- a/source/blender/blenkernel/BKE_pbvh_pixels.hh +++ b/source/blender/blenkernel/BKE_pbvh_pixels.hh @@ -287,6 +287,7 @@ struct PixelCopyCommand { /** Factor to mix between first and second source. */ float mix_factor; + PixelCopyCommand() = default; PixelCopyCommand(const PixelCopyGroup &group) : destination(group.destination), source_1(group.destination), @@ -317,6 +318,10 @@ struct PixelCopyTile { image::TileNumber tile_number; Vector<PixelCopyGroup> groups; + PixelCopyTile(image::TileNumber tile_number) : tile_number(tile_number) + { + } + void copy_pixels(ImBuf &tile_buffer) const { if (tile_buffer.rect_float) { @@ -378,9 +383,9 @@ 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); -void BKE_pbvh_pixels_copy_update(PBVH &pbvh, Image &image, ImageUser &image_user); void BKE_pbvh_pixels_copy_pixels(PBVH &pbvh, Image &image, ImageUser &image_user, image::TileNumber tile_number); + } // namespace blender::bke::pbvh::pixels diff --git a/source/blender/blenkernel/intern/pbvh_pixels.cc b/source/blender/blenkernel/intern/pbvh_pixels.cc index e21103c9f19..3d318c6fb2a 100644 --- a/source/blender/blenkernel/intern/pbvh_pixels.cc +++ b/source/blender/blenkernel/intern/pbvh_pixels.cc @@ -20,6 +20,7 @@ #include "bmesh.h" #include "pbvh_intern.h" +#include "pbvh_pixels_copy.hh" #include "pbvh_uv_islands.hh" namespace blender::bke::pbvh::pixels { @@ -405,6 +406,9 @@ static void update_pixels(PBVH *pbvh, Mesh *mesh, Image *image, ImageUser *image apply_watertight_check(pbvh, image, image_user); } + /* Add solution for non-manifold parts of the model. */ + BKE_pbvh_pixels_copy_update(*pbvh, *image, *image_user, mesh_data); + /* Rebuild the undo regions. */ for (PBVHNode *node : nodes_to_update) { NodeData *node_data = static_cast<NodeData *>(node->pixels.node_data); diff --git a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc index ca850812f02..7a7446ac237 100644 --- a/source/blender/blenkernel/intern/pbvh_pixels_copy.cc +++ b/source/blender/blenkernel/intern/pbvh_pixels_copy.cc @@ -1,6 +1,8 @@ /* 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_vec_types.hh" #include "BLI_vector.hh" @@ -12,31 +14,252 @@ #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; +}; + +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)) { + continue; + } + 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.vert1).uv; + append(edge); + } + } + } + + NonManifoldTileEdges extract_tile_edges(const image::ImageTileWrapper image_tile, + const int2 tile_resolution) + { + NonManifoldTileEdges result; + // TODO add edges that intersects with the given tile. + // Convert the space from uv to tile. + 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)) { + 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) + { + return mesh_edge.primitives.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 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, + }; + + 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 = 0.0f; + 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(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; + } + } + } + } + + void print_debug() const + { + for (const Elem &pixel : pixels) { + printf("%d", pixel.type); + } + printf("\n"); + } +}; + static void copy_pixels_reinit(PixelCopyTiles &tiles) { tiles.clear(); } -void BKE_pbvh_pixels_copy_update(PBVH &pbvh, Image &image, ImageUser &image_user) +void BKE_pbvh_pixels_copy_update(PBVH &pbvh, + Image &image, + ImageUser &image_user, + const uv_islands::MeshData &mesh_data) { PBVHData &pbvh_data = BKE_pbvh_pixels_data_get(pbvh); copy_pixels_reinit(pbvh_data.tiles_copy_pixels); + NonManifoldUVEdges non_manifold_edges(mesh_data); + if (non_manifold_edges.is_empty()) { + printf("Early exit: No non manifold edges detected\n"); + return; + } ImageUser tile_user = image_user; LISTBASE_FOREACH (ImageTile *, tile, &image.tiles) { - image::ImageTileWrapper image_tile = image::ImageTileWrapper(tile); + const image::ImageTileWrapper image_tile = image::ImageTileWrapper(tile); tile_user.tile = image_tile.get_tile_number(); ImBuf *tile_buffer = BKE_image_acquire_ibuf(&image, &tile_user, nullptr); if (tile_buffer == nullptr) { continue; } + const PixelNodesTileData nodes_tile_pixels(pbvh, image_tile); ushort2 tile_resolution(tile_buffer->x, tile_buffer->y); - BKE_image_release_ibuf(&image, tile_buffer, nullptr); + + PixelCopyTile copy_tile(image_tile.get_tile_number()); + Row per_pixel_solution(tile_resolution.x); + + for (int y = 0; y < tile_resolution.y; y++) { + per_pixel_solution.reinit(y); + per_pixel_solution.mask_brush_pixels(nodes_tile_pixels); + per_pixel_solution.print_debug(); + } + + pbvh_data.tiles_copy_pixels.tiles.append(copy_tile); } } dif @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org List details, subscription details or unsubscribe: https://lists.blender.org/mailman/listinfo/bf-blender-cvs