@@ -164,7 +164,7 @@ protected override void LoadContent()
164
164
public override Matrix SetRenderMatrices ( ShapePrimitive baseShapePrimitive , Matrix [ ] animatedMatrices , ref Matrix tileTranslation , out Matrix [ ] bones )
165
165
{
166
166
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 ) ;
168
168
169
169
if ( LodChanged && ExternalLods . Count > 1 )
170
170
{
@@ -173,32 +173,36 @@ public override Matrix SetRenderMatrices(ShapePrimitive baseShapePrimitive, Matr
173
173
}
174
174
LodChanged = false ;
175
175
176
- for ( var j = 0 ; j < bones . Length ; j ++ )
176
+ for ( var j = 0 ; j < shapePrimitive . Joints . Length ; j ++ )
177
177
{
178
- bones [ j ] = MsfsFlavoured ? Matrix . Identity : shapePrimitive . InverseBindMatrices [ j ] ;
178
+ var bone = MsfsFlavoured ? Matrix . Identity : shapePrimitive . InverseBindMatrices [ j ] ;
179
179
var hi = shapePrimitive . Joints [ j ] ;
180
180
while ( hi >= 0 && hi < shapePrimitive . Hierarchy . Length )
181
181
{
182
- Matrix . Multiply ( ref bones [ j ] , ref animatedMatrices [ hi ] , out bones [ j ] ) ;
182
+ Matrix . Multiply ( ref bone , ref animatedMatrices [ hi ] , out bone ) ;
183
183
hi = shapePrimitive . Hierarchy [ hi ] ;
184
184
}
185
- Matrix . Multiply ( ref bones [ j ] , ref PlusZToForward , out bones [ j ] ) ;
185
+ Matrix . Multiply ( ref bone , ref PlusZToForward , out bone ) ;
186
186
187
187
// The ConsistGenerator is used to show all the Khronos sample models for testing purposes. However they need adjustments to show them all at once.
188
188
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 ) ;
190
190
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 ;
192
201
}
193
202
194
203
// 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 ;
202
206
}
203
207
204
208
public GltfDistanceLevel SetLod ( int lodId )
@@ -1339,6 +1343,15 @@ public class GltfPrimitive : ShapePrimitive
1339
1343
{
1340
1344
public readonly int [ ] Joints ; // Replaces ShapePrimitive.HierarchyIndex for non-skinned primitives
1341
1345
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 ;
1342
1355
1343
1356
/// <summary>
1344
1357
/// 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
1407
1420
{
1408
1421
// Skinned model
1409
1422
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 ( ) ;
1410
1425
1411
1426
if ( ! distanceLevel . InverseBindMatrices . TryGetValue ( ( int ) skin . InverseBindMatrices , out InverseBindMatrices ) )
1412
1427
{
0 commit comments