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 
54 {
55  MODE_PRE = 0,
56  MODE_POST,
58 };
59 
60 /// Combine a local transform on top of another with scale inheritance options
61 /// L is modified to contain the effective local transform on return for t.
62 template<typename PREC>
65  const UT_Matrix4T<PREC>& L, /// local transform
66  const UT_Matrix4T<PREC>& pW, /// parent world transform
67  const UT_Matrix4T<PREC>& pL, /// parent local transform
69  UT_Matrix4T<PREC>* effective_local=nullptr,
70  UT_Matrix3T<PREC>* pLS_ptr=nullptr, /// parent local transform stretch
71  UT_Matrix3T<PREC>* pLS_inv_ptr=nullptr, /// parent local transform stretch_inv
72  bool* pLS_init_ptr=nullptr
73  );
74 
75 /// Combine a local transform on top of another with scale inheritance options
76 /// L is modified to contain the effective local transform on return for t.
77 /// Same as UTtransformCombineLocal, but with mode passed as a template argument
78 /// and an optimization with HAS_EFFECTIVE_LOCAL.
79 template <
80  typename PREC,
82  bool HAS_PLS
83 >
86  const UT_Matrix4T<PREC>& L, /// local transform
87  const UT_Matrix4T<PREC>& pW, /// parent world transform
88  const UT_Matrix4T<PREC>& pL, /// parent local transform
89  UT_Matrix4T<PREC>* effective_local = nullptr,
90  UT_Matrix3T<PREC>* pLS_ptr = nullptr, /// parent local transform stretch
91  UT_Matrix3T<PREC>* pLS_inv_ptr = nullptr, /// parent local transform stretch_inv
92  bool* pLS_init_ptr = nullptr);
93 
94 
95 /// Extract relative transform with scale inheritance
96 template<typename PREC>
99  const UT_Matrix4T<PREC>& W, /// source world transform
100  const UT_Matrix4T<PREC>& pW, /// target parent world
101  const UT_Matrix4T<PREC>& pL, /// target parent local
103  UT_Matrix4T<PREC>* effective_local = nullptr);
104 
105 template<typename PREC>
106 void
109  const UT_Matrix4T<PREC>& W, /// source world transform
110  const UT_Matrix4T<PREC>& pW, /// target parent world
111  const UT_Matrix4T<PREC>& pW_inv, /// target parent world
112  const UT_Matrix4T<PREC>& pL, /// target parent local
114  UT_Matrix4T<PREC>* effective_local = nullptr);
115 
116 template <
117  typename PREC,
119  bool HAS_EFFECTIVE_LOCAL = false
120 >
121 SYS_FORCE_INLINE void
124  const UT_Matrix4T<PREC>& W, /// source world transform
125  const UT_Matrix4T<PREC>& pW, /// target parent world
126  const UT_Matrix4T<PREC>& pW_inv, /// target parent world
127  const UT_Matrix4T<PREC>& pL, /// target parent local
128  UT_Matrix4T<PREC>* effective_local = nullptr);
129 
130 /// Method of slerp for blending
131 enum class UT_SLERP_METHOD
132 {
133  NLERP, /// normalized lerp of quaternion
134  ACCURATE, /// use iterative method
135 };
136 
137 /// Flip method for slerp to ensure consistency during blending
139 {
140  FIRST, /// use hemisphere of first quaternion
141  SUCCESSIVE, /// compare each adjacent quaternions when using NLERP
142 };
143 
144 /// Spherically blend transforms by decomposing into separate quaternions
145 template<
146  typename PREC,
147  bool NORMALIZE_WEIGHTS = true,
150 >
152 UTslerp(const UT_Array<UT_Matrix4T<PREC>> &xforms,
153  const UT_Array<PREC> &input_weights);
154 
155 /// Spherically blend 2 transforms by decomposing into separate quaternions
156 template<
157  typename PREC,
160 >
162 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
163  const PREC input_weight);
164 
165 /// Spherically blend multiple quaternions, provided for interface consistency
166 template<
167  typename PREC,
168  bool NORMALIZE_WEIGHTS = true
169 >
172  const UT_Array<PREC> &weights);
173 
174 template<typename PREC>
176 {
177 public:
181 };
182 
183 /// Spherically blend 2 transforms by decomposing into separate quaternions
184 /// Also makes use of a cache to avoid calling makeRotationMatrix if the
185 /// input matrices didn't change. 2 cache entries are used per invocation.
186 template<
187  typename PREC,
190 >
192 UTslerp( const UT_Matrix4T<PREC> &xform0,const UT_Matrix4T<PREC> &xform1,
193  const PREC input_weight, UT_SlerpCache<PREC> *makerotcache);
194 
195 
196 ///////////////////////////////////////////////////////////////////////////////
197 //
198 // Implementations
199 //
200 
201 template<
202  typename PREC,
204  bool HAS_PLS
205 >
208  const UT_Matrix4T<PREC>& L, /// local transform
209  const UT_Matrix4T<PREC>& pW, /// parent world transform
210  const UT_Matrix4T<PREC>& pL, /// parent local transform
211  UT_Matrix4T<PREC>* effective_local,
212  UT_Matrix3T<PREC>* pLS_ptr, /// parent local transform stretch
213  UT_Matrix3T<PREC>* pLS_inv_ptr, /// parent local transform stretch_inv
214  bool* pLS_init_ptr)
215 {
216  // W: child world transform
217  // T,R,S: child local translation, rotation and scale
218  // pW: parent world transform
219  // pT, pR, pS: parent translation, rotation and scale
220  // pL: parent local transform
221  // pLT, pLR, pLS: parent local translate, rotation and scale
222 
223 
224  UT_Matrix3T<PREC> tmp_pLS, tmp_pLS_inv;
225  bool tmp_pLS_init = true;
226 
227  UT_Matrix3T<PREC> &pLS = HAS_PLS ? *pLS_ptr : tmp_pLS;
228  UT_Matrix3T<PREC> &pLS_inv = HAS_PLS ? *pLS_inv_ptr : tmp_pLS_inv;
229  bool &pLS_init = HAS_PLS ? *pLS_init_ptr : tmp_pLS_init;
230 
231  if (effective_local && effective_local != &L)
232  *effective_local = L;
233 
234  UT_Matrix4T<PREC> my_xform;
235 
236  switch (MODE)
237  {
242  if (pLS_init)
243  {
244  UT_Matrix3T<PREC> parent_local(pL);
245  parent_local.polarDecompose(&pLS);
246  pLS.invert(pLS_inv);
247  pLS_init = false;
248  }
249  break;
250 
251  default:
252  break;
253  };
254 
255  switch (MODE)
256  {
258  {
259  my_xform = L * pW;
260  break;
261  }
263  {
264  UT_Matrix4T<PREC> RS = L;
265  constexpr UT_Vector3T<PREC> _t0{ 0.0, 0.0, 0.0 };
266  RS.setTranslates(_t0);
267 
268  UT_Matrix4T<PREC> T{ 1.0 };
270  L.getTranslates(_t);
271  T.setTranslates(_t);
272 
273  my_xform = RS * UT_Matrix4T<PREC>(pLS_inv) * T * pW;
274  break;
275  }
277  {
278 
279  UT_Matrix4T<PREC> RS = L;
280  constexpr UT_Vector3T<PREC> _t0{ 0.0, 0.0, 0.0 };
281  RS.setTranslates(_t0);
282 
283  UT_Matrix4T<PREC> T{ 1.0 };
285  L.getTranslates(_t);
286  T.setTranslates(_t);
287 
288  my_xform = UT_Matrix4T<PREC>(pLS) * RS * UT_Matrix4T<PREC>(pLS_inv)
289  * T * pW;
290  // NB: effective_local here is same as SCALE_ONLY case because
291  // it's for the child transforms
292  if (effective_local)
293  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
294  break;
295  }
297  {
298  my_xform = UT_Matrix4T<PREC>(pLS) * L * UT_Matrix4T<PREC>(pLS_inv)
299  * pW;
300  if (effective_local)
301  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
302  break;
303  }
305  {
306  my_xform = L * UT_Matrix4T<PREC>(pLS_inv) * pW;
307  break;
308  }
309  default:
310  {
311  my_xform = L * pW;
312  break;
313  }
314  }
315  return my_xform;
316 }
317 
318 template<typename PREC>
319 inline UT_Matrix4T<PREC>
321  const UT_Matrix4T<PREC>& L, /// local transform
322  const UT_Matrix4T<PREC>& pW, /// parent world transform
323  const UT_Matrix4T<PREC>& pL, /// parent local transform
325  UT_Matrix4T<PREC>* effective_local,
326  UT_Matrix3T<PREC>* pLS_ptr,
327  UT_Matrix3T<PREC>* pLS_inv_ptr,
328  bool* pLS_init_ptr)
329 {
330 #define UT_TRANSFORM_COMBINE(M, A) \
331  return UTtransformCombineLocalT<PREC, M, A>( \
332  L, pW, pL, effective_local, pLS_ptr, pLS_inv_ptr, pLS_init_ptr); \
333  /**/
334 #define IF_UT_TRANSFORM_COMBINE(M, A) \
335  if (mode == M) \
336  UT_TRANSFORM_COMBINE(M, A) \
337  /**/
338 
339  if (pLS_init_ptr && pLS_ptr && pLS_inv_ptr)
340  {
347  }
348  else
349  {
350  pLS_ptr = nullptr;
351  pLS_inv_ptr = nullptr;
352  pLS_init_ptr = nullptr;
353 
360  }
361 }
362 
363 /// Extract relative transform with scale inheritance
364 template<typename PREC>
365 inline void
368  const UT_Matrix4T<PREC>& W,
369  const UT_Matrix4T<PREC>& pW,
370  const UT_Matrix4T<PREC>& pW_inv,
371  const UT_Matrix4T<PREC>& pL,
373  UT_Matrix4T<PREC>* effective_local)
374 {
375  // W: child world transform
376  // T,R,S: child local translation, rotation and scale
377  // pW: parent world transform
378  // pT, pR, pS: parent translation, rotation and scale
379  // pL: parent local transform
380  // pLT, pLR, pLS: parent local translate, rotation and scale
381 
382  // the result
383 
384  UT_Matrix3T<PREC> pLS{ 1 };
385  UT_Matrix3T<PREC> pLS_inv{ 1 };
386 
387  switch (mode)
388  {
390  {
391  L = W * pW_inv;
392  if (effective_local)
393  *effective_local = L;
394  break;
395  }
397  {
398  UT_Vector3T<PREC> T_vec;
399  W.getTranslates(T_vec);
400  T_vec *= pW_inv;
401 
402  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
403 
404  pLS.invert(pLS_inv);
405 
406  UT_Matrix4T<PREC> _pW{pW};
407  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
408 
409  UT_Matrix4T<PREC> _pW_inv;
410  _pW.invert(_pW_inv);
411 
412  L = W * _pW_inv;
413 
414  L.setTranslates(T_vec);
415 
416  if (effective_local)
417  *effective_local = L;
418  break;
419  }
421  {
422  UT_Vector3T<PREC> T_vec;
423  W.getTranslates(T_vec);
424  T_vec *= pW_inv;
425 
426  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
427 
428  pLS.invert(pLS_inv);
429 
430  UT_Matrix4T<PREC> _pW{ pW };
431  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
432  UT_Matrix4T<PREC> _pW_inv;
433  _pW.invert(_pW_inv);
434 
435  L = W * _pW_inv;
436 
437  L.setTranslates(T_vec);
438 
439  if (effective_local)
440  *effective_local = L;
441 
442  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
443 
444 
445  break;
446  }
448  {
449  // Inverse of:
450  // W = pLS * SRT * pLS^-1 * pW
451 
452  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
453 
454  pLS.invert(pLS_inv);
455 
456  UT_Matrix4T<PREC> _pW{ pW };
457  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
458  UT_Matrix4T<PREC> _pW_inv;
459  _pW.invert(_pW_inv);
460 
461  L = W * _pW_inv;
462 
463  if (effective_local)
464  *effective_local = L;
465 
466  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
467 
468  break;
469  }
471  {
472  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
473  pLS.invert(pLS_inv);
474  UT_Matrix4T<PREC> _pW{ pW };
475  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
476  UT_Matrix4T<PREC> _pW_inv;
477  _pW.invert(_pW_inv);
478  L = W * _pW_inv;
479  if (effective_local)
480  *effective_local = L;
481  break;
482  }
483  default:
484  {
485  L = W * pW_inv;
486  if (effective_local)
487  *effective_local = L;
488  break;
489  }
490  }
491 }
492 
493 /// Extract relative transform with scale inheritance
494 template<typename PREC, UT_ScaleInheritanceMode MODE, bool HAS_EFFECTIVE_LOCAL>
495 SYS_FORCE_INLINE void
498  const UT_Matrix4T<PREC>& W,
499  const UT_Matrix4T<PREC>& pW,
500  const UT_Matrix4T<PREC>& pW_inv,
501  const UT_Matrix4T<PREC>& pL,
502  UT_Matrix4T<PREC>* effective_local)
503 {
504  // W: child world transform
505  // T,R,S: child local translation, rotation and scale
506  // pW: parent world transform
507  // pT, pR, pS: parent translation, rotation and scale
508  // pL: parent local transform
509  // pLT, pLR, pLS: parent local translate, rotation and scale
510 
511  // the result
512 
513  UT_Matrix3T<PREC> pLS;
514  UT_Matrix3T<PREC> pLS_inv;
515 
516  switch (MODE)
517  {
519  {
520  L = W * pW_inv;
521  if (HAS_EFFECTIVE_LOCAL && effective_local)
522  *effective_local = L;
523  break;
524  }
526  {
527  UT_Vector3T<PREC> T_vec;
528  W.getTranslates(T_vec);
529  T_vec *= pW_inv;
530 
531  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
532 
533  pLS.invert(pLS_inv);
534 
535  UT_Matrix4T<PREC> _pW{pW};
536  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
537 
538  UT_Matrix4T<PREC> _pW_inv;
539  _pW.invert(_pW_inv);
540 
541  L = W * _pW_inv;
542 
543  L.setTranslates(T_vec);
544 
545  if (HAS_EFFECTIVE_LOCAL && effective_local)
546  *effective_local = L;
547  break;
548  }
550  {
551  UT_Vector3T<PREC> T_vec;
552  W.getTranslates(T_vec);
553  T_vec *= pW_inv;
554 
555  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
556 
557  pLS.invert(pLS_inv);
558 
559  UT_Matrix4T<PREC> _pW{ pW };
560  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
561  UT_Matrix4T<PREC> _pW_inv;
562  _pW.invert(_pW_inv);
563 
564  L = W * _pW_inv;
565 
566  L.setTranslates(T_vec);
567 
568  if (HAS_EFFECTIVE_LOCAL && effective_local)
569  *effective_local = L;
570 
571  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
572 
573 
574  break;
575  }
577  {
578  // Inverse of:
579  // W = pLS * SRT * pLS^-1 * pW
580 
581  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
582 
583  pLS.invert(pLS_inv);
584 
585  UT_Matrix4T<PREC> _pW{ pW };
586  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
587  UT_Matrix4T<PREC> _pW_inv;
588  _pW.invert(_pW_inv);
589 
590  L = W * _pW_inv;
591 
592  if (HAS_EFFECTIVE_LOCAL && effective_local)
593  *effective_local = L;
594 
595  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
596 
597  break;
598  }
600  {
601  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
602  pLS.invert(pLS_inv);
603  UT_Matrix4T<PREC> _pW{ pW };
604  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
605  UT_Matrix4T<PREC> _pW_inv;
606  _pW.invert(_pW_inv);
607  L = W * _pW_inv;
608  if (HAS_EFFECTIVE_LOCAL && effective_local)
609  *effective_local = L;
610  break;
611  }
612  default:
613  {
614  L = W * pW_inv;
615  if (HAS_EFFECTIVE_LOCAL && effective_local)
616  *effective_local = L;
617  break;
618  }
619  }
620 }
621 
622 /// Extract relative transform with scale inheritance
623 template<typename PREC>
624 inline UT_Matrix4T<PREC>
626  const UT_Matrix4T<PREC>& W,
627  const UT_Matrix4T<PREC>& pW,
628  const UT_Matrix4T<PREC>& pL,
630  UT_Matrix4T<PREC>* effective_local)
631 {
632 
633  UT_Matrix4T<PREC> ret;
634  UT_Matrix4T<PREC>pW_inv;
635  pW.invert(pW_inv);
636  UTtransformExtractLocal(ret, W, pW, pW_inv, pL, mode, effective_local);
637  return ret;
638 }
639 
640 template<
641  typename PREC,
642  bool NORMALIZE_WEIGHTS,
643  UT_SLERP_METHOD METHOD,
644  UT_SLERP_FLIP_METHOD FLIP_METHOD
645 >
646 inline UT_Matrix4T<PREC>
648  const UT_Array<PREC> &input_weights)
649 {
650  const int n = xforms.size();
651  if (n < 1)
652  {
653  UT_ASSERT(!"Not enough inputs");
655  }
656  UT_ASSERT(n == input_weights.size());
657 
658  const PREC *weights = input_weights.data();
659 
660  const int kSmallArrayElements = 16;
662  if (NORMALIZE_WEIGHTS)
663  {
664  PREC total_weights = 0;
665  for (PREC w : input_weights)
666  total_weights += w;
667 
668  if (total_weights > 0)
669  {
670  new_weights.setSizeNoInit(input_weights.size());
671  for (int i = 0; i < n; ++i)
672  new_weights[i] = input_weights[i] / total_weights;
673  weights = new_weights.data();
674  }
675  }
676 
679  UT_Matrix3T<PREC> stretch;
680 
681  switch (METHOD)
682  {
684  {
685  xforms[0].getTranslates(translate);
686  translate *= weights[0];
687 
688  rotate = xforms[0];
689  rotate.makeRotationMatrix(&stretch);
690  stretch *= weights[0];
691 
693  quat.updateFromRotationMatrix(rotate);
694  UT_QuaternionT<PREC> ref = quat;
695  quat *= weights[0];
696 
697  for (int i = 1; i < n; ++i)
698  {
699  const PREC w = weights[i];
700 
702  xforms[i].getTranslates(t);
703  translate += w * t;
704 
705  UT_Matrix3T<PREC> stretch_tmp;
706  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
707  rotate_tmp.makeRotationMatrix(&stretch_tmp);
708  stretch += w * stretch_tmp;
709 
711  q.updateFromRotationMatrix(rotate_tmp);
712  if (dot(ref, q) < 0)
713  q.negate();
714  quat += w * q;
715 
716  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
717  ref = q;
718  }
719 
720  quat.getRotationMatrix(rotate); // uses normalized quat
721  break;
722  }
724  {
726  sizeof(UT_QuaternionT<PREC>)*kSmallArrayElements> rots;
727 
728  translate = 0;
729  stretch = 0;
730  rots.setSizeNoInit(n);
731  for (int i = 0; i < n; ++i)
732  {
733  const PREC w = weights[i];
734 
736  xforms[i].getTranslates(t);
737  translate += w * t;
738 
739  UT_Matrix3T<PREC> stretch_tmp;
740  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
741  rotate_tmp.makeRotationMatrix(&stretch_tmp);
742  stretch += w * stretch_tmp;
743 
744  rots[i].updateFromRotationMatrix(rotate_tmp);
745  }
746 
748  quat.interpolate(rots.data(), weights, rots.size());
749  quat.getRotationMatrix(rotate);
750  break;
751  }
752  }
753 
754  UT_Matrix4T<PREC> result{stretch};
755  result *= rotate;
756  result.setTranslates(translate);
757  return result;
758 }
759 
760 template<
761  typename PREC,
762  UT_SLERP_METHOD METHOD,
763  UT_SLERP_FLIP_METHOD FLIP_METHOD
764 >
766 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
767  const PREC input_weight)
768 {
769  const PREC weight0 = ((PREC)1.0) - input_weight;
770  const PREC weight1 = input_weight;
771 
774  UT_Matrix3T<PREC> stretch;
775 
776  switch (METHOD)
777  {
779  {
780  xform0.getTranslates(translate);
781  translate *= weight0;
782 
783  rotate = xform0;
784  rotate.makeRotationMatrix(&stretch);
785  stretch *= weight0;
786 
788  quat.updateFromRotationMatrix(rotate);
789  UT_QuaternionT<PREC> ref = quat;
790  quat *= weight0;
791 
792  {
793  const PREC w = weight1;
794 
796  xform1.getTranslates(t);
797  translate += w * t;
798 
799  UT_Matrix3T<PREC> stretch_tmp;
800  UT_Matrix3T<PREC> rotate_tmp{xform1};
801  rotate_tmp.makeRotationMatrix(&stretch_tmp);
802  stretch += w * stretch_tmp;
803 
805  q.updateFromRotationMatrix(rotate_tmp);
806  if (dot(ref, q) < 0)
807  q.negate();
808  quat += w * q;
809 
810  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
811  ref = q;
812  }
813 
814  quat.getRotationMatrix(rotate); // uses normalized quat
815  break;
816  }
818  {
819  translate = 0;
820  stretch = 0;
821 
824  {
825  const PREC w = weight0;
826 
828  xform0.getTranslates(t);
829  translate += w * t;
830 
831  UT_Matrix3T<PREC> stretch_tmp;
832  UT_Matrix3T<PREC> rotate_tmp{xform0};
833  rotate_tmp.makeRotationMatrix(&stretch_tmp);
834  stretch += w * stretch_tmp;
835 
836  rot0.updateFromRotationMatrix(rotate_tmp);
837  }
838 
839  {
840  const PREC w = weight1;
841 
843  xform1.getTranslates(t);
844  translate += w * t;
845 
846  UT_Matrix3T<PREC> stretch_tmp;
847  UT_Matrix3T<PREC> rotate_tmp{xform1};
848  rotate_tmp.makeRotationMatrix(&stretch_tmp);
849  stretch += w * stretch_tmp;
850 
851  rot1.updateFromRotationMatrix(rotate_tmp);
852  }
853 
855  quat = rot0.interpolate(rot1,weight1);
856  quat.getRotationMatrix(rotate);
857  break;
858  }
859  }
860 
861  UT_Matrix4T<PREC> result{stretch};
862  result *= rotate;
863  result.setTranslates(translate);
864  return result;
865 }
866 
867 template<
868  typename PREC,
869  UT_SLERP_METHOD METHOD,
870  UT_SLERP_FLIP_METHOD FLIP_METHOD
871 >
872 inline UT_Matrix4T<PREC>
873 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
874  const PREC input_weight, UT_SlerpCache<PREC>* makerotcache)
875 {
876  const PREC weight0 = ((PREC)1.0) - input_weight;
877  const PREC weight1 = input_weight;
878 
881  UT_Matrix3T<PREC> stretch;
882 
883 
884  auto cachedMakeRot = [&makerotcache](
885  const UT_Matrix4T<PREC> &in_xfo,
886  UT_Matrix3T<PREC> &io_stretch,
887  UT_QuaternionT<PREC> &io_quat)
888  {
889  // Check if we have a cache hit
890  if (makerotcache->rot==in_xfo)
891  {
892  io_quat = makerotcache->quat;
893  io_stretch = makerotcache->stretch;
894  }
895  else
896  {
897  // do the computation of stretch and quat
898  // The intermediate makeRotation matrix isn't cached
899  UT_Matrix3T<PREC> in_rot{in_xfo};
900  in_rot.makeRotationMatrix(&io_stretch);
901  io_quat.updateFromRotationMatrix(in_rot);
902 
903  // Fill the cache
904  makerotcache->rot = in_xfo;
905  makerotcache->quat = io_quat;
906  makerotcache->stretch = io_stretch;
907  }
908 
909  makerotcache++;
910  };
911 
912  switch (METHOD)
913  {
915  {
916  xform0.getTranslates(translate);
917  translate *= weight0;
918 
920  cachedMakeRot(xform0,stretch,quat);
921  stretch *= weight0;
922 
923  UT_QuaternionT<PREC> ref = quat;
924  quat *= weight0;
925 
926  {
927  const PREC w = weight1;
928 
930  xform1.getTranslates(t);
931  translate += w * t;
932 
934  UT_Matrix3T<PREC> stretch_tmp;
935  cachedMakeRot(xform1,stretch_tmp,q);
936  stretch += w * stretch_tmp;
937 
938  if (dot(ref, q) < 0)
939  q.negate();
940  quat += w * q;
941 
942  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
943  ref = q;
944  }
945 
946  quat.getRotationMatrix(rotate); // uses normalized quat
947  break;
948  }
950  {
951  translate = 0;
952  stretch = 0;
953 
955  {
956  const PREC w = weight0;
957 
959  xform0.getTranslates(t);
960  translate += w * t;
961 
962  UT_Matrix3T<PREC> stretch_tmp;
963  cachedMakeRot(xform0,stretch_tmp,rot0);
964  stretch += w * stretch_tmp;
965  }
966 
968  {
969  const PREC w = weight1;
970 
972  xform1.getTranslates(t);
973  translate += w * t;
974 
975  UT_Matrix3T<PREC> stretch_tmp;
976  cachedMakeRot(xform1,stretch_tmp,rot1);
977  stretch += w * stretch_tmp;
978  }
979 
981  quat = rot0.interpolate(rot1,weight1);
982  quat.getRotationMatrix(rotate);
983  break;
984  }
985  }
986 
987  UT_Matrix4T<PREC> result{stretch};
988  result *= rotate;
989  result.setTranslates(translate);
990  return result;
991 }
992 
993 namespace UT_Detail
994 {
995  template <typename T, bool NORMALIZE_WEIGHTS>
996  struct QuatSlerp;
997 
998  template <typename T>
999  struct QuatSlerp<T, false>
1000  {
1002  const UT_Array<UT_QuaternionT<T>> &quats,
1003  const UT_Array<T> &weights)
1004  {
1006  q.interpolate(quats.data(), weights.data(), weights.size());
1007  return q;
1008  }
1009  };
1010 
1011  template <typename T>
1012  struct QuatSlerp<T, true>
1013  {
1015  const UT_Array<UT_QuaternionT<T>> &quats,
1016  const UT_Array<T> &weights)
1017  {
1018  const T *w = weights.data();
1019 
1020  UT_SmallArray<T,sizeof(T)*32> tmp_weights;
1021  T total = 0;
1022  const int n = weights.size();
1023  for (int i = 0; i < n; ++i)
1024  total += w[i];
1025  if (total > 0)
1026  {
1027  tmp_weights.setSizeNoInit(n);
1028  for (int i = 0; i < n; ++i)
1029  tmp_weights[i] = w[i] / total;
1030  w = tmp_weights.data();
1031  }
1032 
1034  q.interpolate(quats.data(), w, n);
1035  return q;
1036  }
1037  };
1038 }
1039 
1040 template <typename PREC, bool NORMALIZE_WEIGHTS>
1043  const UT_Array<PREC> &weights)
1044 {
1045  UT_ASSERT(quats.size() == weights.size());
1046  return UT_Detail::QuatSlerp<PREC, NORMALIZE_WEIGHTS>()(quats, weights);
1047 }
1048 
1049 template<typename PREC>
1050 inline void
1052  UT_Matrix4T<PREC> &local,
1053  const UT_Vector3T<PREC> &parent_local_s,
1054  const UT_XformOrder &adjust_ord,
1055  const UT_Vector3T<PREC> &parm_t,
1056  const UT_Vector3T<PREC> &parm_r,
1057  const UT_Vector3T<PREC> &parm_s,
1058  const UT_Vector3T<PREC> &parm_p,
1059  const UT_Vector3T<PREC> &parm_pr,
1060  const UT_ScaleInheritanceMode scalecomp,
1062 )
1063 {
1065 
1066  typename UT_Matrix4T<PREC>::PivotSpace pivotspace;
1067 
1068  pivotspace.myTranslate = parm_p;
1069  pivotspace.myRotate = parm_pr;
1070 
1071  UT_Matrix4T<PREC> adjust {1};
1072  adjust.xform(adjust_ord,
1073  parm_t[0], parm_t[1], parm_t[2],
1074  parm_r[0], parm_r[1], parm_r[2],
1075  parm_s[0], parm_s[1], parm_s[2],
1076  pivotspace);
1077 
1079  {
1080  local = adjust;
1081  return;
1082  }
1083 
1084  bool scales_local_t = scalecomp < UT_ScaleInheritanceMode::SCALE_ONLY;
1085 
1086  UT_Vector3T<PREC> local_t;
1087  UT_Vector3T<PREC> local_r;
1088  UT_Vector3T<PREC> local_s;
1089  local.explode(order, local_r, local_s, local_t, nullptr);
1090 
1094  adjust.explode(
1095  order, r, s, t, nullptr );
1096 
1098  {
1099  if( scales_local_t )
1100  {
1101  UT_Matrix3T<PREC> t_space(local);
1102  // we'll just take the orientation of our 3x3 transform
1103  // and apply the correct scales below
1104  t_space.polarDecompose();
1105 
1106  // We can now apply the scales in our own local space
1107  t_space.prescale(parent_local_s);
1108 
1109  // put the translate delta into the input space by multiplying
1110  // by our input 3x3 transform
1111  t *= t_space;
1112  // inversely scale the delta by the parent local scales,
1113  // ready to be combined with the existing local translates
1114  t *= 1.0 / (parent_local_s);
1115  }
1116  else // our scale compensate mode is >=UT_ScaleInheritanceMode::SCALE_ONLY
1117  {
1118  UT_Matrix4T<PREC> local_polardecomp{ local };
1119  local_polardecomp.polarDecompose();
1120  t *= UT_Matrix3T<PREC>(local_polardecomp);
1121  }
1122  }
1123 
1124  // Apply the local_r by multiplying the quaternion
1125  {
1126  UT_QuaternionT<PREC> parm_q( r, order);
1127  UT_QuaternionT<PREC> local_q( local_r, order);
1128 
1131  q = parm_q * local_q;
1132  else
1133  q = local_q * parm_q;
1134 
1135  // Get back euler angles from the quaternion
1136  UT_Matrix3T<PREC> mq;
1137  q.getRotationMatrix(mq);
1138  mq.crack(r,order);
1139  r.radToDeg();
1140  }
1141 
1142  // Apply local t and s
1143  t = local_t + t;
1144  s = local_s * s;
1145 
1146  // rebuild the transform
1147  local.identity();
1148  local.xform( order,
1149  t.x(), t.y(), t.z(),
1150  r.x(), r.y(), r.z(),
1151  s.x(), s.y(), s.z() );
1152 }
1153 
1154 template <typename PREC>
1155 inline void
1157  const UT_Matrix4T<PREC> &local,
1158  const UT_Matrix4T<PREC> &inputlocal,
1159  const UT_XformOrder &parmorder,
1160  const UT_ScaleInheritanceMode scalecomp,
1162  const UT_Vector3T<PREC> &parent_local_s,
1163  UT_Vector3T<PREC> &parm_t,
1164  UT_Vector3T<PREC> &parm_r,
1165  UT_Vector3T<PREC> &parm_s
1166 )
1167 {
1168  UT_Matrix4T<PREC> adjust {1};
1170 
1172  {
1173  local.explode(parmorder, parm_r, parm_s, parm_t, nullptr);
1174  parm_r.radToDeg();
1175  return;
1176  }
1177 
1178  bool scales_local_t = scalecomp < UT_ScaleInheritanceMode::SCALE_ONLY;
1179 
1180  UT_Vector3T<PREC> local_t;
1181  UT_Vector3T<PREC> local_r;
1182  UT_Vector3T<PREC> local_s;
1183  local.explode(order, local_r, local_s, local_t, nullptr);
1184 
1185  UT_Vector3T<PREC> input_t;
1186  UT_Vector3T<PREC> input_r;
1187  UT_Vector3T<PREC> input_s;
1188  inputlocal.explode(order, input_r, input_s, input_t, nullptr);
1189 
1190  adjust.explode(order, parm_r, parm_s, parm_t, nullptr);
1191 
1192  // Apply local t and s
1193  parm_t = local_t - input_t;
1194  parm_s = local_s / input_s;
1195 
1197  {
1198  if (scales_local_t)
1199  {
1200 
1201  parm_t *= (parent_local_s);
1202 
1203  UT_Matrix3T<PREC> t_space(inputlocal);
1204  t_space.polarDecompose();
1205 
1206  t_space.prescale(parent_local_s);
1207  t_space.invert();
1208 
1209  parm_t *= t_space;
1210  }
1211  else // our scale compensate mode is >=UT_ScaleInheritanceMode::SCALE_ONLY
1212  {
1213  UT_Matrix3T<PREC> t_space(inputlocal);
1214  t_space.polarDecompose();
1215  t_space.invert();
1216  parm_t *= t_space;
1217  }
1218  }
1219 
1220  {
1221  UT_QuaternionT<PREC> input_q( input_r, order);
1222  UT_QuaternionT<PREC> local_q( local_r, order);
1223 
1226  {
1227  input_q.invert();
1228  q = local_q * input_q;
1229  }
1230  else
1231  {
1232  input_q.invert();
1233  q = input_q * local_q;
1234  }
1235 
1236  // Get back euler angles from the quaternion
1237  UT_Matrix3T<PREC> mq;
1238  q.getRotationMatrix(mq);
1239  mq.crack(parm_r,order);
1240  parm_r.radToDeg();
1241  }
1242 
1243  UT_Matrix4D result(1.0);
1244  result.xform(order, parm_t[0], parm_t[1], parm_t[2],
1245  parm_r[0], parm_r[1], parm_r[2],
1246  parm_s[0], parm_s[1], parm_s[2]);
1247  result.explode(parmorder, parm_r, parm_s, parm_t, nullptr);
1248  parm_r.radToDeg();
1249 }
1250 
1251 #endif // __UT_TRANSFORMUTIL_H_INCLUDED__
UT_Matrix3T< PREC > stretch
#define UT_TRANSFORM_COMBINE(M, A)
Transformation order of scales, rotates, and translates.
Definition: UT_XformOrder.h:23
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:695
void radToDeg()
conversion between degrees and radians
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:667
GLdouble s
Definition: glad.h:3009
void prescale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:867
**But if you need a result
Definition: thread.h:613
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
GLdouble GLdouble GLdouble q
Definition: glad.h:2445
UT_ParameterTransformMode
exint size() const
Definition: UT_Array.h:646
UT_QuaternionT< PREC > quat
UT_SLERP_METHOD
Method of slerp for blending.
void UTcombineParameterTransform(UT_Matrix4T< PREC > &local, const UT_Vector3T< PREC > &parent_local_s, const UT_XformOrder &adjust_ord, const UT_Vector3T< PREC > &parm_t, const UT_Vector3T< PREC > &parm_r, const UT_Vector3T< PREC > &parm_s, const UT_Vector3T< PREC > &parm_p, const UT_Vector3T< PREC > &parm_pr, const UT_ScaleInheritanceMode scalecomp, const UT_ParameterTransformMode mode)
SYS_FORCE_INLINE void UTtransformExtractLocalT(UT_Matrix4T< PREC > &L, const UT_Matrix4T< PREC > &W, const UT_Matrix4T< PREC > &pW, const UT_Matrix4T< PREC > &pW_inv, const UT_Matrix4T< PREC > &pL, UT_Matrix4T< PREC > *effective_local=nullptr)
Extract relative transform with scale inheritance.
GLdouble n
Definition: glcorearb.h:2008
GLint ref
Definition: glcorearb.h:124
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:130
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
int explode(const UT_XformOrder &order, UT_Vector3F &r, UT_Vector3F &s, UT_Vector3F &t, UT_Vector3F *shears=0) const
Definition: UT_Matrix4.h:958
#define IF_UT_TRANSFORM_COMBINE(M, A)
GLdouble GLdouble GLint GLint order
Definition: glad.h:2676
void identity()
Set the matrix to identity.
Definition: UT_Matrix4.h:1128
UT_Matrix4T< PREC > rot
SYS_FORCE_INLINE 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, UT_Matrix3T< PREC > *pLS_ptr=nullptr, UT_Matrix3T< PREC > *pLS_inv_ptr=nullptr, bool *pLS_init_ptr=nullptr)
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)
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 xform(const UT_XformOrder &order, T tx=0, T ty=0, T tz=0, T rx=0, T ry=0, T rz=0, T sx=1, T sy=1, T sz=1, T px=0, T py=0, T pz=0, int reverse=0)
GLdouble t
Definition: glad.h:2397
void setTranslates(const UT_Vector3T< S > &translates)
Definition: UT_Matrix4.h:1442
UT_QuaternionT< T > operator()(const UT_Array< UT_QuaternionT< T >> &quats, const UT_Array< T > &weights)
GLenum mode
Definition: glcorearb.h:99
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)
void UTextractParameterTransform(const UT_Matrix4T< PREC > &local, const UT_Matrix4T< PREC > &inputlocal, const UT_XformOrder &parmorder, const UT_ScaleInheritanceMode scalecomp, const UT_ParameterTransformMode mode, const UT_Vector3T< PREC > &parent_local_s, UT_Vector3T< PREC > &parm_t, UT_Vector3T< PREC > &parm_r, UT_Vector3T< PREC > &parm_s)
T * data()
Definition: UT_Array.h:822
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)
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
void leftMult(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:1593
GLboolean r
Definition: glcorearb.h:1222
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
constexpr SYS_FORCE_INLINE T & y() noexcept
Definition: UT_Vector3.h:665
UT_ScaleInheritanceMode
Scale inheritance modes.
UT_QuaternionT< T > operator()(const UT_Array< UT_QuaternionT< T >> &quats, const UT_Array< T > &weights)
SYS_FORCE_INLINE UT_Matrix4T< PREC > UTtransformCombineLocalT(const UT_Matrix4T< PREC > &L, const UT_Matrix4T< PREC > &pW, const UT_Matrix4T< PREC > &pL, UT_Matrix4T< PREC > *effective_local=nullptr, UT_Matrix3T< PREC > *pLS_ptr=nullptr, UT_Matrix3T< PREC > *pLS_inv_ptr=nullptr, bool *pLS_init_ptr=nullptr)
bool polarDecompose(UT_Matrix3T< T > *stretch=nullptr, bool reverse=true, const int max_iter=64, const T rel_tol=FLT_EPSILON)
int crack(UT_Vector3T< S > &rvec, const UT_XformOrder &order) const
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:1432
void updateFromRotationMatrix(const UT_Matrix3 &)
void preMultiply(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:352
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:663