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