OpenSubdiv
vertexDescriptor.h
Go to the documentation of this file.
1 //
2 // Copyright 2021 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #ifndef OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
26 #define OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
27 
28 #include "../version.h"
29 
30 #include "../vtr/stackBuffer.h"
31 
32 namespace OpenSubdiv {
33 namespace OPENSUBDIV_VERSION {
34 
35 namespace Bfr {
36 
50 //
51 // WIP - need to migrate some of these comments into Doxygen
52 // - others will be moved to the external documentation
53 //
54 // It is used by subclasses of SurfaceFactory to provide a complete
55 // topological description for each vertex of a face, i.e. invoked via
56 // the virtual method:
57 //
58 // int populateFaceVertexDescriptor(Index baseFace,
59 // int cornerVertex,
60 // VertexDescriptor & v) const;
61 //
62 // Assignment of the full topology can be involved in the presence of
63 // irregular faces, non-manifold topology or creasing around a vertex, but
64 // many cases will be simple. For example, to specify a regular boundary
65 // vertex of a Catmark mesh without any optional sharpness:
66 //
67 // int numIncidentFaces = 2;
68 // bool vertexOnBoundary = true;
69 //
70 // vd.Initialize(numIncidentFaces);
71 // vd.SetManifold(true);
72 // vd.SetBoundary(vertexOnBoundary);
73 // vd.ClearIncidentFaceSizes();
74 // vd.Finalize();
75 //
76 // For a more general example, to assign a vertex of some valence whose
77 // incident faces are of different sizes (e.g. required when triangles
78 // appear around a vertex in an otherwise quad-dominant Catmark mesh):
79 //
80 // int numIncidentFaces = meshVertex.GetNumIncidentFaces();
81 // bool vertexOnBoundary = meshVertex.IsBoundar();
82 //
83 // vd.Initialize(numIncidentFaces);
84 // vd.SetManifold(true);
85 // vd.SetBoundary(vertexOnBoundary);
86 //
87 // for (int i = 0; i < numIncidentFaces; ++i) {
88 // vd.SetIncidentFaceSize(i, meshVertex.GetIncidentFaceSize(i));
89 // }
90 // vd.Finalize();
91 //
92 // These examples specify the incident faces as forming a manifold ring
93 // (or half-ring) around the vertex, i.e. they can be specified as a
94 // continuous, connected sequence in counter-clockwise order (and also
95 // without degeneracies). In the case of a boundary vertex, the first
96 // face must be on the leading edge of the boundary while the last is on
97 // the trailing edge. For an interior vertex, which face is specified
98 // first does not matter (since the set is periodic).
99 //
100 // In both cases, the location of the base face in this sequence -- the
101 // face whose corner vertex is being described here -- must be specified
102 // in the return value to populateFaceVertexDescriptor() (e.g. when a
103 // boundary vertex has 3 incident faces, a return value of 0, 1 or 2
104 // will indicate which is the base face).
105 //
106 // The corresponding methods to specify mesh control vertex indices (or
107 // face-varying indices) complete the specification of the neighborhood:
108 //
109 // int getFaceCornerVertexIndices(Index baseFace, int cornerVertex,
110 // Index vertexIndices[]) const;
111 //
112 // int getFaceCornerFVarValueIndices(Index baseFace, int cornerVertex,
113 // Index fvarValueIndices[],
114 // int fvarChannel) const;
115 //
116 // and are invoked by the Factory when needed.
117 //
118 // For each incident face, the indices for all vertices of that face are
119 // to be specified (not the one-ring or some other subset). These indices
120 // must also be specified in an orientation relative to the vertex, i.e.
121 // for a vertex A and an incident face with face-vertices that may be
122 // stored internally as {D, C, A, B}, they must be specified with A first
123 // as {A, B, C, D}. This may seem a bit cumbersome, but it has clear
124 // advantages when dealing with face-varying indices and unordered faces.
125 //
126 // More compact ways of specifying vertex indices for ordered, manifold
127 // cases may be worth exploring in future, but face-varying indices and
128 // non-manifold (unordered) vertices will always require such a full set,
129 // so both methods will need to co-exist.
130 //
132 public:
133  // The full declaration must be enclosed by calls to these methods:
134  //
135  // Note that vertex valences or face sizes in excess of those defined
136  // in Bfr::Limits (typically 16-bits) are not valid. When specifying
137  // values in excess of these limits, initialization will fail and/or
138  // the descriptor will be marked invalid and finalization will fail.
139  //
140 
142 
151  bool Initialize(int numIncidentFaces);
152 
154  bool Finalize();
155 
157  bool IsValid() const;
159 
160  //
161  // WIP - need to migrate these comments into Doxygen
162  //
163  // Three groups of methods describe the topology around a vertex:
164  // - simple properties (vertex is a boundary, manifold, etc.)
165  // - sizes of incident faces (constant or size for each face)
166  // - sharpness of the vertex and its incident edges (optional)
167  //
168 
169  // Manifold and boundary conditions:
170  //
171  // The manifold property is a strict condition but preferred for
172  // efficiency and is usually available from common connected mesh
173  // representations. When declaring the topology as "manifold",
174  // the Factory assumes the following:
175  //
176  // - all incident faces are "ordered" (counter-clockwise)
177  // - all incident faces are consistently oriented
178  // - all incident edges are non-degenerate
179  //
180  // If not certain that all of these conditions are met, it is best
181  // to not declare manifold -- leaving the Factory to make sense of
182  // the set of incident faces from the face-vertex indices that are
183  // provided elsewhere.
184  //
185 
187 
193  void SetManifold(bool isManifold);
194 
196  void SetBoundary(bool isOnBoundary);
197 
199  void SetIncidentFaceSize(int faceIndex, int faceSize);
200 
202  void ClearIncidentFaceSizes();
203 
205  void SetVertexSharpness(float sharpness);
206 
208  void ClearVertexSharpness();
209 
221  void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness);
222 
238  void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp,
239  float trailingEdgeSharp);
240 
242  void ClearEdgeSharpness();
244 
246 
253  bool IsManifold() const;
254 
256  bool IsBoundary() const;
257 
259  bool HasIncidentFaceSizes() const;
260 
262  int GetIncidentFaceSize(int faceIndex) const;
263 
265  bool HasVertexSharpness() const;
266 
268  float GetVertexSharpness() const;
269 
271  bool HasEdgeSharpness() const;
272 
274  float GetManifoldEdgeSharpness(int edgeIndex) const;
275 
277  void GetIncidentFaceEdgeSharpness(int faceIndex,
278  float * leadingEdgeSharp, float * trailingEdgeSharp) const;
280 
281 protected:
283  friend class FaceVertex;
284 
285  VertexDescriptor() { }
286  ~VertexDescriptor() { }
287 
288  typedef Vtr::internal::StackBuffer<int,8,true> IntBuffer;
289  typedef Vtr::internal::StackBuffer<float,16,true> FloatBuffer;
290 
291  void initFaceSizes();
292  void initEdgeSharpness();
294 
295 protected:
297  // Member variables assigned through the above interface:
298  unsigned short _isValid : 1;
299  unsigned short _isInitialized : 1;
300  unsigned short _isFinalized : 1;
301 
302  unsigned short _isManifold : 1;
303  unsigned short _isBoundary : 1;
304 
305  unsigned short _hasFaceSizes : 1;
306  unsigned short _hasEdgeSharpness : 1;
307 
308  short _numFaces;
309  float _vertSharpness;
310 
311  FloatBuffer _faceEdgeSharpness;
312  IntBuffer _faceSizeOffsets;
314 };
315 
316 //
317 // Public inline methods for simple assignment:
318 //
319 inline bool
321  return _isValid;
322 }
323 
324 inline void
326  _isManifold = isManifold;
327 }
328 inline bool
330  return _isManifold;
331 }
332 
333 inline void
335  _isBoundary = isBoundary;
336 }
337 inline bool
339  return _isBoundary;
340 }
341 
342 //
343 // Public inline methods involving sizes of incident faces:
344 //
345 inline bool
347  return _hasFaceSizes;
348 }
349 inline void
351  _hasFaceSizes = false;
352 }
353 
354 inline void
355 VertexDescriptor::SetIncidentFaceSize(int incFaceIndex, int faceSize) {
356 
357  if (!_hasFaceSizes) initFaceSizes();
358 
359  _faceSizeOffsets[incFaceIndex] = faceSize;
360 }
361 inline int
362 VertexDescriptor::GetIncidentFaceSize(int incFaceIndex) const {
363 
364  return _isFinalized ?
365  (_faceSizeOffsets[incFaceIndex+1] - _faceSizeOffsets[incFaceIndex]) :
366  _faceSizeOffsets[incFaceIndex];
367 }
368 
369 //
370 // Public inline methods involving vertex sharpness:
371 //
372 inline bool
374  return _vertSharpness > 0.0f;
375 }
376 inline void
378  _vertSharpness = 0.0f;
379 }
380 
381 inline void
383  _vertSharpness = vertSharpness;
384 }
385 inline float
387  return _vertSharpness;
388 }
389 
390 //
391 // Public inline methods involving vertex sharpness:
392 //
393 inline bool
395  return _hasEdgeSharpness;
396 }
397 inline void
399  _hasEdgeSharpness = false;
400 }
401 
402 inline void
403 VertexDescriptor::SetManifoldEdgeSharpness(int edgeIndex, float sharpness) {
404 
405  if (!_hasEdgeSharpness) initEdgeSharpness();
406 
407  // Assign the leading edge of the face after the edge (even index):
408  if (edgeIndex < _numFaces) {
409  _faceEdgeSharpness[2*edgeIndex] = sharpness;
410  }
411 
412  // Assign the trailing edge of the face before the edge (odd index):
413  if (edgeIndex > 0) {
414  _faceEdgeSharpness[2*edgeIndex-1] = sharpness;
415  } else if (!IsBoundary()) {
416  _faceEdgeSharpness[2*_numFaces-1] = sharpness;
417  }
418 }
419 inline float
421 
422  // All edges are first of the pair (even index) except last of boundary
423  return _faceEdgeSharpness[2*edgeIndex - (edgeIndex == _numFaces)];
424 }
425 
426 inline void
428  float leadingEdgeSharpness, float trailingEdgeSharpness) {
429 
430  if (!_hasEdgeSharpness) initEdgeSharpness();
431 
432  _faceEdgeSharpness[2*faceIndex ] = leadingEdgeSharpness;
433  _faceEdgeSharpness[2*faceIndex+1] = trailingEdgeSharpness;
434 }
435 inline void
437  float * leadingEdgeSharpness, float * trailingEdgeSharpness) const {
438 
439  *leadingEdgeSharpness = _faceEdgeSharpness[2*faceIndex];
440  *trailingEdgeSharpness = _faceEdgeSharpness[2*faceIndex+1];
441 }
442 
443 } // end namespace Bfr
444 
445 } // end namespace OPENSUBDIV_VERSION
446 using namespace OPENSUBDIV_VERSION;
447 } // end namespace OpenSubdiv
448 
449 #endif /* OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H */
void GetIncidentFaceEdgeSharpness(int faceIndex, float *leadingEdgeSharp, float *trailingEdgeSharp) const
Return the sharpness assigned to edges of an incident face.
bool HasIncidentFaceSizes() const
Return if the sizes of incident faces are assigned.
void SetManifold(bool isManifold)
Declare the vertex neighborhood as manifold (ordered)
bool IsBoundary() const
Return if vertex neighborhood is on a boundary.
void SetVertexSharpness(float sharpness)
Assign sharpness to the vertex.
void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp, float trailingEdgeSharp)
Assign sharpness to the edges of an incident face.
bool IsManifold() const
Return if vertex neighborhood is manifold.
bool HasVertexSharpness() const
Return if sharpness was assigned to the vertex.
float GetVertexSharpness() const
Return the sharpness of the vertex.
bool IsValid() const
Return if instance is valid.
void ClearVertexSharpness()
Remove any sharpness assigned to the vertex.
void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness)
Assign sharpness to the edge of a manifold neighborhood.
bool Finalize()
Terminate the sequence of specifications.
void ClearEdgeSharpness()
Remove any sharpness assigned to the incident edges.
bool Initialize(int numIncidentFaces)
Initialize specification with the number of incident faces.
float GetManifoldEdgeSharpness(int edgeIndex) const
Return the sharpness assigned to a manifold edge.
Simple class used by subclasses of SurfaceFactory to describe a vertex.
void SetBoundary(bool isOnBoundary)
Declare the vertex neighborhood as being on a boundary.
void ClearIncidentFaceSizes()
Remove any assigned sizes of incident faces.
void SetIncidentFaceSize(int faceIndex, int faceSize)
Assign the size of an incident face.
bool HasEdgeSharpness() const
Return if sharpness was assigned to the incident edges.
int GetIncidentFaceSize(int faceIndex) const
Return the size of an incident face.