OpenSubdiv
Loading...
Searching...
No Matches
fvarLevel.h
Go to the documentation of this file.
1//
2// Copyright 2014 DreamWorks Animation LLC.
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://opensubdiv.org/license.
6//
7#ifndef OPENSUBDIV3_VTR_FVAR_LEVEL_H
8#define OPENSUBDIV3_VTR_FVAR_LEVEL_H
9
10#include "../version.h"
11
12#include "../sdc/types.h"
13#include "../sdc/crease.h"
14#include "../sdc/options.h"
15#include "../vtr/types.h"
16#include "../vtr/level.h"
17
18#include <vector>
19#include <cassert>
20#include <cstring>
21
22
23namespace OpenSubdiv {
24namespace OPENSUBDIV_VERSION {
25
26namespace Vtr {
27namespace internal {
28
29//
30// FVarLevel:
31// A "face-varying channel" includes the topology for a set of face-varying
32// data, relative to the topology of the Level with which it is associated.
33//
34// Analogous to a set of vertices and face-vertices that define the topology for
35// the geometry, a channel requires a set of "values" and "face-values". The
36// "values" are indices of entries in a set of face-varying data, just as vertices
37// are indices into a set of vertex data. The face-values identify a value for
38// each vertex of the face, and so define topology for the values that may be
39// unique to each channel.
40//
41// In addition to the value size and the vector of face-values (which matches the
42// size of the geometry's face-vertices), tags are associated with each component
43// to identify deviations of the face-varying topology from the vertex topology.
44// And since there may be a one-to-many mapping between vertices and face-varying
45// values, that mapping is also allocated.
46//
47// It turns out that the mapping used is able to completely encode the set of
48// face-values and is more amenable to refinement. Currently the face-values
49// take up almost half the memory of this representation, so if memory does
50// become a concern, we do not need to store them. The only reason we do so now
51// is that the face-value interface for specifying base topology and inspecting
52// subsequent levels is very familiar to that of face-vertices for clients. So
53// having them available for such access is convenient.
54//
55// Regarding scope and access...
56// Unclear at this early state, but leaning towards nesting this class within
57// Level, given the intimate dependency between the two.
58// Everything is being declared public for now to facilitate access until it's
59// clearer how this functionality will be provided.
60//
61class FVarLevel {
62public:
63 //
64 // Component tags -- trying to minimize the types needed here:
65 //
66 // Tag per Edge:
67 // - facilitates topological analysis around each vertex
68 // - required during refinement to spawn one or more edge-values
69 //
70 struct ETag {
71 ETag() { }
72
73 void clear() { std::memset(this, 0, sizeof(ETag)); }
74
75 typedef unsigned char ETagSize;
76
77 ETagSize _mismatch : 1; // local FVar topology does not match
78 ETagSize _disctsV0 : 1; // discontinuous at vertex 0
79 ETagSize _disctsV1 : 1; // discontinuous at vertex 1
80 ETagSize _linear : 1; // linear boundary constraints
81
82 Level::ETag combineWithLevelETag(Level::ETag) const;
83 };
84
85 //
86 // Tag per Value:
87 // - informs both refinement and interpolation
88 // - every value spawns a child value in refinement
89 // - includes a subset of Level::VTag to be later combined with a VTag
90 //
91 struct ValueTag {
92 ValueTag() { }
93
94 void clear() { std::memset(this, 0, sizeof(ValueTag)); }
95
96 bool isMismatch() const { return _mismatch; }
97 bool isCrease() const { return _crease; }
98 bool isCorner() const { return !_crease; }
99 bool isSemiSharp() const { return _semiSharp; }
100 bool isInfSharp() const { return !_semiSharp && !_crease; }
101 bool isDepSharp() const { return _depSharp; }
102 bool hasCreaseEnds() const { return _crease || _semiSharp; }
103
104 bool hasInfSharpEdges() const { return _infSharpEdges; }
105 bool hasInfIrregularity() const { return _infIrregular; }
106
107 typedef unsigned char ValueTagSize;
108
109 // If there is no mismatch, no other members should be inspected
110 ValueTagSize _mismatch : 1; // local FVar topology does not match
111 ValueTagSize _xordinary : 1; // local FVar topology is extra-ordinary
112 ValueTagSize _nonManifold : 1; // local FVar topology is non-manifold
113 ValueTagSize _crease : 1; // value is a crease, otherwise a corner
114 ValueTagSize _semiSharp : 1; // value is a corner decaying to crease
115 ValueTagSize _depSharp : 1; // value is a corner by dependency on another
116
117 ValueTagSize _infSharpEdges : 1; // value is a corner by inf-sharp features
118 ValueTagSize _infIrregular : 1; // value span includes inf-sharp irregularity
119
120 Level::VTag combineWithLevelVTag(Level::VTag) const;
121
122 // Alternate constructor and accessor for dealing with integer bits directly:
123 explicit ValueTag(ValueTagSize bits) {
124 std::memcpy(this, &bits, sizeof(bits));
125 }
126 ValueTagSize getBits() const {
127 ValueTagSize bits;
128 std::memcpy(&bits, this, sizeof(bits));
129 return bits;
130 }
131 };
132
133 typedef Vtr::ConstArray<ValueTag> ConstValueTagArray;
134 typedef Vtr::Array<ValueTag> ValueTagArray;
135
136 //
137 // Simple struct containing the "end faces" of a crease, i.e. the faces which
138 // contain the FVar values to be used when interpolating the crease. (Prefer
139 // the struct over std::pair for its member names)
140 //
141 struct CreaseEndPair {
142 LocalIndex _startFace;
143 LocalIndex _endFace;
144 };
145
146 typedef Vtr::ConstArray<CreaseEndPair> ConstCreaseEndPairArray;
147 typedef Vtr::Array<CreaseEndPair> CreaseEndPairArray;
148
149 typedef LocalIndex Sibling;
150
151 typedef ConstLocalIndexArray ConstSiblingArray;
152 typedef LocalIndexArray SiblingArray;
153
154public:
155 FVarLevel(Level const& level);
156 ~FVarLevel();
157
158 // Queries for the entire channel:
159 Level const& getLevel() const { return _level; }
160
161 int getNumValues() const { return _valueCount; }
162 int getNumFaceValuesTotal() const { return (int) _faceVertValues.size(); }
163
164 bool isLinear() const { return _isLinear; }
165 bool hasLinearBoundaries() const { return _hasLinearBoundaries; }
166 bool hasSmoothBoundaries() const { return ! _hasLinearBoundaries; }
167 bool hasCreaseEnds() const { return hasSmoothBoundaries(); }
168
169 Sdc::Options getOptions() const { return _options; }
170
171 // Queries per face:
172 ConstIndexArray getFaceValues(Index fIndex) const;
173 IndexArray getFaceValues(Index fIndex);
174
175 // Queries per edge:
176 ETag getEdgeTag(Index eIndex) const { return _edgeTags[eIndex]; }
177 bool edgeTopologyMatches(Index eIndex) const { return !getEdgeTag(eIndex)._mismatch; }
178
179 // Queries per vertex (and its potential sibling values):
180 int getNumVertexValues(Index v) const { return _vertSiblingCounts[v]; }
181 Index getVertexValueOffset(Index v, Sibling i = 0) const { return _vertSiblingOffsets[v] + i; }
182
183 Index getVertexValue(Index v, Sibling i = 0) const { return _vertValueIndices[getVertexValueOffset(v,i)]; }
184
185 Index findVertexValueIndex(Index vertexIndex, Index valueIndex) const;
186
187 // Methods to access/modify array properties per vertex:
188 ConstIndexArray getVertexValues(Index vIndex) const;
189 IndexArray getVertexValues(Index vIndex);
190
191 ConstValueTagArray getVertexValueTags(Index vIndex) const;
192 ValueTagArray getVertexValueTags(Index vIndex);
193
194 ConstCreaseEndPairArray getVertexValueCreaseEnds(Index vIndex) const;
195 CreaseEndPairArray getVertexValueCreaseEnds(Index vIndex);
196
197 ConstSiblingArray getVertexFaceSiblings(Index vIndex) const;
198 SiblingArray getVertexFaceSiblings(Index vIndex);
199
200 // Queries per value:
201 ValueTag getValueTag(Index valueIndex) const { return _vertValueTags[valueIndex]; }
202 bool valueTopologyMatches(Index valueIndex) const { return !getValueTag(valueIndex)._mismatch; }
203
204 CreaseEndPair getValueCreaseEndPair(Index valueIndex) const { return _vertValueCreaseEnds[valueIndex]; }
205
206 // Tag queries related to faces (use Level methods for those returning Level::VTag/ETag)
207 void getFaceValueTags(Index faceIndex, ValueTag valueTags[]) const;
208
209 ValueTag getFaceCompositeValueTag(Index faceIndex) const;
210
211 // Higher-level topological queries, i.e. values in a neighborhood:
212 void getEdgeFaceValues(Index eIndex, int fIncToEdge, Index valuesPerVert[2]) const;
213 void getVertexEdgeValues(Index vIndex, Index valuesPerEdge[]) const;
214 void getVertexCreaseEndValues(Index vIndex, Sibling sibling, Index endValues[2]) const;
215
216 // Initialization and allocation helpers:
217 void setOptions(Sdc::Options const& options);
218 void resizeVertexValues(int numVertexValues);
219 void resizeValues(int numValues);
220 void resizeComponents();
221
222 // Topological analysis methods -- tagging and face-value population:
223 void completeTopologyFromFaceValues(int regBoundaryValence);
224 void initializeFaceValuesFromFaceVertices();
225 void initializeFaceValuesFromVertexFaceSiblings();
226
227 struct ValueSpan;
228 void gatherValueSpans(Index vIndex, ValueSpan * vValueSpans) const;
229
230 // Debugging methods:
231 bool validate() const;
232 void print() const;
233 void buildFaceVertexSiblingsFromVertexFaceSiblings(std::vector<Sibling>& fvSiblings) const;
234
235private:
236 // Just as Refinements build Levels, FVarRefinements build FVarLevels...
237 friend class FVarRefinement;
238
239 Level const & _level;
240
241 // Linear interpolation options vary between channels:
242 Sdc::Options _options;
243
244 bool _isLinear;
245 bool _hasLinearBoundaries;
246 bool _hasDependentSharpness;
247 int _valueCount;
248
249 //
250 // Vectors recording face-varying topology including tags that help propagate
251 // data through the refinement hierarchy. Vectors are not sparse but most use
252 // 8-bit values relative to the local topology.
253 //
254 // The vector of face-values is actually redundant here, but is constructed as
255 // it is most convenient for clients. It represents almost half the memory of
256 // the topology (4 32-bit integers per face) and not surprisingly, populating
257 // it takes a considerable amount of the refinement time (1/3). We can reduce
258 // both if we are willing to compute these on demand for clients.
259 //
260 // Per-face (matches face-verts of corresponding level):
261 std::vector<Index> _faceVertValues;
262
263 // Per-edge:
264 std::vector<ETag> _edgeTags;
265
266 // Per-vertex:
267 std::vector<Sibling> _vertSiblingCounts;
268 std::vector<int> _vertSiblingOffsets;
269 std::vector<Sibling> _vertFaceSiblings;
270
271 // Per-value:
272 std::vector<Index> _vertValueIndices;
273 std::vector<ValueTag> _vertValueTags;
274 std::vector<CreaseEndPair> _vertValueCreaseEnds;
275};
276
277//
278// Access/modify the values associated with each face:
279//
280inline ConstIndexArray
281FVarLevel::getFaceValues(Index fIndex) const {
282
283 int vCount = _level.getNumFaceVertices(fIndex);
284 int vOffset = _level.getOffsetOfFaceVertices(fIndex);
285 return ConstIndexArray(&_faceVertValues[vOffset], vCount);
286}
287inline IndexArray
288FVarLevel::getFaceValues(Index fIndex) {
289
290 int vCount = _level.getNumFaceVertices(fIndex);
291 int vOffset = _level.getOffsetOfFaceVertices(fIndex);
292 return IndexArray(&_faceVertValues[vOffset], vCount);
293}
294
295inline FVarLevel::ConstSiblingArray
296FVarLevel::getVertexFaceSiblings(Index vIndex) const {
297
298 int vCount = _level.getNumVertexFaces(vIndex);
299 int vOffset = _level.getOffsetOfVertexFaces(vIndex);
300 return ConstSiblingArray(&_vertFaceSiblings[vOffset], vCount);
301}
302inline FVarLevel::SiblingArray
303FVarLevel::getVertexFaceSiblings(Index vIndex) {
304
305 int vCount = _level.getNumVertexFaces(vIndex);
306 int vOffset = _level.getOffsetOfVertexFaces(vIndex);
307 return SiblingArray(&_vertFaceSiblings[vOffset], vCount);
308}
309
310inline ConstIndexArray
311FVarLevel::getVertexValues(Index vIndex) const
312{
313 int vCount = getNumVertexValues(vIndex);
314 int vOffset = getVertexValueOffset(vIndex);
315 return ConstIndexArray(&_vertValueIndices[vOffset], vCount);
316}
317inline IndexArray
318FVarLevel::getVertexValues(Index vIndex)
319{
320 int vCount = getNumVertexValues(vIndex);
321 int vOffset = getVertexValueOffset(vIndex);
322 return IndexArray(&_vertValueIndices[vOffset], vCount);
323}
324
325inline FVarLevel::ConstValueTagArray
326FVarLevel::getVertexValueTags(Index vIndex) const
327{
328 int vCount = getNumVertexValues(vIndex);
329 int vOffset = getVertexValueOffset(vIndex);
330 return ConstValueTagArray(&_vertValueTags[vOffset], vCount);
331}
332inline FVarLevel::ValueTagArray
333FVarLevel::getVertexValueTags(Index vIndex)
334{
335 int vCount = getNumVertexValues(vIndex);
336 int vOffset = getVertexValueOffset(vIndex);
337 return ValueTagArray(&_vertValueTags[vOffset], vCount);
338}
339
340inline FVarLevel::ConstCreaseEndPairArray
341FVarLevel::getVertexValueCreaseEnds(Index vIndex) const
342{
343 int vCount = getNumVertexValues(vIndex);
344 int vOffset = getVertexValueOffset(vIndex);
345 return ConstCreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
346}
347inline FVarLevel::CreaseEndPairArray
348FVarLevel::getVertexValueCreaseEnds(Index vIndex)
349{
350 int vCount = getNumVertexValues(vIndex);
351 int vOffset = getVertexValueOffset(vIndex);
352 return CreaseEndPairArray(&_vertValueCreaseEnds[vOffset], vCount);
353}
354
355inline Index
356FVarLevel::findVertexValueIndex(Index vertexIndex, Index valueIndex) const {
357
358 if (_level.getDepth() > 0) return valueIndex;
359
360 Index vvIndex = getVertexValueOffset(vertexIndex);
361 while (_vertValueIndices[vvIndex] != valueIndex) {
362 ++ vvIndex;
363 }
364 return vvIndex;
365}
366
367//
368// Methods related to tagging:
369//
370inline Level::ETag
371FVarLevel::ETag::combineWithLevelETag(Level::ETag levelTag) const
372{
373 if (this->_mismatch) {
374 levelTag._boundary = true;
375 levelTag._infSharp = true;
376 }
377 return levelTag;
378}
379inline Level::VTag
380FVarLevel::ValueTag::combineWithLevelVTag(Level::VTag levelTag) const
381{
382 if (this->_mismatch) {
383 //
384 // Semi-sharp FVar values are always tagged and treated as corners
385 // (at least three sharp edges (two boundary edges and one interior
386 // semi-sharp) and/or vertex is semi-sharp) until the sharpness has
387 // decayed, but they ultimately lie on the inf-sharp crease of the
388 // FVar boundary. Consider this when tagging inf-sharp features.
389 //
390 if (this->isCorner()) {
391 levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CORNER;
392 } else {
393 levelTag._rule = (Level::VTag::VTagSize) Sdc::Crease::RULE_CREASE;
394 }
395 if (this->isCrease() || this->isSemiSharp()) {
396 levelTag._infSharp = false;
397 levelTag._infSharpCrease = true;
398 levelTag._corner = false;
399 } else {
400 levelTag._infSharp = true;
401 levelTag._infSharpCrease = false;
402 levelTag._corner = !this->_infIrregular && !this->_infSharpEdges;
403 }
404 levelTag._infSharpEdges = true;
405 levelTag._infIrregular = this->_infIrregular;
406
407 levelTag._boundary = true;
408 levelTag._xordinary = this->_xordinary;
409
410 levelTag._nonManifold |= this->_nonManifold;
411 }
412 return levelTag;
413}
414
415} // end namespace internal
416} // end namespace Vtr
417
418} // end namespace OPENSUBDIV_VERSION
419using namespace OPENSUBDIV_VERSION;
420} // end namespace OpenSubdiv
421
422#endif /* OPENSUBDIV3_VTR_FVAR_LEVEL_H */
ConstArray< LocalIndex > ConstLocalIndexArray
Definition types.h:66
Array< LocalIndex > LocalIndexArray
Definition types.h:65
ConstArray< Index > ConstIndexArray
Definition types.h:63