I/O: Smoothgroups: Add option to also consider 'sharp vertices'.
According to reports and testing in blender/blender-addons#104434, DCCs tend to behave badly when rebuilding normals from 'bitflags' smoothgroups, if different smoothgroups using the same bitflag value share (are connected by) some common vertices, even if there are no common edges between them. This commit adds a new option to the RNA API generating smooth groups, to also consider smooth groups only sharing vertices as neighbors. It also makes related required change to implementation, and some refactor of the API, splitting public functions between 'normal' and 'bitflags' versions. This should make changes proposed in blender/blender-addons#105516 much simpler, and allow for a matching behavior in smoothgroups generated by the OBJ exporter as well. Pull Request: https://projects.blender.org/blender/blender/pulls/135248
This commit is contained in:
committed by
Bastien Montagne
parent
ec33541b99
commit
00de07f752
@@ -247,22 +247,52 @@ bool BKE_mesh_calc_islands_loop_face_uvmap(float (*vert_positions)[3],
|
||||
MeshIslandStore *r_island_store);
|
||||
|
||||
/**
|
||||
* Calculate smooth groups from sharp edges.
|
||||
* Calculate smooth groups from sharp edges, using increasing numbers as identifier for each group.
|
||||
*
|
||||
* \param sharp_edges: Optional (possibly empty) span.
|
||||
* \param sharp_faces: Optional (possibly empty) span.
|
||||
* \param r_totgroup: The total number of groups, 1 or more.
|
||||
* \return Polygon aligned array of group index values (bitflags if use_bitflags is true),
|
||||
* starting at 1 (0 being used as 'invalid' flag).
|
||||
* Note it's callers's responsibility to MEM_freeN returned array.
|
||||
* \return Face aligned array of group index values, starting at 1 (0 being used as 'invalid'
|
||||
* flag). Note that it's the callers's responsibility to MEM_freeN the returned array.
|
||||
*/
|
||||
int *BKE_mesh_calc_smoothgroups(int edges_num,
|
||||
blender::OffsetIndices<int> faces,
|
||||
blender::Span<int> corner_edges,
|
||||
blender::Span<bool> sharp_edges,
|
||||
blender::Span<bool> sharp_faces,
|
||||
int *r_totgroup,
|
||||
bool use_bitflags);
|
||||
int *r_totgroup);
|
||||
/**
|
||||
* Same as #BKE_mesh_calc_smoothgroups, but use bitflags instead of increasing numbers for each
|
||||
* group.
|
||||
*
|
||||
* This means that the same value (bit) can be re-used for different groups, as long as they are
|
||||
* not neighbors. Values of each group are always powers of two.
|
||||
*
|
||||
* By default, only groups that share a same sharp edge are considered neighbors, and therefore
|
||||
* prevented to use the same bitflag value.
|
||||
*
|
||||
* If #use_boundary_vertices_for_bitflags is set to `true`, then groups are also considered
|
||||
* neighbors (and therefore cannot have the same bitflag value) if they share a single vertex, even
|
||||
* if they have no common edge. This behavior seems to be required by some DCCs to recompute
|
||||
* correct normals, see e.g. #104434. It will however make it much more likely to run out of
|
||||
* available bits with certain types of topology (e.g. large fans of sharp faces).
|
||||
*
|
||||
* \param sharp_edges: Optional (possibly empty) span.
|
||||
* \param sharp_faces: Optional (possibly empty) span.
|
||||
* \param r_totgroup: The total number of groups, 1 or more.
|
||||
* \return Face aligned array of group bitflags values (i.e. always powers of 2), starting at 1 (0
|
||||
* being used as 'invalid' flag). Note that it's the callers's responsibility to MEM_freeN the
|
||||
* returned array.
|
||||
*/
|
||||
int *BKE_mesh_calc_smoothgroups_bitflags(int edges_num,
|
||||
int verts_num,
|
||||
blender::OffsetIndices<int> faces,
|
||||
blender::Span<int> corner_edges,
|
||||
blender::Span<int> corner_verts,
|
||||
blender::Span<bool> sharp_edges,
|
||||
blender::Span<bool> sharp_faces,
|
||||
bool use_boundary_vertices_for_bitflags,
|
||||
int *r_totgroup);
|
||||
|
||||
/* Use on corner_tri vertex values. */
|
||||
#define BKE_MESH_TESSTRI_VINDEX_ORDER(_tri, _v) \
|
||||
|
||||
@@ -479,28 +479,66 @@ using MeshRemap_CheckIslandBoundary =
|
||||
int edge_user_count,
|
||||
const blender::Span<int> edge_face_map_elem)>;
|
||||
|
||||
static void face_edge_loop_islands_calc_bitflags_exclude_at_boundary(
|
||||
const int *face_groups,
|
||||
const blender::Span<int> faces_from_item,
|
||||
const int face_group_id,
|
||||
const int face_group_id_overflowed,
|
||||
int &r_bit_face_group_mask)
|
||||
{
|
||||
/* Find neighbour faces (either from a boundary edge, or a boundary vertex) that already have a
|
||||
* group assigned, and exclude these groups' bits from the available set of groups bits that can
|
||||
* be assigned to the currently processed group. */
|
||||
for (const int face_idx : faces_from_item) {
|
||||
int bit = face_groups[face_idx];
|
||||
if (!ELEM(bit, 0, face_group_id, face_group_id_overflowed) && !(r_bit_face_group_mask & bit)) {
|
||||
r_bit_face_group_mask |= bit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* ABOUT #use_boundary_vertices_for_bitflags:
|
||||
*
|
||||
* Also exclude bits used in other groups sharing the same boundary vertex, i.e. if one edge
|
||||
* around the vertex of the current corner is a boundary edge.
|
||||
*
|
||||
* NOTE: The reason for this requirement is not very clear. Bitflags groups are only handled here
|
||||
* for I/O purposes, Blender itself does not have this feature. Main external apps heavily
|
||||
* relying on these bitflags groups for their smooth shading computation seem to generate invalid
|
||||
* results when two different groups share the same bits, and are connected by a vertex only
|
||||
* (i.e. have no edge in common). See #104434.
|
||||
*
|
||||
* The downside of also considering boundary vertex-only neighbor faces is that it becomes much
|
||||
* more likely to run out of bits, e.g. in a case of a fan with many faces/edges around a same
|
||||
* vertex, each in their own face group...
|
||||
*/
|
||||
static void face_edge_loop_islands_calc(const int totedge,
|
||||
const int totvert,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const blender::Span<int> corner_edges,
|
||||
const blender::Span<int> corner_verts,
|
||||
blender::GroupedSpan<int> edge_face_map,
|
||||
blender::GroupedSpan<int> vert_face_map,
|
||||
const bool use_bitflags,
|
||||
const bool use_boundary_vertices_for_bitflags,
|
||||
MeshRemap_CheckIslandBoundary edge_boundary_check,
|
||||
int **r_face_groups,
|
||||
int *r_totgroup,
|
||||
BLI_bitmap **r_edge_borders,
|
||||
int *r_totedgeborder)
|
||||
BLI_bitmap **r_edge_boundaries,
|
||||
int *r_totedgeboundaries)
|
||||
{
|
||||
int *face_groups;
|
||||
int *face_stack;
|
||||
|
||||
BLI_bitmap *edge_borders = nullptr;
|
||||
int num_edgeborders = 0;
|
||||
BLI_bitmap *edge_boundaries = nullptr;
|
||||
int num_edgeboundaries = 0;
|
||||
|
||||
int face_prev = 0;
|
||||
const int temp_face_group_id = 3; /* Placeholder value. */
|
||||
constexpr int temp_face_group_id = 3; /* Placeholder value. */
|
||||
|
||||
/* Group we could not find any available bit, will be reset to 0 at end. */
|
||||
const int face_group_id_overflowed = 5;
|
||||
/* For bitflags groups, group we could not find any available bit for, will be reset to 0 at the
|
||||
* end. */
|
||||
constexpr int face_group_id_overflowed = 5;
|
||||
|
||||
int tot_group = 0;
|
||||
bool group_id_overflow = false;
|
||||
@@ -508,16 +546,16 @@ static void face_edge_loop_islands_calc(const int totedge,
|
||||
if (faces.is_empty()) {
|
||||
*r_totgroup = 0;
|
||||
*r_face_groups = nullptr;
|
||||
if (r_edge_borders) {
|
||||
*r_edge_borders = nullptr;
|
||||
*r_totedgeborder = 0;
|
||||
if (r_edge_boundaries) {
|
||||
*r_edge_boundaries = nullptr;
|
||||
*r_totedgeboundaries = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (r_edge_borders) {
|
||||
edge_borders = BLI_BITMAP_NEW(totedge, __func__);
|
||||
*r_totedgeborder = 0;
|
||||
if (r_edge_boundaries) {
|
||||
edge_boundaries = BLI_BITMAP_NEW(totedge, __func__);
|
||||
*r_totedgeboundaries = 0;
|
||||
}
|
||||
|
||||
blender::Array<int> edge_to_face_src_offsets;
|
||||
@@ -526,6 +564,12 @@ static void face_edge_loop_islands_calc(const int totedge,
|
||||
edge_face_map = blender::bke::mesh::build_edge_to_face_map(
|
||||
faces, corner_edges, totedge, edge_to_face_src_offsets, edge_to_face_src_indices);
|
||||
}
|
||||
blender::Array<int> vert_to_face_src_offsets;
|
||||
blender::Array<int> vert_to_face_src_indices;
|
||||
if (use_bitflags && vert_face_map.is_empty()) {
|
||||
vert_face_map = blender::bke::mesh::build_vert_to_face_map(
|
||||
faces, corner_verts, totvert, vert_to_face_src_offsets, vert_to_face_src_indices);
|
||||
}
|
||||
|
||||
face_groups = static_cast<int *>(MEM_callocN(sizeof(int) * size_t(faces.size()), __func__));
|
||||
face_stack = static_cast<int *>(MEM_mallocN(sizeof(int) * size_t(faces.size()), __func__));
|
||||
@@ -577,20 +621,37 @@ static void face_edge_loop_islands_calc(const int totedge,
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (edge_borders && !BLI_BITMAP_TEST(edge_borders, edge)) {
|
||||
BLI_BITMAP_ENABLE(edge_borders, edge);
|
||||
num_edgeborders++;
|
||||
if (edge_boundaries && !BLI_BITMAP_TEST(edge_boundaries, edge)) {
|
||||
BLI_BITMAP_ENABLE(edge_boundaries, edge);
|
||||
num_edgeboundaries++;
|
||||
}
|
||||
if (use_bitflags) {
|
||||
/* Find contiguous smooth groups already assigned,
|
||||
* these are the values we can't reuse! */
|
||||
for (; i--; p++) {
|
||||
int bit = face_groups[*p];
|
||||
if (!ELEM(bit, 0, face_group_id, face_group_id_overflowed) &&
|
||||
!(bit_face_group_mask & bit))
|
||||
{
|
||||
bit_face_group_mask |= bit;
|
||||
}
|
||||
/* Exclude bits used in other groups sharing the same boundary edge. */
|
||||
face_edge_loop_islands_calc_bitflags_exclude_at_boundary(face_groups,
|
||||
map_ele,
|
||||
face_group_id,
|
||||
face_group_id_overflowed,
|
||||
bit_face_group_mask);
|
||||
if (use_boundary_vertices_for_bitflags) {
|
||||
/* Exclude bits used in other groups sharing the same boundary vertex. */
|
||||
/* NOTE: Checking one vertex for each edge (the corner vertex) should be enough:
|
||||
* - Thanks to winding, a fully boundary vertex (i.e. a vertex for which at least
|
||||
* two of the adjacent edges in the same group are boundary ones) will be
|
||||
* processed by at least one of the edges/corners. If not when processing the
|
||||
* first face's corner, then when processing the other face's corner in the same
|
||||
* group.
|
||||
* - Isolated boundary edges (i.e. boundary edges only connected to faces of the
|
||||
* same group) cannot be represented by bitflags groups, at least not with
|
||||
* current algorithm (they cannot define more than one group).
|
||||
* - Inverions of winding (aka flipped faces) always generate boundary edges in
|
||||
* current use-case (smooth groups), i.e. two faces with opposed winding cannot
|
||||
* belong to the same group. */
|
||||
const int vert = corner_verts[loop];
|
||||
face_edge_loop_islands_calc_bitflags_exclude_at_boundary(face_groups,
|
||||
vert_face_map[vert],
|
||||
face_group_id,
|
||||
face_group_id_overflowed,
|
||||
bit_face_group_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -609,10 +670,15 @@ static void face_edge_loop_islands_calc(const int totedge,
|
||||
face_group_id <<= 1; /* will 'overflow' on last possible iteration. */
|
||||
}
|
||||
if (UNLIKELY(gid_bit > 31)) {
|
||||
/* All bits used in contiguous smooth groups, we can't do much!
|
||||
* NOTE: this is *very* unlikely - theoretically, four groups are enough,
|
||||
* I don't think we can reach this goal with such a simple algorithm,
|
||||
* but I don't think either we'll never need all 32 groups!
|
||||
/* All bits used in contiguous smooth groups, not much to do.
|
||||
*
|
||||
* NOTE: If only considering boundary edges, this is *very* unlikely to happen.
|
||||
* Theoretically, four groups are enough, this is probably not achievable with such a
|
||||
* simple algorithm, but 32 groups should always be more than enough.
|
||||
*
|
||||
* When also considering boundary vertices (which is the case currently, see comment
|
||||
* above), a fairly simple fan case with over 30 faces all belonging to different groups
|
||||
* will be enough to cause an overflow.
|
||||
*/
|
||||
printf(
|
||||
"Warning, could not find an available id for current smooth group, faces will me "
|
||||
@@ -652,19 +718,22 @@ static void face_edge_loop_islands_calc(const int totedge,
|
||||
|
||||
*r_totgroup = tot_group;
|
||||
*r_face_groups = face_groups;
|
||||
if (r_edge_borders) {
|
||||
*r_edge_borders = edge_borders;
|
||||
*r_totedgeborder = num_edgeborders;
|
||||
if (r_edge_boundaries) {
|
||||
*r_edge_boundaries = edge_boundaries;
|
||||
*r_totedgeboundaries = num_edgeboundaries;
|
||||
}
|
||||
}
|
||||
|
||||
int *BKE_mesh_calc_smoothgroups(int edges_num,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const blender::Span<int> corner_edges,
|
||||
const blender::Span<bool> sharp_edges,
|
||||
const blender::Span<bool> sharp_faces,
|
||||
int *r_totgroup,
|
||||
bool use_bitflags)
|
||||
static int *mesh_calc_smoothgroups(const int edges_num,
|
||||
const int verts_num,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const blender::Span<int> corner_edges,
|
||||
const blender::Span<int> corner_verts,
|
||||
const blender::Span<bool> sharp_edges,
|
||||
const blender::Span<bool> sharp_faces,
|
||||
int *r_totgroup,
|
||||
const bool use_bitflags,
|
||||
const bool use_boundary_vertices_for_bitflags)
|
||||
{
|
||||
int *face_groups = nullptr;
|
||||
|
||||
@@ -689,10 +758,14 @@ int *BKE_mesh_calc_smoothgroups(int edges_num,
|
||||
};
|
||||
|
||||
face_edge_loop_islands_calc(edges_num,
|
||||
verts_num,
|
||||
faces,
|
||||
corner_edges,
|
||||
corner_verts,
|
||||
{},
|
||||
{},
|
||||
use_bitflags,
|
||||
use_boundary_vertices_for_bitflags,
|
||||
face_is_island_boundary_smooth,
|
||||
&face_groups,
|
||||
r_totgroup,
|
||||
@@ -702,6 +775,39 @@ int *BKE_mesh_calc_smoothgroups(int edges_num,
|
||||
return face_groups;
|
||||
}
|
||||
|
||||
int *BKE_mesh_calc_smoothgroups(int edges_num,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const blender::Span<int> corner_edges,
|
||||
const blender::Span<bool> sharp_edges,
|
||||
const blender::Span<bool> sharp_faces,
|
||||
int *r_totgroup)
|
||||
{
|
||||
return mesh_calc_smoothgroups(
|
||||
edges_num, 0, faces, corner_edges, {}, sharp_edges, sharp_faces, r_totgroup, false, false);
|
||||
}
|
||||
|
||||
int *BKE_mesh_calc_smoothgroups_bitflags(int edges_num,
|
||||
int verts_num,
|
||||
const blender::OffsetIndices<int> faces,
|
||||
const blender::Span<int> corner_edges,
|
||||
const blender::Span<int> corner_verts,
|
||||
const blender::Span<bool> sharp_edges,
|
||||
const blender::Span<bool> sharp_faces,
|
||||
const bool use_boundary_vertices_for_bitflags,
|
||||
int *r_totgroup)
|
||||
{
|
||||
return mesh_calc_smoothgroups(edges_num,
|
||||
verts_num,
|
||||
faces,
|
||||
corner_edges,
|
||||
corner_verts,
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
r_totgroup,
|
||||
true,
|
||||
use_boundary_vertices_for_bitflags);
|
||||
}
|
||||
|
||||
#define MISLAND_DEFAULT_BUFSIZE 64
|
||||
|
||||
void BKE_mesh_loop_islands_init(MeshIslandStore *island_store,
|
||||
@@ -834,12 +940,12 @@ static bool mesh_calc_islands_loop_face_uv(const int totedge,
|
||||
int *loop_indices;
|
||||
int num_pidx, num_lidx;
|
||||
|
||||
/* Those are used to detect 'inner cuts', i.e. edges that are borders,
|
||||
/* Those are used to detect 'inner cuts', i.e. edges that are boundaries,
|
||||
* and yet have two or more faces of a same group using them
|
||||
* (typical case: seam used to unwrap properly a cylinder). */
|
||||
BLI_bitmap *edge_borders = nullptr;
|
||||
int num_edge_borders = 0;
|
||||
char *edge_border_count = nullptr;
|
||||
BLI_bitmap *edge_boundaries = nullptr;
|
||||
int num_edge_boundaries = 0;
|
||||
char *edge_boundary_count = nullptr;
|
||||
int *edge_innercut_indices = nullptr;
|
||||
int num_einnercuts = 0;
|
||||
|
||||
@@ -908,28 +1014,32 @@ static bool mesh_calc_islands_loop_face_uv(const int totedge,
|
||||
};
|
||||
|
||||
face_edge_loop_islands_calc(totedge,
|
||||
0,
|
||||
faces,
|
||||
{corner_edges, corners_num},
|
||||
{},
|
||||
edge_to_face_map,
|
||||
{},
|
||||
false,
|
||||
false,
|
||||
mesh_check_island_boundary_uv,
|
||||
&face_groups,
|
||||
&num_face_groups,
|
||||
&edge_borders,
|
||||
&num_edge_borders);
|
||||
&edge_boundaries,
|
||||
&num_edge_boundaries);
|
||||
|
||||
if (!num_face_groups) {
|
||||
if (edge_borders) {
|
||||
MEM_freeN(edge_borders);
|
||||
if (num_edge_boundaries) {
|
||||
MEM_freeN(edge_boundaries);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (num_edge_borders) {
|
||||
edge_border_count = static_cast<char *>(
|
||||
MEM_mallocN(sizeof(*edge_border_count) * size_t(totedge), __func__));
|
||||
if (num_edge_boundaries) {
|
||||
edge_boundary_count = static_cast<char *>(
|
||||
MEM_mallocN(sizeof(*edge_boundary_count) * size_t(totedge), __func__));
|
||||
edge_innercut_indices = static_cast<int *>(
|
||||
MEM_mallocN(sizeof(*edge_innercut_indices) * size_t(num_edge_borders), __func__));
|
||||
MEM_mallocN(sizeof(*edge_innercut_indices) * size_t(num_edge_boundaries), __func__));
|
||||
}
|
||||
|
||||
face_indices = static_cast<int *>(
|
||||
@@ -940,9 +1050,9 @@ static bool mesh_calc_islands_loop_face_uv(const int totedge,
|
||||
/* NOTE: here we ignore '0' invalid group - this should *never* happen in this case anyway? */
|
||||
for (grp_idx = 1; grp_idx <= num_face_groups; grp_idx++) {
|
||||
num_pidx = num_lidx = 0;
|
||||
if (num_edge_borders) {
|
||||
if (num_edge_boundaries) {
|
||||
num_einnercuts = 0;
|
||||
memset(edge_border_count, 0, sizeof(*edge_border_count) * size_t(totedge));
|
||||
memset(edge_boundary_count, 0, sizeof(*edge_boundary_count) * size_t(totedge));
|
||||
}
|
||||
|
||||
for (const int64_t p_idx : faces.index_range()) {
|
||||
@@ -953,11 +1063,11 @@ static bool mesh_calc_islands_loop_face_uv(const int totedge,
|
||||
for (const int64_t corner : faces[p_idx]) {
|
||||
const int edge_i = corner_edges[corner];
|
||||
loop_indices[num_lidx++] = int(corner);
|
||||
if (num_edge_borders && BLI_BITMAP_TEST(edge_borders, edge_i) &&
|
||||
(edge_border_count[edge_i] < 2))
|
||||
if (num_edge_boundaries && BLI_BITMAP_TEST(edge_boundaries, edge_i) &&
|
||||
(edge_boundary_count[edge_i] < 2))
|
||||
{
|
||||
edge_border_count[edge_i]++;
|
||||
if (edge_border_count[edge_i] == 2) {
|
||||
edge_boundary_count[edge_i]++;
|
||||
if (edge_boundary_count[edge_i] == 2) {
|
||||
edge_innercut_indices[num_einnercuts++] = edge_i;
|
||||
}
|
||||
}
|
||||
@@ -977,12 +1087,12 @@ static bool mesh_calc_islands_loop_face_uv(const int totedge,
|
||||
MEM_freeN(loop_indices);
|
||||
MEM_freeN(face_groups);
|
||||
|
||||
if (edge_borders) {
|
||||
MEM_freeN(edge_borders);
|
||||
if (num_edge_boundaries) {
|
||||
MEM_freeN(edge_boundaries);
|
||||
}
|
||||
|
||||
if (num_edge_borders) {
|
||||
MEM_freeN(edge_border_count);
|
||||
if (num_edge_boundaries) {
|
||||
MEM_freeN(edge_boundary_count);
|
||||
MEM_freeN(edge_innercut_indices);
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -206,13 +206,25 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
|
||||
const bke::AttributeAccessor attributes = export_mesh_->attributes();
|
||||
const VArraySpan sharp_edges = *attributes.lookup<bool>("sharp_edge", bke::AttrDomain::Edge);
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
face_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
|
||||
mesh_faces_,
|
||||
export_mesh_->corner_edges(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
&tot_smooth_groups_,
|
||||
use_bitflags);
|
||||
if (use_bitflags) {
|
||||
face_smooth_groups_ = BKE_mesh_calc_smoothgroups_bitflags(mesh_edges_.size(),
|
||||
export_mesh_->verts_num,
|
||||
mesh_faces_,
|
||||
export_mesh_->corner_edges(),
|
||||
export_mesh_->corner_verts(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
false,
|
||||
&tot_smooth_groups_);
|
||||
}
|
||||
else {
|
||||
face_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
|
||||
mesh_faces_,
|
||||
export_mesh_->corner_edges(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
&tot_smooth_groups_);
|
||||
}
|
||||
}
|
||||
|
||||
void OBJMesh::calc_face_order()
|
||||
|
||||
@@ -84,21 +84,37 @@ static void rna_Mesh_calc_corner_tri(Mesh *mesh)
|
||||
mesh->corner_tris();
|
||||
}
|
||||
|
||||
static void rna_Mesh_calc_smooth_groups(
|
||||
Mesh *mesh, bool use_bitflags, int **r_poly_group, int *r_poly_group_num, int *r_group_total)
|
||||
static void rna_Mesh_calc_smooth_groups(Mesh *mesh,
|
||||
bool use_bitflags,
|
||||
bool use_boundary_vertices_for_bitflags,
|
||||
int **r_poly_group,
|
||||
int *r_poly_group_num,
|
||||
int *r_group_total)
|
||||
{
|
||||
using namespace blender;
|
||||
*r_poly_group_num = mesh->faces_num;
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const VArraySpan sharp_edges = *attributes.lookup<bool>("sharp_edge", bke::AttrDomain::Edge);
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
|
||||
*r_poly_group = BKE_mesh_calc_smoothgroups(mesh->edges_num,
|
||||
mesh->faces(),
|
||||
mesh->corner_edges(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
r_group_total,
|
||||
use_bitflags);
|
||||
if (use_bitflags) {
|
||||
*r_poly_group = BKE_mesh_calc_smoothgroups_bitflags(mesh->edges_num,
|
||||
mesh->verts_num,
|
||||
mesh->faces(),
|
||||
mesh->corner_edges(),
|
||||
mesh->corner_verts(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
use_boundary_vertices_for_bitflags,
|
||||
r_group_total);
|
||||
}
|
||||
else {
|
||||
*r_poly_group = BKE_mesh_calc_smoothgroups(mesh->edges_num,
|
||||
mesh->faces(),
|
||||
mesh->corner_edges(),
|
||||
sharp_edges,
|
||||
sharp_faces,
|
||||
r_group_total);
|
||||
}
|
||||
}
|
||||
|
||||
static void rna_Mesh_normals_split_custom_set(Mesh *mesh,
|
||||
@@ -269,6 +285,15 @@ void RNA_api_mesh(StructRNA *srna)
|
||||
RNA_def_function_ui_description(func, "Calculate smooth groups from sharp edges");
|
||||
RNA_def_boolean(
|
||||
func, "use_bitflags", false, "", "Produce bitflags groups instead of simple numeric values");
|
||||
RNA_def_boolean(
|
||||
func,
|
||||
"use_boundary_vertices_for_bitflags",
|
||||
false,
|
||||
"",
|
||||
"Also consider different smoothgroups sharing only vertices (but without any common edge) "
|
||||
"as neighbors, preventing them from sharing the same bitflag value. Only effective when "
|
||||
"`use_bitflags` is set. WARNING: Will overflow (run out of available bits) easily with some "
|
||||
"types of topology, e.g. large fans of sharp edges");
|
||||
/* return values */
|
||||
parm = RNA_def_int_array(func, "poly_groups", 1, nullptr, 0, 0, "", "Smooth Groups", 0, 0);
|
||||
RNA_def_parameter_flags(parm, PROP_DYNAMIC, PARM_OUTPUT);
|
||||
|
||||
Reference in New Issue
Block a user