Enzo
Loading...
Searching...
No Matches
Mesh.h
1#pragma once
2#include "Engine/Primitives/Primitive.h"
3#include <span>
4#include <tbb/spin_mutex.h>
5#include <unordered_set>
6
7namespace enzo::geo {
8class Mesh;
9class FaceNormalHandle;
10class PointNormalHandle;
11class VertexNormalHandle;
12
14inline constexpr double kDefaultCuspAngle = 60;
15
24class Mesh : public Primitive
25{
26 public:
27 Mesh(std::string_view path = "/mesh");
28 Mesh(const Mesh& other);
29 Mesh& operator=(const Mesh& rhs);
30 ~Mesh() override = default;
31
32 PrimType getType() const override { return PrimType::MESH; }
33 std::shared_ptr<Primitive> clone() const override { return std::make_shared<Mesh>(*this); }
34 TransformClass transformType() const override
35 {
36 return TransformClass::POINT | TransformClass::PRIMITIVE;
37 }
38 void applyTransform(
39 const Matrix4& mat,
40 TransformClass transformClass = TransformClass::POINT
41 ) override;
42 void applyTransform(
43 const Transform& transform,
44 TransformClass transformClass = TransformClass::POINT
45 )
46 {
47 applyTransform(transform.getMatrix(), transformClass);
48 }
49 bool canMerge() const override { return true; }
50 void merge(std::shared_ptr<Primitive> other) override;
51 bool hasOwner(attr::AttributeOwner owner) const override { return true; }
52
58 // TODO: benchmark addFace vs addFaces to quantify the speedup
59 Offset addFace(const std::vector<Offset>& pointOffsets, bool closed = true);
68 std::vector<Offset> addFaces(
69 std::span<const Offset> pointOffsetsFlat,
70 std::span<const Offset> vertexCounts,
71 bool closed = true
72 );
73 Offset addPoint(const Vector3& pos);
80 std::vector<Offset> addPoints(std::span<const Vector3> positions);
89 std::vector<Offset>
90 duplicatePoints(std::span<const Offset> srcPointOffsets, bool copyAttributes = true);
91
92 void deleteFaces(const std::vector<Offset>& faceOffsets, bool andPoints = true);
94 void deleteAllFaces(bool andPoints = true);
95 void deletePoints(const std::vector<Offset>& pointOffsets) override
96 {
97 deletePoints(pointOffsets, false);
98 }
99 void deletePoints(const std::vector<Offset>& pointOffsets, bool andFaces);
100 void deleteVertices(const std::vector<Offset>& vertOffsets);
102 void reverseFaces(const std::vector<Offset>& faceOffsets);
103 bool isValidFace(Offset offset) const;
104 bool isValidVertex(Offset offset) const;
105 bool isValidPoint(Offset offset) const override;
106
107 void defragment() override;
108
109 void merge(Mesh& other);
110
111 std::unordered_set<Offset>::const_iterator soloPointsBegin() const;
112 std::unordered_set<Offset>::const_iterator soloPointsEnd() const;
113
114 void setPointPos(const Offset offset, const Vector3& pos);
119 std::span<const Offset> getFaceStartVertices() const;
120 Vector3 getPosFromVert(Offset vertexOffset) const;
121 Vector3 getPointPos(Offset pointOffset) const;
122 unsigned int getFaceVertCount(Offset faceOffset) const
123 {
124 return vertexCountFaceHandle_[faceOffset];
125 }
126 unsigned int getFacePointCount(Offset faceOffset) const;
127 Offset getVertexFace(Offset vertexOffset) const;
128
129 Offset getVertexPoint(Offset vertexOffset) const
130 {
131 return pointOffsetVertexHandle_.getValue(vertexOffset);
132 }
133
134 std::span<const intT> getFacePoints(Offset faceOffset) const
135 {
136 const Offset start = getFaceStartVertices()[faceOffset];
137 const unsigned int count = getFaceVertCount(faceOffset);
138 return pointOffsetVertexHandle_.getSpan().subspan(start, count);
139 }
140
145 std::span<const intT> vertexPointSpan() const { return pointOffsetVertexHandle_.getSpan(); }
146
151 std::span<const Vector3> pointPosSpan() const { return posPointHandle_.getSpan(); }
152
153 Offset getNumFaces() const { return getElementCount(attr::AttributeOwner::FACE); }
154 Offset getNumVerts() const { return getElementCount(attr::AttributeOwner::VERTEX); }
155 Offset getNumSoloPoints() const;
156
157 // Face Iterator
159 {
160 FaceOffsets(const Mesh& mesh) : mesh_(mesh) {}
161 struct Iterator
162 {
163 using iterator_category = std::forward_iterator_tag;
164 using difference_type = std::ptrdiff_t;
165 using value_type = Offset;
166
167 explicit Iterator(Offset current) : curOffset_(current) {}
168 value_type operator*() const { return curOffset_; }
169 Iterator& operator++()
170 {
171 ++curOffset_;
172 return *this;
173 }
174 Iterator operator++(int)
175 {
176 Iterator tmp = *this;
177 ++(*this);
178 return tmp;
179 }
180 friend bool operator==(const Iterator& a, const Iterator& b)
181 {
182 return a.curOffset_ == b.curOffset_;
183 }
184 friend bool operator!=(const Iterator& a, const Iterator& b)
185 {
186 return a.curOffset_ != b.curOffset_;
187 }
188
189 private:
190 Offset curOffset_ = 0;
191 };
192 Iterator begin() const { return Iterator(0); }
193 Iterator end() const { return Iterator(mesh_.getNumFaces()); }
194
196 std::vector<Offset> toVector() const
197 {
198 std::vector<Offset> offsets;
199 offsets.reserve(mesh_.getNumFaces());
200 for (const Offset faceOffset : *this)
201 offsets.push_back(faceOffset);
202 return offsets;
203 }
204
205 private:
206 const Mesh& mesh_;
207 };
208 // TODO walk only valid faces like Primitive::PointOffsets once deletion settles. For now it is
209 // dense.
210 FaceOffsets getFaces() const { return FaceOffsets(*this); }
211
214 {
215 return addGroup(attr::AttributeOwner::VERTEX, std::move(name));
216 }
219 {
220 return addGroup(attr::AttributeOwner::FACE, std::move(name));
221 }
223 void addToVertexGroup(const std::string& name, const std::vector<Offset>& offsets)
224 {
225 addToGroup(attr::AttributeOwner::VERTEX, name, offsets);
226 }
228 void addToFaceGroup(const std::string& name, const std::vector<Offset>& offsets)
229 {
230 addToGroup(attr::AttributeOwner::FACE, name, offsets);
231 }
232
233 boolT isClosed(Offset faceOffset) const;
234
235 void computeFaceStartVertices() const;
236
250 FaceNormalHandle getFaceNormal(bool precompute = false) const;
251
264 VertexNormalHandle getVertexNormal(double cuspAngle = kDefaultCuspAngle) const;
265
275
276 friend class FaceNormalHandle;
277 friend class VertexNormalHandle;
278
279 protected:
280 attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) override;
281 const attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) const override;
282 attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) override;
283 const attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) const override;
284
285 private:
286 void mergeAppend(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src);
287 template <typename T>
288 void mergeAppendImpl(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src)
289 {
290 auto dstHandle = attr::AttributeHandle<T>(dst);
291 auto srcHandle = attr::AttributeHandle<T>(src);
292
293 const Offset srcCount = srcHandle.getSize();
294 const Offset dstCount = dstHandle.getSize();
295
296 dstHandle.resize(dstCount + srcCount);
297
298 for (Offset i = 0; i < srcCount; ++i)
299 {
300 const T value = srcHandle.getValue(i);
301 const Offset dstOffset = dstCount + i;
302 dstHandle.setValue(dstOffset, value);
303 }
304 };
305
306 attr::attribVector vertexAttributes_;
307 attr::attribVector faceAttributes_;
308 attr::attribVector vertexGroups_;
309 attr::attribVector faceGroups_;
310
311 mutable std::unordered_set<Offset> soloPoints_;
312 mutable bool soloPointsDirty_ = true;
313 void rebuildSoloPoints() const;
314 bool needsDefrag_ = false;
315
316 mutable std::vector<Offset> faceStarts_;
317 mutable std::vector<Offset> vertexFaces_;
318
319 mutable std::atomic<bool> faceStartsDirty_{true};
320 mutable tbb::spin_mutex faceStartsMutex_;
321
322 // intrinsic handles
323 enzo::attr::AttributeHandleInt vertexCountFaceHandle_;
324 enzo::attr::AttributeHandleBool closedFaceHandle_;
325 enzo::attr::AttributeHandleInt pointOffsetVertexHandle_;
327 enzo::attr::AttributeHandleBool validFaceHandle_;
328 enzo::attr::AttributeHandleBool validVertexHandle_;
329 enzo::attr::AttributeHandleBool validPointHandle_;
330};
331
342class FaceNormalHandle
343{
344 public:
345 Vector3 operator[](Offset faceOffset) const
346 {
347 if (cached_) return (*cached_)[faceOffset];
348 if (!precomputed_.empty()) return precomputed_[faceOffset];
349 return computeNormal(faceOffset);
350 }
351
352 private:
353 friend class Mesh;
354 FaceNormalHandle(const Mesh& mesh, bool precompute);
355 Vector3 computeNormal(Offset faceOffset) const;
356 const Mesh& mesh_;
357 std::optional<attr::AttributeHandleRO<Vector3>> cached_;
358 std::vector<Vector3> precomputed_;
359};
360
369class PointNormalHandle
370{
371 public:
372 Vector3 operator[](Offset pointOffset) const
373 {
374 if (attribute_) return (*attribute_)[pointOffset];
375 return computed_[pointOffset];
376 }
377
378 private:
379 friend class Mesh;
380 explicit PointNormalHandle(const Mesh& mesh);
381 std::optional<attr::AttributeHandleRO<Vector3>> attribute_;
382 std::vector<Vector3> computed_;
383};
384
393class VertexNormalHandle
394{
395 public:
396 Vector3 operator[](Offset vertexOffset) const;
397
398 private:
399 friend class Mesh;
400 VertexNormalHandle(const Mesh& mesh, double cuspAngle);
401 const Mesh& mesh_;
402 std::optional<attr::AttributeHandleRO<Vector3>> vertexAttribute_;
403 std::optional<attr::AttributeHandleRO<Vector3>> pointAttribute_;
404 std::vector<Vector3> computed_;
405};
406} // namespace enzo::geo
size_t Offset
enzo::Offset is the internal discontinuous index of an element in a given AttributeOwner.
Definition Types.h:182
AttributeOwner
The segment of geometry that owns a particular attribute.
Definition Types.h:27
Read write accessor for enzo::attr::Attribute.
std::span< const T > getSpan() const
Contiguous read only view over all stored values.
Definition AttributeHandle.h:153
T getValue(size_t offset) const
Gets the value at a given offset.
Definition AttributeHandle.h:134
Read accessor for per-face normals.
Polygonal mesh primitive with point, vertex, and face attributes.
std::span< const Offset > getFaceStartVertices() const
Contiguous view of each face's starting vertex offset.
Definition Mesh.cpp:668
FaceNormalHandle getFaceNormal(bool precompute=false) const
Returns a handle for reading per-face normals.
Definition Mesh.cpp:825
void deleteAllFaces(bool andPoints=true)
Removes every face from the mesh.
Definition Mesh.cpp:371
std::vector< Offset > duplicatePoints(std::span< const Offset > srcPointOffsets, bool copyAttributes=true)
Duplicates existing points into new points carrying the same positions.
Definition Mesh.cpp:584
Offset addFace(const std::vector< Offset > &pointOffsets, bool closed=true)
Adds a single face. Avoid for multiple faces in a loop as a single call to addFaces is much more perf...
Definition Mesh.cpp:229
void addToVertexGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the vertex group.
Definition Mesh.h:223
std::span< const intT > vertexPointSpan() const
Contiguous view mapping each vertex offset to its point offset.
Definition Mesh.h:145
PointNormalHandle getPointNormal() const
Returns a handle for reading per-point normals.
Definition Mesh.cpp:830
std::vector< Offset > addFaces(std::span< const Offset > pointOffsetsFlat, std::span< const Offset > vertexCounts, bool closed=true)
Adds many faces in a single call.
Definition Mesh.cpp:269
attr::AttributeHandleBool addVertexGroup(std::string name)
Returns the vertex group of this name, adding one when the name is free.
Definition Mesh.h:213
bool hasOwner(attr::AttributeOwner owner) const override
Returns whether this primitive type stores elements of the owner.
Definition Mesh.h:51
attr::AttributeHandleBool addFaceGroup(std::string name)
Returns the face group of this name, adding one when the name is free.
Definition Mesh.h:218
void reverseFaces(const std::vector< Offset > &faceOffsets)
Reverses the vertex order of each face, carrying every vertex attribute along.
Definition Mesh.cpp:446
VertexNormalHandle getVertexNormal(double cuspAngle=kDefaultCuspAngle) const
Returns a handle for reading per-vertex normals.
Definition Mesh.cpp:835
std::vector< Offset > addPoints(std::span< const Vector3 > positions)
Adds many points in a single call.
Definition Mesh.cpp:552
void addToFaceGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the face group.
Definition Mesh.h:228
void defragment() override
Compacts storage, removing entries marked invalid so offsets are contiguous again.
Definition Mesh.cpp:466
std::span< const Vector3 > pointPosSpan() const
Contiguous view of every point position.
Definition Mesh.h:151
Read accessor for per-point normals.
attr::AttributeHandleBool addGroup(attr::AttributeOwner owner, std::string name)
Returns the group of this name on the given owner, adding one when the name is free.
Definition Primitive.cpp:216
size_t getElementCount(const attr::AttributeOwner &owner) const
Returns the number of elements in the given owner's store.
Definition Primitive.cpp:204
void addToGroup(attr::AttributeOwner owner, const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the group.
Definition Primitive.cpp:223
Read accessor for per-vertex normals.
Definition Mesh.h:159
std::vector< Offset > toVector() const
Collects the face offsets into a vector for callers that need one.
Definition Mesh.h:196