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 
71 /// Extract relative transform with scale inheritance
72 template<typename PREC>
75  const UT_Matrix4T<PREC>& W, /// source world transform
76  const UT_Matrix4T<PREC>& pW, /// target parent world
77  const UT_Matrix4T<PREC>& pL, /// target parent local
79  UT_Matrix4T<PREC>* effective_local = nullptr);
80 
81 template<typename PREC>
82 void
85  const UT_Matrix4T<PREC>& W, /// source world transform
86  const UT_Matrix4T<PREC>& pW, /// target parent world
87  const UT_Matrix4T<PREC>& pW_inv, /// target parent world
88  const UT_Matrix4T<PREC>& pL, /// target parent local
90  UT_Matrix4T<PREC>* effective_local = nullptr);
91 
92 /// Method of slerp for blending
93 enum class UT_SLERP_METHOD
94 {
95  NLERP, /// normalized lerp of quaternion
96  ACCURATE, /// use iterative method
97 };
98 
99 /// Flip method for slerp to ensure consistency during blending
101 {
102  FIRST, /// use hemisphere of first quaternion
103  SUCCESSIVE, /// compare each adjacent quaternions when using NLERP
104 };
105 
106 /// Spherically blend transforms by decomposing into separate quaternions
107 template<
108  typename PREC,
109  bool NORMALIZE_WEIGHTS = true,
112 >
114 UTslerp(const UT_Array<UT_Matrix4T<PREC>> &xforms,
115  const UT_Array<PREC> &input_weights);
116 
117 /// Spherically blend 2 transforms by decomposing into separate quaternions
118 template<
119  typename PREC,
122 >
124 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
125  const PREC input_weight);
126 
127 
128 template<typename PREC>
130 {
131 public:
135 };
136 
137 /// Spherically blend 2 transforms by decomposing into separate quaternions
138 /// Also makes use of a cache to avoid calling makeRotationMatrix if the
139 /// input matrices didn't change. 2 cache entries are used per invocation.
140 template<
141  typename PREC,
144 >
146 UTslerp( const UT_Matrix4T<PREC> &xform0,const UT_Matrix4T<PREC> &xform1,
147  const PREC input_weight, UT_SlerpCache<PREC> *makerotcache);
148 
149 
150 ///////////////////////////////////////////////////////////////////////////////
151 //
152 // Implementations
153 //
154 
155 template<typename PREC>
156 inline UT_Matrix4T<PREC>
158  const UT_Matrix4T<PREC>& L, /// local transform
159  const UT_Matrix4T<PREC>& pW, /// parent world transform
160  const UT_Matrix4T<PREC>& pL, /// parent local transform
162  UT_Matrix4T<PREC>* effective_local)
163 {
164  // W: child world transform
165  // T,R,S: child local translation, rotation and scale
166  // pW: parent world transform
167  // pT, pR, pS: parent translation, rotation and scale
168  // pL: parent local transform
169  // pLT, pLR, pLS: parent local translate, rotation and scale
170 
171  UT_Matrix3T<PREC> pLS{ 1 };
172  UT_Matrix3T<PREC> pLS_inv{ 1 };
173 
174  UT_Matrix4T<PREC> RS = L;
175  UT_Vector3T<PREC> _t{ 0.0, 0.0, 0.0 };
176  RS.setTranslates(_t);
177 
178  if (effective_local && effective_local != &L)
179  *effective_local = L;
180 
181  UT_Matrix4T<PREC> T{ 1.0 };
182  L.getTranslates(_t);
183  T.setTranslates(_t);
184 
185  UT_Matrix4T<PREC> my_xform{ 1 };
186 
187  switch (mode)
188  {
190  {
191  my_xform = L * pW;
192  break;
193  }
195  {
196  UT_Matrix3T<PREC> parent_local(pL);
197  parent_local.polarDecompose(&pLS);
198  pLS.invert(pLS_inv);
199 
200  my_xform = RS * UT_Matrix4T<PREC>(pLS_inv) * T * pW;
201  break;
202  }
204  {
205  UT_Matrix3T<PREC> parent_local(pL);
206  parent_local.polarDecompose(&pLS);
207  pLS.invert(pLS_inv);
208 
209  my_xform = UT_Matrix4T<PREC>(pLS) * RS * UT_Matrix4T<PREC>(pLS_inv)
210  * T * pW;
211  // NB: effective_local here is same as SCALE_ONLY case because
212  // it's for the child transforms
213  if (effective_local)
214  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
215  break;
216  }
218  {
219  UT_Matrix3T<PREC> parent_local(pL);
220  parent_local.polarDecompose(&pLS);
221  pLS.invert(pLS_inv);
222 
223  my_xform = UT_Matrix4T<PREC>(pLS) * L * UT_Matrix4T<PREC>(pLS_inv)
224  * pW;
225  if (effective_local)
226  effective_local->leftMult(UT_Matrix4T<PREC>(pLS));
227  break;
228  }
230  {
231  UT_Matrix3T<PREC> parent_local(pL);
232  parent_local.polarDecompose(&pLS);
233  pLS.invert(pLS_inv);
234 
235  my_xform = L * UT_Matrix4T<PREC>(pLS_inv) * pW;
236  break;
237  }
238  default:
239  {
240  my_xform = L * pW;
241  break;
242  }
243  }
244  return my_xform;
245 }
246 
247 /// Extract relative transform with scale inheritance
248 template<typename PREC>
249 inline void
252  const UT_Matrix4T<PREC>& W,
253  const UT_Matrix4T<PREC>& pW,
254  const UT_Matrix4T<PREC>& pW_inv,
255  const UT_Matrix4T<PREC>& pL,
257  UT_Matrix4T<PREC>* effective_local)
258 {
259  // W: child world transform
260  // T,R,S: child local translation, rotation and scale
261  // pW: parent world transform
262  // pT, pR, pS: parent translation, rotation and scale
263  // pL: parent local transform
264  // pLT, pLR, pLS: parent local translate, rotation and scale
265 
266  // the result
267 
268  UT_Matrix3T<PREC> pLS{ 1 };
269  UT_Matrix3T<PREC> pLS_inv{ 1 };
270 
271  switch (mode)
272  {
274  {
275  L = W * pW_inv;
276  if (effective_local)
277  *effective_local = L;
278  break;
279  }
281  {
282  UT_Vector3T<PREC> T_vec;
283  W.getTranslates(T_vec);
284  T_vec *= pW_inv;
285 
286  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
287 
288  pLS.invert(pLS_inv);
289 
290  UT_Matrix4T<PREC> _pW{pW};
291  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
292 
293  UT_Matrix4T<PREC> _pW_inv;
294  _pW.invert(_pW_inv);
295 
296  L = W * _pW_inv;
297 
298  L.setTranslates(T_vec);
299 
300  if (effective_local)
301  *effective_local = L;
302  break;
303  }
305  {
306  UT_Vector3T<PREC> T_vec;
307  W.getTranslates(T_vec);
308  T_vec *= pW_inv;
309 
310  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
311 
312  pLS.invert(pLS_inv);
313 
314  UT_Matrix4T<PREC> _pW{ pW };
315  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
316  UT_Matrix4T<PREC> _pW_inv;
317  _pW.invert(_pW_inv);
318 
319  L = W * _pW_inv;
320 
321  L.setTranslates(T_vec);
322 
323  if (effective_local)
324  *effective_local = L;
325 
326  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
327 
328 
329  break;
330  }
332  {
333  // Inverse of:
334  // W = pLS * SRT * pLS^-1 * pW
335 
336  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
337 
338  pLS.invert(pLS_inv);
339 
340  UT_Matrix4T<PREC> _pW{ pW };
341  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
342  UT_Matrix4T<PREC> _pW_inv;
343  _pW.invert(_pW_inv);
344 
345  L = W * _pW_inv;
346 
347  if (effective_local)
348  *effective_local = L;
349 
350  L.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
351 
352  break;
353  }
355  {
356  UT_Matrix4T<PREC>(pL).polarDecompose(&pLS);
357  pLS.invert(pLS_inv);
358  UT_Matrix4T<PREC> _pW{ pW };
359  _pW.preMultiply(UT_Matrix4T<PREC>(pLS_inv));
360  UT_Matrix4T<PREC> _pW_inv;
361  _pW.invert(_pW_inv);
362  L = W * _pW_inv;
363  if (effective_local)
364  *effective_local = L;
365  break;
366  }
367  default:
368  {
369  L = W * pW_inv;
370  if (effective_local)
371  *effective_local = L;
372  break;
373  }
374  }
375 }
376 
377 /// Extract relative transform with scale inheritance
378 template<typename PREC>
379 inline UT_Matrix4T<PREC>
381  const UT_Matrix4T<PREC>& W,
382  const UT_Matrix4T<PREC>& pW,
383  const UT_Matrix4T<PREC>& pL,
385  UT_Matrix4T<PREC>* effective_local)
386 {
387 
388  UT_Matrix4T<PREC> ret;
389  UT_Matrix4T<PREC>pW_inv;
390  pW.invert(pW_inv);
391  UTtransformExtractLocal(ret, W,pW,pW_inv,pL,mode,effective_local);
392  return ret;
393 }
394 
395 template<
396  typename PREC,
397  bool NORMALIZE_WEIGHTS,
398  UT_SLERP_METHOD METHOD,
399  UT_SLERP_FLIP_METHOD FLIP_METHOD
400 >
401 inline UT_Matrix4T<PREC>
403  const UT_Array<PREC> &input_weights)
404 {
405  const int n = xforms.size();
406  if (n < 1)
407  {
408  UT_ASSERT(!"Not enough inputs");
410  }
411  UT_ASSERT(n == input_weights.size());
412 
413  const PREC *weights = input_weights.data();
414 
415  const int kSmallArrayElements = 16;
417  if (NORMALIZE_WEIGHTS)
418  {
419  PREC total_weights = 0;
420  for (PREC w : input_weights)
421  total_weights += w;
422 
423  if (total_weights > 0)
424  {
425  new_weights.setSizeNoInit(input_weights.size());
426  for (int i = 0; i < n; ++i)
427  new_weights[i] = input_weights[i] / total_weights;
428  weights = new_weights.data();
429  }
430  }
431 
434  UT_Matrix3T<PREC> stretch;
435 
436  switch (METHOD)
437  {
439  {
440  xforms[0].getTranslates(translate);
441  translate *= weights[0];
442 
443  rotate = xforms[0];
444  rotate.makeRotationMatrix(&stretch);
445  stretch *= weights[0];
446 
448  quat.updateFromRotationMatrix(rotate);
449  UT_QuaternionT<PREC> ref = quat;
450  quat *= weights[0];
451 
452  for (int i = 1; i < n; ++i)
453  {
454  const PREC w = weights[i];
455 
457  xforms[i].getTranslates(t);
458  translate += w * t;
459 
460  UT_Matrix3T<PREC> stretch_tmp;
461  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
462  rotate_tmp.makeRotationMatrix(&stretch_tmp);
463  stretch += w * stretch_tmp;
464 
466  q.updateFromRotationMatrix(rotate_tmp);
467  if (dot(ref, q) < 0)
468  q.negate();
469  quat += w * q;
470 
471  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
472  ref = q;
473  }
474 
475  quat.getRotationMatrix(rotate); // uses normalized quat
476  break;
477  }
479  {
481  sizeof(UT_QuaternionT<PREC>)*kSmallArrayElements> rots;
482 
483  translate = 0;
484  stretch = 0;
485  rots.setSizeNoInit(n);
486  for (int i = 0; i < n; ++i)
487  {
488  const PREC w = weights[i];
489 
491  xforms[i].getTranslates(t);
492  translate += w * t;
493 
494  UT_Matrix3T<PREC> stretch_tmp;
495  UT_Matrix3T<PREC> rotate_tmp{xforms[i]};
496  rotate_tmp.makeRotationMatrix(&stretch_tmp);
497  stretch += w * stretch_tmp;
498 
499  rots[i].updateFromRotationMatrix(rotate_tmp);
500  }
501 
503  quat.interpolate(rots.data(), weights, rots.size());
504  quat.getRotationMatrix(rotate);
505  break;
506  }
507  }
508 
509  UT_Matrix4T<PREC> result{stretch};
510  result *= rotate;
511  result.setTranslates(translate);
512  return result;
513 }
514 
515 template<
516  typename PREC,
517  UT_SLERP_METHOD METHOD,
518  UT_SLERP_FLIP_METHOD FLIP_METHOD
519 >
520 inline UT_Matrix4T<PREC>
521 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
522  const PREC input_weight)
523 {
524  const PREC weight0 = ((PREC)1.0) - input_weight;
525  const PREC weight1 = input_weight;
526 
529  UT_Matrix3T<PREC> stretch;
530 
531  switch (METHOD)
532  {
534  {
535  xform0.getTranslates(translate);
536  translate *= weight0;
537 
538  rotate = xform0;
539  rotate.makeRotationMatrix(&stretch);
540  stretch *= weight0;
541 
543  quat.updateFromRotationMatrix(rotate);
544  UT_QuaternionT<PREC> ref = quat;
545  quat *= weight0;
546 
547  {
548  const PREC w = weight1;
549 
551  xform1.getTranslates(t);
552  translate += w * t;
553 
554  UT_Matrix3T<PREC> stretch_tmp;
555  UT_Matrix3T<PREC> rotate_tmp{xform1};
556  rotate_tmp.makeRotationMatrix(&stretch_tmp);
557  stretch += w * stretch_tmp;
558 
560  q.updateFromRotationMatrix(rotate_tmp);
561  if (dot(ref, q) < 0)
562  q.negate();
563  quat += w * q;
564 
565  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
566  ref = q;
567  }
568 
569  quat.getRotationMatrix(rotate); // uses normalized quat
570  break;
571  }
573  {
574  translate = 0;
575  stretch = 0;
576 
579  {
580  const PREC w = weight0;
581 
583  xform0.getTranslates(t);
584  translate += w * t;
585 
586  UT_Matrix3T<PREC> stretch_tmp;
587  UT_Matrix3T<PREC> rotate_tmp{xform0};
588  rotate_tmp.makeRotationMatrix(&stretch_tmp);
589  stretch += w * stretch_tmp;
590 
591  rot0.updateFromRotationMatrix(rotate_tmp);
592  }
593 
594  {
595  const PREC w = weight1;
596 
598  xform1.getTranslates(t);
599  translate += w * t;
600 
601  UT_Matrix3T<PREC> stretch_tmp;
602  UT_Matrix3T<PREC> rotate_tmp{xform1};
603  rotate_tmp.makeRotationMatrix(&stretch_tmp);
604  stretch += w * stretch_tmp;
605 
606  rot1.updateFromRotationMatrix(rotate_tmp);
607  }
608 
610  quat = rot0.interpolate(rot1,weight1);
611  quat.getRotationMatrix(rotate);
612  break;
613  }
614  }
615 
616  UT_Matrix4T<PREC> result{stretch};
617  result *= rotate;
618  result.setTranslates(translate);
619  return result;
620 }
621 
622 template<
623  typename PREC,
624  UT_SLERP_METHOD METHOD,
625  UT_SLERP_FLIP_METHOD FLIP_METHOD
626 >
627 inline UT_Matrix4T<PREC>
628 UTslerp( const UT_Matrix4T<PREC> &xform0, const UT_Matrix4T<PREC> &xform1,
629  const PREC input_weight, UT_SlerpCache<PREC>* makerotcache)
630 {
631  const PREC weight0 = ((PREC)1.0) - input_weight;
632  const PREC weight1 = input_weight;
633 
636  UT_Matrix3T<PREC> stretch;
637 
638 
639  auto cachedMakeRot = [&makerotcache](
640  const UT_Matrix4T<PREC> &in_xfo,
641  UT_Matrix3T<PREC> &io_stretch,
642  UT_QuaternionT<PREC> &io_quat)
643  {
644  // Check if we have a cache hit
645  if (makerotcache->rot==in_xfo)
646  {
647  io_quat = makerotcache->quat;
648  io_stretch = makerotcache->stretch;
649  }
650  else
651  {
652  // do the computation of stretch and quat
653  // The intermediate makeRotation matrix isn't cached
654  UT_Matrix3T<PREC> in_rot{in_xfo};
655  in_rot.makeRotationMatrix(&io_stretch);
656  io_quat.updateFromRotationMatrix(in_rot);
657 
658  // Fill the cache
659  makerotcache->rot = in_xfo;
660  makerotcache->quat = io_quat;
661  makerotcache->stretch = io_stretch;
662  }
663 
664  makerotcache++;
665  };
666 
667  switch (METHOD)
668  {
670  {
671  xform0.getTranslates(translate);
672  translate *= weight0;
673 
675  cachedMakeRot(xform0,stretch,quat);
676  stretch *= weight0;
677 
678  UT_QuaternionT<PREC> ref = quat;
679  quat *= weight0;
680 
681  {
682  const PREC w = weight1;
683 
685  xform1.getTranslates(t);
686  translate += w * t;
687 
689  UT_Matrix3T<PREC> stretch_tmp;
690  cachedMakeRot(xform1,stretch_tmp,q);
691  stretch += w * stretch_tmp;
692 
693  if (dot(ref, q) < 0)
694  q.negate();
695  quat += w * q;
696 
697  if (FLIP_METHOD == UT_SLERP_FLIP_METHOD::SUCCESSIVE)
698  ref = q;
699  }
700 
701  quat.getRotationMatrix(rotate); // uses normalized quat
702  break;
703  }
705  {
706  translate = 0;
707  stretch = 0;
708 
710  {
711  const PREC w = weight0;
712 
714  xform0.getTranslates(t);
715  translate += w * t;
716 
717  UT_Matrix3T<PREC> stretch_tmp;
718  cachedMakeRot(xform0,stretch_tmp,rot0);
719  stretch += w * stretch_tmp;
720  }
721 
723  {
724  const PREC w = weight1;
725 
727  xform1.getTranslates(t);
728  translate += w * t;
729 
730  UT_Matrix3T<PREC> stretch_tmp;
731  cachedMakeRot(xform1,stretch_tmp,rot1);
732  stretch += w * stretch_tmp;
733  }
734 
736  quat = rot0.interpolate(rot1,weight1);
737  quat.getRotationMatrix(rotate);
738  break;
739  }
740  }
741 
742  UT_Matrix4T<PREC> result{stretch};
743  result *= rotate;
744  result.setTranslates(translate);
745  return result;
746 }
747 
748 template<typename PREC>
749 inline void
751  UT_Matrix4T<PREC> &local,
752  const UT_Vector3T<PREC> &parent_local_s,
753  const UT_XformOrder &adjust_ord,
754  const UT_Vector3T<PREC> &parm_t,
755  const UT_Vector3T<PREC> &parm_r,
756  const UT_Vector3T<PREC> &parm_s,
757  const UT_Vector3T<PREC> &parm_p,
758  const UT_Vector3T<PREC> &parm_pr,
759  const UT_ScaleInheritanceMode scalecomp,
761 )
762 {
765 
766  typename UT_Matrix4T<PREC>::PivotSpace pivotspace;
767 
768  pivotspace.myTranslate = parm_p;
769  pivotspace.myRotate = parm_pr;
770 
771  UT_Matrix4T<PREC> adjust {1};
772  adjust.xform(adjust_ord,
773  parm_t[0], parm_t[1], parm_t[2],
774  parm_r[0], parm_r[1], parm_r[2],
775  parm_s[0], parm_s[1], parm_s[2],
776  pivotspace);
777 
779  {
780  local = adjust;
781  return;
782  }
783 
784  bool scales_local_t = scalecomp < UT_ScaleInheritanceMode::SCALE_ONLY;
785 
786  UT_Vector3T<PREC> local_t;
787  UT_Vector3T<PREC> local_r;
788  UT_Vector3T<PREC> local_s;
789  local.explode(
790  order, local_r, local_s, local_t, nullptr );
791 
795  adjust.explode(
796  order, r, s, t, nullptr );
797 
799  {
800  if( scales_local_t )
801  {
802  UT_Matrix3T<PREC> t_space(local);
803  // we'll just take the orientation of our 3x3 transform
804  // and apply the correct scales below
805  t_space.polarDecompose();
806 
807  // We can now apply the scales in our own local space
808  t_space.prescale(parent_local_s);
809 
810  // put the translate delta into the input space by multiplying
811  // by our input 3x3 transform
812  t *= t_space;
813  // inversely scale the delta by the parent local scales,
814  // ready to be combined with the existing local translates
815  t *= 1.0 / (parent_local_s);
816  }
817  else // our scale compensate mode is >=UT_ScaleInheritanceMode::SCALE_ONLY
818  {
819  UT_Matrix4T<PREC> local_polardecomp{ local };
820  local_polardecomp.polarDecompose();
821  t *= UT_Matrix3T<PREC>(local_polardecomp);
822  }
823  }
824 
825  // Apply the local_r by multiplying the quaternion
826  {
827  UT_QuaternionT<PREC> parm_q( r, order);
828  UT_QuaternionT<PREC> local_q( local_r, order);
829 
832  q = parm_q * local_q;
833  else
834  q = local_q * parm_q;
835 
836  // Get back euler angles from the quaternion
838  q.getRotationMatrix(mq);
839  mq.crack(r,order);
840  r.radToDeg();
841  }
842 
843  // Apply local t and s
844  t = local_t + t;
845  s = local_s * s;
846 
847  // rebuild the transform
848  local.identity();
849  local.xform( order,
850  t.x(), t.y(), t.z(),
851  r.x(), r.y(), r.z(),
852  s.x(), s.y(), s.z() );
853 }
854 
855 template <typename PREC>
856 inline void
858  const UT_Matrix4T<PREC> &local,
859  const UT_Matrix4T<PREC> &inputlocal,
860  const UT_XformOrder &parmorder,
861  const UT_ScaleInheritanceMode scalecomp,
863  const UT_Vector3T<PREC> &parent_local_s,
864  UT_Vector3T<PREC> &parm_t,
865  UT_Vector3T<PREC> &parm_r,
866  UT_Vector3T<PREC> &parm_s
867 )
868 {
869  UT_Matrix4T<PREC> adjust {1};
871 
872 
874  {
875  local.explode(
876  parmorder, parm_r, parm_s, parm_t, nullptr );
877  parm_r.radToDeg();
878  return;
879  }
880 
881  bool scales_local_t = scalecomp < UT_ScaleInheritanceMode::SCALE_ONLY;
882 
883  UT_Vector3T<PREC> local_t;
884  UT_Vector3T<PREC> local_r;
885  UT_Vector3T<PREC> local_s;
886  local.explode(
887  order, local_r, local_s, local_t, nullptr );
888 
889  UT_Vector3T<PREC> input_t;
890  UT_Vector3T<PREC> input_r;
891  UT_Vector3T<PREC> input_s;
892  inputlocal.explode(
893  order, input_r, input_s, input_t, nullptr );
894 
895  adjust.explode(
896  order, parm_r, parm_s, parm_t, nullptr );
897 
898  // Apply local t and s
899  parm_t = local_t - input_t;
900  parm_s = local_s / input_s;
901 
903  {
904  if( scales_local_t )
905  {
906 
907  parm_t *= (parent_local_s);
908 
909  UT_Matrix3T<PREC> t_space(inputlocal);
910  t_space.polarDecompose();
911 
912  t_space.prescale(parent_local_s);
913  t_space.invert();
914 
915  parm_t *= t_space;
916  }
917  else // our scale compensate mode is >=UT_ScaleInheritanceMode::SCALE_ONLY
918  {
919  UT_Matrix3T<PREC> t_space(inputlocal);
920  t_space.polarDecompose();
921  t_space.invert();
922  parm_t *= t_space;
923  }
924  }
925 
926  {
927  UT_QuaternionT<PREC> input_q( input_r, order);
928  UT_QuaternionT<PREC> local_q( local_r, order);
929 
932  {
933  input_q.invert();
934  q = local_q * input_q;
935  }
936  else
937  {
938  input_q.invert();
939  q = input_q * local_q;
940  }
941 
942  // Get back euler angles from the quaternion
944  q.getRotationMatrix(mq);
945  mq.crack(parm_r,order);
946  parm_r.radToDeg();
947  }
948 
949  UT_Matrix4D result(1.0);
950  result.xform(order, parm_t[0], parm_t[1], parm_t[2],
951  parm_r[0], parm_r[1], parm_r[2],
952  parm_s[0], parm_s[1], parm_s[2]);
953  result.explode(parmorder, parm_r, parm_s, parm_t, nullptr);
954  parm_r.radToDeg();
955 }
956 
957 #endif // __UT_TRANSFORMUTIL_H_INCLUDED__
GLint ref
Definition: glcorearb.h:124
UT_Matrix3T< PREC > stretch
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)
GLuint GLdouble GLdouble GLint GLint order
Definition: glew.h:3460
Transformation order of scales, rotates, and translates.
Definition: UT_XformOrder.h:23
void setSizeNoInit(exint newsize)
Definition: UT_Array.h:658
void radToDeg()
conversion between degrees and radians
constexpr SYS_FORCE_INLINE T & z() noexcept
Definition: UT_Vector3.h:656
void prescale(T sx, T sy, T sz)
Definition: UT_Matrix3.h:862
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.
UT_ParameterTransformMode
GLdouble GLdouble t
Definition: glew.h:1403
exint size() const
Definition: UT_Array.h:609
UT_QuaternionT< PREC > quat
UT_SLERP_METHOD
Method of slerp for blending.
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:857
GLdouble GLdouble GLdouble GLdouble q
Definition: glew.h:1419
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)
int invert()
Invert this matrix and return 0 if OK, 1 if singular.
GLuint64EXT * result
Definition: glew.h:14311
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
int explode(const UT_XformOrder &order, UT_Vector3F &r, UT_Vector3F &s, UT_Vector3F &t, UT_Vector3F *shears=0) const
Definition: UT_Matrix4.h:933
void identity()
Set the matrix to identity.
Definition: UT_Matrix4.h:1090
UT_Matrix4T< PREC > rot
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)
void setTranslates(const UT_Vector3T< S > &translates)
Definition: UT_Matrix4.h:1400
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)
GLdouble n
Definition: glcorearb.h:2008
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:785
GLbyte * weights
Definition: glew.h:7581
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.
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:153
void leftMult(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:1551
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:654
GLboolean r
Definition: glcorearb.h:1222
UT_ScaleInheritanceMode
Scale inheritance modes.
GLdouble s
Definition: glew.h:1395
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:1390
void updateFromRotationMatrix(const UT_Matrix3 &)
void preMultiply(const UT_Matrix4T< T > &m)
Definition: UT_Matrix4.h:363
constexpr SYS_FORCE_INLINE T & x() noexcept
Definition: UT_Vector3.h:652