WIP: Mesh: Refactor vertex normals for determinism #105920
|
@ -6,6 +6,8 @@
|
|||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BLI_offset_indices.hh"
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
namespace blender::bke::mesh {
|
||||
|
@ -223,6 +225,47 @@ void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals);
|
|||
|
||||
} // namespace blender::bke::mesh
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mesh Topology Caches
|
||||
* \{ */
|
||||
|
||||
namespace blender::bke::mesh {
|
||||
|
||||
class VertToPolyMap {
|
||||
OffsetIndices<int> offsets_;
|
||||
Span<int> indices_;
|
||||
|
||||
public:
|
||||
VertToPolyMap() = default;
|
||||
VertToPolyMap(OffsetIndices<int> offsets, Span<int> indices)
|
||||
: offsets_(offsets), indices_(indices)
|
||||
{
|
||||
}
|
||||
/* Indices of all faces using the indexed vertex. */
|
||||
Span<int> operator[](const int64_t vert_index) const
|
||||
{
|
||||
return indices_.slice(offsets_[vert_index]);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Build offsets per vertex used to slice arrays containing the indices of connected
|
||||
* faces or face corners (each vertex used by the same number of corners and faces).
|
||||
*/
|
||||
void build_poly_and_corner_by_vert_offsets(Span<int> corner_verts, MutableSpan<int> offsets);
|
||||
/**
|
||||
* Fill the indices of polygons connected to each vertex, ordered smallest index to largest.
|
||||
* \param offsets: Encodes the number of polygons connected to each vertex.
|
||||
*/
|
||||
void build_vert_to_poly_indices(OffsetIndices<int> polys,
|
||||
Span<int> corner_verts,
|
||||
OffsetIndices<int> offsets,
|
||||
MutableSpan<int> poly_indices);
|
||||
|
||||
} // namespace blender::bke::mesh
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Inline Mesh Data Access
|
||||
* \{ */
|
||||
|
|
|
@ -165,6 +165,13 @@ struct MeshRuntime {
|
|||
SharedCache<Vector<float3>> poly_normals_cache;
|
||||
|
||||
/** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */
|
||||
SharedCache<Vector<int>> vert_to_corner_offset_cache;
|
||||
SharedCache<Vector<int>> vert_to_poly_indices_cache;
|
||||
|
||||
/**
|
||||
* A cache of data about the loose edges. Can be shared with other data-blocks with unchanged
|
||||
* topology. Accessed with #Mesh::loose_edges().
|
||||
*/
|
||||
SharedCache<LooseEdgeCache> loose_edges_cache;
|
||||
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */
|
||||
SharedCache<LooseVertCache> loose_verts_cache;
|
||||
|
|
|
@ -136,6 +136,8 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
|
|||
mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache;
|
||||
mesh_dst->runtime->vert_normals_cache = mesh_src->runtime->vert_normals_cache;
|
||||
mesh_dst->runtime->poly_normals_cache = mesh_src->runtime->poly_normals_cache;
|
||||
mesh_dst->runtime->vert_to_corner_offset_cache = mesh_src->runtime->vert_to_corner_offset_cache;
|
||||
mesh_dst->runtime->vert_to_poly_indices_cache = mesh_src->runtime->vert_to_poly_indices_cache;
|
||||
|
||||
/* Only do tessface if we have no polys. */
|
||||
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BKE_customdata.h"
|
||||
#include "BKE_mesh.h"
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_mesh_mapping.h"
|
||||
#include "BLI_memarena.h"
|
||||
|
||||
|
@ -521,6 +521,34 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
|
|||
*r_mem = indices;
|
||||
}
|
||||
|
||||
namespace blender::bke::mesh {
|
||||
|
||||
void build_poly_and_corner_by_vert_offsets(const Span<int> corner_verts, MutableSpan<int> offsets)
|
||||
{
|
||||
BLI_assert(std::all_of(offsets.begin(), offsets.end(), [](int value) { return value == 0; }));
|
||||
for (const int vert : corner_verts) {
|
||||
offsets[vert]++;
|
||||
}
|
||||
offset_indices::accumulate_counts_to_offsets(offsets);
|
||||
}
|
||||
|
||||
void build_vert_to_poly_indices(const OffsetIndices<int> polys,
|
||||
const Span<int> corner_verts,
|
||||
const OffsetIndices<int> offsets,
|
||||
MutableSpan<int> poly_indices)
|
||||
{
|
||||
BLI_assert(poly_indices.size() == corner_verts.size());
|
||||
Array<int> counts(offsets.size(), 0);
|
||||
for (const int64_t i : polys.index_range()) {
|
||||
for (const int vert : corner_verts.slice(polys[i])) {
|
||||
poly_indices[offsets[vert][counts[vert]]] = int(i);
|
||||
counts[vert]++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke::mesh
|
||||
|
||||
namespace blender::bke::mesh_topology {
|
||||
|
||||
Array<int> build_loop_to_poly_map(const OffsetIndices<int> polys)
|
||||
|
|
|
@ -142,6 +142,26 @@ static void try_tag_verts_no_face_none(const Mesh &mesh)
|
|||
|
||||
} // namespace blender::bke
|
||||
|
||||
blender::bke::mesh::VertToPolyMap Mesh::vert_to_poly_map() const
|
||||
{
|
||||
using namespace blender;
|
||||
this->runtime->vert_to_corner_offset_cache.ensure([&](Vector<int> &r_data) {
|
||||
r_data.clear();
|
||||
r_data.resize(this->totvert + 1, 0);
|
||||
bke::mesh::build_poly_and_corner_by_vert_offsets(this->corner_verts(), r_data);
|
||||
});
|
||||
const OffsetIndices<int> offsets(this->runtime->vert_to_corner_offset_cache.data());
|
||||
|
||||
this->runtime->vert_to_poly_indices_cache.ensure([&](blender::Vector<int> &r_data) {
|
||||
r_data.reinitialize(this->totloop);
|
||||
blender::bke::mesh::build_vert_to_poly_indices(
|
||||
this->polys(), this->corner_verts(), offsets, r_data);
|
||||
});
|
||||
const Span<int> indices = this->runtime->vert_to_poly_indices_cache.data();
|
||||
|
||||
return {offsets, indices};
|
||||
}
|
||||
|
||||
const blender::bke::LooseVertCache &Mesh::loose_verts() const
|
||||
{
|
||||
using namespace blender::bke;
|
||||
|
@ -270,6 +290,8 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh)
|
|||
mesh->runtime->vert_normals_cache.tag_dirty();
|
||||
mesh->runtime->poly_normals_cache.tag_dirty();
|
||||
mesh->runtime->bounds_cache.tag_dirty();
|
||||
mesh->runtime->vert_to_corner_offset_cache.tag_dirty();
|
||||
mesh->runtime->vert_to_poly_indices_cache.tag_dirty();
|
||||
mesh->runtime->loose_edges_cache.tag_dirty();
|
||||
mesh->runtime->loose_verts_cache.tag_dirty();
|
||||
mesh->runtime->verts_no_face_cache.tag_dirty();
|
||||
|
@ -288,6 +310,8 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh)
|
|||
free_bvh_cache(*mesh->runtime);
|
||||
free_subdiv_ccg(*mesh->runtime);
|
||||
mesh->runtime->vert_normals_cache.tag_dirty();
|
||||
mesh->runtime->vert_to_corner_offset_cache.tag_dirty();
|
||||
mesh->runtime->vert_to_poly_indices_cache.tag_dirty();
|
||||
mesh->runtime->loose_edges_cache.tag_dirty();
|
||||
mesh->runtime->loose_verts_cache.tag_dirty();
|
||||
mesh->runtime->verts_no_face_cache.tag_dirty();
|
||||
|
|
|
@ -29,6 +29,9 @@ class AttributeAccessor;
|
|||
class MutableAttributeAccessor;
|
||||
struct LooseVertCache;
|
||||
struct LooseEdgeCache;
|
||||
namespace mesh {
|
||||
class VertToPolyMap;
|
||||
}
|
||||
} // namespace bke
|
||||
} // namespace blender
|
||||
using MeshRuntimeHandle = blender::bke::MeshRuntime;
|
||||
|
@ -299,6 +302,11 @@ typedef struct Mesh {
|
|||
/** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */
|
||||
void bounds_set_eager(const blender::Bounds<blender::float3> &bounds);
|
||||
|
||||
/**
|
||||
* A cached topology map of the faces connected to (using) each vertex.
|
||||
*/
|
||||
blender::bke::mesh::VertToPolyMap vert_to_poly_map() const;
|
||||
|
||||
/**
|
||||
* Cached information about loose edges, calculated lazily when necessary.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue