@@ -2552,65 +2552,91 @@ RMAPI int QuaternionEquals(Quaternion p, Quaternion q)
2552
2552
return result ;
2553
2553
}
2554
2554
2555
- // Decompose a transformation matrix into its rotational, translational and scaling components
2555
+ // Decompose a transformation matrix into its rotational, translational and scaling components and remove shear
2556
2556
RMAPI void MatrixDecompose (Matrix mat , Vector3 * translation , Quaternion * rotation , Vector3 * scale )
2557
2557
{
2558
- // Extract translation.
2558
+ float eps = 1e-9 ;
2559
+
2560
+ // Extract Translation
2559
2561
translation -> x = mat .m12 ;
2560
2562
translation -> y = mat .m13 ;
2561
2563
translation -> z = mat .m14 ;
2562
2564
2563
- // Extract upper-left for determinant computation
2564
- const float a = mat .m0 ;
2565
- const float b = mat .m4 ;
2566
- const float c = mat .m8 ;
2567
- const float d = mat .m1 ;
2568
- const float e = mat .m5 ;
2569
- const float f = mat .m9 ;
2570
- const float g = mat .m2 ;
2571
- const float h = mat .m6 ;
2572
- const float i = mat .m10 ;
2573
- const float A = e * i - f * h ;
2574
- const float B = f * g - d * i ;
2575
- const float C = d * h - e * g ;
2576
-
2577
- // Extract scale
2578
- const float det = a * A + b * B + c * C ;
2579
- Vector3 abc = { a , b , c };
2580
- Vector3 def = { d , e , f };
2581
- Vector3 ghi = { g , h , i };
2582
-
2583
- float scalex = Vector3Length (abc );
2584
- float scaley = Vector3Length (def );
2585
- float scalez = Vector3Length (ghi );
2586
- Vector3 s = { scalex , scaley , scalez };
2587
-
2588
- if (det < 0 ) s = Vector3Negate (s );
2589
-
2590
- * scale = s ;
2591
-
2592
- // Remove scale from the matrix if it is not close to zero
2593
- Matrix clone = mat ;
2594
- if (!FloatEquals (det , 0 ))
2565
+ // Matrix Columns - Rotation will be extracted into here.
2566
+ Vector3 matColumns [3 ] = { { mat .m0 , mat .m4 , mat .m8 },
2567
+ { mat .m1 , mat .m5 , mat .m9 },
2568
+ { mat .m2 , mat .m6 , mat .m10 } };
2569
+
2570
+ // Shear Parameters XY, XZ, and YZ (extract and ignored)
2571
+ float shear [3 ] = { 0 };
2572
+
2573
+ // Normalized Scale Parameters
2574
+ Vector3 scl = { 0 };
2575
+
2576
+ // Max-Normalizing helps numerical stability
2577
+ float stabilizer = eps ;
2578
+ for (int i = 0 ; i < 3 ; i ++ )
2579
+ {
2580
+ stabilizer = fmaxf (stabilizer , fabsf (matColumns [i ].x ));
2581
+ stabilizer = fmaxf (stabilizer , fabsf (matColumns [i ].y ));
2582
+ stabilizer = fmaxf (stabilizer , fabsf (matColumns [i ].z ));
2583
+ };
2584
+ matColumns [0 ] = Vector3Scale (matColumns [0 ], 1.0f / stabilizer );
2585
+ matColumns [1 ] = Vector3Scale (matColumns [1 ], 1.0f / stabilizer );
2586
+ matColumns [2 ] = Vector3Scale (matColumns [2 ], 1.0f / stabilizer );
2587
+
2588
+ // X Scale
2589
+ scl .x = Vector3Length (matColumns [0 ]);
2590
+ if (scl .x > eps )
2595
2591
{
2596
- clone .m0 /= s .x ;
2597
- clone .m4 /= s .x ;
2598
- clone .m8 /= s .x ;
2599
- clone .m1 /= s .y ;
2600
- clone .m5 /= s .y ;
2601
- clone .m9 /= s .y ;
2602
- clone .m2 /= s .z ;
2603
- clone .m6 /= s .z ;
2604
- clone .m10 /= s .z ;
2605
-
2606
- // Extract rotation
2607
- * rotation = QuaternionFromMatrix (clone );
2592
+ matColumns [0 ] = Vector3Scale (matColumns [0 ], 1.0f / scl .x );
2608
2593
}
2609
- else
2594
+
2595
+ // Compute XY shear and make col2 orthogonal
2596
+ shear [0 ] = Vector3DotProduct (matColumns [0 ], matColumns [1 ]);
2597
+ matColumns [1 ] = Vector3Subtract (matColumns [1 ], Vector3Scale (matColumns [0 ], shear [0 ]));
2598
+
2599
+ // Y Scale
2600
+ scl .y = Vector3Length (matColumns [1 ]);
2601
+ if (scl .y > eps )
2610
2602
{
2611
- // Set to identity if close to zero
2612
- * rotation = QuaternionIdentity ();
2603
+ matColumns [ 1 ] = Vector3Scale ( matColumns [ 1 ], 1.0f / scl . y );
2604
+ shear [ 0 ] /= scl . y ; // Correct XY shear
2613
2605
}
2606
+
2607
+ // Compute XZ and YZ shears and make col3 orthogonal
2608
+ shear [1 ] = Vector3DotProduct (matColumns [0 ], matColumns [2 ]);
2609
+ matColumns [2 ] = Vector3Subtract (matColumns [2 ], Vector3Scale (matColumns [0 ], shear [1 ]));
2610
+ shear [2 ] = Vector3DotProduct (matColumns [1 ], matColumns [2 ]);
2611
+ matColumns [2 ] = Vector3Subtract (matColumns [2 ], Vector3Scale (matColumns [1 ], shear [2 ]));
2612
+
2613
+ // Z Scale
2614
+ scl .z = Vector3Length (matColumns [2 ]);
2615
+ if (scl .z > eps )
2616
+ {
2617
+ matColumns [2 ] = Vector3Scale (matColumns [2 ], 1.0f / scl .z );
2618
+ shear [1 ] /= scl .z ; // Correct XZ shear
2619
+ shear [2 ] /= scl .z ; // Correct YZ shear
2620
+ }
2621
+
2622
+ // matColumns are now orthonormal in O(3). Now ensure its in SO(3) by enforcing det = 1.
2623
+ if (Vector3DotProduct (matColumns [0 ], Vector3CrossProduct (matColumns [1 ], matColumns [2 ])) < 0 )
2624
+ {
2625
+ scl = Vector3Negate (scl );
2626
+ matColumns [0 ] = Vector3Negate (matColumns [0 ]);
2627
+ matColumns [1 ] = Vector3Negate (matColumns [1 ]);
2628
+ matColumns [2 ] = Vector3Negate (matColumns [2 ]);
2629
+ }
2630
+
2631
+ // Set Scale
2632
+ * scale = Vector3Scale (scl , stabilizer );
2633
+
2634
+ // Extract Rotation
2635
+ Matrix rotationMatrix = { matColumns [0 ].x , matColumns [0 ].y , matColumns [0 ].z , 0 ,
2636
+ matColumns [1 ].x , matColumns [1 ].y , matColumns [1 ].z , 0 ,
2637
+ matColumns [2 ].x , matColumns [2 ].y , matColumns [2 ].z , 0 ,
2638
+ 0 , 0 , 0 , 1 };
2639
+ * rotation = QuaternionFromMatrix (rotationMatrix );
2614
2640
}
2615
2641
2616
2642
#if defined(__cplusplus ) && !defined(RAYMATH_DISABLE_CPP_OPERATORS )
0 commit comments