2023-08-16 00:20:26 +10:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2019-02-18 08:08:12 +11:00
|
|
|
/** \file
|
2021-10-06 11:37:50 +11:00
|
|
|
* \ingroup bke
|
2011-02-27 20:37:56 +00:00
|
|
|
*/
|
|
|
|
|
|
2010-08-16 05:46:10 +00:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
#include <climits>
|
Refactor CDData masks, to have one mask per mesh elem type.
We already have different storages for cddata of verts, edges etc.,
'simply' do the same for the mask flags we use all around Blender code
to request some data, or limit some operation to some layers, etc.
Reason we need this is that some cddata types (like Normals) are
actually shared between verts/polys/loops, and we don’t want to generate
clnors everytime we request vnors!
As a side note, this also does final fix to T59338, which was the
trigger for this patch (need to request computed loop normals for
another mesh than evaluated one).
Reviewers: brecht, campbellbarton, sergey
Differential Revision: https://developer.blender.org/D4407
2019-03-07 11:13:40 +01:00
|
|
|
|
2023-10-06 23:00:29 +02:00
|
|
|
#include "BLI_array_utils.hh"
|
2023-12-03 17:55:43 -05:00
|
|
|
#include "BLI_bit_span_ops.hh"
|
2012-02-22 23:57:31 +00:00
|
|
|
#include "BLI_bitmap.h"
|
2023-12-04 11:25:07 -05:00
|
|
|
#include "BLI_bounds.hh"
|
2024-01-08 18:49:26 +01:00
|
|
|
#include "BLI_enumerable_thread_specific.hh"
|
Cleanup: reduce amount of math-related includes
Using ClangBuildAnalyzer on the whole Blender build, it was pointing
out that BLI_math.h is the heaviest "header hub" (i.e. non tiny file
that is included a lot).
However, there's very little (actually zero) source files in Blender
that need "all the math" (base, colors, vectors, matrices,
quaternions, intersection, interpolation, statistics, solvers and
time). A common use case is source files needing just vectors, or
just vectors & matrices, or just colors etc. Actually, 181 files
were including the whole math thing without needing it at all.
This change removes BLI_math.h completely, and instead in all the
places that need it, includes BLI_math_vector.h or BLI_math_color.h
and so on.
Change from that:
- BLI_math_color.h was included 1399 times -> now 408 (took 114.0sec
to parse -> now 36.3sec)
- BLI_simd.h 1403 -> 418 (109.7sec -> 34.9sec).
Full rebuild of Blender (Apple M1, Xcode, RelWithDebInfo) is not
affected much (342sec -> 334sec). Most of benefit would be when
someone's changing BLI_simd.h or BLI_math_color.h or similar files,
that now there's 3x fewer files result in a recompile.
Pull Request #110944
2023-08-09 11:39:20 +03:00
|
|
|
#include "BLI_math_geom.h"
|
|
|
|
|
#include "BLI_math_matrix.h"
|
|
|
|
|
#include "BLI_math_vector.h"
|
2023-05-09 22:36:30 +02:00
|
|
|
#include "BLI_math_vector.hh"
|
2020-03-05 14:53:23 +01:00
|
|
|
#include "BLI_rand.h"
|
2024-08-19 17:32:39 -04:00
|
|
|
#include "BLI_stack.hh"
|
2020-03-19 09:33:03 +01:00
|
|
|
#include "BLI_task.h"
|
2023-05-09 22:36:30 +02:00
|
|
|
#include "BLI_task.hh"
|
2024-01-19 14:32:28 +01:00
|
|
|
#include "BLI_time.h"
|
2023-07-27 17:40:53 -04:00
|
|
|
#include "BLI_timeit.hh"
|
2023-02-05 16:56:37 -05:00
|
|
|
#include "BLI_utildefines.h"
|
2023-04-14 21:16:42 +02:00
|
|
|
#include "BLI_vector.hh"
|
2023-05-09 22:36:30 +02:00
|
|
|
#include "BLI_vector_set.hh"
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
#include "DNA_object_types.h"
|
|
|
|
|
|
2023-08-23 22:02:23 -04:00
|
|
|
#include "BKE_attribute.hh"
|
2024-05-30 09:43:56 -04:00
|
|
|
#include "BKE_ccg.hh"
|
2023-03-12 22:29:15 +01:00
|
|
|
#include "BKE_mesh.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_mesh_mapping.hh"
|
2024-08-22 21:00:25 +02:00
|
|
|
#include "BKE_object.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_paint.hh"
|
2023-07-03 19:55:22 -07:00
|
|
|
#include "BKE_pbvh_api.hh"
|
2023-08-02 22:14:18 +02:00
|
|
|
#include "BKE_subdiv_ccg.hh"
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-08-14 23:19:19 -04:00
|
|
|
#include "DEG_depsgraph_query.hh"
|
|
|
|
|
|
2023-12-05 23:01:12 +01:00
|
|
|
#include "bmesh.hh"
|
2013-05-30 02:16:22 +00:00
|
|
|
|
2016-01-27 12:14:00 +01:00
|
|
|
#include "atomic_ops.h"
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
#include "pbvh_intern.hh"
|
2015-07-31 22:52:37 +02:00
|
|
|
|
2024-07-23 23:21:40 -04:00
|
|
|
namespace blender::bke::pbvh {
|
2023-04-08 13:29:37 +02:00
|
|
|
|
2024-09-04 15:55:18 -04:00
|
|
|
// #define DEBUG_BUILD_TIME
|
2024-09-05 16:21:43 +02:00
|
|
|
|
2012-05-11 08:05:47 +00:00
|
|
|
#define STACK_FIXED_DEPTH 100
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2023-12-04 11:25:07 -05:00
|
|
|
/** Create invalid bounds for use with #math::min_max. */
|
|
|
|
|
static Bounds<float3> negative_bounds()
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
2023-12-04 11:25:07 -05:00
|
|
|
return {float3(std::numeric_limits<float>::max()), float3(std::numeric_limits<float>::lowest())};
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:23:22 -04:00
|
|
|
static Bounds<float3> merge_bounds(const Bounds<float3> &a, const Bounds<float3> &b)
|
|
|
|
|
{
|
|
|
|
|
return bounds::merge(a, b);
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-09 15:16:28 +02:00
|
|
|
static int partition_along_axis(const Span<float3> face_centers,
|
|
|
|
|
MutableSpan<int> faces,
|
|
|
|
|
const int axis,
|
|
|
|
|
const float middle)
|
2024-09-05 16:21:43 +02:00
|
|
|
{
|
2024-09-09 15:16:28 +02:00
|
|
|
const int *split = std::partition(faces.begin(), faces.end(), [&](const int face) {
|
2024-09-09 09:49:46 -04:00
|
|
|
return face_centers[face][axis] >= middle;
|
2024-09-09 15:16:28 +02:00
|
|
|
});
|
|
|
|
|
return split - faces.begin();
|
2024-09-05 16:21:43 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-09 15:16:28 +02:00
|
|
|
static int partition_material_indices(const Span<int> material_indices, MutableSpan<int> faces)
|
2012-03-06 02:40:08 +00:00
|
|
|
{
|
2024-09-09 15:16:28 +02:00
|
|
|
const int first = material_indices[faces.first()];
|
|
|
|
|
const int *split = std::partition(
|
|
|
|
|
faces.begin(), faces.end(), [&](const int face) { return material_indices[face] == first; });
|
|
|
|
|
return split - faces.begin();
|
2012-03-06 02:40:08 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 15:49:05 -04:00
|
|
|
BLI_NOINLINE static void build_mesh_leaf_nodes(const int verts_num,
|
2024-09-05 16:21:43 +02:00
|
|
|
const OffsetIndices<int> faces,
|
2024-09-04 15:49:05 -04:00
|
|
|
const Span<int> corner_verts,
|
|
|
|
|
MutableSpan<MeshNode> nodes)
|
|
|
|
|
{
|
2024-09-04 15:55:18 -04:00
|
|
|
#ifdef DEBUG_BUILD_TIME
|
2024-09-04 15:49:05 -04:00
|
|
|
SCOPED_TIMER_AVERAGED(__func__);
|
2024-09-04 15:55:18 -04:00
|
|
|
#endif
|
2024-09-05 16:21:43 +02:00
|
|
|
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();
|
2024-09-19 22:31:26 -04:00
|
|
|
int corners_count = 0;
|
|
|
|
|
for (const int face_index : node.face_indices_) {
|
|
|
|
|
const IndexRange face = faces[face_index];
|
|
|
|
|
verts.add_multiple(corner_verts.slice(face));
|
|
|
|
|
corners_count += face.size();
|
2024-09-05 16:21:43 +02:00
|
|
|
}
|
2024-09-19 22:31:26 -04:00
|
|
|
nodes[i].corners_num_ = corners_count;
|
2024-09-05 16:21:43 +02:00
|
|
|
|
|
|
|
|
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());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
Vector<int> owned_verts;
|
|
|
|
|
Vector<int> shared_verts;
|
|
|
|
|
BitVector<> vert_used(verts_num);
|
2024-09-04 15:49:05 -04:00
|
|
|
for (const int i : nodes.index_range()) {
|
2024-09-05 16:21:43 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2024-09-04 15:49:05 -04:00
|
|
|
}
|
2024-09-05 16:21:43 +02:00
|
|
|
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);
|
2024-09-04 15:49:05 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-09 09:49:46 -04:00
|
|
|
static bool leaf_needs_material_split(const Span<int> faces, const Span<int> material_indices)
|
2024-09-05 16:21:43 +02:00
|
|
|
{
|
|
|
|
|
if (material_indices.is_empty()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2024-09-09 09:49:46 -04:00
|
|
|
const int first = material_indices[faces.first()];
|
|
|
|
|
return std::any_of(
|
|
|
|
|
faces.begin(), faces.end(), [&](const int face) { return material_indices[face] != first; });
|
2024-09-05 16:21:43 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void build_nodes_recursive_mesh(const Span<int> material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
const int leaf_limit,
|
|
|
|
|
const int node_index,
|
2024-09-04 15:23:22 -04:00
|
|
|
const std::optional<Bounds<float3>> &bounds_precalc,
|
2024-09-08 15:52:56 -04:00
|
|
|
const Span<float3> face_centers,
|
2024-09-09 09:56:13 -04:00
|
|
|
const int depth,
|
2024-09-09 09:49:46 -04:00
|
|
|
MutableSpan<int> faces,
|
2024-08-28 15:18:21 +02:00
|
|
|
Vector<MeshNode> &nodes)
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
2024-09-09 09:56:13 -04:00
|
|
|
/* Decide whether this is a leaf or not */
|
2024-09-09 09:49:46 -04:00
|
|
|
const bool below_leaf_limit = faces.size() <= leaf_limit || depth >= STACK_FIXED_DEPTH - 1;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (below_leaf_limit) {
|
2024-09-09 09:49:46 -04:00
|
|
|
if (!leaf_needs_material_split(faces, material_indices)) {
|
2024-08-28 15:18:21 +02:00
|
|
|
MeshNode &node = nodes[node_index];
|
2024-07-23 23:36:30 -04:00
|
|
|
node.flag_ |= PBVH_Leaf;
|
2024-09-09 09:49:46 -04:00
|
|
|
node.face_indices_ = faces;
|
2012-03-06 02:40:08 +00:00
|
|
|
return;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2012-03-06 02:40:08 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-05 22:12:50 +00:00
|
|
|
/* Add two child nodes */
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_ = nodes.size();
|
|
|
|
|
nodes.resize(nodes.size() + 2);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-09 09:56:13 -04:00
|
|
|
int split;
|
2012-03-24 06:18:31 +00:00
|
|
|
if (!below_leaf_limit) {
|
2024-09-04 15:23:22 -04:00
|
|
|
Bounds<float3> bounds;
|
|
|
|
|
if (bounds_precalc) {
|
|
|
|
|
bounds = *bounds_precalc;
|
2012-03-06 02:40:08 +00:00
|
|
|
}
|
2024-09-04 15:23:22 -04:00
|
|
|
else {
|
|
|
|
|
bounds = threading::parallel_reduce(
|
2024-09-09 09:49:46 -04:00
|
|
|
faces.index_range(),
|
2024-09-04 15:23:22 -04:00
|
|
|
1024,
|
|
|
|
|
negative_bounds(),
|
|
|
|
|
[&](const IndexRange range, Bounds<float3> value) {
|
2024-09-09 09:49:46 -04:00
|
|
|
for (const int face : faces.slice(range)) {
|
2024-09-09 09:56:13 -04:00
|
|
|
math::min_max(face_centers[face], value.min, value.max);
|
2024-09-04 15:23:22 -04:00
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
},
|
|
|
|
|
merge_bounds);
|
|
|
|
|
}
|
|
|
|
|
const int axis = math::dominant_axis(bounds.max - bounds.min);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-06 02:40:08 +00:00
|
|
|
/* Partition primitives along that axis */
|
2024-09-09 09:49:46 -04:00
|
|
|
split = partition_along_axis(
|
2024-09-09 09:56:13 -04:00
|
|
|
face_centers, faces, axis, math::midpoint(bounds.min[axis], bounds.max[axis]));
|
2012-03-06 02:40:08 +00:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Partition primitives by material */
|
2024-09-09 09:49:46 -04:00
|
|
|
split = partition_material_indices(material_indices, faces);
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-03-05 22:12:50 +00:00
|
|
|
/* Build children */
|
2024-09-05 16:21:43 +02:00
|
|
|
build_nodes_recursive_mesh(material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
leaf_limit,
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_,
|
2024-09-04 15:23:22 -04:00
|
|
|
std::nullopt,
|
2024-09-08 15:52:56 -04:00
|
|
|
face_centers,
|
2024-09-09 09:56:13 -04:00
|
|
|
depth + 1,
|
2024-09-09 09:49:46 -04:00
|
|
|
faces.take_front(split),
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes);
|
2024-09-05 16:21:43 +02:00
|
|
|
build_nodes_recursive_mesh(material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
leaf_limit,
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_ + 1,
|
2024-09-04 15:23:22 -04:00
|
|
|
std::nullopt,
|
2024-09-08 15:52:56 -04:00
|
|
|
face_centers,
|
2024-09-09 09:56:13 -04:00
|
|
|
depth + 1,
|
2024-09-09 09:49:46 -04:00
|
|
|
faces.drop_front(split),
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes);
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-05 16:21:43 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
Tree Tree::from_mesh(const Mesh &mesh)
|
2023-04-08 13:29:37 +02:00
|
|
|
{
|
2024-09-04 15:55:18 -04:00
|
|
|
#ifdef DEBUG_BUILD_TIME
|
2024-09-04 13:26:16 -04:00
|
|
|
SCOPED_TIMER_AVERAGED(__func__);
|
2024-09-04 15:55:18 -04:00
|
|
|
#endif
|
2024-09-19 15:14:35 -04:00
|
|
|
Tree pbvh(Type::Mesh);
|
2024-08-30 22:57:07 -04:00
|
|
|
const Span<float3> vert_positions = mesh.vert_positions();
|
2024-09-05 16:21:43 +02:00
|
|
|
const OffsetIndices<int> faces = mesh.faces();
|
2024-08-30 22:57:07 -04:00
|
|
|
const Span<int> corner_verts = mesh.corner_verts();
|
2024-09-05 16:21:43 +02:00
|
|
|
if (faces.is_empty()) {
|
2024-08-20 14:02:50 -04:00
|
|
|
return pbvh;
|
|
|
|
|
}
|
2023-04-08 13:29:37 +02:00
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
constexpr int leaf_limit = 10000;
|
|
|
|
|
static_assert(leaf_limit < std::numeric_limits<MeshNode::LocalVertMapIndexT>::max());
|
2022-11-30 13:16:17 -08:00
|
|
|
|
2024-09-08 15:52:56 -04:00
|
|
|
Array<float3> face_centers(faces.size());
|
2024-09-04 15:23:22 -04:00
|
|
|
const Bounds<float3> bounds = threading::parallel_reduce(
|
2024-09-05 16:21:43 +02:00
|
|
|
faces.index_range(),
|
2023-07-27 17:13:19 -04:00
|
|
|
1024,
|
2023-12-04 11:25:07 -05:00
|
|
|
negative_bounds(),
|
|
|
|
|
[&](const IndexRange range, const Bounds<float3> &init) {
|
|
|
|
|
Bounds<float3> current = init;
|
2024-09-10 22:46:04 +02:00
|
|
|
for (const int face : range) {
|
2024-09-08 15:52:56 -04:00
|
|
|
const Bounds<float3> bounds = calc_face_bounds(vert_positions,
|
2024-09-10 22:46:04 +02:00
|
|
|
corner_verts.slice(faces[face]));
|
|
|
|
|
face_centers[face] = bounds.center();
|
2024-09-08 15:52:56 -04:00
|
|
|
current = bounds::merge(current, bounds);
|
2023-07-28 09:33:42 +10:00
|
|
|
}
|
2023-07-27 17:13:19 -04:00
|
|
|
return current;
|
|
|
|
|
},
|
2024-09-04 15:23:22 -04:00
|
|
|
merge_bounds);
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-08-30 22:57:07 -04:00
|
|
|
const AttributeAccessor attributes = mesh.attributes();
|
2024-08-20 14:02:50 -04:00
|
|
|
const VArraySpan hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
|
|
|
|
|
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
|
|
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
pbvh.prim_indices_.reinitialize(faces.size());
|
|
|
|
|
array_utils::fill_index_range<int>(pbvh.prim_indices_);
|
2024-08-20 14:02:50 -04:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
Vector<MeshNode> &nodes = std::get<Vector<MeshNode>>(pbvh.nodes_);
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes.resize(1);
|
2024-09-04 15:55:18 -04:00
|
|
|
{
|
|
|
|
|
#ifdef DEBUG_BUILD_TIME
|
|
|
|
|
SCOPED_TIMER_AVERAGED("build_nodes_recursive_mesh");
|
|
|
|
|
#endif
|
2024-09-09 09:49:46 -04:00
|
|
|
build_nodes_recursive_mesh(
|
2024-09-19 15:14:35 -04:00
|
|
|
material_index, leaf_limit, 0, bounds, face_centers, 0, pbvh.prim_indices_, nodes);
|
2024-09-04 15:55:18 -04:00
|
|
|
}
|
2024-08-20 14:02:50 -04:00
|
|
|
|
2024-09-05 16:21:43 +02:00
|
|
|
build_mesh_leaf_nodes(mesh.verts_num, faces, corner_verts, nodes);
|
2024-09-04 15:49:05 -04:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
pbvh.tag_positions_changed(nodes.index_range());
|
2024-09-13 21:31:08 +02:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
update_bounds_mesh(vert_positions, pbvh);
|
|
|
|
|
store_bounds_orig(pbvh);
|
2024-08-20 14:02:50 -04:00
|
|
|
|
|
|
|
|
if (!hide_vert.is_empty()) {
|
2024-08-28 16:21:22 -04:00
|
|
|
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
|
2024-08-20 14:02:50 -04:00
|
|
|
for (const int i : range) {
|
2024-09-13 23:08:26 -04:00
|
|
|
node_update_visibility_mesh(hide_vert, nodes[i]);
|
2024-08-20 14:02:50 -04:00
|
|
|
}
|
|
|
|
|
});
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
update_mask_mesh(mesh, nodes.index_range(), pbvh);
|
2024-09-13 17:29:25 -04:00
|
|
|
|
2024-04-29 13:10:15 -04:00
|
|
|
return pbvh;
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
static void build_nodes_recursive_grids(const Span<int> material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
const int leaf_limit,
|
|
|
|
|
const int node_index,
|
2024-09-04 15:23:22 -04:00
|
|
|
const std::optional<Bounds<float3>> &bounds_precalc,
|
2024-09-10 22:46:04 +02:00
|
|
|
const Span<float3> face_centers,
|
2024-08-20 14:01:27 -04:00
|
|
|
const int depth,
|
2024-09-10 22:46:04 +02:00
|
|
|
MutableSpan<int> faces,
|
2024-08-28 15:18:21 +02:00
|
|
|
Vector<GridsNode> &nodes)
|
2024-07-23 23:36:30 -04:00
|
|
|
{
|
|
|
|
|
/* Decide whether this is a leaf or not */
|
2024-09-10 22:46:04 +02:00
|
|
|
const bool below_leaf_limit = faces.size() <= leaf_limit || depth >= STACK_FIXED_DEPTH - 1;
|
2024-07-23 23:36:30 -04:00
|
|
|
if (below_leaf_limit) {
|
2024-09-10 22:46:04 +02:00
|
|
|
if (!leaf_needs_material_split(faces, material_indices)) {
|
2024-08-28 15:18:21 +02:00
|
|
|
GridsNode &node = nodes[node_index];
|
2024-07-23 23:36:30 -04:00
|
|
|
node.flag_ |= PBVH_Leaf;
|
2024-09-10 22:46:04 +02:00
|
|
|
node.prim_indices_ = faces;
|
2024-07-23 23:36:30 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Add two child nodes */
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_ = nodes.size();
|
|
|
|
|
nodes.resize(nodes.size() + 2);
|
2024-07-23 23:36:30 -04:00
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
int split;
|
2024-07-23 23:36:30 -04:00
|
|
|
if (!below_leaf_limit) {
|
2024-09-04 15:23:22 -04:00
|
|
|
Bounds<float3> bounds;
|
|
|
|
|
if (bounds_precalc) {
|
|
|
|
|
bounds = *bounds_precalc;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
bounds = threading::parallel_reduce(
|
2024-09-10 22:46:04 +02:00
|
|
|
faces.index_range(),
|
2024-09-04 15:23:22 -04:00
|
|
|
1024,
|
|
|
|
|
negative_bounds(),
|
|
|
|
|
[&](const IndexRange range, Bounds<float3> value) {
|
2024-09-10 22:46:04 +02:00
|
|
|
for (const int face : faces.slice(range)) {
|
|
|
|
|
math::min_max(face_centers[face], value.min, value.max);
|
2024-09-04 15:23:22 -04:00
|
|
|
}
|
|
|
|
|
return value;
|
|
|
|
|
},
|
|
|
|
|
merge_bounds);
|
2024-07-23 23:36:30 -04:00
|
|
|
}
|
2024-09-04 15:23:22 -04:00
|
|
|
const int axis = math::dominant_axis(bounds.max - bounds.min);
|
2024-07-23 23:36:30 -04:00
|
|
|
|
|
|
|
|
/* Partition primitives along that axis */
|
2024-09-10 22:46:04 +02:00
|
|
|
split = partition_along_axis(
|
|
|
|
|
face_centers, faces, axis, math::midpoint(bounds.min[axis], bounds.max[axis]));
|
2024-07-23 23:36:30 -04:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* Partition primitives by material */
|
2024-09-10 22:46:04 +02:00
|
|
|
split = partition_material_indices(material_indices, faces);
|
2024-07-23 23:36:30 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Build children */
|
2024-09-10 22:46:04 +02:00
|
|
|
build_nodes_recursive_grids(material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
leaf_limit,
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_,
|
2024-09-04 15:23:22 -04:00
|
|
|
std::nullopt,
|
2024-09-10 22:46:04 +02:00
|
|
|
face_centers,
|
2024-08-20 14:01:27 -04:00
|
|
|
depth + 1,
|
2024-09-10 22:46:04 +02:00
|
|
|
faces.take_front(split),
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes);
|
2024-09-10 22:46:04 +02:00
|
|
|
build_nodes_recursive_grids(material_indices,
|
2024-07-23 23:36:30 -04:00
|
|
|
leaf_limit,
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes[node_index].children_offset_ + 1,
|
2024-09-04 15:23:22 -04:00
|
|
|
std::nullopt,
|
2024-09-10 22:46:04 +02:00
|
|
|
face_centers,
|
2024-08-20 14:01:27 -04:00
|
|
|
depth + 1,
|
2024-09-10 22:46:04 +02:00
|
|
|
faces.drop_front(split),
|
2024-08-20 14:01:27 -04:00
|
|
|
nodes);
|
2024-07-23 23:36:30 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-11 15:54:46 +02:00
|
|
|
static Bounds<float3> calc_face_grid_bounds(const OffsetIndices<int> faces,
|
|
|
|
|
const Span<float3> positions,
|
|
|
|
|
const CCGKey &key,
|
|
|
|
|
const int face)
|
2024-09-10 22:46:04 +02:00
|
|
|
{
|
|
|
|
|
Bounds<float3> bounds = negative_bounds();
|
2024-09-11 15:54:46 +02:00
|
|
|
for (const float3 &position : positions.slice(ccg::face_range(faces, key, face))) {
|
|
|
|
|
math::min_max(position, bounds.min, bounds.max);
|
2024-09-10 22:46:04 +02:00
|
|
|
}
|
|
|
|
|
return bounds;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
Tree Tree::from_grids(const Mesh &base_mesh, const SubdivCCG &subdiv_ccg)
|
2009-11-25 13:40:43 +00:00
|
|
|
{
|
2024-09-06 12:12:49 -04:00
|
|
|
#ifdef DEBUG_BUILD_TIME
|
|
|
|
|
SCOPED_TIMER_AVERAGED(__func__);
|
|
|
|
|
#endif
|
2024-09-19 15:14:35 -04:00
|
|
|
Tree pbvh(Type::Grids);
|
2024-08-30 22:57:07 -04:00
|
|
|
const OffsetIndices faces = base_mesh.faces();
|
2024-09-10 22:46:04 +02:00
|
|
|
if (faces.is_empty()) {
|
|
|
|
|
return pbvh;
|
|
|
|
|
}
|
2022-11-21 16:57:46 +01:00
|
|
|
|
2024-08-30 22:57:07 -04:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> positions = subdiv_ccg.positions;
|
|
|
|
|
if (positions.is_empty()) {
|
|
|
|
|
return pbvh;
|
|
|
|
|
}
|
2023-12-14 18:20:46 -05:00
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
const int leaf_limit = std::max(2500 / key.grid_area, 1);
|
2009-11-25 13:40:43 +00:00
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
Array<float3> face_centers(faces.size());
|
2024-09-04 15:23:22 -04:00
|
|
|
const Bounds<float3> bounds = threading::parallel_reduce(
|
2024-09-10 22:46:04 +02:00
|
|
|
faces.index_range(),
|
|
|
|
|
leaf_limit,
|
2023-12-04 11:25:07 -05:00
|
|
|
negative_bounds(),
|
|
|
|
|
[&](const IndexRange range, const Bounds<float3> &init) {
|
|
|
|
|
Bounds<float3> current = init;
|
2024-09-10 22:46:04 +02:00
|
|
|
for (const int face : range) {
|
2024-09-11 15:54:46 +02:00
|
|
|
const Bounds<float3> bounds = calc_face_grid_bounds(faces, positions, key, face);
|
2024-09-10 22:46:04 +02:00
|
|
|
face_centers[face] = bounds.center();
|
|
|
|
|
current = bounds::merge(current, bounds);
|
2023-07-27 23:45:58 -04:00
|
|
|
}
|
2023-07-27 23:37:41 -04:00
|
|
|
return current;
|
|
|
|
|
},
|
2024-09-04 15:23:22 -04:00
|
|
|
merge_bounds);
|
2009-11-25 13:40:43 +00:00
|
|
|
|
2024-08-30 22:57:07 -04:00
|
|
|
const AttributeAccessor attributes = base_mesh.attributes();
|
2024-08-20 14:02:50 -04:00
|
|
|
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
|
|
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
Array<int> face_indices(faces.size());
|
|
|
|
|
array_utils::fill_index_range<int>(face_indices);
|
2024-08-20 14:02:50 -04:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
Vector<GridsNode> &nodes = std::get<Vector<GridsNode>>(pbvh.nodes_);
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes.resize(1);
|
2024-09-06 12:12:49 -04:00
|
|
|
{
|
|
|
|
|
#ifdef DEBUG_BUILD_TIME
|
|
|
|
|
SCOPED_TIMER_AVERAGED("build_nodes_recursive_grids");
|
|
|
|
|
#endif
|
2024-09-10 22:46:04 +02:00
|
|
|
build_nodes_recursive_grids(
|
|
|
|
|
material_index, leaf_limit, 0, bounds, face_centers, 0, face_indices, nodes);
|
2024-09-06 12:12:49 -04:00
|
|
|
}
|
2024-08-20 14:02:50 -04:00
|
|
|
|
2024-09-10 22:46:04 +02:00
|
|
|
/* Convert face indices into grid indices. */
|
2024-09-19 15:14:35 -04:00
|
|
|
pbvh.prim_indices_.reinitialize(faces.total_size());
|
2024-09-10 22:46:04 +02:00
|
|
|
{
|
|
|
|
|
int offset = 0;
|
|
|
|
|
for (const int face : face_indices) {
|
|
|
|
|
for (const int corner : faces[face]) {
|
2024-09-19 15:14:35 -04:00
|
|
|
pbvh.prim_indices_[offset] = corner;
|
2024-09-10 22:46:04 +02:00
|
|
|
offset++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Change the nodes to reference the BVH prim_indices array instead of the local face indices. */
|
|
|
|
|
Array<int> node_grids_num(nodes.size() + 1);
|
|
|
|
|
threading::parallel_for(nodes.index_range(), 16, [&](const IndexRange range) {
|
|
|
|
|
for (const int i : range) {
|
2024-09-12 20:28:35 +02:00
|
|
|
node_grids_num[i] = offset_indices::sum_group_sizes(faces, nodes[i].prim_indices_);
|
2024-09-10 22:46:04 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
const OffsetIndices<int> node_grid_offsets = offset_indices::accumulate_counts_to_offsets(
|
|
|
|
|
node_grids_num);
|
|
|
|
|
|
|
|
|
|
threading::parallel_for(nodes.index_range(), 512, [&](const IndexRange range) {
|
|
|
|
|
for (const int i : range) {
|
2024-09-19 15:14:35 -04:00
|
|
|
nodes[i].prim_indices_ = pbvh.prim_indices_.as_span().slice(node_grid_offsets[i]);
|
2024-09-10 22:46:04 +02:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
pbvh.tag_positions_changed(nodes.index_range());
|
2024-09-13 21:31:08 +02:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
update_bounds_grids(key, positions, pbvh);
|
|
|
|
|
store_bounds_orig(pbvh);
|
2024-08-20 14:02:50 -04:00
|
|
|
|
2024-08-30 22:57:07 -04:00
|
|
|
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
2024-08-20 14:02:50 -04:00
|
|
|
if (!grid_hidden.is_empty()) {
|
2024-08-28 16:21:22 -04:00
|
|
|
threading::parallel_for(nodes.index_range(), 8, [&](const IndexRange range) {
|
2024-08-20 14:02:50 -04:00
|
|
|
for (const int i : range) {
|
2024-09-13 23:08:26 -04:00
|
|
|
node_update_visibility_grids(grid_hidden, nodes[i]);
|
2024-08-20 14:02:50 -04:00
|
|
|
}
|
|
|
|
|
});
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-11-25 13:40:43 +00:00
|
|
|
|
2024-09-19 15:14:35 -04:00
|
|
|
update_mask_grids(subdiv_ccg, nodes.index_range(), pbvh);
|
2024-09-13 17:29:25 -04:00
|
|
|
|
2024-04-29 13:10:15 -04:00
|
|
|
return pbvh;
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
Tree::Tree(const Type type) : type_(type)
|
|
|
|
|
{
|
|
|
|
|
switch (type) {
|
|
|
|
|
case bke::pbvh::Type::Mesh:
|
|
|
|
|
nodes_ = Vector<MeshNode>();
|
|
|
|
|
break;
|
|
|
|
|
case bke::pbvh::Type::Grids:
|
|
|
|
|
nodes_ = Vector<GridsNode>();
|
|
|
|
|
break;
|
|
|
|
|
case bke::pbvh::Type::BMesh:
|
|
|
|
|
nodes_ = Vector<BMeshNode>();
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
Sculpt: Restructure PBVH drawing to avoid overhead
This commit rewrites the PBVH drawing using many of the principles from the
ongoing sculpt refactor. First of all, per BVH node overhead is minimized.
Previously the main entry point to the drawing API was per node, so there
was significant overhead fetching global data and maintaining caches on
a per-node basis. Now all of that "global" work happens for the entire
geometry.
We also now avoid creating wireframe index buffers and batches unless
the viewport actually requests wireframe data. This was theoretically
possible before, but the whole logic flow was so convoluted that the
optimization was too difficult. Similarly, multithreading is used more
consistently now. Because of OpenGL, flushing vertex/index buffers to
the GPU has to happen on the main thread, but everything else can be
multithreaded. With outer loops processing all relevant PBVH nodes,
it's now trivial to apply multithreading wherever possible.
Testing performance, overall this commit results in a 10% improvement in
the time between opening a file with a large mesh sculpt and the first
possible interaction. Specifically I measured a change from 8.4 to 7.6
seconds on a completely visible 16 million vertex mesh with a Ryzen 7950x.
I also measured a decrease in memory usage from 4.79 to 4.31 GB.
For multires I observed a similar improvement in memory usage,
though less of a performance improvement.
There are still significant opportunities for future improvement. #122775
would be particularly helpful. #99983 would be helpful too, though more
complicated, and #97665 describes the problems a bit more generally.
Part of #118145.
Pull Request: https://projects.blender.org/blender/blender/pulls/127002
2024-09-04 17:40:50 +02:00
|
|
|
int Tree::nodes_num() const
|
|
|
|
|
{
|
|
|
|
|
return std::visit([](const auto &nodes) { return nodes.size(); }, this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
template<> Span<MeshNode> Tree::nodes() const
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<MeshNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
template<> Span<GridsNode> Tree::nodes() const
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<GridsNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
template<> Span<BMeshNode> Tree::nodes() const
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<BMeshNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
template<> MutableSpan<MeshNode> Tree::nodes()
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<MeshNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
template<> MutableSpan<GridsNode> Tree::nodes()
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<GridsNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
template<> MutableSpan<BMeshNode> Tree::nodes()
|
|
|
|
|
{
|
|
|
|
|
return std::get<Vector<BMeshNode>>(this->nodes_);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
Tree::~Tree()
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[](auto &nodes) {
|
|
|
|
|
for (Node &node : nodes) {
|
|
|
|
|
if (node.flag_ & (PBVH_Leaf | PBVH_TexLeaf)) {
|
|
|
|
|
node_pixels_free(&node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
this->nodes_);
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
pixels_free(this);
|
2024-04-29 13:10:15 -04:00
|
|
|
}
|
2022-11-28 08:31:24 +01:00
|
|
|
|
2024-09-13 21:31:08 +02:00
|
|
|
void Tree::tag_positions_changed(const IndexMask &node_mask)
|
|
|
|
|
{
|
|
|
|
|
this->bounds_dirty_.resize(std::max(this->bounds_dirty_.size(), node_mask.min_array_size()),
|
|
|
|
|
false);
|
2024-09-13 16:03:33 -04:00
|
|
|
this->normals_dirty_.resize(std::max(this->normals_dirty_.size(), node_mask.min_array_size()),
|
|
|
|
|
false);
|
2024-09-14 21:09:41 +02:00
|
|
|
node_mask.set_bits(this->bounds_dirty_);
|
|
|
|
|
node_mask.set_bits(this->normals_dirty_);
|
2024-09-13 16:16:39 -04:00
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_positions_changed(node_mask);
|
|
|
|
|
}
|
2024-09-13 21:31:08 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-13 23:07:00 -04:00
|
|
|
void Tree::tag_visibility_changed(const IndexMask &node_mask)
|
|
|
|
|
{
|
|
|
|
|
this->visibility_dirty_.resize(std::max(this->bounds_dirty_.size(), node_mask.min_array_size()),
|
|
|
|
|
false);
|
2024-09-19 15:16:58 -04:00
|
|
|
node_mask.set_bits(this->visibility_dirty_);
|
2024-09-13 23:07:00 -04:00
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_visibility_changed(node_mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Tree::tag_topology_changed(const IndexMask &node_mask)
|
|
|
|
|
{
|
|
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_topology_changed(node_mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 16:36:05 -04:00
|
|
|
void Tree::tag_face_sets_changed(const IndexMask &node_mask)
|
|
|
|
|
{
|
|
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_face_sets_changed(node_mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 22:25:27 -04:00
|
|
|
void Tree::tag_masks_changed(const IndexMask &node_mask)
|
|
|
|
|
{
|
|
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_masks_changed(node_mask);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 16:55:53 -04:00
|
|
|
void Tree::tag_attribute_changed(const IndexMask &node_mask, const StringRef attribute_name)
|
|
|
|
|
{
|
|
|
|
|
if (this->draw_data) {
|
|
|
|
|
this->draw_data->tag_attribute_changed(node_mask, attribute_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
static bool tree_is_empty(const Tree &pbvh)
|
|
|
|
|
{
|
|
|
|
|
return std::visit([](const auto &nodes) { return nodes.is_empty(); }, pbvh.nodes_);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static Node &first_node(Tree &pbvh)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(!tree_is_empty(pbvh));
|
|
|
|
|
return std::visit([](auto &nodes) -> Node & { return nodes.first(); }, pbvh.nodes_);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-19 17:32:39 -04:00
|
|
|
struct StackItem {
|
2024-08-19 17:22:41 -04:00
|
|
|
Node *node;
|
|
|
|
|
bool revisiting;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct PBVHIter {
|
|
|
|
|
Tree *pbvh;
|
|
|
|
|
blender::FunctionRef<bool(Node &)> scb;
|
|
|
|
|
|
2024-08-19 17:32:39 -04:00
|
|
|
Stack<StackItem, 100> stack;
|
2024-08-19 17:22:41 -04:00
|
|
|
};
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static void pbvh_iter_begin(PBVHIter *iter, Tree &pbvh, FunctionRef<bool(Node &)> scb)
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
{
|
2024-04-29 12:23:35 -04:00
|
|
|
iter->pbvh = &pbvh;
|
2012-05-11 08:05:47 +00:00
|
|
|
iter->scb = scb;
|
2024-08-28 15:18:21 +02:00
|
|
|
iter->stack.push({&first_node(pbvh), false});
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static Node *pbvh_iter_next(PBVHIter *iter, PBVHNodeFlags leaf_flag)
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
/* purpose here is to traverse tree, visiting child nodes before their
|
2012-03-03 20:19:11 +00:00
|
|
|
* parents, this order is necessary for e.g. computing bounding boxes */
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2024-08-19 17:32:39 -04:00
|
|
|
while (!iter->stack.is_empty()) {
|
|
|
|
|
StackItem item = iter->stack.pop();
|
|
|
|
|
Node *node = item.node;
|
|
|
|
|
bool revisiting = item.revisiting;
|
2010-01-10 10:20:44 +00:00
|
|
|
|
2010-01-10 10:50:11 +00:00
|
|
|
/* on a mesh with no faces this can happen
|
|
|
|
|
* can remove this check if we know meshes have at least 1 face */
|
2023-02-05 16:56:37 -05:00
|
|
|
if (node == nullptr) {
|
|
|
|
|
return nullptr;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-01-10 10:20:44 +00:00
|
|
|
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
/* revisiting node already checked */
|
2019-04-22 09:39:35 +10:00
|
|
|
if (revisiting) {
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
return node;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2023-08-22 15:05:37 -04:00
|
|
|
if (iter->scb && !iter->scb(*node)) {
|
2012-05-11 08:05:47 +00:00
|
|
|
continue; /* don't traverse, outside of search zone */
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node->flag_ & leaf_flag) {
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
/* immediately hit leaf node */
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
2020-08-07 12:30:43 +02:00
|
|
|
/* come back later when children are done */
|
2024-08-19 17:32:39 -04:00
|
|
|
iter->stack.push({node, true});
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
/* push two child nodes on the stack */
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[&](auto &nodes) {
|
|
|
|
|
iter->stack.push({&nodes[node->children_offset_ + 1], false});
|
|
|
|
|
iter->stack.push({&nodes[node->children_offset_], false});
|
|
|
|
|
},
|
|
|
|
|
iter->pbvh->nodes_);
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
return nullptr;
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static Node *pbvh_iter_next_occluded(PBVHIter *iter)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2024-08-19 17:32:39 -04:00
|
|
|
while (!iter->stack.is_empty()) {
|
|
|
|
|
StackItem item = iter->stack.pop();
|
|
|
|
|
Node *node = item.node;
|
2011-04-21 13:11:51 +00:00
|
|
|
|
|
|
|
|
/* on a mesh with no faces this can happen
|
|
|
|
|
* can remove this check if we know meshes have at least 1 face */
|
2023-02-05 16:56:37 -05:00
|
|
|
if (node == nullptr) {
|
|
|
|
|
return nullptr;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2011-04-21 13:11:51 +00:00
|
|
|
|
2023-08-22 15:05:37 -04:00
|
|
|
if (iter->scb && !iter->scb(*node)) {
|
2012-05-11 08:05:47 +00:00
|
|
|
continue; /* don't traverse, outside of search zone */
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2011-04-21 13:11:51 +00:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node->flag_ & PBVH_Leaf) {
|
2011-04-21 13:11:51 +00:00
|
|
|
/* immediately hit leaf node */
|
|
|
|
|
return node;
|
|
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[&](auto &nodes) {
|
|
|
|
|
iter->stack.push({&nodes[node->children_offset_ + 1], false});
|
|
|
|
|
iter->stack.push({&nodes[node->children_offset_], false});
|
|
|
|
|
},
|
|
|
|
|
iter->pbvh->nodes_);
|
2011-04-21 13:11:51 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
return nullptr;
|
2010-07-14 14:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
struct node_tree {
|
2024-07-23 22:31:27 +02:00
|
|
|
Node *data;
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
node_tree *left;
|
|
|
|
|
node_tree *right;
|
|
|
|
|
};
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2012-05-11 08:05:47 +00:00
|
|
|
static void node_tree_insert(node_tree *tree, node_tree *new_node)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
if (new_node->data->tmin_ < tree->data->tmin_) {
|
2011-04-21 13:11:51 +00:00
|
|
|
if (tree->left) {
|
|
|
|
|
node_tree_insert(tree->left, new_node);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tree->left = new_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (tree->right) {
|
|
|
|
|
node_tree_insert(tree->right, new_node);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tree->right = new_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
2012-12-30 18:31:31 +00:00
|
|
|
static void traverse_tree(node_tree *tree,
|
2024-07-23 22:31:27 +02:00
|
|
|
const FunctionRef<void(Node &node, float *tmin)> hit_fn,
|
2012-12-30 18:31:31 +00:00
|
|
|
float *tmin)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2019-04-22 09:39:35 +10:00
|
|
|
if (tree->left) {
|
2023-12-16 10:57:42 -05:00
|
|
|
traverse_tree(tree->left, hit_fn, tmin);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2023-12-16 10:57:42 -05:00
|
|
|
hit_fn(*tree->data, tmin);
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (tree->right) {
|
2023-12-16 10:57:42 -05:00
|
|
|
traverse_tree(tree->right, hit_fn, tmin);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
2012-05-11 08:05:47 +00:00
|
|
|
static void free_tree(node_tree *tree)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2011-04-21 13:11:51 +00:00
|
|
|
if (tree->left) {
|
|
|
|
|
free_tree(tree->left);
|
2023-02-05 16:56:37 -05:00
|
|
|
tree->left = nullptr;
|
2011-04-21 13:11:51 +00:00
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2011-04-21 13:11:51 +00:00
|
|
|
if (tree->right) {
|
|
|
|
|
free_tree(tree->right);
|
2023-02-05 16:56:37 -05:00
|
|
|
tree->right = nullptr;
|
2011-04-21 13:11:51 +00:00
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2023-12-16 10:57:42 -05:00
|
|
|
::free(tree);
|
2010-07-14 14:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-16 10:57:42 -05:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
float BKE_pbvh_node_get_tmin(const blender::bke::pbvh::Node *node)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return node->tmin_;
|
2010-07-14 14:11:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static void search_callback_occluded(Tree &pbvh,
|
|
|
|
|
const FunctionRef<bool(Node &)> scb,
|
|
|
|
|
const FunctionRef<void(Node &node, float *tmin)> hit_fn)
|
2010-07-14 14:11:03 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
if (tree_is_empty(pbvh)) {
|
2023-08-22 12:29:36 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2010-07-14 14:11:03 +00:00
|
|
|
PBVHIter iter;
|
2024-07-23 22:31:27 +02:00
|
|
|
Node *node;
|
2023-02-05 16:56:37 -05:00
|
|
|
node_tree *tree = nullptr;
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2023-08-22 15:05:37 -04:00
|
|
|
pbvh_iter_begin(&iter, pbvh, scb);
|
2010-07-14 14:11:03 +00:00
|
|
|
|
2012-05-11 08:05:47 +00:00
|
|
|
while ((node = pbvh_iter_next_occluded(&iter))) {
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node->flag_ & PBVH_Leaf) {
|
2023-02-05 16:56:37 -05:00
|
|
|
node_tree *new_node = static_cast<node_tree *>(malloc(sizeof(node_tree)));
|
2010-07-14 14:11:03 +00:00
|
|
|
|
|
|
|
|
new_node->data = node;
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
new_node->left = nullptr;
|
|
|
|
|
new_node->right = nullptr;
|
2010-07-14 14:11:03 +00:00
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
node_tree_insert(tree, new_node);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
tree = new_node;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (tree) {
|
|
|
|
|
float tmin = FLT_MAX;
|
2023-12-16 10:57:42 -05:00
|
|
|
traverse_tree(tree, hit_fn, &tmin);
|
2010-07-14 14:11:03 +00:00
|
|
|
free_tree(tree);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
/**
|
|
|
|
|
* Logic used to test whether to use the evaluated mesh for positions.
|
|
|
|
|
* \todo A deeper test of equality of topology array pointers would be better. This is kept for now
|
|
|
|
|
* to avoid changing logic during a refactor.
|
|
|
|
|
*/
|
|
|
|
|
static bool mesh_topology_count_matches(const Mesh &a, const Mesh &b)
|
|
|
|
|
{
|
|
|
|
|
return a.faces_num == b.faces_num && a.corners_num == b.corners_num &&
|
|
|
|
|
a.verts_num == b.verts_num;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const SharedCache<Vector<float3>> &vert_normals_cache_eval(const Object &object_orig,
|
|
|
|
|
const Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
const SculptSession &ss = *object_orig.sculpt;
|
|
|
|
|
const Mesh &mesh_orig = *static_cast<const Mesh *>(object_orig.data);
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(bke::object::pbvh_get(object_orig)->type() == Type::Mesh);
|
2024-08-22 21:00:25 +02:00
|
|
|
if (object_orig.mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(&object_eval)) {
|
|
|
|
|
if (mesh_topology_count_matches(*mesh_eval, mesh_orig)) {
|
|
|
|
|
return mesh_eval->runtime->vert_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(&object_eval)) {
|
|
|
|
|
return mesh_eval->runtime->vert_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ss.deform_cos.is_empty()) {
|
|
|
|
|
BLI_assert(ss.deform_cos.size() == mesh_orig.verts_num);
|
|
|
|
|
return ss.vert_normals_deform;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mesh_orig.runtime->vert_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
static SharedCache<Vector<float3>> &vert_normals_cache_eval_for_write(Object &object_orig,
|
|
|
|
|
Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
return const_cast<SharedCache<Vector<float3>> &>(
|
|
|
|
|
vert_normals_cache_eval(object_orig, object_eval));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const SharedCache<Vector<float3>> &face_normals_cache_eval(const Object &object_orig,
|
|
|
|
|
const Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
const SculptSession &ss = *object_orig.sculpt;
|
|
|
|
|
const Mesh &mesh_orig = *static_cast<const Mesh *>(object_orig.data);
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(bke::object::pbvh_get(object_orig)->type() == Type::Mesh);
|
2024-08-22 21:00:25 +02:00
|
|
|
if (object_orig.mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(&object_eval)) {
|
|
|
|
|
if (mesh_topology_count_matches(*mesh_eval, mesh_orig)) {
|
|
|
|
|
return mesh_eval->runtime->face_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(&object_eval)) {
|
|
|
|
|
return mesh_eval->runtime->face_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ss.deform_cos.is_empty()) {
|
|
|
|
|
BLI_assert(ss.deform_cos.size() == mesh_orig.verts_num);
|
|
|
|
|
return ss.face_normals_deform;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mesh_orig.runtime->face_normals_cache;
|
|
|
|
|
}
|
|
|
|
|
static SharedCache<Vector<float3>> &face_normals_cache_eval_for_write(Object &object_orig,
|
|
|
|
|
Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
return const_cast<SharedCache<Vector<float3>> &>(
|
|
|
|
|
face_normals_cache_eval(object_orig, object_eval));
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-24 18:56:15 +02:00
|
|
|
static void normals_calc_faces(const Span<float3> positions,
|
2024-01-08 18:49:26 +01:00
|
|
|
const OffsetIndices<int> faces,
|
2023-10-24 18:56:15 +02:00
|
|
|
const Span<int> corner_verts,
|
2024-01-08 18:49:26 +01:00
|
|
|
const Span<int> face_indices,
|
2023-10-24 18:56:15 +02:00
|
|
|
MutableSpan<float3> face_normals)
|
|
|
|
|
{
|
2024-01-08 18:49:26 +01:00
|
|
|
for (const int i : face_indices) {
|
|
|
|
|
face_normals[i] = mesh::face_normal_calc(positions, corner_verts.slice(faces[i]));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void calc_boundary_face_normals(const Span<float3> positions,
|
|
|
|
|
const OffsetIndices<int> faces,
|
|
|
|
|
const Span<int> corner_verts,
|
|
|
|
|
const Span<int> face_indices,
|
|
|
|
|
MutableSpan<float3> face_normals)
|
|
|
|
|
{
|
|
|
|
|
threading::parallel_for(face_indices.index_range(), 512, [&](const IndexRange range) {
|
|
|
|
|
normals_calc_faces(positions, faces, corner_verts, face_indices.slice(range), face_normals);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void calc_node_face_normals(const Span<float3> positions,
|
|
|
|
|
const OffsetIndices<int> faces,
|
|
|
|
|
const Span<int> corner_verts,
|
2024-08-28 15:18:21 +02:00
|
|
|
const Span<MeshNode> nodes,
|
|
|
|
|
const IndexMask &nodes_to_update,
|
2024-01-08 18:49:26 +01:00
|
|
|
MutableSpan<float3> face_normals)
|
|
|
|
|
{
|
2024-09-05 16:21:43 +02:00
|
|
|
nodes_to_update.foreach_index(GrainSize(1), [&](const int i) {
|
2024-09-05 20:07:03 +02:00
|
|
|
normals_calc_faces(positions, faces, corner_verts, nodes[i].faces(), face_normals);
|
2023-10-24 18:56:15 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-08 18:49:26 +01:00
|
|
|
static void normals_calc_verts_simple(const GroupedSpan<int> vert_to_face_map,
|
2023-10-24 18:56:15 +02:00
|
|
|
const Span<float3> face_normals,
|
2024-01-08 18:49:26 +01:00
|
|
|
const Span<int> verts,
|
2023-10-24 18:56:15 +02:00
|
|
|
MutableSpan<float3> vert_normals)
|
|
|
|
|
{
|
2024-01-08 18:49:26 +01:00
|
|
|
for (const int vert : verts) {
|
|
|
|
|
float3 normal(0.0f);
|
|
|
|
|
for (const int face : vert_to_face_map[vert]) {
|
|
|
|
|
normal += face_normals[face];
|
2023-10-24 18:56:15 +02:00
|
|
|
}
|
2024-01-08 18:49:26 +01:00
|
|
|
vert_normals[vert] = math::normalize(normal);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void calc_boundary_vert_normals(const GroupedSpan<int> vert_to_face_map,
|
|
|
|
|
const Span<float3> face_normals,
|
|
|
|
|
const Span<int> verts,
|
|
|
|
|
MutableSpan<float3> vert_normals)
|
|
|
|
|
{
|
|
|
|
|
threading::parallel_for(verts.index_range(), 1024, [&](const IndexRange range) {
|
|
|
|
|
normals_calc_verts_simple(vert_to_face_map, face_normals, verts.slice(range), vert_normals);
|
2023-10-24 18:56:15 +02:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-08 18:49:26 +01:00
|
|
|
static void calc_node_vert_normals(const GroupedSpan<int> vert_to_face_map,
|
|
|
|
|
const Span<float3> face_normals,
|
2024-08-28 15:18:21 +02:00
|
|
|
const Span<MeshNode> nodes,
|
|
|
|
|
const IndexMask &nodes_to_update,
|
2024-01-08 18:49:26 +01:00
|
|
|
MutableSpan<float3> vert_normals)
|
2022-02-01 13:39:48 +11:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes_to_update.foreach_index(GrainSize(1), [&](const int i) {
|
2024-09-05 20:07:03 +02:00
|
|
|
normals_calc_verts_simple(vert_to_face_map, face_normals, nodes[i].verts(), vert_normals);
|
2024-01-08 18:49:26 +01:00
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
static void update_normals_mesh(Object &object_orig,
|
|
|
|
|
Object &object_eval,
|
|
|
|
|
const Span<MeshNode> nodes,
|
|
|
|
|
const IndexMask &nodes_to_update)
|
2024-01-08 18:49:26 +01:00
|
|
|
{
|
|
|
|
|
/* Position changes are tracked on a per-node level, so all the vertex and face normals for every
|
|
|
|
|
* affected node are recalculated. However, the additional complexity comes from the fact that
|
|
|
|
|
* changing vertex normals also changes surrounding face normals. Those changed face normals then
|
|
|
|
|
* change the normals of all connected vertices, which can be in other nodes. So the set of
|
2024-07-23 22:31:27 +02:00
|
|
|
* vertices that need recalculated normals can propagate into unchanged/untagged Tree nodes.
|
2024-01-08 18:49:26 +01:00
|
|
|
*
|
2024-07-23 22:31:27 +02:00
|
|
|
* Currently we have no good way of finding neighboring Tree nodes, so we use the vertex to
|
2024-01-08 18:49:26 +01:00
|
|
|
* face topology map to find the neighboring vertices that need normal recalculation.
|
|
|
|
|
*
|
|
|
|
|
* Those boundary face and vertex indices are deduplicated with #VectorSet in order to avoid
|
|
|
|
|
* duplicate work recalculation for the same vertex, and to make parallel storage for vertices
|
2024-01-11 16:46:46 +11:00
|
|
|
* during recalculation thread-safe. */
|
2024-08-15 15:43:17 -04:00
|
|
|
Mesh &mesh = *static_cast<Mesh *>(object_orig.data);
|
|
|
|
|
const Span<float3> positions = bke::pbvh::vert_positions_eval_from_eval(object_eval);
|
2023-11-30 18:25:12 -05:00
|
|
|
const OffsetIndices faces = mesh.faces();
|
|
|
|
|
const Span<int> corner_verts = mesh.corner_verts();
|
2024-04-29 16:41:59 -04:00
|
|
|
const GroupedSpan<int> vert_to_face_map = mesh.vert_to_face_map();
|
2023-05-09 22:36:30 +02:00
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
SharedCache<Vector<float3>> &vert_normals_cache = vert_normals_cache_eval_for_write(object_orig,
|
|
|
|
|
object_eval);
|
|
|
|
|
SharedCache<Vector<float3>> &face_normals_cache = face_normals_cache_eval_for_write(object_orig,
|
|
|
|
|
object_eval);
|
|
|
|
|
|
2024-01-08 18:49:26 +01:00
|
|
|
VectorSet<int> boundary_faces;
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes_to_update.foreach_index([&](const int i) {
|
|
|
|
|
const MeshNode &node = nodes[i];
|
|
|
|
|
for (const int vert : node.vert_indices_.as_span().drop_front(node.unique_verts_num_)) {
|
2024-04-29 16:41:59 -04:00
|
|
|
boundary_faces.add_multiple(vert_to_face_map[vert]);
|
2022-02-01 13:39:48 +11:00
|
|
|
}
|
2024-08-28 15:18:21 +02:00
|
|
|
});
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-01-08 18:49:26 +01:00
|
|
|
VectorSet<int> boundary_verts;
|
2024-08-22 21:00:25 +02:00
|
|
|
|
2023-05-09 22:36:30 +02:00
|
|
|
threading::parallel_invoke(
|
|
|
|
|
[&]() {
|
2024-08-22 21:00:25 +02:00
|
|
|
if (face_normals_cache.is_dirty()) {
|
|
|
|
|
face_normals_cache.ensure([&](Vector<float3> &r_data) {
|
|
|
|
|
r_data.resize(faces.size());
|
|
|
|
|
bke::mesh::normals_calc_faces(positions, faces, corner_verts, r_data);
|
|
|
|
|
});
|
2023-10-24 18:56:15 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-22 21:00:25 +02:00
|
|
|
face_normals_cache.update([&](Vector<float3> &r_data) {
|
2024-09-05 16:21:43 +02:00
|
|
|
calc_node_face_normals(positions, faces, corner_verts, nodes, nodes_to_update, r_data);
|
2024-01-08 18:49:26 +01:00
|
|
|
calc_boundary_face_normals(positions, faces, corner_verts, boundary_faces, r_data);
|
2023-08-25 23:06:06 +02:00
|
|
|
});
|
2023-10-24 18:56:15 +02:00
|
|
|
}
|
2023-05-09 22:36:30 +02:00
|
|
|
},
|
|
|
|
|
[&]() {
|
2023-05-26 12:39:28 +10:00
|
|
|
/* Update all normals connected to affected faces, even if not explicitly tagged. */
|
2024-01-08 18:49:26 +01:00
|
|
|
boundary_verts.reserve(boundary_faces.size());
|
|
|
|
|
for (const int face : boundary_faces) {
|
|
|
|
|
boundary_verts.add_multiple(corner_verts.slice(faces[face]));
|
2023-05-09 22:36:30 +02:00
|
|
|
}
|
|
|
|
|
});
|
2024-08-22 21:00:25 +02:00
|
|
|
const Span<float3> face_normals = face_normals_cache.data();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
if (vert_normals_cache.is_dirty()) {
|
|
|
|
|
vert_normals_cache.ensure([&](Vector<float3> &r_data) {
|
|
|
|
|
r_data.resize(positions.size());
|
|
|
|
|
mesh::normals_calc_verts(
|
|
|
|
|
positions, faces, corner_verts, vert_to_face_map, face_normals, r_data);
|
|
|
|
|
});
|
2023-10-24 18:56:15 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-22 21:00:25 +02:00
|
|
|
vert_normals_cache.update([&](Vector<float3> &r_data) {
|
2024-08-28 15:18:21 +02:00
|
|
|
calc_node_vert_normals(vert_to_face_map, face_normals, nodes, nodes_to_update, r_data);
|
2024-08-22 21:00:25 +02:00
|
|
|
calc_boundary_vert_normals(vert_to_face_map, face_normals, boundary_verts, r_data);
|
2023-08-25 23:06:06 +02:00
|
|
|
});
|
2023-12-14 14:56:25 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-15 15:43:17 -04:00
|
|
|
static void update_normals(Object &object_orig, Object &object_eval, Tree &pbvh)
|
2023-12-14 14:56:25 -05:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMaskMemory memory;
|
2024-09-13 16:03:33 -04:00
|
|
|
const IndexMask nodes_to_update = IndexMask::from_bits(pbvh.normals_dirty_, memory);
|
2023-12-14 14:56:25 -05:00
|
|
|
|
2024-08-14 23:19:19 -04:00
|
|
|
switch (pbvh.type()) {
|
|
|
|
|
case Type::Mesh: {
|
2024-08-28 15:18:21 +02:00
|
|
|
update_normals_mesh(object_orig, object_eval, pbvh.nodes<MeshNode>(), nodes_to_update);
|
2024-08-14 23:19:19 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Type::Grids: {
|
2024-08-15 15:43:17 -04:00
|
|
|
SculptSession &ss = *object_orig.sculpt;
|
2024-08-14 23:19:19 -04:00
|
|
|
SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
2024-08-28 15:18:21 +02:00
|
|
|
MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
|
2024-08-14 23:19:19 -04:00
|
|
|
IndexMaskMemory memory;
|
2024-08-28 15:18:21 +02:00
|
|
|
const IndexMask faces_to_update = nodes_to_face_selection_grids(
|
|
|
|
|
subdiv_ccg, nodes, nodes_to_update, memory);
|
2024-08-14 23:19:19 -04:00
|
|
|
BKE_subdiv_ccg_update_normals(subdiv_ccg, faces_to_update);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Type::BMesh: {
|
2024-08-28 15:18:21 +02:00
|
|
|
bmesh_normals_update(pbvh, nodes_to_update);
|
2024-08-14 23:19:19 -04:00
|
|
|
break;
|
2023-12-14 14:56:25 -05:00
|
|
|
}
|
2023-10-24 18:56:15 +02:00
|
|
|
}
|
2024-09-13 16:03:33 -04:00
|
|
|
pbvh.normals_dirty_.clear_and_shrink();
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-15 15:43:17 -04:00
|
|
|
void update_normals(const Depsgraph &depsgraph, Object &object_orig, Tree &pbvh)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(DEG_is_original_object(&object_orig));
|
|
|
|
|
Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object_orig);
|
|
|
|
|
update_normals(object_orig, object_eval, pbvh);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void update_normals_from_eval(Object &object_eval, Tree &pbvh)
|
2024-08-14 23:19:19 -04:00
|
|
|
{
|
|
|
|
|
/* Updating the original object's mesh normals caches is necessary because we skip dependency
|
2024-08-16 09:10:04 +10:00
|
|
|
* graph updates for sculpt deformations in some cases (so the evaluated object doesn't contain
|
2024-08-14 23:19:19 -04:00
|
|
|
* their result), and also because (currently) sculpt deformations skip tagging the mesh normals
|
|
|
|
|
* caches dirty. */
|
2024-08-15 15:43:17 -04:00
|
|
|
Object &object_orig = *DEG_get_original_object(&object_eval);
|
|
|
|
|
update_normals(object_orig, object_eval, pbvh);
|
2024-08-14 23:19:19 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void update_node_bounds_mesh(const Span<float3> positions, MeshNode &node)
|
2024-06-04 15:43:21 -04:00
|
|
|
{
|
|
|
|
|
Bounds<float3> bounds = negative_bounds();
|
2024-09-05 20:07:03 +02:00
|
|
|
for (const int vert : node.all_verts()) {
|
2024-06-04 15:43:21 -04:00
|
|
|
math::min_max(positions[vert], bounds.min, bounds.max);
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bounds_ = bounds;
|
2024-06-04 15:43:21 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-12 23:45:52 +02:00
|
|
|
void update_node_bounds_grids(const int grid_area, const Span<float3> positions, GridsNode &node)
|
2024-06-04 15:43:21 -04:00
|
|
|
{
|
|
|
|
|
Bounds<float3> bounds = negative_bounds();
|
2024-09-05 20:07:03 +02:00
|
|
|
for (const int grid : node.grids()) {
|
2024-09-12 23:45:52 +02:00
|
|
|
for (const float3 &position : positions.slice(bke::ccg::grid_range(grid_area, grid))) {
|
2024-09-11 15:54:46 +02:00
|
|
|
math::min_max(position, bounds.min, bounds.max);
|
2024-06-04 15:43:21 -04:00
|
|
|
}
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bounds_ = bounds;
|
2024-06-04 15:43:21 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void update_node_bounds_bmesh(BMeshNode &node)
|
2024-06-04 15:43:21 -04:00
|
|
|
{
|
|
|
|
|
Bounds<float3> bounds = negative_bounds();
|
2024-07-23 22:31:27 +02:00
|
|
|
for (const BMVert *vert : node.bm_unique_verts_) {
|
2024-06-04 15:43:21 -04:00
|
|
|
math::min_max(float3(vert->co), bounds.min, bounds.max);
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
for (const BMVert *vert : node.bm_other_verts_) {
|
2024-06-04 15:43:21 -04:00
|
|
|
math::min_max(float3(vert->co), bounds.min, bounds.max);
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bounds_ = bounds;
|
2024-06-04 15:43:21 -04:00
|
|
|
}
|
|
|
|
|
|
2024-06-05 19:33:19 +02:00
|
|
|
struct BoundsMergeInfo {
|
|
|
|
|
Bounds<float3> bounds;
|
|
|
|
|
bool update;
|
|
|
|
|
};
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
template<typename NodeT>
|
2024-09-13 21:31:08 +02:00
|
|
|
static BoundsMergeInfo merge_child_bounds(MutableSpan<NodeT> nodes,
|
2024-09-13 15:45:05 -04:00
|
|
|
const BitSpan dirty,
|
2024-09-13 21:31:08 +02:00
|
|
|
const int node_index)
|
2019-04-17 06:17:24 +02:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
NodeT &node = nodes[node_index];
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node.flag_ & PBVH_Leaf) {
|
2024-09-13 21:31:08 +02:00
|
|
|
const bool update = node_index < dirty.size() && dirty[node_index];
|
2024-07-23 22:31:27 +02:00
|
|
|
return {node.bounds_, update};
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-13 21:31:08 +02:00
|
|
|
const BoundsMergeInfo info_0 = merge_child_bounds(nodes, dirty, node.children_offset_ + 0);
|
|
|
|
|
const BoundsMergeInfo info_1 = merge_child_bounds(nodes, dirty, node.children_offset_ + 1);
|
2024-06-05 19:33:19 +02:00
|
|
|
const bool update = info_0.update || info_1.update;
|
|
|
|
|
if (update) {
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bounds_ = bounds::merge(info_0.bounds, info_1.bounds);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
return {node.bounds_, update};
|
2009-11-04 20:36:38 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-12 23:45:52 +02:00
|
|
|
void flush_bounds_to_parents(Tree &pbvh)
|
2009-11-04 20:36:38 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
2024-09-13 21:31:08 +02:00
|
|
|
[&](auto &nodes) {
|
|
|
|
|
nodes.first().bounds_ =
|
|
|
|
|
merge_child_bounds(nodes.as_mutable_span(), pbvh.bounds_dirty_, 0).bounds;
|
2024-08-28 15:18:21 +02:00
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2024-09-13 21:31:08 +02:00
|
|
|
pbvh.bounds_dirty_.clear_and_shrink();
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
}
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
void update_bounds_mesh(const Span<float3> vert_positions, Tree &pbvh)
|
|
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMaskMemory memory;
|
2024-09-13 15:45:05 -04:00
|
|
|
const IndexMask nodes_to_update = IndexMask::from_bits(pbvh.bounds_dirty_, memory);
|
2024-09-13 21:31:08 +02:00
|
|
|
if (nodes_to_update.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-08-28 15:18:21 +02:00
|
|
|
MutableSpan<MeshNode> nodes = pbvh.nodes<MeshNode>();
|
|
|
|
|
nodes_to_update.foreach_index(
|
2024-08-30 14:20:38 -04:00
|
|
|
GrainSize(1), [&](const int i) { update_node_bounds_mesh(vert_positions, nodes[i]); });
|
2024-09-13 21:31:08 +02:00
|
|
|
flush_bounds_to_parents(pbvh);
|
2024-08-13 16:25:08 -04:00
|
|
|
}
|
|
|
|
|
|
2024-09-11 15:54:46 +02:00
|
|
|
void update_bounds_grids(const CCGKey &key, const Span<float3> positions, Tree &pbvh)
|
2024-08-13 16:25:08 -04:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMaskMemory memory;
|
2024-09-13 15:45:05 -04:00
|
|
|
const IndexMask nodes_to_update = IndexMask::from_bits(pbvh.bounds_dirty_, memory);
|
2024-09-13 21:31:08 +02:00
|
|
|
if (nodes_to_update.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-08-28 15:18:21 +02:00
|
|
|
MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
|
2024-09-12 23:45:52 +02:00
|
|
|
nodes_to_update.foreach_index(GrainSize(1), [&](const int i) {
|
|
|
|
|
update_node_bounds_grids(key.grid_area, positions, nodes[i]);
|
|
|
|
|
});
|
2024-09-13 21:31:08 +02:00
|
|
|
flush_bounds_to_parents(pbvh);
|
2024-08-13 16:25:08 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-20 17:47:43 -04:00
|
|
|
void update_bounds_bmesh(const BMesh & /*bm*/, Tree &pbvh)
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMaskMemory memory;
|
2024-09-13 15:45:05 -04:00
|
|
|
const IndexMask nodes_to_update = IndexMask::from_bits(pbvh.bounds_dirty_, memory);
|
2024-09-13 21:31:08 +02:00
|
|
|
if (nodes_to_update.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2024-08-28 15:18:21 +02:00
|
|
|
MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
|
2024-08-30 14:20:38 -04:00
|
|
|
nodes_to_update.foreach_index(GrainSize(1),
|
|
|
|
|
[&](const int i) { update_node_bounds_bmesh(nodes[i]); });
|
2024-09-13 21:31:08 +02:00
|
|
|
flush_bounds_to_parents(pbvh);
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-15 15:43:17 -04:00
|
|
|
void update_bounds(const Depsgraph &depsgraph, const Object &object, Tree &pbvh)
|
2024-08-13 16:25:08 -04:00
|
|
|
{
|
|
|
|
|
switch (pbvh.type()) {
|
|
|
|
|
case Type::Mesh: {
|
2024-08-15 15:43:17 -04:00
|
|
|
const Span<float3> positions = bke::pbvh::vert_positions_eval(depsgraph, object);
|
2024-08-13 16:25:08 -04:00
|
|
|
update_bounds_mesh(positions, pbvh);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Type::Grids: {
|
|
|
|
|
const SculptSession &ss = *object.sculpt;
|
|
|
|
|
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
|
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
2024-09-11 15:54:46 +02:00
|
|
|
update_bounds_grids(key, subdiv_ccg.positions, pbvh);
|
2024-08-13 16:25:08 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
case Type::BMesh: {
|
2024-08-20 17:47:43 -04:00
|
|
|
const SculptSession &ss = *object.sculpt;
|
|
|
|
|
update_bounds_bmesh(*ss.bm, pbvh);
|
2024-08-13 16:25:08 -04:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void store_bounds_orig(Tree &pbvh)
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[](auto &nodes) {
|
|
|
|
|
threading::parallel_for(nodes.index_range(), 256, [&](const IndexRange range) {
|
|
|
|
|
for (const int i : range) {
|
|
|
|
|
nodes[i].bounds_orig_ = nodes[i].bounds_;
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void node_update_mask_mesh(const Span<float> mask, MeshNode &node)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> verts = node.all_verts();
|
2024-06-29 18:45:23 -04:00
|
|
|
const bool fully_masked = std::all_of(
|
|
|
|
|
verts.begin(), verts.end(), [&](const int vert) { return mask[vert] == 1.0f; });
|
|
|
|
|
const bool fully_unmasked = std::all_of(
|
|
|
|
|
verts.begin(), verts.end(), [&](const int vert) { return mask[vert] <= 0.0f; });
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_masked, PBVH_FullyMasked);
|
|
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_unmasked, PBVH_FullyUnmasked);
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
void update_mask_mesh(const Mesh &mesh, const IndexMask &node_mask, Tree &pbvh)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
2024-09-13 17:29:25 -04:00
|
|
|
const MutableSpan<MeshNode> nodes = pbvh.nodes<MeshNode>();
|
2023-12-03 17:55:43 -05:00
|
|
|
const AttributeAccessor attributes = mesh.attributes();
|
2023-12-20 13:13:16 -05:00
|
|
|
const VArraySpan<float> mask = *attributes.lookup<float>(".sculpt_mask", AttrDomain::Point);
|
2023-12-03 17:55:43 -05:00
|
|
|
if (mask.is_empty()) {
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index([&](const int i) {
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes[i].flag_ &= ~PBVH_FullyMasked;
|
|
|
|
|
nodes[i].flag_ |= PBVH_FullyUnmasked;
|
|
|
|
|
});
|
2023-12-03 17:55:43 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2019-09-30 15:56:12 +02:00
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index(GrainSize(1),
|
|
|
|
|
[&](const int i) { node_update_mask_mesh(mask, nodes[i]); });
|
2023-09-27 17:10:02 -04:00
|
|
|
}
|
2019-09-30 15:56:12 +02:00
|
|
|
|
2024-09-11 15:54:46 +02:00
|
|
|
void node_update_mask_grids(const CCGKey &key, const Span<float> masks, GridsNode &node)
|
2023-09-27 17:05:31 -04:00
|
|
|
{
|
2023-12-03 17:55:43 -05:00
|
|
|
bool fully_masked = true;
|
|
|
|
|
bool fully_unmasked = true;
|
2024-09-05 20:07:03 +02:00
|
|
|
for (const int grid : node.grids()) {
|
2024-09-11 15:54:46 +02:00
|
|
|
for (const float mask : masks.slice(bke::ccg::grid_range(key, grid))) {
|
2023-12-03 17:55:43 -05:00
|
|
|
fully_masked &= mask == 1.0f;
|
|
|
|
|
fully_unmasked &= mask <= 0.0f;
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_masked, PBVH_FullyMasked);
|
|
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_unmasked, PBVH_FullyUnmasked);
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
2023-09-27 17:05:31 -04:00
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
void update_mask_grids(const SubdivCCG &subdiv_ccg, const IndexMask &node_mask, Tree &pbvh)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
2024-09-13 17:29:25 -04:00
|
|
|
const MutableSpan<GridsNode> nodes = pbvh.nodes<GridsNode>();
|
2023-12-03 21:21:03 -05:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
2024-09-11 15:54:46 +02:00
|
|
|
if (subdiv_ccg.masks.is_empty()) {
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index([&](const int i) {
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes[i].flag_ &= ~PBVH_FullyMasked;
|
|
|
|
|
nodes[i].flag_ |= PBVH_FullyUnmasked;
|
|
|
|
|
});
|
2023-12-03 17:55:43 -05:00
|
|
|
return;
|
Sculpt Vertex Colors: Initial implementation
Sculpt Vertex Colors is a painting system that runs inside sculpt mode, reusing all its tools and optimizations. This provides much better performance, easier to maintain code and more advanced features (new brush engine, filters, symmetry options, masks and face sets compatibility...). This is also the initial step for future features like vertex painting in Multires and brushes that can sculpt and paint at the same time.
This commit includes:
- SCULPT_UNDO_COLOR for undo support in sculpt mode
- SCULPT_UPDATE_COLOR and PBVH flags and rendering
- Sculpt Color API functions
- Sculpt capability for sculpt tools (only enabled in the Paint Brush for now)
- Rendering support in workbench (default to Sculpt Vertex Colors except in Vertex Paint)
- Conversion operator between MPropCol (Sculpt Vertex Colors) and MLoopCol (Vertex Paint)
- Remesher reprojection in the Voxel Remehser
- Paint Brush and Smear Brush with color smoothing in alt-smooth mode
- Parameters for the new brush engine (density, opacity, flow, wet paint mixing, tip scale) implemented in Sculpt Vertex Colors
- Color Filter
- Color picker (uses S shortcut, replaces smooth)
- Color selector in the top bar
Reviewed By: brecht
Maniphest Tasks: T72866
Differential Revision: https://developer.blender.org/D5975
2020-06-22 20:05:28 +02:00
|
|
|
}
|
2023-12-03 17:55:43 -05:00
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index(
|
2024-09-11 15:54:46 +02:00
|
|
|
GrainSize(1), [&](const int i) { node_update_mask_grids(key, subdiv_ccg.masks, nodes[i]); });
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void node_update_mask_bmesh(const int mask_offset, BMeshNode &node)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(mask_offset != -1);
|
|
|
|
|
bool fully_masked = true;
|
|
|
|
|
bool fully_unmasked = true;
|
2024-07-23 22:31:27 +02:00
|
|
|
for (const BMVert *vert : node.bm_unique_verts_) {
|
2023-12-03 17:55:43 -05:00
|
|
|
fully_masked &= BM_ELEM_CD_GET_FLOAT(vert, mask_offset) == 1.0f;
|
|
|
|
|
fully_unmasked &= BM_ELEM_CD_GET_FLOAT(vert, mask_offset) <= 0.0f;
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
for (const BMVert *vert : node.bm_other_verts_) {
|
2023-12-03 17:55:43 -05:00
|
|
|
fully_masked &= BM_ELEM_CD_GET_FLOAT(vert, mask_offset) == 1.0f;
|
|
|
|
|
fully_unmasked &= BM_ELEM_CD_GET_FLOAT(vert, mask_offset) <= 0.0f;
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_masked, PBVH_FullyMasked);
|
|
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_unmasked, PBVH_FullyUnmasked);
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
void update_mask_bmesh(const BMesh &bm, const IndexMask &node_mask, Tree &pbvh)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
2024-09-13 17:29:25 -04:00
|
|
|
const MutableSpan<BMeshNode> nodes = pbvh.nodes<BMeshNode>();
|
2023-12-03 17:55:43 -05:00
|
|
|
const int offset = CustomData_get_offset_named(&bm.vdata, CD_PROP_FLOAT, ".sculpt_mask");
|
|
|
|
|
if (offset == -1) {
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index([&](const int i) {
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes[i].flag_ &= ~PBVH_FullyMasked;
|
|
|
|
|
nodes[i].flag_ |= PBVH_FullyUnmasked;
|
|
|
|
|
});
|
2023-12-03 17:55:43 -05:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 17:29:25 -04:00
|
|
|
node_mask.foreach_index(GrainSize(1),
|
|
|
|
|
[&](const int i) { node_update_mask_bmesh(offset, nodes[i]); });
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void node_update_visibility_mesh(const Span<bool> hide_vert, MeshNode &node)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(!hide_vert.is_empty());
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> verts = node.all_verts();
|
2024-06-29 18:45:23 -04:00
|
|
|
const bool fully_hidden = std::all_of(
|
|
|
|
|
verts.begin(), verts.end(), [&](const int vert) { return hide_vert[vert]; });
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_hidden, PBVH_FullyHidden);
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
static void update_visibility_faces(const Mesh &mesh,
|
|
|
|
|
const MutableSpan<MeshNode> nodes,
|
2024-09-13 23:07:00 -04:00
|
|
|
const IndexMask &node_mask)
|
2020-02-06 22:14:18 +01:00
|
|
|
{
|
2023-11-30 17:39:37 -05:00
|
|
|
const AttributeAccessor attributes = mesh.attributes();
|
2023-12-20 13:13:16 -05:00
|
|
|
const VArraySpan<bool> hide_vert = *attributes.lookup<bool>(".hide_vert", AttrDomain::Point);
|
2023-11-30 17:39:37 -05:00
|
|
|
if (hide_vert.is_empty()) {
|
2024-09-13 23:07:00 -04:00
|
|
|
node_mask.foreach_index([&](const int i) { nodes[i].flag_ &= ~PBVH_FullyHidden; });
|
2023-11-30 18:25:12 -05:00
|
|
|
return;
|
|
|
|
|
}
|
2020-02-06 22:14:18 +01:00
|
|
|
|
2024-09-13 23:07:00 -04:00
|
|
|
node_mask.foreach_index(GrainSize(1),
|
|
|
|
|
[&](const int i) { node_update_visibility_mesh(hide_vert, nodes[i]); });
|
2020-02-06 22:14:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void node_update_visibility_grids(const BitGroupVector<> &grid_hidden, GridsNode &node)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
|
|
|
|
BLI_assert(!grid_hidden.is_empty());
|
|
|
|
|
const bool fully_hidden = std::none_of(
|
2024-07-23 22:31:27 +02:00
|
|
|
node.prim_indices_.begin(), node.prim_indices_.end(), [&](const int grid) {
|
2023-12-03 17:55:43 -05:00
|
|
|
return bits::any_bit_unset(grid_hidden[grid]);
|
|
|
|
|
});
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, fully_hidden, PBVH_FullyHidden);
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
static void update_visibility_grids(const SubdivCCG &subdiv_ccg,
|
|
|
|
|
const MutableSpan<GridsNode> nodes,
|
2024-09-13 23:07:00 -04:00
|
|
|
const IndexMask &node_mask)
|
2020-02-06 22:14:18 +01:00
|
|
|
{
|
2024-08-13 16:25:08 -04:00
|
|
|
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
2023-12-02 20:05:29 +01:00
|
|
|
if (grid_hidden.is_empty()) {
|
2024-09-13 23:07:00 -04:00
|
|
|
node_mask.foreach_index([&](const int i) { nodes[i].flag_ &= ~PBVH_FullyHidden; });
|
2023-12-02 20:05:29 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-13 23:07:00 -04:00
|
|
|
node_mask.foreach_index(
|
2024-08-28 15:18:21 +02:00
|
|
|
GrainSize(1), [&](const int i) { node_update_visibility_grids(grid_hidden, nodes[i]); });
|
2020-02-06 22:14:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
void node_update_visibility_bmesh(BMeshNode &node)
|
2023-12-03 17:55:43 -05:00
|
|
|
{
|
|
|
|
|
const bool unique_hidden = std::all_of(
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bm_unique_verts_.begin(), node.bm_unique_verts_.end(), [&](const BMVert *vert) {
|
2023-12-03 17:55:43 -05:00
|
|
|
return BM_elem_flag_test(vert, BM_ELEM_HIDDEN);
|
|
|
|
|
});
|
|
|
|
|
const bool other_hidden = std::all_of(
|
2024-07-23 22:31:27 +02:00
|
|
|
node.bm_other_verts_.begin(), node.bm_other_verts_.end(), [&](const BMVert *vert) {
|
2023-12-03 17:55:43 -05:00
|
|
|
return BM_elem_flag_test(vert, BM_ELEM_HIDDEN);
|
|
|
|
|
});
|
2024-07-23 22:31:27 +02:00
|
|
|
SET_FLAG_FROM_TEST(node.flag_, unique_hidden && other_hidden, PBVH_FullyHidden);
|
2023-12-03 17:55:43 -05:00
|
|
|
}
|
|
|
|
|
|
2024-09-13 23:07:00 -04:00
|
|
|
static void update_visibility_bmesh(const MutableSpan<BMeshNode> nodes, const IndexMask &node_mask)
|
2020-02-06 22:14:18 +01:00
|
|
|
{
|
2024-09-13 23:07:00 -04:00
|
|
|
node_mask.foreach_index(GrainSize(1),
|
|
|
|
|
[&](const int i) { node_update_visibility_bmesh(nodes[i]); });
|
2020-02-06 22:14:18 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
void update_visibility(const Object &object, Tree &pbvh)
|
2020-02-06 22:14:18 +01:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMaskMemory memory;
|
2024-09-13 23:07:00 -04:00
|
|
|
const IndexMask node_mask = IndexMask::from_bits(pbvh.visibility_dirty_, memory);
|
|
|
|
|
if (node_mask.is_empty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pbvh.visibility_dirty_.clear_and_shrink();
|
2024-07-23 22:31:27 +02:00
|
|
|
switch (pbvh.type()) {
|
2024-08-13 16:25:08 -04:00
|
|
|
case Type::Mesh: {
|
|
|
|
|
const Mesh &mesh = *static_cast<const Mesh *>(object.data);
|
2024-09-13 23:07:00 -04:00
|
|
|
update_visibility_faces(mesh, pbvh.nodes<MeshNode>(), node_mask);
|
2023-08-01 18:14:43 -04:00
|
|
|
break;
|
2024-08-13 16:25:08 -04:00
|
|
|
}
|
|
|
|
|
case Type::Grids: {
|
|
|
|
|
const SculptSession &ss = *object.sculpt;
|
2024-09-13 23:07:00 -04:00
|
|
|
update_visibility_grids(*ss.subdiv_ccg, pbvh.nodes<GridsNode>(), node_mask);
|
2023-08-01 18:14:43 -04:00
|
|
|
break;
|
2024-08-13 16:25:08 -04:00
|
|
|
}
|
|
|
|
|
case Type::BMesh: {
|
2024-09-13 23:07:00 -04:00
|
|
|
update_visibility_bmesh(pbvh.nodes<BMeshNode>(), node_mask);
|
2023-08-01 18:14:43 -04:00
|
|
|
break;
|
2024-08-13 16:25:08 -04:00
|
|
|
}
|
2020-02-06 22:14:18 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 23:17:47 -04:00
|
|
|
int count_grid_quads(const BitGroupVector<> &grid_hidden,
|
|
|
|
|
const Span<int> grid_indices,
|
|
|
|
|
int gridsize,
|
|
|
|
|
int display_gridsize)
|
|
|
|
|
{
|
|
|
|
|
const int gridarea = (gridsize - 1) * (gridsize - 1);
|
|
|
|
|
if (grid_hidden.is_empty()) {
|
|
|
|
|
return gridarea * grid_indices.size();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* grid hidden layer is present, so have to check each grid for
|
|
|
|
|
* visibility */
|
|
|
|
|
|
|
|
|
|
int depth1 = int(log2(double(gridsize) - 1.0) + DBL_EPSILON);
|
|
|
|
|
int depth2 = int(log2(double(display_gridsize) - 1.0) + DBL_EPSILON);
|
|
|
|
|
|
|
|
|
|
int skip = depth2 < depth1 ? 1 << (depth1 - depth2 - 1) : 1;
|
|
|
|
|
|
|
|
|
|
int totquad = 0;
|
|
|
|
|
for (const int grid : grid_indices) {
|
|
|
|
|
const blender::BoundedBitSpan gh = grid_hidden[grid];
|
|
|
|
|
/* grid hidden are present, have to check each element */
|
|
|
|
|
for (int y = 0; y < gridsize - skip; y += skip) {
|
|
|
|
|
for (int x = 0; x < gridsize - skip; x += skip) {
|
|
|
|
|
if (!paint_is_grid_face_hidden(gh, gridsize, x, y)) {
|
|
|
|
|
totquad++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return totquad;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-14 14:56:25 -05:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-09-05 14:16:28 -04:00
|
|
|
blender::Bounds<blender::float3> BKE_pbvh_redraw_BB(const blender::bke::pbvh::Tree &pbvh)
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
{
|
2023-12-04 11:25:07 -05:00
|
|
|
using namespace blender;
|
2023-12-16 10:57:42 -05:00
|
|
|
using namespace blender::bke::pbvh;
|
2024-08-28 15:18:21 +02:00
|
|
|
if (tree_is_empty(pbvh)) {
|
2023-12-04 11:25:07 -05:00
|
|
|
return {};
|
2023-08-22 12:29:36 -04:00
|
|
|
}
|
2023-12-04 11:25:07 -05:00
|
|
|
Bounds<float3> bounds = negative_bounds();
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2023-12-04 11:25:07 -05:00
|
|
|
PBVHIter iter;
|
2024-09-05 14:16:28 -04:00
|
|
|
pbvh_iter_begin(&iter, const_cast<blender::bke::pbvh::Tree &>(pbvh), {});
|
2024-07-23 22:31:27 +02:00
|
|
|
Node *node;
|
2023-01-23 10:29:40 -08:00
|
|
|
while ((node = pbvh_iter_next(&iter, PBVH_Leaf))) {
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node->flag_ & PBVH_UpdateRedraw) {
|
|
|
|
|
bounds = bounds::merge(bounds, node->bounds_);
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
}
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2023-12-04 11:25:07 -05:00
|
|
|
return bounds;
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-18 15:06:45 -05:00
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
|
|
|
|
IndexMask nodes_to_face_selection_grids(const SubdivCCG &subdiv_ccg,
|
2024-08-28 15:18:21 +02:00
|
|
|
const Span<GridsNode> nodes,
|
|
|
|
|
const IndexMask &nodes_mask,
|
2023-12-18 15:06:45 -05:00
|
|
|
IndexMaskMemory &memory)
|
2009-11-25 13:40:43 +00:00
|
|
|
{
|
2023-12-18 15:06:45 -05:00
|
|
|
const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
|
2023-11-29 11:10:08 -05:00
|
|
|
/* Using a #VectorSet for index deduplication would also work, but the performance gets much
|
|
|
|
|
* worse with large selections since the loop would be single-threaded. A boolean array has an
|
|
|
|
|
* overhead regardless of selection size, but that is small. */
|
2023-12-18 15:06:45 -05:00
|
|
|
Array<bool> faces_to_update(subdiv_ccg.faces.size(), false);
|
2024-08-28 15:18:21 +02:00
|
|
|
nodes_mask.foreach_index(GrainSize(1), [&](const int i) {
|
2024-09-05 20:07:03 +02:00
|
|
|
for (const int grid : nodes[i].grids()) {
|
2024-08-28 15:18:21 +02:00
|
|
|
faces_to_update[grid_to_face_map[grid]] = true;
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
2023-11-29 11:10:08 -05:00
|
|
|
});
|
|
|
|
|
return IndexMask::from_bools(faces_to_update, memory);
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
Bounds<float3> bounds_get(const Tree &pbvh)
|
2013-01-20 00:19:57 +00:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
return std::visit(
|
|
|
|
|
[](auto &nodes) -> Bounds<float3> {
|
|
|
|
|
if (nodes.is_empty()) {
|
|
|
|
|
return float3(0);
|
|
|
|
|
}
|
|
|
|
|
return nodes.first().bounds_;
|
|
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2013-01-20 00:19:57 +00:00
|
|
|
}
|
|
|
|
|
|
2024-04-23 22:57:33 -04:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-08-22 16:07:16 -04:00
|
|
|
int BKE_pbvh_get_grid_num_verts(const Object &object)
|
2019-09-30 16:33:04 +02:00
|
|
|
{
|
2024-08-22 16:07:16 -04:00
|
|
|
const SculptSession &ss = *object.sculpt;
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(blender::bke::object::pbvh_get(object)->type() == blender::bke::pbvh::Type::Grids);
|
2024-08-22 16:07:16 -04:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
|
2024-09-11 15:54:46 +02:00
|
|
|
return ss.subdiv_ccg->grids_num * key.grid_area;
|
2019-09-30 16:33:04 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 16:07:16 -04:00
|
|
|
int BKE_pbvh_get_grid_num_faces(const Object &object)
|
2020-11-27 00:03:58 +01:00
|
|
|
{
|
2024-08-22 16:07:16 -04:00
|
|
|
const SculptSession &ss = *object.sculpt;
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(blender::bke::object::pbvh_get(object)->type() == blender::bke::pbvh::Type::Grids);
|
2024-08-22 16:07:16 -04:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(*ss.subdiv_ccg);
|
2024-09-11 15:54:46 +02:00
|
|
|
return ss.subdiv_ccg->grids_num * square_i(key.grid_size - 1);
|
2020-11-27 00:03:58 +01:00
|
|
|
}
|
|
|
|
|
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
/***************************** Node Access ***********************************/
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
void BKE_pbvh_node_mark_update(blender::bke::pbvh::Node &node)
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
{
|
2024-09-13 23:26:42 -04:00
|
|
|
node.flag_ |= PBVH_RebuildPixels;
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void BKE_pbvh_mark_rebuild_pixels(blender::bke::pbvh::Tree &pbvh)
|
2022-04-15 16:39:50 +02:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[](auto &nodes) {
|
|
|
|
|
for (blender::bke::pbvh::Node &node : nodes) {
|
|
|
|
|
if (node.flag_ & PBVH_Leaf) {
|
|
|
|
|
node.flag_ |= PBVH_RebuildPixels;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2022-04-15 16:39:50 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
void BKE_pbvh_node_fully_hidden_set(blender::bke::pbvh::Node &node, int fully_hidden)
|
2012-03-14 06:32:25 +00:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
BLI_assert(node.flag_ & PBVH_Leaf);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2019-04-22 09:39:35 +10:00
|
|
|
if (fully_hidden) {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ |= PBVH_FullyHidden;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ &= ~PBVH_FullyHidden;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-03-14 06:32:25 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
bool BKE_pbvh_node_fully_hidden_get(const blender::bke::pbvh::Node &node)
|
2020-07-08 18:10:31 +02:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
return (node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_FullyHidden);
|
2020-07-08 18:10:31 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
void BKE_pbvh_node_fully_masked_set(blender::bke::pbvh::Node &node, int fully_masked)
|
2019-09-30 15:56:12 +02:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
BLI_assert(node.flag_ & PBVH_Leaf);
|
2019-09-30 15:56:12 +02:00
|
|
|
|
|
|
|
|
if (fully_masked) {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ |= PBVH_FullyMasked;
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ &= ~PBVH_FullyMasked;
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
bool BKE_pbvh_node_fully_masked_get(const blender::bke::pbvh::Node &node)
|
2019-09-30 15:56:12 +02:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
return (node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_FullyMasked);
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
void BKE_pbvh_node_fully_unmasked_set(blender::bke::pbvh::Node &node, int fully_masked)
|
2019-09-30 15:56:12 +02:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
BLI_assert(node.flag_ & PBVH_Leaf);
|
2019-09-30 15:56:12 +02:00
|
|
|
|
|
|
|
|
if (fully_masked) {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ |= PBVH_FullyUnmasked;
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-21 08:10:56 -04:00
|
|
|
node.flag_ &= ~PBVH_FullyUnmasked;
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-21 08:10:56 -04:00
|
|
|
bool BKE_pbvh_node_fully_unmasked_get(const blender::bke::pbvh::Node &node)
|
2019-09-30 15:56:12 +02:00
|
|
|
{
|
2024-08-21 08:10:56 -04:00
|
|
|
return (node.flag_ & PBVH_Leaf) && (node.flag_ & PBVH_FullyUnmasked);
|
2019-09-30 15:56:12 +02:00
|
|
|
}
|
|
|
|
|
|
2024-04-23 22:57:33 -04:00
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
2024-08-22 16:07:16 -04:00
|
|
|
Span<int> node_face_indices_calc_grids(const SubdivCCG &subdiv_ccg,
|
2024-08-28 15:18:21 +02:00
|
|
|
const GridsNode &node,
|
2024-08-22 16:07:16 -04:00
|
|
|
Vector<int> &faces)
|
2023-11-03 10:27:38 +01:00
|
|
|
{
|
2023-12-14 15:31:12 -05:00
|
|
|
faces.clear();
|
2024-08-22 16:07:16 -04:00
|
|
|
const Span<int> grid_to_face_map = subdiv_ccg.grid_to_face_map;
|
2023-12-14 15:31:12 -05:00
|
|
|
int prev_face = -1;
|
2024-09-05 20:07:03 +02:00
|
|
|
for (const int grid : node.grids()) {
|
2024-08-29 14:12:26 -04:00
|
|
|
const int face = grid_to_face_map[grid];
|
2023-12-14 15:31:12 -05:00
|
|
|
if (face != prev_face) {
|
|
|
|
|
faces.append(face);
|
|
|
|
|
prev_face = face;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return faces.as_span();
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-23 22:57:33 -04:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
|
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
Bounds<float3> node_bounds(const Node &node)
|
2009-11-06 16:46:35 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return node.bounds_;
|
2009-11-06 16:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
2024-04-23 22:57:33 -04:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-07-23 23:21:40 -04:00
|
|
|
blender::Bounds<blender::float3> BKE_pbvh_node_get_original_BB(
|
|
|
|
|
const blender::bke::pbvh::Node *node)
|
2009-11-06 16:46:35 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return node->bounds_orig_;
|
2009-11-06 16:46:35 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 21:20:34 -04:00
|
|
|
void BKE_pbvh_node_get_bm_orco_data(const blender::bke::pbvh::BMeshNode &node,
|
|
|
|
|
blender::Span<blender::float3> &r_orig_positions,
|
|
|
|
|
blender::Span<blender::int3> &r_orig_tris)
|
2015-04-18 04:57:23 +10:00
|
|
|
{
|
2024-09-04 21:20:34 -04:00
|
|
|
r_orig_positions = node.orig_positions_;
|
|
|
|
|
r_orig_tris = node.orig_tris_;
|
2015-04-18 04:57:23 +10:00
|
|
|
}
|
|
|
|
|
|
2021-10-18 11:16:24 +11:00
|
|
|
/********************************* Ray-cast ***********************************/
|
Sculpt: Multithreading & PBVH Changes
* Sculpting, normal update and bounding box code is now multithreaded
using OpenMP.
* Fix a number of update issues: normals on node boundaries, outdated
bounding boxes, partial redraw, .. . There's probably still a few
left, but should be better now.
* Clicking once now does a single paint instead of two (was also
painting on mouse up event).
* Smooth shading now is enabled for the full mesh when the first face
uses it (so it can be tested at least).
Implementation Notes:
* PBVH search can now be done either using a callback or bt gathering the
nodes in an array. The latter makes multithreading with OpenMP easier.
* Normals update code is now inside PBVH, was doing it per node before but
should do all faces first and only then vertices.
* Instead of using search modes + 1 modified flag, now nodes get 4 flags
to indicate what needs to be updated for them, found that this makes it
easier for me to understand the code and fix update bugs.
* PBVHNode is now exposed as an abstract type, I think this makes it more
clear what is happening than having it's data passed as part of callback
functions.
* Active_verts list was replaced by looping over nodes and the vertices
inside them. However the grab brush still uses the active_verts system,
will fix that later.
* Some micro-optimizations, like avoiding a few multiplications/divisions,
using local variables instead of pointers, or looping over fewer vertices
to update the bounding boxes.
2009-11-02 18:47:03 +00:00
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
struct RaycastData {
|
|
|
|
|
IsectRayAABB_Precalc ray;
|
2014-10-09 22:39:59 +02:00
|
|
|
bool original;
|
2023-02-05 16:56:37 -05:00
|
|
|
};
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static bool ray_aabb_intersect(Node &node, const RaycastData &rcd)
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
2023-12-16 10:57:42 -05:00
|
|
|
if (rcd.original) {
|
2024-07-23 22:31:27 +02:00
|
|
|
return isect_ray_aabb_v3(&rcd.ray, node.bounds_orig_.min, node.bounds_orig_.max, &node.tmin_);
|
2016-07-05 18:55:06 +10:00
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
return isect_ray_aabb_v3(&rcd.ray, node.bounds_.min, node.bounds_.max, &node.tmin_);
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void raycast(Tree &pbvh,
|
|
|
|
|
const FunctionRef<void(Node &node, float *tmin)> hit_fn,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
2023-12-15 22:51:10 -05:00
|
|
|
bool original)
|
2009-10-27 19:53:34 +00:00
|
|
|
{
|
|
|
|
|
RaycastData rcd;
|
|
|
|
|
|
2016-01-20 17:00:12 +11:00
|
|
|
isect_ray_aabb_v3_precalc(&rcd.ray, ray_start, ray_normal);
|
2009-11-06 16:46:35 +00:00
|
|
|
rcd.original = original;
|
2009-10-27 19:53:34 +00:00
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
search_callback_occluded(
|
2024-07-23 22:31:27 +02:00
|
|
|
pbvh, [&](Node &node) { return ray_aabb_intersect(node, rcd); }, hit_fn);
|
2009-10-27 19:53:34 +00:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool ray_face_intersection_quad(const float3 &ray_start,
|
2024-09-19 21:27:41 +02:00
|
|
|
const IsectRayPrecalc *isect_precalc,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &t0,
|
|
|
|
|
const float3 &t1,
|
|
|
|
|
const float3 &t2,
|
|
|
|
|
const float3 &t3,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *depth)
|
2009-11-25 13:40:43 +00:00
|
|
|
{
|
2017-10-05 21:06:04 +11:00
|
|
|
float depth_test;
|
2011-04-21 13:11:51 +00:00
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
if ((isect_ray_tri_watertight_v3(ray_start, isect_precalc, t0, t1, t2, &depth_test, nullptr) &&
|
2024-09-20 06:50:54 +02:00
|
|
|
(depth_test < *depth)) ||
|
2023-02-05 16:56:37 -05:00
|
|
|
(isect_ray_tri_watertight_v3(ray_start, isect_precalc, t0, t2, t3, &depth_test, nullptr) &&
|
2024-09-20 06:50:54 +02:00
|
|
|
(depth_test < *depth)))
|
2017-10-05 21:06:04 +11:00
|
|
|
{
|
2024-09-20 06:50:54 +02:00
|
|
|
*depth = depth_test;
|
2015-07-17 04:15:24 +10:00
|
|
|
return true;
|
|
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
return false;
|
2015-07-17 04:15:24 +10:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool ray_face_intersection_tri(const float3 &ray_start,
|
2024-09-19 21:27:41 +02:00
|
|
|
const IsectRayPrecalc *isect_precalc,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &t0,
|
|
|
|
|
const float3 &t1,
|
|
|
|
|
const float3 &t2,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *depth)
|
2015-07-17 04:15:24 +10:00
|
|
|
{
|
2017-10-05 21:06:04 +11:00
|
|
|
float depth_test;
|
2023-02-05 16:56:37 -05:00
|
|
|
if (isect_ray_tri_watertight_v3(ray_start, isect_precalc, t0, t1, t2, &depth_test, nullptr) &&
|
2024-09-20 06:50:54 +02:00
|
|
|
(depth_test < *depth))
|
2022-09-25 15:14:13 +10:00
|
|
|
{
|
2024-09-20 06:50:54 +02:00
|
|
|
*depth = depth_test;
|
2014-12-01 17:11:18 +01:00
|
|
|
return true;
|
2011-04-21 13:11:51 +00:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
return false;
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
|
2021-06-22 10:42:32 -07:00
|
|
|
/* Take advantage of the fact we know this won't be an intersection.
|
2017-10-05 21:16:25 +11:00
|
|
|
* Just handle ray-tri edges. */
|
2024-09-04 11:07:18 -04:00
|
|
|
static float dist_squared_ray_to_tri_v3_fast(const float3 &ray_origin,
|
|
|
|
|
const float3 &ray_direction,
|
|
|
|
|
const float3 &v0,
|
|
|
|
|
const float3 &v1,
|
|
|
|
|
const float3 &v2,
|
|
|
|
|
float3 &r_point,
|
2017-10-05 21:16:25 +11:00
|
|
|
float *r_depth)
|
|
|
|
|
{
|
|
|
|
|
const float *tri[3] = {v0, v1, v2};
|
|
|
|
|
float dist_sq_best = FLT_MAX;
|
|
|
|
|
for (int i = 0, j = 2; i < 3; j = i++) {
|
2024-09-04 11:07:18 -04:00
|
|
|
float3 point_test;
|
|
|
|
|
float depth_test = FLT_MAX;
|
2017-10-05 21:16:25 +11:00
|
|
|
const float dist_sq_test = dist_squared_ray_to_seg_v3(
|
|
|
|
|
ray_origin, ray_direction, tri[i], tri[j], point_test, &depth_test);
|
|
|
|
|
if (dist_sq_test < dist_sq_best || i == 0) {
|
|
|
|
|
copy_v3_v3(r_point, point_test);
|
|
|
|
|
*r_depth = depth_test;
|
|
|
|
|
dist_sq_best = dist_sq_test;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2017-10-05 21:16:25 +11:00
|
|
|
return dist_sq_best;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool ray_face_nearest_quad(const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
|
|
|
|
const float3 &t0,
|
|
|
|
|
const float3 &t1,
|
|
|
|
|
const float3 &t2,
|
|
|
|
|
const float3 &t3,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *r_depth,
|
2017-10-05 21:16:25 +11:00
|
|
|
float *dist_sq)
|
|
|
|
|
{
|
|
|
|
|
float dist_sq_test;
|
2024-09-04 11:07:18 -04:00
|
|
|
float3 co;
|
|
|
|
|
float depth_test;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-25 15:14:13 +10:00
|
|
|
if ((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
|
|
|
|
|
ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq)
|
|
|
|
|
{
|
2017-10-05 21:16:25 +11:00
|
|
|
*dist_sq = dist_sq_test;
|
2024-09-20 06:50:54 +02:00
|
|
|
*r_depth = depth_test;
|
2022-09-25 15:14:13 +10:00
|
|
|
if ((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
|
|
|
|
|
ray_start, ray_normal, t0, t2, t3, co, &depth_test)) < *dist_sq)
|
|
|
|
|
{
|
2017-10-05 21:16:25 +11:00
|
|
|
*dist_sq = dist_sq_test;
|
2024-09-20 06:50:54 +02:00
|
|
|
*r_depth = depth_test;
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool ray_face_nearest_tri(const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
|
|
|
|
const float3 &t0,
|
|
|
|
|
const float3 &t1,
|
|
|
|
|
const float3 &t2,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *r_depth,
|
2017-10-05 21:16:25 +11:00
|
|
|
float *dist_sq)
|
2015-07-17 04:15:24 +10:00
|
|
|
{
|
2017-10-05 21:16:25 +11:00
|
|
|
float dist_sq_test;
|
2024-09-04 11:07:18 -04:00
|
|
|
float3 co;
|
|
|
|
|
float depth_test;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2022-09-25 15:14:13 +10:00
|
|
|
if ((dist_sq_test = dist_squared_ray_to_tri_v3_fast(
|
|
|
|
|
ray_start, ray_normal, t0, t1, t2, co, &depth_test)) < *dist_sq)
|
|
|
|
|
{
|
2017-10-05 21:16:25 +11:00
|
|
|
*dist_sq = dist_sq_test;
|
2024-09-20 06:50:54 +02:00
|
|
|
*r_depth = depth_test;
|
2014-12-01 17:11:18 +01:00
|
|
|
return true;
|
2011-04-21 13:11:51 +00:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
|
|
|
|
|
return false;
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
static void calc_mesh_intersect_data(const Span<int> corner_verts,
|
|
|
|
|
const Span<int3> corner_tris,
|
|
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
2024-09-05 16:21:43 +02:00
|
|
|
const int face_index,
|
2024-09-04 11:07:18 -04:00
|
|
|
const int tri_index,
|
|
|
|
|
const std::array<const float *, 3> co,
|
2024-09-19 21:27:41 +02:00
|
|
|
const float *depth,
|
2024-09-21 20:17:18 +02:00
|
|
|
int &r_active_vertex,
|
2024-09-19 21:27:41 +02:00
|
|
|
int &r_active_face_index,
|
|
|
|
|
float3 &r_face_normal)
|
2024-09-04 11:07:18 -04:00
|
|
|
|
|
|
|
|
{
|
2024-09-19 21:27:41 +02:00
|
|
|
float3 nearest_vertex_co(0.0f);
|
|
|
|
|
normal_tri_v3(r_face_normal, co[0], co[1], co[2]);
|
2024-09-04 11:07:18 -04:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
const float3 location = ray_start + ray_normal * *depth;
|
|
|
|
|
for (int i = 0; i < co.size(); i++) {
|
|
|
|
|
/* Always assign nearest_vertex_co in the first iteration to avoid comparison against
|
|
|
|
|
* uninitialized values. This stores the closest vertex in the current intersecting
|
|
|
|
|
* triangle. */
|
|
|
|
|
if (i == 0 ||
|
|
|
|
|
len_squared_v3v3(location, co[i]) < len_squared_v3v3(location, nearest_vertex_co))
|
|
|
|
|
{
|
|
|
|
|
nearest_vertex_co = co[i];
|
|
|
|
|
r_active_vertex = corner_verts[corner_tris[tri_index][i]];
|
|
|
|
|
r_active_face_index = face_index;
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
bool node_raycast_mesh(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<bool> hide_poly,
|
|
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
|
|
|
|
IsectRayPrecalc *isect_precalc,
|
|
|
|
|
float *depth,
|
|
|
|
|
int &r_active_vertex,
|
|
|
|
|
int &r_active_face_index,
|
|
|
|
|
float3 &r_face_normal)
|
2009-11-25 13:40:43 +00:00
|
|
|
{
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> face_indices = node.faces();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool hit = false;
|
|
|
|
|
if (node_positions.is_empty()) {
|
2024-09-05 16:21:43 +02:00
|
|
|
for (const int i : face_indices.index_range()) {
|
|
|
|
|
const int face_i = face_indices[i];
|
|
|
|
|
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
2024-09-04 11:07:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-05 16:21:43 +02:00
|
|
|
|
|
|
|
|
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]]]}};
|
2024-09-20 06:50:54 +02:00
|
|
|
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
2024-09-05 16:21:43 +02:00
|
|
|
hit = true;
|
|
|
|
|
calc_mesh_intersect_data(corner_verts,
|
|
|
|
|
corner_tris,
|
|
|
|
|
ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
face_i,
|
|
|
|
|
tri_i,
|
|
|
|
|
co,
|
2024-09-20 06:50:54 +02:00
|
|
|
depth,
|
2024-09-05 16:21:43 +02:00
|
|
|
r_active_vertex,
|
|
|
|
|
r_active_face_index,
|
|
|
|
|
r_face_normal);
|
|
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
2012-06-10 16:37:22 +00:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
else {
|
2024-09-05 16:21:43 +02:00
|
|
|
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]) {
|
2024-09-04 11:07:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-05 16:21:43 +02:00
|
|
|
|
|
|
|
|
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]])]}};
|
2024-09-20 06:50:54 +02:00
|
|
|
if (ray_face_intersection_tri(ray_start, isect_precalc, co[0], co[1], co[2], depth)) {
|
2024-09-05 16:21:43 +02:00
|
|
|
hit = true;
|
|
|
|
|
calc_mesh_intersect_data(corner_verts,
|
|
|
|
|
corner_tris,
|
|
|
|
|
ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
face_i,
|
|
|
|
|
tri_i,
|
|
|
|
|
co,
|
2024-09-20 06:50:54 +02:00
|
|
|
depth,
|
2024-09-05 16:21:43 +02:00
|
|
|
r_active_vertex,
|
|
|
|
|
r_active_face_index,
|
|
|
|
|
r_face_normal);
|
|
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
2019-10-08 17:07:18 +02:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return hit;
|
|
|
|
|
}
|
2019-10-08 17:07:18 +02:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
static void calc_grids_intersect_data(const float3 &ray_start,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &ray_normal,
|
|
|
|
|
const int grid,
|
|
|
|
|
const short x,
|
|
|
|
|
const short y,
|
|
|
|
|
const std::array<const float *, 4> co,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *depth,
|
2024-09-21 20:17:18 +02:00
|
|
|
SubdivCCGCoord &r_active_vertex,
|
2024-09-19 21:27:41 +02:00
|
|
|
int &r_active_grid_index,
|
|
|
|
|
float3 &r_face_normal)
|
2019-10-08 17:07:18 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
{
|
|
|
|
|
float3 nearest_vertex_co;
|
2024-09-19 21:27:41 +02:00
|
|
|
normal_quad_v3(r_face_normal, co[0], co[1], co[2], co[3]);
|
2019-10-08 17:07:18 +02:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
const float3 location = ray_start + ray_normal * *depth;
|
2024-09-04 11:07:18 -04:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
constexpr short x_it[4] = {0, 1, 1, 0};
|
|
|
|
|
constexpr short y_it[4] = {1, 1, 0, 0};
|
2024-09-04 11:07:18 -04:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
for (int i = 0; i < co.size(); i++) {
|
|
|
|
|
/* Always assign nearest_vertex_co in the first iteration to avoid comparison against
|
|
|
|
|
* uninitialized values. This stores the closest vertex in the current intersecting
|
|
|
|
|
* quad. */
|
|
|
|
|
if (i == 0 ||
|
|
|
|
|
len_squared_v3v3(location, co[i]) < len_squared_v3v3(location, nearest_vertex_co))
|
|
|
|
|
{
|
|
|
|
|
copy_v3_v3(nearest_vertex_co, co[i]);
|
|
|
|
|
r_active_vertex = SubdivCCGCoord{grid, short(x + x_it[i]), short(y + y_it[i])};
|
2012-06-10 16:37:22 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2024-09-21 20:17:18 +02:00
|
|
|
r_active_grid_index = grid;
|
2012-06-10 16:37:22 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-21 20:17:18 +02:00
|
|
|
bool node_raycast_grids(const SubdivCCG &subdiv_ccg,
|
|
|
|
|
GridsNode &node,
|
|
|
|
|
const Span<float3> node_positions,
|
|
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
|
|
|
|
const IsectRayPrecalc *isect_precalc,
|
|
|
|
|
float *depth,
|
|
|
|
|
SubdivCCGCoord &r_active_vertex,
|
|
|
|
|
int &r_active_grid_index,
|
|
|
|
|
float3 &r_face_normal)
|
2012-06-10 16:37:22 +00:00
|
|
|
{
|
2024-08-22 16:07:16 -04:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> grids = node.grids();
|
2024-09-04 11:07:18 -04:00
|
|
|
const int grid_size = key.grid_size;
|
2014-03-24 13:21:58 +11:00
|
|
|
bool hit = false;
|
2024-08-22 16:07:16 -04:00
|
|
|
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> positions = subdiv_ccg.positions;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
if (node_positions.is_empty()) {
|
|
|
|
|
for (const int grid : grids) {
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
|
2024-09-04 11:07:18 -04:00
|
|
|
for (const short y : IndexRange(grid_size - 1)) {
|
|
|
|
|
for (const short x : IndexRange(grid_size - 1)) {
|
|
|
|
|
if (!grid_hidden.is_empty()) {
|
|
|
|
|
if (paint_is_grid_face_hidden(grid_hidden[grid], grid_size, x, y)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-09-11 15:54:46 +02:00
|
|
|
const std::array<const float *, 4> co{
|
|
|
|
|
{grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x, y)]}};
|
2024-09-04 11:07:18 -04:00
|
|
|
if (ray_face_intersection_quad(
|
2024-09-20 06:50:54 +02:00
|
|
|
ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth))
|
2024-09-04 11:07:18 -04:00
|
|
|
{
|
|
|
|
|
hit = true;
|
2024-09-21 20:17:18 +02:00
|
|
|
calc_grids_intersect_data(ray_start,
|
2024-09-04 11:07:18 -04:00
|
|
|
ray_normal,
|
|
|
|
|
grid,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
co,
|
2024-09-20 06:50:54 +02:00
|
|
|
depth,
|
2024-09-04 11:07:18 -04:00
|
|
|
r_active_vertex,
|
|
|
|
|
r_active_grid_index,
|
|
|
|
|
r_face_normal);
|
2019-10-08 17:07:18 +02:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (const int i : grids.index_range()) {
|
|
|
|
|
const int grid = grids[i];
|
2024-09-18 08:47:27 -04:00
|
|
|
const Span<float3> grid_positions = node_positions.slice(bke::ccg::grid_range(key, i));
|
2024-09-04 11:07:18 -04:00
|
|
|
for (const short y : IndexRange(grid_size - 1)) {
|
|
|
|
|
for (const short x : IndexRange(grid_size - 1)) {
|
|
|
|
|
if (!grid_hidden.is_empty()) {
|
|
|
|
|
if (paint_is_grid_face_hidden(grid_hidden[grid], grid_size, x, y)) {
|
|
|
|
|
continue;
|
2019-10-08 17:07:18 +02:00
|
|
|
}
|
|
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
const std::array<const float *, 4> co{grid_positions[(y + 1) * grid_size + x],
|
|
|
|
|
grid_positions[(y + 1) * grid_size + x + 1],
|
|
|
|
|
grid_positions[y * grid_size + x + 1],
|
|
|
|
|
grid_positions[y * grid_size + x]};
|
|
|
|
|
if (ray_face_intersection_quad(
|
2024-09-20 06:50:54 +02:00
|
|
|
ray_start, isect_precalc, co[0], co[1], co[2], co[3], depth))
|
2024-09-04 11:07:18 -04:00
|
|
|
{
|
|
|
|
|
hit = true;
|
2024-09-21 20:17:18 +02:00
|
|
|
calc_grids_intersect_data(ray_start,
|
2024-09-04 11:07:18 -04:00
|
|
|
ray_normal,
|
|
|
|
|
grid,
|
|
|
|
|
x,
|
|
|
|
|
y,
|
|
|
|
|
co,
|
2024-09-20 06:50:54 +02:00
|
|
|
depth,
|
2024-09-04 11:07:18 -04:00
|
|
|
r_active_vertex,
|
|
|
|
|
r_active_grid_index,
|
|
|
|
|
r_face_normal);
|
2020-04-01 17:51:59 +02:00
|
|
|
}
|
2012-06-10 16:37:22 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
}
|
2012-06-10 16:37:22 +00:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2012-06-10 16:37:22 +00:00
|
|
|
return hit;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
void clip_ray_ortho(
|
2024-07-23 22:31:27 +02:00
|
|
|
Tree &pbvh, bool original, float ray_start[3], float ray_end[3], float ray_normal[3])
|
2013-12-18 18:34:02 +02:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
if (tree_is_empty(pbvh)) {
|
2023-08-01 18:19:13 -04:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
float rootmin_start, rootmin_end;
|
2023-12-04 11:25:07 -05:00
|
|
|
Bounds<float3> bb_root;
|
|
|
|
|
float bb_center[3], bb_diff[3];
|
2023-08-01 18:19:13 -04:00
|
|
|
IsectRayAABB_Precalc ray;
|
|
|
|
|
float ray_normal_inv[3];
|
|
|
|
|
float offset = 1.0f + 1e-3f;
|
|
|
|
|
const float offset_vec[3] = {1e-3f, 1e-3f, 1e-3f};
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-08-01 18:19:13 -04:00
|
|
|
if (original) {
|
2024-08-28 15:18:21 +02:00
|
|
|
bb_root = BKE_pbvh_node_get_original_BB(&first_node(pbvh));
|
2023-08-01 18:19:13 -04:00
|
|
|
}
|
|
|
|
|
else {
|
2024-08-28 15:18:21 +02:00
|
|
|
bb_root = node_bounds(first_node(pbvh));
|
2023-08-01 18:19:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Calc rough clipping to avoid overflow later. See #109555. */
|
|
|
|
|
float mat[3][3];
|
|
|
|
|
axis_dominant_v3_to_m3(mat, ray_normal);
|
|
|
|
|
float a[3], b[3], min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {FLT_MIN, FLT_MIN, FLT_MIN};
|
|
|
|
|
|
2024-04-04 11:26:00 +11:00
|
|
|
/* Compute AABB bounds rotated along ray_normal. */
|
2023-12-04 11:25:07 -05:00
|
|
|
copy_v3_v3(a, bb_root.min);
|
|
|
|
|
copy_v3_v3(b, bb_root.max);
|
2023-08-01 18:19:13 -04:00
|
|
|
mul_m3_v3(mat, a);
|
|
|
|
|
mul_m3_v3(mat, b);
|
|
|
|
|
minmax_v3v3_v3(min, max, a);
|
|
|
|
|
minmax_v3v3_v3(min, max, b);
|
|
|
|
|
|
|
|
|
|
float cent[3];
|
|
|
|
|
|
|
|
|
|
/* Find midpoint of aabb on ray. */
|
2023-12-04 11:25:07 -05:00
|
|
|
mid_v3_v3v3(cent, bb_root.min, bb_root.max);
|
2023-08-01 18:19:13 -04:00
|
|
|
float t = line_point_factor_v3(cent, ray_start, ray_end);
|
|
|
|
|
interp_v3_v3v3(cent, ray_start, ray_end, t);
|
|
|
|
|
|
|
|
|
|
/* Compute rough interval. */
|
|
|
|
|
float dist = max[2] - min[2];
|
|
|
|
|
madd_v3_v3v3fl(ray_start, cent, ray_normal, -dist);
|
|
|
|
|
madd_v3_v3v3fl(ray_end, cent, ray_normal, dist);
|
|
|
|
|
|
|
|
|
|
/* Slightly offset min and max in case we have a zero width node
|
|
|
|
|
* (due to a plane mesh for instance), or faces very close to the bounding box boundary. */
|
2023-12-04 11:25:07 -05:00
|
|
|
mid_v3_v3v3(bb_center, bb_root.max, bb_root.min);
|
2023-08-01 18:19:13 -04:00
|
|
|
/* Diff should be same for both min/max since it's calculated from center. */
|
2023-12-04 11:25:07 -05:00
|
|
|
sub_v3_v3v3(bb_diff, bb_root.max, bb_center);
|
2023-08-01 18:19:13 -04:00
|
|
|
/* Handles case of zero width bb. */
|
|
|
|
|
add_v3_v3(bb_diff, offset_vec);
|
2023-12-04 11:25:07 -05:00
|
|
|
madd_v3_v3v3fl(bb_root.max, bb_center, bb_diff, offset);
|
|
|
|
|
madd_v3_v3v3fl(bb_root.min, bb_center, bb_diff, -offset);
|
2023-08-01 18:19:13 -04:00
|
|
|
|
|
|
|
|
/* Final projection of start ray. */
|
|
|
|
|
isect_ray_aabb_v3_precalc(&ray, ray_start, ray_normal);
|
2023-12-04 11:25:07 -05:00
|
|
|
if (!isect_ray_aabb_v3(&ray, bb_root.min, bb_root.max, &rootmin_start)) {
|
2023-08-01 18:19:13 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-08-01 18:19:13 -04:00
|
|
|
/* Final projection of end ray. */
|
|
|
|
|
mul_v3_v3fl(ray_normal_inv, ray_normal, -1.0);
|
|
|
|
|
isect_ray_aabb_v3_precalc(&ray, ray_end, ray_normal_inv);
|
|
|
|
|
/* Unlikely to fail exiting if entering succeeded, still keep this here. */
|
2023-12-04 11:25:07 -05:00
|
|
|
if (!isect_ray_aabb_v3(&ray, bb_root.min, bb_root.max, &rootmin_end)) {
|
2023-08-01 18:19:13 -04:00
|
|
|
return;
|
|
|
|
|
}
|
2023-07-06 10:21:32 -07:00
|
|
|
|
2023-08-01 18:19:13 -04:00
|
|
|
/*
|
|
|
|
|
* As a last-ditch effort to correct floating point overflow compute
|
|
|
|
|
* and add an epsilon if rootmin_start == rootmin_end.
|
|
|
|
|
*/
|
2023-07-06 10:21:32 -07:00
|
|
|
|
2023-08-01 18:19:13 -04:00
|
|
|
float epsilon = (std::nextafter(rootmin_start, rootmin_start + 1000.0f) - rootmin_start) *
|
|
|
|
|
5000.0f;
|
2023-07-03 22:25:49 -07:00
|
|
|
|
2023-08-01 18:19:13 -04:00
|
|
|
if (rootmin_start == rootmin_end) {
|
|
|
|
|
rootmin_start -= epsilon;
|
|
|
|
|
rootmin_end += epsilon;
|
2013-12-18 18:34:02 +02:00
|
|
|
}
|
2023-08-01 18:19:13 -04:00
|
|
|
|
|
|
|
|
madd_v3_v3v3fl(ray_start, ray_start, ray_normal, rootmin_start);
|
|
|
|
|
madd_v3_v3v3fl(ray_end, ray_end, ray_normal_inv, rootmin_end);
|
2013-12-18 18:34:02 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-05 21:16:25 +11:00
|
|
|
/* -------------------------------------------------------------------- */
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
static bool nearest_to_ray_aabb_dist_sq(Node *node,
|
2024-01-12 14:45:33 -05:00
|
|
|
const DistRayAABB_Precalc &dist_ray_to_aabb_precalc,
|
|
|
|
|
const bool original)
|
2017-10-05 21:16:25 +11:00
|
|
|
{
|
|
|
|
|
const float *bb_min, *bb_max;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-01-12 14:45:33 -05:00
|
|
|
if (original) {
|
2017-10-05 21:16:25 +11:00
|
|
|
/* BKE_pbvh_node_get_original_BB */
|
2024-07-23 22:31:27 +02:00
|
|
|
bb_min = node->bounds_orig_.min;
|
|
|
|
|
bb_max = node->bounds_orig_.max;
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
|
|
|
|
else {
|
2024-07-23 22:31:27 +02:00
|
|
|
bb_min = node->bounds_.min;
|
|
|
|
|
bb_max = node->bounds_.max;
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-05 21:16:25 +11:00
|
|
|
float co_dummy[3], depth;
|
2024-07-23 22:31:27 +02:00
|
|
|
node->tmin_ = dist_squared_ray_to_aabb_v3(
|
2024-01-12 14:45:33 -05:00
|
|
|
&dist_ray_to_aabb_precalc, bb_min, bb_max, co_dummy, &depth);
|
2017-10-05 21:16:25 +11:00
|
|
|
/* Ideally we would skip distances outside the range. */
|
|
|
|
|
return depth > 0.0f;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void find_nearest_to_ray(Tree &pbvh,
|
|
|
|
|
const FunctionRef<void(Node &node, float *tmin)> fn,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
2024-01-12 14:45:33 -05:00
|
|
|
const bool original)
|
2017-10-05 21:16:25 +11:00
|
|
|
{
|
2024-01-12 14:45:33 -05:00
|
|
|
const DistRayAABB_Precalc ray_dist_precalc = dist_squared_ray_to_aabb_v3_precalc(ray_start,
|
|
|
|
|
ray_normal);
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
search_callback_occluded(
|
2024-01-12 14:45:33 -05:00
|
|
|
pbvh,
|
2024-07-23 22:31:27 +02:00
|
|
|
[&](Node &node) { return nearest_to_ray_aabb_dist_sq(&node, ray_dist_precalc, original); },
|
2024-01-12 14:45:33 -05:00
|
|
|
fn);
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
static bool pbvh_faces_node_nearest_to_ray(const MeshNode &node,
|
2024-09-04 11:07:18 -04:00
|
|
|
const Span<float3> node_positions,
|
2024-08-14 23:27:10 -04:00
|
|
|
const Span<float3> vert_positions,
|
2024-09-05 16:21:43 +02:00
|
|
|
const OffsetIndices<int> faces,
|
2023-11-30 18:25:12 -05:00
|
|
|
const Span<int> corner_verts,
|
2024-06-25 21:33:20 -04:00
|
|
|
const Span<int3> corner_tris,
|
2023-12-12 17:49:51 -05:00
|
|
|
const Span<bool> hide_poly,
|
2024-09-04 11:07:18 -04:00
|
|
|
const float3 &ray_start,
|
|
|
|
|
const float3 &ray_normal,
|
2024-09-20 06:50:54 +02:00
|
|
|
float *r_depth,
|
2017-10-05 21:16:25 +11:00
|
|
|
float *dist_sq)
|
|
|
|
|
{
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> face_indices = node.faces();
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool hit = false;
|
|
|
|
|
if (node_positions.is_empty()) {
|
2024-09-05 16:21:43 +02:00
|
|
|
for (const int i : face_indices.index_range()) {
|
|
|
|
|
const int face_i = face_indices[i];
|
|
|
|
|
if (!hide_poly.is_empty() && hide_poly[face_i]) {
|
2024-09-04 11:07:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-05 16:21:43 +02:00
|
|
|
|
|
|
|
|
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]]],
|
2024-09-20 06:50:54 +02:00
|
|
|
r_depth,
|
2024-09-05 16:21:43 +02:00
|
|
|
dist_sq);
|
|
|
|
|
}
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
else {
|
2024-09-05 16:21:43 +02:00
|
|
|
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]) {
|
2024-09-04 11:07:18 -04:00
|
|
|
continue;
|
|
|
|
|
}
|
2024-09-05 16:21:43 +02:00
|
|
|
|
|
|
|
|
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]])],
|
2024-09-20 06:50:54 +02:00
|
|
|
r_depth,
|
2024-09-05 16:21:43 +02:00
|
|
|
dist_sq);
|
|
|
|
|
}
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
|
|
|
|
|
2017-10-05 21:16:25 +11:00
|
|
|
return hit;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-08-22 16:07:16 -04:00
|
|
|
static bool pbvh_grids_node_nearest_to_ray(const SubdivCCG &subdiv_ccg,
|
2024-08-28 15:18:21 +02:00
|
|
|
GridsNode &node,
|
2024-09-04 11:07:18 -04:00
|
|
|
const Span<float3> node_positions,
|
2017-10-05 21:16:25 +11:00
|
|
|
const float ray_start[3],
|
|
|
|
|
const float ray_normal[3],
|
2024-09-20 06:50:54 +02:00
|
|
|
float *r_depth,
|
2017-10-05 21:16:25 +11:00
|
|
|
float *dist_sq)
|
|
|
|
|
{
|
2024-08-22 16:07:16 -04:00
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
2024-09-05 20:07:03 +02:00
|
|
|
const Span<int> grids = node.grids();
|
2024-09-04 11:07:18 -04:00
|
|
|
const int grid_size = key.grid_size;
|
2024-08-22 16:07:16 -04:00
|
|
|
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> positions = subdiv_ccg.positions;
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-09-04 11:07:18 -04:00
|
|
|
bool hit = false;
|
|
|
|
|
if (node_positions.is_empty()) {
|
|
|
|
|
for (const int grid : grids) {
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> grid_positions = positions.slice(bke::ccg::grid_range(key, grid));
|
2024-09-04 11:07:18 -04:00
|
|
|
for (const short y : IndexRange(grid_size - 1)) {
|
|
|
|
|
for (const short x : IndexRange(grid_size - 1)) {
|
|
|
|
|
if (!grid_hidden.is_empty()) {
|
|
|
|
|
if (paint_is_grid_face_hidden(grid_hidden[grid], grid_size, x, y)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-09-11 15:54:46 +02:00
|
|
|
hit |= ray_face_nearest_quad(
|
|
|
|
|
ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x, y)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x + 1, y + 1)],
|
|
|
|
|
grid_positions[CCG_grid_xy_to_index(grid_size, x, y + 1)],
|
2024-09-20 06:50:54 +02:00
|
|
|
r_depth,
|
2024-09-11 15:54:46 +02:00
|
|
|
dist_sq);
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (const int i : grids.index_range()) {
|
|
|
|
|
const int grid = grids[i];
|
2024-09-11 15:54:46 +02:00
|
|
|
const Span<float3> grid_positions = node_positions.slice(bke::ccg::grid_range(key, i));
|
2024-09-04 11:07:18 -04:00
|
|
|
for (const short y : IndexRange(grid_size - 1)) {
|
|
|
|
|
for (const short x : IndexRange(grid_size - 1)) {
|
|
|
|
|
if (!grid_hidden.is_empty()) {
|
|
|
|
|
if (paint_is_grid_face_hidden(grid_hidden[grid], grid_size, x, y)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
hit |= ray_face_nearest_quad(ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
grid_positions[y * grid_size + x],
|
|
|
|
|
grid_positions[y * grid_size + x + 1],
|
|
|
|
|
grid_positions[(y + 1) * grid_size + x + 1],
|
|
|
|
|
grid_positions[(y + 1) * grid_size + x],
|
2024-09-20 06:50:54 +02:00
|
|
|
r_depth,
|
2024-09-04 11:07:18 -04:00
|
|
|
dist_sq);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2017-10-05 21:16:25 +11:00
|
|
|
return hit;
|
|
|
|
|
}
|
2019-04-17 06:17:24 +02:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
bool find_nearest_to_ray_node(Tree &pbvh,
|
2024-07-23 23:15:49 -04:00
|
|
|
Node &node,
|
2024-09-04 11:07:18 -04:00
|
|
|
const Span<float3> node_positions,
|
2023-12-15 22:51:10 -05:00
|
|
|
bool use_origco,
|
2024-08-14 23:27:10 -04:00
|
|
|
const Span<float3> vert_positions,
|
2024-09-05 16:21:43 +02:00
|
|
|
const OffsetIndices<int> faces,
|
2023-12-15 22:51:10 -05:00
|
|
|
const Span<int> corner_verts,
|
2024-06-25 21:33:20 -04:00
|
|
|
const Span<int3> corner_tris,
|
2023-12-15 22:51:10 -05:00
|
|
|
const Span<bool> hide_poly,
|
2024-08-22 16:07:16 -04:00
|
|
|
const SubdivCCG *subdiv_ccg,
|
2023-12-15 22:51:10 -05:00
|
|
|
const float ray_start[3],
|
|
|
|
|
const float ray_normal[3],
|
|
|
|
|
float *depth,
|
|
|
|
|
float *dist_sq)
|
2017-10-05 21:16:25 +11:00
|
|
|
{
|
2024-07-23 23:15:49 -04:00
|
|
|
if (node.flag_ & PBVH_FullyHidden) {
|
2017-10-05 21:16:25 +11:00
|
|
|
return false;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
switch (pbvh.type()) {
|
|
|
|
|
case Type::Mesh:
|
2024-09-04 11:07:18 -04:00
|
|
|
return pbvh_faces_node_nearest_to_ray(static_cast<MeshNode &>(node),
|
|
|
|
|
node_positions,
|
2024-08-14 23:27:10 -04:00
|
|
|
vert_positions,
|
2024-09-05 16:21:43 +02:00
|
|
|
faces,
|
2024-04-29 17:20:55 -04:00
|
|
|
corner_verts,
|
2024-06-25 21:33:20 -04:00
|
|
|
corner_tris,
|
2024-04-29 17:20:55 -04:00
|
|
|
hide_poly,
|
|
|
|
|
ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
depth,
|
|
|
|
|
dist_sq);
|
2024-07-23 22:31:27 +02:00
|
|
|
case Type::Grids:
|
2024-09-04 11:07:18 -04:00
|
|
|
return pbvh_grids_node_nearest_to_ray(*subdiv_ccg,
|
2024-08-28 15:18:21 +02:00
|
|
|
static_cast<GridsNode &>(node),
|
2024-09-04 11:07:18 -04:00
|
|
|
node_positions,
|
2024-08-28 15:18:21 +02:00
|
|
|
ray_start,
|
|
|
|
|
ray_normal,
|
|
|
|
|
depth,
|
|
|
|
|
dist_sq);
|
2024-07-23 22:31:27 +02:00
|
|
|
case Type::BMesh:
|
2024-09-04 11:07:18 -04:00
|
|
|
return bmesh_node_nearest_to_ray(
|
2024-08-28 15:18:21 +02:00
|
|
|
static_cast<BMeshNode &>(node), ray_start, ray_normal, depth, dist_sq, use_origco);
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
2024-09-04 11:07:18 -04:00
|
|
|
BLI_assert_unreachable();
|
|
|
|
|
return false;
|
2017-10-05 21:16:25 +11:00
|
|
|
}
|
|
|
|
|
|
2023-02-05 16:56:37 -05:00
|
|
|
enum PlaneAABBIsect {
|
2012-03-14 06:32:25 +00:00
|
|
|
ISECT_INSIDE,
|
|
|
|
|
ISECT_OUTSIDE,
|
2019-04-16 16:40:47 +02:00
|
|
|
ISECT_INTERSECT,
|
2023-02-05 16:56:37 -05:00
|
|
|
};
|
2012-03-14 06:32:25 +00:00
|
|
|
|
2009-11-25 13:40:43 +00:00
|
|
|
/* Adapted from:
|
2012-03-03 20:19:11 +00:00
|
|
|
* http://www.gamedev.net/community/forums/topic.asp?topic_id=512123
|
|
|
|
|
* Returns true if the AABB is at least partially within the frustum
|
|
|
|
|
* (ok, not a real frustum), false otherwise.
|
|
|
|
|
*/
|
2023-12-04 11:25:07 -05:00
|
|
|
static PlaneAABBIsect test_frustum_aabb(const Bounds<float3> &bounds,
|
2023-12-03 17:37:57 -05:00
|
|
|
const PBVHFrustumPlanes *frustum)
|
2009-11-25 13:40:43 +00:00
|
|
|
{
|
2012-03-14 06:32:25 +00:00
|
|
|
PlaneAABBIsect ret = ISECT_INSIDE;
|
2023-12-03 17:37:57 -05:00
|
|
|
const float(*planes)[4] = frustum->planes;
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-09-27 14:44:45 +02:00
|
|
|
for (int i = 0; i < frustum->num_planes; i++) {
|
2019-09-27 14:23:10 +02:00
|
|
|
float vmin[3], vmax[3];
|
|
|
|
|
|
2019-09-08 00:12:26 +10:00
|
|
|
for (int axis = 0; axis < 3; axis++) {
|
2019-09-27 14:23:10 +02:00
|
|
|
if (planes[i][axis] < 0) {
|
2023-12-04 11:25:07 -05:00
|
|
|
vmin[axis] = bounds.min[axis];
|
|
|
|
|
vmax[axis] = bounds.max[axis];
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
else {
|
2023-12-04 11:25:07 -05:00
|
|
|
vmin[axis] = bounds.max[axis];
|
|
|
|
|
vmax[axis] = bounds.min[axis];
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
}
|
2018-06-17 17:05:51 +02:00
|
|
|
|
2019-09-27 14:23:10 +02:00
|
|
|
if (dot_v3v3(planes[i], vmin) + planes[i][3] < 0) {
|
2012-03-14 06:32:25 +00:00
|
|
|
return ISECT_OUTSIDE;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2020-08-07 12:30:43 +02:00
|
|
|
if (dot_v3v3(planes[i], vmax) + planes[i][3] <= 0) {
|
2012-03-14 06:32:25 +00:00
|
|
|
ret = ISECT_INTERSECT;
|
2019-04-22 09:39:35 +10:00
|
|
|
}
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2009-11-25 13:40:43 +00:00
|
|
|
|
2012-03-14 06:32:25 +00:00
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
bool BKE_pbvh_node_frustum_contain_AABB(const blender::bke::pbvh::Node *node,
|
|
|
|
|
const PBVHFrustumPlanes *data)
|
2012-03-14 06:32:25 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return blender::bke::pbvh::test_frustum_aabb(node->bounds_, data) !=
|
2023-12-15 22:51:10 -05:00
|
|
|
blender::bke::pbvh::ISECT_OUTSIDE;
|
2012-03-14 06:32:25 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
bool BKE_pbvh_node_frustum_exclude_AABB(const blender::bke::pbvh::Node *node,
|
|
|
|
|
const PBVHFrustumPlanes *data)
|
2012-03-14 06:32:25 +00:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return blender::bke::pbvh::test_frustum_aabb(node->bounds_, data) !=
|
2024-06-04 15:26:25 -04:00
|
|
|
blender::bke::pbvh::ISECT_INSIDE;
|
2009-11-25 13:40:43 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void BKE_pbvh_draw_debug_cb(blender::bke::pbvh::Tree &pbvh,
|
|
|
|
|
void (*draw_fn)(blender::bke::pbvh::Node *node,
|
2022-08-16 10:30:23 +10:00
|
|
|
void *user_data,
|
|
|
|
|
const float bmin[3],
|
|
|
|
|
const float bmax[3],
|
|
|
|
|
PBVHNodeFlags flag),
|
|
|
|
|
void *user_data)
|
2019-05-04 01:39:35 +02:00
|
|
|
{
|
2023-01-23 10:29:40 -08:00
|
|
|
PBVHNodeFlags flag = PBVH_Leaf;
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
std::visit(
|
|
|
|
|
[&](auto &nodes) {
|
|
|
|
|
for (blender::bke::pbvh::Node &node : nodes) {
|
|
|
|
|
if (node.flag_ & PBVH_TexLeaf) {
|
|
|
|
|
flag = PBVH_TexLeaf;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-23 10:29:40 -08:00
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
for (blender::bke::pbvh::Node &node : nodes) {
|
|
|
|
|
if (!(node.flag_ & flag)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
2023-01-23 10:29:40 -08:00
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
draw_fn(&node, user_data, node.bounds_.min, node.bounds_.max, node.flag_);
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2017-05-11 21:21:59 +10:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 23:21:40 -04:00
|
|
|
void BKE_pbvh_vert_coords_apply(blender::bke::pbvh::Tree &pbvh,
|
|
|
|
|
const blender::Span<blender::float3> vert_positions)
|
2010-06-21 20:10:59 +00:00
|
|
|
{
|
2023-12-14 14:56:25 -05:00
|
|
|
using namespace blender::bke::pbvh;
|
2024-09-13 21:31:08 +02:00
|
|
|
pbvh.tag_positions_changed(blender::IndexRange(pbvh.nodes_num()));
|
2024-08-22 21:00:25 +02:00
|
|
|
update_bounds_mesh(vert_positions, pbvh);
|
|
|
|
|
store_bounds_orig(pbvh);
|
2010-06-21 20:10:59 +00:00
|
|
|
}
|
2012-10-22 17:33:53 +00:00
|
|
|
|
2023-12-15 22:51:10 -05:00
|
|
|
namespace blender::bke::pbvh {
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void set_frustum_planes(Tree &pbvh, PBVHFrustumPlanes *planes)
|
2020-03-12 17:51:39 +01:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
pbvh.num_planes_ = planes->num_planes;
|
|
|
|
|
for (int i = 0; i < pbvh.num_planes_; i++) {
|
|
|
|
|
copy_v4_v4(pbvh.planes_[i], planes->planes[i]);
|
2020-03-12 17:51:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
void get_frustum_planes(const Tree &pbvh, PBVHFrustumPlanes *planes)
|
2020-03-12 17:51:39 +01:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
planes->num_planes = pbvh.num_planes_;
|
2020-03-12 17:51:39 +01:00
|
|
|
for (int i = 0; i < planes->num_planes; i++) {
|
2024-07-23 22:31:27 +02:00
|
|
|
copy_v4_v4(planes->planes[i], pbvh.planes_[i]);
|
2020-03-12 17:51:39 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
static Span<float3> vert_positions_eval(const Object &object_orig, const Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
const SculptSession &ss = *object_orig.sculpt;
|
|
|
|
|
const Mesh &mesh_orig = *static_cast<const Mesh *>(object_orig.data);
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(bke::object::pbvh_get(object_orig)->type() == Type::Mesh);
|
2024-08-22 21:00:25 +02:00
|
|
|
if (object_orig.mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(&object_eval)) {
|
|
|
|
|
if (mesh_topology_count_matches(*mesh_eval, mesh_orig)) {
|
|
|
|
|
return mesh_eval->vert_positions();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(&object_eval)) {
|
|
|
|
|
return mesh_eval->vert_positions();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ss.deform_cos.is_empty()) {
|
|
|
|
|
BLI_assert(ss.deform_cos.size() == mesh_orig.verts_num);
|
|
|
|
|
return ss.deform_cos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mesh_orig.vert_positions();
|
|
|
|
|
}
|
|
|
|
|
static MutableSpan<float3> vert_positions_eval_for_write(Object &object_orig, Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
SculptSession &ss = *object_orig.sculpt;
|
|
|
|
|
Mesh &mesh_orig = *static_cast<Mesh *>(object_orig.data);
|
2024-09-05 14:16:28 -04:00
|
|
|
BLI_assert(bke::object::pbvh_get(object_orig)->type() == Type::Mesh);
|
2024-08-22 21:00:25 +02:00
|
|
|
if (object_orig.mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT)) {
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(&object_eval)) {
|
|
|
|
|
if (mesh_topology_count_matches(*mesh_eval, mesh_orig)) {
|
|
|
|
|
Mesh *mesh_eval_mut = const_cast<Mesh *>(mesh_eval);
|
|
|
|
|
return mesh_eval_mut->vert_positions_for_write();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (const Mesh *mesh_eval = BKE_object_get_mesh_deform_eval(&object_eval)) {
|
|
|
|
|
Mesh *mesh_eval_mut = const_cast<Mesh *>(mesh_eval);
|
|
|
|
|
return mesh_eval_mut->vert_positions_for_write();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!ss.deform_cos.is_empty()) {
|
|
|
|
|
BLI_assert(ss.deform_cos.size() == mesh_orig.verts_num);
|
|
|
|
|
return ss.deform_cos;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mesh_orig.vert_positions_for_write();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Span<float3> vert_positions_eval(const Depsgraph &depsgraph, const Object &object_orig)
|
2020-02-28 15:58:04 +01:00
|
|
|
{
|
2024-08-22 21:00:25 +02:00
|
|
|
const Object &object_eval = *DEG_get_evaluated_object(&depsgraph,
|
|
|
|
|
&const_cast<Object &>(object_orig));
|
|
|
|
|
return vert_positions_eval(object_orig, object_eval);
|
2020-02-28 15:58:04 +01:00
|
|
|
}
|
2020-04-01 01:03:20 +02:00
|
|
|
|
2024-08-15 15:43:17 -04:00
|
|
|
Span<float3> vert_positions_eval_from_eval(const Object &object_eval)
|
|
|
|
|
{
|
2024-08-16 06:50:16 +02:00
|
|
|
BLI_assert(!DEG_is_original_object(&object_eval));
|
2024-08-22 21:00:25 +02:00
|
|
|
const Object &object_orig = *DEG_get_original_object(&const_cast<Object &>(object_eval));
|
|
|
|
|
return vert_positions_eval(object_orig, object_eval);
|
2024-08-15 15:43:17 -04:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
MutableSpan<float3> vert_positions_eval_for_write(const Depsgraph &depsgraph, Object &object_orig)
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
{
|
2024-08-22 21:00:25 +02:00
|
|
|
Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object_orig);
|
|
|
|
|
return vert_positions_eval_for_write(object_orig, object_eval);
|
2023-12-03 23:43:13 -05:00
|
|
|
}
|
|
|
|
|
|
2024-08-22 21:00:25 +02:00
|
|
|
Span<float3> vert_normals_eval(const Depsgraph &depsgraph, const Object &object_orig)
|
2023-12-03 23:43:13 -05:00
|
|
|
{
|
2024-08-22 21:00:25 +02:00
|
|
|
const Object &object_eval = *DEG_get_evaluated_object(&depsgraph,
|
|
|
|
|
&const_cast<Object &>(object_orig));
|
|
|
|
|
return vert_normals_cache_eval(object_orig, object_eval).data();
|
Refactor: Move normals out of MVert, lazy calculation
As described in T91186, this commit moves mesh vertex normals into a
contiguous array of float vectors in a custom data layer, how face
normals are currently stored.
The main interface is documented in `BKE_mesh.h`. Vertex and face
normals are now calculated on-demand and cached, retrieved with an
"ensure" function. Since the logical state of a mesh is now "has
normals when necessary", they can be retrieved from a `const` mesh.
The goal is to use on-demand calculation for all derived data, but
leave room for eager calculation for performance purposes (modifier
evaluation is threaded, but viewport data generation is not).
**Benefits**
This moves us closer to a SoA approach rather than the current AoS
paradigm. Accessing a contiguous `float3` is much more efficient than
retrieving data from a larger struct. The memory requirements for
accessing only normals or vertex locations are smaller, and at the
cost of more memory usage for just normals, they now don't have to
be converted between float and short, which also simplifies code
In the future, the remaining items can be removed from `MVert`,
leaving only `float3`, which has similar benefits (see T93602).
Removing the combination of derived and original data makes it
conceptually simpler to only calculate normals when necessary.
This is especially important now that we have more opportunities
for temporary meshes in geometry nodes.
**Performance**
In addition to the theoretical future performance improvements by
making `MVert == float3`, I've done some basic performance testing
on this patch directly. The data is fairly rough, but it gives an idea
about where things stand generally.
- Mesh line primitive 4m Verts: 1.16x faster (36 -> 31 ms),
showing that accessing just `MVert` is now more efficient.
- Spring Splash Screen: 1.03-1.06 -> 1.06-1.11 FPS, a very slight
change that at least shows there is no regression.
- Sprite Fright Snail Smoosh: 3.30-3.40 -> 3.42-3.50 FPS, a small
but observable speedup.
- Set Position Node with Scaled Normal: 1.36x faster (53 -> 39 ms),
shows that using normals in geometry nodes is faster.
- Normal Calculation 1.6m Vert Cube: 1.19x faster (25 -> 21 ms),
shows that calculating normals is slightly faster now.
- File Size of 1.6m Vert Cube: 1.03x smaller (214.7 -> 208.4 MB),
Normals are not saved in files, which can help with large meshes.
As for memory usage, it may be slightly more in some cases, but
I didn't observe any difference in the production files I tested.
**Tests**
Some modifiers and cycles test results need to be updated with this
commit, for two reasons:
- The subdivision surface modifier is not responsible for calculating
normals anymore. In master, the modifier creates different normals
than the result of the `Mesh` normal calculation, so this is a bug
fix.
- There are small differences in the results of some modifiers that
use normals because they are not converted to and from `short`
anymore.
**Future improvements**
- Remove `ModifierTypeInfo::dependsOnNormals`. Code in each modifier
already retrieves normals if they are needed anyway.
- Copy normals as part of a better CoW system for attributes.
- Make more areas use lazy instead of eager normal calculation.
- Remove `BKE_mesh_normals_tag_dirty` in more places since that is
now the default state of a new mesh.
- Possibly apply a similar change to derived face corner normals.
Differential Revision: https://developer.blender.org/D12770
2022-01-13 14:37:58 -06:00
|
|
|
}
|
|
|
|
|
|
2024-08-15 15:43:17 -04:00
|
|
|
Span<float3> vert_normals_eval_from_eval(const Object &object_eval)
|
|
|
|
|
{
|
2024-08-16 06:50:16 +02:00
|
|
|
BLI_assert(!DEG_is_original_object(&object_eval));
|
2024-08-15 15:43:17 -04:00
|
|
|
Object &object_orig = *DEG_get_original_object(&const_cast<Object &>(object_eval));
|
2024-08-22 21:00:25 +02:00
|
|
|
return vert_normals_cache_eval(object_orig, object_eval).data();
|
2024-08-15 15:43:17 -04:00
|
|
|
}
|
|
|
|
|
|
Sculpt: Restructure PBVH drawing to avoid overhead
This commit rewrites the PBVH drawing using many of the principles from the
ongoing sculpt refactor. First of all, per BVH node overhead is minimized.
Previously the main entry point to the drawing API was per node, so there
was significant overhead fetching global data and maintaining caches on
a per-node basis. Now all of that "global" work happens for the entire
geometry.
We also now avoid creating wireframe index buffers and batches unless
the viewport actually requests wireframe data. This was theoretically
possible before, but the whole logic flow was so convoluted that the
optimization was too difficult. Similarly, multithreading is used more
consistently now. Because of OpenGL, flushing vertex/index buffers to
the GPU has to happen on the main thread, but everything else can be
multithreaded. With outer loops processing all relevant PBVH nodes,
it's now trivial to apply multithreading wherever possible.
Testing performance, overall this commit results in a 10% improvement in
the time between opening a file with a large mesh sculpt and the first
possible interaction. Specifically I measured a change from 8.4 to 7.6
seconds on a completely visible 16 million vertex mesh with a Ryzen 7950x.
I also measured a decrease in memory usage from 4.79 to 4.31 GB.
For multires I observed a similar improvement in memory usage,
though less of a performance improvement.
There are still significant opportunities for future improvement. #122775
would be particularly helpful. #99983 would be helpful too, though more
complicated, and #97665 describes the problems a bit more generally.
Part of #118145.
Pull Request: https://projects.blender.org/blender/blender/pulls/127002
2024-09-04 17:40:50 +02:00
|
|
|
Span<float3> face_normals_eval_from_eval(const Object &object_eval)
|
|
|
|
|
{
|
|
|
|
|
BLI_assert(!DEG_is_original_object(&object_eval));
|
|
|
|
|
Object &object_orig = *DEG_get_original_object(&const_cast<Object &>(object_eval));
|
|
|
|
|
return face_normals_cache_eval(object_orig, object_eval).data();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-15 17:07:36 +02:00
|
|
|
} // namespace blender::bke::pbvh
|
|
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
int BKE_pbvh_debug_draw_gen_get(blender::bke::pbvh::Node &node)
|
2022-08-15 17:01:17 -07:00
|
|
|
{
|
2024-07-23 22:31:27 +02:00
|
|
|
return node.debug_draw_gen_;
|
2022-08-15 17:01:17 -07:00
|
|
|
}
|
2022-11-20 08:08:26 -08:00
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
void BKE_pbvh_sync_visibility_from_verts(Object &object)
|
2022-11-22 11:11:03 -08:00
|
|
|
{
|
2023-08-23 22:02:23 -04:00
|
|
|
using namespace blender;
|
|
|
|
|
using namespace blender::bke;
|
2024-08-13 16:25:08 -04:00
|
|
|
const SculptSession &ss = *object.sculpt;
|
2024-09-05 14:16:28 -04:00
|
|
|
switch (object::pbvh_get(object)->type()) {
|
2024-07-23 22:31:27 +02:00
|
|
|
case blender::bke::pbvh::Type::Mesh: {
|
2024-08-13 16:25:08 -04:00
|
|
|
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
|
|
|
|
mesh_hide_vert_flush(mesh);
|
2022-11-22 11:11:03 -08:00
|
|
|
break;
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
case blender::bke::pbvh::Type::BMesh: {
|
2024-08-13 16:25:08 -04:00
|
|
|
BMesh &bm = *ss.bm;
|
2022-11-22 11:11:03 -08:00
|
|
|
BMIter iter;
|
|
|
|
|
BMVert *v;
|
|
|
|
|
BMEdge *e;
|
|
|
|
|
BMFace *f;
|
|
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
BM_ITER_MESH (f, &iter, &bm, BM_FACES_OF_MESH) {
|
2022-11-22 11:11:03 -08:00
|
|
|
BM_elem_flag_disable(f, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
BM_ITER_MESH (e, &iter, &bm, BM_EDGES_OF_MESH) {
|
2022-11-22 11:11:03 -08:00
|
|
|
BM_elem_flag_disable(e, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
BM_ITER_MESH (v, &iter, &bm, BM_VERTS_OF_MESH) {
|
2022-11-22 11:11:03 -08:00
|
|
|
if (!BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
BMIter iter_l;
|
|
|
|
|
BMLoop *l;
|
|
|
|
|
|
|
|
|
|
BM_ITER_ELEM (l, &iter_l, v, BM_LOOPS_OF_VERT) {
|
|
|
|
|
BM_elem_flag_enable(l->e, BM_ELEM_HIDDEN);
|
|
|
|
|
BM_elem_flag_enable(l->f, BM_ELEM_HIDDEN);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
2024-07-23 22:31:27 +02:00
|
|
|
case blender::bke::pbvh::Type::Grids: {
|
2024-08-13 16:25:08 -04:00
|
|
|
Mesh &mesh = *static_cast<Mesh *>(object.data);
|
|
|
|
|
const SubdivCCG &subdiv_ccg = *ss.subdiv_ccg;
|
|
|
|
|
const BitGroupVector<> &grid_hidden = subdiv_ccg.grid_hidden;
|
|
|
|
|
const CCGKey key = BKE_subdiv_ccg_key_top_level(subdiv_ccg);
|
|
|
|
|
const OffsetIndices faces = mesh.faces();
|
2022-11-22 11:11:03 -08:00
|
|
|
|
2023-08-23 22:02:23 -04:00
|
|
|
IndexMaskMemory memory;
|
2023-12-02 20:05:29 +01:00
|
|
|
const IndexMask hidden_faces =
|
2024-05-06 23:04:35 +02:00
|
|
|
!grid_hidden.is_empty() ?
|
2023-12-02 20:05:29 +01:00
|
|
|
IndexMask::from_predicate(faces.index_range(),
|
|
|
|
|
GrainSize(1024),
|
|
|
|
|
memory,
|
|
|
|
|
[&](const int i) {
|
|
|
|
|
const IndexRange face = faces[i];
|
|
|
|
|
return std::any_of(
|
|
|
|
|
face.begin(), face.end(), [&](const int corner) {
|
|
|
|
|
return grid_hidden[corner][key.grid_area - 1];
|
|
|
|
|
});
|
|
|
|
|
}) :
|
|
|
|
|
IndexMask();
|
2022-11-22 11:11:03 -08:00
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
MutableAttributeAccessor attributes = mesh.attributes_for_write();
|
2023-08-23 22:02:23 -04:00
|
|
|
if (hidden_faces.is_empty()) {
|
|
|
|
|
attributes.remove(".hide_poly");
|
2022-11-22 11:11:03 -08:00
|
|
|
}
|
2023-08-23 22:02:23 -04:00
|
|
|
else {
|
|
|
|
|
SpanAttributeWriter<bool> hide_poly = attributes.lookup_or_add_for_write_span<bool>(
|
2023-12-20 13:13:16 -05:00
|
|
|
".hide_poly", AttrDomain::Face, AttributeInitConstruct());
|
2023-08-23 22:02:23 -04:00
|
|
|
hide_poly.span.fill(false);
|
|
|
|
|
index_mask::masked_fill(hide_poly.span, true, hidden_faces);
|
|
|
|
|
hide_poly.finish();
|
2022-11-22 11:11:03 -08:00
|
|
|
}
|
|
|
|
|
|
2024-08-13 16:25:08 -04:00
|
|
|
mesh_hide_face_flush(mesh);
|
2022-11-22 11:11:03 -08:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-04-14 21:16:42 +02:00
|
|
|
|
|
|
|
|
namespace blender::bke::pbvh {
|
2024-08-22 23:37:10 +02:00
|
|
|
|
2024-08-29 19:34:22 +02:00
|
|
|
IndexMask all_leaf_nodes(const Tree &pbvh, IndexMaskMemory &memory)
|
2024-08-22 23:37:10 +02:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
return std::visit(
|
2024-08-29 19:34:22 +02:00
|
|
|
[&](const auto &nodes) {
|
|
|
|
|
return IndexMask::from_predicate(
|
|
|
|
|
nodes.index_range(), GrainSize(1024), memory, [&](const int i) {
|
|
|
|
|
return (nodes[i].flag_ & PBVH_Leaf) != 0;
|
|
|
|
|
});
|
2024-08-28 15:18:21 +02:00
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
2024-08-22 23:37:10 +02:00
|
|
|
}
|
|
|
|
|
|
Sculpt: Restructure PBVH drawing to avoid overhead
This commit rewrites the PBVH drawing using many of the principles from the
ongoing sculpt refactor. First of all, per BVH node overhead is minimized.
Previously the main entry point to the drawing API was per node, so there
was significant overhead fetching global data and maintaining caches on
a per-node basis. Now all of that "global" work happens for the entire
geometry.
We also now avoid creating wireframe index buffers and batches unless
the viewport actually requests wireframe data. This was theoretically
possible before, but the whole logic flow was so convoluted that the
optimization was too difficult. Similarly, multithreading is used more
consistently now. Because of OpenGL, flushing vertex/index buffers to
the GPU has to happen on the main thread, but everything else can be
multithreaded. With outer loops processing all relevant PBVH nodes,
it's now trivial to apply multithreading wherever possible.
Testing performance, overall this commit results in a 10% improvement in
the time between opening a file with a large mesh sculpt and the first
possible interaction. Specifically I measured a change from 8.4 to 7.6
seconds on a completely visible 16 million vertex mesh with a Ryzen 7950x.
I also measured a decrease in memory usage from 4.79 to 4.31 GB.
For multires I observed a similar improvement in memory usage,
though less of a performance improvement.
There are still significant opportunities for future improvement. #122775
would be particularly helpful. #99983 would be helpful too, though more
complicated, and #97665 describes the problems a bit more generally.
Part of #118145.
Pull Request: https://projects.blender.org/blender/blender/pulls/127002
2024-09-04 17:40:50 +02:00
|
|
|
static Vector<Node *> search_gather(Tree &pbvh,
|
|
|
|
|
const FunctionRef<bool(Node &)> scb,
|
|
|
|
|
PBVHNodeFlags leaf_flag)
|
2023-04-14 21:16:42 +02:00
|
|
|
{
|
2024-08-28 15:18:21 +02:00
|
|
|
if (tree_is_empty(pbvh)) {
|
2023-08-22 12:29:36 -04:00
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 21:16:42 +02:00
|
|
|
PBVHIter iter;
|
2024-07-23 22:31:27 +02:00
|
|
|
Vector<Node *> nodes;
|
2023-04-14 21:16:42 +02:00
|
|
|
|
2023-08-22 15:05:37 -04:00
|
|
|
pbvh_iter_begin(&iter, pbvh, scb);
|
2023-04-14 21:16:42 +02:00
|
|
|
|
2024-07-23 22:31:27 +02:00
|
|
|
Node *node;
|
2023-04-14 21:16:42 +02:00
|
|
|
while ((node = pbvh_iter_next(&iter, leaf_flag))) {
|
2024-07-23 22:31:27 +02:00
|
|
|
if (node->flag_ & leaf_flag) {
|
2023-04-14 21:16:42 +02:00
|
|
|
nodes.append(node);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nodes;
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-28 15:18:21 +02:00
|
|
|
IndexMask search_nodes(const Tree &pbvh,
|
|
|
|
|
IndexMaskMemory &memory,
|
|
|
|
|
FunctionRef<bool(const Node &)> filter_fn)
|
|
|
|
|
{
|
Sculpt: Restructure PBVH drawing to avoid overhead
This commit rewrites the PBVH drawing using many of the principles from the
ongoing sculpt refactor. First of all, per BVH node overhead is minimized.
Previously the main entry point to the drawing API was per node, so there
was significant overhead fetching global data and maintaining caches on
a per-node basis. Now all of that "global" work happens for the entire
geometry.
We also now avoid creating wireframe index buffers and batches unless
the viewport actually requests wireframe data. This was theoretically
possible before, but the whole logic flow was so convoluted that the
optimization was too difficult. Similarly, multithreading is used more
consistently now. Because of OpenGL, flushing vertex/index buffers to
the GPU has to happen on the main thread, but everything else can be
multithreaded. With outer loops processing all relevant PBVH nodes,
it's now trivial to apply multithreading wherever possible.
Testing performance, overall this commit results in a 10% improvement in
the time between opening a file with a large mesh sculpt and the first
possible interaction. Specifically I measured a change from 8.4 to 7.6
seconds on a completely visible 16 million vertex mesh with a Ryzen 7950x.
I also measured a decrease in memory usage from 4.79 to 4.31 GB.
For multires I observed a similar improvement in memory usage,
though less of a performance improvement.
There are still significant opportunities for future improvement. #122775
would be particularly helpful. #99983 would be helpful too, though more
complicated, and #97665 describes the problems a bit more generally.
Part of #118145.
Pull Request: https://projects.blender.org/blender/blender/pulls/127002
2024-09-04 17:40:50 +02:00
|
|
|
Vector<Node *> nodes = search_gather(
|
|
|
|
|
const_cast<Tree &>(pbvh), [&](Node &node) { return filter_fn(node); }, PBVH_Leaf);
|
2024-08-28 15:18:21 +02:00
|
|
|
Array<int> indices(nodes.size());
|
|
|
|
|
std::visit(
|
|
|
|
|
[&](const auto &pbvh_nodes) {
|
|
|
|
|
using VectorT = std::decay_t<decltype(pbvh_nodes)>;
|
|
|
|
|
for (const int i : nodes.index_range()) {
|
|
|
|
|
indices[i] = static_cast<typename VectorT::value_type *>(nodes[i]) - pbvh_nodes.data();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
pbvh.nodes_);
|
|
|
|
|
std::sort(indices.begin(), indices.end());
|
|
|
|
|
return IndexMask::from_indices(indices.as_span(), memory);
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-14 21:16:42 +02:00
|
|
|
} // namespace blender::bke::pbvh
|