Sculpt: Optimize sculpt vertex neighbor storage
Currently we calculate neighbors for vertices in batches. The idea is to access topology data all at once, storing the result in a local node- sized vector that can fit in CPU caches. Currently we use `Vector<Vector<int>>` for storing the neighbors, and that works well enough when the number of neighbors fits into the inline buffer, but whenever it doesn't it causes many vector reallocations and scatters the neighbor storage in arbitrary memory locations. This commit changes to using a `GroupedSpan` to store the neighbors, in other words contiguous storage split into groups by an array of offset integers. This reduces local per-vertex memory usage by 20 bytes and makes memory access more predictable. I observed a 1.39x performance improvement for the mesh smooth filter on a large triangulated mesh, and a 1.14x improvement for a mesh of mostly quads. In the brush benchmark on a quad mesh the difference I observed is a small slowdown. I'm not sure why that happens but I trust the results from the filter a bit more. Resolves #130797. Pull Request: https://projects.blender.org/blender/blender/pulls/130941
This commit is contained in:
@@ -34,7 +34,8 @@ struct LocalData {
|
||||
Vector<float3> new_positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
|
||||
@@ -138,9 +139,13 @@ static void calc_translations_faces(const Span<float3> vert_positions,
|
||||
{
|
||||
const Span<int> verts = node.verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.new_positions.resize(verts.size());
|
||||
const MutableSpan<float3> new_positions = tls.new_positions;
|
||||
|
||||
@@ -33,19 +33,16 @@ inline namespace relax_cc {
|
||||
struct MeshLocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
};
|
||||
|
||||
struct GridLocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<SubdivCCGCoord>> vert_neighbors;
|
||||
};
|
||||
|
||||
struct BMeshLocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<BMVert *>> vert_neighbors;
|
||||
};
|
||||
|
||||
static void apply_positions_faces(const Sculpt &sd,
|
||||
@@ -189,7 +186,6 @@ static void do_relax_face_sets_brush_mesh(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
MeshLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_faces(
|
||||
position_data.eval,
|
||||
vert_normals,
|
||||
@@ -202,7 +198,6 @@ static void do_relax_face_sets_brush_mesh(const Depsgraph &depsgraph,
|
||||
relax_face_sets,
|
||||
nodes[i].verts(),
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
@@ -321,7 +316,6 @@ static void do_relax_face_sets_brush_grids(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
GridLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_grids(
|
||||
subdiv_ccg,
|
||||
faces,
|
||||
@@ -332,7 +326,6 @@ static void do_relax_face_sets_brush_grids(const Depsgraph &depsgraph,
|
||||
nodes[i].grids(),
|
||||
relax_face_sets,
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
@@ -425,14 +418,12 @@ static void do_relax_face_sets_brush_bmesh(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
BMeshLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_bmesh(
|
||||
BKE_pbvh_bmesh_node_unique_verts(&nodes[i]),
|
||||
current_positions.as_mutable_span().slice(node_vert_offsets[pos]),
|
||||
face_set_offset,
|
||||
relax_face_sets,
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
@@ -528,7 +519,6 @@ static void do_topology_relax_brush_mesh(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
MeshLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_faces(
|
||||
position_data.eval,
|
||||
vert_normals,
|
||||
@@ -541,7 +531,6 @@ static void do_topology_relax_brush_mesh(const Depsgraph &depsgraph,
|
||||
false,
|
||||
nodes[i].verts(),
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
@@ -643,7 +632,6 @@ static void do_topology_relax_brush_grids(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
GridLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_grids(
|
||||
subdiv_ccg,
|
||||
faces,
|
||||
@@ -654,7 +642,6 @@ static void do_topology_relax_brush_grids(const Depsgraph &depsgraph,
|
||||
nodes[i].grids(),
|
||||
false,
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
@@ -745,14 +732,12 @@ static void do_topology_relax_brush_bmesh(const Depsgraph &depsgraph,
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
BMeshLocalData &tls = all_tls.local();
|
||||
smooth::calc_relaxed_translations_bmesh(
|
||||
BKE_pbvh_bmesh_node_unique_verts(&nodes[i]),
|
||||
current_positions.as_mutable_span().slice(node_vert_offsets[pos]),
|
||||
face_set_offset,
|
||||
false,
|
||||
factors.as_span().slice(node_vert_offsets[pos]),
|
||||
tls.vert_neighbors,
|
||||
translations.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> new_positions;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
@@ -126,18 +127,18 @@ BLI_NOINLINE static void do_smooth_brush_mesh(const Depsgraph &depsgraph,
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
LocalData &tls = all_tls.local();
|
||||
const Span<int> verts = nodes[i].verts();
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors_interior(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
ss.vertex_info.boundary,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors_interior(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
ss.vertex_info.boundary,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
smooth::neighbor_data_average_mesh_check_loose(
|
||||
position_data.eval,
|
||||
verts,
|
||||
tls.vert_neighbors,
|
||||
neighbors,
|
||||
new_positions.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float> masks;
|
||||
Vector<float> new_masks;
|
||||
};
|
||||
@@ -54,21 +55,6 @@ static Vector<float> iteration_strengths(const float strength)
|
||||
return result;
|
||||
}
|
||||
|
||||
static void calc_smooth_masks_faces(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
const Span<float> masks,
|
||||
LocalData &tls,
|
||||
const MutableSpan<float> new_masks)
|
||||
{
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, tls.vert_neighbors);
|
||||
const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
|
||||
smooth::neighbor_data_average_mesh(masks, vert_neighbors, new_masks);
|
||||
}
|
||||
|
||||
static void apply_masks_faces(const Depsgraph &depsgraph,
|
||||
const Brush &brush,
|
||||
const Span<float3> positions_eval,
|
||||
@@ -154,14 +140,17 @@ static void do_smooth_brush_mesh(const Depsgraph &depsgraph,
|
||||
* neighboring nodes. */
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
LocalData &tls = all_tls.local();
|
||||
calc_smooth_masks_faces(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
nodes[i].verts(),
|
||||
mask.span.as_span(),
|
||||
tls,
|
||||
new_masks.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
nodes[i].verts(),
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
smooth::neighbor_data_average_mesh(
|
||||
mask.span.as_span(),
|
||||
neighbors,
|
||||
new_masks.as_mutable_span().slice(node_vert_offsets[pos]));
|
||||
});
|
||||
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i, const int pos) {
|
||||
|
||||
@@ -35,7 +35,8 @@ struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> laplacian_disp;
|
||||
Vector<float3> average_positions;
|
||||
Vector<float3> translations;
|
||||
@@ -112,18 +113,17 @@ BLI_NOINLINE static void do_surface_smooth_brush_mesh(const Depsgraph &depsgraph
|
||||
const OrigPositionData orig_data = orig_position_data_get_mesh(object, nodes[i]);
|
||||
const Span<float> factors = all_factors.as_span().slice(node_offsets[pos]);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.average_positions.resize(verts.size());
|
||||
const MutableSpan<float3> average_positions = tls.average_positions;
|
||||
smooth::neighbor_data_average_mesh(
|
||||
position_data.eval, tls.vert_neighbors, average_positions);
|
||||
smooth::neighbor_data_average_mesh(position_data.eval, neighbors, average_positions);
|
||||
|
||||
tls.laplacian_disp.resize(verts.size());
|
||||
const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
|
||||
@@ -147,18 +147,18 @@ BLI_NOINLINE static void do_surface_smooth_brush_mesh(const Depsgraph &depsgraph
|
||||
const MutableSpan<float3> laplacian_disp = gather_data_mesh(
|
||||
all_laplacian_disp.as_span(), verts, tls.laplacian_disp);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.average_positions.resize(verts.size());
|
||||
const MutableSpan<float3> average_laplacian_disps = tls.average_positions;
|
||||
smooth::neighbor_data_average_mesh(
|
||||
all_laplacian_disp.as_span(), tls.vert_neighbors, average_laplacian_disps);
|
||||
all_laplacian_disp.as_span(), neighbors, average_laplacian_disps);
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
|
||||
@@ -34,7 +34,8 @@ struct LocalData {
|
||||
Vector<float3> positions;
|
||||
Vector<float> factors;
|
||||
Vector<float> distances;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
|
||||
@@ -75,7 +76,7 @@ static inline void add_neighbor_influence(const float3 &position,
|
||||
|
||||
BLI_NOINLINE static void calc_neighbor_influence(const Span<float3> vert_positions,
|
||||
const Span<float3> positions,
|
||||
const Span<Vector<int>> vert_neighbors,
|
||||
const GroupedSpan<int> vert_neighbors,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
for (const int i : positions.index_range()) {
|
||||
@@ -181,15 +182,18 @@ static void calc_faces(const Depsgraph &depsgraph,
|
||||
|
||||
scale_factors(tls.factors, cache.bstrength);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(
|
||||
faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, verts, tls.vert_neighbors);
|
||||
const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
calc_translation_directions(brush, cache, positions, translations);
|
||||
calc_neighbor_influence(position_data.eval, positions, vert_neighbors, translations);
|
||||
calc_neighbor_influence(position_data.eval, positions, neighbors, translations);
|
||||
scale_translations(translations, tls.factors);
|
||||
|
||||
clip_and_lock_translations(sd, ss, position_data.eval, verts, translations);
|
||||
|
||||
@@ -437,16 +437,20 @@ OffsetIndices<int> create_node_vert_offsets_bmesh(const Span<bke::pbvh::BMeshNod
|
||||
* vertex to face map. That requires deduplication when building the neighbors, which
|
||||
* requires some intermediate data structure like a vector anyway.
|
||||
*/
|
||||
void calc_vert_neighbors(OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
GroupedSpan<int> vert_to_face,
|
||||
Span<bool> hide_poly,
|
||||
Span<int> verts,
|
||||
MutableSpan<Vector<int>> result);
|
||||
void calc_vert_neighbors(const SubdivCCG &subdiv_ccg,
|
||||
Span<int> grids,
|
||||
MutableSpan<Vector<SubdivCCGCoord>> result);
|
||||
void calc_vert_neighbors(Set<BMVert *, 0> verts, MutableSpan<Vector<BMVert *>> result);
|
||||
GroupedSpan<int> calc_vert_neighbors(OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
GroupedSpan<int> vert_to_face,
|
||||
Span<bool> hide_poly,
|
||||
Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data);
|
||||
GroupedSpan<int> calc_vert_neighbors(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> grids,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data);
|
||||
GroupedSpan<BMVert *> calc_vert_neighbors(Set<BMVert *, 0> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<BMVert *> &r_data);
|
||||
|
||||
/**
|
||||
* Find vertices connected to the indexed vertices across faces. Neighbors connected across hidden
|
||||
@@ -456,13 +460,14 @@ void calc_vert_neighbors(Set<BMVert *, 0> verts, MutableSpan<Vector<BMVert *>> r
|
||||
*
|
||||
* \note See #calc_vert_neighbors for information on why we use a Vector per element.
|
||||
*/
|
||||
void calc_vert_neighbors_interior(OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
GroupedSpan<int> vert_to_face,
|
||||
BitSpan boundary_verts,
|
||||
Span<bool> hide_poly,
|
||||
Span<int> verts,
|
||||
MutableSpan<Vector<int>> result);
|
||||
GroupedSpan<int> calc_vert_neighbors_interior(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const BitSpan boundary_verts,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data);
|
||||
void calc_vert_neighbors_interior(OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
BitSpan boundary_verts,
|
||||
|
||||
@@ -449,6 +449,37 @@ Span<int> vert_neighbors_get_mesh(const OffsetIndices<int> faces,
|
||||
return r_neighbors.as_span();
|
||||
}
|
||||
|
||||
inline void append_neighbors_to_vector(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const int vert,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
const int vert_start = r_data.size();
|
||||
for (const int face : vert_to_face[vert]) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
/* In order to support non-manifold topology, both neighboring vertices are added for each
|
||||
* face corner. That results in half being duplicates for any "normal" topology. */
|
||||
const int2 neighbors = bke::mesh::face_find_adjacent_verts(faces[face], corner_verts, vert);
|
||||
for (const int neighbor : {neighbors[0], neighbors[1]}) {
|
||||
bool found = false;
|
||||
for (int i = r_data.size() - 1; i >= vert_start; i--) {
|
||||
if (r_data[i] == neighbor) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
r_data.append(neighbor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace boundary {
|
||||
|
||||
bool vert_is_boundary(const GroupedSpan<int> vert_to_face_map,
|
||||
@@ -7334,88 +7365,112 @@ OffsetIndices<int> create_node_vert_offsets_bmesh(const Span<bke::pbvh::BMeshNod
|
||||
return offset_indices::accumulate_counts_to_offsets(node_data);
|
||||
}
|
||||
|
||||
void calc_vert_neighbors(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<Vector<int>> result)
|
||||
GroupedSpan<int> calc_vert_neighbors(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
BLI_assert(result.size() == verts.size());
|
||||
BLI_assert(corner_verts.size() == faces.total_size());
|
||||
r_offset_data.resize(verts.size() + 1);
|
||||
r_data.clear();
|
||||
for (const int i : verts.index_range()) {
|
||||
vert_neighbors_get_mesh(faces, corner_verts, vert_to_face, hide_poly, verts[i], result[i]);
|
||||
r_offset_data[i] = r_data.size();
|
||||
append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, verts[i], r_data);
|
||||
}
|
||||
r_offset_data.last() = r_data.size();
|
||||
return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
|
||||
void calc_vert_neighbors(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> grids,
|
||||
const MutableSpan<Vector<SubdivCCGCoord>> result)
|
||||
GroupedSpan<int> calc_vert_neighbors(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> grids,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
SubdivCCGNeighbors neighbors;
|
||||
BLI_assert(result.size() == grids.size() * key.grid_area);
|
||||
|
||||
r_offset_data.resize(key.grid_area * grids.size() + 1);
|
||||
r_data.clear();
|
||||
|
||||
for (const int i : grids.index_range()) {
|
||||
const int grid = grids[i];
|
||||
const int node_verts_start = i * key.grid_area;
|
||||
r_offset_data[node_verts_start] = r_data.size();
|
||||
|
||||
for (const int y : IndexRange(key.grid_size)) {
|
||||
for (const int x : IndexRange(key.grid_size)) {
|
||||
const int offset = CCG_grid_xy_to_index(key.grid_size, x, y);
|
||||
const int node_vert_index = node_verts_start + offset;
|
||||
|
||||
for (const short y : IndexRange(key.grid_size)) {
|
||||
for (const short x : IndexRange(key.grid_size)) {
|
||||
SubdivCCGCoord coord{};
|
||||
coord.grid_index = grid;
|
||||
coord.x = x;
|
||||
coord.y = y;
|
||||
|
||||
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbors);
|
||||
|
||||
result[node_vert_index] = Vector<SubdivCCGCoord>(neighbors.coords.as_span());
|
||||
for (const SubdivCCGCoord neighbor : neighbors.coords) {
|
||||
r_data.append(neighbor.to_index(key));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
void calc_vert_neighbors(Set<BMVert *, 0> verts, const MutableSpan<Vector<BMVert *>> result)
|
||||
{
|
||||
BLI_assert(verts.size() == result.size());
|
||||
|
||||
int i = 0;
|
||||
GroupedSpan<BMVert *> calc_vert_neighbors(Set<BMVert *, 0> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<BMVert *> &r_data)
|
||||
{
|
||||
r_offset_data.resize(verts.size() + 1);
|
||||
r_data.clear();
|
||||
|
||||
Vector<BMVert *, 64> neighbor_data;
|
||||
int i = 0;
|
||||
for (BMVert *vert : verts) {
|
||||
Span<BMVert *> neighbors = vert_neighbors_get_bmesh(*vert, neighbor_data);
|
||||
result[i] = Vector<BMVert *>(neighbors);
|
||||
r_offset_data[i] = r_data.size();
|
||||
r_data.extend(vert_neighbors_get_bmesh(*vert, neighbor_data));
|
||||
i++;
|
||||
}
|
||||
r_offset_data.last() = r_data.size();
|
||||
return GroupedSpan<BMVert *>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
|
||||
void calc_vert_neighbors_interior(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const BitSpan boundary_verts,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<Vector<int>> result)
|
||||
GroupedSpan<int> calc_vert_neighbors_interior(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const BitSpan boundary_verts,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
BLI_assert(result.size() == verts.size());
|
||||
BLI_assert(corner_verts.size() == faces.total_size());
|
||||
|
||||
r_offset_data.resize(verts.size() + 1);
|
||||
r_data.clear();
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
Vector<int> &neighbors = result[i];
|
||||
vert_neighbors_get_mesh(faces, corner_verts, vert_to_face, hide_poly, verts[i], neighbors);
|
||||
const int vert_start = r_data.size();
|
||||
r_offset_data[i] = vert_start;
|
||||
append_neighbors_to_vector(faces, corner_verts, vert_to_face, hide_poly, vert, r_data);
|
||||
|
||||
if (boundary_verts[vert]) {
|
||||
if (neighbors.size() == 2) {
|
||||
/* Do not include neighbors of corner vertices. */
|
||||
neighbors.clear();
|
||||
/* Do not include neighbors of corner vertices. */
|
||||
if (r_data.size() == vert_start + 2) {
|
||||
r_data.resize(vert_start);
|
||||
}
|
||||
else {
|
||||
/* Only include other boundary vertices as neighbors of boundary vertices. */
|
||||
neighbors.remove_if([&](const int vert) { return !boundary_verts[vert]; });
|
||||
for (int neighbor_i = r_data.size() - 1; neighbor_i >= vert_start; neighbor_i--) {
|
||||
if (!boundary_verts[r_data[neighbor_i]]) {
|
||||
r_data.remove_and_reorder(neighbor_i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
r_offset_data.last() = r_data.size();
|
||||
return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
|
||||
void calc_vert_neighbors_interior(const OffsetIndices<int> faces,
|
||||
|
||||
@@ -1015,7 +1015,8 @@ struct LocalDataMesh {
|
||||
Vector<float3> slide_directions;
|
||||
|
||||
/* Smooth */
|
||||
Vector<Vector<int>> neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> average_positions;
|
||||
|
||||
Vector<float3> new_positions;
|
||||
@@ -1037,7 +1038,8 @@ struct LocalDataGrids {
|
||||
Vector<float3> slide_directions;
|
||||
|
||||
/* Smooth */
|
||||
Vector<Vector<SubdivCCGCoord>> neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> average_positions;
|
||||
|
||||
Vector<float3> new_positions;
|
||||
@@ -1059,7 +1061,8 @@ struct LocalDataBMesh {
|
||||
Vector<float3> slide_directions;
|
||||
|
||||
/* Smooth */
|
||||
Vector<Vector<BMVert *>> neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<BMVert *> neighbor_data;
|
||||
Vector<float3> average_positions;
|
||||
|
||||
Vector<float3> new_positions;
|
||||
@@ -2481,7 +2484,7 @@ BLI_NOINLINE static void calc_smooth_position(const Span<float3> positions,
|
||||
|
||||
BLI_NOINLINE static void calc_average_position(const Span<float3> vert_positions,
|
||||
const Span<int> vert_propagation_steps,
|
||||
const Span<Vector<int>> neighbors,
|
||||
const GroupedSpan<int> neighbors,
|
||||
const Span<int> propagation_steps,
|
||||
const MutableSpan<float> factors,
|
||||
const MutableSpan<float3> average_positions)
|
||||
@@ -2507,38 +2510,8 @@ BLI_NOINLINE static void calc_average_position(const Span<float3> vert_positions
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void calc_average_position(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> vert_propagation_steps,
|
||||
const Span<Vector<SubdivCCGCoord>> neighbors,
|
||||
const Span<int> propagation_steps,
|
||||
const MutableSpan<float> factors,
|
||||
const MutableSpan<float3> average_positions)
|
||||
{
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
const Span<float3> positions = subdiv_ccg.positions;
|
||||
|
||||
BLI_assert(neighbors.size() == propagation_steps.size());
|
||||
BLI_assert(neighbors.size() == factors.size());
|
||||
BLI_assert(neighbors.size() == average_positions.size());
|
||||
|
||||
for (const int i : neighbors.index_range()) {
|
||||
average_positions[i] = float3(0.0f);
|
||||
int valid_neighbors = 0;
|
||||
for (const SubdivCCGCoord neighbor : neighbors[i]) {
|
||||
if (propagation_steps[i] == vert_propagation_steps[neighbor.to_index(key)]) {
|
||||
average_positions[i] += positions[neighbor.to_index(key)];
|
||||
valid_neighbors++;
|
||||
}
|
||||
}
|
||||
average_positions[i] *= math::safe_rcp(float(valid_neighbors));
|
||||
if (valid_neighbors == 0) {
|
||||
factors[i] = 0.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void calc_average_position(const Span<int> vert_propagation_steps,
|
||||
const Span<Vector<BMVert *>> neighbors,
|
||||
const GroupedSpan<BMVert *> neighbors,
|
||||
const Span<int> propagation_steps,
|
||||
const MutableSpan<float> factors,
|
||||
const MutableSpan<float3> average_positions)
|
||||
@@ -2597,10 +2570,13 @@ static void calc_smooth_mesh(const Sculpt &sd,
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.neighbors;
|
||||
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
tls.average_positions.resize(verts.size());
|
||||
|
||||
const Span<float3> positions = gather_data_mesh(position_data.eval, verts, tls.positions);
|
||||
@@ -2664,13 +2640,12 @@ static void calc_smooth_grids(const Sculpt &sd,
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.neighbors.resize(grid_verts_num);
|
||||
const MutableSpan<Vector<SubdivCCGCoord>> neighbors = tls.neighbors;
|
||||
calc_vert_neighbors(subdiv_ccg, grids, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(
|
||||
subdiv_ccg, grids, tls.neighbor_offsets, tls.neighbor_data);
|
||||
|
||||
tls.average_positions.resize(grid_verts_num);
|
||||
const MutableSpan<float3> average_positions = tls.average_positions;
|
||||
calc_average_position(subdiv_ccg,
|
||||
calc_average_position(subdiv_ccg.positions,
|
||||
vert_propagation_steps,
|
||||
neighbors,
|
||||
propagation_steps,
|
||||
@@ -2733,9 +2708,8 @@ static void calc_smooth_bmesh(const Sculpt &sd,
|
||||
|
||||
scale_factors(factors, strength);
|
||||
|
||||
tls.neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<BMVert *>> neighbors = tls.neighbors;
|
||||
calc_vert_neighbors(verts, neighbors);
|
||||
const GroupedSpan<BMVert *> neighbors = calc_vert_neighbors(
|
||||
verts, tls.neighbor_offsets, tls.neighbor_data);
|
||||
|
||||
tls.average_positions.resize(verts.size());
|
||||
const MutableSpan<float3> average_positions = tls.average_positions;
|
||||
|
||||
@@ -128,39 +128,50 @@ static MutableSpan<int> calc_visible_vert_indices_bmesh(const Set<BMVert *, 0> &
|
||||
return indices;
|
||||
}
|
||||
|
||||
static void calc_vert_neighbor_indices_grids(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<Vector<int>> neighbor_indices)
|
||||
static GroupedSpan<int> calc_vert_neighbor_indices_grids(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
BLI_assert(verts.size() == neighbor_indices.size());
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
|
||||
r_offset_data.resize(verts.size() + 1);
|
||||
r_data.clear();
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
r_offset_data[i] = r_data.size();
|
||||
SubdivCCGNeighbors neighbors;
|
||||
BKE_subdiv_ccg_neighbor_coords_get(
|
||||
subdiv_ccg, SubdivCCGCoord::from_index(key, verts[i]), false, neighbors);
|
||||
|
||||
neighbor_indices[i].clear();
|
||||
for (const SubdivCCGCoord coord : neighbors.coords) {
|
||||
neighbor_indices[i].append(coord.to_index(key));
|
||||
r_data.append(coord.to_index(key));
|
||||
}
|
||||
}
|
||||
|
||||
r_offset_data.last() = r_data.size();
|
||||
return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
|
||||
static void calc_vert_neighbor_indices_bmesh(const BMesh &bm,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<Vector<int>> neighbor_indices)
|
||||
static GroupedSpan<int> calc_vert_neighbor_indices_bmesh(const BMesh &bm,
|
||||
const Span<int> verts,
|
||||
Vector<int> &r_offset_data,
|
||||
Vector<int> &r_data)
|
||||
{
|
||||
BLI_assert(verts.size() == neighbor_indices.size());
|
||||
Vector<BMVert *, 64> neighbors;
|
||||
|
||||
r_offset_data.resize(verts.size() + 1);
|
||||
r_data.clear();
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
r_offset_data[i] = r_data.size();
|
||||
BMVert *vert = BM_vert_at_index(&const_cast<BMesh &>(bm), verts[i]);
|
||||
neighbor_indices[i].clear();
|
||||
for (const BMVert *neighbor : vert_neighbors_get_bmesh(*vert, neighbors)) {
|
||||
neighbor_indices[i].append(BM_elem_index_get(neighbor));
|
||||
r_data.append(BM_elem_index_get(neighbor));
|
||||
}
|
||||
}
|
||||
r_offset_data.last() = r_data.size();
|
||||
return GroupedSpan<int>(r_offset_data.as_span(), r_data.as_span());
|
||||
}
|
||||
|
||||
static float3 cloth_brush_simulation_location_get(const SculptSession &ss, const Brush *brush)
|
||||
@@ -370,7 +381,7 @@ static void add_constraints_for_verts(const Object &object,
|
||||
const Span<float3> init_positions,
|
||||
const int node_index,
|
||||
const Span<int> verts,
|
||||
const Span<Vector<int>> vert_neighbors,
|
||||
const GroupedSpan<int> vert_neighbors,
|
||||
SimulationData &cloth_sim,
|
||||
Set<OrderedEdge> &created_length_constraints)
|
||||
{
|
||||
@@ -496,7 +507,8 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
IndexMaskMemory memory;
|
||||
Set<OrderedEdge> created_length_constraints;
|
||||
Vector<int> vert_indices;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
switch (pbvh.type()) {
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
|
||||
@@ -529,9 +541,13 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
}
|
||||
uninitialized_nodes.foreach_index([&](const int i) {
|
||||
const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, vert_indices);
|
||||
vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(
|
||||
faces, corner_verts, vert_to_face_map, hide_poly, verts, vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
verts,
|
||||
neighbor_offsets,
|
||||
neighbor_data);
|
||||
add_constraints_for_verts(object,
|
||||
brush,
|
||||
initial_location,
|
||||
@@ -539,7 +555,7 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
init_positions,
|
||||
cloth_sim.node_state_index.lookup(&nodes[i]),
|
||||
verts,
|
||||
vert_neighbors,
|
||||
neighbors,
|
||||
cloth_sim,
|
||||
created_length_constraints);
|
||||
});
|
||||
@@ -558,8 +574,8 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
uninitialized_nodes.foreach_index([&](const int i) {
|
||||
const Span<int> verts = calc_visible_vert_indices_grids(
|
||||
key, grid_hidden, nodes[i].grids(), vert_indices);
|
||||
vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbor_indices_grids(subdiv_ccg, verts, vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbor_indices_grids(
|
||||
subdiv_ccg, verts, neighbor_offsets, neighbor_data);
|
||||
add_constraints_for_verts(object,
|
||||
brush,
|
||||
initial_location,
|
||||
@@ -567,7 +583,7 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
cloth_sim.init_pos,
|
||||
cloth_sim.node_state_index.lookup(&nodes[i]),
|
||||
verts,
|
||||
vert_neighbors,
|
||||
neighbors,
|
||||
cloth_sim,
|
||||
created_length_constraints);
|
||||
});
|
||||
@@ -586,8 +602,8 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
uninitialized_nodes.foreach_index([&](const int i) {
|
||||
const Set<BMVert *, 0> &bm_verts = BKE_pbvh_bmesh_node_unique_verts(&nodes[i]);
|
||||
const Span<int> verts = calc_visible_vert_indices_bmesh(bm_verts, vert_indices);
|
||||
vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbor_indices_bmesh(bm, verts, vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbor_indices_bmesh(
|
||||
bm, verts, neighbor_offsets, neighbor_data);
|
||||
add_constraints_for_verts(object,
|
||||
brush,
|
||||
initial_location,
|
||||
@@ -595,7 +611,7 @@ void ensure_nodes_constraints(const Sculpt &sd,
|
||||
cloth_sim.init_pos,
|
||||
cloth_sim.node_state_index.lookup(&nodes[i]),
|
||||
verts,
|
||||
vert_neighbors,
|
||||
neighbors,
|
||||
cloth_sim,
|
||||
created_length_constraints);
|
||||
});
|
||||
|
||||
@@ -81,7 +81,8 @@ static EnumPropertyItem prop_color_filter_types[] = {
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float4> colors;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float4> average_colors;
|
||||
Vector<float4> new_colors;
|
||||
};
|
||||
@@ -250,9 +251,13 @@ static void color_filter_task(const Depsgraph &depsgraph,
|
||||
verts[i]);
|
||||
}
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, {}, verts, tls.vert_neighbors);
|
||||
const Span<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
{},
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.average_colors.resize(verts.size());
|
||||
const MutableSpan<float4> average_colors = tls.average_colors;
|
||||
@@ -334,7 +339,8 @@ static void sculpt_color_presmooth_init(const Mesh &mesh, Object &object)
|
||||
});
|
||||
|
||||
struct LocalData {
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float4> averaged_colors;
|
||||
};
|
||||
threading::EnumerableThreadSpecific<LocalData> all_tls;
|
||||
@@ -343,14 +349,17 @@ static void sculpt_color_presmooth_init(const Mesh &mesh, Object &object)
|
||||
LocalData &tls = all_tls.local();
|
||||
const Span<int> verts = nodes[i].verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, {}, verts, tls.vert_neighbors);
|
||||
const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
{},
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.averaged_colors.resize(verts.size());
|
||||
const MutableSpan<float4> averaged_colors = tls.averaged_colors;
|
||||
smooth::neighbor_data_average_mesh(
|
||||
pre_smoothed_color.as_span(), vert_neighbors, averaged_colors);
|
||||
smooth::neighbor_data_average_mesh(pre_smoothed_color.as_span(), neighbors, averaged_colors);
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
pre_smoothed_color[verts[i]] = math::interpolate(
|
||||
|
||||
@@ -121,7 +121,8 @@ struct FilterLocalData {
|
||||
Vector<int> visible_verts;
|
||||
Vector<float> node_mask;
|
||||
Vector<float> new_mask;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
};
|
||||
|
||||
static void apply_new_mask_mesh(const Depsgraph &depsgraph,
|
||||
@@ -154,7 +155,7 @@ static void apply_new_mask_mesh(const Depsgraph &depsgraph,
|
||||
|
||||
static void smooth_mask_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<bool> hide_vert,
|
||||
const Span<float> mask,
|
||||
@@ -164,9 +165,13 @@ static void smooth_mask_mesh(const OffsetIndices<int> faces,
|
||||
{
|
||||
const Span<int> verts = node.verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
|
||||
copy_old_hidden_mask_mesh(verts, hide_vert, mask, new_mask);
|
||||
@@ -174,7 +179,7 @@ static void smooth_mask_mesh(const OffsetIndices<int> faces,
|
||||
|
||||
static void sharpen_mask_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<bool> hide_vert,
|
||||
const Span<float> mask,
|
||||
@@ -188,9 +193,13 @@ static void sharpen_mask_mesh(const OffsetIndices<int> faces,
|
||||
const MutableSpan<float> node_mask = tls.node_mask;
|
||||
gather_data_mesh(mask, verts, node_mask);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
smooth::neighbor_data_average_mesh(mask, neighbors, new_mask);
|
||||
|
||||
@@ -200,7 +209,7 @@ static void sharpen_mask_mesh(const OffsetIndices<int> faces,
|
||||
|
||||
static void grow_mask_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<bool> hide_vert,
|
||||
const Span<float> mask,
|
||||
@@ -210,9 +219,13 @@ static void grow_mask_mesh(const OffsetIndices<int> faces,
|
||||
{
|
||||
const Span<int> verts = node.verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
new_mask[i] = mask[verts[i]];
|
||||
@@ -225,7 +238,7 @@ static void grow_mask_mesh(const OffsetIndices<int> faces,
|
||||
|
||||
static void shrink_mask_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const GroupedSpan<int> vert_to_face,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<bool> hide_vert,
|
||||
const Span<float> mask,
|
||||
@@ -235,9 +248,13 @@ static void shrink_mask_mesh(const OffsetIndices<int> faces,
|
||||
{
|
||||
const Span<int> verts = node.verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
new_mask[i] = mask[verts[i]];
|
||||
|
||||
@@ -342,7 +342,8 @@ static void calc_smooth_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> new_positions;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
@@ -373,15 +374,15 @@ static void calc_smooth_filter(const Depsgraph &depsgraph,
|
||||
scale_factors(factors, strength);
|
||||
clamp_factors(factors, -1.0f, 1.0f);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors_interior(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
ss.vertex_info.boundary,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors_interior(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
ss.vertex_info.boundary,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.new_positions.resize(verts.size());
|
||||
const MutableSpan<float3> new_positions = tls.new_positions;
|
||||
smooth::neighbor_data_average_mesh_check_loose(
|
||||
@@ -952,7 +953,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
switch (pbvh.type()) {
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
@@ -991,7 +991,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
false,
|
||||
verts,
|
||||
factors,
|
||||
tls.vert_neighbors,
|
||||
translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
@@ -1004,7 +1003,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<SubdivCCGCoord>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
|
||||
@@ -1041,7 +1039,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
grids,
|
||||
false,
|
||||
factors,
|
||||
tls.vert_neighbors,
|
||||
translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
@@ -1054,7 +1051,6 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<BMVert *>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
BMesh &bm = *ss.bm;
|
||||
@@ -1079,7 +1075,7 @@ static void calc_relax_filter(const Depsgraph &depsgraph,
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
smooth::calc_relaxed_translations_bmesh(
|
||||
verts, positions, face_set_offset, false, factors, tls.vert_neighbors, translations);
|
||||
verts, positions, face_set_offset, false, factors, translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
@@ -1110,7 +1106,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
@@ -1151,7 +1146,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
relax_face_sets,
|
||||
verts,
|
||||
factors,
|
||||
tls.vert_neighbors,
|
||||
translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
@@ -1164,7 +1158,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<SubdivCCGCoord>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
const Mesh &base_mesh = *static_cast<const Mesh *>(object.data);
|
||||
@@ -1211,7 +1204,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
grids,
|
||||
relax_face_sets,
|
||||
factors,
|
||||
tls.vert_neighbors,
|
||||
translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
@@ -1224,7 +1216,6 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<BMVert *>> vert_neighbors;
|
||||
Vector<float3> translations;
|
||||
};
|
||||
BMesh &bm = *ss.bm;
|
||||
@@ -1250,13 +1241,8 @@ static void calc_relax_face_sets_filter(const Depsgraph &depsgraph,
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
smooth::calc_relaxed_translations_bmesh(verts,
|
||||
positions,
|
||||
face_set_offset,
|
||||
relax_face_sets,
|
||||
factors,
|
||||
tls.vert_neighbors,
|
||||
translations);
|
||||
smooth::calc_relaxed_translations_bmesh(
|
||||
verts, positions, face_set_offset, relax_face_sets, factors, translations);
|
||||
|
||||
zero_disabled_axis_components(*ss.filter_cache, translations);
|
||||
clip_and_lock_translations(sd, ss, positions, translations);
|
||||
@@ -1276,7 +1262,8 @@ static void calc_surface_smooth_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> average_positions;
|
||||
Vector<float3> laplacian_disp;
|
||||
Vector<float3> translations;
|
||||
@@ -1311,18 +1298,18 @@ static void calc_surface_smooth_filter(const Depsgraph &depsgraph,
|
||||
scale_factors(factors, strength);
|
||||
clamp_factors(factors, 0.0f, 1.0f);
|
||||
|
||||
tls.vert_neighbors.reinitialize(verts.size());
|
||||
calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.average_positions.reinitialize(verts.size());
|
||||
const MutableSpan<float3> average_positions = tls.average_positions;
|
||||
smooth::neighbor_data_average_mesh_check_loose(
|
||||
position_data.eval, verts, tls.vert_neighbors, average_positions);
|
||||
position_data.eval, verts, neighbors, average_positions);
|
||||
|
||||
tls.laplacian_disp.reinitialize(verts.size());
|
||||
const MutableSpan<float3> laplacian_disp = tls.laplacian_disp;
|
||||
@@ -1358,18 +1345,18 @@ static void calc_surface_smooth_filter(const Depsgraph &depsgraph,
|
||||
const MutableSpan<float3> laplacian_disp = gather_data_mesh(
|
||||
all_laplacian_disp.as_span(), verts, tls.laplacian_disp);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.vert_neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.average_positions.resize(verts.size());
|
||||
const MutableSpan<float3> average_laplacian_disps = tls.average_positions;
|
||||
smooth::neighbor_data_average_mesh_check_loose(
|
||||
all_laplacian_disp.as_span(), verts, tls.vert_neighbors, average_laplacian_disps);
|
||||
all_laplacian_disp.as_span(), verts, neighbors, average_laplacian_disps);
|
||||
|
||||
tls.translations.resize(verts.size());
|
||||
const MutableSpan<float3> translations = tls.translations;
|
||||
@@ -1561,7 +1548,8 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
|
||||
struct LocalData {
|
||||
Vector<float> factors;
|
||||
Vector<float3> positions;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> smooth_positions;
|
||||
Vector<float> sharpen_factors;
|
||||
Vector<float3> detail_directions;
|
||||
@@ -1601,10 +1589,13 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
|
||||
* stable state. */
|
||||
clamp_factors(factors, 0.0f, 0.5f);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(
|
||||
faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.smooth_positions.resize(verts.size());
|
||||
const MutableSpan<float3> smooth_positions = tls.smooth_positions;
|
||||
@@ -1675,8 +1666,6 @@ static void calc_sharpen_filter(const Depsgraph &depsgraph,
|
||||
* stable state. */
|
||||
clamp_factors(factors, 0.0f, 0.5f);
|
||||
|
||||
tls.vert_neighbors.resize(positions.size());
|
||||
|
||||
tls.smooth_positions.resize(positions.size());
|
||||
const MutableSpan<float3> smooth_positions = tls.smooth_positions;
|
||||
smooth::average_data_grids(
|
||||
@@ -2025,7 +2014,8 @@ static void mesh_filter_sharpen_init(const Depsgraph &depsgraph,
|
||||
|
||||
/* Smooth the calculated factors and directions to remove high frequency detail. */
|
||||
struct LocalData {
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float3> smooth_directions;
|
||||
Vector<float> smooth_factors;
|
||||
};
|
||||
@@ -2044,10 +2034,13 @@ static void mesh_filter_sharpen_init(const Depsgraph &depsgraph,
|
||||
LocalData &tls = all_tls.local();
|
||||
const Span<int> verts = nodes[i].verts();
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(
|
||||
faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.smooth_directions.resize(verts.size());
|
||||
smooth::neighbor_data_average_mesh_check_loose(detail_directions.as_span(),
|
||||
|
||||
@@ -255,7 +255,8 @@ struct ColorPaintLocalData {
|
||||
Vector<float4> colors;
|
||||
Vector<float4> new_colors;
|
||||
Vector<float4> mix_colors;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
};
|
||||
|
||||
static void do_color_smooth_task(const Depsgraph &depsgraph,
|
||||
@@ -308,10 +309,13 @@ static void do_color_smooth_task(const Depsgraph &depsgraph,
|
||||
verts[i]);
|
||||
}
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(
|
||||
faces, corner_verts, vert_to_face_map, attribute_data.hide_poly, verts, tls.vert_neighbors);
|
||||
const Span<Vector<int>> vert_neighbors = tls.vert_neighbors;
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
attribute_data.hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.new_colors.resize(verts.size());
|
||||
MutableSpan<float4> new_colors = tls.new_colors;
|
||||
@@ -320,7 +324,7 @@ static void do_color_smooth_task(const Depsgraph &depsgraph,
|
||||
vert_to_face_map,
|
||||
color_attribute.span,
|
||||
color_attribute.domain,
|
||||
vert_neighbors,
|
||||
neighbors,
|
||||
new_colors);
|
||||
|
||||
for (const int i : colors.index_range()) {
|
||||
|
||||
@@ -326,19 +326,30 @@ struct PoseGrowFactorData {
|
||||
|
||||
struct GrowFactorLocalData {
|
||||
Vector<int> vert_indices;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<int> neighbor_data_with_fake;
|
||||
};
|
||||
|
||||
BLI_NOINLINE static void add_fake_neighbors(const Span<int> fake_neighbors,
|
||||
const Span<int> verts,
|
||||
const MutableSpan<Vector<int>> neighbors)
|
||||
const Span<int> orig_neighbor_data,
|
||||
MutableSpan<int> neighbor_offsets,
|
||||
Vector<int> &neighbor_data_with_fake)
|
||||
{
|
||||
const OffsetIndices<int> offsets(neighbor_offsets);
|
||||
for (const int i : verts.index_range()) {
|
||||
const Span<int> orig_neighbors = orig_neighbor_data.slice(offsets[i]);
|
||||
|
||||
/* Modify the offsets in-place after using them to slice the current neighbor data. */
|
||||
neighbor_offsets[i] = neighbor_data_with_fake.size();
|
||||
neighbor_data_with_fake.extend(orig_neighbors);
|
||||
const int neighbor = fake_neighbors[verts[i]];
|
||||
if (neighbor != FAKE_NEIGHBOR_NONE) {
|
||||
neighbors[i].append(neighbor);
|
||||
neighbor_data_with_fake.append(neighbor);
|
||||
}
|
||||
}
|
||||
neighbor_offsets.last() = neighbor_data_with_fake.size();
|
||||
}
|
||||
|
||||
static void grow_factors_mesh(const ePaintSymmetryFlags symm,
|
||||
@@ -358,13 +369,24 @@ static void grow_factors_mesh(const ePaintSymmetryFlags symm,
|
||||
{
|
||||
const Span<int> verts = hide::node_visible_verts(node, hide_vert, tls.vert_indices);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
|
||||
calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
if (!fake_neighbors.is_empty()) {
|
||||
add_fake_neighbors(fake_neighbors, verts, neighbors);
|
||||
add_fake_neighbors(fake_neighbors,
|
||||
verts,
|
||||
tls.neighbor_data,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data_with_fake);
|
||||
}
|
||||
const GroupedSpan<int> neighbors(tls.neighbor_offsets.as_span(),
|
||||
fake_neighbors.is_empty() ?
|
||||
tls.neighbor_data.as_span() :
|
||||
tls.neighbor_data_with_fake.as_span());
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
const int vert = verts[i];
|
||||
|
||||
@@ -47,7 +47,7 @@ template<typename T> T calc_average(const Span<T> positions, const Span<int> ind
|
||||
template<typename T>
|
||||
void neighbor_data_average_mesh_check_loose(const Span<T> src,
|
||||
const Span<int> verts,
|
||||
const Span<Vector<int>> vert_neighbors,
|
||||
const GroupedSpan<int> vert_neighbors,
|
||||
const MutableSpan<T> dst)
|
||||
{
|
||||
BLI_assert(verts.size() == dst.size());
|
||||
@@ -66,16 +66,16 @@ void neighbor_data_average_mesh_check_loose(const Span<T> src,
|
||||
|
||||
template void neighbor_data_average_mesh_check_loose<float>(Span<float>,
|
||||
Span<int>,
|
||||
Span<Vector<int>>,
|
||||
GroupedSpan<int>,
|
||||
MutableSpan<float>);
|
||||
template void neighbor_data_average_mesh_check_loose<float3>(Span<float3>,
|
||||
Span<int>,
|
||||
Span<Vector<int>>,
|
||||
GroupedSpan<int>,
|
||||
MutableSpan<float3>);
|
||||
|
||||
template<typename T>
|
||||
void neighbor_data_average_mesh(const Span<T> src,
|
||||
const Span<Vector<int>> vert_neighbors,
|
||||
const GroupedSpan<int> vert_neighbors,
|
||||
const MutableSpan<T> dst)
|
||||
{
|
||||
BLI_assert(vert_neighbors.size() == dst.size());
|
||||
@@ -86,14 +86,12 @@ void neighbor_data_average_mesh(const Span<T> src,
|
||||
}
|
||||
}
|
||||
|
||||
template void neighbor_data_average_mesh<float>(Span<float>,
|
||||
Span<Vector<int>>,
|
||||
MutableSpan<float>);
|
||||
template void neighbor_data_average_mesh<float>(Span<float>, GroupedSpan<int>, MutableSpan<float>);
|
||||
template void neighbor_data_average_mesh<float3>(Span<float3>,
|
||||
Span<Vector<int>>,
|
||||
GroupedSpan<int>,
|
||||
MutableSpan<float3>);
|
||||
template void neighbor_data_average_mesh<float4>(Span<float4>,
|
||||
Span<Vector<int>>,
|
||||
GroupedSpan<int>,
|
||||
MutableSpan<float4>);
|
||||
|
||||
static float3 average_positions(const CCGKey &key,
|
||||
@@ -333,7 +331,7 @@ void neighbor_color_average(const OffsetIndices<int> faces,
|
||||
const GroupedSpan<int> vert_to_face_map,
|
||||
const GSpan color_attribute,
|
||||
const bke::AttrDomain color_domain,
|
||||
const Span<Vector<int>> vert_neighbors,
|
||||
const GroupedSpan<int> vert_neighbors,
|
||||
const MutableSpan<float4> smooth_colors)
|
||||
{
|
||||
BLI_assert(vert_neighbors.size() == smooth_colors.size());
|
||||
@@ -449,14 +447,12 @@ void calc_relaxed_translations_faces(const Span<float3> vert_positions,
|
||||
const bool filter_boundary_face_sets,
|
||||
const Span<int> verts,
|
||||
const Span<float> factors,
|
||||
Vector<Vector<int>> &neighbors,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
BLI_assert(verts.size() == factors.size());
|
||||
BLI_assert(verts.size() == translations.size());
|
||||
|
||||
neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
Vector<int> neighbors;
|
||||
|
||||
for (const int i : verts.index_range()) {
|
||||
if (factors[i] == 0.0f) {
|
||||
@@ -464,34 +460,36 @@ void calc_relaxed_translations_faces(const Span<float3> vert_positions,
|
||||
continue;
|
||||
}
|
||||
|
||||
vert_neighbors_get_mesh(faces, corner_verts, vert_to_face_map, hide_poly, verts[i], neighbors);
|
||||
|
||||
/* Don't modify corner vertices */
|
||||
if (neighbors[i].size() <= 2) {
|
||||
if (neighbors.size() <= 2) {
|
||||
translations[i] = float3(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_boundary = boundary_verts[verts[i]];
|
||||
if (is_boundary) {
|
||||
neighbors[i].remove_if([&](const int vert) { return !boundary_verts[vert]; });
|
||||
neighbors.remove_if([&](const int vert) { return !boundary_verts[vert]; });
|
||||
}
|
||||
|
||||
if (filter_boundary_face_sets) {
|
||||
neighbors[i].remove_if([&](const int vert) {
|
||||
neighbors.remove_if([&](const int vert) {
|
||||
return face_set::vert_has_unique_face_set(vert_to_face_map, face_sets, vert);
|
||||
});
|
||||
}
|
||||
|
||||
if (neighbors[i].is_empty()) {
|
||||
if (neighbors.is_empty()) {
|
||||
translations[i] = float3(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const float3 smoothed_position = calc_average(vert_positions, neighbors[i]);
|
||||
const float3 smoothed_position = calc_average(vert_positions, neighbors);
|
||||
|
||||
/* Normal Calculation */
|
||||
float3 normal;
|
||||
if (is_boundary && neighbors[i].size() == 2) {
|
||||
normal = calc_boundary_normal_corner(vert_positions[verts[i]], vert_positions, neighbors[i]);
|
||||
if (is_boundary && neighbors.size() == 2) {
|
||||
normal = calc_boundary_normal_corner(vert_positions[verts[i]], vert_positions, neighbors);
|
||||
if (math::is_zero(normal)) {
|
||||
translations[i] = float3(0);
|
||||
continue;
|
||||
@@ -517,20 +515,12 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
|
||||
const Span<int> grids,
|
||||
const bool filter_boundary_face_sets,
|
||||
const Span<float> factors,
|
||||
Vector<Vector<SubdivCCGCoord>> &neighbors,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
const Span<float3> positions = subdiv_ccg.positions;
|
||||
const Span<float3> normals = subdiv_ccg.normals;
|
||||
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
||||
|
||||
const int grid_verts_num = grids.size() * key.grid_area;
|
||||
BLI_assert(grid_verts_num == translations.size());
|
||||
BLI_assert(grid_verts_num == factors.size());
|
||||
|
||||
neighbors.resize(grid_verts_num);
|
||||
calc_vert_neighbors(subdiv_ccg, grids, neighbors);
|
||||
|
||||
for (const int i : grids.index_range()) {
|
||||
const IndexRange grid_range = bke::ccg::grid_range(key, grids[i]);
|
||||
const int node_start = i * key.grid_area;
|
||||
@@ -544,46 +534,49 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Don't modify corner vertices */
|
||||
if (neighbors[node_vert].size() <= 2) {
|
||||
translations[node_vert] = float3(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
SubdivCCGCoord coord{};
|
||||
coord.grid_index = grids[i];
|
||||
coord.x = x;
|
||||
coord.y = y;
|
||||
|
||||
SubdivCCGNeighbors neighbor_storage;
|
||||
BKE_subdiv_ccg_neighbor_coords_get(subdiv_ccg, coord, false, neighbor_storage);
|
||||
Vector<SubdivCCGCoord, 256> &neighbors = neighbor_storage.coords;
|
||||
|
||||
/* Don't modify corner vertices */
|
||||
if (neighbors.size() <= 2) {
|
||||
translations[node_vert] = float3(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const bool is_boundary = BKE_subdiv_ccg_coord_is_mesh_boundary(
|
||||
faces, corner_verts, boundary_verts, subdiv_ccg, coord);
|
||||
|
||||
if (is_boundary) {
|
||||
neighbors[node_vert].remove_if([&](const SubdivCCGCoord neighbor) {
|
||||
neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
|
||||
return !BKE_subdiv_ccg_coord_is_mesh_boundary(
|
||||
faces, corner_verts, boundary_verts, subdiv_ccg, neighbor);
|
||||
});
|
||||
}
|
||||
|
||||
if (filter_boundary_face_sets) {
|
||||
neighbors[node_vert].remove_if([&](const SubdivCCGCoord neighbor) {
|
||||
neighbors.remove_if([&](const SubdivCCGCoord neighbor) {
|
||||
return face_set::vert_has_unique_face_set(
|
||||
faces, corner_verts, vert_to_face_map, face_sets, subdiv_ccg, neighbor);
|
||||
});
|
||||
}
|
||||
|
||||
if (neighbors[i].is_empty()) {
|
||||
if (neighbors.is_empty()) {
|
||||
translations[node_vert] = float3(0);
|
||||
continue;
|
||||
}
|
||||
|
||||
const float3 smoothed_position = average_positions(key, positions, neighbors[node_vert]);
|
||||
const float3 smoothed_position = average_positions(key, positions, neighbors);
|
||||
|
||||
/* Normal Calculation */
|
||||
float3 normal;
|
||||
if (is_boundary && neighbors[i].size() == 2) {
|
||||
normal = calc_boundary_normal_corner(
|
||||
key, positions, positions[vert], neighbors[node_vert]);
|
||||
if (is_boundary && neighbors.size() == 2) {
|
||||
normal = calc_boundary_normal_corner(key, positions, positions[vert], neighbors);
|
||||
if (math::is_zero(normal)) {
|
||||
translations[node_vert] = float3(0);
|
||||
continue;
|
||||
@@ -607,25 +600,25 @@ void calc_relaxed_translations_bmesh(const Set<BMVert *, 0> &verts,
|
||||
const int face_set_offset,
|
||||
const bool filter_boundary_face_sets,
|
||||
const Span<float> factors,
|
||||
Vector<Vector<BMVert *>> &neighbors,
|
||||
const MutableSpan<float3> translations)
|
||||
{
|
||||
BLI_assert(verts.size() == factors.size());
|
||||
BLI_assert(verts.size() == translations.size());
|
||||
|
||||
neighbors.resize(verts.size());
|
||||
calc_vert_neighbors(verts, neighbors);
|
||||
Vector<BMVert *, 64> neighbors;
|
||||
|
||||
int i = 0;
|
||||
for (const BMVert *vert : verts) {
|
||||
for (BMVert *vert : verts) {
|
||||
if (factors[i] == 0.0f) {
|
||||
translations[i] = float3(0);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
vert_neighbors_get_bmesh(*vert, neighbors);
|
||||
|
||||
/* Don't modify corner vertices */
|
||||
if (neighbors[i].size() <= 2) {
|
||||
if (neighbors.size() <= 2) {
|
||||
translations[i] = float3(0);
|
||||
i++;
|
||||
continue;
|
||||
@@ -633,27 +626,27 @@ void calc_relaxed_translations_bmesh(const Set<BMVert *, 0> &verts,
|
||||
|
||||
const bool is_boundary = BM_vert_is_boundary(vert);
|
||||
if (is_boundary) {
|
||||
neighbors[i].remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
|
||||
neighbors.remove_if([&](const BMVert *vert) { return !BM_vert_is_boundary(vert); });
|
||||
}
|
||||
|
||||
if (filter_boundary_face_sets) {
|
||||
neighbors[i].remove_if([&](const BMVert *vert) {
|
||||
neighbors.remove_if([&](const BMVert *vert) {
|
||||
return face_set::vert_has_unique_face_set(face_set_offset, *vert);
|
||||
});
|
||||
}
|
||||
|
||||
if (neighbors[i].is_empty()) {
|
||||
if (neighbors.is_empty()) {
|
||||
translations[i] = float3(0);
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
const float3 smoothed_position = average_positions(neighbors[i]);
|
||||
const float3 smoothed_position = average_positions(neighbors);
|
||||
|
||||
/* Normal Calculation */
|
||||
float3 normal;
|
||||
if (is_boundary && neighbors[i].size() == 2) {
|
||||
normal = calc_boundary_normal_corner(positions[i], neighbors[i]);
|
||||
if (is_boundary && neighbors.size() == 2) {
|
||||
normal = calc_boundary_normal_corner(positions[i], neighbors);
|
||||
if (math::is_zero(normal)) {
|
||||
translations[i] = float3(0);
|
||||
i++;
|
||||
@@ -677,7 +670,8 @@ void blur_geometry_data_array(const Object &object,
|
||||
{
|
||||
struct LocalData {
|
||||
Vector<int> vert_indices;
|
||||
Vector<Vector<int>> vert_neighbors;
|
||||
Vector<int> neighbor_offsets;
|
||||
Vector<int> neighbor_data;
|
||||
Vector<float> new_factors;
|
||||
};
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
@@ -704,9 +698,13 @@ void blur_geometry_data_array(const Object &object,
|
||||
LocalData &tls = all_tls.local();
|
||||
const Span<int> verts = hide::node_visible_verts(nodes[i], hide_vert, tls.vert_indices);
|
||||
|
||||
tls.vert_neighbors.resize(verts.size());
|
||||
const MutableSpan<Vector<int>> neighbors = tls.vert_neighbors;
|
||||
calc_vert_neighbors(faces, corner_verts, vert_to_face_map, hide_poly, verts, neighbors);
|
||||
const GroupedSpan<int> neighbors = calc_vert_neighbors(faces,
|
||||
corner_verts,
|
||||
vert_to_face_map,
|
||||
hide_poly,
|
||||
verts,
|
||||
tls.neighbor_offsets,
|
||||
tls.neighbor_data);
|
||||
|
||||
tls.new_factors.resize(verts.size());
|
||||
const MutableSpan<float> new_factors = tls.new_factors;
|
||||
|
||||
@@ -36,7 +36,7 @@ void neighbor_color_average(OffsetIndices<int> faces,
|
||||
GroupedSpan<int> vert_to_face_map,
|
||||
GSpan color_attribute,
|
||||
bke::AttrDomain color_domain,
|
||||
Span<Vector<int>> vert_neighbors,
|
||||
GroupedSpan<int> vert_neighbors,
|
||||
MutableSpan<float4> smooth_colors);
|
||||
|
||||
void neighbor_position_average_interior_grids(OffsetIndices<int> faces,
|
||||
@@ -52,11 +52,12 @@ void neighbor_position_average_interior_bmesh(const Set<BMVert *, 0> &verts,
|
||||
MutableSpan<float3> new_positions);
|
||||
|
||||
template<typename T>
|
||||
void neighbor_data_average_mesh(Span<T> src, Span<Vector<int>> vert_neighbors, MutableSpan<T> dst);
|
||||
void neighbor_data_average_mesh(Span<T> src, GroupedSpan<int> vert_neighbors, MutableSpan<T> dst);
|
||||
|
||||
template<typename T>
|
||||
void neighbor_data_average_mesh_check_loose(Span<T> src,
|
||||
Span<int> verts,
|
||||
Span<Vector<int>> vert_neighbors,
|
||||
GroupedSpan<int> vert_neighbors,
|
||||
MutableSpan<T> dst);
|
||||
|
||||
template<typename T>
|
||||
@@ -95,7 +96,6 @@ void calc_relaxed_translations_faces(Span<float3> vert_positions,
|
||||
bool filter_boundary_face_sets,
|
||||
Span<int> verts,
|
||||
Span<float> factors,
|
||||
Vector<Vector<int>> &neighbors,
|
||||
MutableSpan<float3> translations);
|
||||
void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
|
||||
OffsetIndices<int> faces,
|
||||
@@ -106,14 +106,12 @@ void calc_relaxed_translations_grids(const SubdivCCG &subdiv_ccg,
|
||||
Span<int> grids,
|
||||
bool filter_boundary_face_sets,
|
||||
Span<float> factors,
|
||||
Vector<Vector<SubdivCCGCoord>> &neighbors,
|
||||
MutableSpan<float3> translations);
|
||||
void calc_relaxed_translations_bmesh(const Set<BMVert *, 0> &verts,
|
||||
Span<float3> positions,
|
||||
const int face_set_offset,
|
||||
bool filter_boundary_face_sets,
|
||||
Span<float> factors,
|
||||
Vector<Vector<BMVert *>> &neighbors,
|
||||
MutableSpan<float3> translations);
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::smooth
|
||||
|
||||
Reference in New Issue
Block a user