HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
primvar.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
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 PXR_USD_USD_GEOM_PRIMVAR_H
25 #define PXR_USD_USD_GEOM_PRIMVAR_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/usdGeom/api.h"
29 #include "pxr/usd/usd/attribute.h"
30 #include "pxr/usd/usdGeom/tokens.h"
31 
32 #include <string>
33 #include <vector>
34 
36 
37 
38 /// \class UsdGeomPrimvar
39 ///
40 /// Schema wrapper for UsdAttribute for authoring and introspecting attributes
41 /// that are primvars.
42 ///
43 /// UsdGeomPrimvar provides API for authoring and retrieving the
44 /// additional data required to encode an attribute as a "Primvar",
45 /// which is a convenient contraction of RenderMan's "Primitive Variable"
46 /// concept, which is represented in Alembic as
47 /// "arbitrary geometry parameters" (arbGeomParams).
48 ///
49 /// This includes the attribute's \ref GetInterpolation() "interpolation"
50 /// across the primitive (which RenderMan refers to as its
51 /// \ref Usd_InterpolationVals "class specifier"
52 /// and Alembic as its <A HREF="https://github.com/alembic/alembic/blob/master/lib/Alembic/AbcGeom/GeometryScope.h#L47"> "geometry scope"</A>);
53 /// it also includes the attribute's \ref GetElementSize() "elementSize",
54 /// which states how many values in the value array must be aggregated for
55 /// each element on the primitive. An attribute's \ref
56 /// UsdAttribute::GetTypeName() "TypeName" also factors into the encoding of
57 /// Primvar.
58 ///
59 /// \section Usd_What_Is_Primvar What is the Purpose of a Primvar?
60 ///
61 /// There are three key aspects of Primvar identity:
62 /// \li Primvars define a value that can vary across the primitive on which
63 /// they are defined, via prescribed interpolation rules
64 /// \li Taken collectively on a prim, its Primvars describe the "per-primitive
65 /// overrides" to the material to which the prim is bound. Different
66 /// renderers may communicate the variables to the shaders using different
67 /// mechanisms over which Usd has no control; Primvars simply provide the
68 /// classification that any renderer should use to locate potential
69 /// overrides. Do please note that primvars override parameters on
70 /// UsdShadeShader objects, \em not
71 /// \ref UsdShadeNodeGraph_Interfaces "Interface Attributes" on UsdShadeMaterial
72 /// prims.
73 /// \li *Primvars inherit down scene namespace.* Regular USD attributes only
74 /// apply to the prim on which they are specified, but primvars implicitly
75 /// also apply to any child prims, unless those child prims have their
76 /// own opinions about those primvars. This capability necessarily
77 /// entails added cost to check for inherited values, but the benefit
78 /// is that it allows concise encoding of certain opinions that broadly
79 /// affect large amounts of geometry. See
80 /// UsdGeomImageable::FindInheritedPrimvars().
81 ///
82 /// \section Usd_Creating_and_Accessing_Primvars Creating and Accessing Primvars
83 ///
84 /// The UsdGeomPrimvarsAPI schema provides a complete interface for creating
85 /// and querying prims for primvars.
86 ///
87 /// The <b>only</b> way to create a new Primvar in scene description is by
88 /// calling UsdGeomPrimvarsAPI::CreatePrimvar(). One cannot "enhance" or
89 /// "promote" an already existing attribute into a Primvar, because doing so
90 /// may require a namespace edit to rename the attribute, which cannot, in
91 /// general, be done within a single UsdEditContext. Instead, create a new
92 /// UsdGeomPrimvar of the desired name using
93 /// UsdGeomPrimvarsAPI::CreatePrimvar(), and then copy the existing attribute
94 /// onto the new UsdGeomPrimvar.
95 ///
96 /// Primvar names can contain arbitrary sub-namespaces. The behavior of
97 /// UsdGeomImageable::GetPrimvar(TfToken const &name) is to prepend "primvars:"
98 /// onto 'name' if it is not already a prefix, and return the result, which
99 /// means we do not have any ambiguity between the primvars
100 /// "primvars:nsA:foo" and "primvars:nsB:foo". <b>There are reserved keywords
101 /// that may not be used as the base names of primvars,</b> and attempting to
102 /// create Primvars of these names will result in a coding error. The
103 /// reserved keywords are tokens the Primvar uses internally to encode various
104 /// features, such as the "indices" keyword used by
105 /// \ref UsdGeomPrimvar_Indexed_primvars "Indexed Primvars".
106 ///
107 /// \anchor UsdGeomPrimvar_Using_Primvar
108 /// If a client wishes to access an already-extant attribute as a Primvar,
109 /// (which may or may not actually be valid Primvar), they can use the
110 /// speculative constructor; typically, a primvar is only "interesting" if it
111 /// additionally provides a value. This might look like:
112 /// \code
113 /// UsdGeomPrimvar primvar = UsdGeomPrimvar(usdAttr);
114 /// if (primvar.HasValue()) {
115 /// VtValue values;
116 /// primvar.Get(&values, timeCode);
117 /// TfToken interpolation = primvar.GetInterpolation();
118 /// int elementSize = primvar.GetElementSize();
119 /// ...
120 /// }
121 /// \endcode
122 ///
123 /// or, because Get() returns `true` if and only if it found a value:
124 /// \code
125 /// UsdGeomPrimvar primvar = UsdGeomPrimvar(usdAttr);
126 /// VtValue values;
127 /// if (primvar.Get(&values, timeCode)) {
128 /// TfToken interpolation = primvar.GetInterpolation();
129 /// int elementSize = primvar.GetElementSize();
130 /// ...
131 /// }
132 /// \endcode
133 ///
134 /// \subsection Usd_Handling_Indexed_Primvars Proper Client Handling of "Indexed" Primvars
135 ///
136 /// As discussed in greater detail in
137 /// \ref UsdGeomPrimvar_Indexed_primvars "Indexed Primvars", primvars can
138 /// optionally contain a (possibly time-varying) indexing attribute that
139 /// establishes a sharing topology for elements of the primvar. Consumers
140 /// can always chose to ignore the possibility of indexed data by exclusively
141 /// using the ComputeFlattened() API. If a client wishes to preserve indexing
142 /// in their processing of a primvar, we suggest a pattern like the following,
143 /// which accounts for the fact that a stronger layer can
144 /// \ref UsdAttribute::Block() "block" a primvar's indexing from a weaker
145 /// layer, via UsdGeomPrimvar::BlockIndices():
146 /// \code
147 /// VtValue values;
148 /// VtIntArray indices;
149 ///
150 /// if (primvar.Get(&values, timeCode)){
151 /// if (primvar.GetIndices(&indices, timeCode)){
152 /// // primvar is indexed: validate/process values and indices together
153 /// }
154 /// else {
155 /// // primvar is not indexed: validate/process values as flat array
156 /// }
157 /// }
158 /// \endcode
159 ///
160 /// \subsection Usd_Primvar_As_Attribute UsdGeomPrimvar and UsdAttribute API
161 ///
162 /// UsdGeomPrimvar presents a small slice of the UsdAttribute API - enough to
163 /// extract the data that comprises the "Declaration info", and get/set of
164 /// the attribute value. A UsdGeomPrimvar also auto-converts to UsdAttribute,
165 /// so you can pass a UsdGeomPrimvar to any function that accepts a UsdAttribute
166 /// or const-ref thereto.
167 ///
168 /// \section Usd_Primvar_Types Primvar Allowed Scene Description Types and Plurality
169 /// There are no limitations imposed on the allowable scene description types
170 /// for Primvars; it is the responsibility of each consuming client to perform
171 /// renderer-specific conversions, if need be (the USD distribution will include
172 /// reference RenderMan conversion utilities).
173 ///
174 /// A note about type plurality of Primvars: It is legitimate for a Primvar
175 /// to be of scalar or array type, and again, consuming clients must be
176 /// prepared to accommodate both. However, while it is not possible, in all
177 /// cases, for USD to \em prevent one from \em changing the type of an attribute
178 /// in different layers or variants of an asset, it is never a good idea to
179 /// do so. This is relevant because, except in a few special cases, it is
180 /// not possible to encode an \em interpolation of any value greater than
181 /// \em constant without providing multiple (i.e. array) data values. Therefore,
182 /// if there is any possibility that downstream clients might need to change
183 /// a Primvar's interpolation, the Primvar-creator should encode it as an
184 /// array rather than a scalar.
185 ///
186 /// Why allow scalar values at all, then? First, sometimes it brings clarity
187 /// to (use of) a shader's API to acknowledge that some parameters are meant
188 /// to be single-valued over a shaded primitive. Second, many DCC's provide
189 /// far richer affordances for editing scalars than they do array values, and
190 /// we feel it is safer to let the content creator make the decision/tradeoff
191 /// of which kind of flexibility is more relevant, rather than leaving it to
192 /// an importer/exporter pair to interpret.
193 ///
194 /// Also, like all attributes, Primvars can be time-sampled, and values can
195 /// be authored and consumed just as any other attribute. There is currently
196 /// no validation that the length of value arrays matches to the size
197 /// required by a gprim's topology, interpolation, and elementSize.
198 ///
199 /// For consumer convenience, we provide GetDeclarationInfo(), which returns
200 /// all the type information (other than topology) needed to compute the
201 /// required array size, which is also all the information required to
202 /// prepare the Primvar's value for consumption by a renderer.
203 ///
204 /// \section Usd_UsdGeomPrimvar_Lifetime Lifetime Management and Primvar Validity
205 ///
206 /// UsdGeomPrimvar has an explicit bool operator that validates that
207 /// the attribute IsDefined() and thus valid for querying and authoring
208 /// values and metadata. This is a fairly expensive query that we do
209 /// <b>not</b> cache, so if client code retains UsdGeomPrimvar objects, it should
210 /// manage its object validity closely, for performance. An ideal pattern
211 /// is to listen for UsdNotice::StageContentsChanged notifications, and
212 /// revalidate/refetch its retained UsdGeomPrimvar s only then, and otherwise use
213 /// them without validity checking.
214 ///
215 /// \section Usd_InterpolationVals Interpolation of Geometric Primitive Variables
216 /// In the following explanation of the meaning of the various kinds/levels
217 /// of Primvar interpolation, each bolded bullet gives the name of the token
218 /// in \ref UsdGeomTokens that provides the value. So to set a Primvar's
219 /// interpolation to "varying", one would:
220 /// \code
221 /// primvar.SetInterpolation(UsdGeomTokens->varying);
222 /// \endcode
223 ///
224 /// Reprinted and adapted from <a HREF="http://renderman.pixar.com/resources/current/rps/appnote.22.html#classSpecifiers">
225 /// the RPS documentation</a>, which contains further details, \em interpolation
226 /// describes how the Primvar will be interpolated over the uv parameter
227 /// space of a surface primitive (or curve or pointcloud). The possible
228 /// values are:
229 /// \li <b>constant</b> One value remains constant over the entire surface
230 /// primitive.
231 /// \li <b>uniform</b> One value remains constant for each uv patch segment of
232 /// the surface primitive (which is a \em face for meshes).
233 /// \li <b>varying</b> Four values are interpolated over each uv patch segment
234 /// of the surface. Bilinear interpolation is used for interpolation
235 /// between the four values.
236 /// \li <b>vertex</b> Values are interpolated between each vertex in the
237 /// surface primitive. The basis function of the surface is used for
238 /// interpolation between vertices.
239 /// \li <b>faceVarying</b> For polygons and subdivision surfaces, four values
240 /// are interpolated over each face of the mesh. Bilinear interpolation
241 /// is used for interpolation between the four values.
242 ///
243 /// \section Usd_Extending_UsdObject_Classes UsdGeomPrimvar As Example of Attribute Schema
244 ///
245 /// Just as UsdSchemaBase and its subclasses provide the pattern for how to
246 /// layer schema onto the generic UsdPrim object, UsdGeomPrimvar provides an
247 /// example of how to layer schema onto a generic UsdAttribute object. In both
248 /// cases, the schema object wraps and contains the UsdObject.
249 ///
250 /// \section Usd_UsdGeomPrimvar_Inheritance Primvar Namespace Inheritance
251 ///
252 /// Constant interpolation primvar values can be inherited down namespace.
253 /// That is, a primvar value set on a prim will also apply to any child
254 /// prims, unless those children have their own opinions about those named
255 /// primvars. For complete details on how primvars inherit, see
256 /// \ref usdGeom_PrimvarInheritance .
257 ///
258 /// \sa UsdGeomImageable::FindInheritablePrimvars().
259 ///
261 {
262 public:
263 
264  // Default constructor returns an invalid Primvar. Exists for
265  // container classes
267  {
268  /* NOTHING */
269  }
270 
271  /// Speculative constructor that will produce a valid UsdGeomPrimvar when
272  /// \p attr already represents an attribute that is Primvar, and
273  /// produces an \em invalid Primvar otherwise (i.e.
274  /// \ref UsdGeomPrimvar_bool "operator bool()" will return false).
275  ///
276  /// Calling \c UsdGeomPrimvar::IsPrimvar(attr) will return the same truth
277  /// value as this constructor, but if you plan to subsequently use the
278  /// Primvar anyways, just use this constructor, as demonstrated in the
279  /// \ref UsdGeomPrimvar_Using_Primvar "class documentation".
281  explicit UsdGeomPrimvar(const UsdAttribute &attr);
282 
283  /// Return the Primvar's interpolation, which is
284  /// \ref Usd_InterpolationVals "UsdGeomTokens->constant" if unauthored
285  ///
286  /// Interpolation determines how the Primvar interpolates over
287  /// a geometric primitive. See \ref Usd_InterpolationVals
289  TfToken GetInterpolation() const;
290 
291  /// Set the Primvar's interpolation.
292  ///
293  /// Errors and returns false if \p interpolation is out of range as
294  /// defined by IsValidInterpolation(). No attempt is made to validate
295  /// that the Primvar's value contains the right number of elements
296  /// to match its interpolation to its topology.
297  ///
298  /// \sa GetInterpolation(), \ref Usd_InterpolationVals
300  bool SetInterpolation(const TfToken &interpolation);
301 
302  /// Has interpolation been explicitly authored on this Primvar?
303  ///
304  /// \sa GetInterpolationSize()
306  bool HasAuthoredInterpolation() const;
307 
308  /// Return the "element size" for this Primvar, which is 1 if
309  /// unauthored. If this Primvar's type is \em not an array type,
310  /// (e.g. "Vec3f[]"), then elementSize is irrelevant.
311  ///
312  /// ElementSize does \em not generally encode the length of an array-type
313  /// primvar, and rarely needs to be authored. ElementSize can be thought
314  /// of as a way to create an "aggregate interpolatable type", by
315  /// dictating how many consecutive elements in the value array should be
316  /// taken as an atomic element to be interpolated over a gprim.
317  ///
318  /// For example, spherical harmonics are often represented as a
319  /// collection of nine floating-point coefficients, and the coefficients
320  /// need to be sampled across a gprim's surface: a perfect case for
321  /// primvars. However, USD has no <tt>float9</tt> datatype. But we can
322  /// communicate the aggregation of nine floats successfully to renderers
323  /// by declaring a simple float-array valued primvar, and setting its
324  /// \em elementSize to 9. To author a \em uniform spherical harmonic
325  /// primvar on a Mesh of 42 faces, the primvar's array value would contain
326  /// 9*42 = 378 float elements.
328  int GetElementSize() const;
329 
330  /// Set the elementSize for this Primvar.
331  ///
332  /// Errors and returns false if \p eltSize less than 1.
333  ///
334  /// \sa GetElementSize()
336  bool SetElementSize(int eltSize);
337 
338  /// Has elementSize been explicitly authored on this Primvar?
339  ///
340  /// \sa GetElementSize()
342  bool HasAuthoredElementSize() const;
343 
344 
345  /// Test whether a given UsdAttribute represents valid Primvar, which
346  /// implies that creating a UsdGeomPrimvar from the attribute will succeed.
347  ///
348  /// Success implies that \c attr.IsDefined() is true.
350  static bool IsPrimvar(const UsdAttribute &attr);
351 
352 
353  /// Test whether a given \p name represents a valid name of a primvar,
354  /// which implies that creating a UsdGeomPrimvar with the given name will
355  /// succeed.
356  ///
358  static bool IsValidPrimvarName(const TfToken& name);
359 
360  /// Returns the \p name, devoid of the "primvars:" token if present,
361  /// otherwise returns the \p name unchanged
363  static TfToken StripPrimvarsName(const TfToken& name);
364 
365  /// Validate that the provided \p interpolation is a valid setting for
366  /// interpolation as defined by \ref Usd_InterpolationVals.
368  static bool IsValidInterpolation(const TfToken &interpolation);
369 
370  /// Convenience function for fetching all information required to
371  /// properly declare this Primvar. The \p name returned is the
372  /// "client name", stripped of the "primvars" namespace, i.e. equivalent to
373  /// GetPrimvarName()
374  ///
375  /// May also be more efficient than querying key individually.
378  TfToken *interpolation, int *elementSize) const;
379 
380  // ---------------------------------------------------------------
381  /// \name UsdAttribute API
382  // ---------------------------------------------------------------
383  /// @{
384 
385  /// Allow UsdGeomPrimvar to auto-convert to UsdAttribute, so you can
386  /// pass a UsdGeomPrimvar to any function that accepts a UsdAttribute or
387  /// const-ref thereto.
388  operator UsdAttribute const& () const { return _attr; }
389 
390  /// Explicit UsdAttribute extractor
391  UsdAttribute const &GetAttr() const { return _attr; }
392 
393  /// Return true if the underlying UsdAttribute::IsDefined(), and in
394  /// addition the attribute is identified as a Primvar. Does not imply
395  /// that the primvar provides a value
396  bool IsDefined() const { return IsPrimvar(_attr); }
397 
398  /// Return true if the underlying attribute has a value, either from
399  /// authored scene description or a fallback.
400  bool HasValue() const { return _attr.HasValue(); }
401 
402  /// Return true if the underlying attribute has an unblocked, authored
403  /// value.
404  bool HasAuthoredValue() const { return _attr.HasAuthoredValue(); }
405 
406  /// \anchor UsdGeomPrimvar_bool
407  /// Return true if this Primvar is valid for querying and authoring
408  /// values and metadata, which is identically equivalent to IsDefined().
409  explicit operator bool() const {
410  return IsDefined() ? &UsdGeomPrimvar::_attr : 0;
411  }
412 
413  /// \sa UsdAttribute::GetName()
414  TfToken const &GetName() const { return _attr.GetName(); }
415 
416  /// Returns the primvar's name, devoid of the "primvars:" namespace.
417  /// This is the name by which clients should refer to the primvar, if
418  /// not by its full attribute name - i.e. they should **not**, in general,
419  /// use GetBaseName(). In the error condition in which this Primvar
420  /// object is not backed by a properly namespaced UsdAttribute, return
421  /// an empty TfToken.
423  TfToken GetPrimvarName() const;
424 
425  /// Does this primvar contain any namespaces other than the "primvars:"
426  /// namespace?
427  ///
428  /// Some clients may only wish to consume primvars that have no extra
429  /// namespaces in their names, for ease of translating to other systems
430  /// that do not allow namespaces.
432  bool NameContainsNamespaces() const;
433 
434  /// \sa UsdAttribute::GetBaseName()
435  TfToken GetBaseName() const { return _attr.GetBaseName(); }
436 
437  /// \sa UsdAttribute::GetNamespace()
438  TfToken GetNamespace() const { return _attr.GetNamespace(); }
439 
440  /// \sa UsdAttribute::SplitName()
441  std::vector<std::string> SplitName() const { return _attr.SplitName(); };
442 
443  /// \sa UsdAttribute::GetTypeName()
444  SdfValueTypeName GetTypeName() const { return _attr.GetTypeName(); }
445 
446  /// Get the attribute value of the Primvar at \p time .
447  ///
448  /// \sa Usd_Handling_Indexed_Primvars for proper handling of
449  /// \ref Usd_Handling_Indexed_Primvars "indexed primvars"
450  template <typename T>
452  return _attr.Get(value, time);
453  }
454 
455  /// Set the attribute value of the Primvar at \p time
456  template <typename T>
457  bool Set(const T& value, UsdTimeCode time = UsdTimeCode::Default()) const {
458  return _attr.Set(value, time);
459  }
460 
461  /// Populates a vector with authored sample times for this primvar.
462  /// Returns false on error.
463  ///
464  /// This considers any timeSamples authored on the associated "indices"
465  /// attribute if the primvar is indexed.
466  ///
467  /// \sa UsdAttribute::GetTimeSamples
469  bool GetTimeSamples(std::vector<double>* times) const;
470 
471  /// Populates a vector with authored sample times in \p interval.
472  ///
473  /// This considers any timeSamples authored on the associated "indices"
474  /// attribute if the primvar is indexed.
475  ///
476  /// \sa UsdAttribute::GetTimeSamplesInInterval
478  bool GetTimeSamplesInInterval(const GfInterval& interval,
479  std::vector<double>* times) const;
480 
481  /// Return true if it is possible, but not certain, that this primvar's
482  /// value changes over time, false otherwise.
483  ///
484  /// This considers time-varyingness of the associated "indices" attribute
485  /// if the primvar is indexed.
486  ///
487  /// \sa UsdAttribute::ValueMightBeTimeVarying
489  bool ValueMightBeTimeVarying() const;
490 
491  /// @}
492 
493  // ---------------------------------------------------------------
494  /// @{
495  /// \anchor UsdGeomPrimvar_Indexed_primvars
496  /// \name Indexed primvars API
497  ///
498  /// For non-constant values of interpolation, it is often the case that the
499  /// same value is repeated many times in the array value of a primvar. An
500  /// indexed primvar can be used in such cases to optimize for data storage
501  /// if the primvar's interpolation is uniform, varying, or vertex.
502  /// For **faceVarying primvars,** however, indexing serves a higher
503  /// purpose (and should be used *only* for this purpose, since renderers
504  /// and OpenSubdiv will assume it) of establishing a surface topology
505  /// for the primvar. That is, faveVarying primvars use indexing to
506  /// unambiguously define discontinuities in their functions at edges
507  /// and vertices. Please see the <a href="http://graphics.pixar.com/opensubdiv/docs/subdivision_surfaces.html#face-varying-interpolation-rules">
508  /// OpenSubdiv documentation on FaceVarying Primvars</a> for more
509  /// information.
510  ///
511  /// To create an indexed primvar, the value of the attribute associated with
512  /// the primvar is set to an array consisting of all the unique values that
513  /// appear in the primvar array. A separate namespaced "indices" attribute
514  /// is set to an integer array containing indices into the array with all
515  /// the unique elements. The final value of the primvar is computed using
516  /// the indices array and the attribute value array.
517  ///
518  /// See also \ref Usd_Handling_Indexed_Primvars
519 
520  /// Sets the indices value of the indexed primvar at \p time.
521  ///
522  /// The values in the indices array must be valid indices into the authored
523  /// array returned by Get(). The element numerality of the primvar's
524  /// 'interpolation' metadata applies to the "indices" array, not the attribute
525  /// value array (returned by Get()).
527  bool SetIndices(const VtIntArray &indices,
529 
530  /// Returns the value of the indices array associated with the indexed
531  /// primvar at \p time.
532  ///
533  /// \sa SetIndices(), \ref Usd_Handling_Indexed_Primvars
535  bool GetIndices(VtIntArray *indices,
537 
538  /// Block the indices that were previously set. This effectively makes an
539  /// indexed primvar no longer indexed. This is useful when overriding an
540  /// existing primvar.
542  void BlockIndices() const;
543 
544  /// Returns true if the primvar is indexed, i.e., if it has an associated
545  /// "indices" attribute.
546  ///
547  /// If you are going to query the indices anyways, prefer to simply
548  /// consult the return-value of GetIndices(), which will be more efficient.
550  bool IsIndexed() const;
551 
552  /// Returns a valid indices attribute if the primvar is indexed. Returns
553  /// an invalid attribute otherwise.
556 
557  /// Returns the existing indices attribute if the primvar is indexed
558  /// or creates a new one.
561 
562  /// Set the index that represents unauthored values in the indices array.
563  ///
564  /// Some apps (like Maya) allow you to author primvars sparsely over a
565  /// surface. Since most apps can't handle sparse primvars, Maya needs to
566  /// provide a value even for the elements it didn't author. This metadatum
567  /// provides a way to recover the information in apps that do support
568  /// sparse authoring / representation of primvars.
569  ///
570  /// The fallback value of unauthoredValuesIndex is -1, which indicates that
571  /// there are no unauthored values.
572  ///
573  /// \sa GetUnauthoredValuesIndex()
575  bool SetUnauthoredValuesIndex(int unauthoredValuesIndex) const;
576 
577  /// Returns the index that represents unauthored values in the indices array.
578  ///
579  /// \sa SetUnauthoredValuesIndex()
581  int GetUnauthoredValuesIndex() const;
582 
583  /// Computes the flattened value of the primvar at \p time.
584  ///
585  /// If the primvar is not indexed or if the value type of this primvar is
586  /// a scalar, this returns the authored value, which is the same as
587  /// \ref Get(). Hence, it's safe to call ComputeFlattened() on non-indexed
588  /// primvars.
589  template <typename ScalarType>
592 
593  /// \overload
594  /// Computes the flattened value of the primvar at \p time as a VtValue.
595  ///
596  /// If the primvar is not indexed or if the value type of this primvar is
597  /// a scalar, this returns the authored value, which is the same as
598  /// \ref Get(). Hence, it's safe to call ComputeFlattened() on non-indexed
599  /// primvars.
601  bool ComputeFlattened(VtValue *value,
603 
604  /// Computes the flattened value of \p attrValue given \p indices.
605  ///
606  /// This method is a static convenience function that performs the main
607  /// work of ComputeFlattened above without needing an instance of a
608  /// UsdGeomPrimvar.
609  ///
610  /// Returns \c false if the value contained in \p attrVal is not a supported
611  /// type for flattening. Otherwise returns \c true. The output
612  /// \p errString variable may be populated with an error string if an error
613  /// is encountered during flattening.
615  static bool ComputeFlattened(VtValue *value, const VtValue &attrVal,
616  const VtIntArray &indices,
617  std::string *errString);
618 
619 
620  /// @}
621 
622  // ---------------------------------------------------------------
623  /// @{
624  /// \anchor UsdGeomPrimvar_Id_primvars
625  /// \name Id attribute API
626  ///
627  /// Often there is the need to identify a prim within a scene (e.g. a mesh
628  /// on which a procedural should operate, or a shader to inherit). A
629  /// string or string[] -typed primvar can be turned into an "Id Path" primvar by
630  /// calling SetIdTarget() with the path of any object on the current stage. When
631  /// the primvar is subsequently queried via Get(), the returned value will
632  /// be the stringified value of the targeted object's path in whatever
633  /// namespace is defined by the querying stage's root layer. In other
634  /// words, authoring an Id primvar into a published model will return the
635  /// path-to-target in the model, but when the model is referenced into a
636  /// larger scene, it will return the complete scene path.
637  ///
638  /// This works by adding a paired UsdRelationship in a ":idFrom" namespace
639  /// "below" the string primvar. Get() evaluates
640  /// UsdRelationship::GetForwardedTargets() to determine the id-string.
641  /// Thus, this mechanism will always produce a unique identifier for every
642  /// object in a scene, regardless of how many times an asset is referenced
643  /// into a scene. Providing a mesh with a unique identifier primvar can be
644  /// especially useful for renderers that allow plugins/shaders access to
645  /// processed scene data based on user-provided string identifiers.
646  ///
647  /// If an Id primvar has both an \em authored string value and a SetIdTarget()'d
648  /// target, the target path takes precedence.
649  ///
650  /// Currently Id primvars can have only a single target, so the only useful
651  /// interpolation is constant.
652  // ---------------------------------------------------------------
653 
654  /// Returns true if the primvar is an Id primvar.
655  ///
656  /// \sa \ref UsdGeomPrimvar_Id_primvars
658  bool IsIdTarget() const;
659 
660  /// This primvar must be of String or StringArray type for this method to
661  /// succeed. If not, a coding error is raised.
662  ///
663  /// \sa \ref UsdGeomPrimvar_Id_primvars
665  bool SetIdTarget(const SdfPath& path) const;
666 
667  /// @}
668 
669  /// Equality comparison. Return true if \a lhs and \a rhs represent the
670  /// same UsdGeomPrimvar, false otherwise.
671  friend bool operator==(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
672  return lhs.GetAttr() == rhs.GetAttr();
673  }
674 
675  /// Inequality comparison. Return false if \a lhs and \a rhs represent the
676  /// same UsdPrimvar, true otherwise.
677  friend bool operator!=(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
678  return !(lhs == rhs);
679  }
680 
681  /// Less-than operator. Returns true if \a lhs < \a rhs.
682  ///
683  /// This simply compares the paths of the underlyingattributes.
684  friend bool operator<(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
685  return lhs.GetAttr().GetPath() < rhs.GetAttr().GetPath();
686  }
687 
688  // hash_value overload for std/hboost hash.
690  friend size_t hash_value(const UsdGeomPrimvar &obj) {
691  return hash_value(obj.GetAttr());
692  }
693 
694 
695 private:
696  friend class UsdGeomImageable;
697  friend class UsdGeomPrimvarsAPI;
698 
699  /// Validate that the given \p name contains the primvars namespace.
700  /// Does not validate name as a legal property identifier
701  static bool _IsNamespaced(const TfToken& name);
702 
703  /// Return \p name prepended with the proper primvars namespace, if
704  /// it is not already prefixed.
705  ///
706  /// Does not validate name as a legal property identifier, but will
707  /// verify that \p name contains no reserved keywords, and will return
708  /// an empty TfToken if it does. If \p quiet is true, the verification
709  /// will be silent
710  static TfToken _MakeNamespaced(const TfToken& name, bool quiet=false);
711 
712  static TfToken const &_GetNamespacePrefix();
713 
714  /// Factory for UsdGeomImageable's use, so that we can encapsulate the
715  /// logic of what discriminates Primvar in this class, while
716  /// preserving the pattern that attributes can only be created
717  /// via their container objects.
718  ///
719  /// The name of the created attribute may or may not be the specified
720  /// \p attrName, due to the possible need to apply property namespacing
721  /// for Primvar.
722  ///
723  /// The behavior with respect to the provided \p typeName
724  /// is the same as for UsdAttributes::Create().
725  ///
726  /// \return an invalid UsdGeomPrimvar if we failed to create a valid
727  /// attribute, a valid UsdGeomPrimvar otherwise. It is not an
728  /// error to create over an existing, compatible attribute.
729  ///
730  /// It is a failed verification for \p prim to be invalid/expired
731  ///
732  /// \sa UsdPrim::CreateAttribute()
733  UsdGeomPrimvar(const UsdPrim& prim, const TfToken& attrName,
734  const SdfValueTypeName &typeName);
735 
736  UsdAttribute _attr;
737 
738  // upon construction, we'll take note of the attrType. If we're a type
739  // that could possibly have an Id associated with it, we'll store that name
740  // so we don't have to pay the cost of constructing that token per-Get().
741  void _SetIdTargetRelName();
742 
743  // Gets or creates the indices attribute corresponding to the primvar.
744  UsdAttribute _GetIndicesAttr(bool create) const;
745 
746  // Helper method for computing the flattened value of an indexed primvar.
747  template<typename ScalarType>
748  static bool _ComputeFlattenedHelper(const VtArray<ScalarType> &authored,
749  const VtIntArray &indices,
750  VtArray<ScalarType> *value,
751  std::string *errString);
752 
753  // Helper function to evaluate the flattened array value of a primvar given
754  // the attribute value and the indices array.
755  template <typename ArrayType>
756  static bool _ComputeFlattenedArray(const VtValue &attrVal,
757  const VtIntArray &indices,
758  VtValue *value,
759  std::string *errString);
760 
761  // Should only be called if _idTargetRelName is set
762  UsdRelationship _GetIdTargetRel(bool create) const;
763  TfToken _idTargetRelName;
764 };
765 
766 // We instantiate the following so we can check and provide the correct value
767 // for Id attributes.
768 template <>
770 
771 template <>
772 USDGEOM_API bool UsdGeomPrimvar::Get(VtStringArray* value, UsdTimeCode time) const;
773 
774 template <>
776 
777 template <typename ScalarType>
778 bool
780 {
781  VtArray<ScalarType> authored;
782  if (!Get(&authored, time))
783  return false;
784 
785  if (!IsIndexed()) {
786  *value = authored;
787  return true;
788  }
789 
790  VtIntArray indices;
791  if (!GetIndices(&indices, time)) {
792  TF_WARN("No indices authored for indexed primvar <%s>.",
793  _attr.GetPath().GetText());
794  return false;
795  }
796 
797  // If the authored array is empty, there's nothing to do.
798  if (authored.empty())
799  return false;
800 
801  std::string errString;
802  bool res = _ComputeFlattenedHelper(authored, indices, value, &errString);
803  if (!errString.empty()) {
804  TF_WARN("For primvar %s: %s",
805  UsdDescribe(_attr).c_str(), errString.c_str());
806  }
807  return res;
808 }
809 
810 template<typename ScalarType>
811 bool
812 UsdGeomPrimvar::_ComputeFlattenedHelper(const VtArray<ScalarType> &authored,
813  const VtIntArray &indices,
814  VtArray<ScalarType> *value,
815  std::string *errString)
816 {
817  value->resize(indices.size());
818  bool success = true;
819 
820  std::vector<size_t> invalidIndexPositions;
821  for (size_t i=0; i < indices.size(); i++) {
822  int index = indices[i];
823  if (index >= 0 && (size_t)index < authored.size()) {
824  (*value)[i] = authored[index];
825  } else {
826  invalidIndexPositions.push_back(i);
827  success = false;
828  }
829  }
830 
831  if (!invalidIndexPositions.empty()) {
832  std::vector<std::string> invalidPositionsStrVec;
833  // Print a maximum of 5 invalid index positions.
834  size_t numElementsToPrint = std::min(invalidIndexPositions.size(),
835  size_t(5));
836  invalidPositionsStrVec.reserve(numElementsToPrint);
837  for (size_t i = 0; i < numElementsToPrint ; ++i) {
838  invalidPositionsStrVec.push_back(
839  TfStringify(invalidIndexPositions[i]));
840  }
841 
842  if (errString) {
843  *errString = TfStringPrintf(
844  "Found %ld invalid indices at positions [%s%s] that are out of "
845  "range [0,%ld).", invalidIndexPositions.size(),
846  TfStringJoin(invalidPositionsStrVec, ", ").c_str(),
847  invalidIndexPositions.size() > 5 ? ", ..." : "",
848  authored.size());
849  }
850  }
851 
852  return success;
853 }
854 
855 
857 
858 #endif // USD_PRIMVAR_H
SDF_API const char * GetText() const
TF_API std::string TfStringPrintf(const char *fmt,...)
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: primvar.h:451
static USDGEOM_API TfToken StripPrimvarsName(const TfToken &name)
static USDGEOM_API bool IsValidPrimvarName(const TfToken &name)
static constexpr UsdTimeCode Default()
Definition: timeCode.h:113
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: attribute.h:431
USDGEOM_API UsdAttribute GetIndicesAttr() const
USD_API TfToken GetBaseName() const
friend bool operator!=(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs)
Definition: primvar.h:677
GT_API const UT_StringHolder time
USDGEOM_API bool ValueMightBeTimeVarying() const
GLsizei const GLchar *const * path
Definition: glcorearb.h:3340
static USDGEOM_API bool IsPrimvar(const UsdAttribute &attr)
USDGEOM_API TfToken GetPrimvarName() const
USDGEOM_API bool GetIndices(VtIntArray *indices, UsdTimeCode time=UsdTimeCode::Default()) const
USD_API SdfValueTypeName GetTypeName() const
Return the "scene description" value type name for this attribute.
TfToken GetNamespace() const
Definition: primvar.h:438
GLuint const GLchar * name
Definition: glcorearb.h:785
USD_API bool HasAuthoredValue() const
USD_API std::string UsdDescribe(const UsdObject &)
Return a human-readable description.
TfToken GetBaseName() const
Definition: primvar.h:435
USDGEOM_API bool NameContainsNamespaces() const
bool ComputeFlattened(VtArray< ScalarType > *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: primvar.h:779
USDGEOM_API int GetUnauthoredValuesIndex() const
Definition: token.h:87
USDGEOM_API bool SetIdTarget(const SdfPath &path) const
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
USD_API std::vector< std::string > SplitName() const
USDGEOM_API bool SetInterpolation(const TfToken &interpolation)
std::vector< std::string > SplitName() const
Definition: primvar.h:441
USD_API bool HasValue() const
GLsizei const GLchar *const * string
Definition: glcorearb.h:813
GLsizei GLenum const void * indices
Definition: glcorearb.h:405
#define TF_WARN
GLhandleARB obj
Definition: glew.h:6266
bool Set(const T &value, UsdTimeCode time=UsdTimeCode::Default()) const
Set the attribute value of the Primvar at time.
Definition: primvar.h:457
USDGEOM_API UsdAttribute CreateIndicesAttr() const
TfToken const & GetName() const
Definition: primvar.h:414
USDGEOM_API friend size_t hash_value(const UsdGeomPrimvar &obj)
Definition: primvar.h:690
Definition: prim.h:132
bool HasAuthoredValue() const
Definition: primvar.h:404
USDGEOM_API bool IsIndexed() const
USD_API TfToken GetNamespace() const
bool Set(const T &value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: attribute.h:462
Definition: types.h:166
Definition: path.h:288
const TfToken & GetName() const
Definition: object.h:229
static USDGEOM_API bool IsValidInterpolation(const TfToken &interpolation)
std::string TfStringJoin(ForwardIterator begin, ForwardIterator end, const char *separator=" ")
Definition: stringUtils.h:364
GLuint res
Definition: glew.h:11549
SdfPath GetPath() const
Definition: object.h:194
SdfValueTypeName GetTypeName() const
Definition: primvar.h:444
USDGEOM_API bool IsIdTarget() const
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1375
GLuint index
Definition: glcorearb.h:785
USDGEOM_API bool HasAuthoredElementSize() const
UsdAttribute const & GetAttr() const
Explicit UsdAttribute extractor.
Definition: primvar.h:391
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
GLsizei const GLfloat * value
Definition: glcorearb.h:823
bool IsDefined() const
Definition: primvar.h:396
USDGEOM_API bool GetTimeSamples(std::vector< double > *times) const
bool HasValue() const
Definition: primvar.h:400
USDGEOM_API bool SetIndices(const VtIntArray &indices, UsdTimeCode time=UsdTimeCode::Default()) const
USDGEOM_API bool HasAuthoredInterpolation() const
#define USDGEOM_API
Definition: api.h:40
std::enable_if<!std::is_enum< T >::value, std::string >::type TfStringify(const T &v)
Definition: stringUtils.h:527
friend bool operator==(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs)
Definition: primvar.h:671
USDGEOM_API bool SetUnauthoredValuesIndex(int unauthoredValuesIndex) const
USDGEOM_API int GetElementSize() const
USDGEOM_API void GetDeclarationInfo(TfToken *name, SdfValueTypeName *typeName, TfToken *interpolation, int *elementSize) const
friend bool operator<(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs)
Definition: primvar.h:684
Definition: value.h:168
USDGEOM_API TfToken GetInterpolation() const
USDGEOM_API bool GetTimeSamplesInInterval(const GfInterval &interval, std::vector< double > *times) const
USDGEOM_API bool SetElementSize(int eltSize)
USDGEOM_API void BlockIndices() const