catmarkScheme.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 OPENSUBDIV3_SDC_CATMARK_SCHEME_H
25 #define OPENSUBDIV3_SDC_CATMARK_SCHEME_H
26
27 #include "../version.h"
28
29 #include "../sdc/scheme.h"
30
31 #include <cassert>
32 #include <cmath>
33
34 namespace OpenSubdiv {
35 namespace OPENSUBDIV_VERSION {
36
37 namespace Sdc {
38
39 //
40 // Specializations for Scheme<SCHEME_CATMARK>:
41 //
42
43 //
44 // Catmark traits:
45 //
46 template <>
47 inline Split Scheme<SCHEME_CATMARK>::GetTopologicalSplitType() { return SPLIT_TO_QUADS; }
48
49 template <>
50 inline int Scheme<SCHEME_CATMARK>::GetRegularFaceSize() { return 4; }
51
52 template <>
53 inline int Scheme<SCHEME_CATMARK>::GetRegularVertexValence() { return 4; }
54
55 template <>
56 inline int Scheme<SCHEME_CATMARK>::GetLocalNeighborhoodSize() { return 1; }
57
58
59 //
60 // Masks for edge-vertices: the hard Crease mask does not need to be specialized
61 // (simply the midpoint), so all that is left is the Smooth case:
62 //
63 // The Smooth mask is complicated by the need to support the "triangle subdivision"
64 // option, which applies different weighting in the presence of triangles. It is
65 // up for debate as to whether this is useful or not -- we may be able to deprecate
66 // this option.
67 //
68 template <>
69 template <typename EDGE, typename MASK>
70 inline void
71 Scheme<SCHEME_CATMARK>::assignSmoothMaskForEdge(EDGE const& edge, MASK& mask) const {
72
73 typedef typename MASK::Weight Weight;
74
75 int faceCount = edge.GetNumFaces();
76
77 mask.SetNumVertexWeights(2);
78 mask.SetNumEdgeWeights(0);
79 mask.SetNumFaceWeights(faceCount);
80 mask.SetFaceWeightsForFaceCenters(true);
81
82 //
83 // Determine if we need to inspect incident faces and apply alternate weighting for
84 // triangles -- and if so, determine which of the two are triangles.
85 //
86 bool face0IsTri = false;
87 bool face1IsTri = false;
88 bool useTriangleOption = (_options.GetTriangleSubdivision() == Options::TRI_SUB_SMOOTH);
89 if (useTriangleOption) {
90 if (faceCount == 2) {
91 //
92 // Ideally we want to avoid this inspection when we have already subdivided at
93 // least once -- need something in the Edge interface to help avoid this, e.g.
94 // an IsRegular() query, the subdivision level...
95 //
96 int vertsPerFace[2];
97 edge.GetNumVerticesPerFace(vertsPerFace);
98
99 face0IsTri = (vertsPerFace[0] == 3);
100 face1IsTri = (vertsPerFace[1] == 3);
101 useTriangleOption = face0IsTri || face1IsTri;
102 } else {
103 useTriangleOption = false;
104 }
105 }
106
107 if (! useTriangleOption) {
108 mask.VertexWeight(0) = 0.25f;
109 mask.VertexWeight(1) = 0.25f;
110
111 if (faceCount == 2) {
112 mask.FaceWeight(0) = 0.25f;
113 mask.FaceWeight(1) = 0.25f;
114 } else {
115 Weight fWeight = 0.5f / (Weight)faceCount;
116 for (int i = 0; i < faceCount; ++i) {
117 mask.FaceWeight(i) = fWeight;
118 }
119 }
120 } else {
121 //
122 // This mimics the implementation in Hbr in terms of order of operations.
123 //
124 const Weight CATMARK_SMOOTH_TRI_EDGE_WEIGHT = 0.470f;
125
126 Weight f0Weight = face0IsTri ? CATMARK_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
127 Weight f1Weight = face1IsTri ? CATMARK_SMOOTH_TRI_EDGE_WEIGHT : 0.25f;
128
129 Weight fWeight = 0.5f * (f0Weight + f1Weight);
130 Weight vWeight = 0.5f * (1.0f - 2.0f * fWeight);
131
132 mask.VertexWeight(0) = vWeight;
133 mask.VertexWeight(1) = vWeight;
134
135 mask.FaceWeight(0) = fWeight;
136 mask.FaceWeight(1) = fWeight;
137 }
138 }
139
140
141 //
142 // Masks for vertex-vertices: the hard Corner mask does not need to be specialized
143 // (simply the vertex itself), leaving the Crease and Smooth cases (Dart is smooth):
144 //
145 template <>
146 template <typename VERTEX, typename MASK>
147 inline void
148 Scheme<SCHEME_CATMARK>::assignCreaseMaskForVertex(VERTEX const& vertex, MASK& mask,
149 int const creaseEnds[2]) const {
150 typedef typename MASK::Weight Weight;
151
152 int valence = vertex.GetNumEdges();
153
154 mask.SetNumVertexWeights(1);
155 mask.SetNumEdgeWeights(valence);
156 mask.SetNumFaceWeights(0);
157 mask.SetFaceWeightsForFaceCenters(false);
158
159 Weight vWeight = 0.75f;
160 Weight eWeight = 0.125f;
161
162 mask.VertexWeight(0) = vWeight;
163 for (int i = 0; i < valence; ++i) {
164 mask.EdgeWeight(i) = 0.0f;
165 }
166 mask.EdgeWeight(creaseEnds[0]) = eWeight;
167 mask.EdgeWeight(creaseEnds[1]) = eWeight;
168 }
169
170 template <>
171 template <typename VERTEX, typename MASK>
172 inline void
173 Scheme<SCHEME_CATMARK>::assignSmoothMaskForVertex(VERTEX const& vertex, MASK& mask) const {
174
175 typedef typename MASK::Weight Weight;
176
177 //
178 // A Smooth vertex must be manifold and interior -- manifold boundary vertices will be
179 // Creases and non-manifold vertices of any kind will be Corners or Creases. If smooth
180 // rules for non-manifold vertices are ever defined, this will need adjusting:
181 //
182 assert(vertex.GetNumFaces() == vertex.GetNumEdges());
183
184 int valence = vertex.GetNumFaces();
185
186 mask.SetNumVertexWeights(1);
187 mask.SetNumEdgeWeights(valence);
188 mask.SetNumFaceWeights(valence);
189 mask.SetFaceWeightsForFaceCenters(true);
190
191 Weight vWeight = (Weight)(valence - 2) / (Weight)valence;
192 Weight fWeight = 1.0f / (Weight)(valence * valence);
193 Weight eWeight = fWeight;
194
195 mask.VertexWeight(0) = vWeight;
196 for (int i = 0; i < valence; ++i) {
197 mask.EdgeWeight(i) = eWeight;
198 mask.FaceWeight(i) = fWeight;
199 }
200 }
201
202 //
203 // Limit masks for position:
204 //
205 template <>
206 template <typename VERTEX, typename MASK>
207 inline void
208 Scheme<SCHEME_CATMARK>::assignCornerLimitMask(VERTEX const& /* vertex */, MASK& posMask) const {
209
210 posMask.SetNumVertexWeights(1);
211 posMask.SetNumEdgeWeights(0);
212 posMask.SetNumFaceWeights(0);
213 posMask.SetFaceWeightsForFaceCenters(false);
214
215 posMask.VertexWeight(0) = 1.0f;
216 }
217
218 template <>
219 template <typename VERTEX, typename MASK>
220 inline void
221 Scheme<SCHEME_CATMARK>::assignCreaseLimitMask(VERTEX const& vertex, MASK& posMask,
222 int const creaseEnds[2]) const {
223
224 typedef typename MASK::Weight Weight;
225
226 int valence = vertex.GetNumEdges();
227
228 posMask.SetNumVertexWeights(1);
229 posMask.SetNumEdgeWeights(valence);
230 posMask.SetNumFaceWeights(0);
231 posMask.SetFaceWeightsForFaceCenters(false);
232
233 Weight vWeight = 2.0f / 3.0f;
234 Weight eWeight = 1.0f / 6.0f;
235
236 posMask.VertexWeight(0) = vWeight;
237 for (int i = 0; i < valence; ++i) {
238 posMask.EdgeWeight(i) = 0.0f;
239 }
240 posMask.EdgeWeight(creaseEnds[0]) = eWeight;
241 posMask.EdgeWeight(creaseEnds[1]) = eWeight;
242 }
243
244 template <>
245 template <typename VERTEX, typename MASK>
246 inline void
247 Scheme<SCHEME_CATMARK>::assignSmoothLimitMask(VERTEX const& vertex, MASK& posMask) const {
248
249 typedef typename MASK::Weight Weight;
250
251 int valence = vertex.GetNumFaces();
252 if (valence == 2) {
253 assignCornerLimitMask(vertex, posMask);
254 return;
255 }
256
257 posMask.SetNumVertexWeights(1);
258 posMask.SetNumEdgeWeights(valence);
259 posMask.SetNumFaceWeights(valence);
260 posMask.SetFaceWeightsForFaceCenters(false);
261
262 // Specialize for the regular case:
263 if (valence == 4) {
264 Weight fWeight = 1.0f / 36.0f;
265 Weight eWeight = 1.0f / 9.0f;
266 Weight vWeight = 4.0f / 9.0f;
267
268 posMask.VertexWeight(0) = vWeight;
269
270 posMask.EdgeWeight(0) = eWeight;
271 posMask.EdgeWeight(1) = eWeight;
272 posMask.EdgeWeight(2) = eWeight;
273 posMask.EdgeWeight(3) = eWeight;
274
275 posMask.FaceWeight(0) = fWeight;
276 posMask.FaceWeight(1) = fWeight;
277 posMask.FaceWeight(2) = fWeight;
278 posMask.FaceWeight(3) = fWeight;
279 } else {
280 Weight fWeight = 1.0f / (Weight)(valence * (valence + 5.0f));
281 Weight eWeight = 4.0f * fWeight;
282 Weight vWeight = (Weight)(1.0f - valence * (eWeight + fWeight));
283
284 posMask.VertexWeight(0) = vWeight;
285 for (int i = 0; i < valence; ++i) {
286 posMask.EdgeWeight(i) = eWeight;
287 posMask.FaceWeight(i) = fWeight;
288 }
289 }
290 }
291
292 //
293 // Limit masks for tangents -- these are stubs for now, or have a temporary
294 // implementation
295 //
296 template <>
297 template <typename VERTEX, typename MASK>
298 inline void
299 Scheme<SCHEME_CATMARK>::assignCornerLimitTangentMasks(VERTEX const& vertex,
300 MASK& tan1Mask, MASK& tan2Mask) const {
301
302 int valence = vertex.GetNumEdges();
303
304 tan1Mask.SetNumVertexWeights(1);
305 tan1Mask.SetNumEdgeWeights(valence);
306 tan1Mask.SetNumFaceWeights(0);
307 tan1Mask.SetFaceWeightsForFaceCenters(false);
308
309 tan2Mask.SetNumVertexWeights(1);
310 tan2Mask.SetNumEdgeWeights(valence);
311 tan2Mask.SetNumFaceWeights(0);
312 tan2Mask.SetFaceWeightsForFaceCenters(false);
313
314 // Should be at least 2 edges -- be sure to clear weights for any more:
315 tan1Mask.VertexWeight(0) = -1.0f;
316 tan1Mask.EdgeWeight(0) = 1.0f;
317 tan1Mask.EdgeWeight(1) = 0.0f;
318
319 tan2Mask.VertexWeight(0) = -1.0f;
320 tan2Mask.EdgeWeight(0) = 0.0f;
321 tan2Mask.EdgeWeight(1) = 1.0f;
322
323 for (int i = 2; i < valence; ++i) {
324 tan1Mask.EdgeWeight(i) = 0.0f;
325 tan2Mask.EdgeWeight(i) = 0.0f;
326 }
327 }
328
329 template <>
330 template <typename VERTEX, typename MASK>
331 inline void
332 Scheme<SCHEME_CATMARK>::assignCreaseLimitTangentMasks(VERTEX const& vertex,
333 MASK& tan1Mask, MASK& tan2Mask, int const creaseEnds[2]) const {
334
335 typedef typename MASK::Weight Weight;
336
337 //
338 // First, the tangent along the crease:
339 // The first crease edge is considered the "leading" edge of the span
340 // of surface for which we are evaluating tangents and the second edge the
341 // "trailing edge". By convention, the tangent along the crease is oriented
342 // in the direction of the leading edge.
343 //
344 int numEdges = vertex.GetNumEdges();
345 int numFaces = vertex.GetNumFaces();
346
347 tan1Mask.SetNumVertexWeights(1);
348 tan1Mask.SetNumEdgeWeights(numEdges);
349 tan1Mask.SetNumFaceWeights(numFaces);
350 tan1Mask.SetFaceWeightsForFaceCenters(false);
351
352 tan1Mask.VertexWeight(0) = 0.0f;
353 for (int i = 0; i < numEdges; ++i) {
354 tan1Mask.EdgeWeight(i) = 0.0f;
355 }
356 for (int i = 0; i < numFaces; ++i) {
357 tan1Mask.FaceWeight(i) = 0.0f;
358 }
359
360 tan1Mask.EdgeWeight(creaseEnds[0]) = 0.5f;
361 tan1Mask.EdgeWeight(creaseEnds[1]) = -0.5f;
362
363 //
364 // Second, the tangent across the interior faces:
365 // Note this is ambigous for an interior vertex. We currently return
366 // the tangent for the surface in the counter-clockwise span between the
367 // leading and trailing edges that form the crease. Given the expected
368 // computation of a surface normal as Tan1 X Tan2, this tangent should be
369 // oriented "inward" from the crease/boundary -- across the surface rather
370 // than outward and away from it.
371 //
372 tan2Mask.SetNumVertexWeights(1);
373 tan2Mask.SetNumEdgeWeights(numEdges);
374 tan2Mask.SetNumFaceWeights(numFaces);
375 tan2Mask.SetFaceWeightsForFaceCenters(false);
376
377 // Prepend weights of 0 preceding the crease:
378 for (int i = 0; i < creaseEnds[0]; ++i) {
379 tan2Mask.EdgeWeight(i) = 0.0f;
380 tan2Mask.FaceWeight(i) = 0.0f;
381 }
382
383 // Assign weights to crease edge and interior points:
384 int interiorEdgeCount = creaseEnds[1] - creaseEnds[0] - 1;
385 if (interiorEdgeCount == 1) {
386 // The regular case -- uniform B-spline cross-tangent:
387
388 tan2Mask.VertexWeight(0) = -4.0f / 6.0f;
389
390 tan2Mask.EdgeWeight(creaseEnds[0]) = -1.0f / 6.0f;
391 tan2Mask.EdgeWeight(creaseEnds[0] + 1) = 4.0f / 6.0f;
392 tan2Mask.EdgeWeight(creaseEnds[1]) = -1.0f / 6.0f;
393
394 tan2Mask.FaceWeight(creaseEnds[0]) = 1.0f / 6.0f;
395 tan2Mask.FaceWeight(creaseEnds[0] + 1) = 1.0f / 6.0f;
396 } else if (interiorEdgeCount > 1) {
397 // The irregular case -- formulae from Biermann et al:
398
399 double k = (double) (interiorEdgeCount + 1);
400 double theta = M_PI / k;
401
402 double cosTheta = std::cos(theta);
403 double sinTheta = std::sin(theta);
404
405 // Loop/Schaefer use a different divisor here (3*k + cos(theta)):
406 double commonDenom = 1.0f / (k * (3.0f + cosTheta));
407 double R = (cosTheta + 1.0f) / sinTheta;
408
409 double vertexWeight = 4.0f * R * (cosTheta - 1.0f);
410 double creaseWeight = -R * (1.0f + 2.0f * cosTheta);
411
412 tan2Mask.VertexWeight(0) = (Weight) (vertexWeight * commonDenom);
413
414 tan2Mask.EdgeWeight(creaseEnds[0]) = (Weight) (creaseWeight * commonDenom);
415 tan2Mask.EdgeWeight(creaseEnds[1]) = (Weight) (creaseWeight * commonDenom);
416
417 tan2Mask.FaceWeight(creaseEnds[0]) = (Weight) (sinTheta * commonDenom);
418
419 double sinThetaI = 0.0f;
420 double sinThetaIplus1 = sinTheta;
421 for (int i = 1; i < k; ++i) {
422 sinThetaI = sinThetaIplus1;
423 sinThetaIplus1 = std::sin((i+1)*theta);
424
425 tan2Mask.EdgeWeight(creaseEnds[0] + i) = (Weight) ((4.0f * sinThetaI) * commonDenom);
426 tan2Mask.FaceWeight(creaseEnds[0] + i) = (Weight) ((sinThetaI + sinThetaIplus1) * commonDenom);
427 }
428 } else {
429 // Special case for a single face -- simple average of boundary edges:
430
431 tan2Mask.VertexWeight(0) = -6.0f;
432
433 tan2Mask.EdgeWeight(creaseEnds[0]) = 3.0f;
434 tan2Mask.EdgeWeight(creaseEnds[1]) = 3.0f;
435
436 tan2Mask.FaceWeight(creaseEnds[0]) = 0.0f;
437 }
438
439 // Append weights of 0 following the crease:
440 for (int i = creaseEnds[1]; i < numFaces; ++i) {
441 tan2Mask.FaceWeight(i) = 0.0f;
442 }
443 for (int i = creaseEnds[1] + 1; i < numEdges; ++i) {
444 tan2Mask.EdgeWeight(i) = 0.0f;
445 }
446 }
447
448 template <>
449 template <typename VERTEX, typename MASK>
450 inline void
451 Scheme<SCHEME_CATMARK>::assignSmoothLimitTangentMasks(VERTEX const& vertex,
452 MASK& tan1Mask, MASK& tan2Mask) const {
453
454 typedef typename MASK::Weight Weight;
455
456 int valence = vertex.GetNumFaces();
457 if (valence == 2) {
458 assignCornerLimitTangentMasks(vertex, tan1Mask, tan2Mask);
459 return;
460 }
461
462 // Compute tan1 initially -- tan2 is simply a rotation:
463 tan1Mask.SetNumVertexWeights(1);
464 tan1Mask.SetNumEdgeWeights(valence);
465 tan1Mask.SetNumFaceWeights(valence);
466 tan1Mask.SetFaceWeightsForFaceCenters(false);
467
468 tan1Mask.VertexWeight(0) = 0.0f;
469
470 if (valence == 4) {
471 tan1Mask.EdgeWeight(0) = 4.0f;
472 tan1Mask.EdgeWeight(1) = 0.0f;
473 tan1Mask.EdgeWeight(2) = -4.0f;
474 tan1Mask.EdgeWeight(3) = 0.0f;
475
476 tan1Mask.FaceWeight(0) = 1.0f;
477 tan1Mask.FaceWeight(1) = -1.0f;
478 tan1Mask.FaceWeight(2) = -1.0f;
479 tan1Mask.FaceWeight(3) = 1.0f;
480 } else {
481 double theta = 2.0f * M_PI / (double)valence;
482
483 double cosTheta = std::cos(theta);
484 double cosHalfTheta = std::cos(theta * 0.5f);
485
486 double lambda = (5.0f / 16.0f) + (1.0f / 16.0f) *
487 (cosTheta + cosHalfTheta * std::sqrt(2.0f * (9.0f + cosTheta)));
488
489 double edgeWeightScale = 4.0f;
490 double faceWeightScale = 1.0f / (4.0f * lambda - 1.0f);
491
492 for (int i = 0; i < valence; ++i) {
493 double cosThetaI = std::cos( i * theta);
494 double cosThetaIplus1 = std::cos((i+1)* theta);
495
496 tan1Mask.EdgeWeight(i) = (Weight) (edgeWeightScale * cosThetaI);
497 tan1Mask.FaceWeight(i) = (Weight) (faceWeightScale * (cosThetaI + cosThetaIplus1));
498 }
499 }
500
501 // Now rotate/copy tan1 weights to tan2:
502 tan2Mask.SetNumVertexWeights(1);
503 tan2Mask.SetNumEdgeWeights(valence);
504 tan2Mask.SetNumFaceWeights(valence);
505 tan2Mask.SetFaceWeightsForFaceCenters(false);
506
507 tan2Mask.VertexWeight(0) = 0.0f;
508 if (valence == 4) {
509 tan2Mask.EdgeWeight(0) = 0.0f;
510 tan2Mask.EdgeWeight(1) = 4.0f;
511 tan2Mask.EdgeWeight(2) = 0.0f;
512 tan2Mask.EdgeWeight(3) = -4.0f;
513
514 tan2Mask.FaceWeight(0) = 1.0f;
515 tan2Mask.FaceWeight(1) = 1.0f;
516 tan2Mask.FaceWeight(2) = -1.0f;
517 tan2Mask.FaceWeight(3) = -1.0f;
518 } else {
519 tan2Mask.EdgeWeight(0) = tan1Mask.EdgeWeight(valence-1);
520 tan2Mask.FaceWeight(0) = tan1Mask.FaceWeight(valence-1);
521 for (int i = 1; i < valence; ++i) {
522 tan2Mask.EdgeWeight(i) = tan1Mask.EdgeWeight(i-1);
523 tan2Mask.FaceWeight(i) = tan1Mask.FaceWeight(i-1);
524 }
525 }
526 }
527
528 } // end namespace sdc
529
530 } // end namespace OPENSUBDIV_VERSION
531 using namespace OPENSUBDIV_VERSION;
532 } // end namespace OpenSubdiv
533
534 #endif /* OPENSUBDIV3_SDC_CATMARK_SCHEME_H */
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::GetRegularVertexValence
static int GetRegularVertexValence()
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignCreaseLimitMask
void assignCreaseLimitMask(VERTEX const &vertex, MASK &pos, int const creaseEnds[2]) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignCreaseLimitTangentMasks
void assignCreaseLimitTangentMasks(VERTEX const &vertex, MASK &tan1, MASK &tan2, int const creaseEnds[2]) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignCreaseMaskForVertex
void assignCreaseMaskForVertex(VERTEX const &edge, MASK &mask, int const creaseEnds[2]) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::GetTopologicalSplitType
static Split GetTopologicalSplitType()
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::GetRegularFaceSize
static int GetRegularFaceSize()
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignSmoothLimitTangentMasks
void assignSmoothLimitTangentMasks(VERTEX const &vertex, MASK &tan1, MASK &tan2) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Split
Split
Enumerated type for all face splitting scheme.
Definition: types.h:47
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignSmoothMaskForVertex
void assignSmoothMaskForVertex(VERTEX const &edge, MASK &mask) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::GetLocalNeighborhoodSize
static int GetLocalNeighborhoodSize()
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignSmoothLimitMask
void assignSmoothLimitMask(VERTEX const &vertex, MASK &pos) const
OpenSubdiv
Definition: error.h:30
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::SPLIT_TO_QUADS
Used by Catmark and Bilinear.
Definition: types.h:48
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignCornerLimitMask
void assignCornerLimitMask(VERTEX const &vertex, MASK &pos) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignCornerLimitTangentMasks
void assignCornerLimitTangentMasks(VERTEX const &vertex, MASK &tan1, MASK &tan2) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme::assignSmoothMaskForEdge
void assignSmoothMaskForEdge(EDGE const &edge, MASK &mask) const
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Options::TRI_SUB_SMOOTH
"smooth triangle" weights (Catmark scheme only)
Definition: options.h:72