@@ -164,7 +164,7 @@ protected override void LoadContent()
164164 public override Matrix SetRenderMatrices ( ShapePrimitive baseShapePrimitive , Matrix [ ] animatedMatrices , ref Matrix tileTranslation , out Matrix [ ] bones )
165165 {
166166 var shapePrimitive = baseShapePrimitive as GltfPrimitive ;
167- bones = Enumerable . Repeat ( Matrix . Identity , Math . Min ( RenderProcess . MAX_BONES , shapePrimitive . Joints . Length ) ) . ToArray ( ) ;
167+ ( shapePrimitive . RenderBonesCurrent , shapePrimitive . RenderBonesNext ) = ( shapePrimitive . RenderBonesNext , shapePrimitive . RenderBonesCurrent ) ;
168168
169169 if ( LodChanged && ExternalLods . Count > 1 )
170170 {
@@ -173,32 +173,36 @@ public override Matrix SetRenderMatrices(ShapePrimitive baseShapePrimitive, Matr
173173 }
174174 LodChanged = false ;
175175
176- for ( var j = 0 ; j < bones . Length ; j ++ )
176+ for ( var j = 0 ; j < shapePrimitive . Joints . Length ; j ++ )
177177 {
178- bones [ j ] = MsfsFlavoured ? Matrix . Identity : shapePrimitive . InverseBindMatrices [ j ] ;
178+ var bone = MsfsFlavoured ? Matrix . Identity : shapePrimitive . InverseBindMatrices [ j ] ;
179179 var hi = shapePrimitive . Joints [ j ] ;
180180 while ( hi >= 0 && hi < shapePrimitive . Hierarchy . Length )
181181 {
182- Matrix . Multiply ( ref bones [ j ] , ref animatedMatrices [ hi ] , out bones [ j ] ) ;
182+ Matrix . Multiply ( ref bone , ref animatedMatrices [ hi ] , out bone ) ;
183183 hi = shapePrimitive . Hierarchy [ hi ] ;
184184 }
185- Matrix . Multiply ( ref bones [ j ] , ref PlusZToForward , out bones [ j ] ) ;
185+ Matrix . Multiply ( ref bone , ref PlusZToForward , out bone ) ;
186186
187187 // The ConsistGenerator is used to show all the Khronos sample models for testing purposes. However they need adjustments to show them all at once.
188188 if ( ConsistGenerator . GltfVisualTestRun && SampleModelsAdjustments . TryGetValue ( Path . GetFileNameWithoutExtension ( FilePath ) , out var adjustment ) )
189- Matrix . Multiply ( ref bones [ j ] , ref adjustment , out bones [ j ] ) ;
189+ Matrix . Multiply ( ref bone , ref adjustment , out bone ) ;
190190
191- Matrix . Multiply ( ref bones [ j ] , ref tileTranslation , out bones [ j ] ) ;
191+ Matrix . Multiply ( ref bone , ref tileTranslation , out bone ) ;
192+
193+ // Non-skinned primitive
194+ if ( shapePrimitive . Joints . Length == 1 )
195+ {
196+ bones = null ;
197+ return bone ;
198+ }
199+
200+ shapePrimitive . RenderBonesCurrent [ j ] = bone ;
192201 }
193202
194203 // Skinned primitive
195- if ( shapePrimitive . Joints . Length > 1 )
196- return Matrix . Identity ;
197-
198- // Non-skinned primitive
199- var matrix = bones [ 0 ] ;
200- bones = null ;
201- return matrix ;
204+ bones = shapePrimitive . RenderBonesCurrent ;
205+ return Matrix . Identity ;
202206 }
203207
204208 public GltfDistanceLevel SetLod ( int lodId )
@@ -1339,6 +1343,15 @@ public class GltfPrimitive : ShapePrimitive
13391343 {
13401344 public readonly int [ ] Joints ; // Replaces ShapePrimitive.HierarchyIndex for non-skinned primitives
13411345 public readonly Matrix [ ] InverseBindMatrices ;
1346+
1347+ /// <summary>
1348+ /// It is used in <see cref="SetRenderMatrices"/> to store the animated bones until uploading them to GPU.
1349+ /// To avoid garbage creation, this array must be reused each time for a new frame calculation.
1350+ /// However the data usually is not getting uploaded before a new calculation begins, so two set of bones needs to be stored:
1351+ /// one is being recalculated while the other is waiting for the upload.
1352+ /// </summary>
1353+ public Matrix [ ] RenderBonesCurrent ;
1354+ public Matrix [ ] RenderBonesNext ;
13421355
13431356 /// <summary>
13441357 /// Indicates what position in the target a specific vertex attribute is located at. Element [6] is set to 1 if the primitive has a skin.
@@ -1407,6 +1420,8 @@ public GltfPrimitive(Material material, List<VertexBufferBinding> vertexAttribut
14071420 {
14081421 // Skinned model
14091422 Joints = skin . Joints ;
1423+ RenderBonesCurrent = Enumerable . Repeat ( Matrix . Identity , Math . Min ( RenderProcess . MAX_BONES , Joints . Length ) ) . ToArray ( ) ;
1424+ RenderBonesNext = Enumerable . Repeat ( Matrix . Identity , Math . Min ( RenderProcess . MAX_BONES , Joints . Length ) ) . ToArray ( ) ;
14101425
14111426 if ( ! distanceLevel . InverseBindMatrices . TryGetValue ( ( int ) skin . InverseBindMatrices , out InverseBindMatrices ) )
14121427 {
0 commit comments