Add Chromium-only Blender WebEngine parity work
This commit is contained in:
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/CMakeLists.txt
vendored
Normal file
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
#
|
||||
# Copyright 2013 Pixar
|
||||
#
|
||||
# Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
# https://opensubdiv.org/license.
|
||||
#
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
set(PUBLIC_HEADER_FILES
|
||||
bilinearScheme.h
|
||||
catmarkScheme.h
|
||||
crease.h
|
||||
loopScheme.h
|
||||
options.h
|
||||
scheme.h
|
||||
types.h
|
||||
)
|
||||
|
||||
set(PRIVATE_HEADER_FILES )
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# source & headers
|
||||
set(SOURCE_FILES
|
||||
crease.cpp
|
||||
typeTraits.cpp
|
||||
)
|
||||
|
||||
set(DOXY_HEADER_FILES ${PUBLIC_HEADER_FILES})
|
||||
|
||||
include_directories("${CMAKE_CURRENT_BINARY_DIR}")
|
||||
|
||||
if (NOT NO_LIB)
|
||||
add_library(sdc_obj
|
||||
OBJECT
|
||||
${SOURCE_FILES}
|
||||
${PRIVATE_HEADER_FILES}
|
||||
${PUBLIC_HEADER_FILES}
|
||||
)
|
||||
|
||||
set_target_properties(sdc_obj
|
||||
PROPERTIES
|
||||
FOLDER "opensubdiv"
|
||||
)
|
||||
|
||||
endif()
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
osd_add_doxy_headers( "${DOXY_HEADER_FILES}" )
|
||||
|
||||
install(
|
||||
FILES
|
||||
${PUBLIC_HEADER_FILES}
|
||||
DESTINATION
|
||||
"${CMAKE_INCDIR_BASE}/sdc"
|
||||
PERMISSIONS
|
||||
OWNER_READ
|
||||
GROUP_READ
|
||||
WORLD_READ )
|
||||
|
||||
147
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/bilinearScheme.h
vendored
Normal file
147
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/bilinearScheme.h
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_BILINEAR_SCHEME_H
|
||||
#define OPENSUBDIV3_SDC_BILINEAR_SCHEME_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/scheme.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
//
|
||||
// Specializations for Scheme<SCHEME_BILINEAR>:
|
||||
//
|
||||
|
||||
//
|
||||
// Bilinear traits:
|
||||
//
|
||||
template <>
|
||||
inline Split Scheme<SCHEME_BILINEAR>::GetTopologicalSplitType() { return SPLIT_TO_QUADS; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_BILINEAR>::GetRegularFaceSize() { return 4; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_BILINEAR>::GetRegularVertexValence() { return 4; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_BILINEAR>::GetLocalNeighborhoodSize() { return 0; }
|
||||
|
||||
|
||||
//
|
||||
// Refinement masks:
|
||||
//
|
||||
template <>
|
||||
template <typename EDGE, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME_BILINEAR>::ComputeEdgeVertexMask(EDGE const& edge, MASK& mask,
|
||||
Crease::Rule, Crease::Rule) const {
|
||||
// This should be inline, otherwise trivially replicate it:
|
||||
assignCreaseMaskForEdge(edge, mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME_BILINEAR>::ComputeVertexVertexMask(VERTEX const& vertex, MASK& mask,
|
||||
Crease::Rule, Crease::Rule) const {
|
||||
// This should be inline, otherwise trivially replicate it:
|
||||
assignCornerMaskForVertex(vertex, mask);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Limit masks for position -- the limit position of all vertices is the refined vertex.
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(0);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
posMask.VertexWeight(0) = 1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
|
||||
int const /* creaseEnds */[2]) const {
|
||||
|
||||
assignCornerLimitMask(vertex, posMask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
|
||||
|
||||
assignCornerLimitMask(vertex, posMask);
|
||||
}
|
||||
|
||||
//
|
||||
// Limit masks for tangents -- these are ambiguous around all vertices. Provide
|
||||
// the tangents based on the incident edges of the first face.
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignCornerLimitTangentMasks(VERTEX const& /* vertex */,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(2);
|
||||
tan1Mask.SetNumFaceWeights(0);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(2);
|
||||
tan2Mask.SetNumFaceWeights(0);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan1Mask.VertexWeight(0) = -1.0f;
|
||||
tan1Mask.EdgeWeight(0) = 1.0f;
|
||||
tan1Mask.EdgeWeight(1) = 0.0f;
|
||||
|
||||
tan2Mask.VertexWeight(0) = -1.0f;
|
||||
tan2Mask.EdgeWeight(0) = 0.0f;
|
||||
tan2Mask.EdgeWeight(1) = 1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask, int const /* creaseEnds */[2]) const {
|
||||
|
||||
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_BILINEAR>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
|
||||
}
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_BILINEAR_SCHEME_H */
|
||||
519
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/catmarkScheme.h
vendored
Normal file
519
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/catmarkScheme.h
vendored
Normal file
@@ -0,0 +1,519 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_CATMARK_SCHEME_H
|
||||
#define OPENSUBDIV3_SDC_CATMARK_SCHEME_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/scheme.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
//
|
||||
// Specializations for Scheme<SCHEME_CATMARK>:
|
||||
//
|
||||
|
||||
//
|
||||
// Catmark traits:
|
||||
//
|
||||
template <>
|
||||
inline Split Scheme<SCHEME_CATMARK>::GetTopologicalSplitType() { return SPLIT_TO_QUADS; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_CATMARK>::GetRegularFaceSize() { return 4; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_CATMARK>::GetRegularVertexValence() { return 4; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_CATMARK>::GetLocalNeighborhoodSize() { return 1; }
|
||||
|
||||
|
||||
//
|
||||
// Masks for edge-vertices: the hard Crease mask does not need to be specialized
|
||||
// (simply the midpoint), so all that is left is the Smooth case:
|
||||
//
|
||||
// The Smooth mask is complicated by the need to support the "triangle subdivision"
|
||||
// option, which applies different weighting in the presence of triangles. It is
|
||||
// up for debate as to whether this is useful or not -- we may be able to deprecate
|
||||
// this option.
|
||||
//
|
||||
template <>
|
||||
template <typename EDGE, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int faceCount = edge.GetNumFaces();
|
||||
|
||||
mask.SetNumVertexWeights(2);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(faceCount);
|
||||
mask.SetFaceWeightsForFaceCenters(true);
|
||||
|
||||
//
|
||||
// Determine if we need to inspect incident faces and apply alternate weighting for
|
||||
// triangles -- and if so, determine which of the two are triangles.
|
||||
//
|
||||
bool face0IsTri = false;
|
||||
bool face1IsTri = false;
|
||||
bool useTriangleOption = (_options.GetTriangleSubdivision() == Options::TRI_SUB_SMOOTH);
|
||||
if (useTriangleOption) {
|
||||
if (faceCount == 2) {
|
||||
//
|
||||
// Ideally we want to avoid this inspection when we have already subdivided at
|
||||
// least once -- need something in the Edge interface to help avoid this, e.g.
|
||||
// an IsRegular() query, the subdivision level...
|
||||
//
|
||||
int vertsPerFace[2];
|
||||
edge.GetNumVerticesPerFace(vertsPerFace);
|
||||
|
||||
face0IsTri = (vertsPerFace[0] == 3);
|
||||
face1IsTri = (vertsPerFace[1] == 3);
|
||||
useTriangleOption = face0IsTri || face1IsTri;
|
||||
} else {
|
||||
useTriangleOption = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (! useTriangleOption) {
|
||||
mask.VertexWeight(0) = 0.25f;
|
||||
mask.VertexWeight(1) = 0.25f;
|
||||
|
||||
if (faceCount == 2) {
|
||||
mask.FaceWeight(0) = 0.25f;
|
||||
mask.FaceWeight(1) = 0.25f;
|
||||
} else {
|
||||
Weight fWeight = 0.5f / (Weight)faceCount;
|
||||
for (int i = 0; i < faceCount; ++i) {
|
||||
mask.FaceWeight(i) = fWeight;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//
|
||||
// This mimics the implementation in Hbr in terms of order of operations.
|
||||
//
|
||||
const Weight CATMARK_SMOOTH_TRI_EDGE_WEIGHT = (Weight) 0.470;
|
||||
|
||||
Weight f0Weight = face0IsTri ? CATMARK_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
|
||||
Weight f1Weight = face1IsTri ? CATMARK_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
|
||||
|
||||
Weight fWeight = 0.5f * (f0Weight + f1Weight);
|
||||
Weight vWeight = 0.5f * (1.0f - 2.0f * fWeight);
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
mask.VertexWeight(1) = vWeight;
|
||||
|
||||
mask.FaceWeight(0) = fWeight;
|
||||
mask.FaceWeight(1) = fWeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Masks for vertex-vertices: the hard Corner mask does not need to be specialized
|
||||
// (simply the vertex itself), leaving the Crease and Smooth cases (Dart is smooth):
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
|
||||
int const creaseEnds[2]) const {
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(valence);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
Weight vWeight = 0.75f;
|
||||
Weight eWeight = 0.125f;
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
mask.EdgeWeight(creaseEnds[0]) = eWeight;
|
||||
mask.EdgeWeight(creaseEnds[1]) = eWeight;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignSmoothMaskForVertex(VERTEX const& vertex, MASK& mask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
//
|
||||
// A Smooth vertex must be manifold and interior -- manifold boundary vertices will be
|
||||
// Creases and non-manifold vertices of any kind will be Corners or Creases. If smooth
|
||||
// rules for non-manifold vertices are ever defined, this will need adjusting:
|
||||
//
|
||||
assert(vertex.GetNumFaces() == vertex.GetNumEdges());
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(valence);
|
||||
mask.SetNumFaceWeights(valence);
|
||||
mask.SetFaceWeightsForFaceCenters(true);
|
||||
|
||||
Weight vWeight = (Weight)(valence - 2) / (Weight)valence;
|
||||
Weight fWeight = 1.0f / (Weight)(valence * valence);
|
||||
Weight eWeight = fWeight;
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
mask.EdgeWeight(i) = eWeight;
|
||||
mask.FaceWeight(i) = fWeight;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Limit masks for position:
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(0);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
posMask.VertexWeight(0) = 1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
|
||||
int const creaseEnds[2]) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(valence);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
Weight vWeight = (Weight)(2.0 / 3.0);
|
||||
Weight eWeight = (Weight)(1.0 / 6.0);
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
posMask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
posMask.EdgeWeight(creaseEnds[0]) = eWeight;
|
||||
posMask.EdgeWeight(creaseEnds[1]) = eWeight;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
if (valence == 2) {
|
||||
assignCornerLimitMask(vertex, posMask);
|
||||
return;
|
||||
}
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(valence);
|
||||
posMask.SetNumFaceWeights(valence);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// Specialize for the regular case:
|
||||
if (valence == 4) {
|
||||
Weight fWeight = (Weight)(1.0 / 36.0);
|
||||
Weight eWeight = (Weight)(1.0 / 9.0);
|
||||
Weight vWeight = (Weight)(4.0 / 9.0);
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
|
||||
posMask.EdgeWeight(0) = eWeight;
|
||||
posMask.EdgeWeight(1) = eWeight;
|
||||
posMask.EdgeWeight(2) = eWeight;
|
||||
posMask.EdgeWeight(3) = eWeight;
|
||||
|
||||
posMask.FaceWeight(0) = fWeight;
|
||||
posMask.FaceWeight(1) = fWeight;
|
||||
posMask.FaceWeight(2) = fWeight;
|
||||
posMask.FaceWeight(3) = fWeight;
|
||||
} else {
|
||||
Weight Valence = (Weight) valence;
|
||||
|
||||
Weight fWeight = 1.0f / (Valence * (Valence + 5.0f));
|
||||
Weight eWeight = 4.0f * fWeight;
|
||||
Weight vWeight = 1.0f - Valence * (eWeight + fWeight);
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
posMask.EdgeWeight(i) = eWeight;
|
||||
posMask.FaceWeight(i) = fWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Limit masks for tangents -- these are stubs for now, or have a temporary
|
||||
// implementation
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignCornerLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(valence);
|
||||
tan1Mask.SetNumFaceWeights(0);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(valence);
|
||||
tan2Mask.SetNumFaceWeights(0);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// Should be at least 2 edges -- be sure to clear weights for any more:
|
||||
tan1Mask.VertexWeight(0) = -1.0f;
|
||||
tan1Mask.EdgeWeight(0) = 1.0f;
|
||||
tan1Mask.EdgeWeight(1) = 0.0f;
|
||||
|
||||
tan2Mask.VertexWeight(0) = -1.0f;
|
||||
tan2Mask.EdgeWeight(0) = 0.0f;
|
||||
tan2Mask.EdgeWeight(1) = 1.0f;
|
||||
|
||||
for (int i = 2; i < valence; ++i) {
|
||||
tan1Mask.EdgeWeight(i) = 0.0f;
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask, int const creaseEnds[2]) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
//
|
||||
// First, the tangent along the crease:
|
||||
// The first crease edge is considered the "leading" edge of the span
|
||||
// of surface for which we are evaluating tangents and the second edge the
|
||||
// "trailing edge". By convention, the tangent along the crease is oriented
|
||||
// in the direction of the leading edge.
|
||||
//
|
||||
int numEdges = vertex.GetNumEdges();
|
||||
int numFaces = vertex.GetNumFaces();
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(numEdges);
|
||||
tan1Mask.SetNumFaceWeights(numFaces);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan1Mask.VertexWeight(0) = 0.0f;
|
||||
for (int i = 0; i < numEdges; ++i) {
|
||||
tan1Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
for (int i = 0; i < numFaces; ++i) {
|
||||
tan1Mask.FaceWeight(i) = 0.0f;
|
||||
}
|
||||
|
||||
tan1Mask.EdgeWeight(creaseEnds[0]) = 0.5f;
|
||||
tan1Mask.EdgeWeight(creaseEnds[1]) = -0.5f;
|
||||
|
||||
//
|
||||
// Second, the tangent across the interior faces:
|
||||
// Note this is ambiguous for an interior vertex. We currently return
|
||||
// the tangent for the surface in the counter-clockwise span between the
|
||||
// leading and trailing edges that form the crease. Given the expected
|
||||
// computation of a surface normal as Tan1 X Tan2, this tangent should be
|
||||
// oriented "inward" from the crease/boundary -- across the surface rather
|
||||
// than outward and away from it.
|
||||
//
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(numEdges);
|
||||
tan2Mask.SetNumFaceWeights(numFaces);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// Prepend weights of 0 preceding the crease:
|
||||
for (int i = 0; i < creaseEnds[0]; ++i) {
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
tan2Mask.FaceWeight(i) = 0.0f;
|
||||
}
|
||||
|
||||
// Assign weights to crease edge and interior points:
|
||||
int interiorEdgeCount = creaseEnds[1] - creaseEnds[0] - 1;
|
||||
if (interiorEdgeCount == 1) {
|
||||
// The regular case -- uniform B-spline cross-tangent:
|
||||
|
||||
tan2Mask.VertexWeight(0) = (Weight)(-4.0 / 6.0);
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = (Weight)(-1.0 / 6.0);
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + 1) = (Weight)( 4.0 / 6.0);
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = (Weight)(-1.0 / 6.0);
|
||||
|
||||
tan2Mask.FaceWeight(creaseEnds[0]) = (Weight)(1.0 / 6.0);
|
||||
tan2Mask.FaceWeight(creaseEnds[0] + 1) = (Weight)(1.0 / 6.0);
|
||||
} else if (interiorEdgeCount > 1) {
|
||||
// The irregular case -- formulae from Biermann et al:
|
||||
|
||||
double k = (double) (interiorEdgeCount + 1);
|
||||
double theta = M_PI / k;
|
||||
|
||||
double cosTheta = std::cos(theta);
|
||||
double sinTheta = std::sin(theta);
|
||||
|
||||
// Loop/Schaefer use a different divisor here (3*k + cos(theta)):
|
||||
double commonDenom = 1.0f / (k * (3.0f + cosTheta));
|
||||
double R = (cosTheta + 1.0f) / sinTheta;
|
||||
|
||||
double vertexWeight = 4.0f * R * (cosTheta - 1.0f);
|
||||
double creaseWeight = -R * (1.0f + 2.0f * cosTheta);
|
||||
|
||||
tan2Mask.VertexWeight(0) = (Weight) (vertexWeight * commonDenom);
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = (Weight) (creaseWeight * commonDenom);
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = (Weight) (creaseWeight * commonDenom);
|
||||
|
||||
tan2Mask.FaceWeight(creaseEnds[0]) = (Weight) (sinTheta * commonDenom);
|
||||
|
||||
double sinThetaI = 0.0f;
|
||||
double sinThetaIplus1 = sinTheta;
|
||||
for (int i = 1; i < k; ++i) {
|
||||
sinThetaI = sinThetaIplus1;
|
||||
sinThetaIplus1 = std::sin((i+1)*theta);
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + i) = (Weight) ((4.0f * sinThetaI) * commonDenom);
|
||||
tan2Mask.FaceWeight(creaseEnds[0] + i) = (Weight) ((sinThetaI + sinThetaIplus1) * commonDenom);
|
||||
}
|
||||
} else {
|
||||
// Special case for a single face -- simple average of boundary edges:
|
||||
|
||||
tan2Mask.VertexWeight(0) = -6.0f;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = 3.0f;
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = 3.0f;
|
||||
|
||||
tan2Mask.FaceWeight(creaseEnds[0]) = 0.0f;
|
||||
}
|
||||
|
||||
// Append weights of 0 following the crease:
|
||||
for (int i = creaseEnds[1]; i < numFaces; ++i) {
|
||||
tan2Mask.FaceWeight(i) = 0.0f;
|
||||
}
|
||||
for (int i = creaseEnds[1] + 1; i < numEdges; ++i) {
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_CATMARK>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
if (valence == 2) {
|
||||
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute tan1 initially -- tan2 is simply a rotation:
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(valence);
|
||||
tan1Mask.SetNumFaceWeights(valence);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan1Mask.VertexWeight(0) = 0.0f;
|
||||
|
||||
if (valence == 4) {
|
||||
tan1Mask.EdgeWeight(0) = 4.0f;
|
||||
tan1Mask.EdgeWeight(1) = 0.0f;
|
||||
tan1Mask.EdgeWeight(2) = -4.0f;
|
||||
tan1Mask.EdgeWeight(3) = 0.0f;
|
||||
|
||||
tan1Mask.FaceWeight(0) = 1.0f;
|
||||
tan1Mask.FaceWeight(1) = -1.0f;
|
||||
tan1Mask.FaceWeight(2) = -1.0f;
|
||||
tan1Mask.FaceWeight(3) = 1.0f;
|
||||
} else {
|
||||
double theta = 2.0f * M_PI / (double)valence;
|
||||
|
||||
double cosTheta = std::cos(theta);
|
||||
double cosHalfTheta = std::cos(theta * 0.5f);
|
||||
|
||||
double lambda = (5.0 / 16.0) + (1.0 / 16.0) *
|
||||
(cosTheta + cosHalfTheta * std::sqrt(2.0f * (9.0f + cosTheta)));
|
||||
|
||||
double edgeWeightScale = 4.0f;
|
||||
double faceWeightScale = 1.0f / (4.0f * lambda - 1.0f);
|
||||
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
double cosThetaI = std::cos( i * theta);
|
||||
double cosThetaIplus1 = std::cos((i+1)* theta);
|
||||
|
||||
tan1Mask.EdgeWeight(i) = (Weight) (edgeWeightScale * cosThetaI);
|
||||
tan1Mask.FaceWeight(i) = (Weight) (faceWeightScale * (cosThetaI + cosThetaIplus1));
|
||||
}
|
||||
}
|
||||
|
||||
// Now rotate/copy tan1 weights to tan2:
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(valence);
|
||||
tan2Mask.SetNumFaceWeights(valence);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan2Mask.VertexWeight(0) = 0.0f;
|
||||
if (valence == 4) {
|
||||
tan2Mask.EdgeWeight(0) = 0.0f;
|
||||
tan2Mask.EdgeWeight(1) = 4.0f;
|
||||
tan2Mask.EdgeWeight(2) = 0.0f;
|
||||
tan2Mask.EdgeWeight(3) = -4.0f;
|
||||
|
||||
tan2Mask.FaceWeight(0) = 1.0f;
|
||||
tan2Mask.FaceWeight(1) = 1.0f;
|
||||
tan2Mask.FaceWeight(2) = -1.0f;
|
||||
tan2Mask.FaceWeight(3) = -1.0f;
|
||||
} else {
|
||||
tan2Mask.EdgeWeight(0) = tan1Mask.EdgeWeight(valence-1);
|
||||
tan2Mask.FaceWeight(0) = tan1Mask.FaceWeight(valence-1);
|
||||
for (int i = 1; i < valence; ++i) {
|
||||
tan2Mask.EdgeWeight(i) = tan1Mask.EdgeWeight(i-1);
|
||||
tan2Mask.FaceWeight(i) = tan1Mask.FaceWeight(i-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_CATMARK_SCHEME_H */
|
||||
183
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/crease.cpp
vendored
Normal file
183
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/crease.cpp
vendored
Normal file
@@ -0,0 +1,183 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../sdc/crease.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
//
|
||||
// Declarations of creasing constants and non-inline methods:
|
||||
//
|
||||
float const Crease::SHARPNESS_SMOOTH = 0.0f;
|
||||
float const Crease::SHARPNESS_INFINITE = 10.0f;
|
||||
|
||||
|
||||
//
|
||||
// Creasing queries dependent on sharpness values:
|
||||
//
|
||||
Crease::Rule
|
||||
Crease::DetermineVertexVertexRule(float vertexSharpness, int sharpEdgeCount) const {
|
||||
|
||||
if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
|
||||
|
||||
return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
|
||||
}
|
||||
|
||||
Crease::Rule
|
||||
Crease::DetermineVertexVertexRule(float vertexSharpness,
|
||||
int incidentEdgeCount,
|
||||
float const* incidentEdgeSharpness) const {
|
||||
|
||||
if (IsSharp(vertexSharpness)) return Crease::RULE_CORNER;
|
||||
|
||||
int sharpEdgeCount = 0;
|
||||
for (int i = 0; i < incidentEdgeCount; ++i) {
|
||||
sharpEdgeCount += IsSharp(incidentEdgeSharpness[i]);
|
||||
}
|
||||
return (sharpEdgeCount > 2) ? Crease::RULE_CORNER : (Crease::Rule)(1 << sharpEdgeCount);
|
||||
}
|
||||
|
||||
float
|
||||
Crease::ComputeFractionalWeightAtVertex(float parentVertexSharpness,
|
||||
float childVertexSharpness,
|
||||
int incidentEdgeCount,
|
||||
float const* parentSharpness,
|
||||
float const* childSharpness) const {
|
||||
|
||||
int transitionCount = 0;
|
||||
float transitionSum = 0.0f;
|
||||
|
||||
if (IsSharp(parentVertexSharpness) && IsSmooth(childVertexSharpness)) {
|
||||
transitionCount = 1;
|
||||
transitionSum = parentVertexSharpness;
|
||||
}
|
||||
|
||||
//
|
||||
// We need the child-edge sharpness values for non-simple methods to ensure
|
||||
// that the sharpness went from a non-zero value (potentially greater than
|
||||
// 1.0) to zero...
|
||||
//
|
||||
if (IsUniform() || (childSharpness == 0)) {
|
||||
for (int i = 0; i < incidentEdgeCount; ++i) {
|
||||
if (IsSharp(parentSharpness[i]) && (parentSharpness[i] <= 1.0f)) {
|
||||
transitionSum += parentSharpness[i];
|
||||
transitionCount ++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < incidentEdgeCount; ++i) {
|
||||
if (IsSharp(parentSharpness[i]) && IsSmooth(childSharpness[i])) {
|
||||
transitionSum += parentSharpness[i];
|
||||
transitionCount ++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (transitionCount == 0) return 0.0f;
|
||||
float fractionalWeight = transitionSum / (float)transitionCount;
|
||||
return (fractionalWeight > 1.0f) ? 1.0f : fractionalWeight;
|
||||
}
|
||||
|
||||
//
|
||||
// Subdividing edge sharpness values (vertex sharpness is inline):
|
||||
//
|
||||
float
|
||||
Crease::SubdivideEdgeSharpnessAtVertex(float edgeSharpness,
|
||||
int incEdgeCountAtVertex,
|
||||
float const * incEdgeSharpness) const {
|
||||
|
||||
if (IsUniform() || (incEdgeCountAtVertex < 2)) {
|
||||
return decrementSharpness(edgeSharpness);
|
||||
}
|
||||
|
||||
if (IsSmooth(edgeSharpness)) return Crease::SHARPNESS_SMOOTH;
|
||||
if (IsInfinite(edgeSharpness)) return Crease::SHARPNESS_INFINITE;
|
||||
|
||||
float sharpSum = 0.0f;
|
||||
int sharpCount = 0;
|
||||
for (int i = 0; i < incEdgeCountAtVertex; ++i) {
|
||||
if (IsSemiSharp(incEdgeSharpness[i])) {
|
||||
sharpCount ++;
|
||||
sharpSum += incEdgeSharpness[i];
|
||||
}
|
||||
}
|
||||
if (sharpCount > 1) {
|
||||
// Chaikin rule is 3/4 original sharpness + 1/4 average of the others
|
||||
|
||||
float avgSharpnessAtVertex = (sharpSum - edgeSharpness) / (float)(sharpCount - 1);
|
||||
|
||||
edgeSharpness = (0.75f * edgeSharpness) + (0.25f * avgSharpnessAtVertex);
|
||||
}
|
||||
edgeSharpness -= 1.0f;
|
||||
return IsSharp(edgeSharpness) ? edgeSharpness : Crease::SHARPNESS_SMOOTH;
|
||||
}
|
||||
|
||||
void
|
||||
Crease::SubdivideEdgeSharpnessesAroundVertex(int edgeCount,
|
||||
float const* parentSharpness,
|
||||
float * childSharpness) const {
|
||||
|
||||
if (IsUniform() || (edgeCount < 2)) {
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
childSharpness[i] = decrementSharpness(parentSharpness[i]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// Chaikin creasing is most efficiently computed for all edges around a vertex at
|
||||
// once as the subdivided value for each creased edge depends on the average of
|
||||
// the other edges around the vertex. So we can sum up the sharpness around the
|
||||
// vertex once and use that for each edge, rather than iterating around the vertex
|
||||
// for each incident edge.
|
||||
//
|
||||
if (_options.GetCreasingMethod() == Options::CREASE_CHAIKIN) {
|
||||
float sharpSum = 0.0f;
|
||||
int sharpCount = 0;
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
if (IsSemiSharp(parentSharpness[i])) {
|
||||
sharpCount ++;
|
||||
sharpSum += parentSharpness[i];
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The smooth case is most common -- specialize for it first:
|
||||
//
|
||||
if (sharpCount == 0) {
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
childSharpness[i] = parentSharpness[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < edgeCount; ++i) {
|
||||
float const& pSharp = parentSharpness[i];
|
||||
float& cSharp = childSharpness[i];
|
||||
|
||||
if (IsSmooth(pSharp)) {
|
||||
cSharp = Crease::SHARPNESS_SMOOTH;
|
||||
} else if (IsInfinite(pSharp)) {
|
||||
cSharp = Crease::SHARPNESS_INFINITE;
|
||||
} else if (sharpCount == 1) {
|
||||
// Need special case here anyway to avoid divide by zero below...
|
||||
cSharp = decrementSharpness(pSharp);
|
||||
} else {
|
||||
float pOtherAverage = (sharpSum - pSharp) / (float)(sharpCount - 1);
|
||||
|
||||
// Chaikin rule is 3/4 original sharpness + 1/4 average of the others
|
||||
cSharp = ((0.75f * pSharp) + (0.25f * pOtherAverage)) - 1.0f;
|
||||
if (IsSmooth(cSharp)) cSharp = Crease::SHARPNESS_SMOOTH;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
230
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/crease.h
vendored
Normal file
230
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/crease.h
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_CREASE_H
|
||||
#define OPENSUBDIV3_SDC_CREASE_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/options.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
///
|
||||
/// \brief Types, constants and utilities related to semi-sharp creasing -- whose implementation
|
||||
/// is independent of the subdivision scheme.
|
||||
///
|
||||
/// Crease is intended to be a light-weight, trivially constructed class that computes
|
||||
/// crease-related properties -- typically sharpness values and associated interpolation
|
||||
/// weights. An instance of Crease is defined with a set of options that include current
|
||||
/// and future variations that will impact computations involving sharpness values.
|
||||
///
|
||||
/// The Crease methods do not use topological neighborhoods as input. The methods here
|
||||
/// rely more on the sharpness values and less on the topology, so we choose to work directly
|
||||
/// with the sharpness values. We also follow the trend of using primitive arrays in the
|
||||
/// interface to encourage local gathering for re-use.
|
||||
///
|
||||
/// Note on the need for and use of sharpness values:
|
||||
/// In general, mask queries rely on the sharpness values. The common case of a smooth
|
||||
/// vertex, when known, avoids the need to inspect them, but unless the rules are well understood,
|
||||
/// users will be expected to provided them -- particularly when they expect the mask queries
|
||||
/// to do all of the work (just determining if a vertex is smooth will require inspection of
|
||||
/// incident edge sharpness).
|
||||
/// Mask queries will occasionally require the subdivided sharpness values around the
|
||||
/// child vertex. So users will be expected to either provide them up front when known, or to be
|
||||
/// gathered on demand. Any implementation of subdivision with creasing cannot avoid subdividing
|
||||
/// the sharpness values first, so keeping them available for re-use is a worthwhile consideration.
|
||||
///
|
||||
|
||||
class Crease {
|
||||
public:
|
||||
//@{
|
||||
/// Constants and related queries of sharpness values:
|
||||
///
|
||||
static float const SHARPNESS_SMOOTH; // = 0.0f, do we really need this?
|
||||
static float const SHARPNESS_INFINITE; // = 10.0f;
|
||||
|
||||
static bool IsSmooth(float sharpness) { return sharpness <= SHARPNESS_SMOOTH; }
|
||||
static bool IsSharp(float sharpness) { return sharpness > SHARPNESS_SMOOTH; }
|
||||
static bool IsInfinite(float sharpness) { return sharpness >= SHARPNESS_INFINITE; }
|
||||
static bool IsSemiSharp(float sharpness) { return (SHARPNESS_SMOOTH < sharpness) && (sharpness < SHARPNESS_INFINITE); }
|
||||
//@}
|
||||
|
||||
///
|
||||
/// Enum for the types of subdivision rules applied based on sharpness values (note these
|
||||
/// correspond to Hbr's vertex "mask"). The values are assigned to bit positions as it is
|
||||
/// useful to use bitwise operations to inspect collections of vertices (i.e. all of the
|
||||
/// vertices incident a particular face).
|
||||
///
|
||||
enum Rule {
|
||||
RULE_UNKNOWN = 0,
|
||||
RULE_SMOOTH = (1 << 0),
|
||||
RULE_DART = (1 << 1),
|
||||
RULE_CREASE = (1 << 2),
|
||||
RULE_CORNER = (1 << 3)
|
||||
};
|
||||
|
||||
public:
|
||||
Crease() : _options() { }
|
||||
Crease(Options const& options) : _options(options) { }
|
||||
~Crease() { }
|
||||
|
||||
bool IsUniform() const { return _options.GetCreasingMethod() == Options::CREASE_UNIFORM; }
|
||||
|
||||
//@{
|
||||
/// Optional sharp features:
|
||||
/// Since options treat certain topological features as infinitely sharp -- boundaries
|
||||
/// or (in future) non-manifold features -- sharpness values should be adjusted before use.
|
||||
/// The following methods will adjust (by return) specific values according to the options
|
||||
/// applied.
|
||||
///
|
||||
float SharpenBoundaryEdge(float edgeSharpness) const;
|
||||
float SharpenBoundaryVertex(float edgeSharpness) const;
|
||||
|
||||
// For future consideration
|
||||
//float SharpenNonManifoldEdge(float edgeSharpness) const;
|
||||
//float SharpenNonManifoldVertex(float edgeSharpness) const;
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// Sharpness subdivision:
|
||||
/// The computation of a Uniform subdivided sharpness value is as follows:
|
||||
/// - Smooth edges or verts stay Smooth
|
||||
/// - Sharp edges or verts stay Sharp
|
||||
/// - semi-sharp edges or verts are decremented by 1.0
|
||||
/// but for Chaikin (and potentially future non-uniform schemes that improve upon it) the
|
||||
/// computation is more involved. In the case of edges in particular, the sharpness of a
|
||||
/// child edge is determined by the sharpness in the neighborhood of the end vertex
|
||||
/// corresponding to the child. For this reason, an alternative to subdividing sharpness
|
||||
/// that computes all child edges around a vertex is given.
|
||||
///
|
||||
float SubdivideUniformSharpness(float vertexOrEdgeSharpness) const;
|
||||
|
||||
float SubdivideVertexSharpness(float vertexSharpness) const;
|
||||
|
||||
float SubdivideEdgeSharpnessAtVertex(float edgeSharpness,
|
||||
int incidentEdgeCountAtEndVertex,
|
||||
float const* edgeSharpnessAroundEndVertex) const;
|
||||
|
||||
void SubdivideEdgeSharpnessesAroundVertex(int incidentEdgeCountAtVertex,
|
||||
float const* incidentEdgeSharpnessAroundVertex,
|
||||
float* childEdgesSharpnessAroundVertex) const;
|
||||
//@}
|
||||
|
||||
//@{
|
||||
/// Rule determination:
|
||||
/// Mask queries do not require the Rule to be known, it can be determined from
|
||||
/// the information provided, but it is generally more efficient when the Rule is known
|
||||
/// and provided. In particular, the Smooth case dominates and is known to be applicable
|
||||
/// based on the origin of the vertex without inspection of sharpness.
|
||||
///
|
||||
Rule DetermineVertexVertexRule(float vertexSharpness,
|
||||
int incidentEdgeCount,
|
||||
float const* incidentEdgeSharpness) const;
|
||||
Rule DetermineVertexVertexRule(float vertexSharpness,
|
||||
int sharpEdgeCount) const;
|
||||
//@}
|
||||
|
||||
/// \brief Transitional weighting:
|
||||
/// When the rules applicable to a parent vertex and its child differ, one or more
|
||||
/// sharpness values has "decayed" to zero. Both rules are then applicable and blended
|
||||
/// by a weight between 0 and 1 that reflects the transition. Most often this will be
|
||||
/// a single sharpness value that decays from within the interval [0,1] to zero -- and
|
||||
/// the weight to apply is exactly that sharpness value -- but more than one may decay,
|
||||
/// and values > 1 may also decay to 0 in a single step while others within [0,1] may
|
||||
/// remain > 0.
|
||||
/// So to properly determine a transitional weight, sharpness values for both the
|
||||
/// parent and child must be inspected, combined and clamped accordingly.
|
||||
///
|
||||
float ComputeFractionalWeightAtVertex(float vertexSharpness,
|
||||
float childVertexSharpness,
|
||||
int incidentEdgeCount,
|
||||
float const* incidentEdgeSharpness,
|
||||
float const* childEdgesSharpness) const;
|
||||
|
||||
void GetSharpEdgePairOfCrease(float const * incidentEdgeSharpness,
|
||||
int incidentEdgeCount,
|
||||
int sharpEdgePair[2]) const;
|
||||
|
||||
// Would these really help? Maybe only need Rules for the vertex-vertex case...
|
||||
//
|
||||
// Rule DetermineEdgeVertexRule(float parentEdgeSharpness) const;
|
||||
// Rule DetermineEdgeVertexRule(float childEdge1Sharpness, float childEdge2Sharpness) const;
|
||||
|
||||
protected:
|
||||
float decrementSharpness(float sharpness) const;
|
||||
|
||||
private:
|
||||
Options _options;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Inline declarations:
|
||||
//
|
||||
inline float
|
||||
Crease::SharpenBoundaryEdge(float /* edgeSharpness */) const {
|
||||
|
||||
//
|
||||
// Despite the presence of the BOUNDARY_NONE option, boundary edges are always sharpened.
|
||||
// Much of the code relies on sharpness to indicate boundaries to avoid the more complex
|
||||
// topological inspection
|
||||
//
|
||||
return SHARPNESS_INFINITE;
|
||||
}
|
||||
|
||||
inline float
|
||||
Crease::SharpenBoundaryVertex(float vertexSharpness) const {
|
||||
|
||||
return (_options.GetVtxBoundaryInterpolation() == Options::VTX_BOUNDARY_EDGE_AND_CORNER) ?
|
||||
SHARPNESS_INFINITE : vertexSharpness;
|
||||
}
|
||||
|
||||
inline float
|
||||
Crease::decrementSharpness(float sharpness) const {
|
||||
|
||||
if (IsSmooth(sharpness)) return Crease::SHARPNESS_SMOOTH; // redundant but most common
|
||||
if (IsInfinite(sharpness)) return Crease::SHARPNESS_INFINITE;
|
||||
if (sharpness > 1.0f) return (sharpness - 1.0f);
|
||||
return Crease::SHARPNESS_SMOOTH;
|
||||
}
|
||||
|
||||
inline float
|
||||
Crease::SubdivideUniformSharpness(float vertexOrEdgeSharpness) const {
|
||||
|
||||
return decrementSharpness(vertexOrEdgeSharpness);
|
||||
}
|
||||
|
||||
inline float
|
||||
Crease::SubdivideVertexSharpness(float vertexSharpness) const {
|
||||
|
||||
return decrementSharpness(vertexSharpness);
|
||||
}
|
||||
|
||||
inline void
|
||||
Crease::GetSharpEdgePairOfCrease(float const * incidentEdgeSharpness, int incidentEdgeCount,
|
||||
int sharpEdgePair[2]) const {
|
||||
|
||||
// Only to be called when a crease is present at a vertex -- exactly two sharp
|
||||
// edges are expected here:
|
||||
//
|
||||
sharpEdgePair[0] = 0;
|
||||
while (IsSmooth(incidentEdgeSharpness[sharpEdgePair[0]])) ++ sharpEdgePair[0];
|
||||
|
||||
sharpEdgePair[1] = incidentEdgeCount - 1;
|
||||
while (IsSmooth(incidentEdgeSharpness[sharpEdgePair[1]])) -- sharpEdgePair[1];
|
||||
}
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_CREASE_H */
|
||||
566
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/loopScheme.h
vendored
Normal file
566
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/loopScheme.h
vendored
Normal file
@@ -0,0 +1,566 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_LOOP_SCHEME_H
|
||||
#define OPENSUBDIV3_SDC_LOOP_SCHEME_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/scheme.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
namespace Sdc {
|
||||
|
||||
|
||||
//
|
||||
// Specializations for Sdc::Scheme<SCHEME_LOOP>:
|
||||
//
|
||||
//
|
||||
|
||||
//
|
||||
// Loop traits:
|
||||
//
|
||||
template <>
|
||||
inline Split Scheme<SCHEME_LOOP>::GetTopologicalSplitType() { return SPLIT_TO_TRIS; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_LOOP>::GetRegularFaceSize() { return 3; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_LOOP>::GetRegularVertexValence() { return 6; }
|
||||
|
||||
template <>
|
||||
inline int Scheme<SCHEME_LOOP>::GetLocalNeighborhoodSize() { return 1; }
|
||||
|
||||
|
||||
//
|
||||
// Protected methods to assign the two types of masks for an edge-vertex --
|
||||
// Crease and Smooth.
|
||||
//
|
||||
// The Crease case does not really need to be specialized, though it may be
|
||||
// preferable to define all explicitly here.
|
||||
//
|
||||
template <>
|
||||
template <typename EDGE, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCreaseMaskForEdge(EDGE const&, MASK& mask) const
|
||||
{
|
||||
mask.SetNumVertexWeights(2);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
mask.VertexWeight(0) = 0.5f;
|
||||
mask.VertexWeight(1) = 0.5f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename EDGE, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) const
|
||||
{
|
||||
int faceCount = edge.GetNumFaces();
|
||||
|
||||
mask.SetNumVertexWeights(2);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(faceCount);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
//
|
||||
// This is where we run into the issue of "face weights" -- we want to weight the
|
||||
// face-centers for Catmark, but face-centers are not generated for Loop. So do
|
||||
// we make assumptions on how the mask is used, assign some property to the mask
|
||||
// to indicate how they were assigned, or take input from the mask itself?
|
||||
//
|
||||
// Regardless, we have two choices:
|
||||
// - face-weights are for the vertices opposite the edge (as in Hbr):
|
||||
// vertex weights = 0.375f;
|
||||
// face weights = 0.125f;
|
||||
//
|
||||
// - face-weights are for the face centers:
|
||||
// vertex weights = 0.125f;
|
||||
// face weights = 0.375f;
|
||||
//
|
||||
// Coincidentally the coefficients are the same but reversed.
|
||||
//
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
Weight vWeight = mask.AreFaceWeightsForFaceCenters() ? 0.125f : 0.375f;
|
||||
Weight fWeight = mask.AreFaceWeightsForFaceCenters() ? 0.375f : 0.125f;
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
mask.VertexWeight(1) = vWeight;
|
||||
|
||||
if (faceCount == 2) {
|
||||
mask.FaceWeight(0) = fWeight;
|
||||
mask.FaceWeight(1) = fWeight;
|
||||
} else {
|
||||
// The non-manifold case is not clearly defined -- we adjust the above
|
||||
// face-weight to preserve the ratio of edge-center and face-centers:
|
||||
fWeight *= 2.0f / (Weight) faceCount;
|
||||
for (int i = 0; i < faceCount; ++i) {
|
||||
mask.FaceWeight(i) = fWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Protected methods to assign the three types of masks for a vertex-vertex --
|
||||
// Corner, Crease and Smooth (Dart is the same as Smooth).
|
||||
//
|
||||
// Corner and Crease do not really need to be specialized, though it may be
|
||||
// preferable to define all explicitly here.
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCornerMaskForVertex(VERTEX const&, MASK& mask) const
|
||||
{
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
mask.VertexWeight(0) = 1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
|
||||
int const creaseEnds[2]) const {
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(valence);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
Weight vWeight = 0.75f;
|
||||
Weight eWeight = 0.125f;
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
mask.EdgeWeight(creaseEnds[0]) = eWeight;
|
||||
mask.EdgeWeight(creaseEnds[1]) = eWeight;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignSmoothMaskForVertex(VERTEX const& vertex, MASK& mask) const
|
||||
{
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(valence);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// Specialize for the regular case: 1/16 per edge-vert, 5/8 for the vert itself:
|
||||
Weight eWeight = (Weight) 0.0625f;
|
||||
Weight vWeight = (Weight) 0.625f;
|
||||
|
||||
if (valence != 6) {
|
||||
// From HbrLoopSubdivision<T>::Subdivide(mesh, vertex):
|
||||
// - could use some lookup tables here for common irregular valence (5, 7, 8)
|
||||
// or all of these cosine calls will be adding up...
|
||||
|
||||
double dValence = (double) valence;
|
||||
double invValence = 1.0f / dValence;
|
||||
double cosTheta = std::cos(M_PI * 2.0f * invValence);
|
||||
|
||||
double beta = 0.25f * cosTheta + 0.375f;
|
||||
|
||||
eWeight = (Weight) ((0.625f - (beta * beta)) * invValence);
|
||||
vWeight = (Weight) (1.0f - (eWeight * dValence));
|
||||
}
|
||||
|
||||
mask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
mask.EdgeWeight(i) = eWeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Limit masks for position:
|
||||
//
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(0);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
posMask.VertexWeight(0) = 1.0f;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
|
||||
int const creaseEnds[2]) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(valence);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
//
|
||||
// The refinement mask for a crease vertex is (1/8, 3/4, 1/8) and for a crease
|
||||
// edge is (1/2, 1/2) -- producing a uniform B-spline curve along the crease
|
||||
// (boundary) whether the vertex or its crease is regular or not. The limit
|
||||
// mask is therefore (1/6, 2/3, 1/6) for ALL cases.
|
||||
//
|
||||
// An alternative limit mask (1/5, 3/5, 1/5) is often published for use either
|
||||
// for irregular crease vertices or for all crease/boundary vertices, but this
|
||||
// is based on an alternate refinement mask for the edge -- (3/8, 5/8) versus
|
||||
// the usual (1/2, 1/2) -- and will not produce the B-spline curve desired.
|
||||
//
|
||||
Weight vWeight = (Weight) (4.0 / 6.0);
|
||||
Weight eWeight = (Weight) (1.0 / 6.0);
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
posMask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
posMask.EdgeWeight(creaseEnds[0]) = eWeight;
|
||||
posMask.EdgeWeight(creaseEnds[1]) = eWeight;
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
|
||||
posMask.SetNumVertexWeights(1);
|
||||
posMask.SetNumEdgeWeights(valence);
|
||||
posMask.SetNumFaceWeights(0);
|
||||
posMask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// Specialize for the regular case: 1/12 per edge-vert, 1/2 for the vert itself:
|
||||
if (valence == 6) {
|
||||
Weight eWeight = (Weight) (1.0 / 12.0);
|
||||
Weight vWeight = 0.5f;
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
|
||||
posMask.EdgeWeight(0) = eWeight;
|
||||
posMask.EdgeWeight(1) = eWeight;
|
||||
posMask.EdgeWeight(2) = eWeight;
|
||||
posMask.EdgeWeight(3) = eWeight;
|
||||
posMask.EdgeWeight(4) = eWeight;
|
||||
posMask.EdgeWeight(5) = eWeight;
|
||||
|
||||
} else {
|
||||
double dValence = (double) valence;
|
||||
double invValence = 1.0f / dValence;
|
||||
double cosTheta = std::cos(M_PI * 2.0f * invValence);
|
||||
|
||||
double beta = 0.25f * cosTheta + 0.375f;
|
||||
double gamma = (0.625f - (beta * beta)) * invValence;
|
||||
|
||||
Weight eWeight = (Weight) (1.0f / (dValence + 3.0f / (8.0f * gamma)));
|
||||
Weight vWeight = (Weight) (1.0f - (eWeight * dValence));
|
||||
|
||||
posMask.VertexWeight(0) = vWeight;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
posMask.EdgeWeight(i) = eWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Limit masks for tangents:
|
||||
//
|
||||
// A note on tangent magnitudes:
|
||||
//
|
||||
// Several formulae exist for limit tangents at a vertex to accommodate the
|
||||
// different topological configurations around the vertex. While these produce
|
||||
// the desired direction, there is inconsistency in the resulting magnitudes.
|
||||
// Ideally a regular mesh of uniformly shaped triangles with similar edge lengths
|
||||
// should produce tangents of similar magnitudes throughout -- including corners
|
||||
// and boundaries. So some of the common formulae for these are adjusted with
|
||||
// scale factors.
|
||||
//
|
||||
// For uses where magnitude does not matter, this scaling should be irrelevant.
|
||||
// But just as with patches, where the magnitudes of partial derivatives are
|
||||
// consistent between similar patches, the magnitudes of limit tangents should
|
||||
// also be similar.
|
||||
//
|
||||
// The reference tangents, in terms of magnitudes, are those produced by the
|
||||
// limit tangent mask for smooth interior vertices, for which well established
|
||||
// sin/cos formulae apply -- these remain unscaled. Formulae for the other
|
||||
// crease/boundary, corner tangents and irregular cases are scaled to be more
|
||||
// consistent with these.
|
||||
//
|
||||
// The crease/boundary tangents for the regular case can be viewed as derived
|
||||
// from the smooth interior masks with two "phantom" points extrapolated across
|
||||
// the regular boundary:
|
||||
//
|
||||
// v3 v2
|
||||
// X - - - - - X
|
||||
// / \ / \
|
||||
// / \ / \
|
||||
// v4 X - - - - - X - - - - - X v1
|
||||
// . . 0 . .
|
||||
// . . . .
|
||||
// . . . .
|
||||
// (v5) (v6)
|
||||
//
|
||||
// where v5 = v0 + (v4 - v3) and v6 = v0 + v1 - v2.
|
||||
//
|
||||
// When the standard limit tangent mask is applied, the cosines of increments
|
||||
// of pi/3 give us coefficients that are multiples of 1/2, leading to the first
|
||||
// tangent T1 = 3/2 * (v1 - v4), rather than the widely used T1 = v1 - v4. So
|
||||
// this scale factor of 3/2 is applied to ensure tangents along the boundaries
|
||||
// are of similar magnitude as tangents in the immediate interior (which may be
|
||||
// parallel).
|
||||
//
|
||||
// Tangents at corners are essentially a form of boundary tangent, and so its
|
||||
// simple difference formula is scaled to be consistent with adjoining boundary
|
||||
// tangents -- not just with the 3/2 factor from above, but with an additional
|
||||
// 2.0 to compensate for the fact that the difference of only side of the vertex
|
||||
// is considered here. The resulting scale factor of 3.0 for the regular corner
|
||||
// is what similarly arises by extrapolating an interior region around the
|
||||
// vertex and using the interior mask for the first tangent.
|
||||
//
|
||||
// The cross-tangent formula for the regular crease/boundary is similarly found
|
||||
// from the above construction of the boundary, but the commonly used weights of
|
||||
// +/- 1 and 2 result from omitting the common factor of sqrt(3)/2 (arising from
|
||||
// the sines of increments of pi/3). With that scale factor close to one, it has
|
||||
// less impact than the irregular cases, which are analogous to corner tangents
|
||||
// in that differences on only one side of the vertex are considered. While a
|
||||
// scaling of 3.0 is similarly understandable for the valence 2 and 3 cases, it is
|
||||
// less obvious in the irregular formula for valence > 4, but similarly effective.
|
||||
//
|
||||
// The end result of these adjustments should be a set of limit tangents that are
|
||||
// of similar magnitude over a regular mesh including boundaries and corners.
|
||||
*/
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCornerLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(valence);
|
||||
tan1Mask.SetNumFaceWeights(0);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(valence);
|
||||
tan2Mask.SetNumFaceWeights(0);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
// See note above regarding scale factor of 3.0:
|
||||
tan1Mask.VertexWeight(0) = -3.0f;
|
||||
tan1Mask.EdgeWeight(0) = 3.0f;
|
||||
tan1Mask.EdgeWeight(1) = 0.0f;
|
||||
|
||||
tan2Mask.VertexWeight(0) = -3.0f;
|
||||
tan2Mask.EdgeWeight(0) = 0.0f;
|
||||
tan2Mask.EdgeWeight(1) = 3.0f;
|
||||
|
||||
// Should be at least 2 edges -- be sure to clear weights for any more:
|
||||
for (int i = 2; i < valence; ++i) {
|
||||
tan1Mask.EdgeWeight(i) = 0.0f;
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask, int const creaseEnds[2]) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
//
|
||||
// First, the tangent along the crease:
|
||||
// The first crease edge is considered the "leading" edge of the span
|
||||
// of surface for which we are evaluating tangents and the second edge the
|
||||
// "trailing edge". By convention, the tangent along the crease is oriented
|
||||
// in the direction of the leading edge.
|
||||
//
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(valence);
|
||||
tan1Mask.SetNumFaceWeights(0);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan1Mask.VertexWeight(0) = 0.0f;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
tan1Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
|
||||
// See the note above regarding scale factor of 1.5:
|
||||
tan1Mask.EdgeWeight(creaseEnds[0]) = 1.5f;
|
||||
tan1Mask.EdgeWeight(creaseEnds[1]) = -1.5f;
|
||||
|
||||
//
|
||||
// Second, the tangent across the interior faces:
|
||||
// Note this is ambiguous for an interior vertex. We currently return
|
||||
// the tangent for the surface in the counter-clockwise span between the
|
||||
// leading and trailing edges that form the crease. Given the expected
|
||||
// computation of a surface normal as Tan1 X Tan2, this tangent should be
|
||||
// oriented "inward" from the crease/boundary -- across the surface rather
|
||||
// than outward and away from it.
|
||||
//
|
||||
// There is inconsistency in the orientation of this tangent in commonly
|
||||
// published results: the general formula provided for arbitrary valence
|
||||
// has the tangent pointing across the crease and "outward" from the surface,
|
||||
// while the special cases for regular valence and lower have the tangent
|
||||
// pointing across the surface and "inward" from the crease. So if we are
|
||||
// to consistently orient the first tangent along the crease, regardless of
|
||||
// the interior topology, we have to correct this. With the first tangent
|
||||
// following the direction of the leading crease edge, we want the second
|
||||
// tangent pointing inward/across the surface -- so we flip the result of
|
||||
// the general formula.
|
||||
//
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(valence);
|
||||
tan2Mask.SetNumFaceWeights(0);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
for (int i = 0; i < creaseEnds[0]; ++i) {
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
int interiorEdgeCount = creaseEnds[1] - creaseEnds[0] - 1;
|
||||
if (interiorEdgeCount == 2) {
|
||||
// See note above regarding scale factor of (sin(60 degs) == sqrt(3)/2:
|
||||
|
||||
static Weight const Root3 = (Weight) 1.73205080756887729352;
|
||||
static Weight const Root3by2 = (Weight) (Root3 * 0.5);
|
||||
|
||||
tan2Mask.VertexWeight(0) = -Root3;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = -Root3by2;
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = -Root3by2;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + 1) = Root3;
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + 2) = Root3;
|
||||
} else if (interiorEdgeCount > 2) {
|
||||
// See notes above regarding scale factor of -3.0 (-1 for orientation,
|
||||
// 2.0 for considering the region as a half-disk, and 1.5 in keeping
|
||||
// with the crease tangent):
|
||||
|
||||
double theta = M_PI / (interiorEdgeCount + 1);
|
||||
|
||||
tan2Mask.VertexWeight(0) = 0.0f;
|
||||
|
||||
Weight cWeight = (Weight) (-3.0f * std::sin(theta));
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = cWeight;
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = cWeight;
|
||||
|
||||
double eCoeff = -3.0f * 2.0f * (std::cos(theta) - 1.0f);
|
||||
for (int i = 1; i <= interiorEdgeCount; ++i) {
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + i) = (Weight) (eCoeff * std::sin(i * theta));
|
||||
}
|
||||
} else if (interiorEdgeCount == 1) {
|
||||
// See notes above regarding scale factor of 3.0:
|
||||
|
||||
tan2Mask.VertexWeight(0) = -3.0f;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = 0.0f;
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = 0.0f;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0] + 1) = 3.0f;
|
||||
} else {
|
||||
// See notes above regarding scale factor of 3.0:
|
||||
|
||||
tan2Mask.VertexWeight(0) = -6.0f;
|
||||
|
||||
tan2Mask.EdgeWeight(creaseEnds[0]) = 3.0f;
|
||||
tan2Mask.EdgeWeight(creaseEnds[1]) = 3.0f;
|
||||
}
|
||||
for (int i = creaseEnds[1] + 1; i < valence; ++i) {
|
||||
tan2Mask.EdgeWeight(i) = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME_LOOP>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
|
||||
MASK& tan1Mask, MASK& tan2Mask) const {
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
int valence = vertex.GetNumFaces();
|
||||
|
||||
tan1Mask.SetNumVertexWeights(1);
|
||||
tan1Mask.SetNumEdgeWeights(valence);
|
||||
tan1Mask.SetNumFaceWeights(0);
|
||||
tan1Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan2Mask.SetNumVertexWeights(1);
|
||||
tan2Mask.SetNumEdgeWeights(valence);
|
||||
tan2Mask.SetNumFaceWeights(0);
|
||||
tan2Mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
tan1Mask.VertexWeight(0) = 0.0f;
|
||||
tan2Mask.VertexWeight(0) = 0.0f;
|
||||
|
||||
if (valence == 6) {
|
||||
static Weight const Root3by2 = (Weight)(0.5 * 1.73205080756887729352);
|
||||
|
||||
tan1Mask.EdgeWeight(0) = 1.0f;
|
||||
tan1Mask.EdgeWeight(1) = 0.5f;
|
||||
tan1Mask.EdgeWeight(2) = -0.5f;
|
||||
tan1Mask.EdgeWeight(3) = -1.0f;
|
||||
tan1Mask.EdgeWeight(4) = -0.5f;
|
||||
tan1Mask.EdgeWeight(5) = 0.5f;
|
||||
|
||||
tan2Mask.EdgeWeight(0) = 0.0f;
|
||||
tan2Mask.EdgeWeight(1) = Root3by2;
|
||||
tan2Mask.EdgeWeight(2) = Root3by2;
|
||||
tan2Mask.EdgeWeight(3) = 0.0f;
|
||||
tan2Mask.EdgeWeight(4) = -Root3by2;
|
||||
tan2Mask.EdgeWeight(5) = -Root3by2;
|
||||
} else {
|
||||
double alpha = 2.0f * M_PI / valence;
|
||||
for (int i = 0; i < valence; ++i) {
|
||||
double alphaI = alpha * i;
|
||||
tan1Mask.EdgeWeight(i) = (Weight) std::cos(alphaI);
|
||||
tan2Mask.EdgeWeight(i) = (Weight) std::sin(alphaI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end namespace Sdc
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_LOOP_SCHEME_H */
|
||||
111
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/options.h
vendored
Normal file
111
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/options.h
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_OPTIONS_H
|
||||
#define OPENSUBDIV3_SDC_OPTIONS_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
///
|
||||
/// \brief All supported options applying to subdivision scheme.
|
||||
///
|
||||
/// The Options class contains all supported options that can be applied to a
|
||||
/// subdivision scheme to affect the shape of the limit surface. These differ from
|
||||
/// approximations that may be applied at a higher level, i.e. options to limit the
|
||||
/// level of feature adaptive subdivision, options to ignore fractional creasing,
|
||||
/// or creasing entirely, etc. These options define the shape of a particular
|
||||
/// limit surface, including the "shape" of primitive variable data associated with
|
||||
/// it.
|
||||
///
|
||||
/// The intent is that these sets of options be defined at a high level and
|
||||
/// propagated into the lowest-level computation in support of each subdivision
|
||||
/// scheme. Ideally it remains a set of bit-fields (essentially an int) and so
|
||||
/// remains light weight and easily passed around by value.
|
||||
///
|
||||
|
||||
class Options {
|
||||
public:
|
||||
enum VtxBoundaryInterpolation {
|
||||
VTX_BOUNDARY_NONE = 0, ///< no boundary interpolation, except where
|
||||
///< boundary edges were explicitly sharpened
|
||||
VTX_BOUNDARY_EDGE_ONLY, ///< all boundary edges sharpened and interpolated
|
||||
VTX_BOUNDARY_EDGE_AND_CORNER ///< all boundary edges and corner vertices
|
||||
///< sharpened and interpolated
|
||||
};
|
||||
enum FVarLinearInterpolation {
|
||||
FVAR_LINEAR_NONE = 0, ///< smooth everywhere ("edge only")
|
||||
FVAR_LINEAR_CORNERS_ONLY, ///< sharpen corners only
|
||||
FVAR_LINEAR_CORNERS_PLUS1, ///< ("edge corner")
|
||||
FVAR_LINEAR_CORNERS_PLUS2, ///< ("edge and corner + propagate corner")
|
||||
FVAR_LINEAR_BOUNDARIES, ///< sharpen all boundaries ("always sharp")
|
||||
FVAR_LINEAR_ALL ///< bilinear interpolation ("bilinear")
|
||||
};
|
||||
enum CreasingMethod {
|
||||
CREASE_UNIFORM = 0, ///< Catmark rule
|
||||
CREASE_CHAIKIN ///< Chaikin rule
|
||||
};
|
||||
enum TriangleSubdivision {
|
||||
TRI_SUB_CATMARK = 0, ///< Catmark weights (Catmark scheme only)
|
||||
TRI_SUB_SMOOTH ///< "smooth triangle" weights (Catmark scheme only)
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
Options() : _vtxBoundInterp(VTX_BOUNDARY_NONE),
|
||||
_fvarLinInterp(FVAR_LINEAR_ALL),
|
||||
_creasingMethod(CREASE_UNIFORM),
|
||||
_triangleSub(TRI_SUB_CATMARK) { }
|
||||
|
||||
//
|
||||
// Trivial get/set methods:
|
||||
//
|
||||
|
||||
/// \brief Get vertex boundary interpolation rule
|
||||
VtxBoundaryInterpolation GetVtxBoundaryInterpolation() const { return (VtxBoundaryInterpolation) _vtxBoundInterp; }
|
||||
|
||||
/// \brief Set vertex boundary interpolation rule
|
||||
void SetVtxBoundaryInterpolation(VtxBoundaryInterpolation b) { _vtxBoundInterp = (EnumIntType) b; }
|
||||
|
||||
/// \brief Get face-varying interpolation rule
|
||||
FVarLinearInterpolation GetFVarLinearInterpolation() const { return (FVarLinearInterpolation) _fvarLinInterp; }
|
||||
|
||||
/// \brief Set face-varying interpolation rule
|
||||
void SetFVarLinearInterpolation(FVarLinearInterpolation b) { _fvarLinInterp = (EnumIntType) b; }
|
||||
|
||||
/// \brief Get edge crease rule
|
||||
CreasingMethod GetCreasingMethod() const { return (CreasingMethod) _creasingMethod; }
|
||||
|
||||
/// \brief Set edge crease rule
|
||||
void SetCreasingMethod(CreasingMethod c) { _creasingMethod = (EnumIntType) c; }
|
||||
|
||||
/// \brief Get triangle subdivision weights rule (Catmark scheme only !)
|
||||
TriangleSubdivision GetTriangleSubdivision() const { return (TriangleSubdivision) _triangleSub; }
|
||||
|
||||
/// \brief Set triangle subdivision weights rule (Catmark scheme only !)
|
||||
void SetTriangleSubdivision(TriangleSubdivision t) { _triangleSub = (EnumIntType) t; }
|
||||
|
||||
private:
|
||||
// Use a small integer type to pack these rather than bitfields:
|
||||
typedef unsigned char EnumIntType;
|
||||
|
||||
EnumIntType _vtxBoundInterp;
|
||||
EnumIntType _fvarLinInterp;
|
||||
EnumIntType _creasingMethod;
|
||||
EnumIntType _triangleSub;
|
||||
};
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_OPTIONS_H */
|
||||
643
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/scheme.h
vendored
Normal file
643
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/scheme.h
vendored
Normal file
@@ -0,0 +1,643 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_SCHEME_H
|
||||
#define OPENSUBDIV3_SDC_SCHEME_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
#include "../sdc/types.h"
|
||||
#include "../sdc/options.h"
|
||||
#include "../sdc/crease.h"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
///
|
||||
/// \brief Scheme is a class template which provides all implementation for the
|
||||
/// subdivision schemes supported by OpenSubdiv through specializations of the
|
||||
/// methods of each. An instance of Scheme<SCHEME_TYPE> includes a set of Options
|
||||
/// that will dictate the variable aspects of its behavior.
|
||||
///
|
||||
/// The primary purpose of Scheme is to provide the mask weights for vertices
|
||||
/// generated by subdivision. Methods to determine the masks are given topological
|
||||
/// neighborhoods from which to compute the appropriate weights for neighboring
|
||||
/// components. While these neighborhoods may require sharpness values for
|
||||
/// creasing, the computation of subdivided crease values is independent of the
|
||||
/// scheme type and is also made available through the Crease class.
|
||||
///
|
||||
/// Mask queries are assisted by two utility classes -- a Neighborhood class
|
||||
/// defining the set of relevant data in the topological neighborhood of the vertex
|
||||
/// being subdivided, and a Mask class into which the associated mask weights will
|
||||
/// be stored. Depending on where and how these queries are used, more or less
|
||||
/// information may be available. See the details of the Neighborhood classes as
|
||||
/// appropriate initialization of them is critical. It is generally best to
|
||||
/// initialize them with what data is known and accessible for immediate and
|
||||
/// efficient retrieval, but subclasses can be created to gather it lazily if
|
||||
/// desired.
|
||||
///
|
||||
template <SchemeType SCHEME_TYPE>
|
||||
class Scheme {
|
||||
|
||||
public:
|
||||
|
||||
Scheme() : _options() { }
|
||||
|
||||
Scheme(Options const& options) : _options(options) { }
|
||||
|
||||
Options GetOptions() const { return _options; }
|
||||
void SetOptions(const Options& newOptions) { _options = newOptions; }
|
||||
|
||||
///
|
||||
/// \brief Face-vertex masks - trivial for all current schemes
|
||||
///
|
||||
template <typename FACE, typename MASK>
|
||||
void ComputeFaceVertexMask(FACE const& faceNeighborhood, MASK& faceVertexMask) const;
|
||||
|
||||
///
|
||||
/// \brief Edge-vertex masks
|
||||
/// If known, the Rule for the edge and/or the derived vertex can be specified to
|
||||
/// accelerate the computation (though the Rule for the parent is trivially determined).
|
||||
/// In particular, knowing the child rule can avoid the need to subdivide the sharpness
|
||||
/// of the edge to see if it is a transitional crease that warrants fractional blending.
|
||||
///
|
||||
/// Whether to use the "Rules" in this interface is really debatable -- the parent Rule
|
||||
/// is really based on the edge and its sharpness, while the child Rule is technically
|
||||
/// based on the neighborhood of the child vertex, but it can be deduced from the two
|
||||
/// child edges' sharpness. So the Crease methods used to compute these rules differ
|
||||
/// from those for the vertex-vertex mask. Perhaps a simple pair of new methods for
|
||||
/// Crease should be added specific to the edge-vertex case, i.e. one that takes a
|
||||
/// single sharpness (for the parent rule) and one that takes a pair (for the child).
|
||||
///
|
||||
template <typename EDGE, typename MASK>
|
||||
void ComputeEdgeVertexMask(EDGE const& edgeNeighborhood, MASK& edgeVertexMask,
|
||||
Crease::Rule parentRule = Crease::RULE_UNKNOWN,
|
||||
Crease::Rule childRule = Crease::RULE_UNKNOWN) const;
|
||||
|
||||
///
|
||||
/// \brief Vertex-vertex masks
|
||||
/// If known, a single Rule or pair of Rules can be specified (indicating a crease
|
||||
/// transition) to accelerate the computation. Either no Rules, the first, or both should
|
||||
/// be specified. Specification of only the first Rule implies it to be true for both
|
||||
/// (wish the compiler would allow such default value specification), i.e. no transition.
|
||||
/// The case of knowing the parent Rule but deferring determination of the child Rule to
|
||||
/// this method is not supported.
|
||||
///
|
||||
template <typename VERTEX, typename MASK>
|
||||
void ComputeVertexVertexMask(VERTEX const& vertexNeighborhood, MASK& vertexVertexMask,
|
||||
Crease::Rule parentRule = Crease::RULE_UNKNOWN,
|
||||
Crease::Rule childRule = Crease::RULE_UNKNOWN) const;
|
||||
|
||||
///
|
||||
/// \brief Limit masks for vertices -- position and tangents
|
||||
/// These presume that a vertex is suitably isolated for its limit to be well-defined
|
||||
/// and, unlike the refinement masks, the subdivision Rule for the vertex (presumably at
|
||||
/// its last level of refinement) is required rather than being optional. In the
|
||||
/// presence of semi-sharp creasing that has not decayed to zero, the limit is neither
|
||||
/// sharp nor smooth -- in such cases the Rule specified by the caller determines the
|
||||
/// result.
|
||||
///
|
||||
/// For tangent masks, the direction of the first tangent (T1) is oriented towards the
|
||||
/// leading edge of the vertex, i.e. the first incident edge of the vertex (beginning
|
||||
/// the set of incident edges in counter-clockwise order). The second tangent (T2) lies
|
||||
/// within the tangent plane such that its normal can be computed as T1 x T2. So for a
|
||||
/// boundary vertex, T1 will point along the boundary in the direction of the leading
|
||||
/// edge while T2 points inward across the limit surface.
|
||||
///
|
||||
/// As for magnitude, no assumptions should be made of the magnitudes of the resulting
|
||||
/// tangent vectors. Common formulae often factor out scale factors that contribute to
|
||||
/// magnitude. While some attempt has been made to make magnitudes more consistent
|
||||
/// between regular corners, boundaries and the interior, the same has not been done at
|
||||
/// irregular vertices -- at least not yet. This may be addressed in future, as having
|
||||
/// consistent magnitudes returned here can aid in the construction of patches from
|
||||
/// limit positions and tangents.
|
||||
///
|
||||
template <typename VERTEX, typename MASK>
|
||||
void ComputeVertexLimitMask(VERTEX const& vertexNeighborhood, MASK& positionMask,
|
||||
Crease::Rule vertexRule) const;
|
||||
|
||||
template <typename VERTEX, typename MASK>
|
||||
void ComputeVertexLimitMask(VERTEX const& vertexNeighborhood, MASK& positionMask,
|
||||
MASK& tangent1Mask, MASK& tangent2Mask,
|
||||
Crease::Rule vertexRule) const;
|
||||
|
||||
//
|
||||
// Static methods defining traits/properties of the scheme:
|
||||
//
|
||||
static Split GetTopologicalSplitType();
|
||||
static int GetRegularFaceSize();
|
||||
static int GetRegularVertexValence();
|
||||
static int GetLocalNeighborhoodSize();
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Supporting internal methods -- optionally implemented, depending on specialization:
|
||||
//
|
||||
|
||||
// Subdivision/refinement masks -- two for edge-vertices and three for vertex-vertices:
|
||||
//
|
||||
template <typename EDGE, typename MASK>
|
||||
void assignCreaseMaskForEdge(EDGE const& edge, MASK& mask) const;
|
||||
template <typename EDGE, typename MASK>
|
||||
void assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) const;
|
||||
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCornerMaskForVertex(VERTEX const& edge, MASK& mask) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCreaseMaskForVertex(VERTEX const& edge, MASK& mask, int const creaseEnds[2]) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignSmoothMaskForVertex(VERTEX const& edge, MASK& mask) const;
|
||||
|
||||
//
|
||||
// Limit masks for position and tangents at vertices -- three cases for each:
|
||||
//
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCornerLimitMask(VERTEX const& vertex, MASK& pos) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCreaseLimitMask(VERTEX const& vertex, MASK& pos, int const creaseEnds[2]) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignSmoothLimitMask(VERTEX const& vertex, MASK& pos) const;
|
||||
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCornerLimitTangentMasks(VERTEX const& vertex, MASK& tan1, MASK& tan2) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignCreaseLimitTangentMasks(VERTEX const& vertex, MASK& tan1, MASK& tan2, int const creaseEnds[2]) const;
|
||||
template <typename VERTEX, typename MASK>
|
||||
void assignSmoothLimitTangentMasks(VERTEX const& vertex, MASK& tan1, MASK& tan2) const;
|
||||
|
||||
private:
|
||||
Options _options;
|
||||
|
||||
protected:
|
||||
|
||||
//
|
||||
// Internal implementation support:
|
||||
//
|
||||
// We need a local "mask" class to be declared locally within the vertex-vertex mask query
|
||||
// to hold one of the two possible masks required and to combine the local mask with the mask
|
||||
// the caller provides. It has been parameterized by <WEIGHT> so that a version compatible
|
||||
// with the caller's mask class is created.
|
||||
//
|
||||
template <typename WEIGHT>
|
||||
class LocalMask {
|
||||
|
||||
public:
|
||||
typedef WEIGHT Weight;
|
||||
|
||||
public:
|
||||
LocalMask(Weight* v, Weight* e, Weight* f) : _vWeights(v), _eWeights(e), _fWeights(f) { }
|
||||
~LocalMask() { }
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Methods required for general mask assignments and queries:
|
||||
//
|
||||
int GetNumVertexWeights() const { return _vCount; }
|
||||
int GetNumEdgeWeights() const { return _eCount; }
|
||||
int GetNumFaceWeights() const { return _fCount; }
|
||||
|
||||
void SetNumVertexWeights(int count) { _vCount = count; }
|
||||
void SetNumEdgeWeights( int count) { _eCount = count; }
|
||||
void SetNumFaceWeights( int count) { _fCount = count; }
|
||||
|
||||
Weight const& VertexWeight(int index) const { return _vWeights[index]; }
|
||||
Weight const& EdgeWeight( int index) const { return _eWeights[index]; }
|
||||
Weight const& FaceWeight( int index) const { return _fWeights[index]; }
|
||||
|
||||
Weight& VertexWeight(int index) { return _vWeights[index]; }
|
||||
Weight& EdgeWeight( int index) { return _eWeights[index]; }
|
||||
Weight& FaceWeight( int index) { return _fWeights[index]; }
|
||||
|
||||
bool AreFaceWeightsForFaceCenters() const { return _fWeightsForCenters; }
|
||||
void SetFaceWeightsForFaceCenters(bool on) { _fWeightsForCenters = on; }
|
||||
|
||||
public:
|
||||
|
||||
//
|
||||
// Additional methods -- mainly the blending method for vertex-vertex masks:
|
||||
//
|
||||
template <typename USER_MASK>
|
||||
inline void
|
||||
CombineVertexVertexMasks(Weight thisCoeff, Weight dstCoeff, USER_MASK& dst) const {
|
||||
|
||||
//
|
||||
// This implementation is convoluted by the potential sparsity of each mask. Since
|
||||
// it is specific to a vertex-vertex mask, we are guaranteed to have exactly one
|
||||
// vertex-weight for both masks, but the edge- and face-weights are optional. The
|
||||
// child mask (the "source") should have a superset of the weights of the parent
|
||||
// (the "destination") given its reduced sharpness, so we fortunately don't need to
|
||||
// test all permutations.
|
||||
//
|
||||
dst.VertexWeight(0) = dstCoeff * dst.VertexWeight(0) + thisCoeff * this->VertexWeight(0);
|
||||
|
||||
int edgeWeightCount = this->GetNumEdgeWeights();
|
||||
if (edgeWeightCount) {
|
||||
if (dst.GetNumEdgeWeights() == 0) {
|
||||
dst.SetNumEdgeWeights(edgeWeightCount);
|
||||
for (int i = 0; i < edgeWeightCount; ++i) {
|
||||
dst.EdgeWeight(i) = thisCoeff * this->EdgeWeight(i);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < edgeWeightCount; ++i) {
|
||||
dst.EdgeWeight(i) = dstCoeff * dst.EdgeWeight(i) + thisCoeff * this->EdgeWeight(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int faceWeightCount = this->GetNumFaceWeights();
|
||||
if (faceWeightCount) {
|
||||
//
|
||||
// If combining face weights, be sure their interpretation (i.e. face-centers
|
||||
// or opposite vertices) is properly set in the destination mask:
|
||||
//
|
||||
if (dst.GetNumFaceWeights() == 0) {
|
||||
dst.SetNumFaceWeights(faceWeightCount);
|
||||
dst.SetFaceWeightsForFaceCenters(this->AreFaceWeightsForFaceCenters());
|
||||
|
||||
for (int i = 0; i < faceWeightCount; ++i) {
|
||||
dst.FaceWeight(i) = thisCoeff * this->FaceWeight(i);
|
||||
}
|
||||
} else {
|
||||
assert(this->AreFaceWeightsForFaceCenters() == dst.AreFaceWeightsForFaceCenters());
|
||||
|
||||
for (int i = 0; i < faceWeightCount; ++i) {
|
||||
dst.FaceWeight(i) = dstCoeff * dst.FaceWeight(i) + thisCoeff * this->FaceWeight(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Weight* _vWeights;
|
||||
Weight* _eWeights;
|
||||
Weight* _fWeights;
|
||||
int _vCount;
|
||||
int _eCount;
|
||||
int _fCount;
|
||||
bool _fWeightsForCenters;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Crease and corner masks are common to most schemes -- the rest need to be provided
|
||||
// for each Scheme specialization.
|
||||
//
|
||||
template <SchemeType SCHEME>
|
||||
template <typename EDGE, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME>::assignCreaseMaskForEdge(EDGE const&, MASK& mask) const {
|
||||
|
||||
mask.SetNumVertexWeights(2);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
mask.VertexWeight(0) = 0.5f;
|
||||
mask.VertexWeight(1) = 0.5f;
|
||||
}
|
||||
|
||||
template <SchemeType SCHEME>
|
||||
template <typename VERTEX, typename MASK>
|
||||
inline void
|
||||
Scheme<SCHEME>::assignCornerMaskForVertex(VERTEX const&, MASK& mask) const {
|
||||
|
||||
mask.SetNumVertexWeights(1);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
mask.VertexWeight(0) = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The computation of a face-vertex mask is trivial and consistent for all schemes:
|
||||
//
|
||||
template <SchemeType SCHEME>
|
||||
template <typename FACE, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME>::ComputeFaceVertexMask(FACE const& face, MASK& mask) const {
|
||||
|
||||
int vertCount = face.GetNumVertices();
|
||||
|
||||
mask.SetNumVertexWeights(vertCount);
|
||||
mask.SetNumEdgeWeights(0);
|
||||
mask.SetNumFaceWeights(0);
|
||||
mask.SetFaceWeightsForFaceCenters(false);
|
||||
|
||||
typename MASK::Weight vWeight = 1.0f / (typename MASK::Weight) vertCount;
|
||||
for (int i = 0; i < vertCount; ++i) {
|
||||
mask.VertexWeight(i) = vWeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// The computation of an edge-vertex mask requires inspection of sharpness values to
|
||||
// determine if smooth or a crease, and also to detect and apply a transition from a
|
||||
// crease to smooth. Using the protected methods to assign the specific masks (only
|
||||
// two -- smooth or crease) this implementation should serve all non-linear schemes
|
||||
// (currently Catmark and Loop) and only needs to be specialized for Bilinear to
|
||||
// trivialize it to the crease case.
|
||||
//
|
||||
// The implementation here is slightly complicated by combining two scenarios into a
|
||||
// single implementation -- either the caller knows the parent and child rules and
|
||||
// provides them, or they don't and the Rules have to be determined from sharpness
|
||||
// values. Both cases include quick return once the parent is determined to be
|
||||
// smooth or the child a crease, leaving the transitional case remaining.
|
||||
//
|
||||
// The overall process is as follows:
|
||||
//
|
||||
// - quickly detect the most common specified or detected Smooth case and return
|
||||
// - quickly detect a full Crease by child Rule assignment and return
|
||||
// - determine from sharpness if unspecified child is a crease -- return if so
|
||||
// - compute smooth mask for child and combine with crease from parent
|
||||
//
|
||||
// Usage of the parent Rule here allows some misuse in that only three of five possible
|
||||
// assignments are legitimate for the parent and four for the child (Dart being only
|
||||
// valid for the child and Corner for neither). Results are undefined in these cases.
|
||||
//
|
||||
template <SchemeType SCHEME>
|
||||
template <typename EDGE, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME>::ComputeEdgeVertexMask(EDGE const& edge,
|
||||
MASK& mask,
|
||||
Crease::Rule parentRule,
|
||||
Crease::Rule childRule) const {
|
||||
|
||||
//
|
||||
// If the parent was specified or determined to be Smooth, we can quickly return
|
||||
// with a Smooth mask. Otherwise the parent is a crease -- if the child was
|
||||
// also specified to be a crease, we can quickly return with a Crease mask.
|
||||
//
|
||||
if ((parentRule == Crease::RULE_SMOOTH) ||
|
||||
((parentRule == Crease::RULE_UNKNOWN) && (edge.GetSharpness() <= 0.0f))) {
|
||||
assignSmoothMaskForEdge(edge, mask);
|
||||
return;
|
||||
}
|
||||
if (childRule == Crease::RULE_CREASE) {
|
||||
assignCreaseMaskForEdge(edge, mask);
|
||||
return;
|
||||
}
|
||||
|
||||
//
|
||||
// We have a Crease on the parent and the child was either specified as Smooth
|
||||
// or was not specified at all -- deal with the unspecified case first (again
|
||||
// returning a Crease mask if the child is also determined to be a Crease) and
|
||||
// continue if we have a transition to Smooth.
|
||||
//
|
||||
// Note when qualifying the child that if the parent sharpness > 1.0, regardless
|
||||
// of the creasing method, whether the child sharpness values decay to zero is
|
||||
// irrelevant -- the fractional weight for such a case (the value of the parent
|
||||
// sharpness) is > 1.0, and when clamped to 1 effectively yields a full crease.
|
||||
//
|
||||
if (childRule == Crease::RULE_UNKNOWN) {
|
||||
Crease crease(_options);
|
||||
|
||||
bool childIsCrease = false;
|
||||
if (parentRule == Crease::RULE_CREASE) {
|
||||
// Child unknown as default value but parent Rule specified as Crease
|
||||
childIsCrease = true;
|
||||
} else if (edge.GetSharpness() >= 1.0f) {
|
||||
// Sharpness >= 1.0 always a crease -- see note above
|
||||
childIsCrease = true;
|
||||
} else if (crease.IsUniform()) {
|
||||
// Sharpness < 1.0 is guaranteed to decay to 0.0 for Uniform child edges
|
||||
childIsCrease = false;
|
||||
} else {
|
||||
// Sharpness <= 1.0 does not necessarily decay to 0.0 for both child edges...
|
||||
float cEdgeSharpness[2];
|
||||
edge.GetChildSharpnesses(crease, cEdgeSharpness);
|
||||
childIsCrease = (cEdgeSharpness[0] > 0.0f) && (cEdgeSharpness[1] > 0.0f);
|
||||
}
|
||||
if (childIsCrease) {
|
||||
assignCreaseMaskForEdge(edge, mask);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// We are now left with the Crease-to-Smooth case -- compute the Smooth mask
|
||||
// for the child and augment it with the transitional Crease of the parent.
|
||||
//
|
||||
// A general combination of separately assigned masks here (as done in the vertex-
|
||||
// vertex case) is overkill -- trivially combine the 0.5f vertex coefficient for
|
||||
// the Crease of the parent with the vertex weights and attenuate the face weights
|
||||
// accordingly.
|
||||
//
|
||||
assignSmoothMaskForEdge(edge, mask);
|
||||
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
Weight pWeight = edge.GetSharpness();
|
||||
Weight cWeight = 1.0f - pWeight;
|
||||
|
||||
mask.VertexWeight(0) = pWeight * 0.5f + cWeight * mask.VertexWeight(0);
|
||||
mask.VertexWeight(1) = pWeight * 0.5f + cWeight * mask.VertexWeight(1);
|
||||
|
||||
int faceCount = mask.GetNumFaceWeights();
|
||||
for (int i = 0; i < faceCount; ++i) {
|
||||
mask.FaceWeight(i) *= cWeight;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// The computation of a vertex-vertex mask requires inspection of creasing sharpness values
|
||||
// to determine what subdivision Rules apply to the parent and its child vertex, and also to
|
||||
// detect and apply a transition between two differing Rules. Using the protected methods to
|
||||
// assign specific masks, this implementation should serve all non-linear schemes (currently
|
||||
// Catmark and Loop) and only needs to be specialized for Bilinear to remove all unnecessary
|
||||
// complexity relating to creasing, Rules, etc.
|
||||
//
|
||||
// The implementation here is slightly complicated by combining two scenarios into one --
|
||||
// either the caller knows the parent and child rules and provides them, or they don't and
|
||||
// the Rules have to be determined from sharpness values. Even when the Rules are known and
|
||||
// provided though, there are cases where the parent and child sharpness values need to be
|
||||
// identified, so accounting for the unknown Rules too is not much of an added complication.
|
||||
//
|
||||
// The benefit of supporting specified Rules is that they can often be trivially
|
||||
// determined from context (e.g. a vertex derived from a face at a previous level will always
|
||||
// be smooth) rather than more generally, and at greater cost, inspecting neighboring and
|
||||
// they are often the same for parent and child.
|
||||
//
|
||||
// The overall process is as follows:
|
||||
//
|
||||
// - quickly detect the most common Smooth case when specified and return
|
||||
// - determine if sharpness for parent is required and gather if so
|
||||
// - if unspecified, determine the parent rule
|
||||
// - assign mask for the parent rule -- returning if Smooth/Dart
|
||||
// - return if child rule matches parent
|
||||
// - gather sharpness for child to determine or combine child rule
|
||||
// - if unspecified, determine the child rule, returning if it matches parent
|
||||
// - assign local mask for child rule
|
||||
// - combine local child mask with the parent mask
|
||||
//
|
||||
// Remember -- if the parent rule is specified but the child is not, this implies only one
|
||||
// of the two optional rules was specified and is meant to indicate there is no transition,
|
||||
// so the child rule should be assigned to be the same (wish the compiler would allow this
|
||||
// in default value assignment).
|
||||
//
|
||||
template <SchemeType SCHEME>
|
||||
template <typename VERTEX, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME>::ComputeVertexVertexMask(VERTEX const& vertex,
|
||||
MASK& mask,
|
||||
Crease::Rule pRule,
|
||||
Crease::Rule cRule) const {
|
||||
|
||||
// Quick assignment and return for the most common case:
|
||||
if ((pRule == Crease::RULE_SMOOTH) || (pRule == Crease::RULE_DART)) {
|
||||
assignSmoothMaskForVertex(vertex, mask);
|
||||
return;
|
||||
}
|
||||
// If unspecified, assign the child rule to match the parent rule if specified:
|
||||
if ((cRule == Crease::RULE_UNKNOWN) && (pRule != Crease::RULE_UNKNOWN)) {
|
||||
cRule = pRule;
|
||||
}
|
||||
int valence = vertex.GetNumEdges();
|
||||
|
||||
//
|
||||
// Determine if we need the parent edge sharpness values -- identify/gather if so
|
||||
// and use it to compute the parent rule if unspecified:
|
||||
//
|
||||
float * pEdgeSharpnessBuffer = (float *)alloca(valence*sizeof(float)),
|
||||
* pEdgeSharpness = 0,
|
||||
pVertexSharpness = 0.0f;
|
||||
|
||||
bool requireParentSharpness = (pRule == Crease::RULE_UNKNOWN) ||
|
||||
(pRule == Crease::RULE_CREASE) ||
|
||||
(pRule != cRule);
|
||||
if (requireParentSharpness) {
|
||||
pVertexSharpness = vertex.GetSharpness();
|
||||
pEdgeSharpness = vertex.GetSharpnessPerEdge(pEdgeSharpnessBuffer);
|
||||
|
||||
if (pRule == Crease::RULE_UNKNOWN) {
|
||||
pRule = Crease(_options).DetermineVertexVertexRule(pVertexSharpness, valence, pEdgeSharpness);
|
||||
}
|
||||
}
|
||||
if ((pRule == Crease::RULE_SMOOTH) || (pRule == Crease::RULE_DART)) {
|
||||
assignSmoothMaskForVertex(vertex, mask);
|
||||
return; // As done on entry, we can return immediately if parent is Smooth/Dart
|
||||
} else if (pRule == Crease::RULE_CREASE) {
|
||||
int creaseEnds[2];
|
||||
Crease(_options).GetSharpEdgePairOfCrease(pEdgeSharpness, valence, creaseEnds);
|
||||
|
||||
assignCreaseMaskForVertex(vertex, mask, creaseEnds);
|
||||
} else {
|
||||
assignCornerMaskForVertex(vertex, mask);
|
||||
}
|
||||
if (cRule == pRule) return;
|
||||
|
||||
//
|
||||
// Identify/gather child sharpness to combine masks for the two differing Rules:
|
||||
//
|
||||
Crease crease(_options);
|
||||
|
||||
float * cEdgeSharpnessBuffer = (float *)alloca(valence*sizeof(float)),
|
||||
* cEdgeSharpness = vertex.GetChildSharpnessPerEdge(crease, cEdgeSharpnessBuffer),
|
||||
cVertexSharpness = vertex.GetChildSharpness(crease);
|
||||
|
||||
if (cRule == Crease::RULE_UNKNOWN) {
|
||||
cRule = crease.DetermineVertexVertexRule(cVertexSharpness, valence, cEdgeSharpness);
|
||||
if (cRule == pRule) return;
|
||||
}
|
||||
|
||||
//
|
||||
// Initialize a local child mask, compute the fractional weight from parent and child
|
||||
// sharpness values and combine the two masks:
|
||||
//
|
||||
typedef typename MASK::Weight Weight;
|
||||
|
||||
Weight * cMaskWeights = (Weight *)alloca((1 + 2 * valence)*sizeof(Weight));
|
||||
LocalMask<Weight> cMask(cMaskWeights, cMaskWeights + 1, cMaskWeights + 1 + valence);
|
||||
|
||||
if ((cRule == Crease::RULE_SMOOTH) || (cRule == Crease::RULE_DART)) {
|
||||
assignSmoothMaskForVertex(vertex, cMask);
|
||||
} else if (cRule == Crease::RULE_CREASE) {
|
||||
int creaseEnds[2];
|
||||
Crease(_options).GetSharpEdgePairOfCrease(cEdgeSharpness, valence, creaseEnds);
|
||||
|
||||
assignCreaseMaskForVertex(vertex, cMask, creaseEnds);
|
||||
} else {
|
||||
assignCornerMaskForVertex(vertex, cMask);
|
||||
}
|
||||
|
||||
Weight pWeight = crease.ComputeFractionalWeightAtVertex(pVertexSharpness, cVertexSharpness,
|
||||
valence, pEdgeSharpness, cEdgeSharpness);
|
||||
Weight cWeight = 1.0f - pWeight;
|
||||
|
||||
cMask.CombineVertexVertexMasks(cWeight, pWeight, mask);
|
||||
}
|
||||
|
||||
//
|
||||
// The computation of limit masks for vertices:
|
||||
//
|
||||
template <SchemeType SCHEME>
|
||||
template <typename VERTEX, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME>::ComputeVertexLimitMask(VERTEX const& vertex,
|
||||
MASK& mask,
|
||||
Crease::Rule rule) const {
|
||||
|
||||
if ((rule == Crease::RULE_SMOOTH) || (rule == Crease::RULE_DART)) {
|
||||
assignSmoothLimitMask(vertex, mask);
|
||||
} else if (rule == Crease::RULE_CREASE) {
|
||||
float * edgeSharpness = (float *)alloca(vertex.GetNumEdges() * sizeof(float));
|
||||
vertex.GetSharpnessPerEdge(edgeSharpness);
|
||||
|
||||
int creaseEnds[2];
|
||||
Crease(_options).GetSharpEdgePairOfCrease(edgeSharpness, vertex.GetNumEdges(), creaseEnds);
|
||||
|
||||
assignCreaseLimitMask(vertex, mask, creaseEnds);
|
||||
} else {
|
||||
assignCornerLimitMask(vertex, mask);
|
||||
}
|
||||
}
|
||||
|
||||
template <SchemeType SCHEME>
|
||||
template <typename VERTEX, typename MASK>
|
||||
void
|
||||
Scheme<SCHEME>::ComputeVertexLimitMask(VERTEX const& vertex,
|
||||
MASK& posMask,
|
||||
MASK& tan1Mask,
|
||||
MASK& tan2Mask,
|
||||
Crease::Rule rule) const {
|
||||
|
||||
if ((rule == Crease::RULE_SMOOTH) || (rule == Crease::RULE_DART)) {
|
||||
assignSmoothLimitMask(vertex, posMask);
|
||||
assignSmoothLimitTangentMasks(vertex, tan1Mask, tan2Mask);
|
||||
} else if (rule == Crease::RULE_CREASE) {
|
||||
float * edgeSharpness = (float *)alloca(vertex.GetNumEdges() * sizeof(float));
|
||||
vertex.GetSharpnessPerEdge(edgeSharpness);
|
||||
|
||||
int creaseEnds[2];
|
||||
Crease(_options).GetSharpEdgePairOfCrease(edgeSharpness, vertex.GetNumEdges(), creaseEnds);
|
||||
|
||||
assignCreaseLimitMask(vertex, posMask, creaseEnds);
|
||||
assignCreaseLimitTangentMasks(vertex, tan1Mask, tan2Mask, creaseEnds);
|
||||
} else {
|
||||
assignCornerLimitMask(vertex, posMask);
|
||||
assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_SCHEME_H */
|
||||
78
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/typeTraits.cpp
vendored
Normal file
78
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/typeTraits.cpp
vendored
Normal file
@@ -0,0 +1,78 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#include "../sdc/types.h"
|
||||
|
||||
#include "../sdc/bilinearScheme.h"
|
||||
#include "../sdc/catmarkScheme.h"
|
||||
#include "../sdc/loopScheme.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
struct TraitsEntry {
|
||||
char const * _name;
|
||||
|
||||
Split _splitType;
|
||||
int _regularFaceSize;
|
||||
int _regularVertexValence;
|
||||
int _localNeighborhood;
|
||||
};
|
||||
|
||||
static const TraitsEntry staticTraitsTable[3] = {
|
||||
{ "bilinear", Scheme<SCHEME_BILINEAR>::GetTopologicalSplitType(),
|
||||
Scheme<SCHEME_BILINEAR>::GetRegularFaceSize(),
|
||||
Scheme<SCHEME_BILINEAR>::GetRegularVertexValence(),
|
||||
Scheme<SCHEME_BILINEAR>::GetLocalNeighborhoodSize() },
|
||||
{ "catmark", Scheme<SCHEME_CATMARK>::GetTopologicalSplitType(),
|
||||
Scheme<SCHEME_CATMARK>::GetRegularFaceSize(),
|
||||
Scheme<SCHEME_CATMARK>::GetRegularVertexValence(),
|
||||
Scheme<SCHEME_CATMARK>::GetLocalNeighborhoodSize() },
|
||||
{ "loop", Scheme<SCHEME_LOOP>::GetTopologicalSplitType(),
|
||||
Scheme<SCHEME_LOOP>::GetRegularFaceSize(),
|
||||
Scheme<SCHEME_LOOP>::GetRegularVertexValence(),
|
||||
Scheme<SCHEME_LOOP>::GetLocalNeighborhoodSize() }
|
||||
};
|
||||
|
||||
//
|
||||
// Static methods for SchemeTypeTraits:
|
||||
//
|
||||
char const*
|
||||
SchemeTypeTraits::GetName(SchemeType schemeType) {
|
||||
|
||||
return staticTraitsTable[schemeType]._name;
|
||||
}
|
||||
|
||||
Split
|
||||
SchemeTypeTraits::GetTopologicalSplitType(SchemeType schemeType) {
|
||||
|
||||
return staticTraitsTable[schemeType]._splitType;
|
||||
}
|
||||
|
||||
int
|
||||
SchemeTypeTraits::GetRegularFaceSize(SchemeType schemeType) {
|
||||
|
||||
return staticTraitsTable[schemeType]._regularFaceSize;
|
||||
}
|
||||
|
||||
int
|
||||
SchemeTypeTraits::GetRegularVertexValence(SchemeType schemeType) {
|
||||
|
||||
return staticTraitsTable[schemeType]._regularVertexValence;
|
||||
}
|
||||
|
||||
int
|
||||
SchemeTypeTraits::GetLocalNeighborhoodSize(SchemeType schemeType) {
|
||||
|
||||
return staticTraitsTable[schemeType]._localNeighborhood;
|
||||
}
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
} // end namespace OpenSubdiv
|
||||
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/types.h
vendored
Normal file
59
blender-5.2.0/extern/opensubdiv-source/opensubdiv/sdc/types.h
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Copyright 2014 DreamWorks Animation LLC.
|
||||
//
|
||||
// Licensed under the terms set forth in the LICENSE.txt file available at
|
||||
// https://opensubdiv.org/license.
|
||||
//
|
||||
#ifndef OPENSUBDIV3_SDC_TYPES_H
|
||||
#define OPENSUBDIV3_SDC_TYPES_H
|
||||
|
||||
#include "../version.h"
|
||||
|
||||
namespace OpenSubdiv {
|
||||
namespace OPENSUBDIV_VERSION {
|
||||
|
||||
namespace Sdc {
|
||||
|
||||
///
|
||||
/// \brief Enumerated type for all subdivision schemes supported by OpenSubdiv
|
||||
///
|
||||
enum SchemeType {
|
||||
SCHEME_BILINEAR,
|
||||
SCHEME_CATMARK,
|
||||
SCHEME_LOOP
|
||||
};
|
||||
|
||||
|
||||
///
|
||||
/// \brief Enumerated type for all face splitting schemes
|
||||
///
|
||||
enum Split {
|
||||
SPLIT_TO_QUADS, ///< Used by Catmark and Bilinear
|
||||
SPLIT_TO_TRIS, ///< Used by Loop
|
||||
SPLIT_HYBRID ///< Not currently used (potential future extension)
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Traits associated with the types of all subdivision schemes -- parameterized by
|
||||
/// the scheme type. All traits are also defined in the scheme itself.
|
||||
///
|
||||
struct SchemeTypeTraits {
|
||||
|
||||
static SchemeType GetType(SchemeType schemeType) { return schemeType; }
|
||||
|
||||
static Split GetTopologicalSplitType(SchemeType schemeType);
|
||||
static int GetRegularFaceSize(SchemeType schemeType);
|
||||
static int GetRegularVertexValence(SchemeType schemeType);
|
||||
static int GetLocalNeighborhoodSize(SchemeType schemeType);
|
||||
|
||||
static char const* GetName(SchemeType schemeType);
|
||||
};
|
||||
|
||||
|
||||
} // end namespace sdc
|
||||
|
||||
} // end namespace OPENSUBDIV_VERSION
|
||||
using namespace OPENSUBDIV_VERSION;
|
||||
} // end namespace OpenSubdiv
|
||||
|
||||
#endif /* OPENSUBDIV3_SDC_TYPES_H */
|
||||
Reference in New Issue
Block a user