@@ -915,6 +915,28 @@ private bool IsBone (Transform t, Dictionary<Transform, int> bones)
915
915
return false ;
916
916
}
917
917
918
+ /// <summary>
919
+ /// Gets the bind pose for the Unity bone.
920
+ /// </summary>
921
+ /// <returns>The bind pose.</returns>
922
+ /// <param name="unityBone">Unity bone.</param>
923
+ /// <param name="bindPoses">Bind poses.</param>
924
+ /// <param name="boneDict">Dictionary of bone to index.</param>
925
+ /// <param name="skinnedMesh">Skinned mesh.</param>
926
+ private Matrix4x4 GetBindPose (
927
+ Transform unityBone , Matrix4x4 [ ] bindPoses ,
928
+ Dictionary < Transform , int > boneDict , SkinnedMeshRenderer skinnedMesh
929
+ ) {
930
+ Matrix4x4 bindPose ;
931
+ int index ;
932
+ if ( boneDict . TryGetValue ( unityBone , out index ) ) {
933
+ bindPose = bindPoses [ index ] ;
934
+ } else {
935
+ bindPose = unityBone . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix ;
936
+ }
937
+ return bindPose ;
938
+ }
939
+
918
940
/// <summary>
919
941
/// Export bones of skinned mesh, if this is a skinned mesh with
920
942
/// bones and bind poses.
@@ -971,17 +993,6 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
971
993
Debug . LogErrorFormat ( "Node {0} should already be created" , t . name ) ;
972
994
}
973
995
974
- // Set it up as a skeleton node if we haven't already.
975
- if ( fbxBoneNode . GetSkeleton ( ) == null ) {
976
- FbxSkeleton fbxSkeleton = FbxSkeleton . Create ( fbxScene , t . name + SkeletonPrefix ) ;
977
-
978
- var fbxSkeletonType = skinnedMesh . rootBone != t
979
- ? FbxSkeleton . EType . eLimbNode : FbxSkeleton . EType . eRoot ;
980
- fbxSkeleton . SetSkeletonType ( fbxSkeletonType ) ;
981
- fbxSkeleton . Size . Set ( 1.0f * UnitScaleFactor ) ;
982
- fbxBoneNode . SetNodeAttribute ( fbxSkeleton ) ;
983
- }
984
-
985
996
boneSet . Add ( t ) ;
986
997
}
987
998
@@ -992,69 +1003,13 @@ private bool ExportSkeleton (SkinnedMeshRenderer skinnedMesh, FbxScene fbxScene,
992
1003
}
993
1004
994
1005
var boneList = boneSet . ToArray ( ) ;
995
-
996
1006
skinnedMeshToBonesMap . Add ( skinnedMesh , boneList ) ;
997
1007
998
- // Step 2: Get bindposes
999
- var boneToBindPose = new Dictionary < Transform , Matrix4x4 > ( ) ;
1000
- for ( int boneIndex = 0 , n = boneList . Length ; boneIndex < n ; boneIndex ++ ) {
1001
- var unityBone = boneList [ boneIndex ] ;
1002
-
1003
- Matrix4x4 pose ;
1004
- if ( index . ContainsKey ( unityBone ) ) {
1005
- int i = index [ unityBone ] ;
1006
- pose = bindPoses [ i ] ;
1007
- } else {
1008
- pose = unityBone . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix ;
1009
- }
1010
- boneToBindPose . Add ( unityBone , pose ) ;
1008
+ var boneInfo = new SkinnedMeshBoneInfo ( skinnedMesh , index ) ;
1009
+ foreach ( var bone in boneList ) {
1010
+ var fbxBone = MapUnityObjectToFbxNode [ bone . gameObject ] ;
1011
+ ExportBoneTransform ( fbxBone , fbxScene , bone , boneInfo ) ;
1011
1012
}
1012
-
1013
- // Step 3: set up the transforms.
1014
- for ( int boneIndex = 0 , n = boneList . Length ; boneIndex < n ; boneIndex ++ ) {
1015
- var unityBone = boneList [ boneIndex ] ;
1016
- var fbxBone = MapUnityObjectToFbxNode [ unityBone . gameObject ] ;
1017
-
1018
- Matrix4x4 pose ;
1019
-
1020
- var bindPose = boneToBindPose [ unityBone ] ;
1021
-
1022
- if ( fbxBone . GetSkeleton ( ) . GetSkeletonType ( ) == FbxSkeleton . EType . eRoot ) {
1023
- // bind pose is local -> root. We want root -> local, so invert.
1024
- pose = ( unityBone . parent . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix * bindPose . inverse ) ;
1025
- } else {
1026
- // Bind pose is local -> parent -> ... -> root.
1027
- // We want parent -> local.
1028
- // Invert our bind pose to get root -> local.
1029
- // The apply parent -> root to leave just parent -> local.
1030
- pose = boneToBindPose [ unityBone . parent ] * bindPose . inverse ;
1031
- }
1032
-
1033
- // FBX is transposed relative to Unity: transpose as we convert.
1034
- FbxMatrix matrix = new FbxMatrix ( ) ;
1035
- matrix . SetColumn ( 0 , new FbxVector4 ( pose . GetRow ( 0 ) . x , pose . GetRow ( 0 ) . y , pose . GetRow ( 0 ) . z , pose . GetRow ( 0 ) . w ) ) ;
1036
- matrix . SetColumn ( 1 , new FbxVector4 ( pose . GetRow ( 1 ) . x , pose . GetRow ( 1 ) . y , pose . GetRow ( 1 ) . z , pose . GetRow ( 1 ) . w ) ) ;
1037
- matrix . SetColumn ( 2 , new FbxVector4 ( pose . GetRow ( 2 ) . x , pose . GetRow ( 2 ) . y , pose . GetRow ( 2 ) . z , pose . GetRow ( 2 ) . w ) ) ;
1038
- matrix . SetColumn ( 3 , new FbxVector4 ( pose . GetRow ( 3 ) . x , pose . GetRow ( 3 ) . y , pose . GetRow ( 3 ) . z , pose . GetRow ( 3 ) . w ) ) ;
1039
-
1040
- // FBX wants translation, rotation (in euler angles) and scale.
1041
- // We assume there's no real shear, just rounding error.
1042
- FbxVector4 translation , rotation , shear , scale ;
1043
- double sign ;
1044
- matrix . GetElements ( out translation , out rotation , out shear , out scale , out sign ) ;
1045
-
1046
- // Export bones with zero rotation, using a pivot instead to set the rotation
1047
- // so that the bones are easier to animate and the rotation shows up as the "joint orientation" in Maya.
1048
- fbxBone . LclTranslation . Set ( new FbxDouble3 ( - translation . X * UnitScaleFactor , translation . Y * UnitScaleFactor , translation . Z * UnitScaleFactor ) ) ;
1049
- fbxBone . LclRotation . Set ( new FbxDouble3 ( 0 , 0 , 0 ) ) ;
1050
- fbxBone . LclScaling . Set ( new FbxDouble3 ( scale . X , scale . Y , scale . Z ) ) ;
1051
-
1052
- // TODO (UNI-34294): add detailed comment about why we export rotation as pre-rotation
1053
- fbxBone . SetRotationActive ( true ) ;
1054
- fbxBone . SetPivotState ( FbxNode . EPivotSet . eSourcePivot , FbxNode . EPivotState . ePivotReference ) ;
1055
- fbxBone . SetPreRotation ( FbxNode . EPivotSet . eSourcePivot , new FbxVector4 ( rotation . X , - rotation . Y , - rotation . Z ) ) ;
1056
- }
1057
-
1058
1013
return true ;
1059
1014
}
1060
1015
@@ -2223,12 +2178,13 @@ protected int ExportAnimationOnly(
2223
2178
// remove the exported bones from the export set
2224
2179
exportData . goExportSet . ExceptWith ( bones ) ;
2225
2180
2181
+ var boneInfo = new SkinnedMeshBoneInfo ( skinnedMesh , boneDict ) ;
2226
2182
foreach ( var bone in bones ) {
2227
2183
FbxNode node ;
2228
2184
if ( ! ExportGameObjectAndParents (
2229
2185
bone . gameObject , unityGO , fbxScene , out node , newCenter ,
2230
2186
exportType , ref numObjectsExported , objectCount ,
2231
- new SkinnedMeshBoneInfo ( skinnedMesh , boneDict )
2187
+ boneInfo
2232
2188
) ) {
2233
2189
// export cancelled
2234
2190
return - 1 ;
@@ -2267,10 +2223,12 @@ protected int ExportAnimationOnly(
2267
2223
class SkinnedMeshBoneInfo {
2268
2224
public SkinnedMeshRenderer skinnedMesh ;
2269
2225
public Dictionary < Transform , int > boneDict ;
2226
+ public Dictionary < Transform , Matrix4x4 > boneToBindPose ;
2270
2227
2271
2228
public SkinnedMeshBoneInfo ( SkinnedMeshRenderer skinnedMesh , Dictionary < Transform , int > boneDict ) {
2272
2229
this . skinnedMesh = skinnedMesh ;
2273
2230
this . boneDict = boneDict ;
2231
+ this . boneToBindPose = new Dictionary < Transform , Matrix4x4 > ( ) ;
2274
2232
}
2275
2233
}
2276
2234
@@ -2323,48 +2281,48 @@ private bool ExportGameObjectAndParents(
2323
2281
ExportTransform ( unityGo . transform , fbxNode , newCenter , exportType ) ;
2324
2282
}
2325
2283
2326
- if ( unityGo . transform . parent != null || unityGo . transform . parent != rootObject . transform . parent ) {
2327
- SkinnedMeshBoneInfo parentBoneInfo = null ;
2328
- if ( boneInfo != null && boneInfo . skinnedMesh . rootBone != null && unityGo . transform != boneInfo . skinnedMesh . rootBone ) {
2329
- parentBoneInfo = boneInfo ;
2330
- }
2331
-
2332
- FbxNode fbxNodeParent ;
2333
- if ( ! ExportGameObjectAndParents (
2334
- unityGo . transform . parent . gameObject ,
2335
- rootObject ,
2336
- fbxScene ,
2337
- out fbxNodeParent ,
2338
- newCenter ,
2339
- TransformExportType . Local ,
2340
- ref exportProgress ,
2341
- objectCount ,
2342
- parentBoneInfo
2343
- ) ) {
2344
- // export cancelled
2345
- return false ;
2346
- }
2347
- fbxNodeParent . AddChild ( fbxNode ) ;
2348
- }
2349
-
2350
2284
if ( unityGo == rootObject || unityGo . transform . parent == null ) {
2351
2285
fbxScene . GetRootNode ( ) . AddChild ( fbxNode ) ;
2286
+ return true ;
2352
2287
}
2353
2288
2289
+ SkinnedMeshBoneInfo parentBoneInfo = null ;
2290
+ if ( boneInfo != null && boneInfo . skinnedMesh . rootBone != null && unityGo . transform != boneInfo . skinnedMesh . rootBone ) {
2291
+ parentBoneInfo = boneInfo ;
2292
+ }
2293
+
2294
+ FbxNode fbxNodeParent ;
2295
+ if ( ! ExportGameObjectAndParents (
2296
+ unityGo . transform . parent . gameObject ,
2297
+ rootObject ,
2298
+ fbxScene ,
2299
+ out fbxNodeParent ,
2300
+ newCenter ,
2301
+ TransformExportType . Local ,
2302
+ ref exportProgress ,
2303
+ objectCount ,
2304
+ parentBoneInfo
2305
+ ) ) {
2306
+ // export cancelled
2307
+ return false ;
2308
+ }
2309
+ fbxNodeParent . AddChild ( fbxNode ) ;
2310
+
2354
2311
return true ;
2355
2312
}
2356
2313
2357
2314
private bool ExportBoneTransform (
2358
2315
FbxNode fbxNode , FbxScene fbxScene , Transform unityBone , SkinnedMeshBoneInfo boneInfo
2359
2316
) {
2360
- if ( boneInfo ! = null || boneInfo . skinnedMesh == null || boneInfo . boneDict == null || unityBone == null ) {
2317
+ if ( boneInfo = = null || boneInfo . skinnedMesh == null || boneInfo . boneDict == null || unityBone == null ) {
2361
2318
return false ;
2362
2319
}
2363
2320
2364
2321
var skinnedMesh = boneInfo . skinnedMesh ;
2365
2322
var boneDict = boneInfo . boneDict ;
2366
2323
var rootBone = skinnedMesh . rootBone ;
2367
2324
2325
+ // setup the skeleton
2368
2326
var fbxSkeleton = fbxNode . GetSkeleton ( ) ;
2369
2327
if ( fbxSkeleton == null ) {
2370
2328
fbxSkeleton = FbxSkeleton . Create ( fbxScene , unityBone . name + SkeletonPrefix ) ;
@@ -2380,26 +2338,21 @@ private bool ExportBoneTransform(
2380
2338
2381
2339
// get bind pose
2382
2340
Matrix4x4 bindPose ;
2383
- int index ;
2384
- if ( boneDict . TryGetValue ( unityBone , out index ) ) {
2385
- bindPose = bindPoses [ index ] ;
2386
- } else {
2387
- bindPose = unityBone . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix ;
2341
+ if ( ! boneInfo . boneToBindPose . TryGetValue ( unityBone , out bindPose ) ) {
2342
+ bindPose = GetBindPose ( unityBone , bindPoses , boneDict , skinnedMesh ) ;
2343
+ boneInfo . boneToBindPose . Add ( unityBone , bindPose ) ;
2388
2344
}
2389
2345
2390
2346
Matrix4x4 pose ;
2391
2347
if ( unityBone == rootBone ) {
2392
2348
pose = ( unityBone . parent . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix * bindPose . inverse ) ;
2393
2349
} else {
2394
2350
// get parent's bind pose
2395
- int pIndex ;
2396
2351
Matrix4x4 parentBindPose ;
2397
- if ( boneDict . TryGetValue ( unityBone . parent , out pIndex ) ) {
2398
- parentBindPose = bindPoses [ pIndex ] ;
2399
- } else {
2400
- parentBindPose = unityBone . parent . worldToLocalMatrix * skinnedMesh . transform . localToWorldMatrix ;
2352
+ if ( ! boneInfo . boneToBindPose . TryGetValue ( unityBone . parent , out parentBindPose ) ) {
2353
+ parentBindPose = GetBindPose ( unityBone . parent , bindPoses , boneDict , skinnedMesh ) ;
2354
+ boneInfo . boneToBindPose . Add ( unityBone . parent , parentBindPose ) ;
2401
2355
}
2402
-
2403
2356
pose = parentBindPose * bindPose . inverse ;
2404
2357
}
2405
2358
0 commit comments