HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_TransformUtil.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_TransformUtil.h (UT Library, C++)
7  *
8  * COMMENTS:
9  */
10 
11 #ifndef __UT_TRANSFORMUTIL_H_INCLUDED__
12 #define __UT_TRANSFORMUTIL_H_INCLUDED__
13 
14 /// @file
15 /// Additional utilities for dealing with transforms
16 
17 #include "UT_API.h"
18 #include "UT_Array.h"
19 #include "UT_Assert.h"
20 #include "UT_Matrix3.h"
21 #include "UT_Matrix4.h"
22 #include "UT_Quaternion.h"
23 #include "UT_SmallArray.h"
24 #include "UT_Vector3.h"
25 #include "UT_Vector4.h"
26 #include <SYS/SYS_Math.h>
27 
28 /// Scale inheritance modes
30 {
31  /// simple inheritance: W = L * pW
32  DEFAULT = 0,
33 
34  /// child doesn't scale with the parent local scales, but local translation
35  /// is scaled: W = SR * pLS^-1 * T * pW
36  /// (Maya segment scale compensation)
38 
39  /// local translation is scaled as before but parent local scaling is also
40  /// reapplied by the child in local space: W = pLS * SR * pLS^-1 * T * pW
41  /// (Softimage hierarchical scaling)
43 
44  /// local translation is not scaled, but parent local scaling is reapplied
45  /// by the child in local space: W = pLS * SRT * pLS^-1 * pW
46  SCALE_ONLY,
47 
48  /// child completely ignores any parent local scaling:
49  /// W = SRT * pLS^-1 * pW
51 };
52 
53 /// Combine a local transform on top of another with scale inheritance options
54 /// L is modified to contain the effective local transform on return for t.
55 template<typename PREC>
58  const UT_Matrix4T<PREC>& L, /// local transform
59  const UT_Matrix4T<PREC>& pW, /// parent world transform
60  const UT_Matrix4T<PREC>& pL, /// parent local transform
62  UT_Matrix4T<PREC>* effective_local = nullptr);
63 
64 /// Extract relative transform with scale inheritance
65 template<typename PREC>
68  const UT_Matrix4T<PREC>& W, /// source world transform
69  const UT_Matrix4T<PREC>& pW, /// target parent world
70  const UT_Matrix4T<PREC>& pL, /// target parent local
72  UT_Matrix4T<PREC>* effective_local = nullptr);
73 
74 /// Method of slerp for blending
75 enum class UT_SLERP_METHOD
76 {
77  NLERP, /// normalized lerp of quaternion
78  ACCURATE, /// use iterative method
79 };
80 
81 /// Flip method for slerp to ensure consistency during blending
83 {
84  FIRST, /// use hemisphere of first quaternion
85  SUCCESSIVE, /// compare each adjacent quaternions when using NLERP
86 };
87 
88 /// Spherically blend transforms by decomposing into separate quaternions
89 template<
90  typename PREC,
91  bool NORMALIZE_WEIGHTS = true,
94 >
96 UTslerp(const UT_Array<UT_Matrix4T<PREC>> &xforms,
97  const UT_Array<PREC> &input_weights);
98 
99 
100 ///////////////////////////////////////////////////////////////////////////////
101 //
102 // Implementations
103 //
104 
105 template<typename PREC>
106 inline UT_Matrix4T<PREC>
108  const UT_Matrix4T<PREC>& L, /// local transform
109  const UT_Matrix4T<PREC>& pW, /// parent world transform
110  const UT_Matrix4T<PREC>& pL, /// parent local transform
112  UT_Matrix4T<PREC>* effective_local)
113 {
114  // W: child world transform
115  // T,R,S: child local translation, rotation and scale
116  // pW: parent world transform
117  // pT, pR, pS: parent translation, rotation and scale
118  // pL: parent local transform
119  // pLT, pLR, pLS: parent local translate, rotation and scale
120 
121  UT_Matrix3T<PREC> pLS{ 1 };
122  UT_Matrix3T<PREC> pLS_inv{ 1 };
123 
124  UT_Matrix4T<PREC> RS = L;
125  UT_Vector3T<PREC> _t{ 0.0, 0.0, 0.0 };
126  RS.setTranslates(_t);
127 
128  if (effective_local && effective_local != &L)
129  *effective_local = L;
130 
131  UT_Matrix4T<PREC> T{ 1.0 };
132  L.getTranslates(_t);
133  T.setTranslates(_t);
134 
135  UT_Matrix4T<PREC> my_xform{ 1 };
136 
137  switch (mode)
138  {
140  {
141  my_xform = L * pW;
142  break;
143  }
145  {
146  UT_Matrix3T<PREC> parent_local(pL);
147  parent_local.polarDecompose(&pLS);
148  pLS.invert(pLS_inv);
149 
150  my_xform = RS * UT_Matrix4T<PREC>(pLS_inv) * T * pW;
151  break;
152  }
154  {
155  UT_Matrix3T<PREC> parent_local(pL);
156  parent_local.polarDecompose(&pLS);
157  pLS.invert(pLS_inv);
158 
159  my_xform = UT_Matrix4T<PREC>(pLS) * RS * UT_Matrix4T<PREC>(pLS_inv)
160  * T * pW;
161  // NB: effective_local here is same as SCALE_ONLY case because
162  // it's for the child transforms
163  if (effective_local)
164  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
165  break;
166  }
168  {
169  UT_Matrix3T<PREC> parent_local(pL);
170  parent_local.polarDecompose(&pLS);
171  pLS.invert(pLS_inv);
172 
173  my_xform = UT_Matrix4T<PREC>(pLS) * L * UT_Matrix4T<PREC>(pLS_inv)
174  * pW;
175  if (effective_local)
176  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
177  break;
178  }
180  {
181  UT_Matrix3T<PREC> parent_local(pL);
182  parent_local.polarDecompose(&pLS);
183  pLS.invert(pLS_inv);
184 
185  my_xform = L * UT_Matrix4T<PREC>(pLS_inv) * pW;
186  break;
187  }
188  default:
189  {
190  my_xform = L * pW;
191  break;
192  }
193  }
194  return my_xform;
195 }
196 
197 /// Extract relative transform with scale inheritance
198 template<typename PREC>
199 inline UT_Matrix4T<PREC>
201  const UT_Matrix4T<PREC>& W,
202  const UT_Matrix4T<PREC>& pW,
203  const UT_Matrix4T<PREC>& pL,
205  UT_Matrix4T<PREC>* effective_local)
206 {
207  // W: child world transform
208  // T,R,S: child local translation, rotation and scale
209  // pW: parent world transform
210  // pT, pR, pS: parent translation, rotation and scale
211  // pL: parent local transform
212  // pLT, pLR, pLS: parent local translate, rotation and scale
213 
214  // the result
215  UT_Matrix4T<PREC>L{ 1 };
216 
217  UT_Matrix4T<PREC>pW_inv;
218  pW.invert(pW_inv);
219 
220  UT_Matrix3T<PREC> pLS{ 1 };
221  UT_Matrix3T<PREC> pLS_inv{ 1 };
222 
223  switch (mode)
224  {
226  {
227  L = W * pW_inv;
228  if (effective_local)
229  *effective_local = L;
230  break;
231  }
233  {
234  UT_Vector3T<PREC> T_vec;
235  W.getTranslates(T_vec);
236  T_vec *= pW_inv;
237 
238  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
239 
240  pLS.invert(pLS_inv);
241  UT_Matrix4T<PREC> _pW{pW};
242  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
243  _pW.invert(pW_inv);
244 
245  L = W * pW_inv;
246 
247  L.setTranslates(T_vec);
248 
249  if (effective_local)
250  *effective_local = L;
251  break;
252  }
254  {
255  UT_Vector3T<PREC> T_vec;
256  W.getTranslates(T_vec);
257  T_vec *= pW_inv;
258 
259  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
260 
261  pLS.invert(pLS_inv);
262  UT_Matrix4T<PREC> _pW{ pW };
263  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
264  _pW.invert(pW_inv);
265 
266  L = W * pW_inv;
267 
268  L.setTranslates(T_vec);
269 
270  if (effective_local)
271  *effective_local = L;
272 
273  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
274 
275 
276  break;
277  }
279  {
280  // Inverse of:
281  // W = pLS * SRT * pLS^-1 * pW
282 
283  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
284 
285  pLS.invert(pLS_inv);
286  UT_Matrix4T<PREC> _pW{ pW };
287  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
288  _pW.invert(pW_inv);
289 
290  L = W * pW_inv;
291 
292  if (effective_local)
293  *effective_local = L;
294 
295  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
296 
297  break;
298  }
300  {
301  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
302  pLS.invert(pLS_inv);
303  UT_Matrix4T<PREC> _pW{ pW };
304  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
305  _pW.invert(pW_inv);
306  L = W * pW_inv;
307  if (effective_local)
308  *effective_local = L;
309  break;
310  }
311  default:
312  {
313  L = W * pW_inv;
314  if (effective_local)
315  *effective_local = L;
316  break;
317  }
318  }
319  return L;
320 }
321 
322 template<
323  typename PREC,
324  bool NORMALIZE_WEIGHTS,
325  UT_SLERP_METHOD METHOD,
326  UT_SLERP_FLIP_METHOD FLIP_METHOD
327 >
328 inline UT_Matrix4T<PREC>
330  const UT_Array<PREC> &input_weights)
331 {
332  const int n = xforms.size();
333  if (n < 1)
334  {
335  UT_ASSERT(!"Not enough inputs");
337  }
338  UT_ASSERT(n == input_weights.size());
339 
340  const PREC *weights = input_weights.data();
341 
343  if (NORMALIZE_WEIGHTS)
344  {
345  PREC total_weights = 0;
346  for (PREC w : input_weights)
347  total_weights += w;
348 
349  if (total_weights > 0)
350  {
351  new_weights.setSizeNoInit(input_weights.size());
352  for (int i = 0; i < n; ++i)
353  new_weights[i] = input_weights[i] / total_weights;
354  weights = new_weights.data();
355  }
356  }
357 
360  UT_Matrix3T<PREC> stretch;
361 
362  switch (METHOD)
363  {
365  {
366  xforms[0].getTranslates(translate);
367  translate *= weights[0];
368 
369  rotate = xforms[0];
370  rotate.makeRotationMatrix(&stretch);
371  stretch *= weights[0];
372 
374  quat.updateFromRotationMatrix(rotate);
375  UT_QuaternionT<PREC> ref = quat;
376  quat *= weights[0];
377 
378  for (int i = 1; i < n; ++i)
379  {
380  const PREC w = weights[i];
381 
383  xforms[i].getTranslates(t);
384  translate += w * t;
385 
386  UT_Matrix3T<PREC> stretch_tmp;
387  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
388  rotate_tmp.makeRotationMatrix(&stretch_tmp);
389  stretch += w * stretch_tmp;
390 
392  q.updateFromRotationMatrix(rotate_tmp);
393  if (dot(ref, q) < 0)
394  q.negate();
395  quat += w * q;
396 
397  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
398  ref = q;
399  }
400 
401  quat.getRotationMatrix(rotate); // uses normalized quat
402  break;
403  }
405  {
407 
408  translate = 0;
409  stretch = 0;
410  rots.setSizeNoInit(n);
411  for (int i = 0; i < n; ++i)
412  {
413  const PREC w = weights[i];
414 
416  xforms[i].getTranslates(t);
417  translate += w * t;
418 
419  UT_Matrix3T<PREC> stretch_tmp;
420  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
421  rotate_tmp.makeRotationMatrix(&stretch_tmp);
422  stretch += w * stretch_tmp;
423 
424  rots[i].updateFromRotationMatrix(rotate_tmp);
425  }
426 
428  quat.interpolate(rots.data(), weights, rots.size());
429  quat.getRotationMatrix(rotate);
430  break;
431  }
432  }
433 
434  UT_Matrix4T<PREC> result{stretch};
435  result *= rotate;
436  result.setTranslates(translate);
437  return result;
438 }
439 
440 #endif // __UT_TRANSFORMUTIL_H_INCLUDED__
GLbyte * weights
Definition: glew.h:7551
UT_Matrix4T< PREC > UTtransformCombineLocal(const UT_Matrix4T< PREC > &L, const UT_Matrix4T< PREC > &pW, const UT_Matrix4T< PREC > &pL, UT_ScaleInheritanceMode mode=UT_ScaleInheritanceMode::DEFAULT, UT_Matrix4T< PREC > *effective_local=nullptr)
GLenum GLint ref
Definition: glew.h:1845
GLenum mode
Definition: glew.h:2163
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:507
UT_Matrix4T< PREC > UTslerp(const UT_Array< UT_Matrix4T< PREC >> &xforms, const UT_Array< PREC > &input_weights)
Spherically blend transforms by decomposing into separate quaternions.
void getRotationMatrix(UT_Matrix3 &mat) const
3D Vector class.
exint size() const
Definition: UT_Array.h:458
UT_SLERP_METHOD
Method of slerp for blending.
GLdouble GLdouble GLdouble GLdouble q
Definition: glew.h:1414
simple inheritance: W = L * pW
static const UT_Matrix4T< T > & getIdentityMatrix()
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:127
GLubyte GLubyte GLubyte GLubyte w
Definition: glew.h:1890
ImageBuf OIIO_API rotate(const ImageBuf &src, float angle, string_view filtername=string_view(), float filterwidth=0.0f, bool recompute_roi=false, ROI roi={}, int nthreads=0)
GLsizei n
Definition: glew.h:4040
UT_Matrix4T< PREC > UTtransformExtractLocal(const UT_Matrix4T< PREC > &W, const UT_Matrix4T< PREC > &pW, const UT_Matrix4T< PREC > &pL, UT_ScaleInheritanceMode mode=UT_ScaleInheritanceMode::DEFAULT, UT_Matrix4T< PREC > *effective_local=nullptr)
Extract relative transform with scale inheritance.
UT_SLERP_FLIP_METHOD
Flip method for slerp to ensure consistency during blending.
void setTranslates(const UT_Vector3T< S > &translates)
Definition: UT_Matrix4.h:1335
UT_QuaternionT< T > interpolate(const UT_QuaternionT< T > &target, T t, T b=0.0f) const
Interpolates between this quat (t==0) and the target (t==1)
Quaternion class.
Definition: UT_Quaternion.h:51
T * data()
Definition: UT_Array.h:634
bool polarDecompose(UT_Matrix3T< T > *stretch=nullptr, bool reverse=true, const int max_iter=64, const T rel_tol=FLT_EPSILON)
int invert(T tol=0.0F)
Invert this matrix and return 0 if OK, 1 if singular.
GLuint64EXT * result
Definition: glew.h:14007
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:135
void leftMult(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:1486
PUGI__FN char_t * translate(char_t *buffer, const char_t *from, const char_t *to, size_t to_length)
Definition: pugixml.cpp:8352
normalized lerp of quaternion
use hemisphere of first quaternion
UT_ScaleInheritanceMode
Scale inheritance modes.
GLdouble GLdouble t
Definition: glew.h:1398
bool makeRotationMatrix(UT_Matrix3T< T > *stretch=nullptr, bool reverse=true, const int max_iter=64, const T rel_tol=FLT_EPSILON)
void getTranslates(UT_Vector3T< S > &translates) const
Definition: UT_Matrix4.h:1325
void updateFromRotationMatrix(const UT_Matrix3 &)
void preMultiply(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:353