mirror of
https://github.com/PixarAnimationStudios/OpenSubdiv
synced 2024-11-25 21:10:08 +00:00
a1c7be7c8e
This set of commits includes the addition of a new evaluation interface that treats a subdivision mesh more like a piecewise parametric surface primitive. The new interface was placed in namespace "Bfr" for "Base Face Representation" as all concepts and classes relate to a single face of the base mesh.
450 lines
16 KiB
C++
450 lines
16 KiB
C++
//
|
|
// 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 {
|
|
|
|
///
|
|
/// @brief Simple class used by subclasses of SurfaceFactory to describe a
|
|
/// vertex
|
|
///
|
|
/// VertexDescriptor is a simple class used by SurfaceFactory and its
|
|
/// subclasses to provide a complete topological description around the
|
|
/// vertex of a face, i.e. its valence, the sizes of its incident faces,
|
|
/// sharpness values, etc.
|
|
///
|
|
/// Instances are created and partially initialized by SurfaceFactory
|
|
/// before being passed to its subclasses to be fully populated. So
|
|
/// public construction is not available (or useful).
|
|
///
|
|
//
|
|
// 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.
|
|
//
|
|
|
|
//@{
|
|
/// @name Methods to begin and end specification
|
|
///
|
|
/// Partially constructed instances are populated using a set of
|
|
/// methods between calls to Initialize() and Finalize(). Both return
|
|
/// false to indicate failure due to invalid input, or the instance
|
|
/// can be inspected after each to determine if valid.
|
|
///
|
|
|
|
/// @brief Initialize specification with the number of incident faces
|
|
bool Initialize(int numIncidentFaces);
|
|
|
|
/// @brief Terminate the sequence of specifications
|
|
bool Finalize();
|
|
|
|
/// @brief Return if instance is valid
|
|
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.
|
|
//
|
|
|
|
//@{
|
|
/// @name Methods to specify topology
|
|
///
|
|
/// Methods to specify the overall topology, the sizes of incident
|
|
/// faces and any assigned sharpness values.
|
|
|
|
/// @brief Declare the vertex neighborhood as manifold (ordered)
|
|
void SetManifold(bool isManifold);
|
|
|
|
/// @brief Declare the vertex neighborhood as being on a boundary
|
|
void SetBoundary(bool isOnBoundary);
|
|
|
|
/// @brief Assign the size of an incident face
|
|
void SetIncidentFaceSize(int faceIndex, int faceSize);
|
|
|
|
/// @brief Remove any assigned sizes of incident faces
|
|
void ClearIncidentFaceSizes();
|
|
|
|
/// @brief Assign sharpness to the vertex
|
|
void SetVertexSharpness(float sharpness);
|
|
|
|
/// @brief Remove any sharpness assigned to the vertex
|
|
void ClearVertexSharpness();
|
|
|
|
/// @brief Assign sharpness to the edge of a manifold neighborhood
|
|
///
|
|
/// For use with a vertex declared manifold only, assigns a given
|
|
/// sharpness to the indicated edge in the ordered sequence of edges
|
|
/// around the vertex. In the case of a boundary vertex, the number
|
|
/// of incident edges in this ordered sequence will exceed the number
|
|
/// of incident faces by one.
|
|
///
|
|
/// @param edgeIndex Index of the edge in the ordered sequence
|
|
/// @param edgeSharpness Sharpness to be assigned to the edge
|
|
///
|
|
void SetManifoldEdgeSharpness(int edgeIndex, float edgeSharpness);
|
|
|
|
/// @brief Assign sharpness to the edges of an incident face
|
|
///
|
|
/// In all cases, sharpness can be assigned to edges by associating
|
|
/// those edges with their incident faces. This method assigns sharpness
|
|
/// to the two edges incident edges of an incident face. An alternative
|
|
/// is available for the case of a manifold vertex.
|
|
///
|
|
/// @param faceIndex Index of the incident face
|
|
/// @param leadingEdgeSharp Sharpness to assign to the leading edge
|
|
/// of the incident face, i.e. the edge of the
|
|
/// face following the vertex.
|
|
/// @param trailingEdgeSharp Sharpness to assign to the trailing edge
|
|
/// of the incident face, i.e. the edge of the
|
|
/// face preceding the vertex.
|
|
///
|
|
void SetIncidentFaceEdgeSharpness(int faceIndex, float leadingEdgeSharp,
|
|
float trailingEdgeSharp);
|
|
|
|
/// @brief Remove any sharpness assigned to the incident edges
|
|
void ClearEdgeSharpness();
|
|
//@}
|
|
|
|
//@{
|
|
/// @name Methods to inspect topology to confirm assignment
|
|
///
|
|
/// While the public interface is primarily intended for assignment,
|
|
/// methods are available to inspect intermediate results.
|
|
///
|
|
|
|
/// @brief Return if vertex neighborhood is manifold
|
|
bool IsManifold() const;
|
|
|
|
/// @brief Return if vertex neighborhood is on a boundary
|
|
bool IsBoundary() const;
|
|
|
|
/// @brief Return if the sizes of incident faces are assigned
|
|
bool HasIncidentFaceSizes() const;
|
|
|
|
/// @brief Return the size of an incident face
|
|
int GetIncidentFaceSize(int faceIndex) const;
|
|
|
|
/// @brief Return if sharpness was assigned to the vertex
|
|
bool HasVertexSharpness() const;
|
|
|
|
/// @brief Return the sharpness of the vertex
|
|
float GetVertexSharpness() const;
|
|
|
|
/// @brief Return if sharpness was assigned to the incident edges
|
|
bool HasEdgeSharpness() const;
|
|
|
|
/// @brief Return the sharpness assigned to a manifold edge
|
|
float GetManifoldEdgeSharpness(int edgeIndex) const;
|
|
|
|
/// @brief Return the sharpness assigned to edges of an incident face
|
|
void GetIncidentFaceEdgeSharpness(int faceIndex,
|
|
float * leadingEdgeSharp, float * trailingEdgeSharp) const;
|
|
//@}
|
|
|
|
protected:
|
|
/// @cond 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();
|
|
/// @endcond
|
|
|
|
protected:
|
|
/// @cond 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;
|
|
/// @endcond
|
|
};
|
|
|
|
//
|
|
// 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 */
|