diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 3c03d679771..1a0cbf7a801 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1660,7 +1660,7 @@ static void sculpt_update_persistent_base(Object *ob) } static void sculpt_update_object( - Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool need_pmap, bool is_paint_tool) + Depsgraph *depsgraph, Object *ob, Object *ob_eval, bool /*need_pmap*/, bool is_paint_tool) { Scene *scene = DEG_get_input_scene(depsgraph); Sculpt *sd = scene->toolsettings->sculpt; @@ -1766,13 +1766,13 @@ static void sculpt_update_object( sculpt_attribute_update_refs(ob); sculpt_update_persistent_base(ob); - if (need_pmap && ob->type == OB_MESH && !ss->pmap) { + if (ob->type == OB_MESH && !ss->pmap) { BKE_mesh_vert_poly_map_create( &ss->pmap, &ss->pmap_mem, me->polys(), me->corner_verts().data(), me->totvert); + } - if (ss->pbvh) { - BKE_pbvh_pmap_set(ss->pbvh, ss->pmap); - } + if (ss->pbvh) { + BKE_pbvh_pmap_set(ss->pbvh, ss->pmap); } if (ss->deform_modifiers_active) { diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index 513d8563ecc..fbcaf838735 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -11,10 +11,13 @@ #include "BLI_bitmap.h" #include "BLI_ghash.h" #include "BLI_math.h" +#include "BLI_math_vector.hh" #include "BLI_rand.h" #include "BLI_task.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLI_vector.hh" +#include "BLI_vector_set.hh" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -862,7 +865,10 @@ void BKE_pbvh_update_mesh_pointers(PBVH *pbvh, Mesh *mesh) /* Make sure cached normals start out calculated. */ mesh->vert_normals(); + mesh->poly_normals(); + pbvh->vert_normals = BKE_mesh_vert_normals_for_write(mesh); + pbvh->poly_normals = mesh->runtime->poly_normals; pbvh->vdata = &mesh->vdata; pbvh->ldata = &mesh->ldata; @@ -1367,7 +1373,6 @@ struct PBVHUpdateData { PBVH *pbvh; Span nodes; - float (*vert_normals)[3] = nullptr; int flag = 0; bool show_sculpt_face_sets = false; PBVHAttrReq *attrs = nullptr; @@ -1376,133 +1381,66 @@ struct PBVHUpdateData { PBVHUpdateData(PBVH *pbvh_, Span nodes_) : pbvh(pbvh_), nodes(nodes_) {} }; -static void pbvh_update_normals_clear_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict /*tls*/) -{ - PBVHUpdateData *data = static_cast(userdata); - PBVH *pbvh = data->pbvh; - PBVHNode *node = data->nodes[n]; - float(*vert_normals)[3] = data->vert_normals; - - if (node->flag & PBVH_UpdateNormals) { - const int *verts = node->vert_indices; - const int totvert = node->uniq_verts; - for (int i = 0; i < totvert; i++) { - const int v = verts[i]; - if (pbvh->vert_bitmap[v]) { - zero_v3(vert_normals[v]); - } - } - } -} - -static void pbvh_update_normals_accum_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict /*tls*/) -{ - PBVHUpdateData *data = static_cast(userdata); - - PBVH *pbvh = data->pbvh; - PBVHNode *node = data->nodes[n]; - float(*vert_normals)[3] = data->vert_normals; - - if (node->flag & PBVH_UpdateNormals) { - uint mpoly_prev = UINT_MAX; - blender::float3 fn; - - const int *faces = node->prim_indices; - const int totface = node->totprim; - - for (int i = 0; i < totface; i++) { - const int tri_index = faces[i]; - const int poly_index = pbvh->looptri_polys[tri_index]; - const MLoopTri *lt = &pbvh->looptri[faces[i]]; - const int vtri[3] = { - pbvh->corner_verts[lt->tri[0]], - pbvh->corner_verts[lt->tri[1]], - pbvh->corner_verts[lt->tri[2]], - }; - const int sides = 3; - - /* Face normal and mask */ - if (poly_index != mpoly_prev) { - const blender::IndexRange poly = pbvh->polys[poly_index]; - fn = blender::bke::mesh::poly_normal_calc( - {reinterpret_cast(pbvh->vert_positions), pbvh->totvert}, - {&pbvh->corner_verts[poly.start()], poly.size()}); - mpoly_prev = poly_index; - } - - for (int j = sides; j--;) { - const int v = vtri[j]; - - if (pbvh->vert_bitmap[v]) { - /* NOTE: This avoids `lock, add_v3_v3, unlock` - * and is five to ten times quicker than a spin-lock. - * Not exact equivalent though, since atomicity is only ensured for one component - * of the vector at a time, but here it shall not make any sensible difference. */ - for (int k = 3; k--;) { - atomic_add_and_fetch_fl(&vert_normals[v][k], fn[k]); - } - } - } - } - } -} - -static void pbvh_update_normals_store_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict /*tls*/) -{ - PBVHUpdateData *data = static_cast(userdata); - PBVH *pbvh = data->pbvh; - PBVHNode *node = data->nodes[n]; - float(*vert_normals)[3] = data->vert_normals; - - if (node->flag & PBVH_UpdateNormals) { - const int *verts = node->vert_indices; - const int totvert = node->uniq_verts; - - for (int i = 0; i < totvert; i++) { - const int v = verts[i]; - - /* No atomics necessary because we are iterating over uniq_verts only, - * so we know only this thread will handle this vertex. */ - if (pbvh->vert_bitmap[v]) { - normalize_v3(vert_normals[v]); - pbvh->vert_bitmap[v] = false; - } - } - - node->flag &= ~PBVH_UpdateNormals; - } -} - static void pbvh_faces_update_normals(PBVH *pbvh, Span nodes) { - /* subtle assumptions: - * - We know that for all edited vertices, the nodes with faces - * adjacent to these vertices have been marked with PBVH_UpdateNormals. - * This is true because if the vertex is inside the brush radius, the - * bounding box of its adjacent faces will be as well. - * - However this is only true for the vertices that have actually been - * edited, not for all vertices in the nodes marked for update, so we - * can only update vertices marked in the `vert_bitmap`. - */ + using namespace blender; + using namespace blender::bke; + const Span positions(reinterpret_cast(pbvh->vert_positions), + pbvh->totvert); + const OffsetIndices polys = pbvh->polys; + const Span corner_verts(pbvh->corner_verts, pbvh->mesh->totloop); - PBVHUpdateData data(pbvh, nodes); - data.pbvh = pbvh; - data.nodes = nodes; - data.vert_normals = pbvh->vert_normals; + MutableSpan update_tags(pbvh->vert_bitmap, pbvh->totvert); - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, nodes.size()); + VectorSet polys_to_update; + for (const PBVHNode *node : nodes) { + for (const int vert : Span(node->vert_indices, node->uniq_verts)) { + if (update_tags[vert]) { + polys_to_update.add_multiple({pbvh->pmap[vert].indices, pbvh->pmap[vert].count}); + } + } + } - /* Zero normals before accumulation. */ - BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_clear_task_cb, &settings); - BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_accum_task_cb, &settings); - BLI_task_parallel_range(0, nodes.size(), &data, pbvh_update_normals_store_task_cb, &settings); + if (polys_to_update.is_empty()) { + return; + } + + MutableSpan vert_normals(reinterpret_cast(pbvh->vert_normals), pbvh->totvert); + MutableSpan poly_normals = pbvh->poly_normals; + + VectorSet verts_to_update; + threading::parallel_invoke( + [&]() { + threading::parallel_for(polys_to_update.index_range(), 512, [&](const IndexRange range) { + for (const int i : polys_to_update.as_span().slice(range)) { + poly_normals[i] = mesh::poly_normal_calc(positions, corner_verts.slice(polys[i])); + } + }); + }, + [&]() { + /* Update all normals connected to affected faces faces, even if not explicitly tagged. */ + verts_to_update.reserve(polys_to_update.size()); + for (const int poly : polys_to_update) { + verts_to_update.add_multiple(corner_verts.slice(polys[poly])); + } + + for (const int vert : verts_to_update) { + update_tags[vert] = false; + } + for (PBVHNode *node : nodes) { + node->flag &= ~PBVH_UpdateNormals; + } + }); + + threading::parallel_for(verts_to_update.index_range(), 1024, [&](const IndexRange range) { + for (const int vert : verts_to_update.as_span().slice(range)) { + float3 normal(0.0f); + for (const int poly : Span(pbvh->pmap[vert].indices, pbvh->pmap[vert].count)) { + normal += poly_normals[poly]; + } + vert_normals[vert] = math::normalize(normal); + } + }); } static void pbvh_update_mask_redraw_task_cb(void *__restrict userdata, diff --git a/source/blender/blenkernel/intern/pbvh_intern.hh b/source/blender/blenkernel/intern/pbvh_intern.hh index 3b810d6f6de..f867907530c 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.hh +++ b/source/blender/blenkernel/intern/pbvh_intern.hh @@ -3,6 +3,8 @@ #pragma once #include "BLI_vector.hh" +#include "BLI_math_vector_types.hh" +#include "BLI_span.hh" /** \file * \ingroup bke @@ -155,6 +157,7 @@ struct PBVH { /* NOTE: Normals are not `const` because they can be updated for drawing by sculpt code. */ float (*vert_normals)[3]; + blender::MutableSpan poly_normals; bool *hide_vert; float (*vert_positions)[3]; blender::OffsetIndices polys;