vertexDescriptor.h
Go to the documentation of this file.
//
// Copyright 2021 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#ifndef OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
#define OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H
#include "../version.h"
#include "../vtr/stackBuffer.h"
namespace OpenSubdiv {
namespace OPENSUBDIV_VERSION {
namespace Bfr {
//
// WIP - need to migrate some of these comments into Doxygen
// - others will be moved to the external documentation
//
// It is used by subclasses of SurfaceFactory to provide a complete
// topological description for each vertex of a face, i.e. invoked via
// the virtual method:
//
// int populateFaceVertexDescriptor(Index baseFace,
// int cornerVertex,
// VertexDescriptor & v) const;
//
// Assignment of the full topology can be involved in the presence of
// irregular faces, non-manifold topology or creasing around a vertex, but
// many cases will be simple. For example, to specify a regular boundary
// vertex of a Catmark mesh without any optional sharpness:
//
// int numIncidentFaces = 2;
// bool vertexOnBoundary = true;
//
// vd.Initialize(numIncidentFaces);
// vd.SetManifold(true);
// vd.SetBoundary(vertexOnBoundary);
// vd.ClearIncidentFaceSizes();
// vd.Finalize();
//
// For a more general example, to assign a vertex of some valence whose
// incident faces are of different sizes (e.g. required when triangles
// appear around a vertex in an otherwise quad-dominant Catmark mesh):
//
// int numIncidentFaces = meshVertex.GetNumIncidentFaces();
// bool vertexOnBoundary = meshVertex.IsBoundar();
//
// vd.Initialize(numIncidentFaces);
// vd.SetManifold(true);
// vd.SetBoundary(vertexOnBoundary);
//
// for (int i = 0; i < numIncidentFaces; ++i) {
// vd.SetIncidentFaceSize(i, meshVertex.GetIncidentFaceSize(i));
// }
// vd.Finalize();
//
// These examples specify the incident faces as forming a manifold ring
// (or half-ring) around the vertex, i.e. they can be specified as a
// continuous, connected sequence in counter-clockwise order (and also
// without degeneracies). In the case of a boundary vertex, the first
// face must be on the leading edge of the boundary while the last is on
// the trailing edge. For an interior vertex, which face is specified
// first does not matter (since the set is periodic).
//
// In both cases, the location of the base face in this sequence -- the
// face whose corner vertex is being described here -- must be specified
// in the return value to populateFaceVertexDescriptor() (e.g. when a
// boundary vertex has 3 incident faces, a return value of 0, 1 or 2
// will indicate which is the base face).
//
// The corresponding methods to specify mesh control vertex indices (or
// face-varying indices) complete the specification of the neighborhood:
//
// int getFaceCornerVertexIndices(Index baseFace, int cornerVertex,
// Index vertexIndices[]) const;
//
// int getFaceCornerFVarValueIndices(Index baseFace, int cornerVertex,
// Index fvarValueIndices[],
// int fvarChannel) const;
//
// and are invoked by the Factory when needed.
//
// For each incident face, the indices for all vertices of that face are
// to be specified (not the one-ring or some other subset). These indices
// must also be specified in an orientation relative to the vertex, i.e.
// for a vertex A and an incident face with face-vertices that may be
// stored internally as {D, C, A, B}, they must be specified with A first
// as {A, B, C, D}. This may seem a bit cumbersome, but it has clear
// advantages when dealing with face-varying indices and unordered faces.
//
// More compact ways of specifying vertex indices for ordered, manifold
// cases may be worth exploring in future, but face-varying indices and
// non-manifold (unordered) vertices will always require such a full set,
// so both methods will need to co-exist.
//
class VertexDescriptor {
public:
// The full declaration must be enclosed by calls to these methods:
//
// Note that vertex valences or face sizes in excess of those defined
// in Bfr::Limits (typically 16-bits) are not valid. When specifying
// values in excess of these limits, initialization will fail and/or
// the descriptor will be marked invalid and finalization will fail.
//
bool Initialize(int numIncidentFaces);
bool Finalize();
bool IsValid() const;
//
// WIP - need to migrate these comments into Doxygen
//
// Three groups of methods describe the topology around a vertex:
// - simple properties (vertex is a boundary, manifold, etc.)
// - sizes of incident faces (constant or size for each face)
// - sharpness of the vertex and its incident edges (optional)
//
// Manifold and boundary conditions:
//
// The manifold property is a strict condition but preferred for
// efficiency and is usually available from common connected mesh
// representations. When declaring the topology as "manifold",
// the Factory assumes the following:
//
// - all incident faces are "ordered" (counter-clockwise)
// - all incident faces are consistently oriented
// - all incident edges are non-degenerate
//
// If not certain that all of these conditions are met, it is best
// to not declare manifold -- leaving the Factory to make sense of
// the set of incident faces from the face-vertex indices that are
// provided elsewhere.
//
void SetManifold(bool isManifold);
void SetBoundary(bool isOnBoundary);
void SetIncidentFaceSize(int faceIndex, int faceSize);
void ClearIncidentFaceSizes();
void SetVertexSharpness(float sharpness);
void ClearVertexSharpness();
void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness);
void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp,
float trailingEdgeSharp);
void ClearEdgeSharpness();
bool IsManifold() const;
bool IsBoundary() const;
bool HasIncidentFaceSizes() const;
int GetIncidentFaceSize(int faceIndex) const;
bool HasVertexSharpness() const;
float GetVertexSharpness() const;
bool HasEdgeSharpness() const;
float GetManifoldEdgeSharpness(int edgeIndex) const;
void GetIncidentFaceEdgeSharpness(int faceIndex,
float * leadingEdgeSharp, float * trailingEdgeSharp) const;
protected:
friend class FaceVertex;
VertexDescriptor() { }
~VertexDescriptor() { }
typedef Vtr::internal::StackBuffer<int,8,true> IntBuffer;
typedef Vtr::internal::StackBuffer<float,16,true> FloatBuffer;
void initFaceSizes();
void initEdgeSharpness();
protected:
// Member variables assigned through the above interface:
unsigned short _isValid : 1;
unsigned short _isInitialized : 1;
unsigned short _isFinalized : 1;
unsigned short _isManifold : 1;
unsigned short _isBoundary : 1;
unsigned short _hasFaceSizes : 1;
unsigned short _hasEdgeSharpness : 1;
short _numFaces;
float _vertSharpness;
FloatBuffer _faceEdgeSharpness;
IntBuffer _faceSizeOffsets;
};
//
// Public inline methods for simple assignment:
//
inline bool
VertexDescriptor::IsValid() const {
return _isValid;
}
inline void
VertexDescriptor::SetManifold(bool isManifold) {
_isManifold = isManifold;
}
inline bool
VertexDescriptor::IsManifold() const {
return _isManifold;
}
inline void
VertexDescriptor::SetBoundary(bool isBoundary) {
_isBoundary = isBoundary;
}
inline bool
VertexDescriptor::IsBoundary() const {
return _isBoundary;
}
//
// Public inline methods involving sizes of incident faces:
//
inline bool
VertexDescriptor::HasIncidentFaceSizes() const {
return _hasFaceSizes;
}
inline void
VertexDescriptor::ClearIncidentFaceSizes() {
_hasFaceSizes = false;
}
inline void
VertexDescriptor::SetIncidentFaceSize(int incFaceIndex, int faceSize) {
if (!_hasFaceSizes) initFaceSizes();
_faceSizeOffsets[incFaceIndex] = faceSize;
}
inline int
VertexDescriptor::GetIncidentFaceSize(int incFaceIndex) const {
return _isFinalized ?
(_faceSizeOffsets[incFaceIndex+1] - _faceSizeOffsets[incFaceIndex]) :
_faceSizeOffsets[incFaceIndex];
}
//
// Public inline methods involving vertex sharpness:
//
inline bool
VertexDescriptor::HasVertexSharpness() const {
return _vertSharpness > 0.0f;
}
inline void
VertexDescriptor::ClearVertexSharpness() {
_vertSharpness = 0.0f;
}
inline void
VertexDescriptor::SetVertexSharpness(float vertSharpness) {
_vertSharpness = vertSharpness;
}
inline float
VertexDescriptor::GetVertexSharpness() const {
return _vertSharpness;
}
//
// Public inline methods involving vertex sharpness:
//
inline bool
VertexDescriptor::HasEdgeSharpness() const {
return _hasEdgeSharpness;
}
inline void
VertexDescriptor::ClearEdgeSharpness() {
_hasEdgeSharpness = false;
}
inline void
VertexDescriptor::SetManifoldEdgeSharpness(int edgeIndex, float sharpness) {
if (!_hasEdgeSharpness) initEdgeSharpness();
// Assign the leading edge of the face after the edge (even index):
if (edgeIndex < _numFaces) {
_faceEdgeSharpness[2*edgeIndex] = sharpness;
}
// Assign the trailing edge of the face before the edge (odd index):
if (edgeIndex > 0) {
_faceEdgeSharpness[2*edgeIndex-1] = sharpness;
} else if (!IsBoundary()) {
_faceEdgeSharpness[2*_numFaces-1] = sharpness;
}
}
inline float
VertexDescriptor::GetManifoldEdgeSharpness(int edgeIndex) const {
// All edges are first of the pair (even index) except last of boundary
return _faceEdgeSharpness[2*edgeIndex - (edgeIndex == _numFaces)];
}
inline void
VertexDescriptor::SetIncidentFaceEdgeSharpness(int faceIndex,
float leadingEdgeSharpness, float trailingEdgeSharpness) {
if (!_hasEdgeSharpness) initEdgeSharpness();
_faceEdgeSharpness[2*faceIndex ] = leadingEdgeSharpness;
_faceEdgeSharpness[2*faceIndex+1] = trailingEdgeSharpness;
}
inline void
VertexDescriptor::GetIncidentFaceEdgeSharpness(int faceIndex,
float * leadingEdgeSharpness, float * trailingEdgeSharpness) const {
*leadingEdgeSharpness = _faceEdgeSharpness[2*faceIndex];
*trailingEdgeSharpness = _faceEdgeSharpness[2*faceIndex+1];
}
} // end namespace Bfr
} // end namespace OPENSUBDIV_VERSION
using namespace OPENSUBDIV_VERSION;
} // end namespace OpenSubdiv
#endif /* OPENSUBDIV3_BFR_VERTEX_DESCRIPTOR_H */
OpenSubdiv
Definition: limits.h:32
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor
Simple class used by subclasses of SurfaceFactory to describe a vertex.
Definition: vertexDescriptor.h:131
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::GetVertexSharpness
float GetVertexSharpness() const
Return the sharpness of the vertex.
Definition: vertexDescriptor.h:386
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::Finalize
bool Finalize()
Terminate the sequence of specifications.
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetManifold
void SetManifold(bool isManifold)
Declare the vertex neighborhood as manifold (ordered)
Definition: vertexDescriptor.h:325
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::Initialize
bool Initialize(int numIncidentFaces)
Initialize specification with the number of incident faces.
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::IsManifold
bool IsManifold() const
Return if vertex neighborhood is manifold.
Definition: vertexDescriptor.h:329
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::HasEdgeSharpness
bool HasEdgeSharpness() const
Return if sharpness was assigned to the incident edges.
Definition: vertexDescriptor.h:394
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::GetIncidentFaceSize
int GetIncidentFaceSize(int faceIndex) const
Return the size of an incident face.
Definition: vertexDescriptor.h:362
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::GetManifoldEdgeSharpness
float GetManifoldEdgeSharpness(int edgeIndex) const
Return the sharpness assigned to a manifold edge.
Definition: vertexDescriptor.h:420
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetIncidentFaceEdgeSharpness
void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp, float trailingEdgeSharp)
Assign sharpness to the edges of an incident face.
Definition: vertexDescriptor.h:427
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::HasVertexSharpness
bool HasVertexSharpness() const
Return if sharpness was assigned to the vertex.
Definition: vertexDescriptor.h:373
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::ClearIncidentFaceSizes
void ClearIncidentFaceSizes()
Remove any assigned sizes of incident faces.
Definition: vertexDescriptor.h:350
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetVertexSharpness
void SetVertexSharpness(float sharpness)
Assign sharpness to the vertex.
Definition: vertexDescriptor.h:382
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::ClearVertexSharpness
void ClearVertexSharpness()
Remove any sharpness assigned to the vertex.
Definition: vertexDescriptor.h:377
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::ClearEdgeSharpness
void ClearEdgeSharpness()
Remove any sharpness assigned to the incident edges.
Definition: vertexDescriptor.h:398
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::GetIncidentFaceEdgeSharpness
void GetIncidentFaceEdgeSharpness(int faceIndex, float *leadingEdgeSharp, float *trailingEdgeSharp) const
Return the sharpness assigned to edges of an incident face.
Definition: vertexDescriptor.h:436
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::IsBoundary
bool IsBoundary() const
Return if vertex neighborhood is on a boundary.
Definition: vertexDescriptor.h:338
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::IsValid
bool IsValid() const
Return if instance is valid.
Definition: vertexDescriptor.h:320
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::HasIncidentFaceSizes
bool HasIncidentFaceSizes() const
Return if the sizes of incident faces are assigned.
Definition: vertexDescriptor.h:346
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetBoundary
void SetBoundary(bool isOnBoundary)
Declare the vertex neighborhood as being on a boundary.
Definition: vertexDescriptor.h:334
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetIncidentFaceSize
void SetIncidentFaceSize(int faceIndex, int faceSize)
Assign the size of an incident face.
Definition: vertexDescriptor.h:355
OpenSubdiv::OPENSUBDIV_VERSION::Bfr::VertexDescriptor::SetManifoldEdgeSharpness
void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness)
Assign sharpness to the edge of a manifold neighborhood.
Definition: vertexDescriptor.h:403