@@ -130,7 +130,7 @@ private static void AddMotToScene(Assimp.Scene scene, MotFile mot, string export
130130 scene . Animations . Add ( anim ) ;
131131 }
132132
133- private static Assimp . Scene ConvertMeshToAssimpScene ( MeshFile file , string rootName , bool isGltf , bool includeAllLods , bool includeShadows , bool includeOcclusion )
133+ private static Assimp . Scene ConvertMeshToAssimpScene ( MeshFile file , string rootName , bool isGltf , bool includeAllLods , bool includeShadows , bool includeOcclusion , FbxSkelFile ? skeleton )
134134 {
135135 // NOTE: every matrix needs to be transposed, assimp expects them transposed compared to default System.Numeric.Matrix4x4 for some shit ass reason
136136 // NOTE2: assimp currently forces vert deduplication for gltf export so we may lose some vertices (https://github.com/assimp/assimp/issues/6349)
@@ -151,6 +151,7 @@ private static Assimp.Scene ConvertMeshToAssimpScene(MeshFile file, string rootN
151151 var bones = file . BoneData ? . Bones ;
152152
153153 var includeShapeKeys = false ;
154+ var extraBones = new List < Node > ( ) ;
154155 if ( bones ? . Count > 0 && file . MeshBuffer ! . Weights . Length > 0 ) {
155156 // insert root bones first to ensure all parents exist
156157 Node boneRoot = scene . RootNode ;
@@ -189,6 +190,27 @@ private static Assimp.Scene ConvertMeshToAssimpScene(MeshFile file, string rootN
189190 parentBone . Children . Add ( boneNode ) ;
190191 }
191192
193+ if ( skeleton != null ) {
194+ foreach ( var refBone in skeleton . Bones ) {
195+ var ( exportId , exportBone ) = boneDict . FirstOrDefault ( bb => bb . Value . Name == refBone . name ) ;
196+ if ( exportBone == null ) {
197+ var parentRef = refBone . parentIndex == - 1 ? null : skeleton . Bones [ refBone . parentIndex ] ;
198+ Node ? parent = null ;
199+ if ( parentRef != null ) {
200+ parent = boneRoot . FindNode ( parentRef . name ) ;
201+ if ( parent == null ) {
202+ throw new NotImplementedException ( "Unordered ref skel bones currently not supported" ) ;
203+ }
204+ }
205+ exportBone = new Node ( refBone . name , parent ) ;
206+ parent ? . Children . Add ( exportBone ) ;
207+ extraBones . Add ( exportBone ) ;
208+ }
209+
210+ exportBone . Transform = Matrix4x4 . Transpose ( Matrix4x4 . CreateScale ( refBone . scale ) * Matrix4x4 . CreateFromQuaternion ( refBone . rotation ) * Matrix4x4 . CreateTranslation ( refBone . position ) ) ;
211+ }
212+ }
213+
192214 if ( includeShapeKeys ) {
193215 if ( isGltf ) {
194216 Logger . Warn ( $ "GLTF exporter does not support enough bones to include shape keys. Mesh will not behave correctly when re-imported. Consider using a different file format.") ;
@@ -220,30 +242,30 @@ static void RecursiveDuplicateShapeBones(Node parent, HashSet<string> boneNames,
220242 for ( int i = 0 ; i < file . MeshData . LODs . Count ; i ++ ) {
221243 var lod = file . MeshData . LODs [ i ] ;
222244 if ( i == 0 ) {
223- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , includeAllLods ? "lod0_" : "" ) ;
245+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , includeAllLods ? "lod0_" : "" , extraBones ) ;
224246 if ( ! includeAllLods ) break ;
225247 } else {
226- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "lod{ i } _") ;
248+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "lod{ i } _", extraBones ) ;
227249 }
228250 }
229251 }
230252 if ( includeShadows && file . ShadowMesh != null ) {
231253 for ( int i = 0 ; i < file . ShadowMesh . LODs . Count ; i ++ ) {
232254 var lod = file . ShadowMesh . LODs [ i ] ;
233- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "shadow_lod{ i } _") ;
255+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "shadow_lod{ i } _", extraBones ) ;
234256 }
235257 }
236258 if ( includeOcclusion && file . OccluderMesh != null ) {
237259 if ( scene . MaterialCount == 0 ) {
238260 scene . Materials . Add ( new Material ( ) { Name = "default" } ) ;
239261 }
240- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , file . OccluderMesh , $ "occ_") ;
262+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , file . OccluderMesh , $ "occ_", extraBones ) ;
241263 }
242264
243265 return scene ;
244266 }
245267
246- private static void ExportLod ( MeshFile file , bool isGltf , Assimp . Scene scene , List < MeshBone > ? bones , bool includeShapeKeys , MeshLOD lod , string namePrefix )
268+ private static void ExportLod ( MeshFile file , bool isGltf , Assimp . Scene scene , List < MeshBone > ? bones , bool includeShapeKeys , MeshLOD lod , string namePrefix , List < Node > extraBones )
247269 {
248270 var bounds = file . MeshData ? . boundingBox ?? new AABB ( ) ;
249271 foreach ( var mesh in lod . MeshGroups ) {
@@ -311,6 +333,19 @@ private static void ExportLod(MeshFile file, bool isGltf, Assimp.Scene scene, Li
311333 }
312334 }
313335 }
336+ foreach ( var extraBone in extraBones ) {
337+ var parentTx = Matrix4x4 . Identity ;
338+ var parent = extraBone . Parent ;
339+ while ( parent != null ) {
340+ parentTx = parentTx * Matrix4x4 . Transpose ( parent . Transform ) ;
341+ parent = parent . Parent ;
342+ }
343+
344+ Matrix4x4 . Invert ( parentTx , out parentTx ) ;
345+ var newBone = new Bone ( ) { Name = extraBone . Name } ;
346+ newBone . OffsetMatrix = Matrix4x4 . Transpose ( parentTx ) ;
347+ aiMesh . Bones . Add ( newBone ) ;
348+ }
314349
315350 if ( sub . Buffer . ExtraWeights != null ) {
316351 for ( int vertId = 0 ; vertId < sub . ExtraWeights . Length ; ++ vertId ) {
0 commit comments