@@ -20,26 +20,6 @@ public static partial class Matrix4X4
2020#endif
2121 private const float DecomposeEpsilon = 0.0001f ;
2222
23- /*
24- private struct CanonicalBasis<T>
25- where T : INumberBase<T>
26- {
27- public Vector3D<T> Row0;
28- public Vector3D<T> Row1;
29- public Vector3D<T> Row2;
30- };
31-
32- private struct VectorBasis<T>
33- where T : INumberBase<T>
34- {
35- #pragma warning disable 649
36- public unsafe Vector3D<T>* Element0;
37- public unsafe Vector3D<T>* Element1;
38- public unsafe Vector3D<T>* Element2;
39- #pragma warning restore 649
40- }
41- */
42-
4323 /// <summary>Creates a spherical billboard that rotates around a specified object position.</summary>
4424 /// <param name="objectPosition">Position of the object the billboard will rotate around.</param>
4525 /// <param name="cameraPosition">Position of the camera.</param>
@@ -1210,136 +1190,181 @@ public static bool Decompose<T>(Matrix4X4<T> matrix, out Vector3D<T> scale, out
12101190 where T : INumber < T > , IRootFunctions < T > , ITrigonometricFunctions < T >
12111191 {
12121192 bool result = true ;
1193+ scale = default ;
12131194
1214- translation = new Vector3D < T > ( matrix . M41 , matrix . M42 , matrix . M43 ) ;
1195+ Vector3D < T > [ ] vectorBasis = new Vector3D < T > [ 3 ] ;
1196+ Matrix3X3 < T > canonicalBasis = Matrix3X3 < T > . Identity ;
1197+ Matrix4X4 < T > matTemp ;
12151198
1216- // Extract basis vectors (rows)
1217- var basis = new Vector3D < T > [ 3 ] ;
1218- basis [ 0 ] = new Vector3D < T > ( matrix . M11 , matrix . M12 , matrix . M13 ) ;
1219- basis [ 1 ] = new Vector3D < T > ( matrix . M21 , matrix . M22 , matrix . M23 ) ;
1220- basis [ 2 ] = new Vector3D < T > ( matrix . M31 , matrix . M32 , matrix . M33 ) ;
1199+ translation = new Vector3D < T > (
1200+ matrix . M41 ,
1201+ matrix . M42 ,
1202+ matrix . M43 ) ;
12211203
1222- // Compute scales
1223- var scales = new T [ 3 ] ;
1224- scales [ 0 ] = basis [ 0 ] . Length ;
1225- scales [ 1 ] = basis [ 1 ] . Length ;
1226- scales [ 2 ] = basis [ 2 ] . Length ;
1204+ matTemp = new Matrix4X4 < T > (
1205+ matrix . M11 , matrix . M12 , matrix . M13 , T . Zero ,
1206+ matrix . M21 , matrix . M22 , matrix . M23 , T . Zero ,
1207+ matrix . M31 , matrix . M32 , matrix . M33 , T . Zero ,
1208+ T . Zero , T . Zero , T . Zero , T . One ) ;
12271209
1228- scale = new Vector3D < T > ( scales [ 0 ] , scales [ 1 ] , scales [ 2 ] ) ;
1210+ T x = scale . X = matTemp . Row1 . Length ;
1211+ T y = scale . Y = matTemp . Row2 . Length ;
1212+ T z = scale . Z = matTemp . Row3 . Length ;
12291213
1230- // Rank axes by scale magnitude
1231- uint a , b , c ;
1214+ int a , b , c ;
1215+ if ( ! ( x >= y ) )
12321216 {
1233- T x = scales [ 0 ] , y = scales [ 1 ] , z = scales [ 2 ] ;
1234-
1235- if ( ! ( x >= y ) )
1217+ if ( ! ( y >= z ) )
12361218 {
1237- if ( ! ( y >= z ) )
1238- { a = 2 ; b = 1 ; c = 0 ; }
1219+ a = 2 ;
1220+ b = 1 ;
1221+ c = 0 ;
1222+ }
1223+ else
1224+ {
1225+ a = 1 ;
1226+
1227+ if ( ! ( x >= z ) )
1228+ {
1229+ b = 2 ;
1230+ c = 0 ;
1231+ }
12391232 else
12401233 {
1241- a = 1 ;
1242- if ( ! ( x >= z ) )
1243- { b = 2 ; c = 0 ; }
1244- else
1245- { b = 0 ; c = 2 ; }
1234+ b = 0 ;
1235+ c = 2 ;
12461236 }
12471237 }
1238+ }
1239+ else
1240+ {
1241+ if ( ! ( x >= z ) )
1242+ {
1243+ a = 2 ;
1244+ b = 0 ;
1245+ c = 1 ;
1246+ }
12481247 else
12491248 {
1250- if ( ! ( x >= z ) )
1251- { a = 2 ; b = 0 ; c = 1 ; }
1249+ a = 0 ;
1250+
1251+ if ( ! ( y >= z ) )
1252+ {
1253+ b = 2 ;
1254+ c = 1 ;
1255+ }
12521256 else
12531257 {
1254- a = 0 ;
1255- if ( ! ( y >= z ) )
1256- { b = 2 ; c = 1 ; }
1257- else
1258- { b = 1 ; c = 2 ; }
1258+ b = 1 ;
1259+ c = 2 ;
12591260 }
12601261 }
12611262 }
12621263
1263- var canonical = new [ ]
1264- {
1265- new Vector3D < T > ( T . One , T . Zero , T . Zero ) ,
1266- new Vector3D < T > ( T . Zero , T . One , T . Zero ) ,
1267- new Vector3D < T > ( T . Zero , T . Zero , T . One )
1268- } ;
1269-
12701264 T eps = T . CreateTruncating ( DecomposeEpsilon ) ;
12711265
1272- if ( ! ( scales [ a ] >= eps ) )
1273- basis [ a ] = canonical [ a ] ;
1266+ if ( ! ( scale [ a ] >= eps ) )
1267+ {
1268+ var normalA = canonicalBasis [ a ] ;
1269+ matTemp [ a ] [ 0 ] = normalA [ 0 ] ;
1270+ matTemp [ a ] [ 1 ] = normalA [ 1 ] ;
1271+ matTemp [ a ] [ 2 ] = normalA [ 2 ] ;
1272+ }
12741273
1275- basis [ a ] = Vector3D . Normalize ( basis [ a ] ) ;
1274+ matTemp [ a ] = matTemp [ a ] . Normalize ( ) ;
12761275
1277- if ( ! ( scales [ b ] >= eps ) )
1276+ if ( ! ( scale [ b ] >= eps ) )
12781277 {
1279- T ax = T . Abs ( basis [ a ] . X ) ;
1280- T ay = T . Abs ( basis [ a ] . Y ) ;
1281- T az = T . Abs ( basis [ a ] . Z ) ;
1278+ int cc ;
1279+ T absX , absY , absZ ;
1280+
1281+ absX = T . Abs ( matTemp [ a ] . X ) ;
1282+ absY = T . Abs ( matTemp [ a ] . Y ) ;
1283+ absZ = T . Abs ( matTemp [ a ] . Z ) ;
12821284
1283- uint cc ;
1284- if ( ! ( ax >= ay ) )
1285+ if ( ! ( absX >= absY ) )
12851286 {
1286- if ( ! ( ay >= az ) )
1287+ if ( ! ( absY >= absZ ) )
1288+ {
12871289 cc = 0 ;
1290+ }
12881291 else
1289- cc = ( ! ( ax >= az ) ) ? 0u : 2u ;
1292+ {
1293+ if ( ! ( absX >= absZ ) )
1294+ {
1295+ cc = 0 ;
1296+ }
1297+ else
1298+ {
1299+ cc = 2 ;
1300+ }
1301+ }
12901302 }
12911303 else
12921304 {
1293- if ( ! ( ax >= az ) )
1305+ if ( ! ( absX >= absZ ) )
1306+ {
12941307 cc = 1 ;
1308+ }
12951309 else
1296- cc = ( ! ( ay >= az ) ) ? 1u : 2u ;
1310+ {
1311+ if ( ! ( absY >= absZ ) )
1312+ {
1313+ cc = 1 ;
1314+ }
1315+ else
1316+ {
1317+ cc = 2 ;
1318+ }
1319+ }
12971320 }
12981321
1299- basis [ b ] = Vector3D . Cross ( basis [ a ] , canonical [ cc ] ) ;
1322+ var normalB = Vector3D . Cross ( new Vector3D < T > ( matTemp [ a ] . AsSpan ( ) [ ^ - 1 ] ) , canonicalBasis [ cc ] ) ;
1323+ matTemp [ b ] [ 0 ] = normalB [ 0 ] ;
1324+ matTemp [ b ] [ 1 ] = normalB [ 1 ] ;
1325+ matTemp [ b ] [ 2 ] = normalB [ 2 ] ;
13001326 }
13011327
1302- basis [ b ] = Vector3D . Normalize ( basis [ b ] ) ;
1303-
1304- if ( ! ( scales [ c ] >= eps ) )
1305- basis [ c ] = Vector3D . Cross ( basis [ a ] , basis [ b ] ) ;
1328+ matTemp [ b ] = matTemp [ b ] . Normalize ( ) ;
13061329
1307- basis [ c ] = Vector3D . Normalize ( basis [ c ] ) ;
1330+ if ( ! ( scale [ c ] >= eps ) )
1331+ {
1332+ var normalC = Vector3D . Cross ( new Vector3D < T > ( matTemp [ a ] . AsSpan ( ) ) , new Vector3D < T > ( matTemp [ b ] . AsSpan ( ) ) ) ;
1333+ matTemp [ c ] [ 0 ] = normalC [ 0 ] ;
1334+ matTemp [ c ] [ 1 ] = normalC [ 1 ] ;
1335+ matTemp [ c ] [ 2 ] = normalC [ 2 ] ;
1336+ }
13081337
1309- // Rebuild orthonormal rotation matrix
1310- var rotationMatrix = new Matrix4X4 < T > (
1311- basis [ 0 ] . X , basis [ 0 ] . Y , basis [ 0 ] . Z , T . Zero ,
1312- basis [ 1 ] . X , basis [ 1 ] . Y , basis [ 1 ] . Z , T . Zero ,
1313- basis [ 2 ] . X , basis [ 2 ] . Y , basis [ 2 ] . Z , T . Zero ,
1314- T . Zero , T . Zero , T . Zero , T . Zero ) ;
1338+ matTemp [ c ] = matTemp [ c ] . Normalize ( ) ;
13151339
1316- T det = rotationMatrix . GetDeterminant ( ) ;
1340+ T det = matTemp . GetDeterminant ( ) ;
13171341
1318- // Fix handedness
1342+ // use Kramer's rule to check for handedness of coordinate system
13191343 if ( ! ( det >= T . Zero ) )
13201344 {
1321- scales [ a ] = - scales [ a ] ;
1345+ // switch coordinate system by negating the scale and inverting the basis vector on the x-axis
1346+ scale [ a ] = - scale [ a ] ;
1347+ matTemp [ a ] [ 0 ] = - matTemp [ a ] [ 0 ] ;
1348+ matTemp [ a ] [ 1 ] = - matTemp [ a ] [ 1 ] ;
1349+ matTemp [ a ] [ 2 ] = - matTemp [ a ] [ 2 ] ;
13221350 det = - det ;
1323-
1324- rotationMatrix . Row1 = - rotationMatrix . Row1 ;
1325- rotationMatrix . Row2 = - rotationMatrix . Row2 ;
1326- rotationMatrix . Row3 = - rotationMatrix . Row3 ;
13271351 }
13281352
1329- T diff = det - T . One ;
1330- diff *= diff ;
1353+ det = det - T . One ;
1354+ det = det * det ;
13311355
1332- if ( ! ( eps >= diff ) )
1356+ if ( ! ( eps >= det ) )
13331357 {
1358+ // Non-SRT matrix encountered
13341359 rotation = Quaternion < T > . Identity ;
13351360 result = false ;
13361361 }
13371362 else
13381363 {
1339- rotation = Quaternion < T > . CreateFromRotationMatrix ( rotationMatrix ) ;
1364+ // generate the quaternion from the matrix
1365+ rotation = Quaternion < T > . CreateFromRotationMatrix ( matTemp ) ;
13401366 }
13411367
1342- scale = new Vector3D < T > ( scales [ 0 ] , scales [ 1 ] , scales [ 2 ] ) ;
13431368 return result ;
13441369 }
13451370
0 commit comments