-
Data interleaving The data view of properties stored in a single bufferView can be stored as an array of structures. For example, a single bufferView can interleave data about vertex positions and vertex normals. In this case, the byte offset of the accessor defines the beginning of the first related data element of the corresponding attribute, and the bufferView defines an additional byte step attribute. This is the number of bytes between the beginning of one element of its accessor and the beginning of the next element. The following figure shows an example of how to store interleaved position and normal attributes in bufferView.
As shown in the figure, byteStride is 24, which exists in bufferView -
Data contents Accessors also contain the minimum and maximum attributes that summarize the contents of their data. They are the component minimum and maximum values for all data elements contained in the accessor. Therefore, in the case of vertex positions, the min and Max attributes define the bounding box of the object. This is useful for determining download priority or visibility detection. In general, this information is also useful for storing and processing quantized data that was unquantified by the renderer at run time, but the details of this quantification are beyond the scope of this tutorial.
-
Sparse accessors In version 2.0, the concept of sparse accessor is introduced into glTF. This is a special representation of data, allowing very compact storage of multiple data blocks with only a few different entries. For example, when there is geometry data that contains vertex positions, it can be used for multiple objects. This can be achieved by referencing the same accessor from two objects. If the vertex positions of two objects are basically the same, and only a few vertices are different, it is not necessary to store the entire geometry data twice. Instead, you can store data only once, and use the sparse accessor to store only the vertex positions of the second object.
The following is an example of a complete glTF asset (in an embedded representation) displaying a sparse accessor:
{ "scenes" : [ { "nodes" : [ 0 ] } ], "nodes" : [ { "mesh" : 0 } ], "meshes" : [ { "primitives" : [ { "attributes" : { "POSITION" : 1 }, "indices" : 0 } ] } ], "buffers" : [ { "uri" : "data:application/gltf-buffer;base64,AAAIAAcAAAABAAgAAQAJAAgAAQACAAkAAgAKAAkAAgADAAoAAwALAAoAAwAEAAsABAAMAAsABAAFAAwABQANAAwABQAGAA0AAAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAQAAAAAAAAAAAAABAQAAAAAAAAAAAAACAQAAAAAAAAAAAAACgQAAAAAAAAAAAAADAQAAAAAAAAAAAAAAAAAAAgD8AAAAAAACAPwAAgD8AAAAAAAAAQAAAgD8AAAAAAABAQAAAgD8AAAAAAACAQAAAgD8AAAAAAACgQAAAgD8AAAAAAADAQAAAgD8AAAAACAAKAAwAAAAAAIA/AAAAQAAAAAAAAEBAAABAQAAAAAAAAKBAAACAQAAAAAA=", "byteLength" : 284 } ], "bufferViews" : [ { "buffer" : 0, "byteOffset" : 0, "byteLength" : 72, "target" : 34963 }, { "buffer" : 0, "byteOffset" : 72, "byteLength" : 168 }, { "buffer" : 0, "byteOffset" : 240, "byteLength" : 6 }, { "buffer" : 0, "byteOffset" : 248, "byteLength" : 36 } ], "accessors" : [ { "bufferView" : 0, "byteOffset" : 0, "componentType" : 5123, "count" : 36, "type" : "SCALAR", "max" : [ 13 ], "min" : [ 0 ] }, { "bufferView" : 1, "byteOffset" : 0, "componentType" : 5126, "count" : 14, "type" : "VEC3", "max" : [ 6.0, 4.0, 0.0 ], "min" : [ 0.0, 0.0, 0.0 ], "sparse" : { "count" : 3, "indices" : { "bufferView" : 2, "byteOffset" : 0, "componentType" : 5123 }, "values" : { "bufferView" : 3, "byteOffset" : 0 } } } ], "asset" : { "version" : "2.0" } }
The results are as follows:
This example includes two accessors: one for the index of the mesh, and one for the vertex position. One of the referenced vertex positions defines an additional accessor.sparse attribute that contains information about the sparse data substitution that should be applied:
"accessors" : [ ... { "bufferView" : 1, "byteOffset" : 0, "componentType" : 5126, "count" : 14, "type" : "VEC3", "max" : [ 6.0, 4.0, 0.0 ], "min" : [ 0.0, 0.0, 0.0 ], "sparse" : { "count" : 3, "indices" : { "bufferView" : 2, "byteOffset" : 0, "componentType" : 5123 }, "values" : { "bufferView" : 3, "byteOffset" : 0 } } } ],
This sparse object itself defines the count of elements affected by the substitution. The sparse.indexes property refers to the bufferView containing the index of the element to be replaced. sparse.values refers to the bufferView containing the actual data.
In this case, the original geometry data is stored in the bufferView with index 1. It describes a rectangular array of vertices. Sparse.indexes references the bufferView with index 2, which contains the index [8,10,12]. sparse.values refers to the bufferView with index 3, which contains new vertex positions, namely [(1,2,0), (3,3,0), (5,4,0)]. The effect of applying the corresponding replacement is shown in the following figure.
I think bufferview 3 needs to store at least 13 vertices, because the index needs to specify the replacement of the 13th vertex. But its size is: 36 is exactly the size of the three vertices. So this replacement operation is very strange What data is stored in the Buffer corresponding to sparse.indexes? It must be the index location to be replaced