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