Sculpt: Store faces instead of triangles in BVH
Currently each sculpt BVH node stores the indices of its triangles. It also stores triangles of vertex indices local to the node, and also potentially the indices of the face corners in the node. The problem with this is that the leaf nodes store plenty of redundant information. The triangles in each face aren't split up between multiple nodes, so storing triangle instead of face indices is unnecesssary. For the local vertex triangles, there is also duplicate information-- twice the number of indices as necessary for quad meshes. We also often need a node's faces, which is currently done with a triangle to face map using 4 bytes per triangle. This "double storage" results in extra processing too. For example, during BVH builds we need to combine twice the number of "Bounds" objects for a quad mesh. And we have to recalculate a node's face indices every time we want them. This commit replaces the PBVH triangle indices with face indices, and replaces the local vertex triangles array by using a `VectorSet` to store each node's vertex indices. This results in significant performance and memory usage improvements. | | Before | After | Improvement | | ----------------- | -------- | -------- | ----------- | | BVH build time | 1.29 s | 0.552 s | 2.3x | | Brush stroke time | 3.57 s | 2.52 s | 1.4x | | Memory usage | 4.14 GiB | 3.66 GiB | 1.3x | All testing is done with a 16 million vertex grid and a Ryzen 7950x. My guess is that the brush stroke time is improved by the added sorting of node vertex indices, and by the overall increase in memory bandwidth availability for mesh data. Personally I'm pleasantly surprised by the whole improvement, since I usually try to avoid hash table data structures for this sort of use case. But a lookup into this set ends up just being a boolean and with an array lookup, so it's quite cheap. Pull Request: https://projects.blender.org/blender/blender/pulls/127162
This commit is contained in:
@@ -96,10 +96,27 @@ class Node {
|
||||
};
|
||||
|
||||
struct MeshNode : public Node {
|
||||
/** Indices into the #Mesh::corner_tris() array. Refers to a subset of Tree::prim_indices_. */
|
||||
Span<int> prim_indices_;
|
||||
/**
|
||||
* Use a 16 bit integer for the slot index type because there will always be less than
|
||||
* #leaf_limit vertices in a node.
|
||||
*/
|
||||
using LocalVertMapIndexT = int16_t;
|
||||
/**
|
||||
* Global vertices are mapped to local indices with a vector set, with a specialized type in
|
||||
* order to use 32 bit integers for slot values. .
|
||||
*/
|
||||
using LocalVertMap = VectorSet<int,
|
||||
DefaultProbingStrategy,
|
||||
DefaultHash<int>,
|
||||
DefaultEquality<int>,
|
||||
SimpleVectorSetSlot<int, LocalVertMapIndexT>,
|
||||
GuardedAllocator>;
|
||||
|
||||
/* Array of indices into the mesh's vertex array. Contains the
|
||||
/** Indices into the #Mesh::faces() array. Refers to a subset of Tree::prim_indices_. */
|
||||
Span<int> face_indices_;
|
||||
|
||||
/**
|
||||
* Array of indices into the mesh's vertex array. Contains the
|
||||
* indices of all vertices used by faces that are within this
|
||||
* node's bounding box.
|
||||
*
|
||||
@@ -117,23 +134,12 @@ struct MeshNode : public Node {
|
||||
* be above that node's 'uniq_verts' value.
|
||||
*
|
||||
* Used for leaf nodes.
|
||||
*
|
||||
* \todo Find a way to disable the #VectorSet inline buffer.
|
||||
*/
|
||||
Array<int, 0> vert_indices_;
|
||||
LocalVertMap vert_indices_;
|
||||
/** The number of vertices in #vert_indices not shared with (owned by) another node. */
|
||||
int unique_verts_num_ = 0;
|
||||
|
||||
/** Array of indices into the Mesh's corner array. */
|
||||
Array<int, 0> corner_indices_;
|
||||
|
||||
/* An array mapping face corners into the vert_indices
|
||||
* array. The array is sized to match 'totprim', and each of
|
||||
* the face's corners gets an index into the vert_indices
|
||||
* array, in the same order as the corners in the original
|
||||
* triangle.
|
||||
*
|
||||
* Used for leaf nodes.
|
||||
*/
|
||||
Array<int3, 0> face_vert_indices_;
|
||||
};
|
||||
|
||||
struct GridsNode : public Node {
|
||||
@@ -248,9 +254,9 @@ bool raycast_node(Tree &pbvh,
|
||||
Span<float3> node_positions,
|
||||
bool use_origco,
|
||||
Span<float3> vert_positions,
|
||||
OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
Span<int3> corner_tris,
|
||||
Span<int> corner_tri_faces,
|
||||
Span<bool> hide_poly,
|
||||
const SubdivCCG *subdiv_ccg,
|
||||
const float3 &ray_start,
|
||||
@@ -291,9 +297,9 @@ bool find_nearest_to_ray_node(Tree &pbvh,
|
||||
Span<float3> node_positions,
|
||||
bool use_origco,
|
||||
Span<float3> vert_positions,
|
||||
const OffsetIndices<int> faces,
|
||||
Span<int> corner_verts,
|
||||
Span<int3> corner_tris,
|
||||
Span<int> corner_tri_faces,
|
||||
Span<bool> hide_poly,
|
||||
const SubdivCCG *subdiv_ccg,
|
||||
const float ray_start[3],
|
||||
@@ -380,18 +386,9 @@ void remove_node_draw_tags(bke::pbvh::Tree &pbvh, const IndexMask &node_mask);
|
||||
|
||||
Span<int> node_grid_indices(const GridsNode &node);
|
||||
|
||||
Span<int> node_tri_indices(const MeshNode &node);
|
||||
Span<int> node_faces(const MeshNode &node);
|
||||
Span<int> node_verts(const MeshNode &node);
|
||||
Span<int> node_unique_verts(const MeshNode &node);
|
||||
Span<int> node_corners(const MeshNode &node);
|
||||
|
||||
/**
|
||||
* Gather the indices of all faces (not triangles) used by the node.
|
||||
* For convenience, pass a reference to the data in the result.
|
||||
*/
|
||||
Span<int> node_face_indices_calc_mesh(Span<int> corner_tri_faces,
|
||||
const MeshNode &node,
|
||||
Vector<int> &faces);
|
||||
|
||||
/**
|
||||
* Gather the indices of all base mesh faces in the node.
|
||||
@@ -510,8 +507,6 @@ Span<float3> face_normals_eval_from_eval(const Object &object_eval);
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
void BKE_pbvh_ensure_node_face_corners(blender::bke::pbvh::Tree &pbvh,
|
||||
blender::Span<blender::int3> corner_tris);
|
||||
int BKE_pbvh_debug_draw_gen_get(blender::bke::pbvh::Node &node);
|
||||
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
@@ -51,7 +51,10 @@
|
||||
namespace blender::bke::pbvh {
|
||||
|
||||
// #define DEBUG_BUILD_TIME
|
||||
#define LEAF_LIMIT 10000
|
||||
|
||||
constexpr int LEAF_LIMIT = 10000;
|
||||
static_assert(LEAF_LIMIT < std::numeric_limits<MeshNode::LocalVertMapIndexT>::max());
|
||||
|
||||
#define STACK_FIXED_DEPTH 100
|
||||
|
||||
/** Create invalid bounds for use with #math::min_max. */
|
||||
@@ -108,6 +111,58 @@ static int partition_prim_indices(MutableSpan<int> prim_indices,
|
||||
return lo2;
|
||||
}
|
||||
|
||||
static int partition_prim_indices(MutableSpan<int> face_indices,
|
||||
MutableSpan<int> prim_scratch,
|
||||
int lo,
|
||||
int hi,
|
||||
int axis,
|
||||
float mid,
|
||||
const Span<Bounds<float3>> face_bounds)
|
||||
{
|
||||
for (int i = lo; i < hi; i++) {
|
||||
prim_scratch[i - lo] = face_indices[i];
|
||||
}
|
||||
|
||||
int lo2 = lo, hi2 = hi - 1;
|
||||
int i1 = lo, i2 = 0;
|
||||
|
||||
while (i1 < hi) {
|
||||
const int face_i = prim_scratch[i2];
|
||||
const Bounds<float3> &bounds = face_bounds[prim_scratch[i2]];
|
||||
const bool side = math::midpoint(bounds.min[axis], bounds.max[axis]) >= mid;
|
||||
|
||||
while (i1 < hi && prim_scratch[i2] == face_i) {
|
||||
face_indices[side ? hi2-- : lo2++] = prim_scratch[i2];
|
||||
i1++;
|
||||
i2++;
|
||||
}
|
||||
}
|
||||
|
||||
return lo2;
|
||||
}
|
||||
|
||||
static int partition_indices_material_faces(MutableSpan<int> face_indices,
|
||||
const Span<int> material_indices,
|
||||
const int lo,
|
||||
const int hi)
|
||||
{
|
||||
int i = lo, j = hi;
|
||||
for (;;) {
|
||||
const int first = face_indices[lo];
|
||||
for (; face_materials_match(material_indices, first, face_indices[i]); i++) {
|
||||
/* pass */
|
||||
}
|
||||
for (; !face_materials_match(material_indices, first, face_indices[j]); j--) {
|
||||
/* pass */
|
||||
}
|
||||
if (!(i < j)) {
|
||||
return i;
|
||||
}
|
||||
std::swap(face_indices[i], face_indices[j]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the index of the first element on the right of the partition */
|
||||
static int partition_indices_material_faces(MutableSpan<int> indices,
|
||||
const Span<int> prim_to_face_map,
|
||||
@@ -132,89 +187,52 @@ static int partition_indices_material_faces(MutableSpan<int> indices,
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a vertex to the map, with a positive value for unique vertices and
|
||||
* a negative value for additional vertices */
|
||||
static int map_insert_vert(Map<int, int> &map,
|
||||
MutableSpan<bool> vert_bitmap,
|
||||
int *face_verts,
|
||||
int *uniq_verts,
|
||||
int vertex)
|
||||
{
|
||||
return map.lookup_or_add_cb(vertex, [&]() {
|
||||
int value;
|
||||
if (!vert_bitmap[vertex]) {
|
||||
vert_bitmap[vertex] = true;
|
||||
value = *uniq_verts;
|
||||
(*uniq_verts)++;
|
||||
}
|
||||
else {
|
||||
value = ~(*face_verts);
|
||||
(*face_verts)++;
|
||||
}
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
/** Find vertices used by the faces in this node. */
|
||||
static void build_mesh_leaf_node(const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
MutableSpan<bool> vert_bitmap,
|
||||
MeshNode &node)
|
||||
{
|
||||
node.unique_verts_num_ = 0;
|
||||
int shared_verts = 0;
|
||||
const Span<int> prim_indices = node.prim_indices_;
|
||||
|
||||
/* reserve size is rough guess */
|
||||
Map<int, int> map;
|
||||
map.reserve(prim_indices.size());
|
||||
|
||||
node.face_vert_indices_.reinitialize(prim_indices.size());
|
||||
|
||||
for (const int i : prim_indices.index_range()) {
|
||||
const int3 &tri = corner_tris[prim_indices[i]];
|
||||
for (int j = 0; j < 3; j++) {
|
||||
node.face_vert_indices_[i][j] = map_insert_vert(
|
||||
map, vert_bitmap, &shared_verts, &node.unique_verts_num_, corner_verts[tri[j]]);
|
||||
}
|
||||
}
|
||||
|
||||
node.vert_indices_.reinitialize(node.unique_verts_num_ + shared_verts);
|
||||
|
||||
/* Build the vertex list, unique verts first */
|
||||
for (const MapItem<int, int> item : map.items()) {
|
||||
int value = item.value;
|
||||
if (value < 0) {
|
||||
value = -value + node.unique_verts_num_ - 1;
|
||||
}
|
||||
|
||||
node.vert_indices_[value] = item.key;
|
||||
}
|
||||
|
||||
for (const int i : prim_indices.index_range()) {
|
||||
for (int j = 0; j < 3; j++) {
|
||||
if (node.face_vert_indices_[i][j] < 0) {
|
||||
node.face_vert_indices_[i][j] = -node.face_vert_indices_[i][j] + node.unique_verts_num_ -
|
||||
1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_NOINLINE static void build_mesh_leaf_nodes(const int verts_num,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
MutableSpan<MeshNode> nodes)
|
||||
{
|
||||
#ifdef DEBUG_BUILD_TIME
|
||||
SCOPED_TIMER_AVERAGED(__func__);
|
||||
#endif
|
||||
Array<bool> vert_bitmap(verts_num, false);
|
||||
for (const int i : nodes.index_range()) {
|
||||
if ((nodes[i].flag_ & PBVH_Leaf) == 0) {
|
||||
continue;
|
||||
Array<Array<int>> verts_per_node(nodes.size(), NoInitialization());
|
||||
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
|
||||
Set<int> verts;
|
||||
for (const int i : range) {
|
||||
MeshNode &node = nodes[i];
|
||||
|
||||
verts.clear();
|
||||
for (const int face : node.face_indices_) {
|
||||
verts.add_multiple(corner_verts.slice(faces[face]));
|
||||
}
|
||||
|
||||
new (&verts_per_node[i]) Array<int>(verts.size());
|
||||
std::copy(verts.begin(), verts.end(), verts_per_node[i].begin());
|
||||
std::sort(verts_per_node[i].begin(), verts_per_node[i].end());
|
||||
}
|
||||
build_mesh_leaf_node(corner_verts, corner_tris, vert_bitmap, nodes[i]);
|
||||
});
|
||||
|
||||
Vector<int> owned_verts;
|
||||
Vector<int> shared_verts;
|
||||
BitVector<> vert_used(verts_num);
|
||||
for (const int i : nodes.index_range()) {
|
||||
MeshNode &node = nodes[i];
|
||||
|
||||
owned_verts.clear();
|
||||
shared_verts.clear();
|
||||
for (const int vert : verts_per_node[i]) {
|
||||
if (vert_used[vert]) {
|
||||
shared_verts.append(vert);
|
||||
}
|
||||
else {
|
||||
vert_used[vert].set();
|
||||
owned_verts.append(vert);
|
||||
}
|
||||
}
|
||||
node.unique_verts_num_ = owned_verts.size();
|
||||
node.vert_indices_.reserve(owned_verts.size() + shared_verts.size());
|
||||
node.vert_indices_.add_multiple(owned_verts);
|
||||
node.vert_indices_.add_multiple(shared_verts);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -235,8 +253,21 @@ static bool leaf_needs_material_split(const Span<int> prim_indices,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void build_nodes_recursive_mesh(const Span<int> tri_faces,
|
||||
const Span<int> material_indices,
|
||||
static bool leaf_needs_material_split(const Span<int> face_indices,
|
||||
const Span<int> material_indices,
|
||||
const IndexRange prim_range)
|
||||
{
|
||||
if (material_indices.is_empty()) {
|
||||
return false;
|
||||
}
|
||||
const int first = material_indices[face_indices[prim_range.first()]];
|
||||
return std::any_of(prim_range.begin(), prim_range.end(), [&](const int i) {
|
||||
return material_indices[face_indices[i]] != first;
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
static void build_nodes_recursive_mesh(const Span<int> material_indices,
|
||||
const int leaf_limit,
|
||||
const int node_index,
|
||||
const std::optional<Bounds<float3>> &bounds_precalc,
|
||||
@@ -254,11 +285,11 @@ static void build_nodes_recursive_mesh(const Span<int> tri_faces,
|
||||
const bool below_leaf_limit = prims_num <= leaf_limit || depth >= STACK_FIXED_DEPTH - 1;
|
||||
if (below_leaf_limit) {
|
||||
if (!leaf_needs_material_split(
|
||||
prim_indices, tri_faces, material_indices, IndexRange(prim_offset, prims_num)))
|
||||
prim_indices, material_indices, IndexRange(prim_offset, prims_num)))
|
||||
{
|
||||
MeshNode &node = nodes[node_index];
|
||||
node.flag_ |= PBVH_Leaf;
|
||||
node.prim_indices_ = prim_indices.as_span().slice(prim_offset, prims_num);
|
||||
node.face_indices_ = prim_indices.as_span().slice(prim_offset, prims_num);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -297,18 +328,16 @@ static void build_nodes_recursive_mesh(const Span<int> tri_faces,
|
||||
prim_offset + prims_num,
|
||||
axis,
|
||||
math::midpoint(bounds.min[axis], bounds.max[axis]),
|
||||
prim_bounds,
|
||||
tri_faces);
|
||||
prim_bounds);
|
||||
}
|
||||
else {
|
||||
/* Partition primitives by material */
|
||||
end = partition_indices_material_faces(
|
||||
prim_indices, tri_faces, material_indices, prim_offset, prim_offset + prims_num - 1);
|
||||
prim_indices, material_indices, prim_offset, prim_offset + prims_num - 1);
|
||||
}
|
||||
|
||||
/* Build children */
|
||||
build_nodes_recursive_mesh(tri_faces,
|
||||
material_indices,
|
||||
build_nodes_recursive_mesh(material_indices,
|
||||
leaf_limit,
|
||||
nodes[node_index].children_offset_,
|
||||
std::nullopt,
|
||||
@@ -319,8 +348,7 @@ static void build_nodes_recursive_mesh(const Span<int> tri_faces,
|
||||
depth + 1,
|
||||
prim_indices,
|
||||
nodes);
|
||||
build_nodes_recursive_mesh(tri_faces,
|
||||
material_indices,
|
||||
build_nodes_recursive_mesh(material_indices,
|
||||
leaf_limit,
|
||||
nodes[node_index].children_offset_ + 1,
|
||||
std::nullopt,
|
||||
@@ -333,6 +361,16 @@ static void build_nodes_recursive_mesh(const Span<int> tri_faces,
|
||||
nodes);
|
||||
}
|
||||
|
||||
inline Bounds<float3> calc_face_bounds(const Span<float3> vert_positions,
|
||||
const Span<int> face_verts)
|
||||
{
|
||||
Bounds<float3> bounds{vert_positions[face_verts.first()]};
|
||||
for (const int vert : face_verts.slice(1, face_verts.size() - 1)) {
|
||||
math::min_max(vert_positions[vert], bounds.min, bounds.max);
|
||||
}
|
||||
return bounds;
|
||||
}
|
||||
|
||||
std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
|
||||
{
|
||||
#ifdef DEBUG_BUILD_TIME
|
||||
@@ -340,32 +378,25 @@ std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
|
||||
#endif
|
||||
std::unique_ptr<Tree> pbvh = std::make_unique<Tree>(Type::Mesh);
|
||||
const Span<float3> vert_positions = mesh.vert_positions();
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int3> corner_tris = mesh.corner_tris();
|
||||
if (corner_tris.is_empty()) {
|
||||
if (faces.is_empty()) {
|
||||
return pbvh;
|
||||
}
|
||||
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
|
||||
const int leaf_limit = LEAF_LIMIT;
|
||||
|
||||
/* For each face, store the AABB and the AABB centroid */
|
||||
Array<Bounds<float3>> prim_bounds(corner_tris.size());
|
||||
Array<Bounds<float3>> prim_bounds(faces.size());
|
||||
const Bounds<float3> bounds = threading::parallel_reduce(
|
||||
corner_tris.index_range(),
|
||||
faces.index_range(),
|
||||
1024,
|
||||
negative_bounds(),
|
||||
[&](const IndexRange range, const Bounds<float3> &init) {
|
||||
Bounds<float3> current = init;
|
||||
for (const int i : range) {
|
||||
const int3 &tri = corner_tris[i];
|
||||
Bounds<float3> &bounds = prim_bounds[i];
|
||||
bounds = {vert_positions[corner_verts[tri[0]]]};
|
||||
math::min_max(vert_positions[corner_verts[tri[1]]], bounds.min, bounds.max);
|
||||
math::min_max(vert_positions[corner_verts[tri[2]]], bounds.min, bounds.max);
|
||||
const float3 center = math::midpoint(prim_bounds[i].min, prim_bounds[i].max);
|
||||
math::min_max(center, current.min, current.max);
|
||||
prim_bounds[i] = calc_face_bounds(vert_positions, corner_verts.slice(faces[i]));
|
||||
current = bounds::merge(current, prim_bounds[i]);
|
||||
}
|
||||
return current;
|
||||
},
|
||||
@@ -375,7 +406,7 @@ std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
|
||||
const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
|
||||
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
|
||||
|
||||
pbvh->prim_indices_.reinitialize(corner_tris.size());
|
||||
pbvh->prim_indices_.reinitialize(faces.size());
|
||||
array_utils::fill_index_range<int>(pbvh->prim_indices_);
|
||||
|
||||
Vector<MeshNode> &nodes = std::get<Vector<MeshNode>>(pbvh->nodes_);
|
||||
@@ -384,21 +415,20 @@ std::unique_ptr<Tree> build_mesh(const Mesh &mesh)
|
||||
#ifdef DEBUG_BUILD_TIME
|
||||
SCOPED_TIMER_AVERAGED("build_nodes_recursive_mesh");
|
||||
#endif
|
||||
build_nodes_recursive_mesh(tri_faces,
|
||||
material_index,
|
||||
build_nodes_recursive_mesh(material_index,
|
||||
leaf_limit,
|
||||
0,
|
||||
bounds,
|
||||
prim_bounds,
|
||||
0,
|
||||
corner_tris.size(),
|
||||
faces.size(),
|
||||
Array<int>(pbvh->prim_indices_.size()),
|
||||
0,
|
||||
pbvh->prim_indices_,
|
||||
nodes);
|
||||
}
|
||||
|
||||
build_mesh_leaf_nodes(mesh.verts_num, corner_verts, corner_tris, nodes);
|
||||
build_mesh_leaf_nodes(mesh.verts_num, faces, corner_verts, nodes);
|
||||
|
||||
update_bounds_mesh(vert_positions, *pbvh);
|
||||
store_bounds_orig(*pbvh);
|
||||
@@ -987,21 +1017,12 @@ static void calc_boundary_face_normals(const Span<float3> positions,
|
||||
static void calc_node_face_normals(const Span<float3> positions,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int> corner_tri_faces,
|
||||
const Span<MeshNode> nodes,
|
||||
const IndexMask &nodes_to_update,
|
||||
MutableSpan<float3> face_normals)
|
||||
{
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_index_data;
|
||||
threading::parallel_for(nodes_to_update.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &node_faces = all_index_data.local();
|
||||
nodes_to_update.slice(range).foreach_index([&](const int i) {
|
||||
normals_calc_faces(positions,
|
||||
faces,
|
||||
corner_verts,
|
||||
node_face_indices_calc_mesh(corner_tri_faces, nodes[i], node_faces),
|
||||
face_normals);
|
||||
});
|
||||
nodes_to_update.foreach_index(GrainSize(1), [&](const int i) {
|
||||
normals_calc_faces(positions, faces, corner_verts, node_faces(nodes[i]), face_normals);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1062,7 +1083,6 @@ static void update_normals_mesh(Object &object_orig,
|
||||
const Span<float3> positions = bke::pbvh::vert_positions_eval_from_eval(object_eval);
|
||||
const OffsetIndices faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
|
||||
|
||||
SharedCache<Vector<float3>> &vert_normals_cache = vert_normals_cache_eval_for_write(object_orig,
|
||||
@@ -1090,8 +1110,7 @@ static void update_normals_mesh(Object &object_orig,
|
||||
}
|
||||
else {
|
||||
face_normals_cache.update([&](Vector<float3> &r_data) {
|
||||
calc_node_face_normals(
|
||||
positions, faces, corner_verts, tri_faces, nodes, nodes_to_update, r_data);
|
||||
calc_node_face_normals(positions, faces, corner_verts, nodes, nodes_to_update, r_data);
|
||||
calc_boundary_face_normals(positions, faces, corner_verts, boundary_faces, r_data);
|
||||
});
|
||||
}
|
||||
@@ -1788,11 +1807,6 @@ void remove_node_draw_tags(bke::pbvh::Tree &pbvh, const IndexMask &node_mask)
|
||||
}
|
||||
}
|
||||
|
||||
Span<int> node_corners(const MeshNode &node)
|
||||
{
|
||||
return node.corner_indices_;
|
||||
}
|
||||
|
||||
Span<int> node_verts(const MeshNode &node)
|
||||
{
|
||||
return node.vert_indices_;
|
||||
@@ -1803,22 +1817,6 @@ Span<int> node_unique_verts(const MeshNode &node)
|
||||
return node.vert_indices_.as_span().take_front(node.unique_verts_num_);
|
||||
}
|
||||
|
||||
Span<int> node_face_indices_calc_mesh(const Span<int> corner_tri_faces,
|
||||
const MeshNode &node,
|
||||
Vector<int> &faces)
|
||||
{
|
||||
faces.clear();
|
||||
int prev_face = -1;
|
||||
for (const int tri : node_tri_indices(node)) {
|
||||
const int face = corner_tri_faces[tri];
|
||||
if (face != prev_face) {
|
||||
faces.append(face);
|
||||
prev_face = face;
|
||||
}
|
||||
}
|
||||
return faces.as_span();
|
||||
}
|
||||
|
||||
Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
|
||||
const GridsNode &node,
|
||||
Vector<int> &faces)
|
||||
@@ -1836,9 +1834,9 @@ Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
|
||||
return faces.as_span();
|
||||
}
|
||||
|
||||
Span<int> node_tri_indices(const MeshNode &node)
|
||||
Span<int> node_faces(const MeshNode &node)
|
||||
{
|
||||
return node.prim_indices_;
|
||||
return node.face_indices_;
|
||||
}
|
||||
|
||||
Span<int> node_grid_indices(const GridsNode &node)
|
||||
@@ -2024,9 +2022,9 @@ bool ray_face_nearest_tri(const float3 &ray_start,
|
||||
|
||||
static void calc_mesh_intersect_data(const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_tri_faces,
|
||||
const float3 &ray_start,
|
||||
const float3 &ray_normal,
|
||||
const int face_index,
|
||||
const int tri_index,
|
||||
const std::array<const float *, 3> co,
|
||||
float *depth,
|
||||
@@ -2052,7 +2050,7 @@ static void calc_mesh_intersect_data(const Span<int> corner_verts,
|
||||
{
|
||||
copy_v3_v3(nearest_vertex_co, co[j]);
|
||||
r_active_vertex->i = corner_verts[corner_tris[tri_index][j]];
|
||||
*r_active_face_index = corner_tri_faces[tri_index];
|
||||
*r_active_face_index = face_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2061,9 +2059,9 @@ static void calc_mesh_intersect_data(const Span<int> corner_verts,
|
||||
static bool pbvh_faces_node_raycast(const MeshNode &node,
|
||||
const Span<float3> node_positions,
|
||||
const Span<float3> vert_positions,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const float3 &ray_start,
|
||||
const float3 &ray_normal,
|
||||
@@ -2073,58 +2071,66 @@ static bool pbvh_faces_node_raycast(const MeshNode &node,
|
||||
int *r_active_face_index,
|
||||
float *r_face_normal)
|
||||
{
|
||||
const Span<int> tris = node_tri_indices(node);
|
||||
const Span<int> face_indices = node_faces(node);
|
||||
|
||||
bool hit = false;
|
||||
if (node_positions.is_empty()) {
|
||||
for (const int i : tris.index_range()) {
|
||||
const int tri_i = tris[i];
|
||||
const int3 &tri = corner_tris[tri_i];
|
||||
if (!hide_poly.is_empty() && hide_poly[corner_tri_faces[tri_i]]) {
|
||||
for (const int i : face_indices.index_range()) {
|
||||
const int face_i = face_indices[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
const std::array<const float *, 3> co{{vert_positions[corner_verts[tri[0]]],
|
||||
vert_positions[corner_verts[tri[1]]],
|
||||
vert_positions[corner_verts[tri[2]]]}};
|
||||
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
||||
hit = true;
|
||||
calc_mesh_intersect_data(corner_verts,
|
||||
corner_tris,
|
||||
corner_tri_faces,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
tri_i,
|
||||
co,
|
||||
depth,
|
||||
r_active_vertex,
|
||||
r_active_face_index,
|
||||
r_face_normal);
|
||||
|
||||
for (const int tri_i : bke::mesh::face_triangles_range(faces, face_i)) {
|
||||
const int3 &tri = corner_tris[tri_i];
|
||||
const std::array<const float *, 3> co{{vert_positions[corner_verts[tri[0]]],
|
||||
vert_positions[corner_verts[tri[1]]],
|
||||
vert_positions[corner_verts[tri[2]]]}};
|
||||
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
||||
hit = true;
|
||||
calc_mesh_intersect_data(corner_verts,
|
||||
corner_tris,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
face_i,
|
||||
tri_i,
|
||||
co,
|
||||
depth,
|
||||
r_active_vertex,
|
||||
r_active_face_index,
|
||||
r_face_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const int i : tris.index_range()) {
|
||||
const int tri_i = tris[i];
|
||||
const int3 face_verts = node.face_vert_indices_[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[corner_tri_faces[tri_i]]) {
|
||||
const MeshNode::LocalVertMap &vert_map = node.vert_indices_;
|
||||
for (const int i : face_indices.index_range()) {
|
||||
const int face_i = face_indices[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
const std::array<const float *, 3> co{{node_positions[face_verts[0]],
|
||||
node_positions[face_verts[1]],
|
||||
node_positions[face_verts[2]]}};
|
||||
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
||||
hit = true;
|
||||
calc_mesh_intersect_data(corner_verts,
|
||||
corner_tris,
|
||||
corner_tri_faces,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
tri_i,
|
||||
co,
|
||||
depth,
|
||||
r_active_vertex,
|
||||
r_active_face_index,
|
||||
r_face_normal);
|
||||
|
||||
for (const int tri_i : bke::mesh::face_triangles_range(faces, face_i)) {
|
||||
const int3 &tri = corner_tris[tri_i];
|
||||
const std::array<const float *, 3> co{
|
||||
{node_positions[vert_map.index_of(corner_verts[tri[0]])],
|
||||
node_positions[vert_map.index_of(corner_verts[tri[1]])],
|
||||
node_positions[vert_map.index_of(corner_verts[tri[2]])]}};
|
||||
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
||||
hit = true;
|
||||
calc_mesh_intersect_data(corner_verts,
|
||||
corner_tris,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
face_i,
|
||||
tri_i,
|
||||
co,
|
||||
depth,
|
||||
r_active_vertex,
|
||||
r_active_face_index,
|
||||
r_face_normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2271,9 +2277,9 @@ bool raycast_node(Tree &pbvh,
|
||||
const Span<float3> node_positions,
|
||||
bool use_origco,
|
||||
const Span<float3> vert_positions,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const SubdivCCG *subdiv_ccg,
|
||||
const float3 &ray_start,
|
||||
@@ -2292,9 +2298,9 @@ bool raycast_node(Tree &pbvh,
|
||||
return pbvh_faces_node_raycast(static_cast<MeshNode &>(node),
|
||||
node_positions,
|
||||
vert_positions,
|
||||
faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
corner_tri_faces,
|
||||
hide_poly,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
@@ -2458,48 +2464,55 @@ void find_nearest_to_ray(Tree &pbvh,
|
||||
static bool pbvh_faces_node_nearest_to_ray(const MeshNode &node,
|
||||
const Span<float3> node_positions,
|
||||
const Span<float3> vert_positions,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const float3 &ray_start,
|
||||
const float3 &ray_normal,
|
||||
float *depth,
|
||||
float *dist_sq)
|
||||
{
|
||||
const Span<int> tris = node_tri_indices(node);
|
||||
const Span<int> face_indices = node_faces(node);
|
||||
|
||||
bool hit = false;
|
||||
if (node_positions.is_empty()) {
|
||||
for (const int i : tris.index_range()) {
|
||||
const int tri_i = tris[i];
|
||||
const int3 &corner_tri = corner_tris[tri_i];
|
||||
if (!hide_poly.is_empty() && hide_poly[corner_tri_faces[tri_i]]) {
|
||||
for (const int i : face_indices.index_range()) {
|
||||
const int face_i = face_indices[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
hit |= ray_face_nearest_tri(ray_start,
|
||||
ray_normal,
|
||||
vert_positions[corner_verts[corner_tri[0]]],
|
||||
vert_positions[corner_verts[corner_tri[1]]],
|
||||
vert_positions[corner_verts[corner_tri[2]]],
|
||||
depth,
|
||||
dist_sq);
|
||||
|
||||
for (const int tri_i : bke::mesh::face_triangles_range(faces, face_i)) {
|
||||
const int3 &corner_tri = corner_tris[tri_i];
|
||||
hit |= ray_face_nearest_tri(ray_start,
|
||||
ray_normal,
|
||||
vert_positions[corner_verts[corner_tri[0]]],
|
||||
vert_positions[corner_verts[corner_tri[1]]],
|
||||
vert_positions[corner_verts[corner_tri[2]]],
|
||||
depth,
|
||||
dist_sq);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const int i : tris.index_range()) {
|
||||
const int tri_i = tris[i];
|
||||
const int3 face_verts = node.face_vert_indices_[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[corner_tri_faces[tri_i]]) {
|
||||
const MeshNode::LocalVertMap &vert_map = node.vert_indices_;
|
||||
for (const int i : face_indices.index_range()) {
|
||||
const int face_i = face_indices[i];
|
||||
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
||||
continue;
|
||||
}
|
||||
hit |= ray_face_nearest_tri(ray_start,
|
||||
ray_normal,
|
||||
node_positions[face_verts[0]],
|
||||
node_positions[face_verts[1]],
|
||||
node_positions[face_verts[2]],
|
||||
depth,
|
||||
dist_sq);
|
||||
|
||||
for (const int tri_i : bke::mesh::face_triangles_range(faces, face_i)) {
|
||||
const int3 &corner_tri = corner_tris[tri_i];
|
||||
hit |= ray_face_nearest_tri(ray_start,
|
||||
ray_normal,
|
||||
node_positions[vert_map.index_of(corner_verts[corner_tri[0]])],
|
||||
node_positions[vert_map.index_of(corner_verts[corner_tri[1]])],
|
||||
node_positions[vert_map.index_of(corner_verts[corner_tri[2]])],
|
||||
depth,
|
||||
dist_sq);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2575,9 +2588,9 @@ bool find_nearest_to_ray_node(Tree &pbvh,
|
||||
const Span<float3> node_positions,
|
||||
bool use_origco,
|
||||
const Span<float3> vert_positions,
|
||||
const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const SubdivCCG *subdiv_ccg,
|
||||
const float ray_start[3],
|
||||
@@ -2593,9 +2606,9 @@ bool find_nearest_to_ray_node(Tree &pbvh,
|
||||
return pbvh_faces_node_nearest_to_ray(static_cast<MeshNode &>(node),
|
||||
node_positions,
|
||||
vert_positions,
|
||||
faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
corner_tri_faces,
|
||||
hide_poly,
|
||||
ray_start,
|
||||
ray_normal,
|
||||
@@ -2826,55 +2839,6 @@ Span<float3> face_normals_eval_from_eval(const Object &object_eval)
|
||||
|
||||
} // namespace blender::bke::pbvh
|
||||
|
||||
void BKE_pbvh_ensure_node_face_corners(blender::bke::pbvh::Tree &pbvh,
|
||||
const blender::Span<blender::int3> corner_tris)
|
||||
{
|
||||
using namespace blender;
|
||||
BLI_assert(pbvh.type() == blender::bke::pbvh::Type::Mesh);
|
||||
|
||||
int totloop = 0;
|
||||
|
||||
/* Check if nodes already have loop indices. */
|
||||
for (blender::bke::pbvh::MeshNode &node : pbvh.nodes<blender::bke::pbvh::MeshNode>()) {
|
||||
if (!(node.flag_ & PBVH_Leaf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!node.corner_indices_.is_empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
totloop += node.prim_indices_.size() * 3;
|
||||
}
|
||||
|
||||
BLI_bitmap *visit = BLI_BITMAP_NEW(totloop, __func__);
|
||||
|
||||
/* Create loop indices from node loop triangles. */
|
||||
Vector<int> corner_indices;
|
||||
for (blender::bke::pbvh::MeshNode &node : pbvh.nodes<blender::bke::pbvh::MeshNode>()) {
|
||||
if (!(node.flag_ & PBVH_Leaf)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
corner_indices.clear();
|
||||
|
||||
for (const int i : node.prim_indices_) {
|
||||
const int3 &tri = corner_tris[i];
|
||||
|
||||
for (int k = 0; k < 3; k++) {
|
||||
if (!BLI_BITMAP_TEST(visit, tri[k])) {
|
||||
corner_indices.append(tri[k]);
|
||||
BLI_BITMAP_ENABLE(visit, tri[k]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node.corner_indices_ = corner_indices.as_span();
|
||||
}
|
||||
|
||||
MEM_SAFE_FREE(visit);
|
||||
}
|
||||
|
||||
int BKE_pbvh_debug_draw_gen_get(blender::bke::pbvh::Node &node)
|
||||
{
|
||||
return node.debug_draw_gen_;
|
||||
|
||||
@@ -163,44 +163,46 @@ static void do_encode_pixels(const uv_islands::MeshData &mesh_data,
|
||||
tile_data.tile_number = image_tile.get_tile_number();
|
||||
float2 tile_offset = float2(image_tile.get_tile_offset());
|
||||
|
||||
for (const int geom_prim_index : node.prim_indices_) {
|
||||
for (const UVPrimitiveLookup::Entry &entry : uv_prim_lookup.lookup[geom_prim_index]) {
|
||||
uv_islands::UVBorder uv_border = entry.uv_primitive->extract_border();
|
||||
float2 uvs[3] = {
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 0)->uv - tile_offset,
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 1)->uv - tile_offset,
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 2)->uv - tile_offset,
|
||||
};
|
||||
const float minv = clamp_f(min_fff(uvs[0].y, uvs[1].y, uvs[2].y), 0.0f, 1.0f);
|
||||
const int miny = floor(minv * image_buffer->y);
|
||||
const float maxv = clamp_f(max_fff(uvs[0].y, uvs[1].y, uvs[2].y), 0.0f, 1.0f);
|
||||
const int maxy = min_ii(ceil(maxv * image_buffer->y), image_buffer->y);
|
||||
const float minu = clamp_f(min_fff(uvs[0].x, uvs[1].x, uvs[2].x), 0.0f, 1.0f);
|
||||
const int minx = floor(minu * image_buffer->x);
|
||||
const float maxu = clamp_f(max_fff(uvs[0].x, uvs[1].x, uvs[2].x), 0.0f, 1.0f);
|
||||
const int maxx = min_ii(ceil(maxu * image_buffer->x), image_buffer->x);
|
||||
for (const int face : node_faces(node)) {
|
||||
for (const int tri : bke::mesh::face_triangles_range(mesh_data.faces, face)) {
|
||||
for (const UVPrimitiveLookup::Entry &entry : uv_prim_lookup.lookup[tri]) {
|
||||
uv_islands::UVBorder uv_border = entry.uv_primitive->extract_border();
|
||||
float2 uvs[3] = {
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 0)->uv - tile_offset,
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 1)->uv - tile_offset,
|
||||
entry.uv_primitive->get_uv_vertex(mesh_data, 2)->uv - tile_offset,
|
||||
};
|
||||
const float minv = clamp_f(min_fff(uvs[0].y, uvs[1].y, uvs[2].y), 0.0f, 1.0f);
|
||||
const int miny = floor(minv * image_buffer->y);
|
||||
const float maxv = clamp_f(max_fff(uvs[0].y, uvs[1].y, uvs[2].y), 0.0f, 1.0f);
|
||||
const int maxy = min_ii(ceil(maxv * image_buffer->y), image_buffer->y);
|
||||
const float minu = clamp_f(min_fff(uvs[0].x, uvs[1].x, uvs[2].x), 0.0f, 1.0f);
|
||||
const int minx = floor(minu * image_buffer->x);
|
||||
const float maxu = clamp_f(max_fff(uvs[0].x, uvs[1].x, uvs[2].x), 0.0f, 1.0f);
|
||||
const int maxx = min_ii(ceil(maxu * image_buffer->x), image_buffer->x);
|
||||
|
||||
/* TODO: Perform bounds check */
|
||||
int uv_prim_index = node_data->uv_primitives.size();
|
||||
node_data->uv_primitives.append(geom_prim_index);
|
||||
UVPrimitivePaintInput &paint_input = node_data->uv_primitives.last();
|
||||
/* TODO: Perform bounds check */
|
||||
int uv_prim_index = node_data->uv_primitives.size();
|
||||
node_data->uv_primitives.append(tri);
|
||||
UVPrimitivePaintInput &paint_input = node_data->uv_primitives.last();
|
||||
|
||||
/* Calculate barycentric delta */
|
||||
paint_input.delta_barycentric_coord_u = calc_barycentric_delta_x(
|
||||
image_buffer, uvs, minx, miny);
|
||||
/* Calculate barycentric delta */
|
||||
paint_input.delta_barycentric_coord_u = calc_barycentric_delta_x(
|
||||
image_buffer, uvs, minx, miny);
|
||||
|
||||
/* Extract the pixels. */
|
||||
extract_barycentric_pixels(tile_data,
|
||||
image_buffer,
|
||||
uv_masks,
|
||||
entry.uv_island_index,
|
||||
uv_prim_index,
|
||||
uvs,
|
||||
tile_offset,
|
||||
minx,
|
||||
miny,
|
||||
maxx,
|
||||
maxy);
|
||||
/* Extract the pixels. */
|
||||
extract_barycentric_pixels(tile_data,
|
||||
image_buffer,
|
||||
uv_masks,
|
||||
entry.uv_island_index,
|
||||
uv_prim_index,
|
||||
uvs,
|
||||
tile_offset,
|
||||
minx,
|
||||
miny,
|
||||
maxx,
|
||||
maxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
BKE_image_release_ibuf(&image, image_buffer, nullptr);
|
||||
@@ -351,7 +353,8 @@ static bool update_pixels(const Depsgraph &depsgraph,
|
||||
const AttributeAccessor attributes = mesh.attributes();
|
||||
const VArraySpan uv_map = *attributes.lookup<float2>(active_uv_name, AttrDomain::Corner);
|
||||
|
||||
uv_islands::MeshData mesh_data(mesh.corner_tris(),
|
||||
uv_islands::MeshData mesh_data(mesh.faces(),
|
||||
mesh.corner_tris(),
|
||||
mesh.corner_verts(),
|
||||
uv_map,
|
||||
bke::pbvh::vert_positions_eval(depsgraph, object));
|
||||
|
||||
@@ -198,11 +198,13 @@ static void mesh_data_init(MeshData &mesh_data)
|
||||
mesh_data.uv_island_len = mesh_data_init_primitive_uv_island_ids(mesh_data);
|
||||
}
|
||||
|
||||
MeshData::MeshData(const Span<int3> corner_tris,
|
||||
MeshData::MeshData(const OffsetIndices<int> faces,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> corner_verts,
|
||||
const Span<float2> uv_map,
|
||||
const Span<float3> vert_positions)
|
||||
: corner_tris(corner_tris),
|
||||
: faces(faces),
|
||||
corner_tris(corner_tris),
|
||||
corner_verts(corner_verts),
|
||||
uv_map(uv_map),
|
||||
vert_positions(vert_positions),
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_rect.h"
|
||||
#include "BLI_vector.hh"
|
||||
#include "BLI_vector_list.hh"
|
||||
@@ -110,6 +111,7 @@ class TriangleToEdgeMap {
|
||||
*/
|
||||
struct MeshData {
|
||||
public:
|
||||
OffsetIndices<int> faces;
|
||||
Span<int3> corner_tris;
|
||||
Span<int> corner_verts;
|
||||
Span<float2> uv_map;
|
||||
@@ -131,7 +133,8 @@ struct MeshData {
|
||||
int64_t uv_island_len;
|
||||
|
||||
public:
|
||||
explicit MeshData(Span<int3> corner_tris,
|
||||
explicit MeshData(OffsetIndices<int> faces,
|
||||
Span<int3> corner_tris,
|
||||
Span<int> corner_verts,
|
||||
Span<float2> uv_map,
|
||||
Span<float3> vert_positions);
|
||||
|
||||
@@ -337,70 +337,74 @@ inline short4 normal_float_to_short(const float3 &value)
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void extract_data_vert_mesh(const Span<int> corner_verts,
|
||||
void extract_data_vert_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<T> attribute,
|
||||
const Span<int> tris,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
VBOType *data = vbo.data<VBOType>().data();
|
||||
for (const int tri : tris) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri]]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri][i]];
|
||||
*data = Converter::convert(attribute[vert]);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void extract_data_face_mesh(const Span<int> tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<T> attribute,
|
||||
const Span<int> tris,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
|
||||
VBOType *data = vbo.data<VBOType>().data();
|
||||
for (const int tri : tris) {
|
||||
const int face = tri_faces[tri];
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
std::fill_n(data, 3, Converter::convert(attribute[face]));
|
||||
data += 3;
|
||||
for (const int tri : bke::mesh::face_triangles_range(faces, face)) {
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri][i]];
|
||||
*data = Converter::convert(attribute[vert]);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void extract_data_corner_mesh(const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
void extract_data_face_mesh(const OffsetIndices<int> faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<T> attribute,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
|
||||
VBOType *data = vbo.data<VBOType>().data();
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const int tris_num = bke::mesh::face_triangles_num(faces[face].size());
|
||||
std::fill_n(data, tris_num * 3, Converter::convert(attribute[face]));
|
||||
data += tris_num * 3;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void extract_data_corner_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<T> attribute,
|
||||
const Span<int> tris,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
using Converter = AttributeConverter<T>;
|
||||
using VBOType = typename Converter::VBOType;
|
||||
|
||||
VBOType *data = vbo.data<VBOType>().data();
|
||||
for (const int tri : tris) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri]]) {
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : IndexRange(3)) {
|
||||
const int corner = corner_tris[tri][i];
|
||||
*data = Converter::convert(attribute[corner]);
|
||||
data++;
|
||||
for (const int tri : bke::mesh::face_triangles_range(faces, face)) {
|
||||
for (int i : IndexRange(3)) {
|
||||
const int corner = corner_tris[tri][i];
|
||||
*data = Converter::convert(attribute[corner]);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -509,15 +513,18 @@ template<> ColorGeometry4b fallback_value_for_fill()
|
||||
return fallback_value_for_fill<ColorGeometry4f>().encode();
|
||||
}
|
||||
|
||||
static int count_visible_tris_mesh(const Span<int> tris,
|
||||
const Span<int> tri_faces,
|
||||
static int count_visible_tris_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> face_indices,
|
||||
const Span<bool> hide_poly)
|
||||
{
|
||||
if (hide_poly.is_empty()) {
|
||||
return tris.size();
|
||||
int tris_count = 0;
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
tris_count += bke::mesh::face_triangles_num(faces[face].size());
|
||||
}
|
||||
return std::count_if(
|
||||
tris.begin(), tris.end(), [&](const int tri) { return !hide_poly[tri_faces[tri]]; });
|
||||
return tris_count;
|
||||
}
|
||||
|
||||
static int count_visible_tris_bmesh(const Set<BMFace *, 0> &faces)
|
||||
@@ -608,105 +615,101 @@ void DrawCacheImpl::free_nodes_with_changed_topology(const Object &object,
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_normal_mesh(const Span<int> corner_verts,
|
||||
static void fill_vbo_normal_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> sharp_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<float3> vert_normals,
|
||||
const Span<float3> face_normals,
|
||||
const Span<int> tris,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vert_buf)
|
||||
{
|
||||
short4 *data = vert_buf.data<short4>().data();
|
||||
|
||||
short4 face_no;
|
||||
int last_face = -1;
|
||||
for (const int tri : tris) {
|
||||
const int face = tri_faces[tri];
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
if (!sharp_faces.is_empty() && sharp_faces[face]) {
|
||||
if (face != last_face) {
|
||||
face_no = normal_float_to_short(face_normals[face]);
|
||||
last_face = face;
|
||||
}
|
||||
std::fill_n(data, 3, face_no);
|
||||
data += 3;
|
||||
const int tris_num = bke::mesh::face_triangles_num(faces[face].size());
|
||||
const short4 face_no = normal_float_to_short(face_normals[face]);
|
||||
std::fill_n(data, tris_num * 3, face_no);
|
||||
data += tris_num * 3;
|
||||
}
|
||||
else {
|
||||
for (const int i : IndexRange(3)) {
|
||||
for (const int tri : bke::mesh::face_triangles_range(faces, face)) {
|
||||
for (const int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri][i]];
|
||||
*data = normal_float_to_short(vert_normals[vert]);
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_mask_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<float> mask,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
float *data = vbo.data<float>().data();
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
for (const int tri : bke::mesh::face_triangles_range(faces, face)) {
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri][i]];
|
||||
*data = normal_float_to_short(vert_normals[vert]);
|
||||
*data = mask[vert];
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_mask_mesh(const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<float> mask,
|
||||
const Span<int> tris,
|
||||
gpu::VertBuf &vbo)
|
||||
{
|
||||
float *data = vbo.data<float>().data();
|
||||
for (const int tri : tris) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri]]) {
|
||||
continue;
|
||||
}
|
||||
for (int i : IndexRange(3)) {
|
||||
const int vert = corner_verts[corner_tris[tri][i]];
|
||||
*data = mask[vert];
|
||||
data++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_face_set_mesh(const Span<int> tri_faces,
|
||||
static void fill_vbo_face_set_mesh(const OffsetIndices<int> faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> face_sets,
|
||||
const int color_default,
|
||||
const int color_seed,
|
||||
const Span<int> tris,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vert_buf)
|
||||
{
|
||||
uchar4 *data = vert_buf.data<uchar4>().data();
|
||||
int last_face = -1;
|
||||
uchar4 fset_color(UCHAR_MAX);
|
||||
for (const int tri : tris) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri]]) {
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const int face = tri_faces[tri];
|
||||
if (last_face != face) {
|
||||
last_face = face;
|
||||
|
||||
const int id = face_sets[face];
|
||||
const int id = face_sets[face];
|
||||
|
||||
if (id != color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(id, color_seed, fset_color);
|
||||
}
|
||||
else {
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
uchar4 fset_color(UCHAR_MAX);
|
||||
if (id != color_default) {
|
||||
BKE_paint_face_set_overlay_color_get(id, color_seed, fset_color);
|
||||
}
|
||||
std::fill_n(data, 3, fset_color);
|
||||
data += 3;
|
||||
else {
|
||||
/* Skip for the default color face set to render it white. */
|
||||
fset_color[0] = fset_color[1] = fset_color[2] = UCHAR_MAX;
|
||||
}
|
||||
|
||||
const int tris_num = bke::mesh::face_triangles_num(faces[face].size());
|
||||
std::fill_n(data, tris_num * 3, fset_color);
|
||||
data += tris_num * 3;
|
||||
}
|
||||
}
|
||||
|
||||
static void fill_vbo_attribute_mesh(const Span<int> corner_verts,
|
||||
static void fill_vbo_attribute_mesh(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const GSpan attribute,
|
||||
const bke::AttrDomain domain,
|
||||
const Span<int> tris,
|
||||
const Span<int> face_indices,
|
||||
gpu::VertBuf &vert_buf)
|
||||
{
|
||||
bke::attribute_math::convert_to_static_type(attribute.type(), [&](auto dummy) {
|
||||
@@ -714,20 +717,21 @@ static void fill_vbo_attribute_mesh(const Span<int> corner_verts,
|
||||
if constexpr (!std::is_void_v<typename AttributeConverter<T>::VBOType>) {
|
||||
switch (domain) {
|
||||
case bke::AttrDomain::Point:
|
||||
extract_data_vert_mesh<T>(corner_verts,
|
||||
extract_data_vert_mesh<T>(faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
hide_poly,
|
||||
attribute.typed<T>(),
|
||||
tris,
|
||||
face_indices,
|
||||
vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Face:
|
||||
extract_data_face_mesh<T>(tri_faces, hide_poly, attribute.typed<T>(), tris, vert_buf);
|
||||
extract_data_face_mesh<T>(
|
||||
faces, hide_poly, attribute.typed<T>(), face_indices, vert_buf);
|
||||
break;
|
||||
case bke::AttrDomain::Corner:
|
||||
extract_data_corner_mesh<T>(
|
||||
corner_tris, tri_faces, hide_poly, attribute.typed<T>(), tris, vert_buf);
|
||||
faces, corner_tris, hide_poly, attribute.typed<T>(), face_indices, vert_buf);
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
@@ -986,9 +990,9 @@ static void fill_vbos_mesh(const Object &object,
|
||||
SculptSession &ss = *object.sculpt;
|
||||
const Span<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int3> corner_tris = mesh.corner_tris();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
const VArraySpan hide_poly = *orig_mesh_data.attributes.lookup<bool>(".hide_poly",
|
||||
bke::AttrDomain::Face);
|
||||
@@ -998,12 +1002,12 @@ static void fill_vbos_mesh(const Object &object,
|
||||
case CustomRequest::Position: {
|
||||
const Span<float3> vert_positions = bke::pbvh::vert_positions_eval_from_eval(object);
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
extract_data_vert_mesh<float3>(corner_verts,
|
||||
extract_data_vert_mesh<float3>(faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
hide_poly,
|
||||
vert_positions,
|
||||
bke::pbvh::node_tri_indices(nodes[i]),
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
*vbos[i]);
|
||||
});
|
||||
break;
|
||||
@@ -1014,14 +1018,14 @@ static void fill_vbos_mesh(const Object &object,
|
||||
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face",
|
||||
bke::AttrDomain::Face);
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
fill_vbo_normal_mesh(corner_verts,
|
||||
fill_vbo_normal_mesh(faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
sharp_faces,
|
||||
hide_poly,
|
||||
vert_normals,
|
||||
face_normals,
|
||||
bke::pbvh::node_tri_indices(nodes[i]),
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
*vbos[i]);
|
||||
});
|
||||
break;
|
||||
@@ -1031,12 +1035,12 @@ static void fill_vbos_mesh(const Object &object,
|
||||
bke::AttrDomain::Point);
|
||||
if (!mask.is_empty()) {
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
fill_vbo_mask_mesh(corner_verts,
|
||||
fill_vbo_mask_mesh(faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
hide_poly,
|
||||
mask,
|
||||
bke::pbvh::node_tri_indices(nodes[i]),
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
*vbos[i]);
|
||||
});
|
||||
}
|
||||
@@ -1053,12 +1057,12 @@ static void fill_vbos_mesh(const Object &object,
|
||||
bke::AttrDomain::Face);
|
||||
if (!face_sets.is_empty()) {
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
fill_vbo_face_set_mesh(tri_faces,
|
||||
fill_vbo_face_set_mesh(faces,
|
||||
hide_poly,
|
||||
face_sets,
|
||||
face_set_default,
|
||||
face_set_seed,
|
||||
bke::pbvh::node_tri_indices(nodes[i]),
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
*vbos[i]);
|
||||
});
|
||||
}
|
||||
@@ -1077,13 +1081,13 @@ static void fill_vbos_mesh(const Object &object,
|
||||
const eCustomDataType data_type = attr.type;
|
||||
const GVArraySpan attribute = *attributes.lookup_or_default(name, domain, data_type);
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
fill_vbo_attribute_mesh(corner_verts,
|
||||
fill_vbo_attribute_mesh(faces,
|
||||
corner_verts,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
hide_poly,
|
||||
attribute,
|
||||
domain,
|
||||
bke::pbvh::node_tri_indices(nodes[i]),
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
*vbos[i]);
|
||||
});
|
||||
}
|
||||
@@ -1277,65 +1281,43 @@ static void fill_vbos_bmesh(const Object &object,
|
||||
}
|
||||
}
|
||||
|
||||
static gpu::IndexBuf *create_index_faces(const Span<int2> edges,
|
||||
static gpu::IndexBuf *create_index_faces(const OffsetIndices<int> faces,
|
||||
const Span<int> corner_verts,
|
||||
const Span<int> corner_edges,
|
||||
const Span<int3> corner_tris,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> hide_poly,
|
||||
const Span<int> tri_indices)
|
||||
const Span<int> face_indices,
|
||||
const bke::pbvh::MeshNode::LocalVertMap &vert_map)
|
||||
{
|
||||
/* Calculate number of edges. */
|
||||
int edge_count = 0;
|
||||
for (const int tri_i : tri_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
|
||||
int tris_count = 0;
|
||||
int corners_count = 0;
|
||||
for (const int face : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, corner_verts, corner_edges, corner_tris[tri_i]);
|
||||
if (real_edges[0] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
edge_count++;
|
||||
}
|
||||
|
||||
tris_count += bke::mesh::face_triangles_num(faces[face].size());
|
||||
corners_count += faces[face].size();
|
||||
}
|
||||
|
||||
GPUIndexBufBuilder builder;
|
||||
GPU_indexbuf_init(&builder, GPU_PRIM_LINES, edge_count, INT_MAX);
|
||||
GPU_indexbuf_init(&builder, GPU_PRIM_LINES, corners_count, INT_MAX);
|
||||
MutableSpan<uint2> data = GPU_indexbuf_get_data(&builder).cast<uint2>();
|
||||
|
||||
int edge_i = 0;
|
||||
int vert_i = 0;
|
||||
for (const int tri_i : tri_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[tri_faces[tri_i]]) {
|
||||
int edge_index = 0;
|
||||
for (const int face_index : face_indices) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face_index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int3 real_edges = bke::mesh::corner_tri_get_real_edges(
|
||||
edges, corner_verts, corner_edges, corner_tris[tri_i]);
|
||||
|
||||
if (real_edges[0] != -1) {
|
||||
data[edge_i] = uint2(vert_i, vert_i + 1);
|
||||
edge_i++;
|
||||
const IndexRange face = faces[face_index];
|
||||
for (const int corner : face) {
|
||||
data[edge_index] = uint2(
|
||||
vert_map.index_of(corner_verts[corner]),
|
||||
vert_map.index_of(corner_verts[bke::mesh::face_corner_next(face, corner)]));
|
||||
edge_index++;
|
||||
}
|
||||
if (real_edges[1] != -1) {
|
||||
data[edge_i] = uint2(vert_i + 1, vert_i + 2);
|
||||
edge_i++;
|
||||
}
|
||||
if (real_edges[2] != -1) {
|
||||
data[edge_i] = uint2(vert_i + 2, vert_i);
|
||||
edge_i++;
|
||||
}
|
||||
|
||||
vert_i += 3;
|
||||
}
|
||||
|
||||
gpu::IndexBuf *ibo = GPU_indexbuf_calloc();
|
||||
GPU_indexbuf_build_in_place_ex(&builder, 0, vert_i, false, ibo);
|
||||
GPU_indexbuf_build_in_place_ex(&builder, 0, tris_count * 3, false, ibo);
|
||||
return ibo;
|
||||
}
|
||||
|
||||
@@ -1558,7 +1540,6 @@ static Array<int> calc_material_indices(const Object &object)
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
const Span<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
const VArray material_indices = *attributes.lookup<int>("material_index",
|
||||
bke::AttrDomain::Face);
|
||||
@@ -1568,11 +1549,11 @@ static Array<int> calc_material_indices(const Object &object)
|
||||
Array<int> node_materials(nodes.size());
|
||||
threading::parallel_for(nodes.index_range(), 64, [&](const IndexRange range) {
|
||||
for (const int i : range) {
|
||||
const Span<int> tris = bke::pbvh::node_tri_indices(nodes[i]);
|
||||
if (tris.is_empty()) {
|
||||
const Span<int> face_indices = bke::pbvh::node_faces(nodes[i]);
|
||||
if (face_indices.is_empty()) {
|
||||
continue;
|
||||
}
|
||||
node_materials[i] = material_indices[tri_faces[tris.first()]];
|
||||
node_materials[i] = material_indices[face_indices.first()];
|
||||
}
|
||||
});
|
||||
return node_materials;
|
||||
@@ -1732,21 +1713,16 @@ Span<gpu::IndexBuf *> DrawCacheImpl::ensure_lines_indices(const Object &object,
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
const Span<bke::pbvh::MeshNode> nodes = pbvh.nodes<bke::pbvh::MeshNode>();
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const Span<int2> edges = mesh.edges();
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int> corner_edges = mesh.corner_edges();
|
||||
const Span<int3> corner_tris = mesh.corner_tris();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
|
||||
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
nodes_to_calculate.foreach_index(GrainSize(1), [&](const int i) {
|
||||
ibos[i] = create_index_faces(edges,
|
||||
ibos[i] = create_index_faces(faces,
|
||||
corner_verts,
|
||||
corner_edges,
|
||||
corner_tris,
|
||||
tri_faces,
|
||||
hide_poly,
|
||||
bke::pbvh::node_tri_indices(nodes[i]));
|
||||
bke::pbvh::node_faces(nodes[i]),
|
||||
nodes[i].vert_indices_);
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -1797,15 +1773,15 @@ BLI_NOINLINE static void ensure_vbos_allocated_mesh(const Object &object,
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const Span<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
const Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const bke::AttributeAccessor attributes = orig_mesh_data.attributes;
|
||||
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
node_mask.foreach_index(GrainSize(64), [&](const int i) {
|
||||
if (!vbos[i]) {
|
||||
vbos[i] = GPU_vertbuf_create_with_format(format);
|
||||
}
|
||||
const Span<int> tris = bke::pbvh::node_tri_indices(nodes[i]);
|
||||
const int verts_num = count_visible_tris_mesh(tris, tri_faces, hide_poly) * 3;
|
||||
const Span<int> face_indices = bke::pbvh::node_faces(nodes[i]);
|
||||
const int verts_num = count_visible_tris_mesh(faces, face_indices, hide_poly) * 3;
|
||||
GPU_vertbuf_data_alloc(*vbos[i], verts_num);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -25,7 +25,6 @@ inline namespace draw_face_sets_cc {
|
||||
constexpr float FACE_SET_BRUSH_MIN_FADE = 0.05f;
|
||||
|
||||
struct MeshLocalData {
|
||||
Vector<int> face_indices;
|
||||
Vector<float3> positions;
|
||||
Vector<float3> normals;
|
||||
Vector<float> factors;
|
||||
@@ -174,9 +173,6 @@ static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph,
|
||||
const SculptSession &ss = *object.sculpt;
|
||||
const Span<float3> positions_eval = bke::pbvh::vert_positions_eval(depsgraph, object);
|
||||
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const Span<int> corner_tris = mesh.corner_tri_faces();
|
||||
|
||||
undo::push_nodes(depsgraph, object, node_mask, undo::Type::FaceSet);
|
||||
|
||||
bke::SpanAttributeWriter<int> face_sets = face_set::ensure_face_sets_mesh(object);
|
||||
@@ -186,8 +182,7 @@ static void do_draw_face_sets_brush_mesh(const Depsgraph &depsgraph,
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
MeshLocalData &tls = all_tls.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
const Span<int> face_indices = bke::pbvh::node_face_indices_calc_mesh(
|
||||
corner_tris, nodes[i], tls.face_indices);
|
||||
const Span<int> face_indices = bke::pbvh::node_faces(nodes[i]);
|
||||
|
||||
calc_faces(depsgraph,
|
||||
object,
|
||||
|
||||
@@ -215,7 +215,6 @@ static void flush_face_changes_node(Mesh &mesh,
|
||||
{
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
|
||||
@@ -223,15 +222,13 @@ static void flush_face_changes_node(Mesh &mesh,
|
||||
".hide_poly", bke::AttrDomain::Face);
|
||||
|
||||
struct TLS {
|
||||
Vector<int> face_indices;
|
||||
Vector<bool> new_hide;
|
||||
};
|
||||
threading::EnumerableThreadSpecific<TLS> all_tls;
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
TLS &tls = all_tls.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
const Span<int> node_faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, nodes[i], tls.face_indices);
|
||||
const Span<int> node_faces = bke::pbvh::node_faces(nodes[i]);
|
||||
|
||||
tls.new_hide.resize(node_faces.size());
|
||||
gather_data_mesh(hide_poly.span.as_span(), node_faces, tls.new_hide.as_mutable_span());
|
||||
@@ -714,23 +711,17 @@ static void invert_visibility_mesh(const Depsgraph &depsgraph,
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
bke::SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
|
||||
".hide_poly", bke::AttrDomain::Face);
|
||||
|
||||
undo::push_nodes(depsgraph, object, node_mask, undo::Type::HideFace);
|
||||
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_index_data;
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &faces = all_index_data.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
bke::pbvh::node_face_indices_calc_mesh(tri_faces, nodes[i], faces);
|
||||
for (const int face : faces) {
|
||||
hide_poly.span[face] = !hide_poly.span[face];
|
||||
}
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
});
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
for (const int face : bke::pbvh::node_faces(nodes[i])) {
|
||||
hide_poly.span[face] = !hide_poly.span[face];
|
||||
}
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
});
|
||||
|
||||
hide_poly.finish();
|
||||
@@ -920,31 +911,24 @@ static void update_undo_state(const Depsgraph &depsgraph,
|
||||
|
||||
static void update_node_visibility_from_face_changes(MutableSpan<bke::pbvh::MeshNode> nodes,
|
||||
const IndexMask &node_mask,
|
||||
const Span<int> tri_faces,
|
||||
const Span<bool> orig_hide_poly,
|
||||
const Span<bool> new_hide_poly,
|
||||
const Span<bool> hide_vert)
|
||||
{
|
||||
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_face_indices;
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &face_indices = all_face_indices.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
bool any_changed = false;
|
||||
const Span<int> indices = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, nodes[i], face_indices);
|
||||
for (const int face_index : indices) {
|
||||
if (orig_hide_poly[face_index] != new_hide_poly[face_index]) {
|
||||
any_changed = true;
|
||||
break;
|
||||
}
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
bool any_changed = false;
|
||||
const Span<int> indices = bke::pbvh::node_faces(nodes[i]);
|
||||
for (const int face_index : indices) {
|
||||
if (orig_hide_poly[face_index] != new_hide_poly[face_index]) {
|
||||
any_changed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (any_changed) {
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
bke::pbvh::node_update_visibility_mesh(hide_vert, nodes[i]);
|
||||
}
|
||||
});
|
||||
if (any_changed) {
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
bke::pbvh::node_update_visibility_mesh(hide_vert, nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -985,7 +969,6 @@ static void grow_shrink_visibility_mesh(const Depsgraph &depsgraph,
|
||||
|
||||
update_node_visibility_from_face_changes(object.sculpt->pbvh->nodes<bke::pbvh::MeshNode>(),
|
||||
node_mask,
|
||||
mesh.corner_tri_faces(),
|
||||
orig_hide_poly,
|
||||
hide_poly,
|
||||
last_buffer);
|
||||
|
||||
@@ -1915,12 +1915,6 @@ static void vpaint_do_paint(bContext *C,
|
||||
mesh.active_color_attribute);
|
||||
BLI_assert(attribute.domain == vpd.domain);
|
||||
|
||||
if (attribute.domain == bke::AttrDomain::Corner) {
|
||||
/* The sculpt undo system needs bke::pbvh::Tree node corner indices for corner domain
|
||||
* color attributes. */
|
||||
BKE_pbvh_ensure_node_face_corners(*ss.pbvh, mesh.corner_tris());
|
||||
}
|
||||
|
||||
/* Paint those leaves. */
|
||||
vpaint_paint_leaves(
|
||||
C, vp, vpd, ob, mesh, attribute.span, ss.pbvh->nodes<bke::pbvh::MeshNode>(), node_mask);
|
||||
@@ -2313,11 +2307,6 @@ static int vertex_color_set_exec(bContext *C, wmOperator *op)
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(*obact.sculpt->pbvh, memory);
|
||||
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(obact.data);
|
||||
/* The sculpt undo system needs bke::pbvh::Tree node corner indices for corner domain
|
||||
* color attributes. */
|
||||
BKE_pbvh_ensure_node_face_corners(*obact.sculpt->pbvh, mesh.corner_tris());
|
||||
|
||||
undo::push_nodes(depsgraph, obact, node_mask, undo::Type::Color);
|
||||
|
||||
fill_active_color(obact, paintcol, true, affect_alpha);
|
||||
|
||||
@@ -317,10 +317,6 @@ static void transform_active_color(bContext *C,
|
||||
undo::push_begin(obact, op);
|
||||
|
||||
bke::pbvh::Tree &pbvh = *obact.sculpt->pbvh;
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(obact.data);
|
||||
/* The sculpt undo system needs pbvh::Tree node corner indices for corner domain color
|
||||
* attributes. */
|
||||
BKE_pbvh_ensure_node_face_corners(pbvh, mesh.corner_tris());
|
||||
|
||||
IndexMaskMemory memory;
|
||||
const IndexMask node_mask = bke::pbvh::all_leaf_nodes(pbvh, memory);
|
||||
|
||||
@@ -1268,18 +1268,13 @@ static void restore_face_set_from_undo_step(Object &object)
|
||||
|
||||
switch (ss.pbvh->type()) {
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
bke::SpanAttributeWriter<int> attribute = face_set::ensure_face_sets_mesh(object);
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_tls;
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
Vector<int> &tls = all_tls.local();
|
||||
if (const std::optional<Span<int>> orig_data = orig_face_set_data_lookup_mesh(object,
|
||||
nodes[i]))
|
||||
{
|
||||
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(tri_faces, nodes[i], tls);
|
||||
scatter_data_mesh(*orig_data, faces, attribute.span);
|
||||
scatter_data_mesh(*orig_data, bke::pbvh::node_faces(nodes[i]), attribute.span);
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
}
|
||||
});
|
||||
@@ -2920,9 +2915,9 @@ struct SculptRaycastData {
|
||||
float depth;
|
||||
bool original;
|
||||
Span<blender::float3> vert_positions;
|
||||
blender::OffsetIndices<int> faces;
|
||||
Span<int> corner_verts;
|
||||
Span<blender::int3> corner_tris;
|
||||
Span<int> corner_tri_faces;
|
||||
blender::VArraySpan<bool> hide_poly;
|
||||
|
||||
const SubdivCCG *subdiv_ccg;
|
||||
@@ -2944,9 +2939,9 @@ struct SculptFindNearestToRayData {
|
||||
float dist_sq_to_ray;
|
||||
bool original;
|
||||
Span<float3> vert_positions;
|
||||
blender::OffsetIndices<int> faces;
|
||||
Span<int> corner_verts;
|
||||
Span<blender::int3> corner_tris;
|
||||
Span<int> corner_tri_faces;
|
||||
blender::VArraySpan<bool> hide_poly;
|
||||
|
||||
const SubdivCCG *subdiv_ccg;
|
||||
@@ -3366,12 +3361,6 @@ static void push_undo_nodes(const Depsgraph &depsgraph,
|
||||
}
|
||||
}
|
||||
else if (SCULPT_brush_type_is_paint(brush.sculpt_brush_type)) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
if (const bke::GAttributeReader attr = color::active_color_attribute(mesh)) {
|
||||
if (attr.domain == bke::AttrDomain::Corner) {
|
||||
BKE_pbvh_ensure_node_face_corners(*ss.pbvh, mesh.corner_tris());
|
||||
}
|
||||
}
|
||||
undo::push_nodes(depsgraph, ob, node_mask, undo::Type::Color);
|
||||
switch (ss.pbvh->type()) {
|
||||
case bke::pbvh::Type::Mesh: {
|
||||
@@ -4811,9 +4800,9 @@ static void sculpt_raycast_cb(blender::bke::pbvh::Node &node, SculptRaycastData
|
||||
origco,
|
||||
use_origco,
|
||||
srd.vert_positions,
|
||||
srd.faces,
|
||||
srd.corner_verts,
|
||||
srd.corner_tris,
|
||||
srd.corner_tri_faces,
|
||||
srd.hide_poly,
|
||||
srd.subdiv_ccg,
|
||||
srd.ray_start,
|
||||
@@ -4871,9 +4860,9 @@ static void sculpt_find_nearest_to_ray_cb(blender::bke::pbvh::Node &node,
|
||||
origco,
|
||||
use_origco,
|
||||
srd.vert_positions,
|
||||
srd.faces,
|
||||
srd.corner_verts,
|
||||
srd.corner_tris,
|
||||
srd.corner_tri_faces,
|
||||
srd.hide_poly,
|
||||
srd.subdiv_ccg,
|
||||
srd.ray_start,
|
||||
@@ -4971,9 +4960,9 @@ bool SCULPT_cursor_geometry_info_update(bContext *C,
|
||||
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
srd.vert_positions = bke::pbvh::vert_positions_eval(*depsgraph, ob);
|
||||
srd.faces = mesh.faces();
|
||||
srd.corner_verts = mesh.corner_verts();
|
||||
srd.corner_tris = mesh.corner_tris();
|
||||
srd.corner_tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
srd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
}
|
||||
@@ -5149,9 +5138,9 @@ bool SCULPT_stroke_get_location_ex(bContext *C,
|
||||
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
srd.vert_positions = bke::pbvh::vert_positions_eval(*depsgraph, ob);
|
||||
srd.faces = mesh.faces();
|
||||
srd.corner_verts = mesh.corner_verts();
|
||||
srd.corner_tris = mesh.corner_tris();
|
||||
srd.corner_tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
srd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
}
|
||||
@@ -5190,9 +5179,9 @@ bool SCULPT_stroke_get_location_ex(bContext *C,
|
||||
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
srd.vert_positions = bke::pbvh::vert_positions_eval(*depsgraph, ob);
|
||||
srd.faces = mesh.faces();
|
||||
srd.corner_verts = mesh.corner_verts();
|
||||
srd.corner_tris = mesh.corner_tris();
|
||||
srd.corner_tri_faces = mesh.corner_tri_faces();
|
||||
const bke::AttributeAccessor attributes = mesh.attributes();
|
||||
srd.hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
}
|
||||
@@ -6255,8 +6244,8 @@ bool SCULPT_vertex_is_occluded(const Object &object, const float3 &position, boo
|
||||
srd.corner_verts = ss.corner_verts;
|
||||
if (ss.pbvh->type() == bke::pbvh::Type::Mesh) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
||||
srd.faces = mesh.faces();
|
||||
srd.corner_tris = mesh.corner_tris();
|
||||
srd.corner_tri_faces = mesh.corner_tri_faces();
|
||||
}
|
||||
else if (ss.pbvh->type() == bke::pbvh::Type::Grids) {
|
||||
srd.subdiv_ccg = ss.subdiv_ccg;
|
||||
|
||||
@@ -2509,9 +2509,6 @@ static void undo_push(const Depsgraph &depsgraph, Object &ob, Cache &expand_cach
|
||||
undo::push_nodes(depsgraph, ob, node_mask, undo::Type::FaceSet);
|
||||
break;
|
||||
case TargetType::Colors: {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
/* The sculpt undo system needs corner indices for corner domain color attributes. */
|
||||
BKE_pbvh_ensure_node_face_corners(*ss.pbvh, mesh.corner_tris());
|
||||
undo::push_nodes(depsgraph, ob, node_mask, undo::Type::Color);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -289,8 +289,6 @@ static void face_sets_update(const Depsgraph &depsgraph,
|
||||
{
|
||||
SculptSession &ss = *object.sculpt;
|
||||
bke::pbvh::Tree &pbvh = *ss.pbvh;
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
|
||||
bke::SpanAttributeWriter<int> face_sets = ensure_face_sets_mesh(object);
|
||||
|
||||
@@ -305,8 +303,7 @@ static void face_sets_update(const Depsgraph &depsgraph,
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
TLS &tls = all_tls.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, nodes[i], tls.face_indices);
|
||||
const Span<int> faces = bke::pbvh::node_faces(nodes[i]);
|
||||
|
||||
tls.new_face_sets.resize(faces.size());
|
||||
MutableSpan<int> new_face_sets = tls.new_face_sets;
|
||||
@@ -364,29 +361,23 @@ static void clear_face_sets(const Depsgraph &depsgraph, Object &object, const In
|
||||
}
|
||||
SculptSession &ss = *object.sculpt;
|
||||
bke::pbvh::Tree &pbvh = *ss.pbvh;
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const int default_face_set = mesh.face_sets_color_default;
|
||||
const VArraySpan face_sets = *attributes.lookup<int>(".sculpt_face_set", bke::AttrDomain::Face);
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_face_indices;
|
||||
if (pbvh.type() == bke::pbvh::Type::Mesh) {
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &face_indices = all_face_indices.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
const Span<int> faces =
|
||||
|
||||
bke::pbvh::node_face_indices_calc_mesh(tri_faces, nodes[i], face_indices);
|
||||
if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
|
||||
return face_sets[face] != default_face_set;
|
||||
}))
|
||||
{
|
||||
undo::push_node(depsgraph, object, &nodes[i], undo::Type::FaceSet);
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
}
|
||||
});
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
const Span<int> faces = bke::pbvh::node_faces(nodes[i]);
|
||||
if (std::any_of(faces.begin(), faces.end(), [&](const int face) {
|
||||
return face_sets[face] != default_face_set;
|
||||
}))
|
||||
{
|
||||
undo::push_node(depsgraph, object, &nodes[i], undo::Type::FaceSet);
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (pbvh.type() == bke::pbvh::Type::Grids) {
|
||||
threading::EnumerableThreadSpecific<Vector<int>> all_face_indices;
|
||||
MutableSpan<bke::pbvh::GridsNode> nodes = ss.pbvh->nodes<bke::pbvh::GridsNode>();
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
Vector<int> &face_indices = all_face_indices.local();
|
||||
@@ -882,7 +873,6 @@ static void face_hide_update(const Depsgraph &depsgraph,
|
||||
SculptSession &ss = *object.sculpt;
|
||||
bke::pbvh::Tree &pbvh = *ss.pbvh;
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
bke::MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
||||
bke::SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
|
||||
".hide_poly", bke::AttrDomain::Face);
|
||||
@@ -899,8 +889,7 @@ static void face_hide_update(const Depsgraph &depsgraph,
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
TLS &tls = all_tls.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, nodes[i], tls.face_indices);
|
||||
const Span<int> faces = bke::pbvh::node_faces(nodes[i]);
|
||||
|
||||
tls.new_hide.resize(faces.size());
|
||||
MutableSpan<bool> new_hide = tls.new_hide;
|
||||
@@ -1652,7 +1641,6 @@ static void gesture_apply_mesh(gesture::GestureData &gesture_data, const IndexMa
|
||||
const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
const VArraySpan<bool> hide_poly = *attributes.lookup<bool>(".hide_poly", bke::AttrDomain::Face);
|
||||
bke::SpanAttributeWriter<int> face_sets = face_set::ensure_face_sets_mesh(object);
|
||||
|
||||
@@ -1663,31 +1651,25 @@ static void gesture_apply_mesh(gesture::GestureData &gesture_data, const IndexMa
|
||||
threading::EnumerableThreadSpecific<TLS> all_tls;
|
||||
if (pbvh.type() == bke::pbvh::Type::Mesh) {
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
threading::parallel_for(node_mask.index_range(), 1, [&](const IndexRange range) {
|
||||
TLS &tls = all_tls.local();
|
||||
node_mask.slice(range).foreach_index([&](const int i) {
|
||||
undo::push_node(depsgraph, *gesture_data.vc.obact, &nodes[i], undo::Type::FaceSet);
|
||||
const Span<int> node_faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, nodes[i], tls.face_indices);
|
||||
|
||||
bool any_updated = false;
|
||||
for (const int face : node_faces) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
const Span<int> face_verts = corner_verts.slice(faces[face]);
|
||||
const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
|
||||
const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
|
||||
if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
|
||||
continue;
|
||||
}
|
||||
face_sets.span[face] = new_face_set;
|
||||
any_updated = true;
|
||||
node_mask.foreach_index(GrainSize(1), [&](const int i) {
|
||||
undo::push_node(depsgraph, *gesture_data.vc.obact, &nodes[i], undo::Type::FaceSet);
|
||||
bool any_updated = false;
|
||||
for (const int face : bke::pbvh::node_faces(nodes[i])) {
|
||||
if (!hide_poly.is_empty() && hide_poly[face]) {
|
||||
continue;
|
||||
}
|
||||
if (any_updated) {
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
const Span<int> face_verts = corner_verts.slice(faces[face]);
|
||||
const float3 face_center = bke::mesh::face_center_calc(positions, face_verts);
|
||||
const float3 face_normal = bke::mesh::face_normal_calc(positions, face_verts);
|
||||
if (!gesture::is_affected(gesture_data, face_center, face_normal)) {
|
||||
continue;
|
||||
}
|
||||
});
|
||||
face_sets.span[face] = new_face_set;
|
||||
any_updated = true;
|
||||
}
|
||||
if (any_updated) {
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
}
|
||||
});
|
||||
}
|
||||
else if (pbvh.type() == bke::pbvh::Type::Grids) {
|
||||
|
||||
@@ -142,11 +142,6 @@ void cache_init(bContext *C,
|
||||
ss.filter_cache->start_filter_strength = start_strength;
|
||||
ss.filter_cache->random_seed = rand();
|
||||
|
||||
if (undo_type == undo::Type::Color) {
|
||||
const Mesh &mesh = *static_cast<const Mesh *>(ob.data);
|
||||
BKE_pbvh_ensure_node_face_corners(pbvh, mesh.corner_tris());
|
||||
}
|
||||
|
||||
ss.filter_cache->node_mask = bke::pbvh::search_nodes(
|
||||
pbvh, ss.filter_cache->node_mask_memory, [&](const bke::pbvh::Node &node) {
|
||||
return !node_fully_masked_or_hidden(node);
|
||||
|
||||
@@ -147,7 +147,10 @@ struct Node {
|
||||
Array<int, 0> vert_indices;
|
||||
int unique_verts_num;
|
||||
|
||||
Array<int, 0> corner_indices;
|
||||
/**
|
||||
* \todo Storing corners rather than faces is unnecessary.
|
||||
*/
|
||||
Vector<int, 0> corner_indices;
|
||||
|
||||
BitVector<0> vert_hidden;
|
||||
BitVector<0> face_hidden;
|
||||
@@ -954,7 +957,6 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
|
||||
if (step_data.object_name != object.id.name) {
|
||||
return;
|
||||
}
|
||||
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
||||
SculptSession &ss = *object.sculpt;
|
||||
|
||||
/* Restore pivot. */
|
||||
@@ -1106,12 +1108,8 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
|
||||
}
|
||||
else {
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
Vector<int> faces_vector;
|
||||
node_mask.foreach_index([&](const int i) {
|
||||
faces_vector.clear();
|
||||
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, static_cast<bke::pbvh::MeshNode &>(nodes[i]), faces_vector);
|
||||
const Span<int> faces = bke::pbvh::node_faces(nodes[i]);
|
||||
if (indices_contain_true(modified_faces, faces)) {
|
||||
BKE_pbvh_node_mark_update_visibility(nodes[i]);
|
||||
}
|
||||
@@ -1187,12 +1185,8 @@ static void restore_list(bContext *C, Depsgraph *depsgraph, StepData &step_data)
|
||||
}
|
||||
else {
|
||||
MutableSpan<bke::pbvh::MeshNode> nodes = ss.pbvh->nodes<bke::pbvh::MeshNode>();
|
||||
const Span<int> tri_faces = mesh.corner_tri_faces();
|
||||
Vector<int> faces_vector;
|
||||
node_mask.foreach_index([&](const int i) {
|
||||
faces_vector.clear();
|
||||
const Span<int> faces = bke::pbvh::node_face_indices_calc_mesh(
|
||||
tri_faces, static_cast<bke::pbvh::MeshNode &>(nodes[i]), faces_vector);
|
||||
const Span<int> faces = bke::pbvh::node_faces(nodes[i]);
|
||||
if (indices_contain_true(modified_faces, faces)) {
|
||||
BKE_pbvh_node_mark_update_face_sets(nodes[i]);
|
||||
}
|
||||
@@ -1399,7 +1393,7 @@ static void store_mask_grids(const SubdivCCG &subdiv_ccg, Node &unode)
|
||||
}
|
||||
}
|
||||
|
||||
static void store_color(const Mesh &mesh, const bke::pbvh::Node &node, Node &unode)
|
||||
static void store_color(const Mesh &mesh, const bke::pbvh::MeshNode &node, Node &unode)
|
||||
{
|
||||
const OffsetIndices<int> faces = mesh.faces();
|
||||
const Span<int> corner_verts = mesh.corner_verts();
|
||||
@@ -1409,14 +1403,17 @@ static void store_color(const Mesh &mesh, const bke::pbvh::Node &node, Node &uno
|
||||
|
||||
/* NOTE: even with loop colors we still store (derived)
|
||||
* vertex colors for original data lookup. */
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(
|
||||
static_cast<const bke::pbvh::MeshNode &>(node));
|
||||
const Span<int> verts = bke::pbvh::node_unique_verts(node);
|
||||
unode.col.reinitialize(verts.size());
|
||||
color::gather_colors_vert(
|
||||
faces, corner_verts, vert_to_face_map, colors, color_attribute.domain, verts, unode.col);
|
||||
|
||||
if (color_attribute.domain == bke::AttrDomain::Corner) {
|
||||
unode.corner_indices = bke::pbvh::node_corners(static_cast<const bke::pbvh::MeshNode &>(node));
|
||||
for (const int face : bke::pbvh::node_faces(node)) {
|
||||
for (const int corner : faces[face]) {
|
||||
unode.corner_indices.append(corner);
|
||||
}
|
||||
}
|
||||
unode.loop_col.reinitialize(unode.corner_indices.size());
|
||||
color::gather_colors(colors, unode.corner_indices, unode.loop_col);
|
||||
}
|
||||
@@ -1468,14 +1465,9 @@ static void fill_node_data_mesh(const Depsgraph &depsgraph,
|
||||
|
||||
const int verts_num = unode.vert_indices.size();
|
||||
|
||||
const bool need_loops = type == Type::Color;
|
||||
if (need_loops) {
|
||||
unode.corner_indices = bke::pbvh::node_corners(node);
|
||||
}
|
||||
|
||||
const bool need_faces = ELEM(type, Type::FaceSet, Type::HideFace);
|
||||
if (need_faces) {
|
||||
bke::pbvh::node_face_indices_calc_mesh(mesh.corner_tri_faces(), node, unode.face_indices);
|
||||
unode.face_indices = bke::pbvh::node_faces(node);
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
|
||||
Reference in New Issue
Block a user