HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
sparseValueWriter.h
Go to the documentation of this file.
1 //
2 // Copyright 2018 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_UTILS_SPARSE_VALUE_WRITER_H
25 #define PXR_USD_USD_UTILS_SPARSE_VALUE_WRITER_H
26 
27 /// \file usdUtils/sparseValueWriter.h
28 ///
29 /// A collection of utilities for authoring time-varying attribute values with
30 /// basic run-length encoding.
31 
32 #include "pxr/pxr.h"
33 
34 #include "pxr/base/vt/value.h"
35 
36 #include "pxr/usd/usdUtils/api.h"
37 #include "pxr/usd/usd/attribute.h"
38 #include "pxr/usd/usd/timeCode.h"
39 
41 
42 /// \class UsdUtilsSparseAttrValueWriter
43 ///
44 /// A utility class for authoring time-varying attribute values with
45 /// simple run-length encoding, by skipping any redundant time-samples.
46 /// Time-samples that are close enough to each other, with relative difference
47 /// smaller than a fixed epsilon value are considered to be equivalent. This is
48 /// to avoid unnecessary authoring of time-samples caused by numerical fuzz in
49 /// certain computations.
50 ///
51 /// For vectors, matrices, and other composite types (like quaternions and
52 /// arrays), each component is compared with the corresponding component for
53 /// closeness. The chosen epsilon value for double precision floating point
54 /// numbers is 1e-12. For single-precision, it is 1e-6 and for half-precision,
55 /// it is 1e-2.
56 ///
57 /// Example c++ usage:
58 /// \code
59 /// UsdGeomSphere sphere = UsdGeomSphere::Define(stage, SdfPath("/Sphere"));
60 /// UsdAttribute radius = sphere.CreateRadiusAttr();
61 /// UsdUtilsSparseAttrValueWriter attrValueWriter(radius,
62 /// /*defaultValue*/ VtValue(1.0));
63 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(1.0));
64 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(2.0));
65 /// attrValueWriter.SetTimeSample(VtValue(10.0), UsdTimeCode(3.0));
66 /// attrValueWriter.SetTimeSample(VtValue(20.0), UsdTimeCode(4.0));
67 /// \endcode
68 ///
69 /// Equivalent python example:
70 /// \code
71 /// sphere = UsdGeom.Sphere.Define(stage, Sdf.Path("/Sphere"))
72 /// radius = sphere.CreateRadiusAttr()
73 /// attrValueWriter = UsdUtils.SparseAttrValueWriter(radius, defaultValue=1.0)
74 /// attrValueWriter.SetTimeSample(10.0, 1.0)
75 /// attrValueWriter.SetTimeSample(10.0, 2.0)
76 /// attrValueWriter.SetTimeSample(10.0, 3.0)
77 /// attrValueWriter.SetTimeSample(20.0, 4.0)
78 /// \endcode
79 ///
80 /// In the above examples, the specified default value of radius (1.0) will not
81 /// be authored into scene description since it matches the fallback value.
82 /// Additionally, the time-sample authored at time=2.0 will be skipped since
83 /// it is redundant. Also note that for correct behavior, the calls to
84 /// SetTimeSample() must be made with sequentially increasing time
85 /// values. If not, a coding error is issued and the authored animation may be
86 /// incorrect.
87 ///
89 public:
90  /// The constructor initializes the data required for run-length encoding of
91  /// time-samples. It also sets the default value of \p attr to
92  /// \p defaultValue, if \p defaultValue is non-empty and different from the
93  /// existing default value of \p attr.
94  ///
95  /// \p defaultValue can be unspecified (or left empty) if you don't
96  /// care about authoring a default value. In this case, the sparse authoring
97  /// logic is initialized with the existing authored default value or
98  /// the fallback value, if \p attr has one.
101  const VtValue &defaultValue=VtValue());
102 
103  /// The constructor initializes the data required for run-length encoding of
104  /// time-samples. It also sets the default value of \p attr to
105  /// \p defaultValue, if \p defaultValue is non-empty and different from
106  /// the existing default value of \p attr.
107  ///
108  /// It \p defaultValue is null or points to an empty VtValue, the sparse
109  /// authoring logic is initialized with the existing authored default value
110  /// or the fallback value, if \p attr has one.
111  ///
112  /// For efficiency, this function swaps out the given \p defaultValue,
113  /// leaving it empty.
115  UsdUtilsSparseAttrValueWriter(const UsdAttribute &attr, VtValue *defaultValue);
116 
117  /// Sets a new time-sample on the attribute with given \p value at the
118  /// given \p time. The time-sample is only authored if it's different
119  /// from the previously set time-sample, in which case the previous
120  /// time-sample is also authored, in order to to end the previous run
121  /// of contiguous identical values and start a new run.
122  ///
123  /// This incurs a copy of \p value. Also, the value will be held in
124  /// memory at least until the next time-sample is written or until the
125  /// SparseAttrValueWriter instance is destroyed.
127  bool SetTimeSample(const VtValue &value, const UsdTimeCode time);
128 
129  /// \overload
130  ///
131  /// For efficiency, this function swaps out the given \p value, leaving
132  /// it empty. The value will be held in memory at least until the next
133  /// time-sample is written or until the SparseAttrValueWriter instance is
134  /// destroyed.
136  bool SetTimeSample(VtValue *value, const UsdTimeCode time);
137 
138  /// Returns the attribute that's held in the sparse value writer.
139  const UsdAttribute & GetAttr() const {
140  return _attr;
141  }
142 
143 private:
144  // Helper method to initialize the sparse authoring scheme.
145  void _InitializeSparseAuthoring(VtValue *defaultValue);
146 
147  // The attribute whose time-samples will be authored via public API.
148  const UsdAttribute _attr;
149 
150  // The time at which previous time-sample was authored.
151  UsdTimeCode _prevTime = UsdTimeCode::Default();
152 
153  // The value at previously authored time-sample.
154  VtValue _prevValue;
155 
156  // Whether a time-sample was written at _prevTime (with value=_prevValue).
157  bool _didWritePrevValue=true;
158 };
159 
160 /// \class UsdUtilsSparseValueWriter
161 ///
162 /// Utility class that manages sparse authoring of a set of UsdAttributes.
163 /// It does this by maintaining a map of UsdAttributes to their corresponding
164 /// UsdUtilsSparseAttrValueWriter objects.
165 ///
166 /// To use this class, simply instantiate an instance of it and invoke
167 /// the SetAttribute() method with various attributes and their associated
168 /// time-samples.
169 ///
170 /// \note If the attribute has a default value, SetAttribute() must be
171 /// called with time=Default first (multiple times, if necessary), followed by
172 /// calls to author time-samples in sequentially increasing time order.
173 ///
174 /// \note This class is not threadsafe.
175 /// In general, authoring to a single USD layer from multiple threads isn't
176 /// threadsafe. Hence, there is little value in making this class threadsafe.
177 ///
178 ///
179 /// Example c++ usage:
180 /// \code
181 /// UsdGeomCylinder cylinder = UsdGeomCylinder::Define(stage, SdfPath("/Cylinder"));
182 /// UsdAttribute radius = cylinder.CreateRadiusAttr();
183 /// UsdAttribute height = cylinder.CreateHeightAttr();
184 /// UsdUtilsSparseValueWriter valueWriter;
185 /// valueWriter.SetAttribute(radius, 2.0, UsdTimeCode::Default());
186 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode::Default());
187 ///
188 /// valueWriter.SetAttribute(radius, 10.0, UsdTimeCode(1.0));
189 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(2.0));
190 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(3.0));
191 /// valueWriter.SetAttribute(radius, 20.0, UsdTimeCode(4.0));
192 ///
193 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode(1.0));
194 /// valueWriter.SetAttribute(height, 2.0, UsdTimeCode(2.0));
195 /// valueWriter.SetAttribute(height, 3.0, UsdTimeCode(3.0));
196 /// valueWriter.SetAttribute(height, 3.0, UsdTimeCode(4.0));
197 /// \endcode
198 ///
199 /// Equivalent python code:
200 /// \code{.py}
201 /// cylinder = UsdGeom.Cylinder.Define(stage, Sdf.Path("/Cylinder"))
202 /// radius = cylinder.CreateRadiusAttr()
203 /// height = cylinder.CreateHeightAttr()
204 /// valueWriter = UsdUtils.SparseValueWriter()
205 /// valueWriter.SetAttribute(radius, 2.0, Usd.TimeCode.Default())
206 /// valueWriter.SetAttribute(height, 2.0, Usd.TimeCode.Default())
207 ///
208 /// valueWriter.SetAttribute(radius, 10.0, 1.0)
209 /// valueWriter.SetAttribute(radius, 20.0, 2.0)
210 /// valueWriter.SetAttribute(radius, 20.0, 3.0)
211 /// valueWriter.SetAttribute(radius, 20.0, 4.0)
212 ///
213 /// valueWriter.SetAttribute(height, 2.0, 1.0)
214 /// valueWriter.SetAttribute(height, 2.0, 2.0)
215 /// valueWriter.SetAttribute(height, 3.0, 3.0)
216 /// valueWriter.SetAttribute(height, 3.0, 4.0)
217 /// \endcode
218 ///
219 /// In the above example,
220 /// <ul><li>The default value of the "height" attribute is not authored into scene
221 /// description since it matches the fallback value.</li>
222 /// <li>Time-samples at time=3.0 and time=4.0 will be skipped for the radius
223 /// attribute.</li>
224 /// <li>For the "height" attribute, the first timesample at time=1.0 will be
225 /// skipped since it matches the default value.</li>
226 /// <li>The last time-sample at time=4.0 will also be skipped for "height"
227 /// since it matches the previously written value at time=3.0.</li>
228 /// </ul>
230 public:
231  /// Sets the value of \p attr to \p value at time \p time. The value
232  /// is written sparsely, i.e., the default value is authored only if
233  /// it is different from the fallback value or the existing default value,
234  /// and any redundant time-samples are skipped when the attribute value does
235  /// not change significantly between consecutive time-samples.
237  bool SetAttribute(const UsdAttribute &attr,
238  const VtValue &value,
240 
241  /// \overload
242  /// For efficiency, this function swaps out the given \p value, leaving
243  /// it empty. The value will be held in memory at least until the next
244  /// time-sample is written or until the SparseAttrValueWriter instance is
245  /// destroyed.
247  bool SetAttribute(const UsdAttribute &attr,
248  VtValue *value,
250 
251  /// \overload
252  template<typename T>
253  bool SetAttribute(const UsdAttribute &attr,
254  T &value,
256  {
257  VtValue val = VtValue::Take(value);
258  return SetAttribute(attr, &val, time);
259  }
260 
261  /// Clears the internal map, thereby releasing all the memory used by
262  /// the sparse value-writers.
264  void Clear() {
265  _attrValueWriterMap.clear();
266  }
267 
268  /// Returns a new vector of UsdUtilsSparseAttrValueWriter populated
269  /// from the attrValueWriter map.
271  std::vector<UsdUtilsSparseAttrValueWriter>
273 
274 private:
275  // Templated helper method used by the two public SetAttribute() methods.
276  template <typename T>
277  bool _SetAttributeImpl(const UsdAttribute &attr,
278  T &value,
279  const UsdTimeCode time);
280 
281  struct _AttrHash {
282  inline size_t operator() (const UsdAttribute &attr) const {
283  return hash_value(attr);
284  }
285  };
286 
287  using _AttrValueWriterMap = std::unordered_map<UsdAttribute,
289  _AttrHash>;
290  _AttrValueWriterMap _attrValueWriterMap;
291 };
292 
294 
295 #endif
static constexpr UsdTimeCode Default()
Definition: timeCode.h:112
const UsdAttribute & GetAttr() const
Returns the attribute that's held in the sparse value writer.
static VtValue Take(T &obj)
Definition: value.h:903
GT_API const UT_StringHolder time
USDUTILS_API UsdUtilsSparseAttrValueWriter(const UsdAttribute &attr, const VtValue &defaultValue=VtValue())
USDUTILS_API bool SetTimeSample(const VtValue &value, const UsdTimeCode time)
USDUTILS_API bool SetAttribute(const UsdAttribute &attr, const VtValue &value, const UsdTimeCode time=UsdTimeCode::Default())
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
GLuint GLfloat * val
Definition: glcorearb.h:1608
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
USDUTILS_API void Clear()
USDUTILS_API std::vector< UsdUtilsSparseAttrValueWriter > GetSparseAttrValueWriters() const
Definition: core.h:1131
#define USDUTILS_API
Definition: api.h:40
size_t hash_value(const CH_ChannelRef &ref)
bool SetAttribute(const UsdAttribute &attr, T &value, const UsdTimeCode time=UsdTimeCode::Default())
Definition: value.h:164