All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
crease.h
Go to the documentation of this file.
1 //
2 // Copyright 2014 DreamWorks Animation LLC.
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef SDC_CREASE_H
25 #define SDC_CREASE_H
26 
27 #include "../version.h"
28 
29 #include "../sdc/options.h"
30 
31 namespace OpenSubdiv {
32 namespace OPENSUBDIV_VERSION {
33 
34 namespace Sdc {
35 
36 //
37 // Types, constants and utilities related to semi-sharp creasing -- whose implementation is
38 // independent of the subdivision scheme.
39 //
40 // Crease is intended to be a light-weight, trivially constructed class that computes
41 // crease-related properties. An instance of an Crease is defined with a set of options
42 // that include current and future variations that will impact computations involving
43 // sharpness values.
44 //
45 // We do not to use Neighborhoods here as input. Since their sharpness values are potentially
46 // not specified (and gathered on demand), and the methods here rely more on the sharpness
47 // values and less on the topology, we choose to work directly with the sharpness values for
48 // more flexibility. We also follow the trend of using primitive arrays in the interface.
49 //
50 // Note on the need for and use of sharpness values:
51 // In general, mask queries rely on the sharpness values. The common case of a smooth
52 // vertex, when known, avoids the need to inspect them, but unless the rules are well understood,
53 // users will be expected to provided them -- particularly when they expect the mask queries
54 // to do all of the work (just determining if a vertex is smooth will require inspection of
55 // incident edge sharpness).
56 // Mask queries will occassionally require the subdivided sharpness values around the
57 // child vertex. So users will be expected to either provide them up front when known, or to be
58 // gathered on demand. Any implementation of subdivision with creasing cannot avoid subdividing
59 // the sharpness values first, so keeping them available for re-use is a worthwhile consideration.
60 //
61 
62 class Crease {
63 public:
64  //
65  // Constants and related queries of sharpness values:
66  //
67  static float const SHARPNESS_SMOOTH; // = 0.0f, do we really need this?
68  static float const SHARPNESS_INFINITE; // = 10.0f;
69 
70  static bool IsSmooth(float sharpness) { return sharpness <= SHARPNESS_SMOOTH; }
71  static bool IsSharp(float sharpness) { return sharpness > SHARPNESS_SMOOTH; }
72  static bool IsInfinite(float sharpness) { return sharpness >= SHARPNESS_INFINITE; }
73  static bool IsSemiSharp(float sharpness) { return (SHARPNESS_SMOOTH < sharpness) && (sharpness < SHARPNESS_INFINITE); }
74 
75  //
76  // Enum for the types of subdivision rules applied based on sharpness values (note these
77  // correspond to Hbr's vertex "mask"). The values are assigned to bit positions as it is
78  // useful to OR the corners of faces to quickly inspect its applicable rules.
79  //
80  enum Rule {
82  RULE_SMOOTH = (1 << 0),
83  RULE_DART = (1 << 1),
84  RULE_CREASE = (1 << 2),
85  RULE_CORNER = (1 << 3)
86  };
87 
88 public:
89  Crease() : _options() { }
90  Crease(Options const& options) : _options(options) { }
91  ~Crease() { }
92 
93  //
94  // Considering labeling the current/default/normal creasing method as "simple" in contrast
95  // to all others that are "complex". The idea is that code can make certain assumptions
96  // and take some "simple" action in some cases to avoid the higher costs of dealing with
97  // more complex implementations.
98  //
99  bool IsUniform() const { return _options.GetCreasingMethod() == Options::CREASE_UNIFORM; }
100 
101  //
102  // Optional sharp features:
103  // Since options treat certain topological features as infinitely sharp -- boundaries
104  // or nonmanifold features -- sharpness values should be adjust before use. The following
105  // methods will adjust specific according to the options applied.
106  //
107  float SharpenBoundaryEdge(float edgeSharpness) const;
108  float SharpenBoundaryVertex(float edgeSharpness) const;
109 
110  float SharpenNonManifoldEdge(float edgeSharpness) const;
111  float SharpenNonManifoldVertex(float edgeSharpness) const;
112 
113  //
114  // Sharpness subdivision:
115  // The simple case for computing a subdivided sharpness value is as follows:
116  // - Smooth edges or verts stay Smooth
117  // - Sharp edges or verts stay Sharp
118  // - semi-sharp edges or verts are decremented by 1.0
119  // but for Chaikin (and potentially future creasing schemes that improve upon it) the
120  // computation is more involved. In the case of edges in particular, the sharpness of a
121  // child edge is determined by the sharpness in the neighborhood of the end vertex
122  // corresponding to the child. For this reason, an alternative to subdividing sharpness
123  // that computes all child edges around a vertex is given.
124  //
125  float SubdivideUniformSharpness(float vertexOrEdgeSharpness) const;
126 
127  float SubdivideVertexSharpness(float vertexSharpness) const;
128 
129  float SubdivideEdgeSharpnessAtVertex(float edgeSharpness,
130  int incidentEdgeCountAtEndVertex,
131  float const* edgeSharpnessAroundEndVertex) const;
132 
133  void SubdivideEdgeSharpnessesAroundVertex(int incidentEdgeCountAtVertex,
134  float const* incidentEdgeSharpnessAroundVertex,
135  float* childEdgesSharpnessAroundVertex) const;
136 
137  //
138  // Rule determination:
139  // Mask queries do not require the Rule to be known, it can be determined from
140  // the information provided, but it is generally more efficient when the Rule is known
141  // and provided. In particular, the Smooth case dominates and is known to be applicable
142  // based on the origin of the vertex without inspection of sharpness.
143  //
144  Rule DetermineVertexVertexRule(float vertexSharpness,
145  int incidentEdgeCount,
146  float const* incidentEdgeSharpness) const;
147  Rule DetermineVertexVertexRule(float vertexSharpness,
148  int sharpEdgeCount) const;
149 
150  //
151  // Transitional weighting:
152  // When the rules applicable to a parent vertex and its child differ, one or more
153  // sharpness values has "decayed" to zero. Both rules are then applicable and blended
154  // by a weight between 0 and 1 that reflects the transition. Most often this will be
155  // a single sharpness value that decays from within the interval [0,1] to zero -- and
156  // the weight to apply is exactly that sharpness value -- but more than one may decay,
157  // and values > 1 may also decay to 0 in a single step while others within [0,1] may
158  // remain > 0.
159  // So to properly determine a transitional weight, sharpness values for both the
160  // parent and child must be inspected, combined and clamped accordingly.
161  //
162  // Open questions:
163  // - does this method need to be public, or can it reside within the mask
164  // query classes? (though it would be the same for anything non-linear, so
165  // may be worth making a protected method somewhere)
166  // - does this need further consideration at an edge-vertex?
167  // - no, the edge-vertex case is far more trivial: one non-zero sharpness
168  // for the edge that decays to zero for one or both child edges -- the
169  // transitional weight is simply the edge sharpness (clamped to 1)
170  // ? why pass only the parent vertex sharpness...
171  // - because it is so trivial to compute the child vertex sharpness?
172  // - may be better off passing both parent and child for both vertex and edge
173  // just to be clear here.
174  //
175  float ComputeFractionalWeightAtVertex(float vertexSharpness,
176  float childVertexSharpness,
177  int incidentEdgeCount,
178  float const* incidentEdgeSharpness,
179  float const* childEdgesSharpness) const;
180 
181  // Would these really help? Maybe only need Rules for the vertex-vertex case...
182  //
183  // Rule DetermineEdgeVertexRule(float parentEdgeSharpness) const;
184  // Rule DetermineEdgeVertexRule(float childEdge1Sharpness, float childEdge2Sharpness) const;
185 
186 protected:
187  float decrementSharpness(float sharpness) const;
188 
189 private:
190  Options _options;
191 };
192 
193 
194 //
195 // Non-trivial inline declarations:
196 //
197 inline float
198 Crease::SharpenBoundaryEdge(float edgeSharpness) const {
199 
201  SHARPNESS_INFINITE : edgeSharpness;
202 }
203 
204 inline float
205 Crease::SharpenBoundaryVertex(float vertexSharpness) const {
206 
208  SHARPNESS_INFINITE : vertexSharpness;
209 }
210 
211 inline float
212 Crease::SharpenNonManifoldEdge(float edgeSharpness) const {
213 
214  // Shouldn't we error/assert somehow if indicated that non-manifold not supported?
215  // assert(_options.GetNonManifoldInterpolation() != Options::NON_MANIFOLD_NONE);
216 
218  SHARPNESS_INFINITE : edgeSharpness;
219 }
220 inline float
221 Crease::SharpenNonManifoldVertex(float vertexSharpness) const {
222 
223  // Shouldn't we error/assert somehow if indicated that non-manifold not supported?
224  // assert(_options.GetNonManifoldInterpolation() != Options::NON_MANIFOLD_NONE);
225 
227  SHARPNESS_INFINITE : vertexSharpness;
228 }
229 
230 
231 inline float
232 Crease::decrementSharpness(float sharpness) const {
233 
234  if (IsSmooth(sharpness)) return Crease::SHARPNESS_SMOOTH; // redundant but most common
235  if (IsInfinite(sharpness)) return Crease::SHARPNESS_INFINITE;
236  if (sharpness > 1.0f) return (sharpness - 1.0f);
238 }
239 
240 inline float
241 Crease::SubdivideUniformSharpness(float vertexOrEdgeSharpness) const {
242 
243  return decrementSharpness(vertexOrEdgeSharpness);
244 }
245 
246 inline float
247 Crease::SubdivideVertexSharpness(float vertexSharpness) const {
248 
249  return decrementSharpness(vertexSharpness);
250 }
251 
252 } // end namespace sdc
253 
254 } // end namespace OPENSUBDIV_VERSION
255 using namespace OPENSUBDIV_VERSION;
256 } // end namespace OpenSubdiv
257 
258 #endif /* SDC_CREASE_H */
259 
static bool IsSmooth(float sharpness)
Definition: crease.h:70
float SubdivideEdgeSharpnessAtVertex(float edgeSharpness, int incidentEdgeCountAtEndVertex, float const *edgeSharpnessAroundEndVertex) const
float SubdivideVertexSharpness(float vertexSharpness) const
Definition: crease.h:247
CreasingMethod GetCreasingMethod() const
Definition: options.h:131
static bool IsInfinite(float sharpness)
Definition: crease.h:72
Rule DetermineVertexVertexRule(float vertexSharpness, int incidentEdgeCount, float const *incidentEdgeSharpness) const
float SharpenNonManifoldVertex(float edgeSharpness) const
Definition: crease.h:221
void SubdivideEdgeSharpnessesAroundVertex(int incidentEdgeCountAtVertex, float const *incidentEdgeSharpnessAroundVertex, float *childEdgesSharpnessAroundVertex) const
float ComputeFractionalWeightAtVertex(float vertexSharpness, float childVertexSharpness, int incidentEdgeCount, float const *incidentEdgeSharpness, float const *childEdgesSharpness) const
float SharpenBoundaryVertex(float edgeSharpness) const
Definition: crease.h:205
Crease(Options const &options)
Definition: crease.h:90
static bool IsSharp(float sharpness)
Definition: crease.h:71
static bool IsSemiSharp(float sharpness)
Definition: crease.h:73
float SharpenNonManifoldEdge(float edgeSharpness) const
Definition: crease.h:212
float SharpenBoundaryEdge(float edgeSharpness) const
Definition: crease.h:198
VVarBoundaryInterpolation GetVVarBoundaryInterpolation() const
Definition: options.h:125
float decrementSharpness(float sharpness) const
Definition: crease.h:232
float SubdivideUniformSharpness(float vertexOrEdgeSharpness) const
Definition: crease.h:241
NonManifoldInterpolation GetNonManifoldInterpolation() const
Definition: options.h:134