glTF学习笔记(5)——glTF Tutorials/Buffers, BufferViews, and Accessors

https://github.com/KhronosGroup/glTF-Tutorials/blob/master/gltfTutorial/gltfTutorial_005_BuffersBufferViewsAccessors.md

Buffers

一个buffer表示一个原始的二进制数据块,这个数据块没有固有的结构或意义。buffer使用其URI引用数据,此URI可能指向一个外部文件,也可以直接在JSON文件中使用编码的二进制数据的data URI。The minimal glTF文件的例子中包括了一个buffer,该buffer具有44个字节(byte)的数据,并用data URI编码。

  "buffers" : [
    {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
      "byteLength" : 44
    }
  ],

Image 1: The buffer data, consisting of 44 bytes.

buffer中数据一部分数据可能被作为顶点属性、索引、包含skinning information、animation key frames等信息传递给渲染器(renders)。为了能使用此数据,需要有关此数据的结构(structure)和类型(type)的其他信息。

BufferViews

从buffer构造数据的第一步是使用bufferView对象。bufferView表示一个缓冲区数据的一个“切片”。该切片使用偏移量(offset)和长度(length,以字节byte为单位)定义。The minimal glTF file定义了两个bufferView对象。

  "bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,
      "byteLength" : 36,
      "target" : 34962
    }
  ],

 第一个bufferView引用buffer数据的前六个字节,第二个bufferView引用buffer数据的36个字节,偏移量为8个字节(见图2)。

Image 2: The buffer views, referring to parts of the buffer.

浅灰色显示的字节是正确对其访问器所需的填充字节:

每一个bufferView还额外包含一个target属性。渲染器往后可以使用该属性来对bufferView引用的buffer数据的类型(type)或性质(nature)进行分类。target是一个常量,该常量只是该数据用于顶点属性(vertex attributes,34962,代表ARRAY_BUFFER),或者该数据用于顶点索引(vertex indices, 34963,代表ELEMENT_ARRAY_BUFFER)。

此时,buffer中的数据以被分成多个部分,每个部分由一个bufferView描述。但是,为了能在渲染器中真正使用此数据,还需要有关数据类型和布局的其他信息。

Accessors

一个accessor引用一个bufferView,且包含定义该bufferView的数据类型和布局的属性。

Data type

accessor数据的类型编码在type和componentType属性中。type属性的值是一个字符串,用于指定数据元素是标量(scalars,SCALAR)、向量(vectors,VEC3)还是矩阵(matrices,MAT4)。对于标量值,该值为SCALAR。对于3D向量,该值为VEC3。对于4×4矩阵,该值可以是MAT4。

componentType指定这些数据元素的组件的类型。这是一个GL常量,可以为5126(FLOAT)或5123(UNSIGNED_SHORT),以知识元素分别具有float或unsigned short分量。

这些属性的不同组合可用于描述任意的数据类型。例如:the minimal glTF file包含两个访问器:

  "accessors" : [
    {
      "bufferView" : 0,
      "byteOffset" : 0,
      "componentType" : 5123,
      "count" : 3,
      "type" : "SCALAR",
      "max" : [ 2 ],
      "min" : [ 0 ]
    },
    {
      "bufferView" : 1,
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 1.0, 1.0, 0.0 ],
      "min" : [ 0.0, 0.0, 0.0 ]
    }
  ],

第一个accessor引用索引为0的bufferView,定义了包含索引的buffer数据部分。其类型为“SCALAR”,它的componentType为5123(UNSIGNED)SHORT),这意味着索引存储为scalar unsigned_short。

第二个accessor引用索引为1的bufferView,它定义了buffer数据中包含顶点属性(尤其是顶点位置)的部分。其类型为“VEC3”,组成类型为5126(FLOAT)。因此,该accessor描述了具有浮点分量的3D矢量。

Data layout

accessor第其他属性进一步指定数据的布局(layout)。count属性指示其包含多少个数据元素。在上面的例子中,每个accessor的count属性都是3,分别代表三角形的三个索引和三个顶点。每个accessor还具有一个byteOffset属性。在上面的例子中,两个accessor的byteOffset均为0,因为每个bufferView只被一个accessor引用。但是,当多个accessor引用同一个bufferView时,byteOffset将描述accessor的数据从bufferView中的何处开始。

Data alignment

一个accessor引用的数据可以被发送到显卡(graohics card)以进行渲染,也可以在主机端(host sides)被用作动画(animation)或蒙皮(skinning)数据。因此,accessor中的数据必须基于数据类型进行对齐。例如,当accessor的componentType为5126(FLOAT)时,数据必须在4字节的边界处对齐,因为单个浮点值由四个字节组成。accessor的这种对齐需求是指bufferView和buffer。特别地,对齐的要求如下:

  • accessor的byteOffset必须可被其componentType的大小整除。
  • accessor和它引用的bufferView的byteOffset的值之和必须可以被componentType的大小整除。

在上面的事例中,索引为1的bufferView的byteOffset为8,以便将顶点位置的accessor数据对齐到4字节边界。因此,buffer中的字节6、7是不携带相关数据的填充字节。

图3说明了如何使用bufferView对象构造buffer的原始数据,以及如何使用accessor对象来增加数据类型信息:

 Image 3: The accessors defining how to interpret the data of the buffer views.

Data interleaving

存储在单个bufferView中的属性数据可以存储为结构数组(Array-Of-Structures)。单个bufferView可以以交错(interleaved)的方式包含顶点位置和顶点法线的数据。在这种情况下,accessor的byteOffset定义相应属性的第一个相关数据元素的开头,bufferView定义一个不加的byteStride属性。这是其accessor的一个元素的开始于下一个元素开始之间的字节数。图4是一个在bufferView中以交错方式存储位置和法线属性的事例。

Image4: Interleaved accessors inone buffer view.

Data contents

accessor还包括min和max属性,汇总其数据内容的属性。它们是accessor中包含的所有数据元素的按组件的最小值和最大值。因此,在顶点位置的情况下,min和max属性定义对象的边界框。这对于优先下载或可见性(visibility)监测很有用。通常来说,此信息对于存储和处理渲染器在运行时反量化的量化数据也很有用,但是此量化的详细信息不在此教程的讨论范围内。

Sparse accessors

在2.0版本中,glTF引入了稀疏访问器(sparse accessors)的概念。这是数据的一种特殊表示形式,允许非常紧凑地存储只有几个不同条目(entries)的多个数据块。例如,当存在包含顶点位置的几何数据时,该几何数据可用于多个对象。这可以通过两个对象引用相同的accessors来实现。如两个对象的顶点位置大部分相同,仅几个顶点不同时,不需要将整个几何数据存储两次。相反,可以只存储一次数据,并使用稀疏访问器仅存储第二个对象的不同顶点位置。

下面是一个完整的glTF asset,以嵌入式表示形式,显示了稀疏访问器的实例:

{
  "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"
  }
}

渲染的结果见图5所示:

Image 5: The result of rendering the simple sparse accessor asset.

这个例子中包含两个accessor,一个是mesh的索引,另一个是顶点位置(vertex positions)。引用顶点位置的那个accessor定义了一个额外的accessor.sparse属性,该属性包含有关应该用稀疏数据替换的信息:

 "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
      }
    }
  } ],

这个sparse对象本身定义了将受替换影响的元素数量(count of elements)。sparse.indices属性引用的bufferView包含将被替换的元素的索引,sparse.values引用包含实际数据的bufferView。

在这个例子中,原始几何数据存储在索引为1的bufferView中,它描述了顶点的矩形阵列。sparse.indices引用具有索引2的bufferView,其中包含索引[8, 10, 12]。sparse.values引用索引为3的bufferView,其中包含新的顶点位置,即[(1, 2, 0), (3, 3, 0), (5, 4, 0)]。图6中显示了相应的替换效果。

Image 6: The substitution that is done with the sparse accessor.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值