From 5876573e14f434a4cd8ae79c69afbe383111ced9 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 8 Mar 2023 15:36:18 +0100 Subject: [PATCH] Mesh: Move face shade smooth flag to a generic attribute Currently the shade smooth status for mesh faces is stored as part of `MPoly::flag`. As described in #95967, this moves that information to a separate boolean attribute. It also flips its status, so the attribute is now called `sharp_face`, which mirrors the existing `sharp_edge` attribute. The attribute doesn't need to be allocated when all faces are smooth. Forward compatibility is kept until 4.0 like the other mesh refactors. This will reduce memory bandwidth requirements for some operations, since the array of booleans uses 12 times less memory than `MPoly`. It also allows faces to be stored more efficiently in the future, since the flag is now unused. It's also possible to use generic functions to process the values. For example, finding whether there is a sharp face is just `sharp_faces.contains(true)`. The `shade_smooth` attribute is no longer accessible with geometry nodes. Since there were dedicated accessor nodes for that data, that shouldn't be a problem. That's difficult to version automatically since the named attribute nodes could be used in arbitrary combinations. **Implementation notes:** - The attribute and array variables in the code use the `sharp_faces` term, to be consistent with the user-facing "sharp faces" wording, and to avoid requiring many renames when #101689 is implemented. - Cycles now accesses smooth face status with the generic attribute, to avoid overhead. - Changing the zero-value from "smooth" to "flat" takes some care to make sure defaults are the same. - Versioning for the edge mode extrude node is particularly complex. New nodes are added by versioning to propagate the attribute in its old inverted state. - A lot of access is still done through the `CustomData` API rather than the attribute API because of a few functions. That can be cleaned up easily in the future. - In the future we would benefit from a way to store attributes as a single value for when all faces are sharp. Pull Request: https://projects.blender.org/blender/blender/pulls/104422 --- intern/cycles/blender/mesh.cpp | 32 +++- scripts/startup/bl_ui/properties_data_mesh.py | 2 +- source/blender/blenkernel/BKE_DerivedMesh.h | 2 +- source/blender/blenkernel/BKE_mesh.h | 7 + .../blenkernel/BKE_mesh_legacy_convert.h | 3 + source/blender/blenkernel/BKE_mesh_mapping.h | 1 + source/blender/blenkernel/BKE_mesh_tangent.h | 1 + source/blender/blenkernel/BKE_shrinkwrap.h | 1 + .../intern/curve_to_mesh_convert.cc | 21 ++- .../blenkernel/intern/data_transfer.cc | 40 ++--- source/blender/blenkernel/intern/fluid.cc | 15 +- .../intern/geometry_component_mesh.cc | 33 ++--- source/blender/blenkernel/intern/key.cc | 3 + .../blenkernel/intern/mball_tessellate.cc | 1 - source/blender/blenkernel/intern/mesh.cc | 20 ++- .../blenkernel/intern/mesh_boolean_convert.cc | 5 - .../blender/blenkernel/intern/mesh_convert.cc | 12 +- .../blenkernel/intern/mesh_legacy_convert.cc | 84 +++++++++-- .../blender/blenkernel/intern/mesh_mapping.cc | 7 +- .../blender/blenkernel/intern/mesh_mirror.cc | 3 + .../blender/blenkernel/intern/mesh_normals.cc | 25 +++- .../blender/blenkernel/intern/mesh_remap.cc | 3 + .../blender/blenkernel/intern/mesh_tangent.cc | 7 +- source/blender/blenkernel/intern/pbvh.cc | 43 ++++-- .../blender/blenkernel/intern/shrinkwrap.cc | 4 +- .../blenkernel/intern/subdiv_ccg_material.cc | 8 +- .../blender/blenkernel/intern/subsurf_ccg.cc | 9 +- .../blenkernel/intern/volume_to_mesh.cc | 1 + .../blenloader/intern/versioning_300.cc | 139 ++++++++++++++++++ .../blenloader/intern/versioning_400.cc | 1 + .../bmesh/intern/bmesh_mesh_convert.cc | 64 +++++--- .../draw_cache_extract_mesh_render_data.cc | 4 + .../intern/draw_cache_impl_subdivision.cc | 4 +- source/blender/draw/intern/draw_pbvh.cc | 12 +- .../intern/mesh_extractors/extract_mesh.hh | 1 + .../mesh_extractors/extract_mesh_vbo_lnor.cc | 12 +- .../mesh_extractors/extract_mesh_vbo_tan.cc | 1 + source/blender/editors/mesh/mesh_data.cc | 8 +- .../blender/editors/object/object_remesh.cc | 16 +- .../editors/sculpt_paint/paint_image_proj.cc | 6 +- .../blender_interface/BlenderFileLoader.cpp | 9 +- .../geometry/intern/mesh_primitive_cuboid.cc | 1 + .../geometry/intern/realize_instances.cc | 1 - .../intern/lineart/lineart_cpu.cc | 8 +- .../io/alembic/exporter/abc_writer_mesh.cc | 12 +- .../io/alembic/intern/abc_reader_mesh.cc | 1 - .../blender/io/collada/GeometryExporter.cpp | 7 +- source/blender/io/collada/MeshImporter.cpp | 14 +- .../io/ply/importer/ply_import_mesh.cc | 2 + .../blender/io/usd/intern/usd_reader_mesh.cc | 1 - .../blender/io/usd/intern/usd_reader_shape.cc | 6 +- .../blender/io/usd/intern/usd_writer_mesh.cc | 5 +- .../wavefront_obj/exporter/obj_export_mesh.cc | 11 +- .../wavefront_obj/exporter/obj_export_mesh.hh | 2 + .../wavefront_obj/importer/obj_import_mesh.cc | 11 +- source/blender/makesdna/DNA_meshdata_types.h | 9 +- .../blender/makesdna/intern/dna_rename_defs.h | 1 + source/blender/makesrna/intern/rna_mesh.c | 34 ++++- source/blender/makesrna/intern/rna_mesh_api.c | 3 + .../modifiers/intern/MOD_normal_edit.cc | 12 +- source/blender/modifiers/intern/MOD_ocean.cc | 1 - source/blender/modifiers/intern/MOD_screw.cc | 11 +- .../modifiers/intern/MOD_solidify_extrude.cc | 1 - .../intern/MOD_solidify_nonmanifold.cc | 3 - .../modifiers/intern/MOD_volume_to_mesh.cc | 4 +- .../modifiers/intern/MOD_weighted_normal.cc | 8 + .../geometry/nodes/node_geo_convex_hull.cc | 1 + .../geometry/nodes/node_geo_curve_fill.cc | 1 + .../geometry/nodes/node_geo_dual_mesh.cc | 2 + .../geometry/nodes/node_geo_extrude_mesh.cc | 1 - .../nodes/node_geo_input_shade_smooth.cc | 4 +- .../nodes/node_geo_mesh_primitive_circle.cc | 1 + .../nodes/node_geo_mesh_primitive_cone.cc | 1 + .../nodes/node_geo_mesh_primitive_grid.cc | 1 + .../node_geo_mesh_primitive_uv_sphere.cc | 1 + .../nodes/node_geo_set_shade_smooth.cc | 45 ++++-- .../geometry/nodes/node_geo_volume_to_mesh.cc | 1 + source/blender/render/intern/bake.cc | 7 +- source/blender/render/intern/multires_bake.cc | 7 +- 79 files changed, 681 insertions(+), 231 deletions(-) diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index b82ef9bbe78..847c7358f7a 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -893,6 +893,23 @@ static std::optional find_material_index_attribute(BL::Mesh b_ return std::nullopt; } +static std::optional find_sharp_face_attribute(BL::Mesh b_mesh) +{ + for (BL::Attribute &b_attribute : b_mesh.attributes) { + if (b_attribute.domain() != BL::Attribute::domain_FACE) { + continue; + } + if (b_attribute.data_type() != BL::Attribute::data_type_BOOLEAN) { + continue; + } + if (b_attribute.name() != "sharp_face") { + continue; + } + return BL::BoolAttribute{b_attribute}; + } + return std::nullopt; +} + static void create_mesh(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, @@ -983,16 +1000,22 @@ static void create_mesh(Scene *scene, return 0; }; + std::optional sharp_faces = find_sharp_face_attribute(b_mesh); + auto get_face_sharp = [&](const int poly_index) -> bool { + if (sharp_faces) { + return sharp_faces->data[poly_index].value(); + } + return false; + }; + /* create faces */ - const MPoly *polys = static_cast(b_mesh.polygons[0].ptr.data); if (!subdivision) { for (BL::MeshLoopTriangle &t : b_mesh.loop_triangles) { const int poly_index = t.polygon_index(); - const MPoly &b_poly = polys[poly_index]; int3 vi = get_int3(t.vertices()); int shader = get_material_index(poly_index); - bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals; + bool smooth = !get_face_sharp(poly_index) || use_loop_normals; if (use_loop_normals) { BL::Array loop_normals = t.split_normals(); @@ -1012,13 +1035,14 @@ static void create_mesh(Scene *scene, else { vector vi; + const MPoly *polys = static_cast(b_mesh.polygons[0].ptr.data); const MLoop *loops = static_cast(b_mesh.loops[0].ptr.data); for (int i = 0; i < numfaces; i++) { const MPoly &b_poly = polys[i]; int n = b_poly.totloop; int shader = get_material_index(i); - bool smooth = (b_poly.flag & ME_SMOOTH) || use_loop_normals; + bool smooth = !get_face_sharp(i) || use_loop_normals; vi.resize(n); for (int i = 0; i < n; i++) { diff --git a/scripts/startup/bl_ui/properties_data_mesh.py b/scripts/startup/bl_ui/properties_data_mesh.py index c837a038c9f..f098172db0b 100644 --- a/scripts/startup/bl_ui/properties_data_mesh.py +++ b/scripts/startup/bl_ui/properties_data_mesh.py @@ -604,7 +604,7 @@ class DATA_PT_mesh_attributes(MeshButtonsPanel, Panel): colliding_names = [] for collection in ( # Built-in names. - {"shade_smooth": None, "crease": None}, + {"crease": None}, mesh.attributes, None if ob is None else ob.vertex_groups, ): diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 967f9ea240c..d0a894389f4 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -74,7 +74,7 @@ struct Scene; /* keep in sync with MFace/MPoly types */ typedef struct DMFlagMat { short mat_nr; - char flag; + bool sharp; } DMFlagMat; typedef enum DerivedMeshType { diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index 2f36e36859a..1050a75e48c 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -453,12 +453,15 @@ void BKE_mesh_ensure_normals_for_display(struct Mesh *mesh); * * Used when defining an empty custom loop normals data layer, * to keep same shading as with auto-smooth! + * + * \param sharp_faces: Optional array used to mark specific faces for sharp shading. */ void BKE_edges_sharp_from_angle_set(int numEdges, const struct MLoop *mloops, int numLoops, const struct MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, int numPolys, float split_angle, bool *sharp_edges); @@ -574,6 +577,7 @@ void BKE_lnor_space_custom_normal_to_data(const MLoopNorSpace *lnor_space, * (splitting edges). * * \param loop_to_poly_map: Optional pre-created map from loops to their polygon. + * \param sharp_faces: Optional array used to mark specific faces for sharp shading. * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on * each side of the edge. */ @@ -591,6 +595,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], bool use_split_normals, float split_angle, const bool *sharp_edges, + const bool *sharp_faces, const int *loop_to_poly_map, MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2]); @@ -605,6 +610,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3], int numLoops, const struct MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, int numPolys, bool *sharp_edges, short (*r_clnors_data)[2]); @@ -618,6 +624,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3 int numLoops, const struct MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, int numPolys, bool *sharp_edges, short (*r_clnors_data)[2]); diff --git a/source/blender/blenkernel/BKE_mesh_legacy_convert.h b/source/blender/blenkernel/BKE_mesh_legacy_convert.h index 38c4ba7d882..950cf76174c 100644 --- a/source/blender/blenkernel/BKE_mesh_legacy_convert.h +++ b/source/blender/blenkernel/BKE_mesh_legacy_convert.h @@ -96,6 +96,9 @@ void BKE_mesh_legacy_convert_loose_edges_to_flag(struct Mesh *mesh); void BKE_mesh_legacy_attribute_flags_to_strings(struct Mesh *mesh); void BKE_mesh_legacy_attribute_strings_to_flags(struct Mesh *mesh); +void BKE_mesh_legacy_sharp_faces_to_flags(struct Mesh *mesh); +void BKE_mesh_legacy_sharp_faces_from_flags(struct Mesh *mesh); + void BKE_mesh_legacy_sharp_edges_to_flags(struct Mesh *mesh); void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh); diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index 3835e3f78e2..6f14b25588f 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -324,6 +324,7 @@ int *BKE_mesh_calc_smoothgroups(int totedge, const struct MLoop *mloop, int totloop, const bool *sharp_edges, + const bool *sharp_faces, int *r_totgroup, bool use_bitflags); diff --git a/source/blender/blenkernel/BKE_mesh_tangent.h b/source/blender/blenkernel/BKE_mesh_tangent.h index a9d7ba2163e..085096c77f1 100644 --- a/source/blender/blenkernel/BKE_mesh_tangent.h +++ b/source/blender/blenkernel/BKE_mesh_tangent.h @@ -48,6 +48,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], const struct MLoop *mloop, const struct MLoopTri *looptri, uint looptri_len, + const bool *sharp_faces, struct CustomData *loopdata, bool calc_active_tangent, diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 448a8938bd3..707dbc0ada6 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -76,6 +76,7 @@ typedef struct ShrinkwrapTreeData { const struct MPoly *polys; const float (*vert_normals)[3]; const float (*poly_normals)[3]; + const bool *sharp_faces; const float (*clnors)[3]; ShrinkwrapBoundaryData *boundary; } ShrinkwrapTreeData; diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 44472a94e7a..33b20b85a45 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -103,7 +103,6 @@ static void fill_mesh_topology(const int vert_offset, MPoly &poly = polys[ring_poly_offset + i_profile]; poly.loopstart = ring_segment_loop_offset; poly.totloop = 4; - poly.flag = ME_SMOOTH; MLoop &loop_a = loops[ring_segment_loop_offset]; loop_a.v = ring_vert_offset + i_profile; @@ -674,6 +673,7 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) { fill_mesh_topology(info.vert_range.start(), @@ -690,6 +690,23 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, polys); }); + if (fill_caps) { + /* TODO: This is used to keep the tests passing after refactoring mesh shade smooth flags. It + * can be removed if the tests are updated and the final shading results will be the same. */ + SpanAttributeWriter sharp_faces = mesh_attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); + foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) { + const bool has_caps = fill_caps && !info.main_cyclic && info.profile_cyclic; + if (has_caps) { + const int poly_num = info.main_segment_num * info.profile_segment_num; + const int cap_poly_offset = info.poly_range.start() + poly_num; + sharp_faces.span[cap_poly_offset] = true; + sharp_faces.span[cap_poly_offset + 1] = true; + } + }); + sharp_faces.finish(); + } + const Span main_positions = main.evaluated_positions(); const Span tangents = main.evaluated_tangents(); const Span normals = main.evaluated_normals(); @@ -721,8 +738,6 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main, positions.slice(info.vert_range)); }); - MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write(); - SpanAttributeWriter sharp_edges; write_sharp_bezier_edges(curves_info, offsets, mesh_attributes, sharp_edges); if (fill_caps) { diff --git a/source/blender/blenkernel/intern/data_transfer.cc b/source/blender/blenkernel/intern/data_transfer.cc index 4c8ef7dc9fc..303124d4106 100644 --- a/source/blender/blenkernel/intern/data_transfer.cc +++ b/source/blender/blenkernel/intern/data_transfer.cc @@ -382,6 +382,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, if (dirty_nors_dst || do_loop_nors_dst) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_split(positions_dst, BKE_mesh_vert_normals_ensure(me_dst), num_verts_dst, @@ -396,6 +398,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src, use_split_nors_dst, split_angle_dst, sharp_edges, + sharp_faces, nullptr, nullptr, custom_nors_dst); @@ -451,6 +454,8 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/, loops_dst.size(), polys_dst.data(), poly_nors_dst, + static_cast(CustomData_get_layer_named( + &me_dst->pdata, CD_PROP_BOOL, "sharp_face")), polys_dst.size(), sharp_edges.span.data(), custom_nors_dst); @@ -1109,26 +1114,21 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map, return true; } if (r_map && cddata_type == CD_FAKE_SHARP) { - const size_t elem_size = sizeof(*((MPoly *)nullptr)); - const size_t data_size = sizeof(((MPoly *)nullptr)->flag); - const size_t data_offset = offsetof(MPoly, flag); - const uint64_t data_flag = ME_SMOOTH; - - data_transfer_layersmapping_add_item(r_map, - cddata_type, - mix_mode, - mix_factor, - mix_weights, - me_src->polys().data(), - me_dst->polys_for_write().data(), - me_src->totpoly, - me_dst->totpoly, - elem_size, - data_size, - data_offset, - data_flag, - nullptr, - interp_data); + if (!CustomData_get_layer_named(&me_dst->pdata, CD_PROP_BOOL, "sharp_face")) { + CustomData_add_layer_named( + &me_dst->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totpoly, "sharp_face"); + } + data_transfer_layersmapping_add_item_cd( + r_map, + CD_PROP_BOOL, + mix_mode, + mix_factor, + mix_weights, + CustomData_get_layer_named(&me_src->pdata, CD_PROP_BOOL, "sharp_face"), + CustomData_get_layer_named_for_write( + &me_dst->pdata, CD_PROP_BOOL, "sharp_face", num_elem_dst), + interp, + interp_data); return true; } diff --git a/source/blender/blenkernel/intern/fluid.cc b/source/blender/blenkernel/intern/fluid.cc index 0bc2564a8ba..130d02a7cd9 100644 --- a/source/blender/blenkernel/intern/fluid.cc +++ b/source/blender/blenkernel/intern/fluid.cc @@ -23,7 +23,7 @@ #include "DNA_object_types.h" #include "DNA_rigidbody_types.h" -#include "BKE_attribute.h" +#include "BKE_attribute.hh" #include "BKE_effect.h" #include "BKE_fluid.h" #include "BKE_global.h" @@ -3213,16 +3213,8 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, float size[3]; float cell_size_scaled[3]; - /* Assign material + flags to new mesh. - * If there are no faces in original mesh, keep materials and flags unchanged. */ - MPoly mp_example = {0}; - if (MPoly *polys = BKE_mesh_polys_for_write(orgmesh)) { - mp_example = *polys; - } - const int *orig_material_indices = BKE_mesh_material_indices(orgmesh); const short mp_mat_nr = orig_material_indices ? orig_material_indices[0] : 0; - const char mp_flag = mp_example.flag; int i; int num_verts, num_faces; @@ -3251,6 +3243,10 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, blender::MutableSpan polys = me->polys_for_write(); blender::MutableSpan loops = me->loops_for_write(); + const bool is_sharp = orgmesh->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false)[0]; + BKE_mesh_smooth_flag_set(me, !is_sharp); + /* Get size (dimension) but considering scaling. */ copy_v3_v3(cell_size_scaled, fds->cell_size); mul_v3_v3(cell_size_scaled, ob->scale); @@ -3338,7 +3334,6 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *fds, for (const int i : polys.index_range()) { /* Initialize from existing face. */ material_indices[i] = mp_mat_nr; - polys[i].flag = mp_flag; polys[i].loopstart = i * 3; polys[i].totloop = 3; diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index a91a615532f..23c2bb3cc71 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -913,16 +913,6 @@ static void tag_component_positions_changed(void *owner) } } -static bool get_shade_smooth(const MPoly &poly) -{ - return poly.flag & ME_SMOOTH; -} - -static void set_shade_smooth(MPoly &poly, bool value) -{ - SET_FLAG_FROM_TEST(poly.flag, value, ME_SMOOTH); -} - static float get_crease(const float &crease) { return crease; @@ -1217,17 +1207,16 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() nullptr, AttributeValidator{&material_index_clamp}); - static BuiltinCustomDataLayerProvider shade_smooth( - "shade_smooth", - ATTR_DOMAIN_FACE, - CD_PROP_BOOL, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::NonDeletable, - face_access, - make_derived_read_attribute, - make_derived_write_attribute, - nullptr); + static BuiltinCustomDataLayerProvider sharp_face("sharp_face", + ATTR_DOMAIN_FACE, + CD_PROP_BOOL, + CD_PROP_BOOL, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Deletable, + face_access, + make_array_read_attribute, + make_array_write_attribute, + nullptr); static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge", ATTR_DOMAIN_EDGE, @@ -1259,7 +1248,7 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh() static CustomDataAttributeProvider face_custom_data(ATTR_DOMAIN_FACE, face_access); return ComponentAttributeProviders( - {&position, &id, &material_index, &shade_smooth, &sharp_edge, &crease}, + {&position, &id, &material_index, &sharp_face, &sharp_edge, &crease}, {&corner_custom_data, &vertex_groups, &point_custom_data, diff --git a/source/blender/blenkernel/intern/key.cc b/source/blender/blenkernel/intern/key.cc index a4f3fbf2de3..832fc3f1ece 100644 --- a/source/blender/blenkernel/intern/key.cc +++ b/source/blender/blenkernel/intern/key.cc @@ -2281,6 +2281,8 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb, &mesh->ldata, CD_CUSTOMLOOPNORMAL, loops.size())); /* May be nullptr. */ const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_split(positions, vert_normals, mesh->totvert, @@ -2295,6 +2297,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb, (mesh->flag & ME_AUTOSMOOTH) != 0, mesh->smoothresh, sharp_edges, + sharp_faces, nullptr, nullptr, clnors); diff --git a/source/blender/blenkernel/intern/mball_tessellate.cc b/source/blender/blenkernel/intern/mball_tessellate.cc index 839834a8326..c4f7178445b 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.cc +++ b/source/blender/blenkernel/intern/mball_tessellate.cc @@ -1480,7 +1480,6 @@ Mesh *BKE_mball_polygonize(Depsgraph *depsgraph, Scene *scene, Object *ob) const int count = indices[2] != indices[3] ? 4 : 3; polys[i].loopstart = loop_offset; polys[i].totloop = count; - polys[i].flag = ME_SMOOTH; mloop[loop_offset].v = uint32_t(indices[0]); mloop[loop_offset + 1].v = uint32_t(indices[1]); diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 0549bee5a5b..42c46d75bdd 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -269,6 +269,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address BKE_mesh_legacy_convert_hide_layers_to_flags(mesh); BKE_mesh_legacy_convert_selection_layers_to_flags(mesh); BKE_mesh_legacy_convert_material_indices_to_mpoly(mesh); + BKE_mesh_legacy_sharp_faces_to_flags(mesh); BKE_mesh_legacy_bevel_weight_from_layers(mesh); BKE_mesh_legacy_edge_crease_from_layers(mesh); BKE_mesh_legacy_sharp_edges_to_flags(mesh); @@ -1485,16 +1486,17 @@ void BKE_mesh_material_remap(Mesh *me, const uint *remap, uint remap_len) void BKE_mesh_smooth_flag_set(Mesh *me, const bool use_smooth) { - MutableSpan polys = me->polys_for_write(); + using namespace blender; + using namespace blender::bke; + MutableAttributeAccessor attributes = me->attributes_for_write(); if (use_smooth) { - for (MPoly &poly : polys) { - poly.flag |= ME_SMOOTH; - } + attributes.remove("sharp_face"); } else { - for (MPoly &poly : polys) { - poly.flag &= ~ME_SMOOTH; - } + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_only_span( + "sharp_face", ATTR_DOMAIN_FACE); + sharp_faces.span.fill(true); + sharp_faces.finish(); } } @@ -1842,7 +1844,8 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, &mesh->ldata, CD_CUSTOMLOOPNORMAL, mesh->totloop); const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge")); - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); const Span positions = mesh->vert_positions(); const Span edges = mesh->edges(); const Span polys = mesh->polys(); @@ -1862,6 +1865,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, use_split_normals, split_angle, sharp_edges, + sharp_faces, nullptr, r_lnors_spacearr, clnors); diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index 44bb0c326e4..6aa9c55f223 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -391,15 +391,12 @@ static void copy_vert_attributes(Mesh *dest_mesh, /* Similar to copy_vert_attributes but for poly attributes. */ static void copy_poly_attributes(Mesh *dest_mesh, - MPoly *poly, - const MPoly *orig_poly, const Mesh *orig_me, int poly_index, int index_in_orig_me, Span material_remap, MutableSpan dst_material_indices) { - poly->flag = orig_poly->flag; CustomData *target_cd = &dest_mesh->pdata; const CustomData *source_cd = &orig_me->pdata; for (int source_layer_i = 0; source_layer_i < source_cd->totlayer; ++source_layer_i) { @@ -751,8 +748,6 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) } copy_poly_attributes(result, - poly, - orig_poly, orig_me, fi, index_in_orig_me, diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index 7bd70dcef46..e287109d47d 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -195,6 +195,9 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter material_indices = attributes.lookup_or_add_for_write_only_span( "material_index", ATTR_DOMAIN_FACE); + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); + blender::float2 *mloopuv = static_cast(CustomData_add_layer_named( &mesh->ldata, CD_PROP_FLOAT2, CD_SET_DEFAULT, nullptr, mesh->totloop, DATA_("UVMap"))); @@ -278,9 +281,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } } - if (is_smooth) { - polys[dst_poly].flag |= ME_SMOOTH; - } + sharp_faces.span[dst_poly] = !is_smooth; dst_poly++; dst_loop += 3; index += 3; @@ -363,9 +364,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } } - if (is_smooth) { - polys[dst_poly].flag |= ME_SMOOTH; - } + sharp_faces.span[dst_poly] = !is_smooth; dst_poly++; dst_loop += 4; @@ -383,6 +382,7 @@ static Mesh *mesh_nurbs_displist_to_mesh(const Curve *cu, const ListBase *dispba } material_indices.finish(); + sharp_faces.finish(); return mesh; } diff --git a/source/blender/blenkernel/intern/mesh_legacy_convert.cc b/source/blender/blenkernel/intern/mesh_legacy_convert.cc index 46908416325..66d02bc3a95 100644 --- a/source/blender/blenkernel/intern/mesh_legacy_convert.cc +++ b/source/blender/blenkernel/intern/mesh_legacy_convert.cc @@ -447,6 +447,12 @@ static void convert_mfaces_to_mpolys(ID *id, material_indices = static_cast(CustomData_add_layer_named( pdata, CD_PROP_INT32, CD_SET_DEFAULT, nullptr, totpoly, "material_index")); } + bool *sharp_faces = static_cast( + CustomData_get_layer_named_for_write(pdata, CD_PROP_BOOL, "sharp_face", totpoly)); + if (!sharp_faces) { + sharp_faces = static_cast(CustomData_add_layer_named( + pdata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, totpoly, "sharp_face")); + } numTex = CustomData_number_of_layers(fdata, CD_MTFACE); numCol = CustomData_number_of_layers(fdata, CD_MCOL); @@ -491,7 +497,7 @@ static void convert_mfaces_to_mpolys(ID *id, poly->totloop = mf->v4 ? 4 : 3; material_indices[i] = mf->mat_nr; - poly->flag = mf->flag; + sharp_faces[i] = (mf->flag & ME_SMOOTH) == 0; #define ML(v1, v2) \ { \ @@ -975,6 +981,8 @@ static int mesh_tessface_calc(Mesh &mesh, mloop = (const MLoop *)CustomData_get_layer(ldata, CD_MLOOP); const int *material_indices = static_cast( CustomData_get_layer_named(pdata, CD_PROP_INT32, "material_index")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(pdata, CD_PROP_BOOL, "sharp_face")); /* Allocate the length of `totfaces`, avoid many small reallocation's, * if all faces are triangles it will be correct, `quads == 2x` allocations. */ @@ -1014,7 +1022,7 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[2] = l3; \ lidx[3] = 0; \ mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \ - mf->flag = poly->flag; \ + mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \ mf->edcode = 0; \ (void)0 @@ -1037,7 +1045,7 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[2] = l3; \ lidx[3] = l4; \ mf->mat_nr = material_indices ? material_indices[poly_index] : 0; \ - mf->flag = poly->flag; \ + mf->flag = (sharp_faces && sharp_faces[poly_index]) ? 0 : ME_SMOOTH; \ mf->edcode = TESSFACE_IS_QUAD; \ (void)0 @@ -1123,7 +1131,6 @@ static int mesh_tessface_calc(Mesh &mesh, lidx[3] = 0; mf->mat_nr = material_indices ? material_indices[poly_index] : 0; - mf->flag = poly->flag; mf->edcode = 0; mface_index++; @@ -1214,6 +1221,57 @@ void BKE_mesh_tessface_ensure(struct Mesh *mesh) /** \} */ +/* -------------------------------------------------------------------- */ +/** \name Sharp Edge Conversion + * \{ */ + +void BKE_mesh_legacy_sharp_faces_to_flags(Mesh *mesh) +{ + using namespace blender; + MutableSpan polys = mesh->polys_for_write(); + if (const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face"))) { + threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) { + for (const int i : range) { + SET_FLAG_FROM_TEST(polys[i].flag_legacy, !sharp_faces[i], ME_SMOOTH); + } + }); + } + else { + for (const int i : polys.index_range()) { + polys[i].flag_legacy |= ME_SMOOTH; + } + } +} + +void BKE_mesh_legacy_sharp_faces_from_flags(Mesh *mesh) +{ + using namespace blender; + using namespace blender::bke; + const Span polys = mesh->polys(); + MutableAttributeAccessor attributes = mesh->attributes_for_write(); + if (attributes.contains("sharp_face")) { + return; + } + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return !(poly.flag_legacy & ME_SMOOTH); + })) { + SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_only_span( + "sharp_face", ATTR_DOMAIN_FACE); + threading::parallel_for(polys.index_range(), 4096, [&](const IndexRange range) { + for (const int i : range) { + sharp_faces.span[i] = !(polys[i].flag_legacy & ME_SMOOTH); + } + }); + sharp_faces.finish(); + } + else { + attributes.remove("sharp_face"); + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Face Set Conversion * \{ */ @@ -1496,7 +1554,7 @@ void BKE_mesh_legacy_convert_hide_layers_to_flags(Mesh *mesh) ".hide_poly", ATTR_DOMAIN_FACE, false); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - SET_FLAG_FROM_TEST(polys[i].flag, hide_poly[i], ME_HIDE); + SET_FLAG_FROM_TEST(polys[i].flag_legacy, hide_poly[i], ME_HIDE); } }); } @@ -1539,13 +1597,14 @@ void BKE_mesh_legacy_convert_flags_to_hide_layers(Mesh *mesh) } const Span polys = mesh->polys(); - if (std::any_of( - polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_HIDE; })) { + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return poly.flag_legacy & ME_HIDE; + })) { SpanAttributeWriter hide_poly = attributes.lookup_or_add_for_write_only_span( ".hide_poly", ATTR_DOMAIN_FACE); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - hide_poly.span[i] = polys[i].flag & ME_HIDE; + hide_poly.span[i] = polys[i].flag_legacy & ME_HIDE; } }); hide_poly.finish(); @@ -1814,7 +1873,7 @@ void BKE_mesh_legacy_convert_selection_layers_to_flags(Mesh *mesh) ".select_poly", ATTR_DOMAIN_FACE, false); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - SET_FLAG_FROM_TEST(polys[i].flag, select_poly[i], ME_FACE_SEL); + SET_FLAG_FROM_TEST(polys[i].flag_legacy, select_poly[i], ME_FACE_SEL); } }); } @@ -1858,13 +1917,14 @@ void BKE_mesh_legacy_convert_flags_to_selection_layers(Mesh *mesh) } const Span polys = mesh->polys(); - if (std::any_of( - polys.begin(), polys.end(), [](const MPoly &poly) { return poly.flag & ME_FACE_SEL; })) { + if (std::any_of(polys.begin(), polys.end(), [](const MPoly &poly) { + return poly.flag_legacy & ME_FACE_SEL; + })) { SpanAttributeWriter select_poly = attributes.lookup_or_add_for_write_only_span( ".select_poly", ATTR_DOMAIN_FACE); threading::parallel_for(polys.index_range(), 4096, [&](IndexRange range) { for (const int i : range) { - select_poly.span[i] = polys[i].flag & ME_FACE_SEL; + select_poly.span[i] = polys[i].flag_legacy & ME_FACE_SEL; } }); select_poly.finish(); diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index fd2452554fa..6ee3d0981b1 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -845,11 +845,14 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, const MLoop *mloop, const int totloop, const bool *sharp_edges, + const bool *sharp_faces, int *r_totgroup, const bool use_bitflags) { int *poly_groups = nullptr; + auto poly_is_smooth = [&](const int i) { return !(sharp_faces && sharp_faces[i]); }; + auto poly_is_island_boundary_smooth = [&](const int poly_index, const int /*loop_index*/, const int edge_index, @@ -857,13 +860,13 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, const MeshElemMap &edge_poly_map_elem) { /* Edge is sharp if one of its polys is flat, or edge itself is sharp, * or edge is not used by exactly two polygons. */ - if ((polys[poly_index].flag & ME_SMOOTH) && !(sharp_edges && sharp_edges[edge_index]) && + if ((poly_is_smooth(poly_index)) && !(sharp_edges && sharp_edges[edge_index]) && (edge_user_count == 2)) { /* In that case, edge appears to be smooth, but we need to check its other poly too. */ const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ? edge_poly_map_elem.indices[1] : edge_poly_map_elem.indices[0]; - return (polys[other_poly_index].flag & ME_SMOOTH) == 0; + return !poly_is_smooth(other_poly_index); } return true; }; diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 1a672d157dd..1baa7f97b3e 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -389,6 +389,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, const bool *sharp_edges = static_cast( CustomData_get_layer_named(&result->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_split(BKE_mesh_vert_positions(result), BKE_mesh_vert_normals_ensure(result), result->totvert, @@ -403,6 +405,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, true, result->smoothresh, sharp_edges, + sharp_faces, nullptr, &lnors_spacearr, clnors); diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index ba7eaf00e3d..da07c553f68 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -786,6 +786,7 @@ static void mesh_edges_sharp_tag(const Span polys, const Span loops, const Span loop_to_poly_map, const Span poly_normals, + const Span sharp_faces, const Span sharp_edges, const bool check_angle, const float split_angle, @@ -794,6 +795,9 @@ static void mesh_edges_sharp_tag(const Span polys, { using namespace blender; const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f; + auto poly_is_smooth = [&](const int poly_i) { + return sharp_faces.is_empty() || !sharp_faces[poly_i]; + }; for (const int poly_i : polys.index_range()) { const MPoly &poly = polys[poly_i]; @@ -808,7 +812,7 @@ static void mesh_edges_sharp_tag(const Span polys, /* 'Empty' edge until now, set e2l[0] (and e2l[1] to INDEX_UNSET to tag it as unset). */ e2l[0] = loop_index; /* We have to check this here too, else we might miss some flat faces!!! */ - e2l[1] = (poly.flag & ME_SMOOTH) ? INDEX_UNSET : INDEX_INVALID; + e2l[1] = (poly_is_smooth(poly_i)) ? INDEX_UNSET : INDEX_INVALID; } else if (e2l[1] == INDEX_UNSET) { const bool is_angle_sharp = (check_angle && @@ -820,7 +824,7 @@ static void mesh_edges_sharp_tag(const Span polys, * or both poly have opposed (flipped) normals, i.e. both loops on the same edge share the * same vertex, or angle between both its polys' normals is above split_angle value. */ - if (!(poly.flag & ME_SMOOTH) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) || + if (!poly_is_smooth(poly_i) || (!sharp_edges.is_empty() && sharp_edges[edge_i]) || vert_i == loops[e2l[0]].v || is_angle_sharp) { /* NOTE: we are sure that loop != 0 here ;). */ e2l[1] = INDEX_INVALID; @@ -855,6 +859,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges, const int numLoops, const MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, const int numPolys, const float split_angle, bool *sharp_edges) @@ -877,6 +882,7 @@ void BKE_edges_sharp_from_angle_set(const int numEdges, {mloops, numLoops}, loop_to_poly, {reinterpret_cast(poly_normals), numPolys}, + Span(sharp_faces, sharp_faces ? numPolys : 0), Span(sharp_edges, numEdges), true, split_angle, @@ -1442,6 +1448,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], const bool use_split_normals, const float split_angle, const bool *sharp_edges, + const bool *sharp_faces, const int *loop_to_poly_map, MLoopNorSpaceArray *r_lnors_spacearr, short (*clnors_data)[2]) @@ -1465,7 +1472,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], const MPoly &poly = polys[poly_index]; int ml_index = poly.loopstart; const int ml_index_end = ml_index + poly.totloop; - const bool is_poly_flat = ((poly.flag & ME_SMOOTH) == 0); + const bool is_poly_flat = sharp_faces && sharp_faces[poly_index]; for (; ml_index < ml_index_end; ml_index++) { if (is_poly_flat) { @@ -1555,6 +1562,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3], loops, loop_to_poly, {reinterpret_cast(poly_normals), numPolys}, + Span(sharp_faces, sharp_faces ? numPolys : 0), Span(sharp_edges, sharp_edges ? numEdges : 0), check_angle, split_angle, @@ -1605,6 +1613,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], const int numLoops, const MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, const int numPolys, MutableSpan sharp_edges, short (*r_clnors_data)[2], @@ -1646,6 +1655,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], use_split_normals, split_angle, sharp_edges.data(), + sharp_faces, loop_to_poly.data(), &lnors_spacearr, nullptr); @@ -1774,6 +1784,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3], use_split_normals, split_angle, sharp_edges.data(), + sharp_faces, loop_to_poly.data(), &lnors_spacearr, nullptr); @@ -1848,6 +1859,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3], const int numLoops, const MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, const int numPolys, bool *sharp_edges, short (*r_clnors_data)[2]) @@ -1862,6 +1874,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3], numLoops, polys, poly_normals, + sharp_faces, numPolys, {sharp_edges, numEdges}, r_clnors_data, @@ -1878,6 +1891,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3 const int numLoops, const MPoly *polys, const float (*poly_normals)[3], + const bool *sharp_faces, const int numPolys, bool *sharp_edges, short (*r_clnors_data)[2]) @@ -1892,6 +1906,7 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3 numLoops, polys, poly_normals, + sharp_faces, numPolys, {sharp_edges, numEdges}, r_clnors_data, @@ -1921,7 +1936,8 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const MutableAttributeAccessor attributes = mesh->attributes_for_write(); SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); mesh_normals_loop_custom_set(reinterpret_cast(positions.data()), BKE_mesh_vert_normals_ensure(mesh), positions.size(), @@ -1932,6 +1948,7 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const loops.size(), polys.data(), BKE_mesh_poly_normals_ensure(mesh), + sharp_faces, polys.size(), sharp_edges.span, clnors, diff --git a/source/blender/blenkernel/intern/mesh_remap.cc b/source/blender/blenkernel/intern/mesh_remap.cc index 361616b67ab..733f649a4d6 100644 --- a/source/blender/blenkernel/intern/mesh_remap.cc +++ b/source/blender/blenkernel/intern/mesh_remap.cc @@ -1361,6 +1361,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, if (dirty_nors_dst || do_loop_nors_dst) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&mesh_dst->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh_dst->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_split(vert_positions_dst, BKE_mesh_vert_normals_ensure(mesh_dst), numverts_dst, @@ -1375,6 +1377,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, use_split_nors_dst, split_angle_dst, sharp_edges, + sharp_faces, nullptr, nullptr, custom_nors_dst); diff --git a/source/blender/blenkernel/intern/mesh_tangent.cc b/source/blender/blenkernel/intern/mesh_tangent.cc index ab7a5a2579e..9bb18f72507 100644 --- a/source/blender/blenkernel/intern/mesh_tangent.cc +++ b/source/blender/blenkernel/intern/mesh_tangent.cc @@ -240,7 +240,7 @@ struct SGLSLMeshToTangent { if (precomputedLoopNormals) { return mikk::float3(precomputedLoopNormals[loop_index]); } - if ((polys[lt->poly].flag & ME_SMOOTH) == 0) { /* flat */ + if (sharp_faces && sharp_faces[lt->poly]) { /* flat */ if (precomputedFaceNormals) { return mikk::float3(precomputedFaceNormals[lt->poly]); } @@ -285,6 +285,7 @@ struct SGLSLMeshToTangent { const float (*vert_normals)[3]; const float (*orco)[3]; float (*tangent)[4]; /* destination */ + const bool *sharp_faces; int numTessFaces; #ifdef USE_LOOPTRI_DETECT_QUADS @@ -394,6 +395,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], const MLoop *mloop, const MLoopTri *looptri, const uint looptri_len, + const bool *sharp_faces, CustomData *loopdata, bool calc_active_tangent, @@ -498,6 +500,7 @@ void BKE_mesh_calc_loop_tangent_ex(const float (*vert_positions)[3], mesh2tangent->polys = polys; mesh2tangent->mloop = mloop; mesh2tangent->looptri = looptri; + mesh2tangent->sharp_faces = sharp_faces; /* NOTE: we assume we do have tessellated loop normals at this point * (in case it is object-enabled), have to check this is valid. */ mesh2tangent->precomputedLoopNormals = loop_normals; @@ -583,6 +586,8 @@ void BKE_mesh_calc_loop_tangents(Mesh *me_eval, me_eval->loops().data(), looptris.data(), uint(looptris.size()), + static_cast( + CustomData_get_layer_named(&me_eval->pdata, CD_PROP_BOOL, "sharp_face")), &me_eval->ldata, calc_active_tangent, tangent_names, diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index cb45736d303..6837fcd3d8c 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -151,19 +151,27 @@ static void update_node_vb(PBVH *pbvh, PBVHNode *node) // BB_expand(&node->vb, co); //} -static bool face_materials_match(const PBVH *pbvh, const int a, const int b) +static bool face_materials_match(const PBVH *pbvh, + const bool *sharp_faces, + const int a, + const int b) { if (pbvh->material_indices) { if (pbvh->material_indices[a] != pbvh->material_indices[b]) { return false; } } - return (pbvh->polys[a].flag & ME_SMOOTH) == (pbvh->polys[b].flag & ME_SMOOTH); + if (sharp_faces) { + if (sharp_faces[a] != sharp_faces[b]) { + return false; + } + } + return true; } static bool grid_materials_match(const DMFlagMat *f1, const DMFlagMat *f2) { - return ((f1->flag & ME_SMOOTH) == (f2->flag & ME_SMOOTH) && (f1->mat_nr == f2->mat_nr)); + return (f1->sharp == f2->sharp) && (f1->mat_nr == f2->mat_nr); } /* Adapted from BLI_kdopbvh.c */ @@ -229,7 +237,7 @@ static int partition_indices_grids(int *prim_indices, } /* Returns the index of the first element on the right of the partition */ -static int partition_indices_material(PBVH *pbvh, int lo, int hi) +static int partition_indices_material(PBVH *pbvh, const bool *sharp_faces, int lo, int hi) { const MLoopTri *looptri = pbvh->looptri; const DMFlagMat *flagmats = pbvh->grid_flag_mats; @@ -239,10 +247,10 @@ static int partition_indices_material(PBVH *pbvh, int lo, int hi) for (;;) { if (pbvh->looptri) { const int first = looptri[pbvh->prim_indices[lo]].poly; - for (; face_materials_match(pbvh, first, looptri[indices[i]].poly); i++) { + for (; face_materials_match(pbvh, sharp_faces, first, looptri[indices[i]].poly); i++) { /* pass */ } - for (; !face_materials_match(pbvh, first, looptri[indices[j]].poly); j--) { + for (; !face_materials_match(pbvh, sharp_faces, first, looptri[indices[j]].poly); j--) { /* pass */ } } @@ -450,7 +458,7 @@ static void build_leaf(PBVH *pbvh, int node_index, BBC *prim_bbc, int offset, in /* Return zero if all primitives in the node can be drawn with the * same material (including flat/smooth shading), non-zero otherwise */ -static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) +static bool leaf_needs_material_split(PBVH *pbvh, const bool *sharp_faces, int offset, int count) { if (count <= 1) { return false; @@ -460,7 +468,7 @@ static bool leaf_needs_material_split(PBVH *pbvh, int offset, int count) const MLoopTri *first = &pbvh->looptri[pbvh->prim_indices[offset]]; for (int i = offset + count - 1; i > offset; i--) { int prim = pbvh->prim_indices[i]; - if (!face_materials_match(pbvh, first->poly, pbvh->looptri[prim].poly)) { + if (!face_materials_match(pbvh, sharp_faces, first->poly, pbvh->looptri[prim].poly)) { return true; } } @@ -539,6 +547,7 @@ static void test_face_boundaries(PBVH *pbvh) */ static void build_sub(PBVH *pbvh, + const bool *sharp_faces, int node_index, BB *cb, BBC *prim_bbc, @@ -557,7 +566,7 @@ static void build_sub(PBVH *pbvh, /* Decide whether this is a leaf or not */ const bool below_leaf_limit = count <= pbvh->leaf_limit || depth >= STACK_FIXED_DEPTH - 1; if (below_leaf_limit) { - if (!leaf_needs_material_split(pbvh, offset, count)) { + if (!leaf_needs_material_split(pbvh, sharp_faces, offset, count)) { build_leaf(pbvh, node_index, prim_bbc, offset, count); if (node_index == 0) { @@ -610,11 +619,12 @@ static void build_sub(PBVH *pbvh, } else { /* Partition primitives by material */ - end = partition_indices_material(pbvh, offset, offset + count - 1); + end = partition_indices_material(pbvh, sharp_faces, offset, offset + count - 1); } /* Build children */ build_sub(pbvh, + sharp_faces, pbvh->nodes[node_index].children_offset, nullptr, prim_bbc, @@ -623,6 +633,7 @@ static void build_sub(PBVH *pbvh, prim_scratch, depth + 1); build_sub(pbvh, + sharp_faces, pbvh->nodes[node_index].children_offset + 1, nullptr, prim_bbc, @@ -636,7 +647,7 @@ static void build_sub(PBVH *pbvh, } } -static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim) +static void pbvh_build(PBVH *pbvh, const bool *sharp_faces, BB *cb, BBC *prim_bbc, int totprim) { if (totprim != pbvh->totprim) { pbvh->totprim = totprim; @@ -659,7 +670,7 @@ static void pbvh_build(PBVH *pbvh, BB *cb, BBC *prim_bbc, int totprim) } pbvh->totnode = 1; - build_sub(pbvh, 0, cb, prim_bbc, 0, totprim, nullptr, 0); + build_sub(pbvh, sharp_faces, 0, cb, prim_bbc, 0, totprim, nullptr, 0); } static void pbvh_draw_args_init(PBVH *pbvh, PBVH_GPU_Args *args, PBVHNode *node) @@ -881,7 +892,9 @@ void BKE_pbvh_build_mesh(PBVH *pbvh, } if (looptri_num) { - pbvh_build(pbvh, &cb, prim_bbc, looptri_num); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); + pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, looptri_num); #ifdef TEST_PBVH_FACE_SPLIT test_face_boundaries(pbvh); @@ -968,7 +981,9 @@ void BKE_pbvh_build_grids(PBVH *pbvh, } if (totgrid) { - pbvh_build(pbvh, &cb, prim_bbc, totgrid); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); + pbvh_build(pbvh, sharp_faces, &cb, prim_bbc, totgrid); #ifdef TEST_PBVH_FACE_SPLIT test_face_boundaries(pbvh); diff --git a/source/blender/blenkernel/intern/shrinkwrap.cc b/source/blender/blenkernel/intern/shrinkwrap.cc index 6b010418e11..92531e10499 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.cc +++ b/source/blender/blenkernel/intern/shrinkwrap.cc @@ -116,6 +116,8 @@ bool BKE_shrinkwrap_init_tree( data->mesh = mesh; data->polys = mesh->polys().data(); data->vert_normals = BKE_mesh_vert_normals_ensure(mesh); + data->sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_face")); if (shrinkType == MOD_SHRINKWRAP_NEAREST_VERTEX) { data->bvh = BKE_bvhtree_from_mesh_get(&data->treeData, mesh, BVHTREE_FROM_VERTS, 2); @@ -1175,7 +1177,7 @@ void BKE_shrinkwrap_compute_smooth_normal(const ShrinkwrapTreeData *tree, const float(*vert_normals)[3] = tree->vert_normals; /* Interpolate smooth normals if enabled. */ - if ((tree->polys[tri->poly].flag & ME_SMOOTH) != 0) { + if (!(tree->sharp_faces && tree->sharp_faces[tri->poly])) { const uint32_t vert_indices[3] = {treeData->loop[tri->tri[0]].v, treeData->loop[tri->tri[1]].v, treeData->loop[tri->tri[2]].v}; diff --git a/source/blender/blenkernel/intern/subdiv_ccg_material.cc b/source/blender/blenkernel/intern/subdiv_ccg_material.cc index 9f03eca889f..a690da515ed 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg_material.cc +++ b/source/blender/blenkernel/intern/subdiv_ccg_material.cc @@ -15,7 +15,7 @@ struct CCGMaterialFromMeshData { const Mesh *mesh; - blender::Span polys; + const bool *sharp_faces; const int *material_indices; }; @@ -24,9 +24,8 @@ static DMFlagMat subdiv_ccg_material_flags_eval( { CCGMaterialFromMeshData *data = (CCGMaterialFromMeshData *)material_flags_evaluator->user_data; BLI_assert(coarse_face_index < data->mesh->totpoly); - const MPoly &poly = data->polys[coarse_face_index]; DMFlagMat material_flags; - material_flags.flag = poly.flag; + material_flags.sharp = data->sharp_faces && data->sharp_faces[coarse_face_index]; material_flags.mat_nr = data->material_indices ? data->material_indices[coarse_face_index] : 0; return material_flags; } @@ -45,7 +44,8 @@ void BKE_subdiv_ccg_material_flags_init_from_mesh( data->mesh = mesh; data->material_indices = (const int *)CustomData_get_layer_named( &mesh->pdata, CD_PROP_INT32, "material_index"); - data->polys = mesh->polys(); + data->sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); material_flags_evaluator->eval_material_flags = subdiv_ccg_material_flags_eval; material_flags_evaluator->free = subdiv_ccg_material_flags_free; material_flags_evaluator->user_data = data; diff --git a/source/blender/blenkernel/intern/subsurf_ccg.cc b/source/blender/blenkernel/intern/subsurf_ccg.cc index cbe26721cc9..923dd7a7788 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.cc +++ b/source/blender/blenkernel/intern/subsurf_ccg.cc @@ -1068,20 +1068,17 @@ static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *polys) int gridSize = ccgSubSurf_getGridSize(ss); /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */ int i = 0, k = 0; - DMFlagMat *faceFlags = ccgdm->faceFlags; totface = ccgSubSurf_getNumFaces(ss); for (index = 0; index < totface; index++) { CCGFace *f = ccgdm->faceMap[index].face; int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f); - char flag = (faceFlags) ? faceFlags[index].flag : char(ME_SMOOTH); for (S = 0; S < numVerts; S++) { for (y = 0; y < gridSize - 1; y++) { for (x = 0; x < gridSize - 1; x++) { polys[i].loopstart = k; polys[i].totloop = 4; - polys[i].flag = flag; k += 4; i++; @@ -1541,9 +1538,11 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, gridSideEdges = gridSize - 1; gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; - const MPoly *polys = static_cast(CustomData_get_layer(&dm->polyData, CD_MPOLY)); const int *material_indices = static_cast( CustomData_get_layer_named(&dm->polyData, CD_MPOLY, "material_index")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); + const int *base_polyOrigIndex = static_cast( CustomData_get_layer(&dm->polyData, CD_ORIGINDEX)); @@ -1569,7 +1568,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, ccgdm->faceMap[index].startEdge = edgeNum; ccgdm->faceMap[index].startFace = faceNum; - faceFlags->flag = polys ? polys[origIndex].flag : 0; + faceFlags->sharp = sharp_faces ? sharp_faces[origIndex] : false; faceFlags->mat_nr = material_indices ? material_indices[origIndex] : 0; faceFlags++; diff --git a/source/blender/blenkernel/intern/volume_to_mesh.cc b/source/blender/blenkernel/intern/volume_to_mesh.cc index 1aeedcd04c1..6395376bd14 100644 --- a/source/blender/blenkernel/intern/volume_to_mesh.cc +++ b/source/blender/blenkernel/intern/volume_to_mesh.cc @@ -180,6 +180,7 @@ Mesh *volume_to_mesh(const openvdb::GridBase &grid, mesh->loops_for_write()); BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/blenloader/intern/versioning_300.cc b/source/blender/blenloader/intern/versioning_300.cc index f451da4e419..45c5b40486d 100644 --- a/source/blender/blenloader/intern/versioning_300.cc +++ b/source/blender/blenloader/intern/versioning_300.cc @@ -14,6 +14,7 @@ #include "BLI_listbase.h" #include "BLI_math_vector.h" +#include "BLI_multi_value_map.hh" #include "BLI_path_util.h" #include "BLI_string.h" #include "BLI_string_utils.h" @@ -940,6 +941,139 @@ static void version_geometry_nodes_primitive_uv_maps(bNodeTree &ntree) } } +/** + * When extruding from loose edges, the extrude geometry node used to create flat faces due to the + * default of the old "shade_smooth" attribute. Since the "false" value has changed with the + * "sharp_face" attribute, add nodes to propagate the new attribute in its inverted "smooth" form. + */ +static void version_geometry_nodes_extrude_smooth_propagation(bNodeTree &ntree) +{ + using namespace blender; + Vector new_nodes; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) { + if (node->idname != StringRef("GeometryNodeExtrudeMesh")) { + continue; + } + if (static_cast(node->storage)->mode != + GEO_NODE_EXTRUDE_MESH_EDGES) { + continue; + } + bNodeSocket *geometry_in_socket = nodeFindSocket(node, SOCK_IN, "Mesh"); + bNodeSocket *geometry_out_socket = nodeFindSocket(node, SOCK_OUT, "Mesh"); + + Map in_links_per_socket; + MultiValueMap out_links_per_socket; + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + in_links_per_socket.add(link->tosock, link); + out_links_per_socket.add(link->fromsock, link); + } + + bNodeLink *geometry_in_link = in_links_per_socket.lookup_default(geometry_in_socket, nullptr); + Span geometry_out_links = out_links_per_socket.lookup(geometry_out_socket); + if (!geometry_in_link || geometry_out_links.is_empty()) { + continue; + } + + const bool versioning_already_done = [&]() { + if (geometry_in_link->fromnode->idname != StringRef("GeometryNodeCaptureAttribute")) { + return false; + } + bNode *capture_node = geometry_in_link->fromnode; + const NodeGeometryAttributeCapture &capture_storage = + *static_cast(capture_node->storage); + if (capture_storage.data_type != CD_PROP_BOOL || + capture_storage.domain != ATTR_DOMAIN_FACE) { + return false; + } + bNodeSocket *capture_in_socket = nodeFindSocket(capture_node, SOCK_IN, "Value_003"); + bNodeLink *capture_in_link = in_links_per_socket.lookup_default(capture_in_socket, nullptr); + if (!capture_in_link) { + return false; + } + if (capture_in_link->fromnode->idname != StringRef("GeometryNodeInputShadeSmooth")) { + return false; + } + if (geometry_out_links.size() != 1) { + return false; + } + bNodeLink *geometry_out_link = geometry_out_links.first(); + if (geometry_out_link->tonode->idname != StringRef("GeometryNodeSetShadeSmooth")) { + return false; + } + bNode *set_smooth_node = geometry_out_link->tonode; + bNodeSocket *smooth_in_socket = nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth"); + bNodeLink *connecting_link = in_links_per_socket.lookup_default(smooth_in_socket, nullptr); + if (!connecting_link) { + return false; + } + if (connecting_link->fromnode != capture_node) { + return false; + } + return true; + }(); + if (versioning_already_done) { + continue; + } + + bNode *capture_node = nodeAddNode(nullptr, &ntree, "GeometryNodeCaptureAttribute"); + capture_node->parent = node->parent; + capture_node->locx = node->locx - 25; + capture_node->locy = node->locy; + new_nodes.append(capture_node); + static_cast(capture_node->storage)->data_type = CD_PROP_BOOL; + static_cast(capture_node->storage)->domain = ATTR_DOMAIN_FACE; + + bNode *is_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeInputShadeSmooth"); + is_smooth_node->parent = node->parent; + is_smooth_node->locx = capture_node->locx - 25; + is_smooth_node->locy = capture_node->locy; + new_nodes.append(is_smooth_node); + nodeAddLink(&ntree, + is_smooth_node, + nodeFindSocket(is_smooth_node, SOCK_OUT, "Smooth"), + capture_node, + nodeFindSocket(capture_node, SOCK_IN, "Value_003")); + nodeAddLink(&ntree, + capture_node, + nodeFindSocket(capture_node, SOCK_OUT, "Geometry"), + capture_node, + geometry_in_socket); + geometry_in_link->tonode = capture_node; + geometry_in_link->tosock = nodeFindSocket(capture_node, SOCK_IN, "Geometry"); + + bNode *set_smooth_node = nodeAddNode(nullptr, &ntree, "GeometryNodeSetShadeSmooth"); + set_smooth_node->parent = node->parent; + set_smooth_node->locx = node->locx + 25; + set_smooth_node->locy = node->locy; + new_nodes.append(set_smooth_node); + nodeAddLink(&ntree, + node, + geometry_out_socket, + set_smooth_node, + nodeFindSocket(set_smooth_node, SOCK_IN, "Geometry")); + + bNodeSocket *smooth_geometry_out = nodeFindSocket(set_smooth_node, SOCK_OUT, "Geometry"); + for (bNodeLink *link : geometry_out_links) { + link->fromnode = set_smooth_node; + link->fromsock = smooth_geometry_out; + } + nodeAddLink(&ntree, + capture_node, + nodeFindSocket(capture_node, SOCK_OUT, "Attribute_003"), + set_smooth_node, + nodeFindSocket(set_smooth_node, SOCK_IN, "Shade Smooth")); + } + + /* Move nodes to the front so that they are drawn behind existing nodes. */ + for (bNode *node : new_nodes) { + BLI_remlink(&ntree.nodes, node); + BLI_addhead(&ntree.nodes, node); + } + if (!new_nodes.is_empty()) { + nodeRebuildIDVector(&ntree); + } +} + void do_versions_after_linking_300(FileData * /*fd*/, Main *bmain) { if (MAIN_VERSION_ATLEAST(bmain, 300, 0) && !MAIN_VERSION_ATLEAST(bmain, 300, 1)) { @@ -4047,5 +4181,10 @@ void blo_do_versions_300(FileData *fd, Library * /*lib*/, Main *bmain) } } /* Keep this block, even when empty. */ + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type == NTREE_GEOMETRY) { + version_geometry_nodes_extrude_smooth_propagation(*ntree); + } + } } } diff --git a/source/blender/blenloader/intern/versioning_400.cc b/source/blender/blenloader/intern/versioning_400.cc index e482fbe1d9f..b7465e37186 100644 --- a/source/blender/blenloader/intern/versioning_400.cc +++ b/source/blender/blenloader/intern/versioning_400.cc @@ -31,6 +31,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh) BKE_mesh_legacy_convert_flags_to_hide_layers(&mesh); BKE_mesh_legacy_convert_uvs_to_generic(&mesh); BKE_mesh_legacy_convert_mpoly_to_material_indices(&mesh); + BKE_mesh_legacy_sharp_faces_from_flags(&mesh); BKE_mesh_legacy_bevel_weight_to_layers(&mesh); BKE_mesh_legacy_sharp_edges_from_flags(&mesh); BKE_mesh_legacy_face_set_to_generic(&mesh); diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index c2484e30bf2..c5ac86c4448 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -113,18 +113,6 @@ using blender::Span; using blender::StringRef; using blender::Vector; -static char bm_face_flag_from_mflag(const char mflag) -{ - return ((mflag & ME_SMOOTH) ? BM_ELEM_SMOOTH : 0); -} - -static char bm_face_flag_to_mflag(const BMFace *f) -{ - const char hflag = f->head.hflag; - - return ((hflag & BM_ELEM_SMOOTH) ? ME_SMOOTH : 0); -} - bool BM_attribute_stored_in_bmesh_builtin(const StringRef name) { return ELEM(name, @@ -137,6 +125,7 @@ bool BM_attribute_stored_in_bmesh_builtin(const StringRef name) ".select_edge", ".select_poly", "material_index", + "sharp_face", "sharp_edge"); } @@ -426,6 +415,8 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar &me->pdata, CD_PROP_BOOL, ".hide_poly"); const int *material_indices = (const int *)CustomData_get_layer_named( &me->pdata, CD_PROP_INT32, "material_index"); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); const bool *sharp_edges = (const bool *)CustomData_get_layer_named( &me->edata, CD_PROP_BOOL, "sharp_edge"); const bool *uv_seams = (const bool *)CustomData_get_layer_named( @@ -527,7 +518,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar BM_elem_index_set(f, bm->totface - 1); /* set_ok */ /* Transfer flag. */ - f->head.hflag = bm_face_flag_from_mflag(polys[i].flag); + if (!(sharp_faces && sharp_faces[i])) { + BM_elem_flag_enable(f, BM_ELEM_SMOOTH); + } if (hide_poly && hide_poly[i]) { BM_elem_flag_enable(f, BM_ELEM_HIDDEN); } @@ -1252,6 +1245,7 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh bool need_hide_edge = false; bool need_hide_poly = false; bool need_material_index = false; + bool need_sharp_face = false; bool need_sharp_edge = false; bool need_uv_seam = false; @@ -1312,7 +1306,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh if (f->mat_nr != 0) { need_material_index = true; } - polys[i].flag = bm_face_flag_to_mflag(f); + if (!BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + need_sharp_face = true; + } if (BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { need_hide_poly = true; } @@ -1357,6 +1353,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH); }); } + if (need_sharp_face) { + BM_mesh_elem_table_ensure(bm, BM_FACE); + write_fn_to_attribute( + me->attributes_for_write(), "sharp_face", ATTR_DOMAIN_FACE, [&](const int i) { + return !BM_elem_flag_test(BM_face_at_index(bm, i), BM_ELEM_SMOOTH); + }); + } if (need_uv_seam) { BM_mesh_elem_table_ensure(bm, BM_EDGE); write_fn_to_attribute( @@ -1524,6 +1527,7 @@ static void bm_face_loop_table_build(BMesh &bm, MutableSpan loop_table, bool &need_select_poly, bool &need_hide_poly, + bool &need_sharp_face, bool &need_material_index) { char hflag = 0; @@ -1535,6 +1539,7 @@ static void bm_face_loop_table_build(BMesh &bm, BM_elem_index_set(face, face_i); /* set_inline */ face_table[face_i] = face; hflag |= face->head.hflag; + need_sharp_face |= (face->head.hflag & BM_ELEM_SMOOTH) == 0; need_material_index |= face->mat_nr != 0; BMLoop *loop = BM_FACE_FIRST_LOOP(face); @@ -1622,6 +1627,7 @@ static void bm_to_mesh_faces(const BMesh &bm, Mesh &mesh, MutableSpan select_poly, MutableSpan hide_poly, + MutableSpan sharp_faces, MutableSpan material_indices) { const Vector info = bm_to_mesh_copy_info_calc(bm.pdata, mesh.pdata); @@ -1632,7 +1638,6 @@ static void bm_to_mesh_faces(const BMesh &bm, MPoly &dst_poly = dst_polys[face_i]; dst_poly.totloop = src_face.len; dst_poly.loopstart = BM_elem_index_get(BM_FACE_FIRST_LOOP(&src_face)); - dst_poly.flag = bm_face_flag_to_mflag(&src_face); bmesh_block_copy_to_mesh_attributes(info, face_i, src_face.head.data); } if (!select_poly.is_empty()) { @@ -1650,6 +1655,11 @@ static void bm_to_mesh_faces(const BMesh &bm, material_indices[face_i] = bm_faces[face_i]->mat_nr; } } + if (!sharp_faces.is_empty()) { + for (const int face_i : range) { + sharp_faces[face_i] = !BM_elem_flag_test(bm_faces[face_i], BM_ELEM_SMOOTH); + } + } }); } @@ -1721,6 +1731,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bool need_hide_poly = false; bool need_material_index = false; bool need_sharp_edge = false; + bool need_sharp_face = false; bool need_uv_seams = false; Array vert_table; Array edge_table; @@ -1740,8 +1751,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * [&]() { face_table.reinitialize(bm->totface); loop_table.reinitialize(bm->totloop); - bm_face_loop_table_build( - *bm, face_table, loop_table, need_select_poly, need_hide_poly, need_material_index); + bm_face_loop_table_build(*bm, + face_table, + loop_table, + need_select_poly, + need_hide_poly, + need_sharp_face, + need_material_index); }); bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE | BM_LOOP); @@ -1756,6 +1772,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bke::SpanAttributeWriter uv_seams; bke::SpanAttributeWriter select_poly; bke::SpanAttributeWriter hide_poly; + bke::SpanAttributeWriter sharp_face; bke::SpanAttributeWriter material_index; if (need_select_vert) { select_vert = attrs.lookup_or_add_for_write_only_span(".select_vert", ATTR_DOMAIN_POINT); @@ -1781,6 +1798,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * if (need_hide_poly) { hide_poly = attrs.lookup_or_add_for_write_only_span(".hide_poly", ATTR_DOMAIN_FACE); } + if (need_sharp_face) { + sharp_face = attrs.lookup_or_add_for_write_only_span("sharp_face", ATTR_DOMAIN_FACE); + } if (need_material_index) { material_index = attrs.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); @@ -1800,8 +1820,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * uv_seams.span); }, [&]() { - bm_to_mesh_faces( - *bm, face_table, *me, select_poly.span, hide_poly.span, material_index.span); + bm_to_mesh_faces(*bm, + face_table, + *me, + select_poly.span, + hide_poly.span, + sharp_face.span, + material_index.span); }, [&]() { bm_to_mesh_loops(*bm, loop_table, *me); }); @@ -1813,5 +1838,6 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * uv_seams.finish(); select_poly.finish(); hide_poly.finish(); + sharp_face.finish(); material_index.finish(); } diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 4d844e3fb0d..6fba9eed4e9 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -383,6 +383,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_ is_auto_smooth, split_angle, sharp_edges, + mr->sharp_faces, nullptr, nullptr, clnors); @@ -573,6 +574,9 @@ MeshRenderData *mesh_render_data_create(Object *object, CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, ".select_edge")); mr->select_poly = static_cast( CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, ".select_poly")); + + mr->sharp_faces = static_cast( + CustomData_get_layer_named(&mr->me->pdata, CD_PROP_BOOL, "sharp_face")); } else { /* #BMesh */ diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index d2af318bd6b..bba4ecd050a 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -757,7 +757,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mesh(const MeshRenderData * const Span polys = mesh->polys(); for (const int i : polys.index_range()) { uint32_t flag = 0; - if ((polys[i].flag & ME_SMOOTH) != 0) { + if (!(mr->sharp_faces && mr->sharp_faces[i])) { flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH; } if (mr->select_poly && mr->select_poly[i]) { @@ -786,7 +786,7 @@ static void draw_subdiv_cache_extra_coarse_face_data_mapped(Mesh *mesh, /* Selection and hiding from bmesh. */ uint32_t flag = (f) ? compute_coarse_face_flag_bm(f, mr->efa_act) : 0; /* Smooth from mesh. */ - if ((polys[i].flag & ME_SMOOTH) != 0) { + if (!(mr->sharp_faces && mr->sharp_faces[i])) { flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH; } flags_data[i] = uint(polys[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET); diff --git a/source/blender/draw/intern/draw_pbvh.cc b/source/blender/draw/intern/draw_pbvh.cc index dea095c1b71..d3450e14ab7 100644 --- a/source/blender/draw/intern/draw_pbvh.cc +++ b/source/blender/draw/intern/draw_pbvh.cc @@ -336,15 +336,17 @@ struct PBVHBatches { float fno[3]; short no[3]; int last_poly = -1; - bool smooth = false; + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(args->pdata, CD_PROP_BOOL, "sharp_face")); foreach_faces([&](int /*buffer_i*/, int /*tri_i*/, int vertex_i, const MLoopTri *tri) { + bool smooth = false; if (tri->poly != last_poly) { last_poly = tri->poly; - const MPoly &poly = args->polys[tri->poly]; - if (!(poly.flag & ME_SMOOTH)) { + if (sharp_faces && sharp_faces[tri->poly]) { smooth = true; + const MPoly &poly = args->polys[tri->poly]; BKE_mesh_calc_poly_normal( &poly, args->mloop + poly.loopstart, args->vert_positions, fno); normal_float_to_short_v3(no, fno); @@ -409,7 +411,7 @@ struct PBVHBatches { foreach_grids([&](int /*x*/, int /*y*/, int grid_index, CCGElem *elems[4], int /*i*/) { float3 no(0.0f, 0.0f, 0.0f); - const bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + const bool smooth = !args->grid_flag_mats[grid_index].sharp; if (smooth) { no = CCG_elem_no(&args->ccg_key, elems[0]); @@ -1085,7 +1087,7 @@ struct PBVHBatches { for (int i : IndexRange(args->totprim)) { int grid_index = args->grid_indices[i]; - bool smooth = args->grid_flag_mats[grid_index].flag & ME_SMOOTH; + bool smooth = !args->grid_flag_mats[grid_index].sharp; BLI_bitmap *gh = args->grid_hidden[grid_index]; for (int y = 0; y < gridsize - 1; y += skip) { diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh index 81ab8b6bd1a..bab2123dc11 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.hh +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.hh @@ -94,6 +94,7 @@ struct MeshRenderData { const bool *select_vert; const bool *select_edge; const bool *select_poly; + const bool *sharp_faces; float (*loop_normals)[3]; int *lverts, *ledges; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 4c69a66d152..cefd6438477 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -71,11 +71,11 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, if (mr->loop_normals) { *lnor_data = GPU_normal_convert_i10_v3(mr->loop_normals[ml_index]); } - else if (poly->flag & ME_SMOOTH) { - *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]); + else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { + *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]); } else { - *lnor_data = GPU_normal_convert_i10_v3(mr->poly_normals[poly_index]); + *lnor_data = GPU_normal_convert_i10_v3(mr->vert_normals[ml->v]); } /* Flag for paint mode overlay. @@ -195,11 +195,11 @@ static void extract_lnor_hq_iter_poly_mesh(const MeshRenderData *mr, if (mr->loop_normals) { normal_float_to_short_v3(&lnor_data->x, mr->loop_normals[ml_index]); } - else if (poly->flag & ME_SMOOTH) { - normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]); + else if (mr->sharp_faces && mr->sharp_faces[poly_index]) { + normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]); } else { - normal_float_to_short_v3(&lnor_data->x, mr->poly_normals[poly_index]); + normal_float_to_short_v3(&lnor_data->x, mr->vert_normals[ml->v]); } /* Flag for paint mode overlay. diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc index 336a785103e..24fd7e9abd6 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_tan.cc @@ -120,6 +120,7 @@ static void extract_tan_init_common(const MeshRenderData *mr, mr->loops.data(), mr->looptris.data(), mr->tri_len, + mr->sharp_faces, cd_ldata, calc_active_tangent, r_tangent_names, diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 52f67860c90..17d106e70cf 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -800,11 +800,14 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator bke::MutableAttributeAccessor attributes = me->attributes_for_write(); bke::SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( "sharp_edge", ATTR_DOMAIN_EDGE); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&me->pdata, CD_PROP_BOOL, "sharp_face")); BKE_edges_sharp_from_angle_set(me->totedge, loops.data(), loops.size(), polys.data(), BKE_mesh_poly_normals_ensure(me), + sharp_faces, polys.size(), me->smoothresh, sharp_edges.span.data()); @@ -1468,6 +1471,8 @@ void ED_mesh_split_faces(Mesh *mesh) const bke::AttributeAccessor attributes = mesh->attributes(); const VArray mesh_sharp_edges = attributes.lookup_or_default( "sharp_edge", ATTR_DOMAIN_EDGE, false); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); Array sharp_edges(mesh->totedge); mesh_sharp_edges.materialize(sharp_edges); @@ -1477,6 +1482,7 @@ void ED_mesh_split_faces(Mesh *mesh) loops.size(), polys.data(), BKE_mesh_poly_normals_ensure(mesh), + sharp_faces, polys.size(), split_angle, sharp_edges.data()); @@ -1484,7 +1490,7 @@ void ED_mesh_split_faces(Mesh *mesh) threading::parallel_for(polys.index_range(), 1024, [&](const IndexRange range) { for (const int poly_i : range) { const MPoly &poly = polys[poly_i]; - if (!(poly.flag & ME_SMOOTH)) { + if (sharp_faces && sharp_faces[poly_i]) { for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { sharp_edges[loop.e] = true; } diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index dd1ea454a66..b76af724e62 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -25,6 +25,7 @@ #include "BLT_translation.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_customdata.h" #include "BKE_global.h" @@ -118,6 +119,7 @@ static bool object_remesh_poll(bContext *C) static int voxel_remesh_exec(bContext *C, wmOperator *op) { + using namespace blender; Object *ob = CTX_data_active_object(C); Mesh *mesh = static_cast(ob->data); @@ -132,8 +134,10 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) } /* Output mesh will be all smooth or all flat shading. */ - const Span polys = mesh->polys(); - const bool smooth_normals = polys.first().flag & ME_SMOOTH; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + const bool smooth_normals = !sharp_faces[0]; float isovalue = 0.0f; if (mesh->flag & ME_REMESH_REPROJECT_VOLUME) { @@ -176,9 +180,7 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob); - if (smooth_normals) { - BKE_mesh_smooth_flag_set(static_cast(ob->data), true); - } + BKE_mesh_smooth_flag_set(static_cast(ob->data), smooth_normals); if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_end(ob); @@ -898,9 +900,7 @@ static void quadriflow_start_job(void *customdata, bool *stop, bool *do_update, BKE_mesh_nomain_to_mesh(new_mesh, mesh, ob); - if (qj->smooth_normals) { - BKE_mesh_smooth_flag_set(static_cast(ob->data), true); - } + BKE_mesh_smooth_flag_set(static_cast(ob->data), qj->smooth_normals); if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_end(ob); diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.cc b/source/blender/editors/sculpt_paint/paint_image_proj.cc index 260eda97262..06000be7f50 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.cc +++ b/source/blender/editors/sculpt_paint/paint_image_proj.cc @@ -419,6 +419,7 @@ struct ProjPaintState { blender::Span loops_eval; const bool *select_poly_eval; const int *material_indices; + const bool *sharp_faces_eval; blender::Span looptris_eval; const float (*mloopuv_stencil_eval)[2]; @@ -1721,10 +1722,9 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps, if (ps->do_mask_normal) { const MLoopTri *lt = &ps->looptris_eval[tri_index]; const int lt_vtri[3] = {PS_LOOPTRI_AS_VERT_INDEX_3(ps, lt)}; - const MPoly &poly = ps->polys_eval[lt->poly]; float no[3], angle_cos; - if (poly.flag & ME_SMOOTH) { + if (!(ps->sharp_faces_eval && ps->sharp_faces_eval[lt->poly])) { const float *no1, *no2, *no3; no1 = ps->vert_normals[lt_vtri[0]]; no2 = ps->vert_normals[lt_vtri[1]]; @@ -4079,6 +4079,8 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p &ps->me_eval->pdata, CD_PROP_BOOL, ".select_poly"); ps->material_indices = (const int *)CustomData_get_layer_named( &ps->me_eval->pdata, CD_PROP_INT32, "material_index"); + ps->sharp_faces_eval = static_cast( + CustomData_get_layer_named(&ps->me_eval->pdata, CD_PROP_BOOL, "sharp_face")); ps->totvert_eval = ps->me_eval->totvert; ps->totedge_eval = ps->me_eval->totedge; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp index 6526dd68d9c..eac5de3b150 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderFileLoader.cpp @@ -400,6 +400,7 @@ static bool testEdgeMark(Mesh *me, const FreestyleEdge *fed, const MLoopTri *lt, void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) { + using namespace blender; char *name = ob->id.name + 2; const Span vert_positions = me->vert_positions(); @@ -514,14 +515,16 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) FrsMaterial tmpMat; - const blender::VArray material_indices = me->attributes().lookup_or_default( + const bke::AttributeAccessor attributes = me->attributes(); + const VArray material_indices = attributes.lookup_or_default( "material_index", ATTR_DOMAIN_FACE, 0); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); // We parse the vlak nodes again and import meshes while applying the clipping // by the near and far view planes. for (int a = 0; a < tottri; a++) { const MLoopTri *lt = &mlooptri[a]; - const MPoly *poly = &mesh_polys[lt->poly]; Material *mat = BKE_object_material_get(ob, material_indices[lt->poly] + 1); copy_v3_v3(v1, vert_positions[mesh_loops[lt->tri[0]].v]); @@ -536,7 +539,7 @@ void BlenderFileLoader::insertShapeNode(Object *ob, Mesh *me, int id) v2[2] += _z_offset; v3[2] += _z_offset; - if (_smooth && (poly->flag & ME_SMOOTH) && lnors) { + if (_smooth && (!sharp_faces[lt->poly]) && lnors) { copy_v3_v3(n1, lnors[lt->tri[0]]); copy_v3_v3(n2, lnors[lt->tri[1]]); copy_v3_v3(n3, lnors[lt->tri[2]]); diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc index 052cd4c5171..6743ff9178c 100644 --- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc +++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc @@ -407,6 +407,7 @@ Mesh *create_cuboid_mesh(const float3 &size, MutableSpan positions = mesh->vert_positions_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); calculate_positions(config, positions); diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index 6359dc7a2aa..142e62ca8ec 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -846,7 +846,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate( options.propagation_info, attributes_to_propagate); attributes_to_propagate.remove("position"); - attributes_to_propagate.remove("shade_smooth"); r_create_id = attributes_to_propagate.pop_try("id").has_value(); r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value(); OrderedAttributes ordered_attributes; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc index 046e480e0eb..c0890df8aea 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.cc @@ -1481,6 +1481,7 @@ struct EdgeFeatData { blender::Span looptris; LineartTriangle *tri_array; blender::VArray sharp_edges; + blender::VArray sharp_faces; LineartVert *v_array; float crease_threshold; bool use_auto_smooth; @@ -1648,8 +1649,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata, if (ld->conf.use_crease) { bool do_crease = true; if (!ld->conf.force_crease && !e_feat_data->use_auto_smooth && - (e_feat_data->polys[looptris[f1].poly].flag & ME_SMOOTH) && - (e_feat_data->polys[looptris[f2].poly].flag & ME_SMOOTH)) { + (!e_feat_data->sharp_faces[looptris[f1].poly]) && + (!e_feat_data->sharp_faces[looptris[f2].poly])) { do_crease = false; } if (do_crease && (dot_v3v3_db(tri1->gn, tri2->gn) < e_feat_data->crease_threshold)) { @@ -2092,6 +2093,8 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, const bke::AttributeAccessor attributes = me->attributes(); const VArray sharp_edges = attributes.lookup_or_default( "sharp_edge", ATTR_DOMAIN_EDGE, false); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); EdgeFeatData edge_feat_data = {nullptr}; edge_feat_data.ld = la_data; @@ -2103,6 +2106,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info, edge_feat_data.loops = me->loops(); edge_feat_data.looptris = looptris; edge_feat_data.sharp_edges = sharp_edges; + edge_feat_data.sharp_faces = sharp_faces; edge_feat_data.edge_nabr = lineart_build_edge_neighbor(me, total_edges); edge_feat_data.tri_array = la_tri_arr; edge_feat_data.v_array = la_v_arr; diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 7dab627acc2..312aff79191 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -451,7 +451,15 @@ static void get_topology(struct Mesh *mesh, { const Span polys = mesh->polys(); const Span loops = mesh->loops(); - r_has_flat_shaded_poly = false; + const bke::AttributeAccessor attributes = mesh->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + for (const int i : sharp_faces.index_range()) { + if (sharp_faces[i]) { + r_has_flat_shaded_poly = true; + break; + } + } poly_verts.clear(); loop_counts.clear(); @@ -463,8 +471,6 @@ static void get_topology(struct Mesh *mesh, const MPoly &poly = polys[i]; loop_counts.push_back(poly.totloop); - r_has_flat_shaded_poly |= (poly.flag & ME_SMOOTH) == 0; - const MLoop *loop = &loops[poly.loopstart + (poly.totloop - 1)]; for (int j = 0; j < poly.totloop; j++, loop--) { diff --git a/source/blender/io/alembic/intern/abc_reader_mesh.cc b/source/blender/io/alembic/intern/abc_reader_mesh.cc index ba2259ad322..3789b656468 100644 --- a/source/blender/io/alembic/intern/abc_reader_mesh.cc +++ b/source/blender/io/alembic/intern/abc_reader_mesh.cc @@ -203,7 +203,6 @@ static void read_mpolys(CDStreamConfig &config, const AbcMeshData &mesh_data) /* Polygons are always assumed to be smooth-shaded. If the Alembic mesh should be flat-shaded, * this is encoded in custom loop normals. See #71246. */ - poly.flag |= ME_SMOOTH; /* NOTE: Alembic data is stored in the reverse order. */ rev_loop_index = loop_index + (face_size - 1); diff --git a/source/blender/io/collada/GeometryExporter.cpp b/source/blender/io/collada/GeometryExporter.cpp index c68bac9e627..fd6f66187c4 100644 --- a/source/blender/io/collada/GeometryExporter.cpp +++ b/source/blender/io/collada/GeometryExporter.cpp @@ -615,6 +615,7 @@ void GeometryExporter::create_normals(std::vector &normals, std::vector &polygons_normals, Mesh *me) { + using namespace blender; std::map shared_normal_indices; int last_normal_index = -1; @@ -625,6 +626,10 @@ void GeometryExporter::create_normals(std::vector &normals, const float(*lnors)[3] = nullptr; bool use_custom_normals = false; + const bke::AttributeAccessor attributes = me->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); + BKE_mesh_calc_normals_split(me); if (CustomData_has_layer(&me->ldata, CD_NORMAL)) { lnors = (float(*)[3])CustomData_get_layer(&me->ldata, CD_NORMAL); @@ -633,7 +638,7 @@ void GeometryExporter::create_normals(std::vector &normals, for (const int poly_index : polys.index_range()) { const MPoly *poly = &polys[poly_index]; - bool use_vert_normals = use_custom_normals || poly->flag & ME_SMOOTH; + bool use_vert_normals = use_custom_normals || !sharp_faces[poly_index]; if (!use_vert_normals) { /* For flat faces use face normal as vertex normal: */ diff --git a/source/blender/io/collada/MeshImporter.cpp b/source/blender/io/collada/MeshImporter.cpp index 7290d2c76de..110ad37384c 100644 --- a/source/blender/io/collada/MeshImporter.cpp +++ b/source/blender/io/collada/MeshImporter.cpp @@ -617,6 +617,12 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, MaterialIdPrimitiveArrayMap mat_prim_map; int *material_indices = BKE_mesh_material_indices_for_write(me); + bool *sharp_faces = static_cast( + CustomData_get_layer_named_for_write(&me->pdata, CD_PROP_BOOL, "sharp_face", me->totpoly)); + if (!sharp_faces) { + sharp_faces = static_cast(CustomData_add_layer_named( + &me->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, me->totpoly, "sharp_face")); + } COLLADAFW::MeshPrimitiveArray &prim_arr = collada_mesh->getMeshPrimitives(); COLLADAFW::MeshVertexData &nor = collada_mesh->getNormals(); @@ -659,9 +665,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, if (mp_has_normals) { /* vertex normals, same implementation as for the triangles */ /* The same for vertices normals. */ uint vertex_normal_indices[3] = {first_normal, normal_indices[1], normal_indices[2]}; - if (!is_flat_face(vertex_normal_indices, nor, 3)) { - polys[poly_index].flag |= ME_SMOOTH; - } + sharp_faces[poly_index] = is_flat_face(vertex_normal_indices, nor, 3); normal_indices++; } @@ -729,9 +733,7 @@ void MeshImporter::read_polys(COLLADAFW::Mesh *collada_mesh, if (mp_has_normals) { /* If it turns out that we have complete custom normals for each MPoly * and we want to use custom normals, this will be overridden. */ - if (!is_flat_face(normal_indices, nor, vcount)) { - polys[poly_index].flag |= ME_SMOOTH; - } + sharp_faces[poly_index] = is_flat_face(normal_indices, nor, vcount); if (use_custom_normals) { /* Store the custom normals for later application. */ diff --git a/source/blender/io/ply/importer/ply_import_mesh.cc b/source/blender/io/ply/importer/ply_import_mesh.cc index b281af75d3d..49a99e458e1 100644 --- a/source/blender/io/ply/importer/ply_import_mesh.cc +++ b/source/blender/io/ply/importer/ply_import_mesh.cc @@ -121,6 +121,8 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶ } } + BKE_mesh_smooth_flag_set(mesh, false); + return mesh; } } // namespace blender::io::ply diff --git a/source/blender/io/usd/intern/usd_reader_mesh.cc b/source/blender/io/usd/intern/usd_reader_mesh.cc index cd452f972b4..88aeeac3314 100644 --- a/source/blender/io/usd/intern/usd_reader_mesh.cc +++ b/source/blender/io/usd/intern/usd_reader_mesh.cc @@ -277,7 +277,6 @@ void USDMeshReader::read_mpolys(Mesh *mesh) /* Polygons are always assumed to be smooth-shaded. If the mesh should be flat-shaded, * this is encoded in custom loop normals. */ - poly.flag |= ME_SMOOTH; if (is_left_handed_) { int loop_end_index = loop_index + (face_size - 1); diff --git a/source/blender/io/usd/intern/usd_reader_shape.cc b/source/blender/io/usd/intern/usd_reader_shape.cc index 19df18c8b02..3ebddedf208 100644 --- a/source/blender/io/usd/intern/usd_reader_shape.cc +++ b/source/blender/io/usd/intern/usd_reader_shape.cc @@ -145,7 +145,8 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh, MutableSpan polys = active_mesh->polys_for_write(); MutableSpan loops = active_mesh->loops_for_write(); - const char should_smooth = prim_.IsA() ? 0 : ME_SMOOTH; + /* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */ + BKE_mesh_smooth_flag_set(active_mesh, !prim_.IsA()); int loop_index = 0; for (int i = 0; i < face_counts.size(); i++) { @@ -155,9 +156,6 @@ Mesh *USDShapeReader::read_mesh(struct Mesh *existing_mesh, poly.loopstart = loop_index; poly.totloop = face_size; - /* Don't smooth-shade cubes; we're not worrying about sharpness for Gprims. */ - poly.flag |= should_smooth; - for (int f = 0; f < face_size; ++f, ++loop_index) { loops[loop_index].v = face_indices[loop_index]; } diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 9472946e680..6dd1ec80ae8 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -440,12 +440,15 @@ void USDGenericMeshWriter::write_normals(const Mesh *mesh, pxr::UsdGeomMesh usd_ } else { /* Compute the loop normals based on the 'smooth' flag. */ + bke::AttributeAccessor attributes = mesh->attributes(); const float(*vert_normals)[3] = BKE_mesh_vert_normals_ensure(mesh); const float(*face_normals)[3] = BKE_mesh_poly_normals_ensure(mesh); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); for (const int i : polys.index_range()) { const MPoly &poly = polys[i]; - if ((poly.flag & ME_SMOOTH) == 0) { + if (sharp_faces[i]) { /* Flat shaded, use common normal for all verts. */ pxr::GfVec3f pxr_normal(face_normals[i]); for (int loop_idx = 0; loop_idx < poly.totloop; ++loop_idx) { diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc index d915fcc8aa9..0696ac29137 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -44,6 +44,8 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj mesh_edges_ = export_mesh_->edges(); mesh_polys_ = export_mesh_->polys(); mesh_loops_ = export_mesh_->loops(); + sharp_faces_ = export_mesh_->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); } else { /* Curves and NURBS surfaces need a new mesh when they're @@ -76,6 +78,8 @@ void OBJMesh::set_mesh(Mesh *mesh) mesh_edges_ = mesh->edges(); mesh_polys_ = mesh->polys(); mesh_loops_ = mesh->loops(); + sharp_faces_ = export_mesh_->attributes().lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); } void OBJMesh::clear() @@ -194,12 +198,15 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags) { const bool *sharp_edges = static_cast( CustomData_get_layer_named(&export_mesh_->edata, CD_PROP_BOOL, "sharp_edge")); + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&export_mesh_->pdata, CD_PROP_BOOL, "sharp_face")); poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(), mesh_polys_.data(), mesh_polys_.size(), mesh_loops_.data(), mesh_loops_.size(), sharp_edges, + sharp_faces, &tot_smooth_groups_, use_bitflags); } @@ -245,7 +252,7 @@ const Material *OBJMesh::get_object_material(const int16_t mat_nr) const bool OBJMesh::is_ith_poly_smooth(const int poly_index) const { - return mesh_polys_[poly_index].flag & ME_SMOOTH; + return !sharp_faces_[poly_index]; } const char *OBJMesh::get_object_name() const @@ -399,7 +406,7 @@ void OBJMesh::store_normal_coords_and_indices() CustomData_get_layer(&export_mesh_->ldata, CD_NORMAL)); for (int poly_index = 0; poly_index < export_mesh_->totpoly; ++poly_index) { const MPoly &poly = mesh_polys_[poly_index]; - bool need_per_loop_normals = lnors != nullptr || (poly.flag & ME_SMOOTH); + bool need_per_loop_normals = lnors != nullptr || !(sharp_faces_[poly_index]); if (need_per_loop_normals) { for (int loop_of_poly = 0; loop_of_poly < poly.totloop; ++loop_of_poly) { float3 loop_normal; diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh index 0c151cb4454..21d212f5575 100644 --- a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -11,6 +11,7 @@ #include "BLI_math_vector_types.hh" #include "BLI_utility_mixins.hh" #include "BLI_vector.hh" +#include "BLI_virtual_array.hh" #include "DNA_material_types.h" #include "DNA_mesh_types.h" @@ -40,6 +41,7 @@ class OBJMesh : NonCopyable { Span mesh_edges_; Span mesh_polys_; Span mesh_loops_; + VArray sharp_faces_; /** * Final transform of an object obtained from export settings (up_axis, forward_axis) and the diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc index e68d4fc54fb..c572e465aa6 100644 --- a/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc +++ b/source/blender/io/wavefront_obj/importer/obj_import_mesh.cc @@ -185,9 +185,11 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + bke::MutableAttributeAccessor attributes = mesh->attributes_for_write(); bke::SpanAttributeWriter material_indices = - mesh->attributes_for_write().lookup_or_add_for_write_only_span("material_index", - ATTR_DOMAIN_FACE); + attributes.lookup_or_add_for_write_only_span("material_index", ATTR_DOMAIN_FACE); + bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); const int64_t tot_face_elems{mesh->totpoly}; int tot_loop_idx = 0; @@ -203,9 +205,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) MPoly &poly = polys[poly_idx]; poly.totloop = curr_face.corner_count_; poly.loopstart = tot_loop_idx; - if (curr_face.shaded_smooth) { - poly.flag |= ME_SMOOTH; - } + sharp_faces.span[poly_idx] = !curr_face.shaded_smooth; material_indices.span[poly_idx] = curr_face.material_index; /* Importing obj files without any materials would result in negative indices, which is not * supported. */ @@ -233,6 +233,7 @@ void MeshFromGeometry::create_polys_loops(Mesh *mesh, bool use_vertex_groups) } material_indices.finish(); + sharp_faces.finish(); } void MeshFromGeometry::create_vertex_groups(Object *obj) diff --git a/source/blender/makesdna/DNA_meshdata_types.h b/source/blender/makesdna/DNA_meshdata_types.h index 7bb2c3fbd54..e2bfef9629d 100644 --- a/source/blender/makesdna/DNA_meshdata_types.h +++ b/source/blender/makesdna/DNA_meshdata_types.h @@ -63,19 +63,20 @@ typedef struct MPoly { int totloop; /** Deprecated material index. Now stored in the "material_index" attribute, but kept for IO. */ short mat_nr_legacy; - char flag, _pad; + char flag_legacy, _pad; } MPoly; /** #MPoly.flag */ -enum { - ME_SMOOTH = (1 << 0), #ifdef DNA_DEPRECATED_ALLOW +enum { + /** Deprecated smooth shading status. Now stored reversed in "sharp_face" attribute. */ + ME_SMOOTH = (1 << 0), /** Deprecated selection status. Now stored in ".select_poly" attribute. */ ME_FACE_SEL = (1 << 1), -#endif /** Deprecated hide status. Now stored in ".hide_poly" attribute. */ /* ME_HIDE = (1 << 4), */ }; +#endif /** * Mesh Face Corners. diff --git a/source/blender/makesdna/intern/dna_rename_defs.h b/source/blender/makesdna/intern/dna_rename_defs.h index e1386dbab79..3318603ffd3 100644 --- a/source/blender/makesdna/intern/dna_rename_defs.h +++ b/source/blender/makesdna/intern/dna_rename_defs.h @@ -90,6 +90,7 @@ DNA_STRUCT_RENAME_ELEM(MDefCell, totinfluence, influences_num) DNA_STRUCT_RENAME_ELEM(MEdge, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, crease, crease_legacy) DNA_STRUCT_RENAME_ELEM(MEdge, flag, flag_legacy) +DNA_STRUCT_RENAME_ELEM(MPoly, flag, flag_legacy) DNA_STRUCT_RENAME_ELEM(MPoly, mat_nr, mat_nr_legacy) DNA_STRUCT_RENAME_ELEM(MVert, bweight, bweight_legacy) DNA_STRUCT_RENAME_ELEM(MVert, co, co_legacy) diff --git a/source/blender/makesrna/intern/rna_mesh.c b/source/blender/makesrna/intern/rna_mesh.c index 79ec8ac73d3..5330b7f9957 100644 --- a/source/blender/makesrna/intern/rna_mesh.c +++ b/source/blender/makesrna/intern/rna_mesh.c @@ -659,6 +659,32 @@ static void rna_MeshPolygon_hide_set(PointerRNA *ptr, bool value) hide_poly[index] = value; } +static bool rna_MeshPolygon_use_smooth_get(PointerRNA *ptr) +{ + const Mesh *mesh = rna_mesh(ptr); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); + const int index = rna_MeshPolygon_index_get(ptr); + return !(sharp_faces && sharp_faces[index]); +} + +static void rna_MeshPolygon_use_smooth_set(PointerRNA *ptr, bool value) +{ + Mesh *mesh = rna_mesh(ptr); + bool *sharp_faces = (bool *)CustomData_get_layer_named_for_write( + &mesh->pdata, CD_PROP_BOOL, "sharp_face", mesh->totpoly); + if (!sharp_faces) { + if (!value) { + /* Skip adding layer if the value is the same as the default. */ + return; + } + sharp_faces = (bool *)CustomData_add_layer_named( + &mesh->pdata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totpoly, "sharp_face"); + } + const int index = rna_MeshPolygon_index_get(ptr); + sharp_faces[index] = !value; +} + static bool rna_MeshPolygon_select_get(PointerRNA *ptr) { const Mesh *mesh = rna_mesh(ptr); @@ -1790,8 +1816,9 @@ static bool rna_MeshLoopTriangle_use_smooth_get(PointerRNA *ptr) { const Mesh *me = rna_mesh(ptr); const MLoopTri *ltri = (MLoopTri *)ptr->data; - const MPoly *polys = BKE_mesh_polys(me); - return polys[ltri->poly].flag & ME_SMOOTH; + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &me->pdata, CD_PROP_BOOL, "sharp_face"); + return !(sharp_faces && sharp_faces[ltri->poly]); } /* path construction */ @@ -2960,7 +2987,8 @@ static void rna_def_mpolygon(BlenderRNA *brna) RNA_def_property_update(prop, 0, "rna_Mesh_update_select"); prop = RNA_def_property(srna, "use_smooth", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SMOOTH); + RNA_def_property_boolean_funcs( + prop, "rna_MeshPolygon_use_smooth_get", "rna_MeshPolygon_use_smooth_set"); RNA_def_property_ui_text(prop, "Smooth", ""); RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all"); diff --git a/source/blender/makesrna/intern/rna_mesh_api.c b/source/blender/makesrna/intern/rna_mesh_api.c index 2e2c0f1b694..1f41c8e5bdc 100644 --- a/source/blender/makesrna/intern/rna_mesh_api.c +++ b/source/blender/makesrna/intern/rna_mesh_api.c @@ -93,12 +93,15 @@ static void rna_Mesh_calc_smooth_groups( *r_poly_group_len = mesh->totpoly; const bool *sharp_edges = (const bool *)CustomData_get_layer_named( &mesh->edata, CD_PROP_BOOL, "sharp_edge"); + const bool *sharp_faces = (const bool *)CustomData_get_layer_named( + &mesh->pdata, CD_PROP_BOOL, "sharp_face"); *r_poly_group = BKE_mesh_calc_smoothgroups(mesh->totedge, BKE_mesh_polys(mesh), mesh->totpoly, BKE_mesh_loops(mesh), mesh->totloop, sharp_edges, + sharp_faces, r_group_total, use_bitflags); } diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index e829a2d1183..6ec413bc109 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -325,7 +325,8 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, /* We need to recompute vertex normals! */ BKE_mesh_normals_tag_dirty(mesh); } - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_custom_set(vert_positions, BKE_mesh_vert_normals_ensure(mesh), verts_num, @@ -336,6 +337,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd, loops.size(), polys.data(), poly_normals, + sharp_faces, polys.size(), sharp_edges, clnors); @@ -439,7 +441,8 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, loops, nos, &mesh->ldata, polys, BKE_mesh_poly_normals_for_write(mesh))) { BKE_mesh_normals_tag_dirty(mesh); } - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_custom_set(positions, BKE_mesh_vert_normals_ensure(mesh), verts_num, @@ -450,6 +453,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd, loops.size(), polys.data(), poly_normals, + sharp_faces, polys.size(), sharp_edges, clnors); @@ -547,7 +551,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, CustomData_get_layer_for_write(ldata, CD_CUSTOMLOOPNORMAL, loops.size())); loop_normals = static_cast( MEM_malloc_arrayN(loops.size(), sizeof(*loop_normals), __func__)); - + const bool *sharp_faces = static_cast( + CustomData_get_layer_named(&result->pdata, CD_PROP_BOOL, "sharp_face")); BKE_mesh_normals_loop_split(positions, vert_normals, verts_num, @@ -562,6 +567,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, true, result->smoothresh, sharp_edges.span.data(), + sharp_faces, nullptr, nullptr, clnors); diff --git a/source/blender/modifiers/intern/MOD_ocean.cc b/source/blender/modifiers/intern/MOD_ocean.cc index 792efd2215c..401165a8efe 100644 --- a/source/blender/modifiers/intern/MOD_ocean.cc +++ b/source/blender/modifiers/intern/MOD_ocean.cc @@ -204,7 +204,6 @@ static void generate_ocean_geometry_polys(void *__restrict userdata, gogd->polys[fi].loopstart = fi * 4; gogd->polys[fi].totloop = 4; - gogd->polys[fi].flag |= ME_SMOOTH; } } diff --git a/source/blender/modifiers/intern/MOD_screw.cc b/source/blender/modifiers/intern/MOD_screw.cc index 986e3fba52e..f49ec7d759f 100644 --- a/source/blender/modifiers/intern/MOD_screw.cc +++ b/source/blender/modifiers/intern/MOD_screw.cc @@ -22,6 +22,7 @@ #include "DNA_object_types.h" #include "DNA_screen_types.h" +#include "BKE_attribute.hh" #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_lib_query.h" @@ -191,6 +192,7 @@ static Mesh *mesh_remove_doubles_on_axis(Mesh *result, static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *meshData) { + using namespace blender; const Mesh *mesh = meshData; Mesh *result; ScrewModifierData *ltmd = (ScrewModifierData *)md; @@ -257,7 +259,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * ScrewVertConnect *vc, *vc_tmp, *vert_connect = nullptr; - const char mpoly_flag = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) ? ME_SMOOTH : 0; + const bool use_flat_shading = (ltmd->flag & MOD_SCREW_SMOOTH_SHADING) == 0; /* don't do anything? */ if (!totvert) { @@ -405,6 +407,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * blender::MutableSpan edges_new = result->edges_for_write(); blender::MutableSpan polys_new = result->polys_for_write(); blender::MutableSpan loops_new = result->loops_for_write(); + bke::MutableAttributeAccessor attributes = result->attributes_for_write(); + bke::SpanAttributeWriter sharp_faces = attributes.lookup_or_add_for_write_span( + "sharp_face", ATTR_DOMAIN_FACE); if (!CustomData_has_layer(&result->pdata, CD_ORIGINDEX)) { CustomData_add_layer(&result->pdata, CD_ORIGINDEX, CD_SET_DEFAULT, nullptr, int(maxPolys)); @@ -877,7 +882,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * else { origindex[mpoly_index] = ORIGINDEX_NONE; dst_material_index[mpoly_index] = mat_nr; - mp_new->flag = mpoly_flag; + sharp_faces.span[i] = use_flat_shading; } mp_new->loopstart = mpoly_index * 4; mp_new->totloop = 4; @@ -1001,6 +1006,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } #endif + sharp_faces.finish(); + if (edge_poly_map) { MEM_freeN(edge_poly_map); } diff --git a/source/blender/modifiers/intern/MOD_solidify_extrude.cc b/source/blender/modifiers/intern/MOD_solidify_extrude.cc index 243129b28ae..98d25be8641 100644 --- a/source/blender/modifiers/intern/MOD_solidify_extrude.cc +++ b/source/blender/modifiers/intern/MOD_solidify_extrude.cc @@ -1085,7 +1085,6 @@ Mesh *MOD_solidify_extrude_modifyMesh(ModifierData *md, const ModifierEvalContex CustomData_copy_data( &mesh->pdata, &result->pdata, int(pidx), int((polys_num * stride) + i), 1); polys[new_poly_index].loopstart = int(j + (loops_num * stride)); - polys[new_poly_index].flag = polys[pidx].flag; /* notice we use 'polys[new_poly_index].totloop' which is later overwritten, * we could lookup the original face but there's no point since this is a copy diff --git a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc index e15d7c0b434..e158c1d74ec 100644 --- a/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc +++ b/source/blender/modifiers/intern/MOD_solidify_nonmanifold.cc @@ -2320,7 +2320,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, dst_material_index[poly_index] = most_mat_nr + (g->is_orig_closed || !do_rim ? 0 : mat_ofs_rim); CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = orig_polys[most_mat_nr_face].flag; poly_index++; for (uint k = 0; g2->valid && k < j; g2++) { @@ -2395,7 +2394,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, dst_material_index[poly_index] = (src_material_index ? src_material_index[orig_face_index] : 0) + mat_ofs_rim; CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = face->flag; poly_index++; int loop1 = -1; @@ -2588,7 +2586,6 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md, 0) + (fr->reversed != do_flip ? mat_ofs : 0); CLAMP(dst_material_index[poly_index], 0, mat_nr_max); - polys[poly_index].flag = fr->face->flag; if (fr->reversed != do_flip) { for (int l = int(k) - 1; l >= 0; l--) { if (shell_defgrp_index != -1) { diff --git a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc index 2c3eadc3343..f6714aa1476 100644 --- a/source/blender/modifiers/intern/MOD_volume_to_mesh.cc +++ b/source/blender/modifiers/intern/MOD_volume_to_mesh.cc @@ -183,9 +183,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * } BKE_mesh_copy_parameters_for_eval(mesh, input_mesh); - if (vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE) { - BKE_mesh_smooth_flag_set(mesh, true); - } + BKE_mesh_smooth_flag_set(mesh, vmmd->flag & VOLUME_TO_MESH_USE_SMOOTH_SHADE); return mesh; #else UNUSED_VARS(md); diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 4db720822a5..afa9e27a9d1 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -83,6 +83,7 @@ struct WeightedNormalData { blender::Span polys; const float (*poly_normals)[3]; + const bool *sharp_faces; const int *poly_strength; const MDeformVert *dvert; @@ -233,6 +234,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, true, split_angle, wn_data->sharp_edges, + wn_data->sharp_faces, loop_to_poly.data(), &lnors_spacearr, has_clnors ? clnors : nullptr); @@ -357,6 +359,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, loops.size(), polys.data(), poly_normals, + wn_data->sharp_faces, polys.size(), wn_data->sharp_edges, clnors); @@ -389,6 +392,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, loops.size(), polys.data(), poly_normals, + wn_data->sharp_faces, polys.size(), wn_data->sharp_edges, clnors); @@ -413,6 +417,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, true, split_angle, wn_data->sharp_edges, + wn_data->sharp_faces, loop_to_poly.data(), nullptr, has_clnors ? clnors : nullptr); @@ -434,6 +439,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd, loops.size(), polys.data(), poly_normals, + wn_data->sharp_faces, polys.size(), wn_data->sharp_edges, clnors); @@ -618,6 +624,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * wn_data.polys = polys; wn_data.poly_normals = BKE_mesh_poly_normals_ensure(mesh); + wn_data.sharp_faces = static_cast( + CustomData_get_layer_named(&mesh->pdata, CD_PROP_BOOL, "sharp_face")); wn_data.poly_strength = static_cast(CustomData_get_layer_named( &result->pdata, CD_PROP_INT32, MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 33dc6bec641..7bdba586d6d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -43,6 +43,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span coords) result = BKE_mesh_new_nomain(verts_num, edges_num, loops_num, faces_num); BKE_id_material_eval_ensure_default_slot(&result->id); } + BKE_mesh_smooth_flag_set(result, false); /* Copy vertices. */ MutableSpan dst_positions = result->vert_positions_for_write(); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 9bb358f2cd9..8a77f2cf207 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -105,6 +105,7 @@ static Mesh *cdt_to_mesh(const meshintersect::CDT_result &result) /* The delaunay triangulation doesn't seem to return all of the necessary edges, even in * triangulation mode. */ BKE_mesh_calc_edges(mesh, true, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index 11c7f60909f..00271b053c1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -140,6 +140,7 @@ static void transfer_attributes( * Remove anonymous attributes that don't need to be propagated. */ Set attribute_ids = src_attributes.all_ids(); attribute_ids.remove("position"); + attribute_ids.remove("sharp_face"); attribute_ids.remove_if([&](const AttributeIDRef &id) { return id.is_anonymous() && !propagation_info.propagate(id.anonymous_id()); }); @@ -887,6 +888,7 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, } Mesh *mesh_out = BKE_mesh_new_nomain( vert_positions.size(), new_edges.size(), loops.size(), loop_lengths.size()); + BKE_mesh_smooth_flag_set(mesh_out, false); transfer_attributes(vertex_types, keep_boundaries, diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 86a9d2b794d..25e956c6edc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -160,7 +160,6 @@ static MPoly new_poly(const int loopstart, const int totloop) MPoly poly; poly.loopstart = loopstart; poly.totloop = totloop; - poly.flag = 0; return poly; } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index 54279719bd4..dd54bf1136e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -11,8 +11,8 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_geo_exec(GeoNodeExecParams params) { - Field shade_smooth_field = AttributeFieldInput::Create("shade_smooth"); - params.set_output("Smooth", std::move(shade_smooth_field)); + Field shade_smooth_field = AttributeFieldInput::Create("sharp_face"); + params.set_output("Smooth", fn::invert_boolean_field(shade_smooth_field)); } } // namespace blender::nodes::node_geo_input_shade_smooth_cc diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 3a871f2291f..c228bece849 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -112,6 +112,7 @@ static Mesh *create_circle_mesh(const float radius, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); /* Assign vertex coordinates. */ const float angle_delta = 2.0f * (M_PI / float(verts_num)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 15cea9d5db4..a30d08922f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -692,6 +692,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); calculate_cone_verts(config, positions); calculate_cone_edges(config, edges); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 9534160cccd..da4c2c7f094 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -57,6 +57,7 @@ Mesh *create_grid_mesh(const int verts_x, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); { const float dx = edges_x == 0 ? 0.0f : size_x / edges_x; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 45aed66e35e..d10abd8d2f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -315,6 +315,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, MutableSpan edges = mesh->edges_for_write(); MutableSpan polys = mesh->polys_for_write(); MutableSpan loops = mesh->loops_for_write(); + BKE_mesh_smooth_flag_set(mesh, false); threading::parallel_invoke( 1024 < segments * rings, diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 7dd721288ac..af80cf75e2e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -14,36 +14,63 @@ static void node_declare(NodeDeclarationBuilder &b) b.add_output(N_("Geometry")).propagate_all(); } -static void set_smooth(Mesh &mesh, - const Field &selection_field, - const Field &shade_field) +/** + * When the `sharp_face` attribute doesn't exist, all faces are considered smooth. If all faces + * are selected and the sharp value is a constant false value, we can remove the attribute instead + * as an optimization to avoid storing it and propagating it in the future. + */ +static bool try_removing_sharp_attribute(Mesh &mesh, + const Field &selection_field, + const Field &sharp_field) +{ + if (selection_field.node().depends_on_input() || sharp_field.node().depends_on_input()) { + return false; + } + const bool selection = fn::evaluate_constant_field(selection_field); + if (!selection) { + return true; + } + const bool sharp = fn::evaluate_constant_field(sharp_field); + if (sharp) { + return false; + } + mesh.attributes_for_write().remove("sharp_face"); + return true; +} + +static void set_sharp_faces(Mesh &mesh, + const Field &selection_field, + const Field &sharp_field) { if (mesh.totpoly == 0) { return; } + if (try_removing_sharp_attribute(mesh, selection_field, sharp_field)) { + return; + } MutableAttributeAccessor attributes = mesh.attributes_for_write(); - AttributeWriter smooth = attributes.lookup_or_add_for_write("shade_smooth", - ATTR_DOMAIN_FACE); + AttributeWriter sharp_faces = attributes.lookup_or_add_for_write("sharp_face", + ATTR_DOMAIN_FACE); bke::MeshFieldContext field_context{mesh, ATTR_DOMAIN_FACE}; fn::FieldEvaluator evaluator{field_context, mesh.totpoly}; evaluator.set_selection(selection_field); - evaluator.add_with_destination(shade_field, smooth.varray); + evaluator.add_with_destination(sharp_field, sharp_faces.varray); evaluator.evaluate(); - smooth.finish(); + sharp_faces.finish(); } static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input("Geometry"); Field selection_field = params.extract_input>("Selection"); - Field shade_field = params.extract_input>("Shade Smooth"); + Field smooth_field = params.extract_input>("Shade Smooth"); geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (Mesh *mesh = geometry_set.get_mesh_for_write()) { - set_smooth(*mesh, selection_field, shade_field); + set_sharp_faces(*mesh, selection_field, fn::invert_boolean_field(smooth_field)); } }); params.set_output("Geometry", std::move(geometry_set)); diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 776f98e281a..04ce9cfcf0b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -141,6 +141,7 @@ static Mesh *create_mesh_from_volume_grids(Span gri } BKE_mesh_calc_edges(mesh, false, false); + BKE_mesh_smooth_flag_set(mesh, false); return mesh; } diff --git a/source/blender/render/intern/bake.cc b/source/blender/render/intern/bake.cc index fb4f81a0367..b70de0fd141 100644 --- a/source/blender/render/intern/bake.cc +++ b/source/blender/render/intern/bake.cc @@ -56,6 +56,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "BKE_attribute.hh" #include "BKE_bvhutils.h" #include "BKE_customdata.h" #include "BKE_image.h" @@ -450,6 +451,7 @@ static bool cast_ray_highpoly(BVHTreeFromMesh *treeData, */ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval) { + using namespace blender; int i; const int tottri = poly_to_tri_count(me->totpoly, me->totloop); @@ -463,6 +465,9 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval const float(*positions)[3] = BKE_mesh_vert_positions(me); const blender::Span polys = me->polys(); const blender::Span loops = me->loops(); + const bke::AttributeAccessor attributes = me->attributes(); + const VArray sharp_faces = attributes.lookup_or_default( + "sharp_face", ATTR_DOMAIN_FACE, false); looptri = static_cast(MEM_mallocN(sizeof(*looptri) * tottri, __func__)); triangles = static_cast(MEM_callocN(sizeof(TriTessFace) * tottri, __func__)); @@ -511,7 +516,7 @@ static TriTessFace *mesh_calc_tri_tessface(Mesh *me, bool tangent, Mesh *me_eval triangles[i].vert_normals[0] = vert_normals[loops[lt->tri[0]].v]; triangles[i].vert_normals[1] = vert_normals[loops[lt->tri[1]].v]; triangles[i].vert_normals[2] = vert_normals[loops[lt->tri[2]].v]; - triangles[i].is_smooth = (poly.flag & ME_SMOOTH) != 0; + triangles[i].is_smooth = !sharp_faces[lt->poly]; if (tangent) { triangles[i].tspace[0] = &tspace[lt->tri[0]]; diff --git a/source/blender/render/intern/multires_bake.cc b/source/blender/render/intern/multires_bake.cc index 5ec2989381e..1185dd971bd 100644 --- a/source/blender/render/intern/multires_bake.cc +++ b/source/blender/render/intern/multires_bake.cc @@ -64,6 +64,7 @@ struct MResolvePixelData { const float (*vert_normals)[3]; const MPoly *polys; const int *material_indices; + const bool *sharp_faces; MLoop *mloop; float (*mloopuv)[2]; float uv_offset[2]; @@ -114,7 +115,7 @@ static void multiresbake_get_normal(const MResolvePixelData *data, { const int poly_index = data->mlooptri[tri_num].poly; const MPoly &poly = data->polys[poly_index]; - const bool smoothnormal = (poly.flag & ME_SMOOTH) != 0; + const bool smoothnormal = !(data->sharp_faces && data->sharp_faces[poly_index]); if (smoothnormal) { const int vi = data->mloop[data->mlooptri[tri_num].tri[vert_index]].v; @@ -504,6 +505,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, dm->getLoopArray(dm), dm->getLoopTriArray(dm), dm->getNumLoopTri(dm), + static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")), &dm->loopData, true, nullptr, @@ -550,6 +553,8 @@ static void do_multires_bake(MultiresBakeRender *bkr, handle->data.polys = polys; handle->data.material_indices = static_cast( CustomData_get_layer_named(&dm->polyData, CD_PROP_INT32, "material_index")); + handle->data.sharp_faces = static_cast( + CustomData_get_layer_named(&dm->polyData, CD_PROP_BOOL, "sharp_face")); handle->data.vert_positions = positions; handle->data.vert_normals = vert_normals; handle->data.mloopuv = mloopuv;