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  /// Test whether a given \p name contains the "primvars:" prefix
361  ///
363  static bool IsPrimvarRelatedPropertyName(const TfToken& name);
364 
365  /// Returns the \p name, devoid of the "primvars:" token if present,
366  /// otherwise returns the \p name unchanged
368  static TfToken StripPrimvarsName(const TfToken& name);
369 
370  /// Validate that the provided \p interpolation is a valid setting for
371  /// interpolation as defined by \ref Usd_InterpolationVals.
373  static bool IsValidInterpolation(const TfToken &interpolation);
374 
375  /// Convenience function for fetching all information required to
376  /// properly declare this Primvar. The \p name returned is the
377  /// "client name", stripped of the "primvars" namespace, i.e. equivalent to
378  /// GetPrimvarName()
379  ///
380  /// May also be more efficient than querying key individually.
383  TfToken *interpolation, int *elementSize) const;
384 
385  // ---------------------------------------------------------------
386  /// \name UsdAttribute API
387  // ---------------------------------------------------------------
388  /// @{
389 
390  /// Allow UsdGeomPrimvar to auto-convert to UsdAttribute, so you can
391  /// pass a UsdGeomPrimvar to any function that accepts a UsdAttribute or
392  /// const-ref thereto.
393  operator UsdAttribute const& () const { return _attr; }
394 
395  /// Explicit UsdAttribute extractor
396  UsdAttribute const &GetAttr() const { return _attr; }
397 
398  /// Return true if the underlying UsdAttribute::IsDefined(), and in
399  /// addition the attribute is identified as a Primvar. Does not imply
400  /// that the primvar provides a value
401  bool IsDefined() const { return IsPrimvar(_attr); }
402 
403  /// Return true if the underlying attribute has a value, either from
404  /// authored scene description or a fallback.
405  bool HasValue() const { return _attr.HasValue(); }
406 
407  /// Return true if the underlying attribute has an unblocked, authored
408  /// value.
409  bool HasAuthoredValue() const { return _attr.HasAuthoredValue(); }
410 
411  /// \anchor UsdGeomPrimvar_bool
412  /// Return true if this Primvar is valid for querying and authoring
413  /// values and metadata, which is identically equivalent to IsDefined().
414  explicit operator bool() const {
415  return IsDefined() ? &UsdGeomPrimvar::_attr : 0;
416  }
417 
418  /// \sa UsdAttribute::GetName()
419  TfToken const &GetName() const { return _attr.GetName(); }
420 
421  /// Returns the primvar's name, devoid of the "primvars:" namespace.
422  /// This is the name by which clients should refer to the primvar, if
423  /// not by its full attribute name - i.e. they should **not**, in general,
424  /// use GetBaseName(). In the error condition in which this Primvar
425  /// object is not backed by a properly namespaced UsdAttribute, return
426  /// an empty TfToken.
428  TfToken GetPrimvarName() const;
429 
430  /// Does this primvar contain any namespaces other than the "primvars:"
431  /// namespace?
432  ///
433  /// Some clients may only wish to consume primvars that have no extra
434  /// namespaces in their names, for ease of translating to other systems
435  /// that do not allow namespaces.
437  bool NameContainsNamespaces() const;
438 
439  /// \sa UsdAttribute::GetBaseName()
440  TfToken GetBaseName() const { return _attr.GetBaseName(); }
441 
442  /// \sa UsdAttribute::GetNamespace()
443  TfToken GetNamespace() const { return _attr.GetNamespace(); }
444 
445  /// \sa UsdAttribute::SplitName()
446  std::vector<std::string> SplitName() const { return _attr.SplitName(); };
447 
448  /// \sa UsdAttribute::GetTypeName()
449  SdfValueTypeName GetTypeName() const { return _attr.GetTypeName(); }
450 
451  /// Get the attribute value of the Primvar at \p time .
452  ///
453  /// \sa Usd_Handling_Indexed_Primvars for proper handling of
454  /// \ref Usd_Handling_Indexed_Primvars "indexed primvars"
455  template <typename T>
457  return _attr.Get(value, time);
458  }
459 
460  /// Set the attribute value of the Primvar at \p time
461  template <typename T>
462  bool Set(const T& value, UsdTimeCode time = UsdTimeCode::Default()) const {
463  return _attr.Set(value, time);
464  }
465 
466  /// Populates a vector with authored sample times for this primvar.
467  /// Returns false on error.
468  ///
469  /// This considers any timeSamples authored on the associated "indices"
470  /// attribute if the primvar is indexed.
471  ///
472  /// \sa UsdAttribute::GetTimeSamples
474  bool GetTimeSamples(std::vector<double>* times) const;
475 
476  /// Populates a vector with authored sample times in \p interval.
477  ///
478  /// This considers any timeSamples authored on the associated "indices"
479  /// attribute if the primvar is indexed.
480  ///
481  /// \sa UsdAttribute::GetTimeSamplesInInterval
483  bool GetTimeSamplesInInterval(const GfInterval& interval,
484  std::vector<double>* times) const;
485 
486  /// Return true if it is possible, but not certain, that this primvar's
487  /// value changes over time, false otherwise.
488  ///
489  /// This considers time-varyingness of the associated "indices" attribute
490  /// if the primvar is indexed.
491  ///
492  /// \sa UsdAttribute::ValueMightBeTimeVarying
494  bool ValueMightBeTimeVarying() const;
495 
496  /// @}
497 
498  // ---------------------------------------------------------------
499  /// @{
500  /// \anchor UsdGeomPrimvar_Indexed_primvars
501  /// \name Indexed primvars API
502  ///
503  /// For non-constant values of interpolation, it is often the case that the
504  /// same value is repeated many times in the array value of a primvar. An
505  /// indexed primvar can be used in such cases to optimize for data storage
506  /// if the primvar's interpolation is uniform, varying, or vertex.
507  /// For **faceVarying primvars,** however, indexing serves a higher
508  /// purpose (and should be used *only* for this purpose, since renderers
509  /// and OpenSubdiv will assume it) of establishing a surface topology
510  /// for the primvar. That is, faveVarying primvars use indexing to
511  /// unambiguously define discontinuities in their functions at edges
512  /// and vertices. Please see the <a href="http://graphics.pixar.com/opensubdiv/docs/subdivision_surfaces.html#face-varying-interpolation-rules">
513  /// OpenSubdiv documentation on FaceVarying Primvars</a> for more
514  /// information.
515  ///
516  /// To create an indexed primvar, the value of the attribute associated with
517  /// the primvar is set to an array consisting of all the unique values that
518  /// appear in the primvar array. A separate namespaced "indices" attribute
519  /// is set to an integer array containing indices into the array with all
520  /// the unique elements. The final value of the primvar is computed using
521  /// the indices array and the attribute value array.
522  ///
523  /// See also \ref Usd_Handling_Indexed_Primvars
524 
525  /// Sets the indices value of the indexed primvar at \p time.
526  ///
527  /// The values in the indices array must be valid indices into the authored
528  /// array returned by Get(). The element numerality of the primvar's
529  /// 'interpolation' metadata applies to the "indices" array, not the attribute
530  /// value array (returned by Get()).
532  bool SetIndices(const VtIntArray &indices,
534 
535  /// Returns the value of the indices array associated with the indexed
536  /// primvar at \p time.
537  ///
538  /// \sa SetIndices(), \ref Usd_Handling_Indexed_Primvars
540  bool GetIndices(VtIntArray *indices,
542 
543  /// Block the indices that were previously set. This effectively makes an
544  /// indexed primvar no longer indexed. This is useful when overriding an
545  /// existing primvar.
547  void BlockIndices() const;
548 
549  /// Returns true if the primvar is indexed, i.e., if it has an associated
550  /// "indices" attribute.
551  ///
552  /// If you are going to query the indices anyways, prefer to simply
553  /// consult the return-value of GetIndices(), which will be more efficient.
555  bool IsIndexed() const;
556 
557  /// Returns a valid indices attribute if the primvar is indexed. Returns
558  /// an invalid attribute otherwise.
561 
562  /// Returns the existing indices attribute if the primvar is indexed
563  /// or creates a new one.
566 
567  /// Set the index that represents unauthored values in the indices array.
568  ///
569  /// Some apps (like Maya) allow you to author primvars sparsely over a
570  /// surface. Since most apps can't handle sparse primvars, Maya needs to
571  /// provide a value even for the elements it didn't author. This metadatum
572  /// provides a way to recover the information in apps that do support
573  /// sparse authoring / representation of primvars.
574  ///
575  /// The fallback value of unauthoredValuesIndex is -1, which indicates that
576  /// there are no unauthored values.
577  ///
578  /// \sa GetUnauthoredValuesIndex()
580  bool SetUnauthoredValuesIndex(int unauthoredValuesIndex) const;
581 
582  /// Returns the index that represents unauthored values in the indices array.
583  ///
584  /// \sa SetUnauthoredValuesIndex()
586  int GetUnauthoredValuesIndex() const;
587 
588  /// Computes the flattened value of the primvar at \p time.
589  ///
590  /// If the primvar is not indexed or if the value type of this primvar is
591  /// a scalar, this returns the authored value, which is the same as
592  /// \ref Get(). Hence, it's safe to call ComputeFlattened() on non-indexed
593  /// primvars.
594  template <typename ScalarType>
597 
598  /// \overload
599  /// Computes the flattened value of the primvar at \p time as a VtValue.
600  ///
601  /// If the primvar is not indexed or if the value type of this primvar is
602  /// a scalar, this returns the authored value, which is the same as
603  /// \ref Get(). Hence, it's safe to call ComputeFlattened() on non-indexed
604  /// primvars.
606  bool ComputeFlattened(VtValue *value,
608 
609  /// Computes the flattened value of \p attrValue given \p indices.
610  ///
611  /// This method is a static convenience function that performs the main
612  /// work of ComputeFlattened above without needing an instance of a
613  /// UsdGeomPrimvar.
614  ///
615  /// Returns \c false if the value contained in \p attrVal is not a supported
616  /// type for flattening. Otherwise returns \c true. The output
617  /// \p errString variable may be populated with an error string if an error
618  /// is encountered during flattening.
620  static bool ComputeFlattened(VtValue *value, const VtValue &attrVal,
621  const VtIntArray &indices,
622  std::string *errString);
623 
624 
625  /// @}
626 
627  // ---------------------------------------------------------------
628  /// @{
629  /// \anchor UsdGeomPrimvar_Id_primvars
630  /// \name Id attribute API
631  ///
632  /// Often there is the need to identify a prim within a scene (e.g. a mesh
633  /// on which a procedural should operate, or a shader to inherit). A
634  /// string or string[] -typed primvar can be turned into an "Id Path" primvar by
635  /// calling SetIdTarget() with the path of any object on the current stage. When
636  /// the primvar is subsequently queried via Get(), the returned value will
637  /// be the stringified value of the targeted object's path in whatever
638  /// namespace is defined by the querying stage's root layer. In other
639  /// words, authoring an Id primvar into a published model will return the
640  /// path-to-target in the model, but when the model is referenced into a
641  /// larger scene, it will return the complete scene path.
642  ///
643  /// This works by adding a paired UsdRelationship in a ":idFrom" namespace
644  /// "below" the string primvar. Get() evaluates
645  /// UsdRelationship::GetForwardedTargets() to determine the id-string.
646  /// Thus, this mechanism will always produce a unique identifier for every
647  /// object in a scene, regardless of how many times an asset is referenced
648  /// into a scene. Providing a mesh with a unique identifier primvar can be
649  /// especially useful for renderers that allow plugins/shaders access to
650  /// processed scene data based on user-provided string identifiers.
651  ///
652  /// If an Id primvar has both an \em authored string value and a SetIdTarget()'d
653  /// target, the target path takes precedence.
654  ///
655  /// Currently Id primvars can have only a single target, so the only useful
656  /// interpolation is constant.
657  // ---------------------------------------------------------------
658 
659  /// Returns true if the primvar is an Id primvar.
660  ///
661  /// \sa \ref UsdGeomPrimvar_Id_primvars
663  bool IsIdTarget() const;
664 
665  /// This primvar must be of String or StringArray type for this method to
666  /// succeed. If not, a coding error is raised.
667  ///
668  /// \sa \ref UsdGeomPrimvar_Id_primvars
670  bool SetIdTarget(const SdfPath& path) const;
671 
672  /// @}
673 
674  /// Equality comparison. Return true if \a lhs and \a rhs represent the
675  /// same UsdGeomPrimvar, false otherwise.
676  friend bool operator==(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
677  return lhs.GetAttr() == rhs.GetAttr();
678  }
679 
680  /// Inequality comparison. Return false if \a lhs and \a rhs represent the
681  /// same UsdPrimvar, true otherwise.
682  friend bool operator!=(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
683  return !(lhs == rhs);
684  }
685 
686  /// Less-than operator. Returns true if \a lhs < \a rhs.
687  ///
688  /// This simply compares the paths of the underlyingattributes.
689  friend bool operator<(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs) {
690  return lhs.GetAttr().GetPath() < rhs.GetAttr().GetPath();
691  }
692 
693  // hash_value overload for std/hboost hash.
695  friend size_t hash_value(const UsdGeomPrimvar &obj) {
696  return hash_value(obj.GetAttr());
697  }
698 
699 
700 private:
701  friend class UsdGeomImageable;
702  friend class UsdGeomPrimvarsAPI;
703 
704  /// Validate that the given \p name contains the primvars namespace.
705  /// Does not validate name as a legal property identifier
706  static bool _IsNamespaced(const TfToken& name);
707 
708  /// Return \p name prepended with the proper primvars namespace, if
709  /// it is not already prefixed.
710  ///
711  /// Does not validate name as a legal property identifier, but will
712  /// verify that \p name contains no reserved keywords, and will return
713  /// an empty TfToken if it does. If \p quiet is true, the verification
714  /// will be silent
715  static TfToken _MakeNamespaced(const TfToken& name, bool quiet=false);
716 
717  static TfToken const &_GetNamespacePrefix();
718 
719  /// Factory for UsdGeomImageable's use, so that we can encapsulate the
720  /// logic of what discriminates Primvar in this class, while
721  /// preserving the pattern that attributes can only be created
722  /// via their container objects.
723  ///
724  /// The name of the created attribute may or may not be the specified
725  /// \p attrName, due to the possible need to apply property namespacing
726  /// for Primvar.
727  ///
728  /// The behavior with respect to the provided \p typeName
729  /// is the same as for UsdAttributes::Create().
730  ///
731  /// \return an invalid UsdGeomPrimvar if we failed to create a valid
732  /// attribute, a valid UsdGeomPrimvar otherwise. It is not an
733  /// error to create over an existing, compatible attribute.
734  ///
735  /// It is a failed verification for \p prim to be invalid/expired
736  ///
737  /// \sa UsdPrim::CreateAttribute()
738  UsdGeomPrimvar(const UsdPrim& prim, const TfToken& attrName,
739  const SdfValueTypeName &typeName);
740 
741  UsdAttribute _attr;
742 
743  // upon construction, we'll take note of the attrType. If we're a type
744  // that could possibly have an Id associated with it, we'll store that name
745  // so we don't have to pay the cost of constructing that token per-Get().
746  void _SetIdTargetRelName();
747 
748  // Gets or creates the indices attribute corresponding to the primvar.
749  UsdAttribute _GetIndicesAttr(bool create) const;
750 
751  // Helper method for computing the flattened value of an indexed primvar.
752  template<typename ScalarType>
753  static bool _ComputeFlattenedHelper(const VtArray<ScalarType> &authored,
754  const VtIntArray &indices,
755  VtArray<ScalarType> *value,
756  std::string *errString);
757 
758  // Helper function to evaluate the flattened array value of a primvar given
759  // the attribute value and the indices array.
760  template <typename ArrayType>
761  static bool _ComputeFlattenedArray(const VtValue &attrVal,
762  const VtIntArray &indices,
763  VtValue *value,
764  std::string *errString);
765 
766  // Should only be called if _idTargetRelName is set
767  UsdRelationship _GetIdTargetRel(bool create) const;
768  TfToken _idTargetRelName;
769 };
770 
771 // We instantiate the following so we can check and provide the correct value
772 // for Id attributes.
773 template <>
775 
776 template <>
777 USDGEOM_API bool UsdGeomPrimvar::Get(VtStringArray* value, UsdTimeCode time) const;
778 
779 template <>
781 
782 template <typename ScalarType>
783 bool
785 {
786  VtArray<ScalarType> authored;
787  if (!Get(&authored, time))
788  return false;
789 
790  if (!IsIndexed()) {
791  *value = authored;
792  return true;
793  }
794 
795  VtIntArray indices;
796  if (!GetIndices(&indices, time)) {
797  TF_WARN("No indices authored for indexed primvar <%s>.",
798  _attr.GetPath().GetText());
799  return false;
800  }
801 
802  // If the authored array is empty, there's nothing to do.
803  if (authored.empty())
804  return false;
805 
806  std::string errString;
807  bool res = _ComputeFlattenedHelper(authored, indices, value, &errString);
808  if (!errString.empty()) {
809  TF_WARN("For primvar %s: %s",
810  UsdDescribe(_attr).c_str(), errString.c_str());
811  }
812  return res;
813 }
814 
815 template<typename ScalarType>
816 bool
817 UsdGeomPrimvar::_ComputeFlattenedHelper(const VtArray<ScalarType> &authored,
818  const VtIntArray &indices,
819  VtArray<ScalarType> *value,
820  std::string *errString)
821 {
822  value->resize(indices.size());
823  bool success = true;
824 
825  std::vector<size_t> invalidIndexPositions;
826  for (size_t i=0; i < indices.size(); i++) {
827  int index = indices[i];
828  if (index >= 0 && (size_t)index < authored.size()) {
829  (*value)[i] = authored[index];
830  } else {
831  invalidIndexPositions.push_back(i);
832  success = false;
833  }
834  }
835 
836  if (!invalidIndexPositions.empty()) {
837  std::vector<std::string> invalidPositionsStrVec;
838  // Print a maximum of 5 invalid index positions.
839  size_t numElementsToPrint = std::min(invalidIndexPositions.size(),
840  size_t(5));
841  invalidPositionsStrVec.reserve(numElementsToPrint);
842  for (size_t i = 0; i < numElementsToPrint ; ++i) {
843  invalidPositionsStrVec.push_back(
844  TfStringify(invalidIndexPositions[i]));
845  }
846 
847  if (errString) {
848  *errString = TfStringPrintf(
849  "Found %ld invalid indices at positions [%s%s] that are out of "
850  "range [0,%ld).", invalidIndexPositions.size(),
851  TfStringJoin(invalidPositionsStrVec, ", ").c_str(),
852  invalidIndexPositions.size() > 5 ? ", ..." : "",
853  authored.size());
854  }
855  }
856 
857  return success;
858 }
859 
860 
862 
863 #endif // USD_PRIMVAR_H
SDF_API const char * GetText() const
Returns the string representation of this path as a c string.
TF_API std::string TfStringPrintf(const char *fmt,...)
bool Get(T *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: primvar.h:456
static USDGEOM_API TfToken StripPrimvarsName(const TfToken &name)
static USDGEOM_API bool IsValidPrimvarName(const TfToken &name)
GLuint const GLchar * name
Definition: glew.h:1814
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:682
GT_API const UT_StringHolder time
GLuint index
Definition: glew.h:1814
USDGEOM_API bool ValueMightBeTimeVarying() const
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:443
GLhandleARB obj
Definition: glew.h:6236
USD_API bool HasAuthoredValue() const
USD_API std::string UsdDescribe(const UsdObject &)
Return a human-readable description.
TfToken GetBaseName() const
Definition: primvar.h:440
USDGEOM_API bool NameContainsNamespaces() const
bool ComputeFlattened(VtArray< ScalarType > *value, UsdTimeCode time=UsdTimeCode::Default()) const
Definition: primvar.h:784
USDGEOM_API int GetUnauthoredValuesIndex() const
Definition: token.h:87
USDGEOM_API bool SetIdTarget(const SdfPath &path) const
static USDGEOM_API bool IsPrimvarRelatedPropertyName(const TfToken &name)
USD_API std::vector< std::string > SplitName() const
USDGEOM_API bool SetInterpolation(const TfToken &interpolation)
std::vector< std::string > SplitName() const
Definition: primvar.h:446
USD_API bool HasValue() const
GLuint GLuint GLsizei GLenum const void * indices
Definition: glew.h:1253
#define TF_WARN
bool Set(const T &value, UsdTimeCode time=UsdTimeCode::Default()) const
Set the attribute value of the Primvar at time.
Definition: primvar.h:462
USDGEOM_API UsdAttribute CreateIndicesAttr() const
TfToken const & GetName() const
Definition: primvar.h:419
USDGEOM_API friend size_t hash_value(const UsdGeomPrimvar &obj)
Definition: primvar.h:695
Definition: prim.h:132
bool HasAuthoredValue() const
Definition: primvar.h:409
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
GLsizei const GLchar *const * path
Definition: glew.h:6461
GLsizei const GLchar *const * string
Definition: glew.h:1844
SdfPath GetPath() const
Definition: object.h:194
SdfValueTypeName GetTypeName() const
Definition: primvar.h:449
USDGEOM_API bool IsIdTarget() const
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1346
USDGEOM_API bool HasAuthoredElementSize() const
UsdAttribute const & GetAttr() const
Explicit UsdAttribute extractor.
Definition: primvar.h:396
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
bool IsDefined() const
Definition: primvar.h:401
USDGEOM_API bool GetTimeSamples(std::vector< double > *times) const
bool HasValue() const
Definition: primvar.h:405
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:523
vint4 min(const vint4 &a, const vint4 &b)
Definition: simd.h:4694
friend bool operator==(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs)
Definition: primvar.h:676
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
GLsizei const GLfloat * value
Definition: glew.h:1849
friend bool operator<(const UsdGeomPrimvar &lhs, const UsdGeomPrimvar &rhs)
Definition: primvar.h:689
Definition: value.h:174
USDGEOM_API TfToken GetInterpolation() const
USDGEOM_API bool GetTimeSamplesInInterval(const GfInterval &interval, std::vector< double > *times) const
USDGEOM_API bool SetElementSize(int eltSize)
GLuint res
Definition: glew.h:11507
USDGEOM_API void BlockIndices() const