opensubdiv/far/primvarRefiner.h Source File

- Main Page
- Namespaces
- Classes
- Files

- File List

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
56 class PrimvarRefiner {
57
58 public:
59 PrimvarRefiner(TopologyRefiner const & refiner) : _refiner(refiner) { }
60 ~PrimvarRefiner() { }
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) :
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 and 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;
281 case Sdc::SCHEME_BILINEAR:
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 and 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;
306 case Sdc::SCHEME_BILINEAR:
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) {
319 Error(FAR_RUNTIME_ERROR,
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;
332 case Sdc::SCHEME_BILINEAR:
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) {
343 Error(FAR_RUNTIME_ERROR,
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;
356 case Sdc::SCHEME_BILINEAR:
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) {
367 Error(FAR_RUNTIME_ERROR,
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;
380 case Sdc::SCHEME_BILINEAR:
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 and 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 and 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 interolate 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
476 Vtr::internal::StackBuffer<float,16> fVertWeights(parent.getMaxValence());
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, its 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 intialize (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();
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)
745 ? Sdc::Crease::RULE_CREASE : Sdc::Crease::RULE_SMOOTH;
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 edges'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();
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, its 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 (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 semisharp 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 // refinment masks to vertex data, in order to improve numerical precision, its
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 accomodate 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 */
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::ConstArray< Index >
OpenSubdiv::OPENSUBDIV_VERSION::Far::TopologyRefiner::GetMaxLevel
int GetMaxLevel() const
Returns the highest level of refinement.
Definition: topologyRefiner.h:72
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::IndexIsValid
bool IndexIsValid(Index index)
Definition: types.h:58
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::SCHEME_LOOP
Definition: types.h:40
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getFVarLevel
FVarLevel & getFVarLevel(int channel)
Definition: level.h:213
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Refinement::parent
Level const & parent() const
Definition: refinement.h:75
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::GetTopologyRefiner
TopologyRefiner const & GetTopologyRefiner() const
Definition: primvarRefiner.h:62
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getEdgeVertices
ConstIndexArray getEdgeVertices(Index edgeIndex) const
Definition: level.h:604
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::ConstArray::size
size_type size() const
Definition: array.h:72
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::FVarLevel::ConstValueTagArray
Vtr::ConstArray< ValueTag > ConstValueTagArray
Definition: fvarLevel.h:127
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::StackBuffer
Definition: stackBuffer.h:50
OpenSubdiv::OPENSUBDIV_VERSION::Far::LocalIndex
Vtr::LocalIndex LocalIndex
Definition: types.h:42
OpenSubdiv::OPENSUBDIV_VERSION::Far::FAR_RUNTIME_ERROR
Issue a generic runtime error, but continue execution.
Definition: error.h:40
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::SCHEME_BILINEAR
Definition: types.h:38
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::InterpolateFaceUniform
void InterpolateFaceUniform(int level, T const &src, U &dst) const
Refine uniform (per-face) primvar data between levels.
Definition: primvarRefiner.h:388
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::SCHEME_CATMARK
Definition: types.h:39
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getNumFaces
int getNumFaces() const
Definition: level.h:160
OpenSubdiv::OPENSUBDIV_VERSION::Far::TopologyRefiner::getRefinement
Vtr::internal::Refinement & getRefinement(int l)
Definition: topologyRefiner.h:193
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Scheme
Scheme is a class template which provides all implementation for the subdivision schemes supported by...
Definition: scheme.h:66
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getNumEdges
int getNumEdges() const
Definition: level.h:161
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::InterpolateFaceVarying
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...
Definition: primvarRefiner.h:291
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Crease::RULE_CREASE
Definition: crease.h:86
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level
Definition: level.h:83
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getFaceVertices
ConstIndexArray getFaceVertices(Index faceIndex) const
Definition: level.h:479
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::FaceInterface
Definition: componentInterfaces.h:56
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Refinement::getNumChildVerticesFromFaces
int getNumChildVerticesFromFaces() const
Definition: refinement.h:133
OpenSubdiv::OPENSUBDIV_VERSION::Far::ConstLocalIndexArray
Vtr::ConstLocalIndexArray ConstLocalIndexArray
Definition: types.h:48
OpenSubdiv::OPENSUBDIV_VERSION::Far::ConstIndexArray
Vtr::ConstIndexArray ConstIndexArray
Definition: types.h:47
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Crease::Rule
Rule
Definition: crease.h:82
OpenSubdiv::OPENSUBDIV_VERSION::Far::TopologyRefiner::getLevel
Vtr::internal::Level & getLevel(int l)
Definition: topologyRefiner.h:190
OpenSubdiv::OPENSUBDIV_VERSION::Far::Index
Vtr::Index Index
Definition: types.h:41
OpenSubdiv::OPENSUBDIV_VERSION::Sdc::Crease::RULE_SMOOTH
Definition: crease.h:84
OpenSubdiv::OPENSUBDIV_VERSION::Far::TopologyRefiner
Stores topology data for a specified set of refinement options.
Definition: topologyRefiner.h:49
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::InterpolateVarying
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...
Definition: primvarRefiner.h:405
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::Limit
void Limit(T const &src, U &dstPos) const
Apply limit weights to a primvar buffer.
Definition: primvarRefiner.h:316
OpenSubdiv::OPENSUBDIV_VERSION::Far::Error
void Error(ErrorType err, const char *format,...)
Sends an OSD error with a message (internal use only)
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getNumVertices
int getNumVertices() const
Definition: level.h:159
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Refinement::getFaceChildVertex
Index getFaceChildVertex(Index f) const
Definition: refinement.h:144
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::Index
int Index
Definition: types.h:54
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::Interpolate
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...
Definition: primvarRefiner.h:266
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::LimitFaceVarying
void LimitFaceVarying(T const &src, U &dst, int channel=0) const
Definition: primvarRefiner.h:364
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Level::getMaxValence
int getMaxValence() const
Definition: level.h:171
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::PrimvarRefiner
PrimvarRefiner(TopologyRefiner const &refiner)
Definition: primvarRefiner.h:59
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner::~PrimvarRefiner
~PrimvarRefiner()
Definition: primvarRefiner.h:60
OpenSubdiv::OPENSUBDIV_VERSION::Vtr::internal::Refinement
Definition: refinement.h:69
OpenSubdiv::OPENSUBDIV_VERSION::Far::PrimvarRefiner
Applies refinement operations to generic primvar data.
Definition: primvarRefiner.h:56