Sculpt: Reuse existing mesh triangles cache in sculpt mode #123638
@ -94,6 +94,19 @@ struct LooseEdgeCache : public LooseGeomCache {};
|
|||||||
*/
|
*/
|
||||||
struct LooseVertCache : public LooseGeomCache {};
|
struct LooseVertCache : public LooseGeomCache {};
|
||||||
|
|
||||||
|
struct TrianglesCache {
|
||||||
|
SharedCache<Array<int3>> data;
|
||||||
|
bool frozen = false;
|
||||||
|
bool dirty_while_frozen = false;
|
||||||
|
|
||||||
|
/** Delay applying dirty tags from #tag_dirty() until #unfreeze is called. */
|
||||||
|
void freeze();
|
||||||
|
/** Apply dirty tags from after #freeze, and make future dirty tags apply immediately. */
|
||||||
|
void unfreeze();
|
||||||
|
/** Call instead of `data.tag_dirty()`. */
|
||||||
|
void tag_dirty();
|
||||||
|
};
|
||||||
|
|
||||||
struct MeshRuntime {
|
struct MeshRuntime {
|
||||||
/**
|
/**
|
||||||
* "Evaluated" mesh owned by this mesh. Used for objects which don't have effective modifiers, so
|
* "Evaluated" mesh owned by this mesh. Used for objects which don't have effective modifiers, so
|
||||||
@ -141,7 +154,7 @@ struct MeshRuntime {
|
|||||||
void *batch_cache = nullptr;
|
void *batch_cache = nullptr;
|
||||||
|
|
||||||
/** Cache for derived triangulation of the mesh, accessed with #Mesh::corner_tris(). */
|
/** Cache for derived triangulation of the mesh, accessed with #Mesh::corner_tris(). */
|
||||||
SharedCache<Array<int3>> corner_tris_cache;
|
TrianglesCache corner_tris_cache;
|
||||||
/** Cache for triangle to original face index map, accessed with #Mesh::corner_tri_faces(). */
|
/** Cache for triangle to original face index map, accessed with #Mesh::corner_tri_faces(). */
|
||||||
SharedCache<Array<int>> corner_tri_faces_cache;
|
SharedCache<Array<int>> corner_tri_faces_cache;
|
||||||
|
|
||||||
|
@ -226,9 +226,38 @@ void Mesh::tag_overlapping_none()
|
|||||||
this->flag |= ME_NO_OVERLAPPING_TOPOLOGY;
|
this->flag |= ME_NO_OVERLAPPING_TOPOLOGY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace blender::bke {
|
||||||
|
|
||||||
|
void TrianglesCache::freeze()
|
||||||
|
{
|
||||||
|
this->frozen = true;
|
||||||
|
this->dirty_while_frozen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrianglesCache::unfreeze()
|
||||||
|
{
|
||||||
|
this->frozen = false;
|
||||||
|
if (this->dirty_while_frozen) {
|
||||||
|
this->data.tag_dirty();
|
||||||
|
}
|
||||||
|
this->dirty_while_frozen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TrianglesCache::tag_dirty()
|
||||||
|
{
|
||||||
|
if (this->frozen) {
|
||||||
|
this->dirty_while_frozen = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this->data.tag_dirty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace blender::bke
|
||||||
|
|
||||||
blender::Span<blender::int3> Mesh::corner_tris() const
|
blender::Span<blender::int3> Mesh::corner_tris() const
|
||||||
{
|
{
|
||||||
this->runtime->corner_tris_cache.ensure([&](blender::Array<blender::int3> &r_data) {
|
this->runtime->corner_tris_cache.data.ensure([&](blender::Array<blender::int3> &r_data) {
|
||||||
const Span<float3> positions = this->vert_positions();
|
const Span<float3> positions = this->vert_positions();
|
||||||
const blender::OffsetIndices faces = this->faces();
|
const blender::OffsetIndices faces = this->faces();
|
||||||
const Span<int> corner_verts = this->corner_verts();
|
const Span<int> corner_verts = this->corner_verts();
|
||||||
@ -244,7 +273,7 @@ blender::Span<blender::int3> Mesh::corner_tris() const
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return this->runtime->corner_tris_cache.data();
|
return this->runtime->corner_tris_cache.data.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
blender::Span<int> Mesh::corner_tri_faces() const
|
blender::Span<int> Mesh::corner_tri_faces() const
|
||||||
@ -296,7 +325,7 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
|
|||||||
mesh->runtime->loose_edges_cache.tag_dirty();
|
mesh->runtime->loose_edges_cache.tag_dirty();
|
||||||
mesh->runtime->loose_verts_cache.tag_dirty();
|
mesh->runtime->loose_verts_cache.tag_dirty();
|
||||||
mesh->runtime->verts_no_face_cache.tag_dirty();
|
mesh->runtime->verts_no_face_cache.tag_dirty();
|
||||||
mesh->runtime->corner_tris_cache.tag_dirty();
|
mesh->runtime->corner_tris_cache.data.tag_dirty();
|
||||||
mesh->runtime->corner_tri_faces_cache.tag_dirty();
|
mesh->runtime->corner_tri_faces_cache.tag_dirty();
|
||||||
mesh->runtime->shrinkwrap_boundary_cache.tag_dirty();
|
mesh->runtime->shrinkwrap_boundary_cache.tag_dirty();
|
||||||
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
|
mesh->runtime->subsurf_face_dot_tags.clear_and_shrink();
|
||||||
|
@ -654,14 +654,10 @@ std::unique_ptr<PBVH> build_mesh(Mesh *mesh)
|
|||||||
pbvh->header.type = PBVH_FACES;
|
pbvh->header.type = PBVH_FACES;
|
||||||
|
|
||||||
const int totvert = mesh->verts_num;
|
const int totvert = mesh->verts_num;
|
||||||
const int corner_tris_num = poly_to_tri_count(mesh->faces_num, mesh->corners_num);
|
|
||||||
MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
|
MutableSpan<float3> vert_positions = mesh->vert_positions_for_write();
|
||||||
const OffsetIndices<int> faces = mesh->faces();
|
|
||||||
const Span<int> corner_verts = mesh->corner_verts();
|
const Span<int> corner_verts = mesh->corner_verts();
|
||||||
HooglyBoogly marked this conversation as resolved
Outdated
|
|||||||
|
const Span<int3> corner_tris = mesh->corner_tris();
|
||||||
pbvh->corner_tris.reinitialize(corner_tris_num);
|
pbvh->corner_tris = corner_tris;
|
||||||
mesh::corner_tris_calc(vert_positions, faces, corner_verts, pbvh->corner_tris);
|
|
||||||
const Span<int3> corner_tris = pbvh->corner_tris;
|
|
||||||
|
|
||||||
pbvh->mesh = mesh;
|
pbvh->mesh = mesh;
|
||||||
|
|
||||||
@ -681,7 +677,7 @@ std::unique_ptr<PBVH> build_mesh(Mesh *mesh)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* For each face, store the AABB and the AABB centroid */
|
/* For each face, store the AABB and the AABB centroid */
|
||||||
Array<Bounds<float3>> prim_bounds(corner_tris_num);
|
Array<Bounds<float3>> prim_bounds(corner_tris.size());
|
||||||
const Bounds<float3> cb = threading::parallel_reduce(
|
const Bounds<float3> cb = threading::parallel_reduce(
|
||||||
corner_tris.index_range(),
|
corner_tris.index_range(),
|
||||||
1024,
|
1024,
|
||||||
@ -701,7 +697,7 @@ std::unique_ptr<PBVH> build_mesh(Mesh *mesh)
|
|||||||
},
|
},
|
||||||
[](const Bounds<float3> &a, const Bounds<float3> &b) { return bounds::merge(a, b); });
|
[](const Bounds<float3> &a, const Bounds<float3> &b) { return bounds::merge(a, b); });
|
||||||
|
|
||||||
if (corner_tris_num) {
|
if (!corner_tris.is_empty()) {
|
||||||
const AttributeAccessor attributes = mesh->attributes();
|
const AttributeAccessor attributes = mesh->attributes();
|
||||||
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", AttrDomain::Face);
|
const VArraySpan hide_poly = *attributes.lookup<bool>(".hide_poly", AttrDomain::Face);
|
||||||
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
|
const VArraySpan material_index = *attributes.lookup<int>("material_index", AttrDomain::Face);
|
||||||
@ -716,7 +712,7 @@ std::unique_ptr<PBVH> build_mesh(Mesh *mesh)
|
|||||||
vert_bitmap,
|
vert_bitmap,
|
||||||
&cb,
|
&cb,
|
||||||
prim_bounds,
|
prim_bounds,
|
||||||
corner_tris_num);
|
corner_tris.size());
|
||||||
|
|
||||||
#ifdef TEST_PBVH_FACE_SPLIT
|
#ifdef TEST_PBVH_FACE_SPLIT
|
||||||
test_face_boundaries(pbvh, tri_faces);
|
test_face_boundaries(pbvh, tri_faces);
|
||||||
|
@ -154,8 +154,7 @@ struct PBVH {
|
|||||||
/** Only valid for polygon meshes. */
|
/** Only valid for polygon meshes. */
|
||||||
blender::OffsetIndices<int> faces;
|
blender::OffsetIndices<int> faces;
|
||||||
blender::Span<int> corner_verts;
|
blender::Span<int> corner_verts;
|
||||||
/* Owned by the #PBVH, because after deformations they have to be recomputed. */
|
blender::Span<blender::int3> corner_tris;
|
||||||
blender::Array<blender::int3> corner_tris;
|
|
||||||
|
|
||||||
/* Grid Data */
|
/* Grid Data */
|
||||||
CCGKey gridkey;
|
CCGKey gridkey;
|
||||||
|
@ -355,6 +355,10 @@ void ED_object_sculptmode_enter_ex(Main &bmain,
|
|||||||
const int mode_flag = OB_MODE_SCULPT;
|
const int mode_flag = OB_MODE_SCULPT;
|
||||||
Mesh *mesh = BKE_mesh_from_object(&ob);
|
Mesh *mesh = BKE_mesh_from_object(&ob);
|
||||||
|
|
||||||
|
/* Re-triangulating the mesh for position changes in sculpt mode isn't worth the performance
|
||||||
|
* impact, so delay triangulation updates until the user exits sculpt mode. */
|
||||||
|
mesh->runtime->corner_tris_cache.freeze();
|
||||||
|
|
||||||
/* Enter sculpt mode. */
|
/* Enter sculpt mode. */
|
||||||
ob.mode |= mode_flag;
|
ob.mode |= mode_flag;
|
||||||
|
|
||||||
@ -450,6 +454,8 @@ void ED_object_sculptmode_exit_ex(Main &bmain, Depsgraph &depsgraph, Scene &scen
|
|||||||
const int mode_flag = OB_MODE_SCULPT;
|
const int mode_flag = OB_MODE_SCULPT;
|
||||||
Mesh *mesh = BKE_mesh_from_object(&ob);
|
Mesh *mesh = BKE_mesh_from_object(&ob);
|
||||||
|
|
||||||
|
mesh->runtime->corner_tris_cache.unfreeze();
|
||||||
|
|
||||||
multires_flush_sculpt_updates(&ob);
|
multires_flush_sculpt_updates(&ob);
|
||||||
|
|
||||||
/* Not needed for now. */
|
/* Not needed for now. */
|
||||||
|
Loading…
Reference in New Issue
Block a user
const OffsetIndices<int> faces = mesh->faces();
is now unused.