OpenSubdiv
Loading...
Searching...
No Matches
vertexDescriptor.h
Go to the documentation of this file.
1//
2// Copyright 2021 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://opensubdiv.org/license.
6//
7
8#ifndef OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
9#define OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
10
11#include "../version.h"
12
13#include "../vtr/stackBuffer.h"
14
15namespace OpenSubdiv {
16namespace OPENSUBDIV_VERSION {
17
18namespace Bfr {
19
33//
34// WIP - need to migrate some of these comments into Doxygen
35// - others will be moved to the external documentation
36//
37// It is used by subclasses of SurfaceFactory to provide a complete
38// topological description for each vertex of a face, i.e. invoked via
39// the virtual method:
40//
41// int populateFaceVertexDescriptor(Index baseFace,
42// int cornerVertex,
43// VertexDescriptor & v) const;
44//
45// Assignment of the full topology can be involved in the presence of
46// irregular faces, non-manifold topology or creasing around a vertex, but
47// many cases will be simple. For example, to specify a regular boundary
48// vertex of a Catmark mesh without any optional sharpness:
49//
50// int numIncidentFaces = 2;
51// bool vertexOnBoundary = true;
52//
53// vd.Initialize(numIncidentFaces);
54// vd.SetManifold(true);
55// vd.SetBoundary(vertexOnBoundary);
56// vd.ClearIncidentFaceSizes();
57// vd.Finalize();
58//
59// For a more general example, to assign a vertex of some valence whose
60// incident faces are of different sizes (e.g. required when triangles
61// appear around a vertex in an otherwise quad-dominant Catmark mesh):
62//
63// int numIncidentFaces = meshVertex.GetNumIncidentFaces();
64// bool vertexOnBoundary = meshVertex.IsBoundar();
65//
66// vd.Initialize(numIncidentFaces);
67// vd.SetManifold(true);
68// vd.SetBoundary(vertexOnBoundary);
69//
70// for (int i = 0; i < numIncidentFaces; ++i) {
71// vd.SetIncidentFaceSize(i, meshVertex.GetIncidentFaceSize(i));
72// }
73// vd.Finalize();
74//
75// These examples specify the incident faces as forming a manifold ring
76// (or half-ring) around the vertex, i.e. they can be specified as a
77// continuous, connected sequence in counter-clockwise order (and also
78// without degeneracies). In the case of a boundary vertex, the first
79// face must be on the leading edge of the boundary while the last is on
80// the trailing edge. For an interior vertex, which face is specified
81// first does not matter (since the set is periodic).
82//
83// In both cases, the location of the base face in this sequence -- the
84// face whose corner vertex is being described here -- must be specified
85// in the return value to populateFaceVertexDescriptor() (e.g. when a
86// boundary vertex has 3 incident faces, a return value of 0, 1 or 2
87// will indicate which is the base face).
88//
89// The corresponding methods to specify mesh control vertex indices (or
90// face-varying indices) complete the specification of the neighborhood:
91//
92// int getFaceCornerVertexIndices(Index baseFace, int cornerVertex,
93// Index vertexIndices[]) const;
94//
95// int getFaceCornerFVarValueIndices(Index baseFace, int cornerVertex,
96// Index fvarValueIndices[],
97// int fvarChannel) const;
98//
99// and are invoked by the Factory when needed.
100//
101// For each incident face, the indices for all vertices of that face are
102// to be specified (not the one-ring or some other subset). These indices
103// must also be specified in an orientation relative to the vertex, i.e.
104// for a vertex A and an incident face with face-vertices that may be
105// stored internally as {D, C, A, B}, they must be specified with A first
106// as {A, B, C, D}. This may seem a bit cumbersome, but it has clear
107// advantages when dealing with face-varying indices and unordered faces.
108//
109// More compact ways of specifying vertex indices for ordered, manifold
110// cases may be worth exploring in future, but face-varying indices and
111// non-manifold (unordered) vertices will always require such a full set,
112// so both methods will need to co-exist.
113//
115public:
116 // The full declaration must be enclosed by calls to these methods:
117 //
118 // Note that vertex valences or face sizes in excess of those defined
119 // in Bfr::Limits (typically 16-bits) are not valid. When specifying
120 // values in excess of these limits, initialization will fail and/or
121 // the descriptor will be marked invalid and finalization will fail.
122 //
123
125
132
134 bool Initialize(int numIncidentFaces);
135
137 bool Finalize();
138
140 bool IsValid() const;
142
143 //
144 // WIP - need to migrate these comments into Doxygen
145 //
146 // Three groups of methods describe the topology around a vertex:
147 // - simple properties (vertex is a boundary, manifold, etc.)
148 // - sizes of incident faces (constant or size for each face)
149 // - sharpness of the vertex and its incident edges (optional)
150 //
151
152 // Manifold and boundary conditions:
153 //
154 // The manifold property is a strict condition but preferred for
155 // efficiency and is usually available from common connected mesh
156 // representations. When declaring the topology as "manifold",
157 // the Factory assumes the following:
158 //
159 // - all incident faces are "ordered" (counter-clockwise)
160 // - all incident faces are consistently oriented
161 // - all incident edges are non-degenerate
162 //
163 // If not certain that all of these conditions are met, it is best
164 // to not declare manifold -- leaving the Factory to make sense of
165 // the set of incident faces from the face-vertex indices that are
166 // provided elsewhere.
167 //
168
170
174
176 void SetManifold(bool isManifold);
177
179 void SetBoundary(bool isOnBoundary);
180
182 void SetIncidentFaceSize(int faceIndex, int faceSize);
183
186
188 void SetVertexSharpness(float sharpness);
189
192
204 void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness);
205
221 void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp,
222 float trailingEdgeSharp);
223
225 void ClearEdgeSharpness();
227
229
234
236 bool IsManifold() const;
237
239 bool IsBoundary() const;
240
242 bool HasIncidentFaceSizes() const;
243
245 int GetIncidentFaceSize(int faceIndex) const;
246
248 bool HasVertexSharpness() const;
249
251 float GetVertexSharpness() const;
252
254 bool HasEdgeSharpness() const;
255
257 float GetManifoldEdgeSharpness(int edgeIndex) const;
258
260 void GetIncidentFaceEdgeSharpness(int faceIndex,
261 float * leadingEdgeSharp, float * trailingEdgeSharp) const;
263
264protected:
266 friend class FaceVertex;
267
268 VertexDescriptor() { }
270
271 typedef Vtr::internal::StackBuffer<int,8,true> IntBuffer;
272 typedef Vtr::internal::StackBuffer<float,16,true> FloatBuffer;
273
274 void initFaceSizes();
275 void initEdgeSharpness();
277
278protected:
280 // Member variables assigned through the above interface:
281 unsigned short _isValid : 1;
282 unsigned short _isInitialized : 1;
283 unsigned short _isFinalized : 1;
284
285 unsigned short _isManifold : 1;
286 unsigned short _isBoundary : 1;
287
288 unsigned short _hasFaceSizes : 1;
289 unsigned short _hasEdgeSharpness : 1;
290
291 short _numFaces;
292 float _vertSharpness;
293
294 FloatBuffer _faceEdgeSharpness;
295 IntBuffer _faceSizeOffsets;
297};
298
299//
300// Public inline methods for simple assignment:
301//
302inline bool
304 return _isValid;
305}
306
307inline void
309 _isManifold = isManifold;
310}
311inline bool
313 return _isManifold;
314}
315
316inline void
318 _isBoundary = isBoundary;
319}
320inline bool
322 return _isBoundary;
323}
324
325//
326// Public inline methods involving sizes of incident faces:
327//
328inline bool
330 return _hasFaceSizes;
331}
332inline void
334 _hasFaceSizes = false;
335}
336
337inline void
338VertexDescriptor::SetIncidentFaceSize(int incFaceIndex, int faceSize) {
339
340 if (!_hasFaceSizes) initFaceSizes();
341
342 _faceSizeOffsets[incFaceIndex] = faceSize;
343}
344inline int
346
347 return _isFinalized ?
348 (_faceSizeOffsets[incFaceIndex+1] - _faceSizeOffsets[incFaceIndex]) :
349 _faceSizeOffsets[incFaceIndex];
350}
351
352//
353// Public inline methods involving vertex sharpness:
354//
355inline bool
357 return _vertSharpness > 0.0f;
358}
359inline void
361 _vertSharpness = 0.0f;
362}
363
364inline void
366 _vertSharpness = vertSharpness;
367}
368inline float
370 return _vertSharpness;
371}
372
373//
374// Public inline methods involving vertex sharpness:
375//
376inline bool
378 return _hasEdgeSharpness;
379}
380inline void
382 _hasEdgeSharpness = false;
383}
384
385inline void
386VertexDescriptor::SetManifoldEdgeSharpness(int edgeIndex, float sharpness) {
387
388 if (!_hasEdgeSharpness) initEdgeSharpness();
389
390 // Assign the leading edge of the face after the edge (even index):
391 if (edgeIndex < _numFaces) {
392 _faceEdgeSharpness[2*edgeIndex] = sharpness;
393 }
394
395 // Assign the trailing edge of the face before the edge (odd index):
396 if (edgeIndex > 0) {
397 _faceEdgeSharpness[2*edgeIndex-1] = sharpness;
398 } else if (!IsBoundary()) {
399 _faceEdgeSharpness[2*_numFaces-1] = sharpness;
400 }
401}
402inline float
404
405 // All edges are first of the pair (even index) except last of boundary
406 return _faceEdgeSharpness[2*edgeIndex - (edgeIndex == _numFaces)];
407}
408
409inline void
411 float leadingEdgeSharpness, float trailingEdgeSharpness) {
412
413 if (!_hasEdgeSharpness) initEdgeSharpness();
414
415 _faceEdgeSharpness[2*faceIndex ] = leadingEdgeSharpness;
416 _faceEdgeSharpness[2*faceIndex+1] = trailingEdgeSharpness;
417}
418inline void
420 float * leadingEdgeSharpness, float * trailingEdgeSharpness) const {
421
422 *leadingEdgeSharpness = _faceEdgeSharpness[2*faceIndex];
423 *trailingEdgeSharpness = _faceEdgeSharpness[2*faceIndex+1];
424}
425
426} // end namespace Bfr
427
428} // end namespace OPENSUBDIV_VERSION
429using namespace OPENSUBDIV_VERSION;
430} // end namespace OpenSubdiv
431
432#endif /* OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H */
Simple class used by subclasses of SurfaceFactory to describe a vertex.
float GetVertexSharpness() const
Return the sharpness of the vertex.
bool Finalize()
Terminate the sequence of specifications.
void SetManifold(bool isManifold)
Declare the vertex neighborhood as manifold (ordered)
bool Initialize(int numIncidentFaces)
Initialize specification with the number of incident faces.
bool IsManifold() const
Return if vertex neighborhood is manifold.
bool HasEdgeSharpness() const
Return if sharpness was assigned to the incident edges.
int GetIncidentFaceSize(int faceIndex) const
Return the size of an incident face.
float GetManifoldEdgeSharpness(int edgeIndex) const
Return the sharpness assigned to a manifold edge.
void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp, float trailingEdgeSharp)
Assign sharpness to the edges of an incident face.
bool HasVertexSharpness() const
Return if sharpness was assigned to the vertex.
void ClearIncidentFaceSizes()
Remove any assigned sizes of incident faces.
void SetVertexSharpness(float sharpness)
Assign sharpness to the vertex.
void ClearVertexSharpness()
Remove any sharpness assigned to the vertex.
void ClearEdgeSharpness()
Remove any sharpness assigned to the incident edges.
void GetIncidentFaceEdgeSharpness(int faceIndex, float *leadingEdgeSharp, float *trailingEdgeSharp) const
Return the sharpness assigned to edges of an incident face.
bool IsBoundary() const
Return if vertex neighborhood is on a boundary.
bool IsValid() const
Return if instance is valid.
bool HasIncidentFaceSizes() const
Return if the sizes of incident faces are assigned.
void SetBoundary(bool isOnBoundary)
Declare the vertex neighborhood as being on a boundary.
void SetIncidentFaceSize(int faceIndex, int faceSize)
Assign the size of an incident face.
void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness)
Assign sharpness to the edge of a manifold neighborhood.