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