@@ -130,17 +130,15 @@ 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 , FbxSkelFile ? skeleton )
133+ private static Assimp . Scene AddMeshToScene ( Assimp . Scene scene , 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)
137137 // NOTE3: weights > 4 will get get lost for gltf because we can't tell it to write more weights (AI_CONFIG_EXPORT_GLTF_UNLIMITED_SKINNING_BONES_PER_VERTEX)
138- // we'd either need access to assim's Exporter class directly, or have the ExportFile method modified on the assimp side
139- // TODO: export extra dummy nodes to ensure materials with no meshes (possibly used by LODs only) don't get dropped? (see dd2 ch20_000.mesh.240423143)
140- // also: lods read and export?
138+ // we'd either need access to assimp's Exporter class directly, or have the ExportFile method modified on the assimp side
141139
142- var scene = new Assimp . Scene ( ) ;
143- scene . RootNode = new Node ( rootName ) ;
140+ scene . RootNode ?? = new Node ( rootName ) ;
141+ var matIndexOffset = scene . Materials . Count ;
144142 foreach ( var name in file . MaterialNames ) {
145143 var aiMat = new Material ( ) ;
146144 aiMat . Name = name ;
@@ -152,6 +150,10 @@ private static Assimp.Scene ConvertMeshToAssimpScene(MeshFile file, string rootN
152150
153151 var includeShapeKeys = false ;
154152 var extraBones = new List < Node > ( ) ;
153+ var existingNodes = FlatNodes ( scene . RootNode ) ;
154+ var nodeDict = new Dictionary < string , Node > ( ) ;
155+ foreach ( var ext in existingNodes ) nodeDict . TryAdd ( ext . Name , ext ) ;
156+
155157 if ( bones ? . Count > 0 && file . MeshBuffer ! . Weights . Length > 0 ) {
156158 // insert root bones first to ensure all parents exist
157159 Node boneRoot = scene . RootNode ;
@@ -164,13 +166,19 @@ private static Assimp.Scene ConvertMeshToAssimpScene(MeshFile file, string rootN
164166 }
165167 foreach ( var srcBone in bones ) {
166168 if ( srcBone . parentIndex == - 1 ) {
167- var boneNode = new Node ( srcBone . name , boneRoot ) ;
169+ if ( nodeDict . TryGetValue ( srcBone . name , out var boneNode ) ) {
170+ boneDict [ srcBone . index ] = boneNode ;
171+ continue ;
172+ }
173+
174+ boneNode = new Node ( srcBone . name , boneRoot ) ;
168175 boneDict [ srcBone . index ] = boneNode ;
169176 boneNode . Transform = Matrix4x4 . Transpose ( srcBone . localTransform . ToSystem ( ) ) ;
170177 boneRoot . Children . Add ( boneNode ) ;
171178 if ( srcBone . useSecondaryWeight ) {
172179 boneNode . Children . Add ( new Node ( SecondaryWeightDummyBonePrefix + srcBone . name , boneNode ) ) ;
173180 }
181+ nodeDict [ srcBone . name ] = boneNode ;
174182 }
175183 }
176184
@@ -181,18 +189,25 @@ private static Assimp.Scene ConvertMeshToAssimpScene(MeshFile file, string rootN
181189 pendingBones . Enqueue ( srcBone ) ;
182190 continue ;
183191 }
184- var boneNode = new Node ( srcBone . name , parentBone ) ;
192+
193+ if ( nodeDict . TryGetValue ( srcBone . name , out var boneNode ) ) {
194+ boneDict [ srcBone . index ] = boneNode ;
195+ continue ;
196+ }
197+
198+ boneNode = new Node ( srcBone . name , parentBone ) ;
185199 boneDict [ srcBone . index ] = boneNode ;
186200 boneNode . Transform = Matrix4x4 . Transpose ( srcBone . localTransform . ToSystem ( ) ) ;
187201 if ( srcBone . useSecondaryWeight ) {
188202 boneNode . Children . Add ( new Node ( SecondaryWeightDummyBonePrefix + srcBone . name , boneNode ) ) ;
189203 }
190204 parentBone . Children . Add ( boneNode ) ;
205+ nodeDict [ srcBone . name ] = boneNode ;
191206 }
192207
193208 if ( skeleton != null ) {
194209 foreach ( var refBone in skeleton . Bones ) {
195- var ( exportId , exportBone ) = boneDict . FirstOrDefault ( bb => bb . Value . Name == refBone . name ) ;
210+ var exportBone = nodeDict . GetValueOrDefault ( refBone . name ) ;
196211 if ( exportBone == null ) {
197212 var parentRef = refBone . parentIndex == - 1 ? null : skeleton . Bones [ refBone . parentIndex ] ;
198213 Node ? parent = null ;
@@ -242,37 +257,37 @@ static void RecursiveDuplicateShapeBones(Node parent, HashSet<string> boneNames,
242257 for ( int i = 0 ; i < file . MeshData . LODs . Count ; i ++ ) {
243258 var lod = file . MeshData . LODs [ i ] ;
244259 if ( i == 0 ) {
245- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , includeAllLods ? "lod0_" : "" , extraBones ) ;
260+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , includeAllLods ? "lod0_" : "" , extraBones , matIndexOffset ) ;
246261 if ( ! includeAllLods ) break ;
247262 } else {
248- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "lod{ i } _", extraBones ) ;
263+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "lod{ i } _", extraBones , matIndexOffset ) ;
249264 }
250265 }
251266 }
252267 if ( includeShadows && file . ShadowMesh != null ) {
253268 for ( int i = 0 ; i < file . ShadowMesh . LODs . Count ; i ++ ) {
254269 var lod = file . ShadowMesh . LODs [ i ] ;
255- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "shadow_lod{ i } _", extraBones ) ;
270+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , lod , $ "shadow_lod{ i } _", extraBones , matIndexOffset ) ;
256271 }
257272 }
258273 if ( includeOcclusion && file . OccluderMesh != null ) {
259274 if ( scene . MaterialCount == 0 ) {
260275 scene . Materials . Add ( new Material ( ) { Name = "default" } ) ;
261276 }
262- ExportLod ( file , isGltf , scene , bones , includeShapeKeys , file . OccluderMesh , $ "occ_", extraBones ) ;
277+ ExportLod ( file , isGltf , scene , bones , includeShapeKeys , file . OccluderMesh , $ "occ_", extraBones , matIndexOffset ) ;
263278 }
264279
265280 return scene ;
266281 }
267282
268- private static void ExportLod ( MeshFile file , bool isGltf , Assimp . Scene scene , List < MeshBone > ? bones , bool includeShapeKeys , MeshLOD lod , string namePrefix , List < Node > extraBones )
283+ private static void ExportLod ( MeshFile file , bool isGltf , Assimp . Scene scene , List < MeshBone > ? bones , bool includeShapeKeys , MeshLOD lod , string namePrefix , List < Node > extraBones , int matIndexOffset )
269284 {
270285 var bounds = file . MeshData ? . boundingBox ?? new AABB ( ) ;
271286 foreach ( var mesh in lod . MeshGroups ) {
272287 int subId = 0 ;
273288 foreach ( var sub in mesh . Submeshes ) {
274289 var aiMesh = new Mesh ( PrimitiveType . Triangle ) ;
275- aiMesh . MaterialIndex = sub . materialIndex ;
290+ aiMesh . MaterialIndex = sub . materialIndex + matIndexOffset ;
276291
277292
278293 aiMesh . Vertices . AddRange ( sub . Positions ) ;
0 commit comments