HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
meshUtil.h
Go to the documentation of this file.
1 //
2 // Copyright 2017 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_IMAGING_HD_MESH_UTIL_H
8 #define PXR_IMAGING_HD_MESH_UTIL_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/imaging/hd/api.h"
12 #include "pxr/imaging/hd/version.h"
13 #include "pxr/imaging/hd/types.h"
15 
16 #include "pxr/usd/sdf/path.h"
17 
18 #include "pxr/base/gf/vec2i.h"
19 #include "pxr/base/gf/vec3i.h"
20 #include "pxr/base/gf/vec4i.h"
21 
22 #include "pxr/base/vt/array.h"
23 #include "pxr/base/vt/value.h"
24 
26 
27 /// \class HdQuadInfo
28 /// A helper class for quadrangulation computation.
29 
30 // v0 v2
31 // +-----e2----+
32 // \ | /
33 // \ __c__ /
34 // e0 e1
35 // \ /
36 // \ /
37 // + v1
38 //
39 //
40 // original points additional center and edge points
41 // +------------ ... ----+--------------------------------+
42 // | v0 v1 v2 vn | e0 e1 e2 c0, e3 e4 e5 c1 ... |
43 // +------------ ... ----+--------------------------------+
44 // ^
45 // pointsOffset
46 // <----- numAdditionalPoints ---->
47 
48 struct HdQuadInfo {
50 
51  /// Returns true if the mesh is all-quads.
52  bool IsAllQuads() const { return numAdditionalPoints == 0; }
53 
57  std::vector<int> numVerts; // num vertices of non-quads
58  std::vector<int> verts; // vertex indices of non-quads
59 };
60 
61 /// Return status for a computation
62 enum class [[nodiscard]] HdMeshComputationResult
63 {
64  /// Computation failed
66  /// Computation succeeded and a result was produced
67  Success,
68  /// Computation succeeded but no result was produced,
69  /// because it is the same as the input.
70  Unchanged
71 };
72 
73 /// \class HdMeshUtil
74 /// A collection of utility algorithms for generating triangulation
75 /// and quadrangulation of an input topology.
76 
78 {
79 public:
81  : _topology(topology), _id(id) {}
82  virtual ~HdMeshUtil() {}
83 
84  // --------------------------------------------------------------------
85  /// \name Triangulation
86  ///
87  /// Produces a mesh where each non-triangle face in the base mesh topology
88  /// is fan-triangulated such that the resulting mesh consists entirely
89  /// of triangles.
90  ///
91  /// In order to access per-face signals (face color, face selection etc)
92  /// we need a mapping from primitiveID to authored face index domain.
93  /// This is encoded in primitiveParams, and computed along with indices.
94  /// See \ref PrimitiveParamEncoding.
95  /// @{
96  /*
97  +--------+-------+
98  /| \ |\ |\
99  / | \ 1 | \ 2 | \
100  / | \ | \ | \
101  / | \ | \ | 2 +
102  / 0 | 1 \ | 2 \ | /
103  / | \ | \ | /
104  / | \| \|/
105  +-------+--------+-------+
106  */
107 
108  /// Return a triangulation of the input topology. indices and
109  /// primitiveParams are output parameters.
110  HD_API
111  void ComputeTriangleIndices(VtVec3iArray *indices,
112  VtIntArray *primitiveParams,
113  VtIntArray *edgeIndices = nullptr) const;
114 
115  /// Perform a triangulation of a face-varying primvar. source is
116  /// a buffer of size numElements and type corresponding to dataType
117  /// (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
118  /// correct type written to the variable "triangulated", unless the
119  /// result is not "Success", in which case the argument is unmodified.
120  HD_API
122  void const* source,
123  int numElements,
125  VtValue *triangulated) const;
126 
127  /// @}
128 
129  // --------------------------------------------------------------------
130  /// \name Quadrangulation
131  ///
132  /// Produces a mesh where each non-quad face in the base mesh topology
133  /// is quadrangulated such that the resulting mesh consists entirely
134  /// of quads. Additionally, supports splitting each resulting quad
135  /// face into a pair of triangles. This is different than simply
136  /// triangulating the base mesh topology and can be useful for
137  /// maintaining consistency with quad-based subdivision schemes.
138  ///
139  /// In order to access per-face signals (face color, face selection etc)
140  /// we need a mapping from primitiveID to authored face index domain.
141  /// This is encoded in primitiveParams, and computed along with indices.
142  /// See \ref PrimitiveParamEncoding.
143  /// @{
144 
145  /*
146  +--------+-------+
147  /| | | \
148  / | | 2 | 2 /\
149  / | | \ / \
150  / 0 | 1 |------+ 2 +
151  /\ /| | / \ /
152  / \/ | | 2 | 2 \/
153  / 0 | 0| | | /
154  +-------+--------+-------+
155  */
156 
157  /// Generate a quadInfo struct for the input topology.
158  HD_API
159  void ComputeQuadInfo(HdQuadInfo* quadInfo) const;
160 
161  /// Return quadrangulated indices of the input topology. indices and
162  /// primitiveParams are output parameters.
163  HD_API
164  void ComputeQuadIndices(VtIntArray *indices,
165  VtIntArray *primitiveParams,
166  VtVec2iArray *edgeIndices = nullptr) const;
167 
168  /// Return triquad indices (triangulated after quadrangulation) of the
169  /// input topology. indices and primitiveParams are output parameters.
170  HD_API
171  void ComputeTriQuadIndices(VtIntArray *indices,
172  VtIntArray *primitiveParams,
173  VtVec2iArray *edgeIndices = nullptr) const;
174 
175  /// Return a quadrangulation of a per-vertex primvar. source is
176  /// a buffer of size numElements and type corresponding to dataType
177  /// (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
178  /// correct type written to the variable "quadrangulated".
179  /// This function returns false if it can't resolve dataType.
180  HD_API
182  void const* source,
183  int numElements,
185  VtValue *quadrangulated) const;
186 
187  /// Return a quadrangulation of a face-varying primvar.
188  /// source is a buffer of size numElements and type corresponding
189  /// to dataType (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
190  /// correct type written to the variable "quadrangulated".
191  /// This function returns false if it can't resolve dataType.
192  HD_API
194  int numElements,
196  VtValue *quadrangulated) const;
197 
198  /// @}
199 
200  /// Return a buffer filled with face vertex index pairs corresponding
201  /// to the sequence in which edges are visited when iterating through
202  /// the mesh topology. The edges of degenerate and hole faces are
203  /// included so that this sequence will correspond with either base
204  /// face triangulation or quadrangulation (which typically skips
205  /// over hole faces) as well as for refined surfaces which take into
206  /// account faces tagged as holes as well as other non-manifold faces.
207  /// Optionally, records the first edge index for each face.
208  /// Subsequent edge indices for each face are implicitly assigned
209  /// sequentially following the first edge index.
210  HD_API
211  void EnumerateEdges(
212  std::vector<GfVec2i> * edgeVerticesOut,
213  std::vector<int> * firstEdgeIndexForFacesOut = nullptr) const;
214 
215  // --------------------------------------------------------------------
216  /// \anchor PrimitiveParamEncoding
217  /// \name Primitive Param bit encoding
218  ///
219  /// This encoding provides information about each sub-face resulting
220  /// from the triangulation or quadrangulation of a base topology face.
221  ///
222  /// The encoded faceIndex is the index of the base topology face
223  /// corresponding to a triangulated or quadrangulated sub-face.
224  ///
225  /// The encoded edge flag identifies where a sub-face occurs in the
226  /// sequence of sub-faces produced for each base topology face.
227  /// This edge flag can be used to determine which edges of a sub-face
228  /// correspond to edges of a base topology face and which are internal
229  /// edges that were introduced by triangulation or quadrangulation:
230  /// - 0 unaffected triangle or quad base topology face
231  /// - 1 first sub-face produced by triangulation or quadrangulation
232  /// - 2 last sub-face produced by triangulation or quadrangulation
233  /// - 3 intermediate sub-face produced by triangulation or quadrangulation
234  /// @{
235 
236  // Per-primitive coarse-face-param encoding/decoding functions
237  static int EncodeCoarseFaceParam(int faceIndex, int edgeFlag) {
238  return ((faceIndex << 2) | (edgeFlag & 3));
239  }
240  static int DecodeFaceIndexFromCoarseFaceParam(int coarseFaceParam) {
241  return (coarseFaceParam >> 2);
242  }
243  static int DecodeEdgeFlagFromCoarseFaceParam(int coarseFaceParam) {
244  return (coarseFaceParam & 3);
245  }
246 
247  /// }@
248 
249 private:
250  /// Return the number of quadrangulated quads.
251  /// If degenerate face is found, sets invalidFaceFound as true.
252  int _ComputeNumQuads(VtIntArray const &numVerts,
253  VtIntArray const &holeIndices,
254  bool *invalidFaceFound = nullptr) const;
255 
256  /// Return quad indices (optionally triangulated after quadrangulation).
257  void _ComputeQuadIndices(
258  VtIntArray *indices,
259  VtIntArray *primitiveParams,
260  VtVec2iArray *edgeIndices,
261  bool triangulate = false) const;
262 
263  HdMeshTopology const* _topology;
264  SdfPath const _id;
265 };
266 
267 /// \class HdMeshEdgeIndexTable
268 ///
269 /// Mesh edges are described as a pair of adjacent vertices encoded
270 /// as GfVec2i.
271 ///
272 /// The encoding of mesh edge indices is derived from the enumeration
273 /// of face vertex index pairs provided by HdMeshUtil::EnumerateEdges().
274 ///
275 /// This encoding is consistent across triangulation or quadrangulation
276 /// of the base mesh faces as well as for non-manifold faces on refined
277 /// subdivision surface meshes.
278 ///
279 /// There can be multiple edge indices associated with each pair of
280 /// topological vertices in the mesh, e.g. one for each face incident
281 /// on the edge.
282 ///
283 /// For example, here is a typical edge index assignment for a mesh
284 /// with 2 quad faces and 6 vertices:
285 ///
286 /// faceVertexCounts: [4, 4]
287 /// faceVertexIndices: [0, 1, 4, 3, 1, 2, 5, 4]
288 ///
289 /// edgeId:(edgeVertex[0], edgeVertex[1])
290 ///
291 /// 2:(3,4) 6:(4,5)
292 /// 3----------------4----------------5
293 /// | | |
294 /// | Face 0 | Face 1 |
295 /// | | |
296 /// |3:(0,3) 1:(1,4)|7:(1,4) 5:(2,5)|
297 /// | | |
298 /// | | |
299 /// | | |
300 /// 0----------------1----------------2
301 /// 0:(0,1) 4:(1,2)
302 ///
303 /// Notice that with this assignment, there are eight edge indices even
304 /// though the mesh has seven topological edges. The mesh edge between
305 /// vertex 1 and vertex 4 is associated with two edgeIds (1 and 7),
306 /// one for each incident face.
307 ///
308 /// This kind of edge index assignment can be implemented efficiently
309 /// on the GPU since it falls out automatically from the primitive
310 /// drawing order and requires minimal additional GPU data.
311 ///
312 ///
314 {
315 public:
316  HD_API
317  explicit HdMeshEdgeIndexTable(HdMeshTopology const * topology);
318  HD_API
320 
321  HD_API
322  bool GetVerticesForEdgeIndex(int edgeId, GfVec2i * edgeVerticesOut) const;
323 
324  HD_API
326  std::vector<int> const & edgeIndices,
327  std::vector<GfVec2i> * edgeVerticesOut) const;
328 
329  HD_API
330  bool GetEdgeIndices(GfVec2i const & edgeVertices,
331  std::vector<int> * edgeIndicesOut) const;
332 
333  /// Returns the edge indices for all faces in faceIndices.
334  HD_API
335  VtIntArray CollectFaceEdgeIndices(VtIntArray const &faceIndices) const;
336 
337 private:
338  struct _Edge{
339  _Edge(GfVec2i const & verts_ = GfVec2i(-1), int index_ = -1)
340  : verts(verts_)
341  , index(index_)
342  {
343  // Simplify sorting and searching by keeping the vertices ordered.
344  if (verts[0] > verts[1]) {
345  std::swap(verts[0], verts[1]);
346  }
347  }
348  GfVec2i verts;
349  int index;
350 
351  };
352 
353  struct _CompareEdgeVertices {
354  bool operator() (_Edge const &lhs, _Edge const & rhs) const {
355  return (lhs.verts[0] < rhs.verts[0] ||
356  (lhs.verts[0] == rhs.verts[0] &&
357  lhs.verts[1] < rhs.verts[1]));
358  }
359  };
360 
361  struct _EdgeVerticesHash {
362  // Use a custom hash so that edges (a,b) and (b,a) are equivalent
363  inline size_t operator()(GfVec2i const& v) const {
364  // Triangular numbers for 2-d hash.
365  int theMin = v[0], theMax = v[1];
366  if (theMin > theMax) {
367  std::swap(theMin, theMax);
368  }
369  size_t x = theMin;
370  size_t y = x + theMax;
371  return x + (y * (y + 1)) / 2;
372  }
373  };
374 
375  HdMeshTopology const *_topology;
376  std::vector<int> _firstEdgeIndexForFaces;
377 
378  std::vector<GfVec2i> _edgeVertices;
379  std::vector<_Edge> _edgesByIndex;
380 };
381 
382 /// \class HdMeshTriQuadBuilder
383 ///
384 /// Helper class for emitting a buffer of quad indices, optionally
385 /// splitting each quad into two triangles.
386 ///
388 {
389 public:
390  static int const NumIndicesPerQuad = 4;
391  static int const NumIndicesPerTriQuad = 6;
392 
393  HdMeshTriQuadBuilder(int * indicesBuffer, bool triangulate)
394  : _outputPtr(indicesBuffer)
395  , _triangulate(triangulate)
396  { }
397 
398  void EmitQuadFace(GfVec4i const & quadIndices) {
399  if (_triangulate) {
400  *_outputPtr++ = quadIndices[0];
401  *_outputPtr++ = quadIndices[1];
402  *_outputPtr++ = quadIndices[2];
403  *_outputPtr++ = quadIndices[2];
404  *_outputPtr++ = quadIndices[3];
405  *_outputPtr++ = quadIndices[0];
406  } else {
407  *_outputPtr++ = quadIndices[0];
408  *_outputPtr++ = quadIndices[1];
409  *_outputPtr++ = quadIndices[2];
410  *_outputPtr++ = quadIndices[3];
411  }
412  }
413 
414 private:
415  int * _outputPtr;
416  bool const _triangulate;
417 };
418 
419 
421 
422 #endif // PXR_IMAGING_HD_MESH_UTIL_H
Definition: vec4i.h:43
std::vector< int > numVerts
Definition: meshUtil.h:57
GLsizei GLenum const void * indices
Definition: glcorearb.h:406
HD_API void ComputeTriQuadIndices(VtIntArray *indices, VtIntArray *primitiveParams, VtVec2iArray *edgeIndices=nullptr) const
HD_API HdMeshComputationResult ComputeTriangulatedFaceVaryingPrimvar(void const *source, int numElements, HdType dataType, VtValue *triangulated) const
Definition: vec2i.h:43
HD_API void ComputeTriangleIndices(VtVec3iArray *indices, VtIntArray *primitiveParams, VtIntArray *edgeIndices=nullptr) const
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1699
HD_API bool ComputeQuadrangulatedFaceVaryingPrimvar(void const *source, int numElements, HdType dataType, VtValue *quadrangulated) const
const GLdouble * v
Definition: glcorearb.h:837
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
static int DecodeFaceIndexFromCoarseFaceParam(int coarseFaceParam)
}@
Definition: meshUtil.h:240
bool IsAllQuads() const
Returns true if the mesh is all-quads.
Definition: meshUtil.h:52
#define HD_API
Definition: api.h:23
void EmitQuadFace(GfVec4i const &quadIndices)
Definition: meshUtil.h:398
int maxNumVert
Definition: meshUtil.h:56
GLint y
Definition: glcorearb.h:103
HD_API HdMeshEdgeIndexTable(HdMeshTopology const *topology)
HD_API bool GetVerticesForEdgeIndices(std::vector< int > const &edgeIndices, std::vector< GfVec2i > *edgeVerticesOut) const
static int DecodeEdgeFlagFromCoarseFaceParam(int coarseFaceParam)
}@
Definition: meshUtil.h:243
virtual ~HdMeshUtil()
Definition: meshUtil.h:82
HdMeshTriQuadBuilder(int *indicesBuffer, bool triangulate)
Definition: meshUtil.h:393
GT_API const UT_StringHolder topology
int pointsOffset
Definition: meshUtil.h:54
GLsizei GLsizei GLchar * source
Definition: glcorearb.h:803
static int const NumIndicesPerQuad
Definition: meshUtil.h:390
HD_API VtIntArray CollectFaceEdgeIndices(VtIntArray const &faceIndices) const
Returns the edge indices for all faces in faceIndices.
Definition: path.h:280
GLint GLenum GLint x
Definition: glcorearb.h:409
HD_API ~HdMeshEdgeIndexTable()
HD_API void ComputeQuadIndices(VtIntArray *indices, VtIntArray *primitiveParams, VtVec2iArray *edgeIndices=nullptr) const
static int const NumIndicesPerTriQuad
Definition: meshUtil.h:391
int numAdditionalPoints
Definition: meshUtil.h:55
HdQuadInfo()
Definition: meshUtil.h:49
HD_API void EnumerateEdges(std::vector< GfVec2i > *edgeVerticesOut, std::vector< int > *firstEdgeIndexForFacesOut=nullptr) const
HD_API bool GetEdgeIndices(GfVec2i const &edgeVertices, std::vector< int > *edgeIndicesOut) const
GLuint index
Definition: glcorearb.h:786
A number was successfully parsed.
static int EncodeCoarseFaceParam(int faceIndex, int edgeFlag)
}@
Definition: meshUtil.h:237
HD_API bool GetVerticesForEdgeIndex(int edgeId, GfVec2i *edgeVerticesOut) const
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
HD_API bool ComputeQuadrangulatedPrimvar(HdQuadInfo const *qi, void const *source, int numElements, HdType dataType, VtValue *quadrangulated) const
HdMeshUtil(HdMeshTopology const *topology, SdfPath const &id)
Definition: meshUtil.h:80
enum nodiscard HdMeshComputationResult
Return status for a computation.
Definition: meshUtil.h:62
std::vector< int > verts
Definition: meshUtil.h:58
HdType
Definition: types.h:272
HUSD_API const char * dataType()
Definition: value.h:89
HD_API void ComputeQuadInfo(HdQuadInfo *quadInfo) const
Generate a quadInfo struct for the input topology.