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