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 /// \class HdMeshUtil
62 /// A collection of utility algorithms for generating triangulation
63 /// and quadrangulation of an input topology.
64 
66 {
67 public:
69  : _topology(topology), _id(id) {}
70  virtual ~HdMeshUtil() {}
71 
72  // --------------------------------------------------------------------
73  /// \name Triangulation
74  ///
75  /// Produces a mesh where each non-triangle face in the base mesh topology
76  /// is fan-triangulated such that the resulting mesh consists entirely
77  /// of triangles.
78  ///
79  /// In order to access per-face signals (face color, face selection etc)
80  /// we need a mapping from primitiveID to authored face index domain.
81  /// This is encoded in primitiveParams, and computed along with indices.
82  /// See \ref PrimitiveParamEncoding.
83  /// @{
84  /*
85  +--------+-------+
86  /| \ |\ |\
87  / | \ 1 | \ 2 | \
88  / | \ | \ | \
89  / | \ | \ | 2 +
90  / 0 | 1 \ | 2 \ | /
91  / | \ | \ | /
92  / | \| \|/
93  +-------+--------+-------+
94  */
95 
96  /// Return a triangulation of the input topology. indices and
97  /// primitiveParams are output parameters.
98  HD_API
99  void ComputeTriangleIndices(VtVec3iArray *indices,
100  VtIntArray *primitiveParams,
101  VtIntArray *edgeIndices = nullptr) const;
102 
103  /// Return a triangulation of a face-varying primvar. source is
104  /// a buffer of size numElements and type corresponding to dataType
105  /// (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
106  /// correct type written to the variable "triangulated".
107  /// This function returns false if it can't resolve dataType.
108  HD_API
110  int numElements,
112  VtValue *triangulated) const;
113 
114  /// @}
115 
116  // --------------------------------------------------------------------
117  /// \name Quadrangulation
118  ///
119  /// Produces a mesh where each non-quad face in the base mesh topology
120  /// is quadrangulated such that the resulting mesh consists entirely
121  /// of quads. Additionally, supports splitting each resulting quad
122  /// face into a pair of triangles. This is different than simply
123  /// triangulating the base mesh topology and can be useful for
124  /// maintaining consistency with quad-based subdivision schemes.
125  ///
126  /// In order to access per-face signals (face color, face selection etc)
127  /// we need a mapping from primitiveID to authored face index domain.
128  /// This is encoded in primitiveParams, and computed along with indices.
129  /// See \ref PrimitiveParamEncoding.
130  /// @{
131 
132  /*
133  +--------+-------+
134  /| | | \
135  / | | 2 | 2 /\
136  / | | \ / \
137  / 0 | 1 |------+ 2 +
138  /\ /| | / \ /
139  / \/ | | 2 | 2 \/
140  / 0 | 0| | | /
141  +-------+--------+-------+
142  */
143 
144  /// Generate a quadInfo struct for the input topology.
145  HD_API
146  void ComputeQuadInfo(HdQuadInfo* quadInfo) const;
147 
148  /// Return quadrangulated indices of the input topology. indices and
149  /// primitiveParams are output parameters.
150  HD_API
151  void ComputeQuadIndices(VtIntArray *indices,
152  VtIntArray *primitiveParams,
153  VtVec2iArray *edgeIndices = nullptr) const;
154 
155  /// Return triquad indices (triangulated after quadrangulation) of the
156  /// input topology. indices and primitiveParams are output parameters.
157  HD_API
158  void ComputeTriQuadIndices(VtIntArray *indices,
159  VtIntArray *primitiveParams,
160  VtVec2iArray *edgeIndices = nullptr) const;
161 
162  /// Return a quadrangulation of a per-vertex primvar. source is
163  /// a buffer of size numElements and type corresponding to dataType
164  /// (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
165  /// correct type written to the variable "quadrangulated".
166  /// This function returns false if it can't resolve dataType.
167  HD_API
169  void const* source,
170  int numElements,
172  VtValue *quadrangulated) const;
173 
174  /// Return a quadrangulation of a face-varying primvar.
175  /// source is a buffer of size numElements and type corresponding
176  /// to dataType (e.g. HdTypeFloatVec3); the result is a VtArray<T> of the
177  /// correct type written to the variable "quadrangulated".
178  /// This function returns false if it can't resolve dataType.
179  HD_API
181  int numElements,
183  VtValue *quadrangulated) const;
184 
185  /// @}
186 
187  /// Return a buffer filled with face vertex index pairs corresponding
188  /// to the sequence in which edges are visited when iterating through
189  /// the mesh topology. The edges of degenerate and hole faces are
190  /// included so that this sequence will correspond with either base
191  /// face triangulation or quadrangulation (which typically skips
192  /// over hole faces) as well as for refined surfaces which take into
193  /// account faces tagged as holes as well as other non-manifold faces.
194  /// Optionally, records the first edge index for each face.
195  /// Subsequent edge indices for each face are implicitly assigned
196  /// sequentially following the first edge index.
197  HD_API
198  void EnumerateEdges(
199  std::vector<GfVec2i> * edgeVerticesOut,
200  std::vector<int> * firstEdgeIndexForFacesOut = nullptr) const;
201 
202  // --------------------------------------------------------------------
203  /// \anchor PrimitiveParamEncoding
204  /// \name Primitive Param bit encoding
205  ///
206  /// This encoding provides information about each sub-face resulting
207  /// from the triangulation or quadrangulation of a base topology face.
208  ///
209  /// The encoded faceIndex is the index of the base topology face
210  /// corresponding to a triangulated or quadrangulated sub-face.
211  ///
212  /// The encoded edge flag identifies where a sub-face occurs in the
213  /// sequence of sub-faces produced for each base topology face.
214  /// This edge flag can be used to determine which edges of a sub-face
215  /// correspond to edges of a base topology face and which are internal
216  /// edges that were introduced by triangulation or quadrangulation:
217  /// - 0 unaffected triangle or quad base topology face
218  /// - 1 first sub-face produced by triangulation or quadrangulation
219  /// - 2 last sub-face produced by triangulation or quadrangulation
220  /// - 3 intermediate sub-face produced by triangulation or quadrangulation
221  /// @{
222 
223  // Per-primitive coarse-face-param encoding/decoding functions
224  static int EncodeCoarseFaceParam(int faceIndex, int edgeFlag) {
225  return ((faceIndex << 2) | (edgeFlag & 3));
226  }
227  static int DecodeFaceIndexFromCoarseFaceParam(int coarseFaceParam) {
228  return (coarseFaceParam >> 2);
229  }
230  static int DecodeEdgeFlagFromCoarseFaceParam(int coarseFaceParam) {
231  return (coarseFaceParam & 3);
232  }
233 
234  /// }@
235 
236 private:
237  /// Return the number of quadrangulated quads.
238  /// If degenerate face is found, sets invalidFaceFound as true.
239  int _ComputeNumQuads(VtIntArray const &numVerts,
240  VtIntArray const &holeIndices,
241  bool *invalidFaceFound = nullptr) const;
242 
243  /// Return quad indices (optionally triangulated after quadrangulation).
244  void _ComputeQuadIndices(
245  VtIntArray *indices,
246  VtIntArray *primitiveParams,
247  VtVec2iArray *edgeIndices,
248  bool triangulate = false) const;
249 
250  HdMeshTopology const* _topology;
251  SdfPath const _id;
252 };
253 
254 /// \class HdMeshEdgeIndexTable
255 ///
256 /// Mesh edges are described as a pair of adjacent vertices encoded
257 /// as GfVec2i.
258 ///
259 /// The encoding of mesh edge indices is derived from the enumeration
260 /// of face vertex index pairs provided by HdMeshUtil::EnumerateEdges().
261 ///
262 /// This encoding is consistent across triangulation or quadrangulation
263 /// of the base mesh faces as well as for non-manifold faces on refined
264 /// subdivision surface meshes.
265 ///
266 /// There can be multiple edge indices associated with each pair of
267 /// topological vertices in the mesh, e.g. one for each face incident
268 /// on the edge.
269 ///
270 /// For example, here is a typical edge index assignment for a mesh
271 /// with 2 quad faces and 6 vertices:
272 ///
273 /// faceVertexCounts: [4, 4]
274 /// faceVertexIndices: [0, 1, 4, 3, 1, 2, 5, 4]
275 ///
276 /// edgeId:(edgeVertex[0], edgeVertex[1])
277 ///
278 /// 2:(3,4) 6:(4,5)
279 /// 3----------------4----------------5
280 /// | | |
281 /// | Face 0 | Face 1 |
282 /// | | |
283 /// |3:(0,3) 1:(1,4)|7:(1,4) 5:(2,5)|
284 /// | | |
285 /// | | |
286 /// | | |
287 /// 0----------------1----------------2
288 /// 0:(0,1) 4:(1,2)
289 ///
290 /// Notice that with this assignment, there are eight edge indices even
291 /// though the mesh has seven topological edges. The mesh edge between
292 /// vertex 1 and vertex 4 is associated with two edgeIds (1 and 7),
293 /// one for each incident face.
294 ///
295 /// This kind of edge index assignment can be implemented efficiently
296 /// on the GPU since it falls out automatically from the primitive
297 /// drawing order and requires minimal additional GPU data.
298 ///
299 ///
301 {
302 public:
303  HD_API
304  explicit HdMeshEdgeIndexTable(HdMeshTopology const * topology);
305  HD_API
307 
308  HD_API
309  bool GetVerticesForEdgeIndex(int edgeId, GfVec2i * edgeVerticesOut) const;
310 
311  HD_API
313  std::vector<int> const & edgeIndices,
314  std::vector<GfVec2i> * edgeVerticesOut) const;
315 
316  HD_API
317  bool GetEdgeIndices(GfVec2i const & edgeVertices,
318  std::vector<int> * edgeIndicesOut) const;
319 
320  /// Returns the edge indices for all faces in faceIndices.
321  HD_API
322  VtIntArray CollectFaceEdgeIndices(VtIntArray const &faceIndices) const;
323 
324 private:
325  struct _Edge{
326  _Edge(GfVec2i const & verts_ = GfVec2i(-1), int index_ = -1)
327  : verts(verts_)
328  , index(index_)
329  {
330  // Simplify sorting and searching by keeping the vertices ordered.
331  if (verts[0] > verts[1]) {
332  std::swap(verts[0], verts[1]);
333  }
334  }
335  GfVec2i verts;
336  int index;
337 
338  };
339 
340  struct _CompareEdgeVertices {
341  bool operator() (_Edge const &lhs, _Edge const & rhs) const {
342  return (lhs.verts[0] < rhs.verts[0] ||
343  (lhs.verts[0] == rhs.verts[0] &&
344  lhs.verts[1] < rhs.verts[1]));
345  }
346  };
347 
348  struct _EdgeVerticesHash {
349  // Use a custom hash so that edges (a,b) and (b,a) are equivalent
350  inline size_t operator()(GfVec2i const& v) const {
351  // Triangular numbers for 2-d hash.
352  int theMin = v[0], theMax = v[1];
353  if (theMin > theMax) {
354  std::swap(theMin, theMax);
355  }
356  size_t x = theMin;
357  size_t y = x + theMax;
358  return x + (y * (y + 1)) / 2;
359  }
360  };
361 
362  HdMeshTopology const *_topology;
363  std::vector<int> _firstEdgeIndexForFaces;
364 
365  std::vector<GfVec2i> _edgeVertices;
366  std::vector<_Edge> _edgesByIndex;
367 };
368 
369 /// \class HdMeshTriQuadBuilder
370 ///
371 /// Helper class for emitting a buffer of quad indices, optionally
372 /// splitting each quad into two triangles.
373 ///
375 {
376 public:
377  static int const NumIndicesPerQuad = 4;
378  static int const NumIndicesPerTriQuad = 6;
379 
380  HdMeshTriQuadBuilder(int * indicesBuffer, bool triangulate)
381  : _outputPtr(indicesBuffer)
382  , _triangulate(triangulate)
383  { }
384 
385  void EmitQuadFace(GfVec4i const & quadIndices) {
386  if (_triangulate) {
387  *_outputPtr++ = quadIndices[0];
388  *_outputPtr++ = quadIndices[1];
389  *_outputPtr++ = quadIndices[2];
390  *_outputPtr++ = quadIndices[2];
391  *_outputPtr++ = quadIndices[3];
392  *_outputPtr++ = quadIndices[0];
393  } else {
394  *_outputPtr++ = quadIndices[0];
395  *_outputPtr++ = quadIndices[1];
396  *_outputPtr++ = quadIndices[2];
397  *_outputPtr++ = quadIndices[3];
398  }
399  }
400 
401 private:
402  int * _outputPtr;
403  bool const _triangulate;
404 };
405 
406 
408 
409 #endif // PXR_IMAGING_HD_MESH_UTIL_H
Definition: vec4i.h:43
HD_API bool ComputeTriangulatedFaceVaryingPrimvar(void const *source, int numElements, HdType dataType, VtValue *triangulated) const
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
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
static int DecodeFaceIndexFromCoarseFaceParam(int coarseFaceParam)
}@
Definition: meshUtil.h:227
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:385
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:230
virtual ~HdMeshUtil()
Definition: meshUtil.h:70
HdMeshTriQuadBuilder(int *indicesBuffer, bool triangulate)
Definition: meshUtil.h:380
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:377
HD_API VtIntArray CollectFaceEdgeIndices(VtIntArray const &faceIndices) const
Returns the edge indices for all faces in faceIndices.
Definition: path.h:273
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:378
int numAdditionalPoints
Definition: meshUtil.h:55
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
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
static int EncodeCoarseFaceParam(int faceIndex, int edgeFlag)
}@
Definition: meshUtil.h:224
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:68
std::vector< int > verts
Definition: meshUtil.h:58
HdType
Definition: types.h:272
HUSD_API const char * dataType()
Definition: value.h:146
HD_API void ComputeQuadInfo(HdQuadInfo *quadInfo) const
Generate a quadInfo struct for the input topology.