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