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 hasPoints() 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);
101 bool isValidFace(Offset offset) const;
102 bool isValidVertex(Offset offset) const;
103 bool isValidPoint(Offset offset) const override;
104
105 void defragment() override;
106
107 void merge(Mesh& other);
108
109 std::unordered_set<Offset>::const_iterator soloPointsBegin() const;
110 std::unordered_set<Offset>::const_iterator soloPointsEnd() const;
111
112 void setPointPos(const Offset offset, const Vector3& pos);
117 std::span<const Offset> getFaceStartVertices() const;
118 Vector3 getPosFromVert(Offset vertexOffset) const;
119 Vector3 getPointPos(Offset pointOffset) const;
120 unsigned int getFaceVertCount(Offset faceOffset) const
121 {
122 return vertexCountFaceHandle_[faceOffset];
123 }
124 unsigned int getFacePointCount(Offset faceOffset) const;
125 Offset getVertexFace(Offset vertexOffset) const;
126
127 Offset getVertexPoint(Offset vertexOffset) const
128 {
129 return pointOffsetVertexHandle_.getValue(vertexOffset);
130 }
131
132 std::span<const intT> getFacePoints(Offset faceOffset) const
133 {
134 const Offset start = getFaceStartVertices()[faceOffset];
135 const unsigned int count = getFaceVertCount(faceOffset);
136 return pointOffsetVertexHandle_.getSpan().subspan(start, count);
137 }
138
143 std::span<const intT> vertexPointSpan() const { return pointOffsetVertexHandle_.getSpan(); }
144
149 std::span<const Vector3> pointPosSpan() const { return posPointHandle_.getSpan(); }
150
151 Offset getNumFaces() const { return getElementCount(attr::AttributeOwner::FACE); }
152 Offset getNumVerts() const { return getElementCount(attr::AttributeOwner::VERTEX); }
153 Offset getNumSoloPoints() const;
154
155 // Face Iterator
157 {
158 FaceOffsets(const Mesh& mesh) : mesh_(mesh) {}
159 struct Iterator
160 {
161 using iterator_category = std::forward_iterator_tag;
162 using difference_type = std::ptrdiff_t;
163 using value_type = Offset;
164
165 explicit Iterator(Offset current) : curOffset_(current) {}
166 value_type operator*() const { return curOffset_; }
167 Iterator& operator++()
168 {
169 ++curOffset_;
170 return *this;
171 }
172 Iterator operator++(int)
173 {
174 Iterator tmp = *this;
175 ++(*this);
176 return tmp;
177 }
178 friend bool operator==(const Iterator& a, const Iterator& b)
179 {
180 return a.curOffset_ == b.curOffset_;
181 }
182 friend bool operator!=(const Iterator& a, const Iterator& b)
183 {
184 return a.curOffset_ != b.curOffset_;
185 }
186
187 private:
188 Offset curOffset_ = 0;
189 };
190 Iterator begin() const { return Iterator(0); }
191 Iterator end() const { return Iterator(mesh_.getNumFaces()); }
192
194 std::vector<Offset> toVector() const
195 {
196 std::vector<Offset> offsets;
197 offsets.reserve(mesh_.getNumFaces());
198 for (const Offset faceOffset : *this)
199 offsets.push_back(faceOffset);
200 return offsets;
201 }
202
203 private:
204 const Mesh& mesh_;
205 };
206 // TODO walk only valid faces like Primitive::PointOffsets once deletion settles. For now it is
207 // dense.
208 FaceOffsets getFaces() const { return FaceOffsets(*this); }
209
212 {
213 return addGroup(attr::AttributeOwner::VERTEX, std::move(name));
214 }
217 {
218 return addGroup(attr::AttributeOwner::FACE, std::move(name));
219 }
221 void addToVertexGroup(const std::string& name, const std::vector<Offset>& offsets)
222 {
223 addToGroup(attr::AttributeOwner::VERTEX, name, offsets);
224 }
226 void addToFaceGroup(const std::string& name, const std::vector<Offset>& offsets)
227 {
228 addToGroup(attr::AttributeOwner::FACE, name, offsets);
229 }
230
231 boolT isClosed(Offset faceOffset) const;
232
233 void computeFaceStartVertices() const;
234
248 FaceNormalHandle getFaceNormal(bool precompute = false) const;
249
262 VertexNormalHandle getVertexNormal(double cuspAngle = kDefaultCuspAngle) const;
263
273
274 friend class FaceNormalHandle;
275 friend class VertexNormalHandle;
276
277 protected:
278 attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) override;
279 const attr::attribVector& getAttributeStore(const attr::AttributeOwner& owner) const override;
280 attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) override;
281 const attr::attribVector& getGroupStore(const attr::AttributeOwner& owner) const override;
282
283 private:
284 void mergeAppend(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src);
285 template <typename T>
286 void mergeAppendImpl(std::shared_ptr<attr::Attribute> dst, std::shared_ptr<attr::Attribute> src)
287 {
288 auto dstHandle = attr::AttributeHandle<T>(dst);
289 auto srcHandle = attr::AttributeHandle<T>(src);
290
291 const Offset srcCount = srcHandle.getSize();
292 const Offset dstCount = dstHandle.getSize();
293
294 dstHandle.resize(dstCount + srcCount);
295
296 for (Offset i = 0; i < srcCount; ++i)
297 {
298 const T value = srcHandle.getValue(i);
299 const Offset dstOffset = dstCount + i;
300 dstHandle.setValue(dstOffset, value);
301 }
302 };
303
304 attr::attribVector vertexAttributes_;
305 attr::attribVector faceAttributes_;
306 attr::attribVector vertexGroups_;
307 attr::attribVector faceGroups_;
308
309 mutable std::unordered_set<Offset> soloPoints_;
310 mutable bool soloPointsDirty_ = true;
311 void rebuildSoloPoints() const;
312 bool needsDefrag_ = false;
313
314 mutable std::vector<Offset> faceStarts_;
315 mutable std::vector<Offset> vertexFaces_;
316
317 mutable std::atomic<bool> faceStartsDirty_{true};
318 mutable tbb::spin_mutex faceStartsMutex_;
319
320 // intrinsic handles
321 enzo::attr::AttributeHandleInt vertexCountFaceHandle_;
322 enzo::attr::AttributeHandleBool closedFaceHandle_;
323 enzo::attr::AttributeHandleInt pointOffsetVertexHandle_;
325 enzo::attr::AttributeHandleBool validFaceHandle_;
326 enzo::attr::AttributeHandleBool validVertexHandle_;
327 enzo::attr::AttributeHandleBool validPointHandle_;
328};
329
340class FaceNormalHandle
341{
342 public:
343 Vector3 operator[](Offset faceOffset) const
344 {
345 if (cached_) return (*cached_)[faceOffset];
346 if (!precomputed_.empty()) return precomputed_[faceOffset];
347 return computeNormal(faceOffset);
348 }
349
350 private:
351 friend class Mesh;
352 FaceNormalHandle(const Mesh& mesh, bool precompute);
353 Vector3 computeNormal(Offset faceOffset) const;
354 const Mesh& mesh_;
355 std::optional<attr::AttributeHandleRO<Vector3>> cached_;
356 std::vector<Vector3> precomputed_;
357};
358
367class PointNormalHandle
368{
369 public:
370 Vector3 operator[](Offset pointOffset) const
371 {
372 if (attribute_) return (*attribute_)[pointOffset];
373 return computed_[pointOffset];
374 }
375
376 private:
377 friend class Mesh;
378 explicit PointNormalHandle(const Mesh& mesh);
379 std::optional<attr::AttributeHandleRO<Vector3>> attribute_;
380 std::vector<Vector3> computed_;
381};
382
391class VertexNormalHandle
392{
393 public:
394 Vector3 operator[](Offset vertexOffset) const;
395
396 private:
397 friend class Mesh;
398 VertexNormalHandle(const Mesh& mesh, double cuspAngle);
399 const Mesh& mesh_;
400 std::optional<attr::AttributeHandleRO<Vector3>> vertexAttribute_;
401 std::optional<attr::AttributeHandleRO<Vector3>> pointAttribute_;
402 std::vector<Vector3> computed_;
403};
404} // namespace enzo::geo
size_t Offset
enzo::Offset is the internal discontinuous index of an element in a given AttributeOwner.
Definition Types.h:181
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:670
FaceNormalHandle getFaceNormal(bool precompute=false) const
Returns a handle for reading per-face normals.
Definition Mesh.cpp:824
void deleteAllFaces(bool andPoints=true)
Removes every face from the mesh.
Definition Mesh.cpp:389
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:588
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:247
void addToVertexGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the vertex group.
Definition Mesh.h:221
std::span< const intT > vertexPointSpan() const
Contiguous view mapping each vertex offset to its point offset.
Definition Mesh.h:143
PointNormalHandle getPointNormal() const
Returns a handle for reading per-point normals.
Definition Mesh.cpp:829
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:287
attr::AttributeHandleBool addVertexGroup(std::string name)
Returns the vertex group of this name, adding one when the name is free.
Definition Mesh.h:211
attr::AttributeHandleBool addFaceGroup(std::string name)
Returns the face group of this name, adding one when the name is free.
Definition Mesh.h:216
VertexNormalHandle getVertexNormal(double cuspAngle=kDefaultCuspAngle) const
Returns a handle for reading per-vertex normals.
Definition Mesh.cpp:834
std::vector< Offset > addPoints(std::span< const Vector3 > positions)
Adds many points in a single call.
Definition Mesh.cpp:556
void addToFaceGroup(const std::string &name, const std::vector< Offset > &offsets)
Marks the given offsets as members of the face group.
Definition Mesh.h:226
void defragment() override
Compacts storage, removing entries marked invalid so offsets are contiguous again.
Definition Mesh.cpp:470
std::span< const Vector3 > pointPosSpan() const
Contiguous view of every point position.
Definition Mesh.h:149
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:157
std::vector< Offset > toVector() const
Collects the face offsets into a vector for callers that need one.
Definition Mesh.h:194