WIP: Mesh: Refactor vertex normals for determinism #105920
|
@ -6,6 +6,8 @@
|
||||||
* \ingroup bke
|
* \ingroup bke
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "BLI_offset_indices.hh"
|
||||||
|
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.h"
|
||||||
|
|
||||||
namespace blender::bke::mesh {
|
namespace blender::bke::mesh {
|
||||||
|
@ -223,6 +225,47 @@ void mesh_vert_normals_assign(Mesh &mesh, Vector<float3> vert_normals);
|
||||||
|
|
||||||
} // namespace blender::bke::mesh
|
} // 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
|
/** \name Inline Mesh Data Access
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
|
@ -165,6 +165,13 @@ struct MeshRuntime {
|
||||||
SharedCache<Vector<float3>> poly_normals_cache;
|
SharedCache<Vector<float3>> poly_normals_cache;
|
||||||
|
|
||||||
/** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */
|
/** 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;
|
SharedCache<LooseEdgeCache> loose_edges_cache;
|
||||||
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */
|
/** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */
|
||||||
SharedCache<LooseVertCache> loose_verts_cache;
|
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->looptris_cache = mesh_src->runtime->looptris_cache;
|
||||||
mesh_dst->runtime->vert_normals_cache = mesh_src->runtime->vert_normals_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->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. */
|
/* Only do tessface if we have no polys. */
|
||||||
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
|
const bool do_tessface = ((mesh_src->totface != 0) && (mesh_src->totpoly == 0));
|
||||||
|
|
|
@ -21,7 +21,7 @@
|
||||||
#include "BLI_utildefines.h"
|
#include "BLI_utildefines.h"
|
||||||
|
|
||||||
#include "BKE_customdata.h"
|
#include "BKE_customdata.h"
|
||||||
#include "BKE_mesh.h"
|
#include "BKE_mesh.hh"
|
||||||
#include "BKE_mesh_mapping.h"
|
#include "BKE_mesh_mapping.h"
|
||||||
#include "BLI_memarena.h"
|
#include "BLI_memarena.h"
|
||||||
|
|
||||||
|
@ -521,6 +521,34 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map,
|
||||||
*r_mem = indices;
|
*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 {
|
namespace blender::bke::mesh_topology {
|
||||||
|
|
||||||
Array<int> build_loop_to_poly_map(const OffsetIndices<int> polys)
|
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
|
} // 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
|
const blender::bke::LooseVertCache &Mesh::loose_verts() const
|
||||||
{
|
{
|
||||||
using namespace blender::bke;
|
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->vert_normals_cache.tag_dirty();
|
||||||
mesh->runtime->poly_normals_cache.tag_dirty();
|
mesh->runtime->poly_normals_cache.tag_dirty();
|
||||||
mesh->runtime->bounds_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_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();
|
||||||
|
@ -288,6 +310,8 @@ void BKE_mesh_tag_edges_split(struct Mesh *mesh)
|
||||||
free_bvh_cache(*mesh->runtime);
|
free_bvh_cache(*mesh->runtime);
|
||||||
free_subdiv_ccg(*mesh->runtime);
|
free_subdiv_ccg(*mesh->runtime);
|
||||||
mesh->runtime->vert_normals_cache.tag_dirty();
|
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_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();
|
||||||
|
|
|
@ -29,6 +29,9 @@ class AttributeAccessor;
|
||||||
class MutableAttributeAccessor;
|
class MutableAttributeAccessor;
|
||||||
struct LooseVertCache;
|
struct LooseVertCache;
|
||||||
struct LooseEdgeCache;
|
struct LooseEdgeCache;
|
||||||
|
namespace mesh {
|
||||||
|
class VertToPolyMap;
|
||||||
|
}
|
||||||
} // namespace bke
|
} // namespace bke
|
||||||
} // namespace blender
|
} // namespace blender
|
||||||
using MeshRuntimeHandle = blender::bke::MeshRuntime;
|
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. */
|
/** 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);
|
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.
|
* Cached information about loose edges, calculated lazily when necessary.
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in New Issue