Mitsuba Renderer  0.5.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
track.h
Go to the documentation of this file.
1 /*
2  This file is part of Mitsuba, a physically based rendering system.
3 
4  Copyright (c) 2007-2014 by Wenzel Jakob and others.
5 
6  Mitsuba is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License Version 3
8  as published by the Free Software Foundation.
9 
10  Mitsuba is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 #if !defined(__MITSUBA_CORE_TRACK_H_)
21 #define __MITSUBA_CORE_TRACK_H_
22 
23 #include <mitsuba/core/quat.h>
25 #include <set>
26 
28 
29 template <typename T> class AnimationTrack;
30 
31 /**
32  * \brief Base class of animation tracks
33  * \ingroup librender
34  */
36  template<typename T> friend class AnimationTrack;
37 public:
38  enum EType {
39  EInvalid = 0,
40  ETranslationX = 1,
41  ETranslationY = 2,
42  ETranslationZ = 3,
43  ETranslationXYZ = 4,
44  EScaleX = 5,
45  EScaleY = 6,
46  EScaleZ = 7,
47  EScaleXYZ = 8,
48  ERotationX = 9,
49  ERotationY = 10,
50  ERotationZ = 11,
51  ERotationQuat = 12
52  };
53 
54  /// Return the type of this track
55  inline EType getType() const { return m_type; }
56 
57  /// Set the time value of a certain keyframe
58  inline void setTime(size_t idx, Float time) { m_times[idx] = time; }
59 
60  /// Return the time value of a certain keyframe
61  inline Float getTime(size_t idx) const { return m_times[idx]; }
62 
63  /// Return the number of keyframes
64  inline size_t getSize() const { return m_times.size(); }
65 
66  /// Serialize to a binary data stream
67  virtual void serialize(Stream *stream) const = 0;
68 
69  /// Clone this track
70  virtual AbstractAnimationTrack *clone() const = 0;
71 
73 protected:
74  AbstractAnimationTrack(EType type, size_t nKeyframes)
75  : m_type(type), m_times(nKeyframes) { }
76 
78 protected:
80  std::vector<Float> m_times;
81 };
82 
83 /**
84  * \brief Parameterizable animation track
85  * \ingroup librender
86  */
87 template <typename T> class AnimationTrack : public AbstractAnimationTrack {
88 public:
89  typedef T ValueType;
90 
91  AnimationTrack(EType type, size_t nKeyframes = 0)
92  : AbstractAnimationTrack(type, nKeyframes), m_values(nKeyframes) { }
93 
94  AnimationTrack(EType type, Stream *stream)
95  : AbstractAnimationTrack(type, stream->readSize()) {
96  m_values.resize(m_times.size());
97  stream->readFloatArray(&m_times[0], m_times.size());
98  for (size_t i=0; i<m_values.size(); ++i)
99  unserialize(stream, m_values[i]);
100  }
101 
102  /// Copy constructor
104  : AbstractAnimationTrack(track->getType(), track->getSize()) {
105  m_times = track->m_times;
106  m_values = track->m_values;
107  }
108 
109  /// Set the value of a certain keyframe
110  inline void setValue(size_t idx, const ValueType &value) { m_values[idx] = value; }
111 
112  /// Return the value of a certain keyframe
113  inline const ValueType &getValue(size_t idx) const { return m_values[idx]; }
114 
115  /// Reserve space for a certain number of entries
116  inline void reserve(size_t count) { m_times.reserve(count); m_values.reserve(count); }
117 
118  /// Append a value
119  inline void append(Float time, const ValueType &value) {
120  m_times.push_back(time);
121  m_values.push_back(value);
122  }
123 
124  /// Clone this instance
126  return new AnimationTrack(this);
127  }
128 
129  /// Prepend a transformation to every entry of this track
130  void prependTransformation(const ValueType &value) {
131  for (size_t i=0; i<m_values.size(); ++i)
132  m_values[i] = concatenateTransformations(m_values[i], value);
133  }
134 
135  /// Append a transformation to every entry of this track
136  void appendTransformation(const ValueType &value) {
137  for (size_t i=0; i<m_values.size(); ++i)
138  m_values[i] = concatenateTransformations(value, m_values[i]);
139  }
140 
141  /// Serialize to a binary data stream
142  inline void serialize(Stream *stream) const {
143  stream->writeUInt(m_type);
144  stream->writeSize(m_times.size());
145  stream->writeFloatArray(&m_times[0], m_times.size());
146  for (size_t i=0; i<m_values.size(); ++i)
147  serialize(stream, m_values[i]);
148  }
149 
150  /// Evaluate the animation track at an arbitrary time value
151  inline ValueType eval(Float time) const {
152  SAssert(m_times.size() > 0);
153  std::vector<Float>::const_iterator entry =
154  std::lower_bound(m_times.begin(), m_times.end(), time);
155  size_t idx0 = (size_t) std::max(
156  (ptrdiff_t) (entry - m_times.begin()) - 1,
157  (ptrdiff_t) 0);
158  size_t idx1 = std::min(idx0+1, m_times.size()-1);
159  Float t = 0.5f;
160  if (m_times[idx0] != m_times[idx1]) {
161  time = std::max(m_times[idx0], std::min(m_times[idx1], time));
162  t = (time-m_times[idx0]) / (m_times[idx1]-m_times[idx0]);
163  }
164  return lerp(idx0, idx1, t);
165  }
166 
167 private:
168  struct SortPredicate {
169  inline bool operator()(const std::pair<Float, ValueType> &p1,
170  const std::pair<Float, ValueType> &p2) const {
171  return p1.first < p2.first;
172  }
173  };
174 
175  struct UniqueTimePredicate {
176  inline bool operator()(const std::pair<Float, ValueType> &p1,
177  const std::pair<Float, ValueType> &p2) const {
178  return p1.first == p2.first;
179  }
180  };
181 
182 public:
183  /**
184  * \brief Sort all animation tracks and remove
185  * unnecessary data (for user-provided input)
186  *
187  * \return \c false if this animation track was deemed to be "trivial"
188  * after the cleanup (for instance, it only contains (0,0,0) translation operations)
189  */
191  SAssert(m_values.size() == m_times.size());
192  if (m_values.size() == 0)
193  return false;
194 
195  std::vector< std::pair<Float, ValueType> > temp(m_values.size());
196  for (size_t i=0; i<m_values.size(); ++i)
197  temp[i] = std::make_pair(m_times[i], m_values[i]);
198  std::sort(temp.begin(), temp.end(), SortPredicate());
199 
200  m_times.clear(); m_values.clear();
201  m_times.push_back(temp[0].first);
202  m_values.push_back(temp[0].second);
203 
204  for (size_t i=1; i<temp.size(); ++i) {
205  Float time = temp[i].first;
206  const ValueType &value = temp[i].second;
207 
208  if (m_times.back() == time)
209  SLog(EError, "Duplicate time value in animated transformation!");
210 
211  /* Ignore irrelevant keys */
212  if (i+1 < temp.size() && value == temp[i+1].second &&
213  value == m_values.back())
214  continue;
215  else if (i+1 == temp.size() && value == m_values.back())
216  continue;
217 
218  m_times.push_back(time);
219  m_values.push_back(value);
220  }
221 
222  return !(m_values.size() == 0 || (m_values.size() == 1 && isNoOp(m_values[0])));
223  }
224 protected:
225  /// Evaluate the animation track using linear interpolation
226  inline ValueType lerp(size_t idx0, size_t idx1, Float t) const;
227 
228  /// Is this a "no-op" transformation?
229  inline bool isNoOp(const ValueType &value) const;
230 
231  /// Concatenate two transformations
232  inline ValueType concatenateTransformations(
233  const ValueType &value1, const ValueType &value2) const;
234 
235  inline void unserialize(Stream *stream, ValueType &value) {
236  value = stream->readElement<ValueType>();
237  }
238 
239  inline void serialize(Stream *stream, const ValueType &value) const {
240  stream->writeElement<ValueType>(value);
241  }
242 private:
243  std::vector<ValueType> m_values;
244 };
245 
246 template<typename T> inline T AnimationTrack<T>::lerp(size_t idx0, size_t idx1, Float t) const {
247  return m_values[idx0] * (1-t) + m_values[idx1] * t;
248 }
249 
250 /// Partial specialization for quaternions (uses \ref slerp())
251 template<> inline Quaternion AnimationTrack<Quaternion>::lerp(size_t idx0, size_t idx1, Float t) const {
252  return slerp(m_values[idx0], m_values[idx1], t);
253 }
254 
255 template<typename T> inline T AnimationTrack<T>::concatenateTransformations(
256  const T &value1, const T &value2) const {
257  return value1 * value2;
258 }
259 
261  const Vector &value1, const Vector &value2) const {
262  if (m_type == ETranslationXYZ)
263  return value1 + value2;
264  else
265  return Vector(value1.x * value2.x, value1.y * value2.y, value1.z * value2.z);
266 }
267 
269  const Point &value1, const Point &value2) const {
270  return value1 + value2;
271 }
272 
274  const Float &value1, const Float &value2) const {
275  if (m_type == ETranslationX || m_type == ETranslationY || m_type == ETranslationZ)
276  return value1 + value2;
277  else
278  return value1 * value2;
279 }
280 
281 template<typename T> inline bool AnimationTrack<T>::isNoOp(const ValueType &value) const {
282  return false;
283 }
284 
285 template<> inline bool AnimationTrack<Float>::isNoOp(const Float &value) const {
286  if ((m_type == ETranslationX || m_type == ETranslationY || m_type == ETranslationZ) && value == 0)
287  return true;
288  else if ((m_type == ERotationX || m_type == ERotationY || m_type == ERotationZ) && value == 0)
289  return true;
290  else if ((m_type == EScaleX || m_type == EScaleY || m_type == EScaleZ) && value == 1)
291  return true;
292  return false;
293 }
294 
295 template<> inline bool AnimationTrack<Vector>::isNoOp(const Vector &value) const {
296  if (m_type == ETranslationXYZ && value.isZero())
297  return true;
298  else if (m_type == EScaleXYZ && (value.x == 1 && value.y == 1 && value.z == 1))
299  return true;
300  return false;
301 }
302 
303 template<> inline bool AnimationTrack<Quaternion>::isNoOp(const Quaternion &value) const {
304  return value.isIdentity();
305 }
306 
307 template<> inline void AnimationTrack<Point>::unserialize(Stream *stream, Point &value) {
308  value = Point(stream);
309 }
310 
311 template<> inline void AnimationTrack<Point>::serialize(Stream *stream, const Point &value) const {
312  value.serialize(stream);
313 }
314 
315 template<> inline void AnimationTrack<Vector>::unserialize(Stream *stream, Vector &value) {
316  value = Vector(stream);
317 }
318 
319 template<> inline void AnimationTrack<Vector>::serialize(Stream *stream, const Vector &value) const {
320  value.serialize(stream);
321 }
322 
323 template<> inline void AnimationTrack<Quaternion>::unserialize(Stream *stream, Quaternion &value) {
324  value = Quaternion(stream);
325 }
326 
327 template<> inline void AnimationTrack<Quaternion>::serialize(Stream *stream, const Quaternion &value) const {
328  value.serialize(stream);
329 }
330 
331 /**
332  * \brief Animated transformation with an underlying keyframe representation
333  * \ingroup librender
334  */
336 private:
337  /// Internal functor used by \ref eval() and \ref SimpleCache
338  struct MTS_EXPORT_CORE TransformFunctor {
339  public:
340  inline TransformFunctor(const std::vector<AbstractAnimationTrack *> &tracks)
341  : m_tracks(tracks) {}
342 
343  void operator()(const Float &time, Transform &trafo) const;
344  private:
345  const std::vector<AbstractAnimationTrack *> &m_tracks;
346  };
347 public:
348  /**
349  * \brief Create a new animated transformation
350  *
351  * When the transformation is constant (i.e. there are no
352  * animation tracks), the supplied parameter specifies the
353  * target value.
354  */
356  : m_transform(trafo) { }
357 
358  /// Unserialized an animated transformation from a binary data stream
359  AnimatedTransform(Stream *stream);
360 
361  /// Copy constructor
362  AnimatedTransform(const AnimatedTransform *trafo);
363 
364  /// Return the number of associated animation tracks
365  inline size_t getTrackCount() const { return m_tracks.size(); }
366 
367  /// Find a track of the given type
369 
370  /// Find a track of the given type
371  const AbstractAnimationTrack *findTrack(AbstractAnimationTrack::EType type) const;
372 
373  /// Look up one of the tracks by index
374  inline AbstractAnimationTrack *getTrack(size_t idx) { return m_tracks[idx]; }
375 
376  /// Look up one of the tracks by index (const version)
377  inline const AbstractAnimationTrack *getTrack(size_t idx) const { return m_tracks[idx]; }
378 
379  /// Return the used keyframes as a set
380  void collectKeyframes(std::set<Float> &result) const;
381 
382  /// Append an animation track
383  void addTrack(AbstractAnimationTrack *track);
384 
385  /**
386  * \brief Convenience function, which appends a linear transformation to the track
387  *
388  * Internally, a polar decomposition is used to split the transformation into scale,
389  * translation, and rotation, which are all separately interpolated.
390  *
391  * \remark Remember to run \ref sortAndSimplify() after adding all transformations.
392  */
393  void appendTransform(Float time, const Transform &trafo);
394 
395  /**
396  * \brief Compute the transformation for the specified time value
397  *
398  * Note that the returned reference leads to a thread-local cache.
399  * This means that it will become invalidated at the next call
400  * to this function.
401  */
402  inline const Transform &eval(Float t) const {
403  if (EXPECT_TAKEN(m_tracks.size() == 0))
404  return m_transform;
405  else
406  return m_cache.get(TransformFunctor(m_tracks), t);
407  }
408 
409  /// Is the animation static?
410  inline bool isStatic() const { return m_tracks.size() == 0; }
411 
412  /**
413  * \brief Sort all animation tracks and remove unnecessary
414  * data (for user-provided input)
415  */
416  void sortAndSimplify();
417 
418  /// Transform a point by an affine / non-projective matrix
419  inline Point transformAffine(Float t, const Point &p) const {
420  return eval(t).transformAffine(p);
421  }
422 
423  /// Transform a point by an affine / non-projective matrix (no temporaries)
424  inline void transformAffine(Float t, const Point &p, Point &dest) const {
425  eval(t).transformAffine(p, dest);
426  }
427 
428  /// Transform a ray by an affine / non-projective matrix
429  inline Ray transformAffine(Float t, const Ray &r) const {
430  return eval(t).transformAffine(r);
431  }
432 
433  /// Transform a ray by an affine / non-projective matrix (no temporaries)
434  inline void transformAffine(Float t, const Ray &r, Ray &dest) const {
435  eval(t).transformAffine(r, dest);
436  }
437 
438  /// Matrix-vector multiplication for points in 3d space
439  inline Point operator()(Float t, const Point &p) const {
440  return eval(t).transformAffine(p);
441  }
442 
443  /// Matrix-vector multiplication for points in 3d space (no temporaries)
444  inline void operator()(Float t, const Point &p, Point &dest) const {
445  eval(t).operator()(p, dest);
446  }
447 
448  /// Matrix-vector multiplication for vectors in 3d space
449  inline Vector operator()(Float t, const Vector &v) const {
450  return eval(t).operator()(v);
451  }
452 
453  /// Matrix-vector multiplication for vectors in 3d space (no temporaries)
454  inline void operator()(Float t, const Vector &v, Vector &dest) const {
455  eval(t).operator()(v, dest);
456  }
457 
458  /// Matrix-vector multiplication for normals in 3d space
459  inline Normal operator()(Float t, const Normal &n) const {
460  return eval(t).operator()(n);
461  }
462 
463  /// Matrix-vector multiplication for normals in 3d space (no temporaries)
464  inline void operator()(Float t, const Normal &n, Normal &dest) const {
465  eval(t).operator()(n, dest);
466  }
467 
468  /// \brief Transform a ray
469  inline Ray operator()(Float t, const Ray &r) const {
470  return eval(t).operator()(r);
471  }
472 
473  /// Transform a ray (no temporaries)
474  inline void operator()(Float t, const Ray &r, Ray &dest) const {
475  eval(t).operator()(r, dest);
476  }
477 
478  /// Prepend a scale transformation to the transform (this is often useful)
479  void prependScale(const Vector &scale);
480 
481  /// Serialize to a binary data stream
482  void serialize(Stream *stream) const;
483 
484  /// Return the extents along the time axis
485  AABB1 getTimeBounds() const;
486 
487  /// Return an axis-aligned box bounding the amount of translation
488  AABB getTranslationBounds() const;
489 
490  /// Compute the spatial bounds of a transformed (static) AABB
491  AABB getSpatialBounds(const AABB &aabb) const;
492 
493  /// Return a human-readable string description
494  std::string toString() const;
495 
497 protected:
498  /// Virtual destructor
499  virtual ~AnimatedTransform();
500 private:
501  std::vector<AbstractAnimationTrack *> m_tracks;
502  mutable SimpleCache<Float, Transform> m_cache;
503  Transform m_transform;
504 };
505 
507 
508 #endif /* __MITSUBA_CORE_TRACK_H_ */
std::vector< Float > m_times
Definition: track.h:80
void appendTransformation(const ValueType &value)
Append a transformation to every entry of this track.
Definition: track.h:136
void setValue(size_t idx, const ValueType &value)
Set the value of a certain keyframe.
Definition: track.h:110
void append(Float time, const ValueType &value)
Append a value.
Definition: track.h:119
Normal operator()(Float t, const Normal &n) const
Matrix-vector multiplication for normals in 3d space.
Definition: track.h:459
Vector concatenateTransformations(const Vector &value1, const Vector &value2) const
Definition: track.h:260
AnimationTrack(EType type, size_t nKeyframes=0)
Definition: track.h:91
size_t getSize() const
Return the number of keyframes.
Definition: track.h:64
Three-dimensional normal data structure.
Definition: normal.h:39
void transformAffine(Float t, const Point &p, Point &dest) const
Transform a point by an affine / non-projective matrix (no temporaries)
Definition: track.h:424
Definition: fwd.h:102
T readElement()
Read an element from the stream (uses partial template specialization to select a method appropriate ...
Definition: stream.h:508
Ray transformAffine(Float t, const Ray &r) const
Transform a ray by an affine / non-projective matrix.
Definition: track.h:429
EType m_type
Definition: track.h:79
Base class of animation tracks.
Definition: track.h:35
T ValueType
Definition: track.h:89
void serialize(Stream *stream) const
Serialize to a binary data stream.
Definition: track.h:142
TVector3< Float > Vector
Definition: fwd.h:113
ValueType eval(Float time) const
Evaluate the animation track at an arbitrary time value.
Definition: track.h:151
AbstractAnimationTrack * getTrack(size_t idx)
Look up one of the tracks by index.
Definition: track.h:374
Ray operator()(Float t, const Ray &r) const
Transform a ray.
Definition: track.h:469
bool isNoOp(const Float &value) const
Definition: track.h:285
void writeUInt(unsigned int value)
Write an unsigned int (32 bit) to the stream.
Parameterizable animation track.
Definition: track.h:29
TQuaternion< T > slerp(const TQuaternion< T > &q1, const TQuaternion< T > &_q2, Float t)
Definition: quat.h:356
#define MTS_EXPORT_CORE
Definition: getopt.h:29
#define SLog(level, fmt,...)
Write a Log message to the console (static version - to be used outside of classes that derive from O...
Definition: logger.h:49
size_t getTrackCount() const
Return the number of associated animation tracks.
Definition: track.h:365
void operator()(Float t, const Ray &r, Ray &dest) const
Transform a ray (no temporaries)
Definition: track.h:474
bool sortAndSimplify()
Sort all animation tracks and remove unnecessary data (for user-provided input)
Definition: track.h:190
void unserialize(Stream *stream, ValueType &value)
Definition: track.h:235
#define MTS_NAMESPACE_BEGIN
Definition: platform.h:137
void serialize(Stream *stream, const Point &value) const
Definition: track.h:311
EType getType() const
Return the type of this track.
Definition: track.h:55
const ValueType & getValue(size_t idx) const
Return the value of a certain keyframe.
Definition: track.h:113
Quaternion lerp(size_t idx0, size_t idx1, Float t) const
Definition: track.h:251
AbstractAnimationTrack * clone() const
Clone this instance.
Definition: track.h:125
const Transform & eval(Float t) const
Compute the transformation for the specified time value.
Definition: track.h:402
Definition: fwd.h:103
bool isStatic() const
Is the animation static?
Definition: track.h:410
void unserialize(Stream *stream, Point &value)
Definition: track.h:307
void writeFloatArray(const Float *data, size_t size)
Write an array of floating point values (configured precision) to the stream.
Definition: stream.h:280
TPoint3< Float > Point
Definition: fwd.h:136
AnimationTrack(const AnimationTrack *track)
Copy constructor.
Definition: track.h:103
Axis-aligned bounding box data structure in three dimensions.
Definition: aabb.h:437
void transformAffine(Float t, const Ray &r, Ray &dest) const
Transform a ray by an affine / non-projective matrix (no temporaries)
Definition: track.h:434
virtual ~AbstractAnimationTrack()
Definition: track.h:77
void writeElement(T value)
Write an element to the stream (uses partial template specialization to select a method appropriate t...
Definition: stream.h:512
#define SAssert(cond)
``Static&#39;&#39; assertion (to be used outside of classes that derive from Object)
Definition: logger.h:79
void operator()(Float t, const Normal &n, Normal &dest) const
Matrix-vector multiplication for normals in 3d space (no temporaries)
Definition: track.h:464
Abstract seekable stream class.
Definition: stream.h:58
#define MTS_DECLARE_CLASS()
This macro must be used in the initial definition in classes that derive from Object.
Definition: class.h:158
void operator()(Float t, const Point &p, Point &dest) const
Matrix-vector multiplication for points in 3d space (no temporaries)
Definition: track.h:444
Encapsulates a 4x4 linear transformation and its inverse.
Definition: transform.h:33
void readFloatArray(Float *data, size_t size)
Write an array of floating point values (configured precision) to the stream.
Definition: stream.h:433
Definition: fwd.h:65
Definition: fwd.h:96
Error message, causes an exception to be thrown.
Definition: formatter.h:33
void setTime(size_t idx, Float time)
Set the time value of a certain keyframe.
Definition: track.h:58
EType
Definition: track.h:38
void prependTransformation(const ValueType &value)
Prepend a transformation to every entry of this track.
Definition: track.h:130
void serialize(Stream *stream, const ValueType &value) const
Definition: track.h:239
AnimationTrack(EType type, Stream *stream)
Definition: track.h:94
Animated transformation with an underlying keyframe representation.
Definition: track.h:335
AnimatedTransform(const Transform &trafo=Transform())
Create a new animated transformation.
Definition: track.h:355
TQuaternion< Float > Quaternion
Definition: fwd.h:150
Float getTime(size_t idx) const
Return the time value of a certain keyframe.
Definition: track.h:61
Point transformAffine(Float t, const Point &p) const
Transform a point by an affine / non-projective matrix.
Definition: track.h:419
Point operator()(Float t, const Point &p) const
Matrix-vector multiplication for points in 3d space.
Definition: track.h:439
Definition: fwd.h:100
Parent of all Mitsuba classes.
Definition: object.h:38
void reserve(size_t count)
Reserve space for a certain number of entries.
Definition: track.h:116
const AbstractAnimationTrack * getTrack(size_t idx) const
Look up one of the tracks by index (const version)
Definition: track.h:377
void writeSize(size_t value)
Write a size value to the stream.
Definition: stream.h:214
#define MTS_NAMESPACE_END
Definition: platform.h:138
void operator()(Float t, const Vector &v, Vector &dest) const
Matrix-vector multiplication for vectors in 3d space (no temporaries)
Definition: track.h:454
Vector operator()(Float t, const Vector &v) const
Matrix-vector multiplication for vectors in 3d space.
Definition: track.h:449
Generic thread-local storage for caching evaluations of expensive function calls. ...
Definition: simplecache.h:71