OpenSubdiv
Loading...
Searching...
No Matches
primvarRefiner.h
Go to the documentation of this file.
1//
2// Copyright 2015 DreamWorks Animation LLC.
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://opensubdiv.org/license.
6//
7#ifndef OPENSUBDIV3_FAR_PRIMVAR_REFINER_H
8#define OPENSUBDIV3_FAR_PRIMVAR_REFINER_H
9
10#include "../version.h"
11
12#include "../sdc/types.h"
13#include "../sdc/options.h"
16#include "../sdc/loopScheme.h"
17#include "../vtr/level.h"
18#include "../vtr/fvarLevel.h"
19#include "../vtr/refinement.h"
21#include "../vtr/stackBuffer.h"
23#include "../far/types.h"
24#include "../far/error.h"
27
28#include <cassert>
29
30namespace OpenSubdiv {
31namespace OPENSUBDIV_VERSION {
32
33namespace Far {
34
38template <typename REAL>
39class PrimvarRefinerReal {
40
41public:
42 PrimvarRefinerReal(TopologyRefiner const & refiner) : _refiner(refiner) { }
44
45 TopologyRefiner const & GetTopologyRefiner() const { return _refiner; }
46
48
83
96 template <class T, class U> void Interpolate(int level, T const & src, U & dst) const;
97
113 template <class T, class U> void InterpolateVarying(int level, T const & src, U & dst) const;
114
131 template <class T, class U> void InterpolateFaceUniform(int level, T const & src, U & dst) const;
132
144 template <class T, class U> void InterpolateFaceVarying(int level, T const & src, U & dst, int channel = 0) const;
145
146
158 template <class T, class U> void Limit(T const & src, U & dstPos) const;
159
160 template <class T, class U, class U1, class U2>
161 void Limit(T const & src, U & dstPos, U1 & dstTan1, U2 & dstTan2) const;
162
163 template <class T, class U> void LimitFaceVarying(T const & src, U & dst, int channel = 0) const;
164
166
167private:
168 typedef REAL Weight;
169
170 // Non-copyable:
171 PrimvarRefinerReal(PrimvarRefinerReal const & src) : _refiner(src._refiner) { }
172 PrimvarRefinerReal & operator=(PrimvarRefinerReal const &) { return *this; }
173
174 template <Sdc::SchemeType SCHEME, class T, class U> void interpFromFaces(int, T const &, U &) const;
175 template <Sdc::SchemeType SCHEME, class T, class U> void interpFromEdges(int, T const &, U &) const;
176 template <Sdc::SchemeType SCHEME, class T, class U> void interpFromVerts(int, T const &, U &) const;
177
178 template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromFaces(int, T const &, U &, int) const;
179 template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromEdges(int, T const &, U &, int) const;
180 template <Sdc::SchemeType SCHEME, class T, class U> void interpFVarFromVerts(int, T const &, U &, int) const;
181
182 template <Sdc::SchemeType SCHEME, class T, class U, class U1, class U2>
183 void limit(T const & src, U & pos, U1 * tan1, U2 * tan2) const;
184
185 template <Sdc::SchemeType SCHEME, class T, class U>
186 void limitFVar(T const & src, U & dst, int channel) const;
187
188private:
189 TopologyRefiner const & _refiner;
190
191private:
192 //
193 // Local class to fulfill interface for <typename MASK> in the Scheme mask queries:
194 //
195 class Mask {
196 public:
197 typedef REAL Weight; // Also part of the expected interface
198
199 public:
200 Mask(Weight* v, Weight* e, Weight* f) :
201 _vertWeights(v), _edgeWeights(e), _faceWeights(f),
202 _vertCount(0), _edgeCount(0), _faceCount(0),
203 _faceWeightsForFaceCenters(false)
204 { }
205
206 ~Mask() { }
207
208 public: // Generic interface expected of <typename MASK>:
209 int GetNumVertexWeights() const { return _vertCount; }
210 int GetNumEdgeWeights() const { return _edgeCount; }
211 int GetNumFaceWeights() const { return _faceCount; }
212
213 void SetNumVertexWeights(int count) { _vertCount = count; }
214 void SetNumEdgeWeights( int count) { _edgeCount = count; }
215 void SetNumFaceWeights( int count) { _faceCount = count; }
216
217 Weight const& VertexWeight(int index) const { return _vertWeights[index]; }
218 Weight const& EdgeWeight( int index) const { return _edgeWeights[index]; }
219 Weight const& FaceWeight( int index) const { return _faceWeights[index]; }
220
221 Weight& VertexWeight(int index) { return _vertWeights[index]; }
222 Weight& EdgeWeight( int index) { return _edgeWeights[index]; }
223 Weight& FaceWeight( int index) { return _faceWeights[index]; }
224
225 bool AreFaceWeightsForFaceCenters() const { return _faceWeightsForFaceCenters; }
226 void SetFaceWeightsForFaceCenters(bool on) { _faceWeightsForFaceCenters = on; }
227
228 private:
229 Weight* _vertWeights;
230 Weight* _edgeWeights;
231 Weight* _faceWeights;
232
233 int _vertCount;
234 int _edgeCount;
235 int _faceCount;
236
237 bool _faceWeightsForFaceCenters;
238 };
239};
240
241
242//
243// Public entry points to the methods. Queries of the scheme type and its
244// use as a template parameter in subsequent implementation will be factored
245// out of a later release:
246//
247template <typename REAL>
248template <class T, class U>
249inline void
250PrimvarRefinerReal<REAL>::Interpolate(int level, T const & src, U & dst) const {
251
252 assert(level>0 && level<=(int)_refiner._refinements.size());
253
254 switch (_refiner._subdivType) {
256 interpFromFaces<Sdc::SCHEME_CATMARK>(level, src, dst);
257 interpFromEdges<Sdc::SCHEME_CATMARK>(level, src, dst);
258 interpFromVerts<Sdc::SCHEME_CATMARK>(level, src, dst);
259 break;
260 case Sdc::SCHEME_LOOP:
261 interpFromFaces<Sdc::SCHEME_LOOP>(level, src, dst);
262 interpFromEdges<Sdc::SCHEME_LOOP>(level, src, dst);
263 interpFromVerts<Sdc::SCHEME_LOOP>(level, src, dst);
264 break;
266 interpFromFaces<Sdc::SCHEME_BILINEAR>(level, src, dst);
267 interpFromEdges<Sdc::SCHEME_BILINEAR>(level, src, dst);
268 interpFromVerts<Sdc::SCHEME_BILINEAR>(level, src, dst);
269 break;
270 }
271}
272
273template <typename REAL>
274template <class T, class U>
275inline void
276PrimvarRefinerReal<REAL>::InterpolateFaceVarying(int level, T const & src, U & dst, int channel) const {
277
278 assert(level>0 && level<=(int)_refiner._refinements.size());
279
280 switch (_refiner._subdivType) {
282 interpFVarFromFaces<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
283 interpFVarFromEdges<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
284 interpFVarFromVerts<Sdc::SCHEME_CATMARK>(level, src, dst, channel);
285 break;
286 case Sdc::SCHEME_LOOP:
287 interpFVarFromFaces<Sdc::SCHEME_LOOP>(level, src, dst, channel);
288 interpFVarFromEdges<Sdc::SCHEME_LOOP>(level, src, dst, channel);
289 interpFVarFromVerts<Sdc::SCHEME_LOOP>(level, src, dst, channel);
290 break;
292 interpFVarFromFaces<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
293 interpFVarFromEdges<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
294 interpFVarFromVerts<Sdc::SCHEME_BILINEAR>(level, src, dst, channel);
295 break;
296 }
297}
298
299template <typename REAL>
300template <class T, class U>
301inline void
302PrimvarRefinerReal<REAL>::Limit(T const & src, U & dst) const {
303
304 if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
306 "Failure in PrimvarRefiner::Limit() -- "
307 "last level of refinement does not include full topology.");
308 return;
309 }
310
311 switch (_refiner._subdivType) {
313 limit<Sdc::SCHEME_CATMARK>(src, dst, (U*)0, (U*)0);
314 break;
315 case Sdc::SCHEME_LOOP:
316 limit<Sdc::SCHEME_LOOP>(src, dst, (U*)0, (U*)0);
317 break;
319 limit<Sdc::SCHEME_BILINEAR>(src, dst, (U*)0, (U*)0);
320 break;
321 }
322}
323
324template <typename REAL>
325template <class T, class U, class U1, class U2>
326inline void
327PrimvarRefinerReal<REAL>::Limit(T const & src, U & dstPos, U1 & dstTan1, U2 & dstTan2) const {
328
329 if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
331 "Failure in PrimvarRefiner::Limit() -- "
332 "last level of refinement does not include full topology.");
333 return;
334 }
335
336 switch (_refiner._subdivType) {
338 limit<Sdc::SCHEME_CATMARK>(src, dstPos, &dstTan1, &dstTan2);
339 break;
340 case Sdc::SCHEME_LOOP:
341 limit<Sdc::SCHEME_LOOP>(src, dstPos, &dstTan1, &dstTan2);
342 break;
344 limit<Sdc::SCHEME_BILINEAR>(src, dstPos, &dstTan1, &dstTan2);
345 break;
346 }
347}
348
349template <typename REAL>
350template <class T, class U>
351inline void
352PrimvarRefinerReal<REAL>::LimitFaceVarying(T const & src, U & dst, int channel) const {
353
354 if (_refiner.getLevel(_refiner.GetMaxLevel()).getNumVertexEdgesTotal() == 0) {
356 "Failure in PrimvarRefiner::LimitFaceVarying() -- "
357 "last level of refinement does not include full topology.");
358 return;
359 }
360
361 switch (_refiner._subdivType) {
363 limitFVar<Sdc::SCHEME_CATMARK>(src, dst, channel);
364 break;
365 case Sdc::SCHEME_LOOP:
366 limitFVar<Sdc::SCHEME_LOOP>(src, dst, channel);
367 break;
369 limitFVar<Sdc::SCHEME_BILINEAR>(src, dst, channel);
370 break;
371 }
372}
373
374template <typename REAL>
375template <class T, class U>
376inline void
377PrimvarRefinerReal<REAL>::InterpolateFaceUniform(int level, T const & src, U & dst) const {
378
379 assert(level>0 && level<=(int)_refiner._refinements.size());
380
381 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
382 Vtr::internal::Level const & child = refinement.child();
383
384 for (int cFace = 0; cFace < child.getNumFaces(); ++cFace) {
385
386 Vtr::Index pFace = refinement.getChildFaceParentFace(cFace);
387
388 dst[cFace] = src[pFace];
389 }
390}
391
392template <typename REAL>
393template <class T, class U>
394inline void
395PrimvarRefinerReal<REAL>::InterpolateVarying(int level, T const & src, U & dst) const {
396
397 assert(level>0 && level<=(int)_refiner._refinements.size());
398
399 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
400 Vtr::internal::Level const & parent = refinement.parent();
401
402 //
403 // Group values to interpolate based on origin -- note that there may
404 // be none originating from faces:
405 //
406 if (refinement.getNumChildVerticesFromFaces() > 0) {
407
408 for (int face = 0; face < parent.getNumFaces(); ++face) {
409
410 Vtr::Index cVert = refinement.getFaceChildVertex(face);
411 if (Vtr::IndexIsValid(cVert)) {
412
413 // Apply the weights to the parent face's vertices:
414 ConstIndexArray fVerts = parent.getFaceVertices(face);
415
416 Weight fVaryingWeight = 1.0f / (Weight) fVerts.size();
417
418 dst[cVert].Clear();
419 for (int i = 0; i < fVerts.size(); ++i) {
420 dst[cVert].AddWithWeight(src[fVerts[i]], fVaryingWeight);
421 }
422 }
423 }
424 }
425 for (int edge = 0; edge < parent.getNumEdges(); ++edge) {
426
427 Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
428 if (Vtr::IndexIsValid(cVert)) {
429
430 // Apply the weights to the parent edges's vertices
431 ConstIndexArray eVerts = parent.getEdgeVertices(edge);
432
433 dst[cVert].Clear();
434 dst[cVert].AddWithWeight(src[eVerts[0]], 0.5f);
435 dst[cVert].AddWithWeight(src[eVerts[1]], 0.5f);
436 }
437 }
438 for (int vert = 0; vert < parent.getNumVertices(); ++vert) {
439
440 Vtr::Index cVert = refinement.getVertexChildVertex(vert);
441 if (Vtr::IndexIsValid(cVert)) {
442
443 // Essentially copy the parent vertex:
444 dst[cVert].Clear();
445 dst[cVert].AddWithWeight(src[vert], 1.0f);
446 }
447 }
448}
449
450
451//
452// Internal implementation methods -- grouping vertices to be interpolated
453// based on the type of parent component from which they originated:
454//
455template <typename REAL>
456template <Sdc::SchemeType SCHEME, class T, class U>
457inline void
458PrimvarRefinerReal<REAL>::interpFromFaces(int level, T const & src, U & dst) const {
459
460 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
461 Vtr::internal::Level const & parent = refinement.parent();
462
463 if (refinement.getNumChildVerticesFromFaces() == 0) return;
464
465 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
466
467 Vtr::internal::StackBuffer<Weight,16> fVertWeights(parent.getMaxValence());
468
469 for (int face = 0; face < parent.getNumFaces(); ++face) {
470
471 Vtr::Index cVert = refinement.getFaceChildVertex(face);
472 if (!Vtr::IndexIsValid(cVert))
473 continue;
474
475 // Declare and compute mask weights for this vertex relative to its parent face:
476 ConstIndexArray fVerts = parent.getFaceVertices(face);
477
478 Mask fMask(fVertWeights, 0, 0);
479 Vtr::internal::FaceInterface fHood(fVerts.size());
480
481 scheme.ComputeFaceVertexMask(fHood, fMask);
482
483 // Apply the weights to the parent face's vertices:
484 dst[cVert].Clear();
485
486 for (int i = 0; i < fVerts.size(); ++i) {
487
488 dst[cVert].AddWithWeight(src[fVerts[i]], fVertWeights[i]);
489 }
490 }
491}
492
493template <typename REAL>
494template <Sdc::SchemeType SCHEME, class T, class U>
495inline void
496PrimvarRefinerReal<REAL>::interpFromEdges(int level, T const & src, U & dst) const {
497
498 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
499 Vtr::internal::Level const & parent = refinement.parent();
500 Vtr::internal::Level const & child = refinement.child();
501
502 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
503
504 Vtr::internal::EdgeInterface eHood(parent);
505
506 Weight eVertWeights[2];
507 Vtr::internal::StackBuffer<Weight,8> eFaceWeights(parent.getMaxEdgeFaces());
508
509 for (int edge = 0; edge < parent.getNumEdges(); ++edge) {
510
511 Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
512 if (!Vtr::IndexIsValid(cVert))
513 continue;
514
515 // Declare and compute mask weights for this vertex relative to its parent edge:
516 ConstIndexArray eVerts = parent.getEdgeVertices(edge),
517 eFaces = parent.getEdgeFaces(edge);
518
519 Mask eMask(eVertWeights, 0, eFaceWeights);
520
521 eHood.SetIndex(edge);
522
523 Sdc::Crease::Rule pRule = (parent.getEdgeSharpness(edge) > 0.0f) ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH;
524 Sdc::Crease::Rule cRule = child.getVertexRule(cVert);
525
526 scheme.ComputeEdgeVertexMask(eHood, eMask, pRule, cRule);
527
528 // Apply the weights to the parent edges's vertices and (if applicable) to
529 // the child vertices of its incident faces:
530 dst[cVert].Clear();
531 dst[cVert].AddWithWeight(src[eVerts[0]], eVertWeights[0]);
532 dst[cVert].AddWithWeight(src[eVerts[1]], eVertWeights[1]);
533
534 if (eMask.GetNumFaceWeights() > 0) {
535
536 for (int i = 0; i < eFaces.size(); ++i) {
537
538 if (eMask.AreFaceWeightsForFaceCenters()) {
539 assert(refinement.getNumChildVerticesFromFaces() > 0);
540 Vtr::Index cVertOfFace = refinement.getFaceChildVertex(eFaces[i]);
541
542 assert(Vtr::IndexIsValid(cVertOfFace));
543 dst[cVert].AddWithWeight(dst[cVertOfFace], eFaceWeights[i]);
544 } else {
545 Vtr::Index pFace = eFaces[i];
546 ConstIndexArray pFaceEdges = parent.getFaceEdges(pFace),
547 pFaceVerts = parent.getFaceVertices(pFace);
548
549 int eInFace = 0;
550 for ( ; pFaceEdges[eInFace] != edge; ++eInFace ) ;
551
552 int vInFace = eInFace + 2;
553 if (vInFace >= pFaceVerts.size()) vInFace -= pFaceVerts.size();
554
555 Vtr::Index pVertNext = pFaceVerts[vInFace];
556 dst[cVert].AddWithWeight(src[pVertNext], eFaceWeights[i]);
557 }
558 }
559 }
560 }
561}
562
563template <typename REAL>
564template <Sdc::SchemeType SCHEME, class T, class U>
565inline void
566PrimvarRefinerReal<REAL>::interpFromVerts(int level, T const & src, U & dst) const {
567
568 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
569 Vtr::internal::Level const & parent = refinement.parent();
570 Vtr::internal::Level const & child = refinement.child();
571
572 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
573
574 Vtr::internal::VertexInterface vHood(parent, child);
575
576 Vtr::internal::StackBuffer<Weight,32> weightBuffer(2*parent.getMaxValence());
577
578 for (int vert = 0; vert < parent.getNumVertices(); ++vert) {
579
580 Vtr::Index cVert = refinement.getVertexChildVertex(vert);
581 if (!Vtr::IndexIsValid(cVert))
582 continue;
583
584 // Declare and compute mask weights for this vertex relative to its parent edge:
585 ConstIndexArray vEdges = parent.getVertexEdges(vert),
586 vFaces = parent.getVertexFaces(vert);
587
588 Weight vVertWeight,
589 * vEdgeWeights = weightBuffer,
590 * vFaceWeights = vEdgeWeights + vEdges.size();
591
592 Mask vMask(&vVertWeight, vEdgeWeights, vFaceWeights);
593
594 vHood.SetIndex(vert, cVert);
595
596 Sdc::Crease::Rule pRule = parent.getVertexRule(vert);
597 Sdc::Crease::Rule cRule = child.getVertexRule(cVert);
598
599 scheme.ComputeVertexVertexMask(vHood, vMask, pRule, cRule);
600
601 // Apply the weights to the parent vertex, the vertices opposite its incident
602 // edges, and the child vertices of its incident faces:
603 //
604 // In order to improve numerical precision, it's better to apply smaller weights
605 // first, so begin with the face-weights followed by the edge-weights and the
606 // vertex weight last.
607 dst[cVert].Clear();
608
609 if (vMask.GetNumFaceWeights() > 0) {
610 assert(vMask.AreFaceWeightsForFaceCenters());
611
612 for (int i = 0; i < vFaces.size(); ++i) {
613
614 Vtr::Index cVertOfFace = refinement.getFaceChildVertex(vFaces[i]);
615 assert(Vtr::IndexIsValid(cVertOfFace));
616 dst[cVert].AddWithWeight(dst[cVertOfFace], vFaceWeights[i]);
617 }
618 }
619 if (vMask.GetNumEdgeWeights() > 0) {
620
621 for (int i = 0; i < vEdges.size(); ++i) {
622
623 ConstIndexArray eVerts = parent.getEdgeVertices(vEdges[i]);
624 Vtr::Index pVertOppositeEdge = (eVerts[0] == vert) ? eVerts[1] : eVerts[0];
625
626 dst[cVert].AddWithWeight(src[pVertOppositeEdge], vEdgeWeights[i]);
627 }
628 }
629 dst[cVert].AddWithWeight(src[vert], vVertWeight);
630 }
631}
632
633
634//
635// Internal face-varying implementation details:
636//
637template <typename REAL>
638template <Sdc::SchemeType SCHEME, class T, class U>
639inline void
640PrimvarRefinerReal<REAL>::interpFVarFromFaces(int level, T const & src, U & dst, int channel) const {
641
642 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
643
644 if (refinement.getNumChildVerticesFromFaces() == 0) return;
645
646 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
647
648 Vtr::internal::Level const & parentLevel = refinement.parent();
649 Vtr::internal::Level const & childLevel = refinement.child();
650
651 Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
652 Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
653
654 Vtr::internal::StackBuffer<Weight,16> fValueWeights(parentLevel.getMaxValence());
655
656 for (int face = 0; face < parentLevel.getNumFaces(); ++face) {
657
658 Vtr::Index cVert = refinement.getFaceChildVertex(face);
659 if (!Vtr::IndexIsValid(cVert))
660 continue;
661
662 Vtr::Index cVertValue = childFVar.getVertexValueOffset(cVert);
663
664 // The only difference for face-varying here is that we get the values associated
665 // with each face-vertex directly from the FVarLevel, rather than using the parent
666 // face-vertices directly. If any face-vertex has any sibling values, then we may
667 // get the wrong one using the face-vertex index directly.
668
669 // Declare and compute mask weights for this vertex relative to its parent face:
670 ConstIndexArray fValues = parentFVar.getFaceValues(face);
671
672 Mask fMask(fValueWeights, 0, 0);
673 Vtr::internal::FaceInterface fHood(fValues.size());
674
675 scheme.ComputeFaceVertexMask(fHood, fMask);
676
677 // Apply the weights to the parent face's vertices:
678 dst[cVertValue].Clear();
679
680 for (int i = 0; i < fValues.size(); ++i) {
681 dst[cVertValue].AddWithWeight(src[fValues[i]], fValueWeights[i]);
682 }
683 }
684}
685
686template <typename REAL>
687template <Sdc::SchemeType SCHEME, class T, class U>
688inline void
689PrimvarRefinerReal<REAL>::interpFVarFromEdges(int level, T const & src, U & dst, int channel) const {
690
691 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
692
693 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
694
695 Vtr::internal::Level const & parentLevel = refinement.parent();
696 Vtr::internal::Level const & childLevel = refinement.child();
697
698 Vtr::internal::FVarRefinement const & refineFVar = refinement.getFVarRefinement(channel);
699 Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
700 Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
701
702 //
703 // Allocate and initialize (if linearly interpolated) interpolation weights for
704 // the edge mask:
705 //
706 Weight eVertWeights[2];
707 Vtr::internal::StackBuffer<Weight,8> eFaceWeights(parentLevel.getMaxEdgeFaces());
708
709 Mask eMask(eVertWeights, 0, eFaceWeights);
710
711 bool isLinearFVar = parentFVar.isLinear() || (_refiner._subdivType == Sdc::SCHEME_BILINEAR);
712 if (isLinearFVar) {
713 eMask.SetNumVertexWeights(2);
714 eMask.SetNumEdgeWeights(0);
715 eMask.SetNumFaceWeights(0);
716
717 eVertWeights[0] = 0.5f;
718 eVertWeights[1] = 0.5f;
719 }
720
721 Vtr::internal::EdgeInterface eHood(parentLevel);
722
723 for (int edge = 0; edge < parentLevel.getNumEdges(); ++edge) {
724
725 Vtr::Index cVert = refinement.getEdgeChildVertex(edge);
726 if (!Vtr::IndexIsValid(cVert))
727 continue;
728
729 ConstIndexArray cVertValues = childFVar.getVertexValues(cVert);
730
731 bool fvarEdgeVertMatchesVertex = childFVar.valueTopologyMatches(cVertValues[0]);
732 if (fvarEdgeVertMatchesVertex) {
733 //
734 // If smoothly interpolated, compute new weights for the edge mask:
735 //
736 if (!isLinearFVar) {
737 eHood.SetIndex(edge);
738
739 Sdc::Crease::Rule pRule = (parentLevel.getEdgeSharpness(edge) > 0.0f)
741 Sdc::Crease::Rule cRule = childLevel.getVertexRule(cVert);
742
743 scheme.ComputeEdgeVertexMask(eHood, eMask, pRule, cRule);
744 }
745
746 // Apply the weights to the parent edge's vertices and (if applicable) to
747 // the child vertices of its incident faces:
748 //
749 // Even though the face-varying topology matches the vertex topology, we need
750 // to be careful here when getting values corresponding to the two end-vertices.
751 // While the edge may be continuous, the vertices at their ends may have
752 // discontinuities elsewhere in their neighborhood (i.e. on the "other side"
753 // of the end-vertex) and so have sibling values associated with them. In most
754 // cases the topology for an end-vertex will match and we can use it directly,
755 // but we must still check and retrieve as needed.
756 //
757 // Indices for values corresponding to face-vertices are guaranteed to match,
758 // so we can use the child-vertex indices directly.
759 //
760 // And by "directly", we always use getVertexValue(vertexIndex) to reference
761 // values in the "src" to account for the possible indirection that may exist at
762 // level 0 -- where there may be fewer values than vertices and an additional
763 // indirection is necessary. We can use a vertex index directly for "dst" when
764 // it matches.
765 //
766 Vtr::Index eVertValues[2];
767
768 parentFVar.getEdgeFaceValues(edge, 0, eVertValues);
769
770 Index cVertValue = cVertValues[0];
771
772 dst[cVertValue].Clear();
773 dst[cVertValue].AddWithWeight(src[eVertValues[0]], eVertWeights[0]);
774 dst[cVertValue].AddWithWeight(src[eVertValues[1]], eVertWeights[1]);
775
776 if (eMask.GetNumFaceWeights() > 0) {
777
778 ConstIndexArray eFaces = parentLevel.getEdgeFaces(edge);
779
780 for (int i = 0; i < eFaces.size(); ++i) {
781 if (eMask.AreFaceWeightsForFaceCenters()) {
782
783 Vtr::Index cVertOfFace = refinement.getFaceChildVertex(eFaces[i]);
784 assert(Vtr::IndexIsValid(cVertOfFace));
785
786 Vtr::Index cValueOfFace = childFVar.getVertexValueOffset(cVertOfFace);
787 dst[cVertValue].AddWithWeight(dst[cValueOfFace], eFaceWeights[i]);
788 } else {
789 Vtr::Index pFace = eFaces[i];
790 ConstIndexArray pFaceEdges = parentLevel.getFaceEdges(pFace),
791 pFaceVerts = parentLevel.getFaceVertices(pFace);
792
793 int eInFace = 0;
794 for ( ; pFaceEdges[eInFace] != edge; ++eInFace ) ;
795
796 // Edge "i" spans vertices [i,i+1] so we want i+2...
797 int vInFace = eInFace + 2;
798 if (vInFace >= pFaceVerts.size()) vInFace -= pFaceVerts.size();
799
800 Vtr::Index pValueNext = parentFVar.getFaceValues(pFace)[vInFace];
801 dst[cVertValue].AddWithWeight(src[pValueNext], eFaceWeights[i]);
802 }
803 }
804 }
805 } else {
806 //
807 // Mismatched edge-verts should just be linearly interpolated between the pairs of
808 // values for each sibling of the child edge-vertex -- the question is: which face
809 // holds that pair of values for a given sibling?
810 //
811 // In the manifold case, the sibling and edge-face indices will correspond. We
812 // will eventually need to update this to account for > 3 incident faces.
813 //
814 for (int i = 0; i < cVertValues.size(); ++i) {
815 Vtr::Index eVertValues[2];
816 int eFaceIndex = refineFVar.getChildValueParentSource(cVert, i);
817 assert(eFaceIndex == i);
818
819 parentFVar.getEdgeFaceValues(edge, eFaceIndex, eVertValues);
820
821 Index cVertValue = cVertValues[i];
822
823 dst[cVertValue].Clear();
824 dst[cVertValue].AddWithWeight(src[eVertValues[0]], 0.5);
825 dst[cVertValue].AddWithWeight(src[eVertValues[1]], 0.5);
826 }
827 }
828 }
829}
830
831template <typename REAL>
832template <Sdc::SchemeType SCHEME, class T, class U>
833inline void
834PrimvarRefinerReal<REAL>::interpFVarFromVerts(int level, T const & src, U & dst, int channel) const {
835
836 Vtr::internal::Refinement const & refinement = _refiner.getRefinement(level-1);
837
838 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
839
840 Vtr::internal::Level const & parentLevel = refinement.parent();
841 Vtr::internal::Level const & childLevel = refinement.child();
842
843 Vtr::internal::FVarRefinement const & refineFVar = refinement.getFVarRefinement(channel);
844 Vtr::internal::FVarLevel const & parentFVar = parentLevel.getFVarLevel(channel);
845 Vtr::internal::FVarLevel const & childFVar = childLevel.getFVarLevel(channel);
846
847 bool isLinearFVar = parentFVar.isLinear() || (_refiner._subdivType == Sdc::SCHEME_BILINEAR);
848
849 Vtr::internal::StackBuffer<Weight,32> weightBuffer(2*parentLevel.getMaxValence());
850
851 Vtr::internal::StackBuffer<Vtr::Index,16> vEdgeValues(parentLevel.getMaxValence());
852
853 Vtr::internal::VertexInterface vHood(parentLevel, childLevel);
854
855 for (int vert = 0; vert < parentLevel.getNumVertices(); ++vert) {
856
857 Vtr::Index cVert = refinement.getVertexChildVertex(vert);
858 if (!Vtr::IndexIsValid(cVert))
859 continue;
860
861 ConstIndexArray pVertValues = parentFVar.getVertexValues(vert),
862 cVertValues = childFVar.getVertexValues(cVert);
863
864 bool fvarVertVertMatchesVertex = childFVar.valueTopologyMatches(cVertValues[0]);
865 if (isLinearFVar && fvarVertVertMatchesVertex) {
866 dst[cVertValues[0]].Clear();
867 dst[cVertValues[0]].AddWithWeight(src[pVertValues[0]], 1.0f);
868 continue;
869 }
870
871 if (fvarVertVertMatchesVertex) {
872 //
873 // Declare and compute mask weights for this vertex relative to its parent edge:
874 //
875 // (We really need to encapsulate this somewhere else for use here and in the
876 // general case)
877 //
878 ConstIndexArray vEdges = parentLevel.getVertexEdges(vert);
879
880 Weight vVertWeight;
881 Weight * vEdgeWeights = weightBuffer;
882 Weight * vFaceWeights = vEdgeWeights + vEdges.size();
883
884 Mask vMask(&vVertWeight, vEdgeWeights, vFaceWeights);
885
886 vHood.SetIndex(vert, cVert);
887
888 Sdc::Crease::Rule pRule = parentLevel.getVertexRule(vert);
889 Sdc::Crease::Rule cRule = childLevel.getVertexRule(cVert);
890
891 scheme.ComputeVertexVertexMask(vHood, vMask, pRule, cRule);
892
893 // Apply the weights to the parent vertex, the vertices opposite its incident
894 // edges, and the child vertices of its incident faces:
895 //
896 // Even though the face-varying topology matches the vertex topology, we need
897 // to be careful here when getting values corresponding to vertices at the
898 // ends of edges. While the edge may be continuous, the end vertex may have
899 // discontinuities elsewhere in their neighborhood (i.e. on the "other side"
900 // of the end-vertex) and so have sibling values associated with them. In most
901 // cases the topology for an end-vertex will match and we can use it directly,
902 // but we must still check and retrieve as needed.
903 //
904 // Indices for values corresponding to face-vertices are guaranteed to match,
905 // so we can use the child-vertex indices directly.
906 //
907 // And by "directly", we always use getVertexValue(vertexIndex) to reference
908 // values in the "src" to account for the possible indirection that may exist at
909 // level 0 -- where there may be fewer values than vertices and an additional
910 // indirection is necessary. We can use a vertex index directly for "dst" when
911 // it matches.
912 //
913 // As with applying the mask to vertex data, in order to improve numerical
914 // precision, it's better to apply smaller weights first, so begin with the
915 // face-weights followed by the edge-weights and the vertex weight last.
916 //
917 Vtr::Index pVertValue = pVertValues[0];
918 Vtr::Index cVertValue = cVertValues[0];
919
920 dst[cVertValue].Clear();
921 if (vMask.GetNumFaceWeights() > 0) {
922 assert(vMask.AreFaceWeightsForFaceCenters());
923
924 ConstIndexArray vFaces = parentLevel.getVertexFaces(vert);
925
926 for (int i = 0; i < vFaces.size(); ++i) {
927
928 Vtr::Index cVertOfFace = refinement.getFaceChildVertex(vFaces[i]);
929 assert(Vtr::IndexIsValid(cVertOfFace));
930
931 Vtr::Index cValueOfFace = childFVar.getVertexValueOffset(cVertOfFace);
932 dst[cVertValue].AddWithWeight(dst[cValueOfFace], vFaceWeights[i]);
933 }
934 }
935 if (vMask.GetNumEdgeWeights() > 0) {
936
937 parentFVar.getVertexEdgeValues(vert, vEdgeValues);
938
939 for (int i = 0; i < vEdges.size(); ++i) {
940 dst[cVertValue].AddWithWeight(src[vEdgeValues[i]], vEdgeWeights[i]);
941 }
942 }
943 dst[cVertValue].AddWithWeight(src[pVertValue], vVertWeight);
944 } else {
945 //
946 // Each FVar value associated with a vertex will be either a corner or a crease,
947 // or potentially in transition from corner to crease:
948 // - if the CHILD is a corner, there can be no transition so we have a corner
949 // - otherwise if the PARENT is a crease, both will be creases (no transition)
950 // - otherwise the parent must be a corner and the child a crease (transition)
951 //
952 Vtr::internal::FVarLevel::ConstValueTagArray pValueTags = parentFVar.getVertexValueTags(vert);
953 Vtr::internal::FVarLevel::ConstValueTagArray cValueTags = childFVar.getVertexValueTags(cVert);
954
955 for (int cSiblingIndex = 0; cSiblingIndex < cVertValues.size(); ++cSiblingIndex) {
956 int pSiblingIndex = refineFVar.getChildValueParentSource(cVert, cSiblingIndex);
957 assert(pSiblingIndex == cSiblingIndex);
958
959 typedef Vtr::internal::FVarLevel::Sibling SiblingIntType;
960
961 SiblingIntType cSibling = (SiblingIntType) cSiblingIndex;
962 SiblingIntType pSibling = (SiblingIntType) pSiblingIndex;
963
964 Vtr::Index pVertValue = pVertValues[pSibling];
965 Vtr::Index cVertValue = cVertValues[cSibling];
966
967 dst[cVertValue].Clear();
968 if (isLinearFVar || cValueTags[cSibling].isCorner()) {
969 dst[cVertValue].AddWithWeight(src[pVertValue], 1.0f);
970 } else {
971 //
972 // We have either a crease or a transition from corner to crease -- in
973 // either case, we need the end values for the full/fractional crease:
974 //
975 Index pEndValues[2];
976 parentFVar.getVertexCreaseEndValues(vert, pSibling, pEndValues);
977
978 Weight vWeight = 0.75f;
979 Weight eWeight = 0.125f;
980
981 //
982 // If semi-sharp we need to apply fractional weighting -- if made sharp because
983 // of the other sibling (dependent-sharp) use the fractional weight from that
984 // other sibling (should only occur when there are 2):
985 //
986 if (pValueTags[pSibling].isSemiSharp()) {
987 Weight wCorner = pValueTags[pSibling].isDepSharp()
988 ? refineFVar.getFractionalWeight(vert, !pSibling, cVert, !cSibling)
989 : refineFVar.getFractionalWeight(vert, pSibling, cVert, cSibling);
990 Weight wCrease = 1.0f - wCorner;
991
992 vWeight = wCrease * 0.75f + wCorner;
993 eWeight = wCrease * 0.125f;
994 }
995 dst[cVertValue].AddWithWeight(src[pEndValues[0]], eWeight);
996 dst[cVertValue].AddWithWeight(src[pEndValues[1]], eWeight);
997 dst[cVertValue].AddWithWeight(src[pVertValue], vWeight);
998 }
999 }
1000 }
1001 }
1002}
1003
1004template <typename REAL>
1005template <Sdc::SchemeType SCHEME, class T, class U, class U1, class U2>
1006inline void
1007PrimvarRefinerReal<REAL>::limit(T const & src, U & dstPos, U1 * dstTan1Ptr, U2 * dstTan2Ptr) const {
1008
1009 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
1010
1011 Vtr::internal::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
1012
1013 int maxWeightsPerMask = 1 + 2 * level.getMaxValence();
1014 bool hasTangents = (dstTan1Ptr && dstTan2Ptr);
1015 int numMasks = 1 + (hasTangents ? 2 : 0);
1016
1017 Vtr::internal::StackBuffer<Index,33> indexBuffer(maxWeightsPerMask);
1018 Vtr::internal::StackBuffer<Weight,99> weightBuffer(numMasks * maxWeightsPerMask);
1019
1020 Weight * vPosWeights = weightBuffer,
1021 * ePosWeights = vPosWeights + 1,
1022 * fPosWeights = ePosWeights + level.getMaxValence();
1023 Weight * vTan1Weights = vPosWeights + maxWeightsPerMask,
1024 * eTan1Weights = ePosWeights + maxWeightsPerMask,
1025 * fTan1Weights = fPosWeights + maxWeightsPerMask;
1026 Weight * vTan2Weights = vTan1Weights + maxWeightsPerMask,
1027 * eTan2Weights = eTan1Weights + maxWeightsPerMask,
1028 * fTan2Weights = fTan1Weights + maxWeightsPerMask;
1029
1030 Mask posMask( vPosWeights, ePosWeights, fPosWeights);
1031 Mask tan1Mask(vTan1Weights, eTan1Weights, fTan1Weights);
1032 Mask tan2Mask(vTan2Weights, eTan2Weights, fTan2Weights);
1033
1034 // This is a bit obscure -- assigning both parent and child as last level -- but
1035 // this mask type was intended for another purpose. Consider one for the limit:
1036 Vtr::internal::VertexInterface vHood(level, level);
1037
1038 for (int vert = 0; vert < level.getNumVertices(); ++vert) {
1039 ConstIndexArray vEdges = level.getVertexEdges(vert);
1040
1041 // Incomplete vertices (present in sparse refinement) do not have their full
1042 // topological neighborhood to determine a proper limit -- just leave the
1043 // vertex at the refined location and continue to the next:
1044 if (level.getVertexTag(vert)._incomplete || (vEdges.size() == 0)) {
1045 dstPos[vert].Clear();
1046 dstPos[vert].AddWithWeight(src[vert], 1.0);
1047 if (hasTangents) {
1048 (*dstTan1Ptr)[vert].Clear();
1049 (*dstTan2Ptr)[vert].Clear();
1050 }
1051 continue;
1052 }
1053
1054 //
1055 // Limit masks require the subdivision Rule for the vertex in order to deal
1056 // with infinitely sharp features correctly -- including boundaries and corners.
1057 // The vertex neighborhood is minimally defined with vertex and edge counts.
1058 //
1059 Sdc::Crease::Rule vRule = level.getVertexRule(vert);
1060
1061 // This is a bit obscure -- child vertex index will be ignored here
1062 vHood.SetIndex(vert, vert);
1063
1064 if (hasTangents) {
1065 scheme.ComputeVertexLimitMask(vHood, posMask, tan1Mask, tan2Mask, vRule);
1066 } else {
1067 scheme.ComputeVertexLimitMask(vHood, posMask, vRule);
1068 }
1069
1070 //
1071 // Gather the neighboring vertices of this vertex -- the vertices opposite its
1072 // incident edges, and the opposite vertices of its incident faces:
1073 //
1074 Index * eIndices = indexBuffer;
1075 Index * fIndices = indexBuffer + vEdges.size();
1076
1077 for (int i = 0; i < vEdges.size(); ++i) {
1078 ConstIndexArray eVerts = level.getEdgeVertices(vEdges[i]);
1079
1080 eIndices[i] = (eVerts[0] == vert) ? eVerts[1] : eVerts[0];
1081 }
1082 if (posMask.GetNumFaceWeights() || (hasTangents && tan1Mask.GetNumFaceWeights())) {
1083 ConstIndexArray vFaces = level.getVertexFaces(vert);
1084 ConstLocalIndexArray vInFace = level.getVertexFaceLocalIndices(vert);
1085
1086 for (int i = 0; i < vFaces.size(); ++i) {
1087 ConstIndexArray fVerts = level.getFaceVertices(vFaces[i]);
1088
1089 LocalIndex vOppInFace = (vInFace[i] + 2);
1090 if (vOppInFace >= fVerts.size()) vOppInFace -= (LocalIndex)fVerts.size();
1091
1092 fIndices[i] = level.getFaceVertices(vFaces[i])[vOppInFace];
1093 }
1094 }
1095
1096 //
1097 // Combine the weights and indices for position and tangents. As with applying
1098 // refinement masks to vertex data, in order to improve numerical precision, it's
1099 // better to apply smaller weights first, so begin with the face-weights followed
1100 // by the edge-weights and the vertex weight last.
1101 //
1102 dstPos[vert].Clear();
1103 for (int i = 0; i < posMask.GetNumFaceWeights(); ++i) {
1104 dstPos[vert].AddWithWeight(src[fIndices[i]], fPosWeights[i]);
1105 }
1106 for (int i = 0; i < posMask.GetNumEdgeWeights(); ++i) {
1107 dstPos[vert].AddWithWeight(src[eIndices[i]], ePosWeights[i]);
1108 }
1109 dstPos[vert].AddWithWeight(src[vert], vPosWeights[0]);
1110
1111 //
1112 // Apply the tangent masks -- both will have the same number of weights and
1113 // indices (one tangent may be "padded" to accommodate the other), but these
1114 // may differ from those of the position:
1115 //
1116 if (hasTangents) {
1117 assert(tan1Mask.GetNumFaceWeights() == tan2Mask.GetNumFaceWeights());
1118 assert(tan1Mask.GetNumEdgeWeights() == tan2Mask.GetNumEdgeWeights());
1119
1120 U1 & dstTan1 = *dstTan1Ptr;
1121 U2 & dstTan2 = *dstTan2Ptr;
1122
1123 dstTan1[vert].Clear();
1124 dstTan2[vert].Clear();
1125 for (int i = 0; i < tan1Mask.GetNumFaceWeights(); ++i) {
1126 dstTan1[vert].AddWithWeight(src[fIndices[i]], fTan1Weights[i]);
1127 dstTan2[vert].AddWithWeight(src[fIndices[i]], fTan2Weights[i]);
1128 }
1129 for (int i = 0; i < tan1Mask.GetNumEdgeWeights(); ++i) {
1130 dstTan1[vert].AddWithWeight(src[eIndices[i]], eTan1Weights[i]);
1131 dstTan2[vert].AddWithWeight(src[eIndices[i]], eTan2Weights[i]);
1132 }
1133 dstTan1[vert].AddWithWeight(src[vert], vTan1Weights[0]);
1134 dstTan2[vert].AddWithWeight(src[vert], vTan2Weights[0]);
1135 }
1136 }
1137}
1138
1139template <typename REAL>
1140template <Sdc::SchemeType SCHEME, class T, class U>
1141inline void
1142PrimvarRefinerReal<REAL>::limitFVar(T const & src, U & dst, int channel) const {
1143
1144 Sdc::Scheme<SCHEME> scheme(_refiner._subdivOptions);
1145
1146 Vtr::internal::Level const & level = _refiner.getLevel(_refiner.GetMaxLevel());
1147 Vtr::internal::FVarLevel const & fvarChannel = level.getFVarLevel(channel);
1148
1149 int maxWeightsPerMask = 1 + 2 * level.getMaxValence();
1150
1151 Vtr::internal::StackBuffer<Weight,33> weightBuffer(maxWeightsPerMask);
1152 Vtr::internal::StackBuffer<Index,16> vEdgeBuffer(level.getMaxValence());
1153
1154 // This is a bit obscure -- assign both parent and child as last level
1155 Vtr::internal::VertexInterface vHood(level, level);
1156
1157 for (int vert = 0; vert < level.getNumVertices(); ++vert) {
1158
1159 ConstIndexArray vEdges = level.getVertexEdges(vert);
1160 ConstIndexArray vValues = fvarChannel.getVertexValues(vert);
1161
1162 // Incomplete vertices (present in sparse refinement) do not have their full
1163 // topological neighborhood to determine a proper limit -- just leave the
1164 // values (perhaps more than one per vertex) at the refined location.
1165 //
1166 // The same can be done if the face-varying channel is purely linear.
1167 //
1168 bool isIncomplete = (level.getVertexTag(vert)._incomplete || (vEdges.size() == 0));
1169 if (isIncomplete || fvarChannel.isLinear()) {
1170 for (int i = 0; i < vValues.size(); ++i) {
1171 Vtr::Index vValue = vValues[i];
1172
1173 dst[vValue].Clear();
1174 dst[vValue].AddWithWeight(src[vValue], 1.0f);
1175 }
1176 continue;
1177 }
1178
1179 bool fvarVertMatchesVertex = fvarChannel.valueTopologyMatches(vValues[0]);
1180 if (fvarVertMatchesVertex) {
1181
1182 // Assign the mask weights to the common buffer and compute the mask:
1183 //
1184 Weight * vWeights = weightBuffer,
1185 * eWeights = vWeights + 1,
1186 * fWeights = eWeights + vEdges.size();
1187
1188 Mask vMask(vWeights, eWeights, fWeights);
1189
1190 vHood.SetIndex(vert, vert);
1191
1192 scheme.ComputeVertexLimitMask(vHood, vMask, level.getVertexRule(vert));
1193
1194 //
1195 // Apply mask to corresponding FVar values for neighboring vertices:
1196 //
1197 Vtr::Index vValue = vValues[0];
1198
1199 dst[vValue].Clear();
1200 if (vMask.GetNumFaceWeights() > 0) {
1201 assert(!vMask.AreFaceWeightsForFaceCenters());
1202
1203 ConstIndexArray vFaces = level.getVertexFaces(vert);
1204 ConstLocalIndexArray vInFace = level.getVertexFaceLocalIndices(vert);
1205
1206 for (int i = 0; i < vFaces.size(); ++i) {
1207 ConstIndexArray faceValues = fvarChannel.getFaceValues(vFaces[i]);
1208 LocalIndex vOppInFace = vInFace[i] + 2;
1209 if (vOppInFace >= faceValues.size()) vOppInFace -= faceValues.size();
1210
1211 Index vValueOppositeFace = faceValues[vOppInFace];
1212
1213 dst[vValue].AddWithWeight(src[vValueOppositeFace], fWeights[i]);
1214 }
1215 }
1216 if (vMask.GetNumEdgeWeights() > 0) {
1217 Index * vEdgeValues = vEdgeBuffer;
1218 fvarChannel.getVertexEdgeValues(vert, vEdgeValues);
1219
1220 for (int i = 0; i < vEdges.size(); ++i) {
1221 dst[vValue].AddWithWeight(src[vEdgeValues[i]], eWeights[i]);
1222 }
1223 }
1224 dst[vValue].AddWithWeight(src[vValue], vWeights[0]);
1225 } else {
1226 //
1227 // Sibling FVar values associated with a vertex will be either a corner or a crease:
1228 //
1229 for (int i = 0; i < vValues.size(); ++i) {
1230 Vtr::Index vValue = vValues[i];
1231
1232 dst[vValue].Clear();
1233 if (fvarChannel.getValueTag(vValue).isCorner()) {
1234 dst[vValue].AddWithWeight(src[vValue], 1.0f);
1235 } else {
1236 Index vEndValues[2];
1237 fvarChannel.getVertexCreaseEndValues(vert, i, vEndValues);
1238
1239 dst[vValue].AddWithWeight(src[vEndValues[0]], 1.0f/6.0f);
1240 dst[vValue].AddWithWeight(src[vEndValues[1]], 1.0f/6.0f);
1241 dst[vValue].AddWithWeight(src[vValue], 2.0f/3.0f);
1242 }
1243 }
1244 }
1245 }
1246}
1247
1248class PrimvarRefiner : public PrimvarRefinerReal<float> {
1249public:
1251 : PrimvarRefinerReal<float>(refiner) { }
1252};
1253
1254} // end namespace Far
1255
1256} // end namespace OPENSUBDIV_VERSION
1257using namespace OPENSUBDIV_VERSION;
1258} // end namespace OpenSubdiv
1259
1260#endif /* OPENSUBDIV3_FAR_PRIMVAR_REFINER_H */
void Error(ErrorType err, const char *format,...)
Sends an OSD error with a message (internal use only)
Vtr::ConstIndexArray ConstIndexArray
Definition types.h:30
Vtr::ConstLocalIndexArray ConstLocalIndexArray
Definition types.h:31
@ FAR_RUNTIME_ERROR
Issue a generic runtime error, but continue execution.
Definition error.h:23
bool IndexIsValid(Index index)
Definition types.h:41
Applies refinement operations to generic primvar data.
void Limit(T const &src, U &dstPos) const
Apply limit weights to a primvar buffer.
void Limit(T const &src, U &dstPos, U1 &dstTan1, U2 &dstTan2) const
void InterpolateFaceUniform(int level, T const &src, U &dst) const
Refine uniform (per-face) primvar data between levels.
void InterpolateVarying(int level, T const &src, U &dst) const
Apply only varying interpolation weights to a primvar buffer for a single level of refinement.
void Interpolate(int level, T const &src, U &dst) const
Apply vertex interpolation weights to a primvar buffer for a single level of refinement.
void InterpolateFaceVarying(int level, T const &src, U &dst, int channel=0) const
Apply face-varying interpolation weights to a primvar buffer associated with a particular face-varyin...
void LimitFaceVarying(T const &src, U &dst, int channel=0) const
Stores topology data for a specified set of refinement options.
Scheme is a class template which provides all implementation for the subdivision schemes supported by...
Definition scheme.h:49