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;