@@ -338,8 +338,9 @@ public class GltfDistanceLevel : DistanceLevel
338338 // These are only temporary variables needed during the construction
339339 readonly Stack < int > TempStack = new Stack < int > ( ) ;
340340 readonly List < VertexElement > VertexElements = new List < VertexElement > ( ) ;
341- readonly List < int > Accessors = new List < int > ( ) ;
341+ readonly Dictionary < int , string > Accessors = new Dictionary < int , string > ( ) ;
342342 string DebugName = "" ;
343+ internal const int BUFFER_INDEX_OFFSET = 10000 ; // Arbitrary number
343344
344345 public GltfDistanceLevel ( GltfShape shape , int lodId , Gltf gltfFile , string gltfFileName , GltfDistanceLevel lod0DetailLevel )
345346 {
@@ -499,7 +500,7 @@ void GetBinaryData(GltfShape shape, Gltf gltfFile, string gltfFileName)
499500 // Sparse buffers may index into a null buffer, so create a real one for these.
500501 if ( GetBufferViewSpan ( accessor . BufferView , 0 ) is var buffer && buffer . IsEmpty )
501502 {
502- BinaryBuffers . Add ( 1000 + a , new byte [ accessor . Count * GetSizeInBytes ( accessor ) ] ) ;
503+ BinaryBuffers . Add ( BUFFER_INDEX_OFFSET + a , new byte [ accessor . Count * GetSizeInBytes ( accessor ) ] ) ;
503504 buffer = BinaryBuffers . Last ( ) . Value . AsSpan ( ) ;
504505 }
505506 // It might have already been processed in another distance level.
@@ -550,48 +551,62 @@ void GetBinaryData(GltfShape shape, Gltf gltfFile, string gltfFileName)
550551 // Trigger the loading of the binary buffer.
551552 GetBufferViewSpan ( bufferView . Key , 0 ) ;
552553
553- var previousOffset = 0 ;
554554 var attributes = bufferView . GetEnumerator ( ) ;
555555 var loop = attributes . MoveNext ( ) ;
556+ var semantic = GetVertexElementSemantic ( attributes . Current . Key , out var index ) ;
556557 do
557558 {
558559 DebugName = "" ;
559560 VertexElements . Clear ( ) ;
560561 Accessors . Clear ( ) ;
561- previousOffset = gltfFile . Accessors [ attributes . Current . Value ] . ByteOffset ;
562+ var previousOffset = gltfFile . Accessors [ attributes . Current . Value ] . ByteOffset ;
563+ var currentOffset = previousOffset ;
564+ var previousAttribute = attributes . Current . Key ;
565+ var bindingKey = attributes . Current . Value + ( int ) semantic * BUFFER_INDEX_OFFSET ;
562566
563567 // For interleaved data, multiple vertexElements and multiple accessors will be in a single vertexBuffer.
564568 // For non-interleaved data, we create a distinct vertexBuffer for each accessor.
565569 // A bufferView may consist of a series of (non-interleaved) accessors of POSITION:NORMAL:POSITION:NORMAL:POSITION:NORMAL etc. (See: 2CylinderEngine)
566570 // Also e.g. TEXCOORDS_0 and TEXCOORDS_1 may refer to the same accessor.
571+ // Also POSITION and NORMAL may refer to the same accessor (see: PrimitiveModeNormalsTest), however due to the MonoGame limitations
572+ // we cannot use the same VertexBuffer with two different VertexElementUsage-s, duplicate ones are needed with the same data.
567573 do
568574 {
569- if ( ! Accessors . Contains ( attributes . Current . Value ) && ! VertexBufferBindings . ContainsKey ( attributes . Current . Value ) )
575+ if ( ! Accessors . ContainsKey ( attributes . Current . Value ) && ! VertexBufferBindings . ContainsKey ( bindingKey ) )
570576 {
571577 VertexElements . Add ( new VertexElement ( gltfFile . Accessors [ attributes . Current . Value ] . ByteOffset - previousOffset ,
572- GetVertexElementFormat ( gltfFile . Accessors [ attributes . Current . Value ] , shape . MsfsFlavoured ) ,
573- GetVertexElementSemantic ( attributes . Current . Key , out var index ) , index ) ) ;
574- Accessors . Add ( attributes . Current . Value ) ;
578+ GetVertexElementFormat ( gltfFile . Accessors [ attributes . Current . Value ] , shape . MsfsFlavoured ) , semantic , index ) ) ;
575579 if ( Debugger . IsAttached ) DebugName = ( DebugName != "" ? DebugName + "," : "" ) + attributes . Current . Key ;
576580 }
577- loop = attributes . MoveNext ( ) ;
581+ // Multiple accessors to same bufferview with same semantic. Will reuse the VertexBuffer:
582+ //while (loop && previousOffset == currentOffset && attributes.Current.Key == previousAttribute)
583+ {
584+ if ( ! Accessors . ContainsKey ( attributes . Current . Value ) && ! VertexBufferBindings . ContainsKey ( bindingKey ) )
585+ {
586+ Accessors . Add ( attributes . Current . Value , attributes . Current . Key ) ;
587+ }
588+ loop = attributes . MoveNext ( ) ;
589+ semantic = GetVertexElementSemantic ( attributes . Current . Key , out index ) ;
590+ currentOffset = gltfFile . Accessors [ attributes . Current . Value ] . ByteOffset ;
591+ }
578592 }
579- while ( loop && gltfFile . Accessors [ attributes . Current . Value ] . ByteOffset < previousOffset + byteStride ) ;
593+ while ( loop && previousOffset < currentOffset && currentOffset < previousOffset + byteStride ) ;
580594
581- if ( Debugger . IsAttached ) DebugName += ":" + Path . GetFileNameWithoutExtension ( gltfFileName ) ;
582-
583- if ( Accessors . All ( a => VertexBufferBindings . ContainsKey ( a ) ) )
595+ if ( VertexBufferBindings . ContainsKey ( bindingKey ) )
584596 continue ;
585597
586- var vertexCount = gltfFile . Accessors [ Accessors . First ( ) ] . Count ;
598+ if ( Debugger . IsAttached ) DebugName += ":" + Path . GetFileNameWithoutExtension ( gltfFileName ) ;
599+
600+ var vertexCount = Accessors . Max ( a => gltfFile . Accessors [ a . Key ] . Count ) ;
587601 var vertexBuffer = new VertexBuffer ( shape . Viewer . GraphicsDevice , new VertexDeclaration ( byteStride , VertexElements . ToArray ( ) ) , vertexCount , BufferUsage . None ) { Name = DebugName } ;
588602
603+ byte [ ] binaryBuffer = null ;
589604 if ( gltfFile . BufferViews . ElementAtOrDefault ( bufferView . Key ) is var bv && bv != null )
590605 {
591- var byteOffset = bv . ByteOffset + gltfFile . Accessors [ Accessors . First ( ) ] . ByteOffset ;
606+ var byteOffset = bv . ByteOffset + Accessors . Min ( a => gltfFile . Accessors [ a . Key ] . ByteOffset ) ;
592607 vertexBuffer . SetData ( BinaryBuffers [ bv . Buffer ] , byteOffset , vertexCount * byteStride ) ;
593608 }
594- else if ( BinaryBuffers . TryGetValue ( 1000 + Accessors . First ( ) , out var binaryBuffer ) )
609+ else if ( Accessors . Any ( a => BinaryBuffers . TryGetValue ( BUFFER_INDEX_OFFSET + a . Key , out binaryBuffer ) ) )
595610 {
596611 vertexBuffer . SetData ( binaryBuffer ) ;
597612 }
@@ -603,7 +618,25 @@ void GetBinaryData(GltfShape shape, Gltf gltfFile, string gltfFileName)
603618 }
604619
605620 var vertexBufferBinding = new VertexBufferBinding ( vertexBuffer ) ;
606- VertexBufferBindings . Add ( Accessors . First ( ) , vertexBufferBinding ) ;
621+ VertexBufferBindings . Add ( bindingKey , vertexBufferBinding ) ;
622+
623+ if ( Accessors . Count > 1 )
624+ {
625+ // Multiple accessors may refer to the same bufferview, in which case we may reuse the same VertexBuffer. (See: PrimitiveModeNormalsTest)
626+ // If the accessors ByteOffset is greater than the first, then it is interleaved, leave it alone. If eaqual, then reuse.
627+ // But we need to add it the the bindigs with all keys, otherwise it would not be found.
628+ var minByteOffset = Accessors . Min ( a => gltfFile . Accessors [ a . Key ] . ByteOffset ) ;
629+ for ( var i = 1 ; i < Accessors . Count ; i ++ )
630+ {
631+ var accessor = Accessors . ElementAt ( i ) ;
632+ if ( gltfFile . Accessors [ accessor . Key ] . ByteOffset == minByteOffset )
633+ {
634+ semantic = GetVertexElementSemantic ( accessor . Value , out _ ) ;
635+ bindingKey = accessor . Key + ( int ) semantic * BUFFER_INDEX_OFFSET ;
636+ VertexBufferBindings . Add ( bindingKey , vertexBufferBinding ) ;
637+ }
638+ }
639+ }
607640 }
608641 while ( loop ) ;
609642 }
@@ -846,7 +879,7 @@ static float ToTwoByteFloat(byte[] bytes) // Hi, Lo
846879 return BitConverter . ToSingle ( BitConverter . GetBytes ( ( intVal & 0x8000 ) << 16 | ( exp | mant ) << 13 ) , 0 ) ;
847880 }
848881
849- static VertexElementUsage GetVertexElementSemantic ( string semantic , out int index )
882+ internal static VertexElementUsage GetVertexElementSemantic ( string semantic , out int index )
850883 {
851884 var split = semantic . Split ( '_' ) ;
852885 if ( ! int . TryParse ( split . ElementAtOrDefault ( 1 ) , out index ) )
@@ -1164,7 +1197,11 @@ public GltfSubObject(MeshPrimitive meshPrimitive, string name, int hierarchyInde
11641197 options |= SceneryMaterialOptions . PbrHasIndices ;
11651198 }
11661199
1167- var vertexAttributes = meshPrimitive . Attributes . SelectMany ( a => distanceLevel . VertexBufferBindings . Where ( kvp => kvp . Key == a . Value ) . Select ( kvp => kvp . Value ) ) . ToList ( ) ;
1200+ var vertexAttributes = meshPrimitive . Attributes
1201+ . SelectMany ( a => distanceLevel . VertexBufferBindings
1202+ . Where ( kvp => kvp . Key == a . Value + ( int ) GltfDistanceLevel . GetVertexElementSemantic ( a . Key , out _ ) * GltfDistanceLevel . BUFFER_INDEX_OFFSET )
1203+ . Select ( kvp => kvp . Value ) )
1204+ . ToList ( ) ;
11681205 var vertexCount = vertexAttributes . FirstOrDefault ( ) . VertexBuffer ? . VertexCount ?? 0 ;
11691206
11701207 // Currently the below PBR vertex input combinations are possible. Any model must use one of those pipelines.
@@ -1198,8 +1235,8 @@ public GltfSubObject(MeshPrimitive meshPrimitive, string name, int hierarchyInde
11981235 MaxPosition = new Vector4 ( a . Max [ 0 ] , a . Max [ 1 ] , a . Max [ 2 ] , 1 ) ;
11991236 }
12001237
1201- // Cannot proceed without Normal at all , must add a dummy one.
1202- if ( ! meshPrimitive . Attributes . ContainsKey ( "NORMAL" ) )
1238+ // Cannot proceed without Normal either , must add a dummy one.
1239+ if ( ! vertexAttributes . Any ( a => a . VertexBuffer . VertexDeclaration . GetVertexElements ( ) . Any ( e => e . VertexElementUsage == VertexElementUsage . Normal ) ) )
12031240 {
12041241 vertexAttributes . Add ( new VertexBufferBinding ( new VertexBuffer ( shape . Viewer . GraphicsDevice ,
12051242 new VertexDeclaration ( new VertexElement ( 0 , VertexElementFormat . Color , VertexElementUsage . Normal , 0 ) ) , vertexCount , BufferUsage . None ) { Name = "NORMAL_DUMMY" } ) ) ;
@@ -1208,7 +1245,7 @@ public GltfSubObject(MeshPrimitive meshPrimitive, string name, int hierarchyInde
12081245 else
12091246 options |= SceneryMaterialOptions . PbrHasNormals ;
12101247
1211- // Cannot proceed without TexCoord_0 at all , must add a dummy one.
1248+ // Cannot proceed without TexCoord_0 neither , must add a dummy one.
12121249 if ( ! meshPrimitive . Attributes . ContainsKey ( "TEXCOORD_0" ) )
12131250 {
12141251 vertexAttributes . Add ( new VertexBufferBinding ( new VertexBuffer ( shape . Viewer . GraphicsDevice ,
@@ -1744,7 +1781,10 @@ public void Animate(int animationNumber, float time, Matrix[] animatedMatrices)
17441781 { "AnimatedMorphCube" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17451782 { "AnimatedMorphSphere" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17461783 { "AnimatedTriangle" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1784+ { "AnisotropyBarnLamp" . ToLower ( ) , Matrix . CreateScale ( 10f ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17471785 { "AntiqueCamera" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) } ,
1786+ { "AnisotropyRotationTest" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 5 , 0 ) } ,
1787+ { "AnisotropyStrengthTest" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17481788 { "AttenuationTest" . ToLower ( ) , Matrix . CreateScale ( 0.3f ) * Matrix . CreateTranslation ( 0 , 4 , 0 ) } ,
17491789 { "Avocado" . ToLower ( ) , Matrix . CreateScale ( 30 ) } ,
17501790 { "BarramundiFish" . ToLower ( ) , Matrix . CreateScale ( 10 ) } ,
@@ -1758,33 +1798,65 @@ public void Animate(int animationNumber, float time, Matrix[] animatedMatrices)
17581798 { "BoxTexturedNonPowerOfTwo" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17591799 { "BoxVertexColors" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17601800 { "Buggy" . ToLower ( ) , Matrix . CreateScale ( 0.02f ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1801+ { "ChairDamaskPurplegold" . ToLower ( ) , Matrix . CreateScale ( 3f ) } ,
17611802 { "ClearCoatTest" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) * Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
1762- { "Corset" . ToLower ( ) , Matrix . CreateScale ( 30 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1803+ { "CompareAlphaCoverage" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1804+ { "CompareAmbientOcclusion" . ToLower ( ) , Matrix . CreateScale ( 3 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1805+ { "CompareBaseColor" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1806+ { "CompareClearcoat" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1807+ { "CompareDispersion" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1808+ { "CompareEmissiveStrength" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1809+ { "CompareIor" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1810+ { "CompareIridescence" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1811+ { "CompareMetallic" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1812+ { "CompareNormal" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1813+ { "CompareRoughness" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1814+ { "CompareSheen" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1815+ { "CompareSpecular" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1816+ { "CompareTransmission" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1817+ { "CompareVolume" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1818+ { "Corset" . ToLower ( ) , Matrix . CreateScale ( 30 ) } ,
17631819 { "Cube" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17641820 { "DamagedHelmet" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1765- { "DragonAttenuation" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1821+ { "DiffuseTransmissionPlant" . ToLower ( ) , Matrix . CreateScale ( 4 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1822+ { "DiffuseTransmissionTeacup" . ToLower ( ) , Matrix . CreateScale ( 8 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1823+ { "DirectionalLight" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1824+ { "DispersionTest" . ToLower ( ) , Matrix . CreateScale ( 16 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1825+ { "DragonAttenuation" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1826+ { "DragonDispersion" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17661827 { "EmissiveStrengthTest" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) * Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
17671828 { "EnvironmentTest" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) } ,
17681829 { "FlightHelmet" . ToLower ( ) , Matrix . CreateScale ( 5 ) } ,
17691830 { "Fox" . ToLower ( ) , Matrix . CreateScale ( 0.02f ) } ,
17701831 { "GearboxAssy" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) * Matrix . CreateTranslation ( 80 , - 5 , 0 ) } ,
17711832 { "GlamVelvetSofa" . ToLower ( ) , Matrix . CreateScale ( 2 ) } ,
1833+ { "GlassBrokenWindow" . ToLower ( ) , Matrix . CreateScale ( 5 ) } ,
1834+ { "GlassHurricaneCandleHolder" . ToLower ( ) , Matrix . CreateScale ( 5 ) } ,
1835+ { "GlassVaseFlowers" . ToLower ( ) , Matrix . CreateScale ( 10 ) } ,
17721836 { "InterpolationTest" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1773- { "IridescenceDielectricSpheres" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) * Matrix . CreateTranslation ( 0 , 4 , 0 ) } ,
1837+ { "IORTestGrid" . ToLower ( ) , Matrix . CreateScale ( 5 ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1838+ { "IridescenceAbalone" . ToLower ( ) , Matrix . CreateScale ( 5 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
1839+ { "IridescenceDielectricSpheres" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) * Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
17741840 { "IridescenceLamp" . ToLower ( ) , Matrix . CreateScale ( 5 ) } ,
1775- { "IridescenceMetallicSpheres" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) * Matrix . CreateTranslation ( 0 , 4 , 0 ) } ,
1841+ { "IridescenceMetallicSpheres" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) * Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
17761842 { "IridescenceSuzanne" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17771843 { "IridescentDishWithOlives" . ToLower ( ) , Matrix . CreateScale ( 10 ) } ,
17781844 { "Lantern" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) } ,
1845+ { "MandarinOrange" . ToLower ( ) , Matrix . CreateScale ( 30 ) } ,
17791846 { "MaterialsVariantsShoe" . ToLower ( ) , Matrix . CreateScale ( 5 ) } ,
1847+ { "MeshPrimitiveModes" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 5 , 0 ) } ,
17801848 { "MetalRoughSpheres" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 5 , 0 ) } ,
17811849 { "MetalRoughSpheresNoTextures" . ToLower ( ) , Matrix . CreateScale ( 800 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17821850 { "MorphPrimitivesTest" . ToLower ( ) , Matrix . CreateScale ( 2 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17831851 { "MosquitoInAmber" . ToLower ( ) , Matrix . CreateScale ( 25 ) * Matrix . CreateTranslation ( 0 , 1 , 0 ) } ,
17841852 { "MultiUVTest" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1853+ { "NegativeScaleTest" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
17851854 { "NormalTangentMirrorTest" . ToLower ( ) , Matrix . CreateScale ( 2 ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17861855 { "NormalTangentTest" . ToLower ( ) , Matrix . CreateScale ( 2 ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
17871856 { "OrientationTest" . ToLower ( ) , Matrix . CreateScale ( 0.2f ) * Matrix . CreateTranslation ( 0 , 2 , 0 ) } ,
1857+ { "PlaysetLightTest" . ToLower ( ) , Matrix . CreateScale ( 30 ) } ,
1858+ { "PotOfCoals" . ToLower ( ) , Matrix . CreateScale ( 30 ) } ,
1859+ { "PrimitiveModeNormalsTest" . ToLower ( ) , Matrix . CreateScale ( 0.5f ) * Matrix . CreateTranslation ( 0 , 5 , 0 ) } ,
17881860 { "ReciprocatingSaw" . ToLower ( ) , Matrix . CreateScale ( 0.01f ) * Matrix . CreateTranslation ( 0 , 3 , 0 ) } ,
17891861 { "RecursiveSkeletons" . ToLower ( ) , Matrix . CreateScale ( 0.05f ) } ,
17901862 { "RiggedSimple" . ToLower ( ) , Matrix . CreateTranslation ( 0 , 5 , 0 ) } ,
0 commit comments