Mesh: Move sharp edge flag to generic attribute

Move the `ME_SHARP` flag for mesh edges to a generic boolean
attribute. This will help allow changing mesh edges to just a pair
of integers, giving performance improvements. In the future it could
also give benefits for normal calculation, which could more easily
check if all or no edges are marked sharp, which is helpful considering
the plans in T93551.

The attribute is generally only allocated when it's necessary. When
leaving edit mode, it will only be created if an edge is marked sharp.
The data can be edited with geometry nodes just like a regular edge
domain boolean attribute.

The attribute is named `sharp_edge`, aiming to reflect the similar
`select_edge` naming and to allow a future `sharp_face` name in
a separate commit.

Ref T95966

Differential Revision: https://developer.blender.org/D16921
This commit is contained in:
Hans Goudey 2023-01-10 16:12:14 -05:00
parent 30c90f0ad0
commit dd9e1eded0
Notes: blender-bot 2023-03-31 12:02:52 +02:00
Referenced by issue #104348, Regression: Geometry Nodes triangulate node incorrectly alters point attributes
Referenced by issue #104334, Regression: Baking Bevel Shader does not work
Referenced by issue #103818, VSE: frozen frames after simple edit/cut in final render
Referenced by issue #103774, Crash scaling object with boolean modifier
Referenced by issue #95966, Struct of Arrays Refactor for Mesh Edges
Referenced by issue #72011, Visible wireframe artifacts after baking normal map with bevel shader (2)
Referenced by issue #106315, Regression: Smooth shading artefacts with mirror modifier (in 3.5, 3.6 is fine, for corrective release)
29 changed files with 360 additions and 112 deletions

View File

@ -472,14 +472,14 @@ 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!
*/
void BKE_edges_sharp_from_angle_set(struct MEdge *medges,
int numEdges,
void BKE_edges_sharp_from_angle_set(int numEdges,
const struct MLoop *mloops,
int numLoops,
const struct MPoly *mpolys,
const float (*poly_normals)[3],
int numPolys,
float split_angle);
float split_angle,
bool *sharp_edges);
/**
* References a contiguous loop-fan with normal offset vars.
@ -592,6 +592,8 @@ 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_edges: Optional array of sharp edge tags, used to split the evaluated normals on
* each side of the edge.
*/
void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
const float (*vert_normals)[3],
@ -606,6 +608,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
int numPolys,
bool use_split_normals,
float split_angle,
const bool *sharp_edges,
const int *loop_to_poly_map,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2]);
@ -613,7 +616,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
const float (*vert_normals)[3],
int numVerts,
struct MEdge *medges,
const struct MEdge *medges,
int numEdges,
const struct MLoop *mloops,
float (*r_custom_loop_normals)[3],
@ -621,18 +624,20 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
const struct MPoly *mpolys,
const float (*poly_normals)[3],
int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2]);
void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3],
const float (*vert_normals)[3],
float (*r_custom_vert_normals)[3],
int numVerts,
struct MEdge *medges,
const struct MEdge *medges,
int numEdges,
const struct MLoop *mloops,
int numLoops,
const struct MPoly *mpolys,
const float (*poly_normals)[3],
int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2]);
/**

View File

@ -95,6 +95,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_edges_to_flags(struct Mesh *mesh);
void BKE_mesh_legacy_sharp_edges_from_flags(struct Mesh *mesh);
struct MVert *BKE_mesh_legacy_convert_positions_to_verts(
Mesh *mesh,
blender::ResourceScope &temp_arrays_for_convert,

View File

@ -322,6 +322,7 @@ int *BKE_mesh_calc_smoothgroups(const struct MEdge *medge,
int totpoly,
const struct MLoop *mloop,
int totloop,
const bool *sharp_edges,
int *r_totgroup,
bool use_bitflags);

View File

@ -17,13 +17,6 @@
namespace blender::bke {
static void mark_edges_sharp(MutableSpan<MEdge> edges)
{
for (MEdge &edge : edges) {
edge.flag |= ME_SHARP;
}
}
static void fill_mesh_topology(const int vert_offset,
const int edge_offset,
const int poly_offset,
@ -155,28 +148,26 @@ static void fill_mesh_topology(const int vert_offset,
loop_end.v = last_ring_vert_offset + i;
loop_end.e = last_ring_edge_offset + i;
}
mark_edges_sharp(edges.slice(profile_edges_start, profile_segment_num));
mark_edges_sharp(edges.slice(last_ring_edge_offset, profile_segment_num));
}
}
/** Set the sharp status for edges that correspond to control points with vector handles. */
static void mark_bezier_vector_edges_sharp(const int profile_point_num,
const int main_segment_num,
const Span<int> control_point_offsets,
const Span<int8_t> handle_types_left,
const Span<int8_t> handle_types_right,
MutableSpan<MEdge> edges)
MutableSpan<bool> sharp_edges)
{
const int main_edges_start = 0;
if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, 0)) {
mark_edges_sharp(edges.slice(main_edges_start, main_segment_num));
sharp_edges.slice(main_edges_start, main_segment_num).fill(true);
}
for (const int i : IndexRange(profile_point_num).drop_front(1)) {
if (curves::bezier::point_is_sharp(handle_types_left, handle_types_right, i)) {
mark_edges_sharp(edges.slice(
main_edges_start + main_segment_num * control_point_offsets[i - 1], main_segment_num));
const int offset = main_edges_start + main_segment_num * control_point_offsets[i - 1];
sharp_edges.slice(offset, main_segment_num).fill(true);
}
}
}
@ -624,6 +615,38 @@ static void copy_curve_domain_attribute_to_mesh(const ResultOffsets &mesh_offset
});
}
static void write_sharp_bezier_edges(const CurvesInfo &curves_info,
const ResultOffsets &offsets,
MutableAttributeAccessor mesh_attributes,
SpanAttributeWriter<bool> &sharp_edges)
{
const CurvesGeometry &profile = curves_info.profile;
if (!profile.has_curve_with_type(CURVE_TYPE_BEZIER)) {
return;
}
const VArraySpan<int8_t> handle_types_left{profile.handle_types_left()};
const VArraySpan<int8_t> handle_types_right{profile.handle_types_right()};
if (!handle_types_left.contains(BEZIER_HANDLE_VECTOR) &&
!handle_types_right.contains(BEZIER_HANDLE_VECTOR)) {
return;
}
sharp_edges = mesh_attributes.lookup_or_add_for_write_span<bool>("sharp_edge", ATTR_DOMAIN_EDGE);
const VArray<int8_t> types = profile.curve_types();
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
if (types[info.i_profile] == CURVE_TYPE_BEZIER) {
const IndexRange points = profile.points_for_curve(info.i_profile);
mark_bezier_vector_edges_sharp(points.size(),
info.main_segment_num,
profile.bezier_evaluated_offsets_for_curve(info.i_profile),
handle_types_left.slice(points),
handle_types_right.slice(points),
sharp_edges.span.slice(info.edge_range));
}
});
}
Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
const CurvesGeometry &profile,
const bool fill_caps,
@ -691,28 +714,34 @@ Mesh *curve_to_mesh_sweep(const CurvesGeometry &main,
positions.slice(info.vert_range));
});
if (profile.curve_type_counts()[CURVE_TYPE_BEZIER] > 0) {
const VArray<int8_t> curve_types = profile.curve_types();
const VArraySpan<int8_t> handle_types_left{profile.handle_types_left()};
const VArraySpan<int8_t> handle_types_right{profile.handle_types_right()};
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> sharp_edges;
write_sharp_bezier_edges(curves_info, offsets, mesh_attributes, sharp_edges);
if (fill_caps) {
if (!sharp_edges) {
sharp_edges = mesh_attributes.lookup_or_add_for_write_span<bool>("sharp_edge",
ATTR_DOMAIN_EDGE);
}
foreach_curve_combination(curves_info, offsets, [&](const CombinationInfo &info) {
if (curve_types[info.i_profile] == CURVE_TYPE_BEZIER) {
const IndexRange points = profile.points_for_curve(info.i_profile);
mark_bezier_vector_edges_sharp(points.size(),
info.main_segment_num,
profile.bezier_evaluated_offsets_for_curve(info.i_profile),
handle_types_left.slice(points),
handle_types_right.slice(points),
edges.slice(info.edge_range));
if (info.main_cyclic || !info.profile_cyclic) {
return;
}
const int main_edges_start = info.edge_range.start();
const int last_ring_index = info.main_points.size() - 1;
const int profile_edges_start = main_edges_start +
info.profile_points.size() * info.main_segment_num;
const int last_ring_edge_offset = profile_edges_start +
info.profile_segment_num * last_ring_index;
sharp_edges.span.slice(profile_edges_start, info.profile_segment_num).fill(true);
sharp_edges.span.slice(last_ring_edge_offset, info.profile_segment_num).fill(true);
});
}
sharp_edges.finish();
Set<AttributeIDRef> main_attributes_set;
MutableAttributeAccessor mesh_attributes = mesh->attributes_for_write();
main_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (!should_add_attribute_to_mesh(
main_attributes, mesh_attributes, id, meta_data, propagation_info)) {

View File

@ -2300,7 +2300,8 @@ static bool attribute_stored_in_bmesh_flag(const StringRef name)
".select_vert",
".select_edge",
".select_poly",
"material_index");
"material_index",
"sharp_edge");
}
CustomData CustomData_shallow_copy_remove_non_bmesh_attributes(const CustomData *src,

View File

@ -20,6 +20,7 @@
#include "BLI_utildefines.h"
#include "BKE_attribute.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_data_transfer.h"
#include "BKE_deform.h"
@ -287,6 +288,8 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst || do_loop_nors_dst) {
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge"));
BKE_mesh_normals_loop_split(positions_dst,
BKE_mesh_vertex_normals_ensure(me_dst),
num_verts_dst,
@ -300,6 +303,7 @@ static void data_transfer_dtdata_type_preprocess(Mesh *me_src,
num_polys_dst,
use_split_nors_dst,
split_angle_dst,
sharp_edges,
nullptr,
nullptr,
custom_nors_dst);
@ -314,6 +318,7 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/,
const int dtdata_type,
const bool changed)
{
using namespace blender;
if (dtdata_type == DT_TYPE_LNOR) {
if (!changed) {
return;
@ -341,6 +346,10 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/,
ldata_dst, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, num_loops_dst));
}
bke::MutableAttributeAccessor attributes = me_dst->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
/* Note loop_nors_dst contains our custom normals as transferred from source... */
BKE_mesh_normals_loop_custom_set(positions_dst,
BKE_mesh_vertex_normals_ensure(me_dst),
@ -353,7 +362,9 @@ static void data_transfer_dtdata_type_postprocess(Object * /*ob_src*/,
polys_dst,
poly_nors_dst,
num_polys_dst,
sharp_edges.span.data(),
custom_nors_dst);
sharp_edges.finish();
}
}
@ -961,11 +972,11 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
}
return true;
}
if (r_map && ELEM(cddata_type, CD_FAKE_SHARP, CD_FAKE_SEAM)) {
if (r_map && cddata_type == CD_FAKE_SEAM) {
const size_t elem_size = sizeof(*((MEdge *)nullptr));
const size_t data_size = sizeof(((MEdge *)nullptr)->flag);
const size_t data_offset = offsetof(MEdge, flag);
const uint64_t data_flag = (cddata_type == CD_FAKE_SHARP) ? ME_SHARP : ME_SEAM;
const uint64_t data_flag = ME_SEAM;
data_transfer_layersmapping_add_item(r_map,
cddata_type,
@ -984,7 +995,23 @@ static bool data_transfer_layersmapping_generate(ListBase *r_map,
interp_data);
return true;
}
if (r_map && cddata_type == CD_FAKE_SHARP) {
if (!CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge")) {
CustomData_add_layer_named(
&me_dst->edata, CD_PROP_BOOL, CD_SET_DEFAULT, nullptr, me_dst->totedge, "sharp_edge");
}
data_transfer_layersmapping_add_item_cd(
r_map,
CD_PROP_BOOL,
mix_mode,
mix_factor,
mix_weights,
CustomData_get_layer_named(&me_src->edata, CD_PROP_BOOL, "sharp_edge"),
CustomData_get_layer_named(&me_dst->edata, CD_PROP_BOOL, "sharp_edge"),
interp,
interp_data);
return true;
}
return false;
}
else if (elem_type == ME_LOOP) {

View File

@ -1276,6 +1276,18 @@ static ComponentAttributeProviders create_attribute_providers_for_mesh()
make_derived_write_attribute<MPoly, bool, get_shade_smooth, set_shade_smooth>,
nullptr);
static BuiltinCustomDataLayerProvider sharp_edge("sharp_edge",
ATTR_DOMAIN_EDGE,
CD_PROP_BOOL,
CD_PROP_BOOL,
BuiltinAttributeProvider::Creatable,
BuiltinAttributeProvider::Writable,
BuiltinAttributeProvider::Deletable,
edge_access,
make_array_read_attribute<bool>,
make_array_write_attribute<bool>,
nullptr);
static BuiltinCustomDataLayerProvider crease(
"crease",
ATTR_DOMAIN_EDGE,
@ -1296,7 +1308,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, &normal, &crease},
{&position, &id, &material_index, &shade_smooth, &sharp_edge, &normal, &crease},
{&corner_custom_data,
&vertex_groups,
&point_custom_data,

View File

@ -2274,6 +2274,8 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
if (loop_normals_needed) {
short(*clnors)[2] = static_cast<short(*)[2]>(
CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL)); /* May be nullptr. */
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
BKE_mesh_normals_loop_split(positions,
vert_normals,
mesh->totvert,
@ -2287,6 +2289,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb,
mesh->totpoly,
(mesh->flag & ME_AUTOSMOOTH) != 0,
mesh->smoothresh,
sharp_edges,
nullptr,
nullptr,
clnors);

View File

@ -272,6 +272,7 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address
BKE_mesh_legacy_bevel_weight_from_layers(mesh);
BKE_mesh_legacy_face_set_from_generic(mesh, poly_layers);
BKE_mesh_legacy_edge_crease_from_layers(mesh);
BKE_mesh_legacy_sharp_edges_to_flags(mesh);
BKE_mesh_legacy_attribute_strings_to_flags(mesh);
mesh->active_color_attribute = nullptr;
mesh->default_color_attribute = nullptr;
@ -1830,8 +1831,6 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
MLoopNorSpaceArray *r_lnors_spacearr,
float (*r_corner_normals)[3])
{
short(*clnors)[2] = nullptr;
/* Note that we enforce computing clnors when the clnor space array is requested by caller here.
* However, we obviously only use the auto-smooth angle threshold
* only in case auto-smooth is enabled. */
@ -1840,7 +1839,9 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
/* may be nullptr */
clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
short(*clnors)[2] = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL);
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
const Span<float3> positions = mesh->vert_positions();
const Span<MEdge> edges = mesh->edges();
@ -1860,6 +1861,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh,
polys.size(),
use_split_normals,
split_angle,
sharp_edges,
nullptr,
r_lnors_spacearr,
clnors);

View File

@ -1341,6 +1341,48 @@ void BKE_mesh_legacy_edge_crease_to_layers(Mesh *mesh)
}
}
/* -------------------------------------------------------------------- */
/** \name Sharp Edge Conversion
* \{ */
void BKE_mesh_legacy_sharp_edges_to_flags(Mesh *mesh)
{
using namespace blender;
MutableSpan<MEdge> edges = mesh->edges_for_write();
if (const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"))) {
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
SET_FLAG_FROM_TEST(edges[i].flag, sharp_edges[i], ME_SHARP);
}
});
}
else {
for (const int i : edges.index_range()) {
edges[i].flag &= ~ME_SHARP;
}
}
}
void BKE_mesh_legacy_sharp_edges_from_flags(Mesh *mesh)
{
using namespace blender;
using namespace blender::bke;
const Span<MEdge> edges = mesh->edges();
MutableAttributeAccessor attributes = mesh->attributes_for_write();
if (std::any_of(
edges.begin(), edges.end(), [](const MEdge &edge) { return edge.flag & ME_SHARP; })) {
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_only_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
for (const int i : range) {
sharp_edges.span[i] = edges[i].flag & ME_SHARP;
}
});
sharp_edges.finish();
}
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@ -632,6 +632,8 @@ Vector<Vector<int>> build_edge_to_loop_map_resizable(const Span<MLoop> loops, co
using MeshRemap_CheckIslandBoundary = bool (*)(const MPoly *mpoly,
const MLoop *mloop,
const MEdge *medge,
const int edge_index,
const bool *sharp_edges,
const int edge_user_count,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
@ -643,6 +645,7 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
const int totpoly,
const MLoop *mloop,
const int totloop,
const bool *sharp_edges,
MeshElemMap *edge_poly_map,
const bool use_bitflags,
MeshRemap_CheckIslandBoundary edge_boundary_check,
@ -734,7 +737,8 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
const MeshElemMap *map_ele = &edge_poly_map[me_idx];
const int *p = map_ele->indices;
int i = map_ele->count;
if (!edge_boundary_check(mp, ml, me, i, mpoly, map_ele, edge_boundary_check_data)) {
if (!edge_boundary_check(
mp, ml, me, me_idx, sharp_edges, i, mpoly, map_ele, edge_boundary_check_data)) {
for (; i--; p++) {
/* if we meet other non initialized its a bug */
BLI_assert(ELEM(poly_groups[*p], 0, poly_group_id));
@ -834,7 +838,9 @@ static void poly_edge_loop_islands_calc(const MEdge *medge,
static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
const MLoop * /*ml*/,
const MEdge *me,
const MEdge * /*me*/,
const int edge_index,
const bool *sharp_edges,
const int edge_user_count,
const MPoly *mpoly_array,
const MeshElemMap *edge_poly_map,
@ -842,7 +848,8 @@ static bool poly_is_island_boundary_smooth_cb(const MPoly *mp,
{
/* 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 ((mp->flag & ME_SMOOTH) && !(me->flag & ME_SHARP) && (edge_user_count == 2)) {
if ((mp->flag & ME_SMOOTH) && !(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 MPoly *mp_other = (mp == &mpoly_array[edge_poly_map->indices[0]]) ?
&mpoly_array[edge_poly_map->indices[1]] :
@ -858,6 +865,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
const int totpoly,
const MLoop *mloop,
const int totloop,
const bool *sharp_edges,
int *r_totgroup,
const bool use_bitflags)
{
@ -869,6 +877,7 @@ int *BKE_mesh_calc_smoothgroups(const MEdge *medge,
totpoly,
mloop,
totloop,
sharp_edges,
nullptr,
use_bitflags,
poly_is_island_boundary_smooth_cb,
@ -1011,6 +1020,8 @@ struct MeshCheckIslandBoundaryUv {
static bool mesh_check_island_boundary_uv(const MPoly * /*mp*/,
const MLoop *ml,
const MEdge *me,
const int /*edge_index*/,
const bool * /*sharp_edges*/,
const int /*edge_user_count*/,
const MPoly * /*mpoly_array*/,
const MeshElemMap * /*edge_poly_map*/,
@ -1109,6 +1120,7 @@ static bool mesh_calc_islands_loop_poly_uv(const MEdge *edges,
totpoly,
loops,
totloop,
nullptr,
edge_poly_map,
false,
mesh_check_island_boundary_uv,

View File

@ -408,6 +408,8 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
/* calculate custom normals into loop_normals, then mirror first half into second half */
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh->edata, CD_PROP_BOOL, "sharp_edge"));
BKE_mesh_normals_loop_split(BKE_mesh_vert_positions(result),
BKE_mesh_vertex_normals_ensure(result),
result->totvert,
@ -421,6 +423,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd,
totpoly,
true,
mesh->smoothresh,
sharp_edges,
nullptr,
&lnors_spacearr,
clnors);

View File

@ -30,6 +30,7 @@
#include "BLI_timeit.hh"
#include "BLI_utildefines.h"
#include "BKE_attribute.hh"
#include "BKE_customdata.h"
#include "BKE_editmesh_cache.h"
#include "BKE_global.h"
@ -44,6 +45,7 @@ using blender::int2;
using blender::MutableSpan;
using blender::short2;
using blender::Span;
using blender::VArray;
// #define DEBUG_TIME
@ -787,15 +789,15 @@ struct LoopSplitTaskDataCommon {
/* See comment about edge_to_loops below. */
#define IS_EDGE_SHARP(_e2l) ELEM((_e2l)[1], INDEX_UNSET, INDEX_INVALID)
static void mesh_edges_sharp_tag(const Span<MEdge> edges,
const Span<MPoly> polys,
static void mesh_edges_sharp_tag(const Span<MPoly> polys,
const Span<MLoop> loops,
const Span<int> loop_to_poly_map,
const Span<float3> poly_normals,
const Span<bool> sharp_edges,
const bool check_angle,
const float split_angle,
MutableSpan<int2> edge_to_loops,
BitVector<> *r_sharp_edges)
MutableSpan<bool> r_sharp_edges)
{
using namespace blender;
const float split_angle_cos = check_angle ? cosf(split_angle) : -1.0f;
@ -825,15 +827,15 @@ static void mesh_edges_sharp_tag(const Span<MEdge> edges,
* 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) || (edges[edge_i].flag & ME_SHARP) ||
if (!(poly.flag & ME_SMOOTH) || (!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;
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */
if (r_sharp_edges && is_angle_sharp) {
(*r_sharp_edges)[edge_i].set();
if (!r_sharp_edges.is_empty() && is_angle_sharp) {
r_sharp_edges[edge_i] = true;
}
}
else {
@ -846,8 +848,8 @@ static void mesh_edges_sharp_tag(const Span<MEdge> edges,
/* We want to avoid tagging edges as sharp when it is already defined as such by
* other causes than angle threshold. */
if (r_sharp_edges) {
(*r_sharp_edges)[edge_i].reset();
if (!r_sharp_edges.is_empty()) {
r_sharp_edges[edge_i] = false;
}
}
/* Else, edge is already 'disqualified' (i.e. sharp)! */
@ -855,14 +857,14 @@ static void mesh_edges_sharp_tag(const Span<MEdge> edges,
}
}
void BKE_edges_sharp_from_angle_set(MEdge *medges,
const int numEdges,
void BKE_edges_sharp_from_angle_set(const int numEdges,
const MLoop *mloops,
const int numLoops,
const MPoly *mpolys,
const float (*poly_normals)[3],
const int numPolys,
const float split_angle)
const float split_angle,
bool *sharp_edges)
{
using namespace blender;
using namespace blender::bke;
@ -878,24 +880,15 @@ void BKE_edges_sharp_from_angle_set(MEdge *medges,
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map({mpolys, numPolys},
numLoops);
BitVector<> sharp_edges(numEdges, false);
mesh_edges_sharp_tag({medges, numEdges},
{mpolys, numPolys},
mesh_edges_sharp_tag({mpolys, numPolys},
{mloops, numLoops},
loop_to_poly,
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
Span<bool>(sharp_edges, numEdges),
true,
split_angle,
edge_to_loops,
&sharp_edges);
threading::parallel_for(IndexRange(numEdges), 4096, [&](const IndexRange range) {
for (const int edge_i : range) {
if (sharp_edges[edge_i]) {
medges[edge_i].flag |= ME_SHARP;
}
}
});
{sharp_edges, numEdges});
}
static void loop_manifold_fan_around_vert_next(const Span<MLoop> loops,
@ -1455,6 +1448,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
const int numPolys,
const bool use_split_normals,
const float split_angle,
const bool *sharp_edges,
const int *loop_to_poly_map,
MLoopNorSpaceArray *r_lnors_spacearr,
short (*clnors_data)[2])
@ -1565,15 +1559,15 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
});
/* This first loop check which edges are actually smooth, and compute edge vectors. */
mesh_edges_sharp_tag({medges, numEdges},
polys,
mesh_edges_sharp_tag(polys,
loops,
loop_to_poly,
{reinterpret_cast<const float3 *>(poly_normals), numPolys},
Span<bool>(sharp_edges, sharp_edges ? numEdges : 0),
check_angle,
split_angle,
edge_to_loops,
nullptr);
{});
if (numLoops < LOOP_SPLIT_TASK_BLOCK_SIZE * 8) {
/* Not enough loops to be worth the whole threading overhead. */
@ -1612,7 +1606,7 @@ void BKE_mesh_normals_loop_split(const float (*vert_positions)[3],
static void mesh_normals_loop_custom_set(const float (*positions)[3],
const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const MEdge *medges,
const int numEdges,
const MLoop *mloops,
float (*r_custom_loop_normals)[3],
@ -1620,6 +1614,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
const MPoly *mpolys,
const float (*poly_normals)[3],
const int numPolys,
MutableSpan<bool> sharp_edges,
short (*r_clnors_data)[2],
const bool use_vertices)
{
@ -1658,6 +1653,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
numPolys,
use_split_normals,
split_angle,
sharp_edges.data(),
loop_to_poly.data(),
&lnors_spacearr,
nullptr);
@ -1740,7 +1736,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
sharp_edges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e] = true;
org_nor = nor;
}
@ -1765,7 +1761,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
const MPoly *mp = &mpolys[loop_to_poly[lidx]];
const MLoop *mlp =
&mloops[(lidx == mp->loopstart) ? mp->loopstart + mp->totloop - 1 : lidx - 1];
medges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e].flag |= ME_SHARP;
sharp_edges[(prev_ml->e == mlp->e) ? prev_ml->e : ml->e] = true;
}
}
}
@ -1785,6 +1781,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
numPolys,
use_split_normals,
split_angle,
sharp_edges.data(),
loop_to_poly.data(),
&lnors_spacearr,
nullptr);
@ -1852,7 +1849,7 @@ static void mesh_normals_loop_custom_set(const float (*positions)[3],
void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
const float (*vert_normals)[3],
const int numVerts,
MEdge *medges,
const MEdge *medges,
const int numEdges,
const MLoop *mloops,
float (*r_custom_loop_normals)[3],
@ -1860,6 +1857,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
const MPoly *mpolys,
const float (*poly_normals)[3],
const int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(vert_positions,
@ -1873,6 +1871,7 @@ void BKE_mesh_normals_loop_custom_set(const float (*vert_positions)[3],
mpolys,
poly_normals,
numPolys,
{sharp_edges, numEdges},
r_clnors_data,
false);
}
@ -1881,13 +1880,14 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
const float (*vert_normals)[3],
float (*r_custom_vert_normals)[3],
const int numVerts,
MEdge *medges,
const MEdge *medges,
const int numEdges,
const MLoop *mloops,
const int numLoops,
const MPoly *mpolys,
const float (*poly_normals)[3],
const int numPolys,
bool *sharp_edges,
short (*r_clnors_data)[2])
{
mesh_normals_loop_custom_set(vert_positions,
@ -1901,12 +1901,15 @@ void BKE_mesh_normals_loop_custom_from_verts_set(const float (*vert_positions)[3
mpolys,
poly_normals,
numPolys,
{sharp_edges, numEdges},
r_clnors_data,
true);
}
static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const bool use_vertices)
{
using namespace blender;
using namespace blender::bke;
short(*clnors)[2];
const int numloops = mesh->totloop;
@ -1922,6 +1925,9 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
MutableSpan<MEdge> edges = mesh->edges_for_write();
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
MutableAttributeAccessor attributes = mesh->attributes_for_write();
SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
mesh_normals_loop_custom_set(reinterpret_cast<const float(*)[3]>(positions.data()),
BKE_mesh_vertex_normals_ensure(mesh),
@ -1934,8 +1940,10 @@ static void mesh_set_custom_normals(Mesh *mesh, float (*r_custom_nors)[3], const
polys.data(),
BKE_mesh_poly_normals_ensure(mesh),
polys.size(),
sharp_edges.span,
clnors,
use_vertices);
sharp_edges.finish();
}
void BKE_mesh_set_custom_normals(Mesh *mesh, float (*r_custom_loop_normals)[3])

View File

@ -1368,6 +1368,8 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
CustomData_set_layer_flag(ldata_dst, CD_NORMAL, CD_FLAG_TEMPORARY);
}
if (dirty_nors_dst || do_loop_nors_dst) {
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mesh_dst->edata, CD_PROP_BOOL, "sharp_edge"));
BKE_mesh_normals_loop_split(vert_positions_dst,
BKE_mesh_vertex_normals_ensure(mesh_dst),
numverts_dst,
@ -1381,6 +1383,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode,
numpolys_dst,
use_split_nors_dst,
split_angle_dst,
sharp_edges,
nullptr,
nullptr,
custom_nors_dst);

View File

@ -999,7 +999,7 @@ static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
if (edgeFlags) {
if (edgeIdx != -1) {
ed_flag |= ((edgeFlags[index] & (ME_SEAM | ME_SHARP)) | ME_EDGEDRAW);
ed_flag |= ((edgeFlags[index] & ME_SEAM) | ME_EDGEDRAW);
}
}
else {

View File

@ -32,6 +32,7 @@ static void version_mesh_legacy_to_struct_of_array_format(Mesh &mesh)
BKE_mesh_legacy_convert_uvs_to_generic(&mesh);
BKE_mesh_legacy_convert_mpoly_to_material_indices(&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);
BKE_mesh_legacy_edge_crease_to_layers(&mesh);
BKE_mesh_legacy_convert_verts_to_positions(&mesh);

View File

@ -718,8 +718,7 @@ BMesh *BM_mesh_copy(BMesh *bm_old)
char BM_edge_flag_from_mflag(const short mflag)
{
return (((mflag & ME_SEAM) ? BM_ELEM_SEAM : 0) | ((mflag & ME_EDGEDRAW) ? BM_ELEM_DRAW : 0) |
((mflag & ME_SHARP) == 0 ? BM_ELEM_SMOOTH : 0));
return (((mflag & ME_SEAM) ? BM_ELEM_SEAM : 0) | ((mflag & ME_EDGEDRAW) ? BM_ELEM_DRAW : 0));
}
char BM_face_flag_from_mflag(const char mflag)
{
@ -730,8 +729,7 @@ short BM_edge_flag_to_mflag(BMEdge *e)
{
const char hflag = e->head.hflag;
return (((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) | ((hflag & BM_ELEM_DRAW) ? ME_EDGEDRAW : 0) |
((hflag & BM_ELEM_SMOOTH) == 0 ? ME_SHARP : 0));
return (((hflag & BM_ELEM_SEAM) ? ME_SEAM : 0) | ((hflag & BM_ELEM_DRAW) ? ME_EDGEDRAW : 0));
}
char BM_face_flag_to_mflag(BMFace *f)
{

View File

@ -336,6 +336,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_edges = (const bool *)CustomData_get_layer_named(
&me->edata, CD_PROP_BOOL, "sharp_edge");
const Span<float3> positions = me->vert_positions();
Array<BMVert *> vtable(me->totvert);
@ -390,6 +392,9 @@ void BM_mesh_bm_from_me(BMesh *bm, const Mesh *me, const struct BMeshFromMeshPar
if (select_edge && select_edge[i]) {
BM_edge_select_set(bm, e, true);
}
if (!(sharp_edges && sharp_edges[i])) {
BM_elem_flag_enable(e, BM_ELEM_SMOOTH);
}
/* Copy Custom Data */
CustomData_to_bmesh_block(&mesh_edata, &bm->edata, i, &e->head.data, true);
@ -1063,6 +1068,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_edge = false;
i = 0;
BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
@ -1098,6 +1104,9 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
need_select_edge = true;
}
if (!BM_elem_flag_test(e, BM_ELEM_SMOOTH)) {
need_sharp_edge = true;
}
BM_elem_index_set(e, i); /* set_inline */
@ -1158,6 +1167,13 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh
ATTR_DOMAIN_FACE,
[&](const int i) { return int(BM_face_at_index(bm, i)->mat_nr); });
}
if (need_sharp_edge) {
BM_mesh_elem_table_ensure(bm, BM_EDGE);
write_fn_to_attribute<bool>(
me->attributes_for_write(), "sharp_edge", ATTR_DOMAIN_EDGE, [&](const int i) {
return !BM_elem_flag_test(BM_edge_at_index(bm, i), BM_ELEM_SMOOTH);
});
}
/* Patch hook indices and vertex parents. */
if (params->calc_object_remap && (ototvert > 0)) {
@ -1352,6 +1368,7 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
bke::SpanAttributeWriter<bool> hide_edge_attribute;
bke::SpanAttributeWriter<bool> select_edge_attribute;
bke::SpanAttributeWriter<bool> sharp_edge_attribute;
BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) {
MEdge *med = &medge[i];
@ -1375,6 +1392,13 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
}
select_edge_attribute.span[i] = true;
}
if (!BM_elem_flag_test(eed, BM_ELEM_SMOOTH)) {
if (!sharp_edge_attribute) {
sharp_edge_attribute = mesh_attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
}
sharp_edge_attribute.span[i] = true;
}
CustomData_from_bmesh_block(&bm->edata, &me->edata, eed->head.data, i);
}
@ -1442,4 +1466,5 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *
select_vert_attribute.finish();
select_edge_attribute.finish();
select_poly_attribute.finish();
sharp_edge_attribute.finish();
}

View File

@ -368,6 +368,8 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
MEM_mallocN(sizeof(*mr->loop_normals) * mr->loop_len, __func__));
short(*clnors)[2] = static_cast<short(*)[2]>(
CustomData_get_layer(&mr->me->ldata, CD_CUSTOMLOOPNORMAL));
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&mr->me->edata, CD_PROP_BOOL, "sharp_edge"));
BKE_mesh_normals_loop_split(reinterpret_cast<const float(*)[3]>(mr->vert_positions),
mr->vert_normals,
mr->vert_len,
@ -381,6 +383,7 @@ void mesh_render_data_update_normals(MeshRenderData *mr, const eMRDataType data_
mr->poly_len,
is_auto_smooth,
split_angle,
sharp_edges,
nullptr,
nullptr,
clnors);

View File

@ -843,6 +843,7 @@ void MESH_OT_customdata_skin_clear(wmOperatorType *ot)
/* Clear custom loop normals */
static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator * /*op*/)
{
using namespace blender;
Mesh *me = ED_mesh_context(C);
if (BKE_mesh_has_custom_loop_normals(me)) {
return OPERATOR_CANCELLED;
@ -862,18 +863,20 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator
/* Tag edges as sharp according to smooth threshold if needed,
* to preserve auto-smooth shading. */
if (me->flag & ME_AUTOSMOOTH) {
MutableSpan<MEdge> edges = me->edges_for_write();
const Span<MPoly> polys = me->polys();
const Span<MLoop> loops = me->loops();
BKE_edges_sharp_from_angle_set(edges.data(),
edges.size(),
bke::MutableAttributeAccessor attributes = me->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
BKE_edges_sharp_from_angle_set(me->totedge,
loops.data(),
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(me),
polys.size(),
me->smoothresh);
me->smoothresh,
sharp_edges.span.data());
sharp_edges.finish();
}
CustomData_add_layer(&me->ldata, CD_CUSTOMLOOPNORMAL, CD_SET_DEFAULT, nullptr, me->totloop);
@ -1532,36 +1535,34 @@ Mesh *ED_mesh_context(bContext *C)
void ED_mesh_split_faces(Mesh *mesh)
{
using namespace blender;
Array<MEdge> edges(mesh->edges());
const Span<MPoly> polys = mesh->polys();
const Span<MLoop> loops = mesh->loops();
const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : float(M_PI);
BKE_edges_sharp_from_angle_set(edges.data(),
edges.size(),
Array<bool> sharp_edges(mesh->totedge, false);
BKE_edges_sharp_from_angle_set(mesh->totedge,
loops.data(),
loops.size(),
polys.data(),
BKE_mesh_poly_normals_ensure(mesh),
polys.size(),
split_angle);
split_angle,
sharp_edges.data());
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)) {
for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) {
edges[loop.e].flag |= ME_SHARP;
sharp_edges[loop.e] = true;
}
}
}
});
Vector<int64_t> split_indices;
const IndexMask split_mask = index_mask_ops::find_indices_based_on_predicate(
edges.index_range(), 4096, split_indices, [&](const int64_t i) {
return edges[i].flag & ME_SHARP;
});
const IndexMask split_mask = index_mask_ops::find_indices_from_virtual_array(
sharp_edges.index_range(), VArray<bool>::ForSpan(sharp_edges), 4096, split_indices);
if (split_mask.is_empty()) {
return;
}

View File

@ -697,10 +697,11 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op)
break;
}
case SCULPT_FACE_SETS_FROM_SHARP_EDGES: {
const Span<MEdge> edges = mesh->edges();
const VArraySpan<bool> sharp_edges = mesh->attributes().lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
sculpt_face_sets_init_flood_fill(
ob, [&](const int /*from_face*/, const int edge, const int /*to_face*/) -> bool {
return (edges[edge].flag & ME_SHARP) == 0;
return !sharp_edges[edge];
});
break;
}

View File

@ -17,6 +17,7 @@
#include "PIL_time.h"
#include "BKE_attribute.hh"
#include "BKE_camera.h"
#include "BKE_collection.h"
#include "BKE_customdata.h"
@ -1477,6 +1478,7 @@ struct EdgeFeatData {
blender::Span<MLoop> loops;
blender::Span<MPoly> polys;
LineartTriangle *tri_array;
blender::VArray<bool> sharp_edges;
LineartVert *v_array;
float crease_threshold;
bool use_auto_smooth;
@ -1682,9 +1684,8 @@ static void lineart_identify_mlooptri_feature_edges(void *__restrict userdata,
e_feat_data->edges.data(), e_feat_data->loops.data(), &mlooptri[i / 3], real_edges);
if (real_edges[i % 3] >= 0) {
const MEdge *medge = &e_feat_data->edges[real_edges[i % 3]];
if (ld->conf.use_crease && ld->conf.sharp_as_crease && (medge->flag & ME_SHARP)) {
if (ld->conf.use_crease && ld->conf.sharp_as_crease &&
e_feat_data->sharp_edges[real_edges[i % 3]]) {
edge_flag_result |= LRT_EDGE_FLAG_CREASE;
}
@ -2068,6 +2069,10 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
edge_feat_settings.userdata_chunk_size = sizeof(EdgeFeatReduceData);
edge_feat_settings.func_reduce = feat_data_sum_reduce;
const bke::AttributeAccessor attributes = me->attributes();
const VArray<bool> sharp_edges = attributes.lookup_or_default<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE, false);
EdgeFeatData edge_feat_data = {nullptr};
edge_feat_data.ld = la_data;
edge_feat_data.me = me;
@ -2077,6 +2082,7 @@ static void lineart_geometry_object_load(LineartObjectInfo *ob_info,
edge_feat_data.edges = me->edges();
edge_feat_data.polys = me->polys();
edge_feat_data.loops = me->loops();
edge_feat_data.sharp_edges = sharp_edges;
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;

View File

@ -192,12 +192,15 @@ void OBJMesh::ensure_mesh_normals() const
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
{
const bool *sharp_edges = static_cast<const bool *>(
CustomData_get_layer_named(&export_mesh_->edata, CD_PROP_BOOL, "sharp_edge"));
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.data(),
mesh_edges_.size(),
mesh_polys_.data(),
mesh_polys_.size(),
mesh_loops_.data(),
mesh_loops_.size(),
sharp_edges,
&tot_smooth_groups_,
use_bitflags);
}

View File

@ -46,8 +46,9 @@ enum {
#ifdef DNA_DEPRECATED_ALLOW
/** Deprecated loose edge status. Now stored in #Mesh::loose_edges() runtime cache. */
ME_LOOSEEDGE = (1 << 7),
/** Deprecated sharp edge status. Now stored in "sharp_edge" attribute. */
ME_SHARP = (1 << 9),
#endif
ME_SHARP = (1 << 9), /* only reason this flag remains a 'short' */
};
/**

View File

@ -1506,6 +1506,32 @@ static void rna_MeshEdge_select_set(PointerRNA *ptr, bool value)
select_edge[index] = value;
}
static bool rna_MeshEdge_use_edge_sharp_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
const bool *sharp_edge = (const bool *)CustomData_get_layer_named(
&mesh->edata, CD_PROP_BOOL, "sharp_edge");
const int index = rna_MeshEdge_index_get(ptr);
return sharp_edge == NULL ? false : sharp_edge[index];
}
static void rna_MeshEdge_use_edge_sharp_set(PointerRNA *ptr, bool value)
{
Mesh *mesh = rna_mesh(ptr);
bool *sharp_edge = (bool *)CustomData_duplicate_referenced_layer_named(
&mesh->edata, CD_PROP_BOOL, "sharp_edge", mesh->totedge);
if (!sharp_edge) {
if (!value) {
/* Skip adding layer if it doesn't exist already anyway and we're not hiding an element. */
return;
}
sharp_edge = (bool *)CustomData_add_layer_named(
&mesh->edata, CD_PROP_BOOL, CD_SET_DEFAULT, NULL, mesh->totedge, "sharp_edge");
}
const int index = rna_MeshEdge_index_get(ptr);
sharp_edge[index] = value;
}
static bool rna_MeshEdge_is_loose_get(PointerRNA *ptr)
{
const Mesh *mesh = rna_mesh(ptr);
@ -2476,8 +2502,9 @@ static void rna_def_medge(BlenderRNA *brna)
RNA_def_property_update(prop, 0, "rna_Mesh_update_select");
prop = RNA_def_property(srna, "use_edge_sharp", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "flag", ME_SHARP);
RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for the Edge Split modifier");
RNA_def_property_boolean_funcs(
prop, "rna_MeshEdge_use_edge_sharp_get", "rna_MeshEdge_use_edge_sharp_set");
RNA_def_property_ui_text(prop, "Sharp", "Sharp edge for shading");
RNA_def_property_update(prop, 0, "rna_Mesh_update_data_legacy_deg_tag_all");
prop = RNA_def_property(srna, "is_loose", PROP_BOOLEAN, PROP_NONE);

View File

@ -91,12 +91,15 @@ static void rna_Mesh_calc_smooth_groups(
Mesh *mesh, bool use_bitflags, int *r_poly_group_len, int **r_poly_group, int *r_group_total)
{
*r_poly_group_len = mesh->totpoly;
const bool *sharp_edges = (const bool *)CustomData_get_layer_named(
&mesh->edata, CD_PROP_BOOL, "sharp_edge");
*r_poly_group = BKE_mesh_calc_smoothgroups(BKE_mesh_edges(mesh),
mesh->totedge,
BKE_mesh_polys(mesh),
mesh->totpoly,
BKE_mesh_loops(mesh),
mesh->totloop,
sharp_edges,
r_group_total,
use_bitflags);
}

View File

@ -21,6 +21,7 @@
#include "DNA_object_types.h"
#include "DNA_screen_types.h"
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_lib_id.h"
@ -224,8 +225,9 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
const bool use_invert_vgroup,
const float (*vert_positions)[3],
const int verts_num,
MEdge *medge,
const MEdge *medge,
const int edges_num,
bool *sharp_edges,
MLoop *mloop,
const int loops_num,
const MPoly *mpoly,
@ -341,6 +343,7 @@ static void normalEditModifier_do_radial(NormalEditModifierData *enmd,
mpoly,
poly_normals,
polys_num,
sharp_edges,
clnors);
MEM_freeN(cos);
@ -363,8 +366,9 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
const bool use_invert_vgroup,
const float (*positions)[3],
const int verts_num,
MEdge *medge,
const MEdge *medge,
const int edges_num,
bool *sharp_edges,
MLoop *mloop,
const int loops_num,
const MPoly *mpoly,
@ -457,6 +461,7 @@ static void normalEditModifier_do_directional(NormalEditModifierData *enmd,
mpoly,
poly_normals,
polys_num,
sharp_edges,
clnors);
MEM_freeN(nos);
@ -487,6 +492,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
Object *ob,
Mesh *mesh)
{
using namespace blender;
const bool use_invert_vgroup = ((enmd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
const bool use_current_clnors = !((enmd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
(enmd->mix_factor == 1.0f) && (enmd->defgrp_name[0] == '\0') &&
@ -529,7 +535,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
const int loops_num = result->totloop;
const int polys_num = result->totpoly;
const float(*positions)[3] = BKE_mesh_vert_positions(result);
MEdge *edges = BKE_mesh_edges_for_write(result);
const MEdge *edges = BKE_mesh_edges(result);
const MPoly *polys = BKE_mesh_polys(result);
MLoop *loops = BKE_mesh_loops_for_write(result);
@ -543,6 +549,10 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(result);
const float(*poly_normals)[3] = BKE_mesh_poly_normals_ensure(result);
bke::MutableAttributeAccessor attributes = result->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
short(*clnors)[2] = static_cast<short(*)[2]>(CustomData_get_layer(ldata, CD_CUSTOMLOOPNORMAL));
if (use_current_clnors) {
clnors = static_cast<short(*)[2]>(
@ -563,6 +573,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
polys_num,
true,
result->smoothresh,
sharp_edges.span.data(),
nullptr,
nullptr,
clnors);
@ -593,6 +604,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
verts_num,
edges,
edges_num,
sharp_edges.span.data(),
loops,
loops_num,
polys,
@ -616,6 +628,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
verts_num,
edges,
edges_num,
sharp_edges.span.data(),
loops,
loops_num,
polys,
@ -626,6 +639,8 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd,
result->runtime->is_original_bmesh = false;
sharp_edges.finish();
return result;
}

View File

@ -2204,7 +2204,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
}
medge[edge_index].v1 = last_g->new_vert;
medge[edge_index].v2 = g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW | ((last_flag | flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].flag = ME_EDGEDRAW | ((last_flag | flag) & ME_SEAM);
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, max_crease));
@ -2237,8 +2237,7 @@ Mesh *MOD_solidify_nonmanifold_modifyMesh(ModifierData *md,
last_g->open_face_edge = edge_index;
medge[edge_index].v1 = last_g->new_vert;
medge[edge_index].v2 = first_g->new_vert;
medge[edge_index].flag = ME_EDGEDRAW |
((last_flag | first_flag) & (ME_SEAM | ME_SHARP));
medge[edge_index].flag = ME_EDGEDRAW | ((last_flag | first_flag) & ME_SEAM);
if (result_edge_crease) {
result_edge_crease[edge_index] = max_ff(mv_crease,
min_ff(last_max_crease, first_max_crease));

View File

@ -19,6 +19,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "BKE_attribute.hh"
#include "BKE_context.h"
#include "BKE_deform.h"
#include "BKE_lib_id.h"
@ -74,7 +75,8 @@ struct WeightedNormalData {
const float (*vert_positions)[3];
const float (*vert_normals)[3];
MEdge *medge;
const MEdge *medge;
bool *sharp_edges;
const MLoop *mloop;
blender::Span<int> loop_to_poly;
@ -188,7 +190,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
const int polys_num = wn_data->polys_num;
const float(*positions)[3] = wn_data->vert_positions;
MEdge *medge = wn_data->medge;
const MEdge *medge = wn_data->medge;
const MLoop *mloop = wn_data->mloop;
short(*clnors)[2] = wn_data->clnors;
@ -236,6 +238,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
polys_num,
true,
split_angle,
wn_data->sharp_edges,
loop_to_poly.data(),
&lnors_spacearr,
has_clnors ? clnors : nullptr);
@ -366,6 +369,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
mpoly,
poly_normals,
polys_num,
wn_data->sharp_edges,
clnors);
}
else {
@ -397,6 +401,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
mpoly,
poly_normals,
polys_num,
wn_data->sharp_edges,
clnors);
MEM_freeN(vert_normals);
@ -418,6 +423,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
polys_num,
true,
split_angle,
wn_data->sharp_edges,
loop_to_poly.data(),
nullptr,
has_clnors ? clnors : nullptr);
@ -440,6 +446,7 @@ static void apply_weights_vertex_normal(WeightedNormalModifierData *wnmd,
mpoly,
poly_normals,
polys_num,
wn_data->sharp_edges,
clnors);
}
}
@ -584,7 +591,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const int loops_num = result->totloop;
const int polys_num = result->totpoly;
const float(*positions)[3] = BKE_mesh_vert_positions(result);
MEdge *medge = BKE_mesh_edges_for_write(result);
const MEdge *medge = BKE_mesh_edges(result);
const MPoly *mpoly = BKE_mesh_polys(result);
const MLoop *mloop = BKE_mesh_loops(result);
@ -624,6 +631,10 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
const Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(result->polys(),
result->totloop);
bke::MutableAttributeAccessor attributes = result->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(
"sharp_edge", ATTR_DOMAIN_EDGE);
WeightedNormalData wn_data{};
wn_data.verts_num = verts_num;
wn_data.edges_num = edges_num;
@ -633,6 +644,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
wn_data.vert_positions = positions;
wn_data.vert_normals = BKE_mesh_vertex_normals_ensure(result);
wn_data.medge = medge;
wn_data.sharp_edges = sharp_edges.span.data();
wn_data.mloop = mloop;
wn_data.loop_to_poly = loop_to_poly_map;
@ -669,6 +681,8 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *
result->runtime->is_original_bmesh = false;
sharp_edges.finish();
return result;
}