图形语言传输格式glTF学习

发布于:2024-09-19 ⋅ 阅读:(11) ⋅ 点赞:(0)

文章目录

一、3DTiles —— 三维瓦片

工具+详解+版权所属@四季留歌

版面问题,详见这里。
3D Tiles 是一种开源的、优化的文件格式,支持逐级细节(LOD)和空间索引,使得数据可以根据视点距离动态加载和卸载。
3DTiles由tileset.json和tile组成,其中tile可以是.b3dm、.i3dm、.pnts、.vctr和.cmpt中的任一种格式文件。

  • 是一种规范,即并没有统一的数据格式,实际上它定义数据的基本框架是瓦片集,瓦片集包括瓦片集数据(tileset.json)和瓦片数据(tile),其中瓦片数据可以是多种文件类型:
    在这里插入图片描述

二、b3dm

版面问题,详见这里。

B3DM 是 3D Tiles 格式中的一种子格式,专门用于表示和存储三维模型。它通常包含几何数据、纹理和其他属性,适用于大规模的3D城市模型和建筑物。B3DM 文件通常封装了 glTF 模型,可以通过 3D Tiles 渲染引擎进行高效展示和流式传输。

即b3dm数据是基于 gltf 的 ( 单模型基础上做了批量化处理 )。
解析
读取工具TinyGLTFLoader——picojson库
格式详解参考文章
工具+格式详解参考文章
在这里插入图片描述

三、glTF——三维图形界的通用格式

格式与规范!!!!!!
官方教程+中文教程
1.0
2.0
属性详解
是一种针对GL(WebGL,OpenGL ES以及OpenGL)接口的运行时资产传递格式,是一种开放标准的3D模型文件格式,glTF通过提供高效、可扩展、可互操作的格式来传输和加载三维内容,填补了3D建模工具与现代图形应用程序之间的空白。

1.glTF 3D模型格式有两种

*.gltf: 基于JSON的文本文件,可使用文本编辑器轻松编辑,通常会引用外部文件,例如纹理贴图、二进制网格数据等;

即以JSON 格式描述模型的结构,并可以包含二进制数据(如顶点数据和纹理)来优化加载性能。

*.glb: 是二进制格式,通常文件较小且自包含所有资源,但不容易编辑。

VS Code编辑器,建议安装 glTF Tools 扩展工具,能够非常方便的查看glTF的数据结构、glTF和glb互转等。
可以说glTF是3D 模型的JPEG格式。

2.glTF 场景描述结构和坐标系

  • JSON格式的文件(.gltf)

包含完整的场景描述,并通过场景结点引用网格进行定义 。包括:节点层次结构、材质(定义了3D对象的外观)、相机(定义义了渲染程序的视锥体设置 )、mesh(网格)、动画(定义了3D对象的变换操作,比如选择、平移操作)、蒙皮(定义了3D对象如何进行骨骼变换)等;

  • .bin包含几何和动画数据以及其他基于缓冲区的数据的二进制文件
  • 图像文件(.jpg,.png)的纹理
  • GLSL 着色器源代码的 GLSL 文本文件 ().glsl

以其他格式定义的资源(例如图像和 GLSL 着色器源代码)可以存储在通过 URI 引用的外部文件中,也可以使用数据 URI 直接嵌入到 JSON 中。
在这里插入图片描述在这里插入图片描述

  • glTF 使用右手坐标系,和opengl一样的坐标系
    在这里插入图片描述

所有线性距离的单位均为米。
所有角度均以弧度为单位。
正旋转是逆时针旋转。

3.glTF的索引访问与ID

场景对象以数组的形式存储在JSON文件的字典中,可以使用ID+数组中各个对象的索引/ID来访问它们:

  • 例子1:
对象里面还可以接着通过索引/id来引用
"buffers": {
    "a-buffer-id1": {
        "byteLength": 1024,
        "type": "arraybuffer",
        "uri": "path-to.bin"
    },
    "a-buffer-id2":{...},
},

"bufferViews": {
    "a-bufferView-id1": {
        "buffer": "a-buffer-id1",//或 "buffer": 0,
        "byteLength": 512,
        "byteOffset": 0
    },
    "a-bufferView-id2": {...}
}
  • 例子2:
"meshes": {
    "FirstExampleMeshId": { ... },
    "SecondExampleMeshId": { ... },
    "ThirdExampleMeshId": { ... }
}

"nodes:" {
    "FirstExampleNodeId": {
        "meshes": ["FirstExampleMeshId"]
    },
    ...
}
或者
"nodes:" {
    "FirstExampleNodeId": {
        "meshes": 01....
    },
    ...
}

不用id直接用索引也行:

"scenes": [
        {
            "name": "singleScene",
            "nodes": [
                0
            ]
        }
    ],
 "scene": 0

glTF 顶级字典对象 (accessors, animations, buffers, bufferViews, cameras, images, materials, meshes, nodes, programs, samplers, scenes, shaders, skins, techniques, and textures)的 ID 位于同一命名空间中,并且是唯一的。

"buffers": {
    "an-id": {
        // ...
    }
},
"bufferViews": {
    "an-id": { // Not allowed since this ID is already used
        // ...
    }
}

非顶级 glTF 字典对象的 ID 都位于其自己的命名空间中,ID 只用在对象中是唯一的,由 JSON 强制执行,例如 不同animation.samplers的id可以重复。
例如,允许执行以下操作:

// gltf1.0
"animations": {
    "animation-0": {
        // ...
        "samplers": {
            "animation-sampler-id": {
                // ...
            }
        }
    },
    "animation-1": {
        // ...
        "samplers": {
            "animation-sampler-id": { // 不会冲突
                // ...
            }
        }
    }
}

4.glTF asset

顶级必须包含 asset 属性,其中必须包含 version 指明 glTF 的版本,还可包含如下的其他附加信息。

"asset": {
  "extras": {
    "author": "EdwinRC (https://sketchfab.com/Edwin3D)",
    "license": "CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/)",
    "source": "https://sketchfab.com/3d-models/low-poly-winter-scene-2ffe1ed449414cc184078dd1e2882284",
    "title": "Low Poly Winter Scene"
  },
  "generator": "Sketchfab-4.86.2",
  "version": "2.0",
  "copyright": "2017 (c) Khronos Group"
}

5.glTF的JSON结构

glTF格式本质上是一个JSON文件。这一文件描述了整个3D场景的内容。
在这里插入图片描述
glTF属性2.0详解

scenes

通过引用node来定义的场景图,glTF asset包含一个或多个scenes,An object containing a list of root nodes to render.
>  在这里插入图片描述

scene.nodes
  • scene.nodes 数组中列出的所有节点都必须是根节点,即,它们不得在任何节点的 node.children 数组中列出。
  • The same root node MAY appear in multiple scenes。
  • 每个元素都必须是唯一的。
"scene": "defaultScene",
"scenes": {
    "defaultScene": {
        "nodes": [
            "node_1"
        ]
    }
},
 "nodes": [
        {
            "name": "singleNode"//索引0
        }
    ],
 "scenes": [
        {
            "name": "singleScene",
            "nodes": [
                0
            ]
        }
    ],
 "scene": 0

scene:根级别属性(注意为单数)标识数组中的哪些场景应在加载时显示,glTF中的场景描述的入口点;如果未定义,则客户端实现可以延迟渲染,直到请求特定场景。

nodes

它可以包含 mesh 或应用平移 (translation)、旋转 (rotation)、缩放 (scale) 或任意矩阵变换 (matrix),可以引用其他(子)节点等。另外,它可以引用附加到该节点的 mesh 或者 camera 实例,或者描述网格变形的 skin 。
更多属性见官方glTF属性2.0详解

nodes.children
children :此节点的子节点的索引,非必须。这些children 节点中的每一个都可以有自己的子节点。
"nodes": [
        {
            "name": "Car",
            "children": [1, 2, 3, 4]
        },
        {
            "name": "wheel_1"
        },
        {
            "name": "wheel_2"
        },
        {
            "name": "wheel_3"
        },
        {
            "name": "wheel_4"
        }
    ]

在这里插入图片描述

nodes[0] 包含子节点 nodes[1],并且应用了旋转变换,这里旋转用四元数表示。
而 nodes[1] 包含了 meshes[0] 的网格数据。
"nodes": [
  {
    "children": [
      1
    ],
    "name": "RootNode (gltf orientation matrix)",
    "rotation": [
      -0.70710678118654746,
      -0,
      -0,
      0.70710678118654757
    ]
  },
  {
    "mesh": 0,
    "name": "Cylinder.008_0"
  },
  // ...
]

transformations

  • 节点的局部变换:
    每个node都可以有一个变换,此转换将应用于附加到节点本身及其所有子节点的所有元素:
matrix矩阵
"nodes": [
        {
            "name": "node-camera",
            "camera": 1,
            "matrix": [
                2.0,    0.0,    0.0,    0.0,
        		0.0,    0.866,  0.5,    0.0,
        		0.0,   -0.25,   0.433,  0.0,
       			10.0,   20.0,   30.0,    1.0
            ]
        }
    ]

在这里插入图片描述
也可以使用translation ,旋转,和scale节点的属性:

TRS 属性
"nodes": [
        {
            "name": "Box",
            "translation": [ 10.0, 20.0, 30.0 ],
   			"rotation": [ 0.259, 0.0, 0.0, 0.966 ],
    		"scale": [ 2.0, 1.0, 0.5 ]
        }
    ]
//伪代码:localTransform = translationMatrix * rotationMatrix * scaleMatrix;必须是这种顺序。

当这三个属性中的任何一个未给定时,将使用单位矩阵。类似地,当一个节点既不包含matrix属性或TRS属性,则其局部变换将成为单位矩阵。

  • 节点的全局变换:
    在这里插入图片描述

接下来是关于二进制数据存储:

对外部数据的引用

在这里插入图片描述

buffers 原始二进制数据块,没有固有的结构或含义

允许高效创建 GL 缓冲区和纹理,因为它们不需要额外的解析。
glTF 可以具有任意数量的buffer,都定义在数组buffers中。

  • 虽然缓冲区的大小没有硬性上限,但 glTF 不应使用大于 2^53 字节的缓冲区,因为某些 JSON 解析器可能无法正确解析它们。
  • 存储为glb 二进制块的缓冲区具有 2byteLength^32-1 字节的隐式限制。
  • 缓冲区数据是 little endian(小端字节顺序)。
    在这里插入图片描述
    "buffers": {
        "duck": {
            "byteLength": 102040,//缓冲区文件大小,必须大于等于该缓冲区
            "type": "arraybuffer",//数据的存储方式,二进制数组缓冲区还是文本
            "uri": "duck.bin"//指向外部文件,例如binary geometry, animation, or skins
        }
    },"buffers": [
       {
           "byteLength": 102040,
           "uri": "duck.bin"
       }
   ]
  • 数据URI

数据URI它直接在JSON文件中对二进制数据进行编码,参考

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

bufferViews 索引视图(buffer的数据的切片/缓冲区的子集)

此切片使用偏移量byteOffset和长度byteLength(以字节为单位)定义。
在这里插入图片描述
在这里插入图片描述

"bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963//表示顶点索引ELEMENT_ARRAY_BUFFER
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,
      "byteLength" : 36,
      "target" : 34962//表示顶点属性ARRAY_BUFFER
    }
  ],

同一缓冲区视图bufferViews 不得同时用于顶点索引ELEMENT_ARRAY_BUFFER和顶点属性ARRAY_BUFFER。

  • target:渲染器稍后可能会使用此属性对缓冲区视图所引用的数据的类型或性质进行分类。
  • 这允许客户端实现提前将每个缓冲区视图指定给适当的处理步骤,例如,具有顶点索引和属性的缓冲区视图将被复制到相应的 GPU 缓冲区,而带有图像数据的缓冲区视图将传递给特定于格式的图像解码器。

在这里插入图片描述

  • 浅灰色显示的字节是正确对齐访问器所需的填充字节,详见下文数据对齐

accessors 访问器

buffers 和 bufferView 不包含类型信息。它们只是定义要从文件中检索的原始数据。glTF 文件中的对象(网格、皮肤、动画)从不直接访问 buffers 或 bufferView,而是通过访问器accessors 访问。

访问器定义了一种从 bufferView 中检索类型化数组数据的方法。访问器指定component type(例如 FLOAT)和type (例如 VEC3),它们组合在一起时定义每个数组元素的完整数据类型
元素可以是,例如,顶点索引vertex indices、顶点属性vertex attributes、动画关键帧animation keyframes等。
访问器还使用属性 byteOffset(指定引用的缓冲区视图bufferView中第一个数据元素的位置) 和 count (数组元素个数)指定 bufferView 中数据的位置和大小。

Data type 数据类型

The type of an accessor’s data is encoded in the type and the componentType properties.

type (必需)

值是一个字符串,用于指定数据元素是标量、向量还是矩阵,即指定了一个元素的组件个数。
在这里插入图片描述

componentType (必需)

访问器组件的数据类型。
UNSIGNED_INT type MUST NOT be used for any accessor that is not referenced by mesh.primitive.indices.

Allowed values:

  • 5120 BYTE
  • 5121 UNSIGNED_BYTE
  • 5122 SHORT
  • 5123 UNSIGNED_SHORT
  • 5125 UNSIGNED_INT
  • 5126 FLOAT
count (必需)

此访问器引用的元素数,count specifies the number of attributes within the bufferView, not the number of bytes。

min 和 max 属性
  • 代表所有数据元素的组件级最小值和最大值,所以就是一个type+component。
  • 如果是vertex positions的accessor,则the min and max properties thus define the bounding box of an object,且为必需。
例子
对应上文bufferView的访问器accessor
 "accessors" : [
    {
      "bufferView" : 0,// "target" : 34963,表示顶点索引ELEMENT_ARRAY_BUFFER
      "byteOffset" : 0,//该访问器第一个数据元素在bufferView中的位置,多个accessor可以指向同一个bufferView
      "componentType" : 5123,// UNSIGNED_SHORT,组件类型
      "count" : 3,//元素个数
      "type" : "SCALAR",//数据类型,指定组件个数
      "max" : [ 2 ],
      "min" : [ 0 ]
    },
    {
      "bufferView" : 1,//"target" : 34962//表示顶点属性ARRAY_BUFFER,可以拥有多个属性
      "byteOffset" : 0,
      "componentType" : 5126,//FLOAT
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 1.0, 1.0, 0.0 ],// 分量个数由type决定,每个分量数据类型由componentType决定
      "min" : [ 0.0, 0.0, 0.0 ]
    }
  ],
Data alignment 数据对齐

访问器引用的数据可以发送到图形卡进行渲染,也可以在主机端用作动画或蒙皮数据。因此,必须根据数据类型对齐存取器的数据。
对齐要求如下:

  • 访问器的 byteOffset 必须能被其 componentType 的大小整除。
  • 访问器的 byteOffset 和它引用的 bufferView 的 byteOffset 之和必须能被其 componentType 的大小整除。

accessor.byteOffset + bufferView.byteOffset能被componentType 的大小(byte)整除。

  • 定义 byteStride 时,它必须是访问器组件类型componentType大小的倍数。

当两个或多个 vertex 属性访问器使用相同的 bufferView 时,必须定义其 byteStride,参考 数据交错

  • 每个访问器都必须适合其 bufferView,不能越界。
  • 出于性能和兼容性原因,vertex 属性的每个元素都必须与 bufferView 内的 4 字节边界对齐

即 此时accessor.byteOffset 和 bufferView.byteStride必须是 4 的倍数。

  • matrix 类型的访问器按列优先顺序存储数据;每列的 start 必须与 4 字节边界对齐。

具体来说,当 ROWS * SIZE_OF_COMPONENT(其中 ROWS 是矩阵的行数,SIZE_OF_COMPONENT指定了分量的字节数)不是 4 的倍数时, (ROWS * SIZE_OF_COMPONENT) % 4 必须在每列的末尾插入填充字节。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对齐要求仅适用于每列的开头,因此如果没有更多数据,则可以省略尾随字节

"bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,
      "byteLength" : 36,
      "target" : 34962
    }
  ],
 "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 ]
    }
  ],

“bufferView” : 1的byteOffset为8,加上"accessors":0的byteOffset为0,能被"componentType" : 5126的大小4整除,因此,缓冲区的字节 6 和 7 是不携带相关数据的填充字节。
在这里插入图片描述

Data interleaving 数据交错

当缓冲区视图bufferView用于顶点属性数据(target : ARRAY_BUFFER)时,它可以具有多个属性,并且可以Data interleaving数据交错

  • 此时将针对这多个属性中的每一个属性,都创建一个专属accessor对其访问数据,即多个accessors 使用相同的缓冲区视图bufferView,则必须定义byteStride(可accessor.byteStride,且未定义则数据将紧密打包)。
  • bufferView.byteStride:访问器的一个元素的开头与下一个元素的开头之间的字节数,同类型顶点属性之间的步幅(前一个头到下一个头,以字节为单位)。
单属性bufferView

即accessor.component字节数*accessor.type字节数。

在这里插入图片描述

在这里插入图片描述

"accessor_1": {
    "bufferView": "bufferView_1",//多个属性/元素
    "byteOffset": 7032,//该访问器第一个数据元素在bufferView中的位置,多个accessor可以指向同一个bufferView
    "byteStride": 12,//元素大小/步长(字节)
    "componentType": 5126, // FLOAT,组件类型
    "count": 586,//元素个数
    "type": "VEC3"//组件个数
}

在此访问器中,componentType 为 5126 (FLOAT),因此每个组件为 4 个字节。类型为 “VEC3”,因此有三个组件。属性类型的大小byteStride为 12 字节 (4 * 3)。

多属性bufferView—— Array-Of-Structures

在这里插入图片描述

sparse accessors 稀疏访问器(glTF 2.0)

当存在包含顶点位置的几何数据时,此几何数据可用于多个对象,这可以通过引用两个对象中的同一访问器来实现。
如果两个对象的顶点位置基本相同,并且只有几个顶点不同,则无需将整个几何数据存储两次。相反,可以只存储一次数据,并使用稀疏访问器仅存储与第二个对象不同的顶点位置(即用稀疏访问器数据替换原来的几何数据,构成新的几何对象)。

  • sparse 对象包含以下 REQUIRED 属性:
  • count: number of displaced elements,需要位移元素的数量,或者需要替换的顶点的数量。
    This number MUST NOT be greater than the number of the base accessor elements.
    此数字不得大于基于的访问器元素的数量。
  • indices: 描述bufferView(Required ),componentType(Required ),byteOffset等。
    索引必须形成一个严格递增的序列。并且The number of indices is equal to count.。
  • values: 描述bufferView(Required),byteOffset等。
  • PS: the referenced buffer view MUST NOT have its target or byteStride properties defined
{
  "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// 顶点索引ELEMENT_ARRAY_BUFFER,而下面几个bufferView受sparse引用,
    // MUST NOT have its target or byteStride properties defined. 
  }, {
    "buffer" : 0,
    "byteOffset" : 72,
    "byteLength" : 168
  }, {
    "buffer" : 0,
    "byteOffset" : 240,
    "byteLength" : 6
  }, {
    "buffer" : 0,
    "byteOffset" : 248,
    "byteLength" : 36
  } ],
  // 两个访问器,一个用于网格的索引(0);一个用于顶点位置(1),并且附加 accessor.sparse 属性
  "accessors" : [ {
    "bufferView" : 0,
    "byteOffset" : 0,
    "componentType" : 5123,//2byte
    "count" : 36,//2*36 = 72,对应"bufferView" : 0中"byteLength" : 72
    "type" : "SCALAR",//1分量
    "max" : [ 13 ],
    "min" : [ 0 ]
  }, {
    "bufferView" : 1,
    "byteOffset" : 0,
    "componentType" : 5126,//float,4
    "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// unsigned_short,2byte
      },
      "values" : {
        "bufferView" : 3,
        "byteOffset" : 0
      }
    }
  } ],
  
  "asset" : {
    "version" : "2.0"
  }
}

用于顶点位置(1),并且附加 accessor.sparse 属性:

 "accessors" : [ 
  ...
  {
    "bufferView" : 1,
    "byteOffset" : 0,
    "componentType" : 5126,//float,4byte
    "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//UNSIGNED_SHORT,2byte
      },
      "values" : {
        "bufferView" : 3,//包含新的顶点坐标位置
        "byteOffset" : 0
      }
    }
  } ],

1.原始几何数据在bufferView:1中,34 = 12字节,1214 = 168字节,对应bufferView:0中"byteLength",配合"byteLength" : 72,代表从"buffer" : 0的72~72+168字节都是bufferView:1。一个元素为vec3f,有14个,其实又buffer中数据可知对应的是14个坐标点:
在这里插入图片描述
2.接下来是accessor:1中sparse accessor,有3个元素。

  • 首先sparse.indices索引属性对应的bufferView:2是从"buffer" : 0中的72+168=240字节开始(也和bufferView:2中"byteOffset" : 240对应上)。代表了3个用UNSIGNED_SHORT表示的索引,3*2byte = 6(对应bufferView:2中"byteLength" : 6)。
  • 其次是sparse.values值属性对应的bufferView:3是从"buffer" : 0中的240+6+2(为了字节对齐246不能整除4) = 248字节开始。代表了3个vec3f,即3个需要替换的新顶点坐标位置。
    在这里插入图片描述
    在这里插入图片描述

meshes(primitives数组:必需)

Any node MAY contain one mesh

  • meshs被定义为primitives数组,对应GL绘图所需的数据。
  • primitives可以指定一个或多个"attributes" ,对应于绘制调用中使用的顶点属性(类似opengl中顶点属性概念)。
  • Indexed primitives可以定义 “indices”。
  • attributes和indices定义为访问器
  • 每个primitive还可以指定一个材质material 和一个与 GL 基元类型相对应的基元类型(例如,triangle )
  • If material is undefined, then a default material MUST be used.

每个primitive基元对应一个 GL 绘制调用(当然,引擎可以自由地批量绘制调用)。
定义基元的 indices 属性时,它会引用用于索引数据的访问器,并且应使用 GL 的 drawElements 函数。
如果未定义 indices 属性,则应使用 GL 的 drawArrays 函数,其 count 等于 attributes 属性引用的任何访问器accessor 的 count 属性(对于给定的基元,它们都相等)。

primitives.attributes
  • attributes的名称对应于标识 vertex attribute顶点属性的枚举值,此值将映射到网格的 GLSL 着色器中的特定命名属性

有效的attributes的名称有:

  • 1.0:POSITION, NORMAL, TEXCOORD, COLOR, JOINT, and WEIGHT。
  • 2.0:POSITION、NORMAL、TANGENT、TEXCOORD_n、COLOR_n、JOINTS_n 和 WEIGHTS_n。
    可以是 [semantic]_[set_index] 的形式,例如 TEXCOORD_0、TEXCOORD_1 等。
    特定于应用程序的属性语义必须以下划线开头,例如 _TEMPERATURE。特定于应用程序的属性语义不得使用 unsigned int 组件类型。
  • attributes的值是包含数据的访问器accessor 的 ID。
    下面定义了每个attribute 的有效访问器type 类型和component type组件类型:
    在这里插入图片描述
    在这里插入图片描述
    注意:
  • POSITION accessor 必须定义其 min 和 max 属性。
  • 每个 TANGENT accessor 元素的 W 分量必须设置为 1.0 或 -1.0。
  • 当 COLOR_n attribute 使用“VEC3”类型的访问器时,必须假定其 alpha 分量的值为 1.0。
  • 采用 [semantic]_[set_index] 格式时,所有索引必须以 0 开头,并且是连续的正整数:TEXCOORD_0、TEXCOORD_1 等。索引不得使用前导零来填充位数(例如,不允许使用 TEXCOORD_01)。
  • All attribute accessors for a given primitive MUST have the same count.
  • When indices property is not defined, attribute accessors’ count indicates表示 the number of vertices to render。
  • when indices property is defined, it indicates the upper (exclusive) bound on the index values in the indices accessor(它表示 indices 访问器中索引值的上限(不包括)), i.e., all index values MUST be less than attribute accessors’ count(因为索引从0开始)。
  • indices accessors 不得包含所用组件类型的最大可能值(例如,255 表示无符号字节,65535 表示无符号整数,4294967295表示无符号整数)。

最大值会触发某些图形 API 中的基元重启,并且需要客户端实现重新构建索引缓冲区。

  • 当 indices 属性未定义时,要渲染的顶点索引数由attribute accessors的count 定义(使用范围 [0…count) 中的隐含值)。
  • 定义 indices 属性时,要渲染的顶点索引数由 indices 引用的accessors的count 定义。在任何一种情况下,顶点索引的数量都必须对所使用的拓扑类型有效+拓扑类型定义如下:
  • Points :pi = {vi};顶点索引的数量MUST be non-zero。
    在这里插入图片描述
  • Line Strips:pi = {vi, vi+1};顶点索引的数量MUST be 2 or greater。
    在这里插入图片描述
  • Line Loops:pi = {vi, vi+1};顶点索引的数量MUST be 2 or greater。
    在这里插入图片描述
  • Lines:pi = {v2i, v2i+1};顶点索引的数量MUST be divisible by 2 and non-zero.
    在这里插入图片描述
  • Triangles:pi = {v3i, v3i+1, v3i+2};顶点索引的数量MUST be divisible by 3 and non-zero.
    在这里插入图片描述
  • Triangle Strips:pi = {vi, vi+(1+i%2), vi+(2-i%2)};
    在这里插入图片描述
  • Triangle Fans:pi = {vi+1, vi+2, v0};
    在这里插入图片描述
  • 网格几何图形不应包含退化的线条或三角形,即每个拓扑基元多次使用同一顶点的线条或三角形。
  • 如果未指定切线,则应使用默认MikkTSpace算法计算切线,并使用与法线纹理关联的指定顶点位置、法线和纹理坐标。
  • 如果未指定法线,则客户端实现必须计算flat normals平坦法线,并且必须忽略提供的切线(如果存在)。‘
  • 同一三角形的顶点应具有相同的 tangent.w 值。当同一三角形的顶点具有不同的 tangent.w 值时,其切线空间被视为未定义。
  • bitangent vectors的计算方式是:取法线和切线 XYZ 向量的叉积,并将其乘以切线的 W 分量:
    bitangent = cross(normal.xyz, tangent.xyz) * tangent.w
primitives.mode —— default: 4 TRIANGLES

Allowed values:

0 POINTS

1 LINES

2 LINE_LOOP

3 LINE_STRIP

4 TRIANGLES

5 TRIANGLE_STRIP

6 TRIANGLE_FAN

primitives.targets (Morph Targets 变形目标,glTF 2.0)

教程参考,建议在学完动画animations后观看

  • 从版本 2.0 开始,glTF 支持定义网格的变形目标Morph Targets(可变形的网格,存储某些网格属性attributes的置换或差异),在运行时,这些差异可能会以不同的权重添加到原始网格中,以便为网格的各个部分制作动画。这通常用于角色动画中,例如,对虚拟角色的不同面部表情进行编码。
    例如,索引 i 处的基元的变形目标顶点 POSITION 是按以下方式计算的:
primitives[i].attributes.POSITION +
  weights[0] * primitives[i].targets[0].POSITION +
  weights[1] * primitives[i].targets[1].POSITION +
  weights[2] * primitives[i].targets[2].POSITION + ...
  • All primitives MUST have the same number of morph targets in the same order.
  • targets 支持至少三个属性 — POSITION、NORMAL 和 TANGENT — 用于变形。可以选择支持变形的 TEXCOORD_n 和/或 COLOR_n 属性。
  • targets.attribute 的有效访问器type 类型和component type组件类型:
    在这里插入图片描述
    在这里插入图片描述
  • POSITION 访问器必须定义其 min 和 max 属性
  • POSITION、NORMAL 和 TANGENT 属性的置换必须在影响网格顶点的任何变换矩阵 (如skinning 蒙皮或节点变换) 之前应用。
  • 当COLOR_n delta 使用“VEC3”类型的访问器时,必须假定其 alpha 分量的值为 0.0(注意与primitives.attributes的区别)。
  • 应用颜色增量后,每个 COLOR_0 变形访问器元素的所有组件都必须限制在 [0.0, 1.0] 范围内。
  • morph target accessors必须与the accessors of the original primitive具有相同的count 。
  • 具有targets 的mesh还可以定义一个可选的 mesh.weights 属性来存储默认targets 的权重。当 node.weights 定义时,必须使用这些权重。当 mesh.weights 未定义时,默认目标的权重为零。
  • 变形目标的数量没有限制。但是一般支持至少 8 个 morphed 属性,即一个target有一个attribute,则应支持8个target;一个target有两个attribute,则应支持4个target.
{
    "primitives": [
        {
            "attributes": {
                "NORMAL": 23,
                "POSITION": 22,
                "TANGENT": 24,
                "TEXCOORD_0": 25
            },
            "indices": 21,
            "material": 3,
            "targets": [
                {
                    "NORMAL": 33,
                    "POSITION": 32,
                    "TANGENT": 34
                },
                {
                    "NORMAL": 43,
                    "POSITION": 42,
                    "TANGENT": 44
                }
            ]
        }
    ],
    "weights": [0, 0.5]
}
例子:最小 glTF 文件
{
  "scene": 0,
  "scenes" : [
    {
      "nodes" : [ 0 ]
    }
  ],
  
  "nodes" : [
    {
      "mesh" : 0
    }
  ],
  
  "meshes" : [
    {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : 1// 看accessor:1
        },
        "indices" : 0// 看accessor:0
      } ]
    }
  ],

  "buffers" : [
    {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
      "byteLength" : 44
    }
  ],
  "bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963// 顶点索引ELEMENT_ARRAY_BUFFER
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,//字节对齐,因为6不是4的倍数!
      "byteLength" : 36,
      "target" : 34962// 顶点属性ARRAY_BUFFER
    }
  ],
  "accessors" : [
    {
      "bufferView" : 0,
      "byteOffset" : 0,
      "componentType" : 5123,//UNSIGNED_SHORT,2byte
      "count" : 3,
      "type" : "SCALAR",//1
      "max" : [ 2 ],
      "min" : [ 0 ]
    },
    {
      "bufferView" : 1,
      "byteOffset" : 0,
      "componentType" : 5126,// float,4byte
      "count" : 3,
      "type" : "VEC3",//3
      "max" : [ 1.0, 1.0, 0.0 ],
      "min" : [ 0.0, 0.0, 0.0 ]
    }
  ],
  
  "asset" : {
    "version" : "2.0"
  }
}

在这里插入图片描述

例子:Simple Meshes
{
  "scene": 0,
  "scenes" : [
    {
      "nodes" : [ 0, 1]
    }
  ],
  "nodes" : [
    {
      "mesh" : 0
    },
    {
      "mesh" : 0,//网格被渲染了两次。通过将网格附加到两个不同的节点+节点下的变换来实现
      "translation" : [ 1.0, 0.0, 0.0 ]
    }
  ],
  
  "meshes" : [
    {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : 1,
          "NORMAL" : 2
        },
        "indices" : 0
      } ]
    }
  ],

  "buffers" : [
    {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8AAAAAAAAAAAAAgD8=",
      "byteLength" : 80
    }
  ],
  "bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,
      "byteLength" : 72,
      "target" : 34962
    }
  ],
  "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 ]
    },
    {
      "bufferView" : 1,
      "byteOffset" : 36,
      "componentType" : 5126,
      "count" : 3,
      "type" : "VEC3",
      "max" : [ 0.0, 0.0, 1.0 ],
      "min" : [ 0.0, 0.0, 1.0 ]
    }
  ],
  
  "asset" : {
    "version" : "2.0"
  }
}

在这里插入图片描述

Skins(后补

glTF 支持顶点蒙皮vertex skinning,这允许根据骨架skeleton的姿势对网格的几何体(顶点)进行变形。
这对于为动画几何体(例如虚拟角色)提供逼真的外观至关重要。
在这里插入图片描述
在这里插入图片描述

Instantiation 实例化——同一网格可以由许多节点使用,这些节点可能具有不同的变换

Textures, Images, and Samplers

glTF 2.0把纹理访问access分为三种不同类型的对象:Textures纹理, Images图像, and Samplers采样器。

textures

纹理存储在textures数组中,一个纹理由图像索引image index定义,由source属性和采样器sampler索引表示。

{
    "textures": [
        {
            "sampler": 0,// 采样器索引
            "source": 2// 纹理资源,The index of the image used by this texture.
        }
    ]
}
  • glTF 2.0 仅支持静态 2D 纹理。
  • When texture.sampler is undefined, a sampler with repeat wrapping (in both directions) and auto filtering MUST be used.
images

纹理引用的图像存储在images数组中。

{
    "images": [
        {
            "uri": "duckCM.png"
        },
        {
            "bufferView": 14,
            "mimeType": "image/jpeg"
        }
    ]
}

一般(非必需)每个image都包含一个:

  • URI(或 IRI)到受支持图像格式之一的外部文件,或者包含嵌入数据的数据 URI,或对 bufferView 的引用(此时必须定义 images.mimeType图像的媒体类型,且和uri互斥)。
    其中MIME:(Multipurpose Internet Mail Extensions) 是描述消息内容类型的标准,用来表示文档、文件或字节流的性质和格式。
  • 以下用于手动确定某些图片的媒体类型:
    在这里插入图片描述
  • 定义 image.mimeType 属性时,图像数据必须与 image.mimeType 属性匹配。
  • 纹理坐标的原点 (0, 0) 对应于纹理图像的左上角:
    在这里插入图片描述
  • 大多数image是由material属性使用。
samplers

采样器存储在samplers 数组中。每个采样器都指定filtering 过滤和wrapping 环绕模式。
在这里插入图片描述

samplers.magFilter和samplers.minFilter

过滤模式控制纹理的放大和缩小。

  • sampler.magFilter放大模式包括:
  • Nearest:9728,对于每个请求的纹素坐标,采样器会选择具有最近坐标的纹素。
  • Linear:9729,对于每个请求的纹素坐标,采样器会计算几个相邻纹素的加权和。此过程有时称为 “双线性插值”。
  • sampler.minFilter缩小模式:
  • Nearest:9728
  • Linear:9729
  • Nearest-mipmap-nearest:9984,对于每个请求的纹素坐标,采样器首先选择原始图像的预缩小版本之一,然后选择具有最近(以曼哈顿距离为单位)坐标的纹素。
  • Linear-mipmap-nearest:9985 ,对于每个请求的纹素坐标,采样器首先选择原始图像的预缩小版本之一,然后从中计算几个相邻纹素的加权和。
  • Nearest-mipmap-linear:9986,对于每个请求的纹素坐标,采样器首先选择原始图像的两个预缩小版本,选择与每个图像具有最近(以曼哈顿距离为单位)坐标的纹素,并在这两个中间结果之间执行最终线性插值。
  • Linear-mipmap-linear:9987 ,对于每个请求的纹素坐标,采样器首先选择原始图像的两个预缩小版本,从每个版本计算几个相邻纹素的加权和,并在这两个中间结果之间执行最终线性插值。此过程有时称为 “三线性插值”。
  • 为了正确支持 mipmap 模式,客户端实现应在运行时生成 mipmap。当无法生成运行时 mipmap 时,客户端实现应覆盖缩小筛选模式:
    在这里插入图片描述
samplers.wrapping

通过TEXCOORD_n属性值提供的每顶点纹理坐标针对图像大小进行规范化:
在这里插入图片描述

  • 支持的模式:
  • Repeat:10497 ,重复,纹理坐标小数部分的映射:
    在这里插入图片描述
  • Mirrored Repeat:33648 ,镜像重复,此模式与 repeat 相同,但当整数部分(向 −∞ 截断)为奇数时,会翻转方向:在这里插入图片描述
  • CLAMP_TO_EDGE:33071
{
    "samplers": [
        {
            "magFilter": 9729,//LINEAR 
            "minFilter": 9987,//LINEAR_MIPMAP_LINEAR
            "wrapS": 10497,//REPEAT
            "wrapT": 10497//REPEAT
        }
    ]
}
非 2 的幂次方纹理

在对非 2 的幂次方纹理的平台上运行时,客户端实现应调整其大小(以便其水平和垂直大小是 2 的幂)。

特别是环绕模式为repeat和mirrored repeat,或者缩小器具有mipmapping属性。

materials

材质定义为着色技术shading technique的实例以及参数化值(用一组通用参数定义材质),例如,光色、镜面反射度或光泽度。着色技术使用 JSON 属性来描述 GLSL 顶点和片段着色器程序的数据类型和语义

这些参数参考了基于物理的渲染PBR中广泛使用的材质。例如metallic-roughness material model金属粗糙度模型,对应于Materials 中pbrMetallicRoughness属性(未定义则使用默认值)。
其他材质表示,如 specular-glossiness-model ,通过扩展支持。在这里插入图片描述

materials.pbrMetallicRoughness

没有必需的属性。
如果因子和纹理都存在,则因子值将充当相应纹理值的线性乘数。
基础颜色base color:即对象表面的“主”颜色

  • baseColorFactor —— number [4] —— default: [1,1,1,1],材质基础颜色因子。
  • baseColorTexture —— textureInfo —— The base color texture基色纹理,必须包含使用 sRGB 光电传递函数编码的 8 位值,因此 RGB 值在用于任何计算之前必须解码为实际线性值。为了实现正确的滤波,应在执行线性插值之前对传递函数进行解码。

金属值metallic value:一个参数,用于描述材料的反射行为与金属的反射行为的相似程度

  • metallicFactor —— default: 1 —— 值范围从 0.0 (非金属) 到 1.0 (金属)。
  • metallicRoughnessTexture —— textureInfo,绿色通道包含粗糙度值,蓝色通道包含金属度值,每个通道可以使用超过 8 位的位。

粗糙度值roughness value:指示表面的粗糙程度,影响光散射

  • roughnessFactor —— default: 1 —— 值范围介于 0.0 (平滑) 到 1.0 (粗糙)。
    在这里插入图片描述

根据金属度的值,底色有两种不同的解释。当材质为金属时,基色是法向入射处测得的特定反射率值 (F0)。对于非金属,基础颜色表示材质的反射漫反射颜色。在此模型中,无法为非金属指定 F0 值,而是使用 4% (0.04) 的线性值。

textureInfo

在这里插入图片描述

例子:将纹理用于其 base color 属性的材质
{
    "materials": [
        {
            "pbrMetallicRoughness": {
                "baseColorTexture": {
                    "index": 0,//纹理卡槽
                    "texCoord": 1//纹理的 TEXCOORD 属性的集索引。
                },
            }
        }
    ],
    "textures": [
        {
            "source": 0// image索引
        }
    ],
    "images": [
        {
            "uri": "base_color.png"
        }
    ]
}

假设从 baseColorTexture 采样 8 位 RGBA 值 [64, 124, 231, 255],并假设 baseColorFactor 为 [0.2, 1.0, 0.7, 1.0]。然后,最终的基色值将是(在解码传递函数并乘以因子之后):
[0.051 * 0.2, 0.202 * 1.0, 0.799 * 0.7, 1.0 * 1.0] = [0.0102, 0.202, 0.5593, 1.0]
除了材质属性之外,如果基元使用属性语义属性 COLOR_0 指定顶点颜色,则上面这值将充当基础颜色的附加线性乘数。

以下示例显示了具有环境光颜色、漫反射纹理、自发光颜色、光泽度和镜面反射颜色的 Blinn 着色器

"materials": {
    "blinn-1": {// blinn-1为着色器
        "technique": "technique1",
        "values": {
            "ambient": [
                0,
                0,
                0,
                1
            ],
            "diffuse": "texture_file2",
            "emission": [
                0,
                0,
                0,
                1
            ],
            "shininess": 38.4,
            "specular": [
                0,
                0,
                0,
                1
            ]
        }
        "name": "blinn1"
    }
},
其他纹理

根据着色模型,可以将其他效果应用于对象表面,可以与金属粗糙度材质模型以及其他材质模型一起使用。这些通常以纹理和缩放因子的组合形式给出:

  • normal :material.normalTexture ,法线贴图,用于调制表面法线,使其能够模拟更精细的几何细节,而无需牺牲更高的网格分辨率。
    在这里插入图片描述
  • occlusion :material.occlusionTexture,遮挡纹理,指从环境源接收较少间接照明的区域。可用于模拟对象相互自阴影的效果

纹理的红色通道对遮挡值进行编码,其中 0.0 表示完全遮挡区域(无间接照明),1.0 表示未遮挡区域(完全间接照明)。其他纹理通道(如果存在)不会影响遮挡。
在这里插入图片描述

  • emissive : material.emissiveTexture+material.emissiveFactor(default: [0,0,0]) ,自发光纹理,描述对象表面中发射具有特定颜色的光的部分。

纹理必须包含使用 sRGB 光电传递函数编码的 8 位值,因此 RGB 值在用于任何计算之前必须解码为实际线性值。
在这里插入图片描述

例子:使用 pbrMetallicRoughness 参数定义的材质以及其他纹理
{
    "materials": [
        {
            "name": "Material0",
            "pbrMetallicRoughness": {
                "baseColorFactor": [ 0.5, 0.5, 0.5, 1.0 ],
                "baseColorTexture": {
                    "index": 1,
                    "texCoord": 1
                },
                "metallicFactor": 1,
                "roughnessFactor": 1,
                "metallicRoughnessTexture": {
                    "index": 2,
                    "texCoord": 1
                }
            },
            "normalTexture": {
                "scale": 2,
                "index": 3,
                "texCoord": 1
            },
            "emissiveFactor": [ 0.2, 0.1, 0.0 ]
        }
    ]
}
materials.alphaMode —— default: "OPAQUE"不透明

定义如何解释 alpha 值。Alpha 值取自金属粗糙度材质模型的基色的第四个分量。

  • OPAQUE:渲染的输出是完全不透明的,并且将忽略任何 Alpha 值。
  • MASK :渲染的输出是完全不透明或完全透明的,具体取决于 Alpha 值和指定的 Alpha 截止值。
  • BLEND :使用“over”运算符将渲染的输出与背景组合在一起。
materials.alphaCutoff —— default: 0.5

当 alphaMode 设置为 MASK 时,alphaCutoff 属性指定截止阈值。如果 alpha 值大于或等于 alphaCutoff 值,则将其渲染为完全不透明,否则,将其渲染为完全透明。alphaCutoff 值被忽略。

materials.doubleSided —— default: false

当此值为 false 时,将启用背面剔除,即仅渲染正面三角形。

animations

所有动画都存储在asset的 animations 数组中,定义为一组通道(animations.channels 属性)和一组采样器(animations.samplers ),这些采样器使用含有关键帧数据和插值方法(samplers 属性)的指定访问器。

在这里插入图片描述

animations.channel

在这里插入图片描述

animations.channel.target

Within one animation, each target (a combination of a node and a path) MUST NOT be used more than once.
它使用其 node 属性标识要对哪个节点进行动画处理,以及使用 path 对节点的哪个属性进行动画处理。

  • node:如果未定义 node,则应忽略 channel
  • path :必需, Valid path names are “translation”, “rotation”, “scale”, and “weights”.不包含具有变形目标的网格物体的节点不能以 “weights” 路径为目标。
animations.sampler

在这里插入图片描述

  • 动画采样器的输入访问器必须定义其 min 和 max 属性。
animations.sampler.interpolation

键之间的插值是使用 interpolation 属性中指定的插值方法执行的。

  • LINEAR
  • STEP
  • CUBICSPLINE在这里插入图片描述
例子:A Simple Animation
{
  "scene": 0,
  "scenes" : [
    {
      "nodes" : [ 0 ]
    }
  ],
  
  "nodes" : [
    {
      "mesh" : 0,
      "rotation" : [ 0.0, 0.0, 0.0, 1.0 ]
      //给定的值是描述 “旋转约 0 度” 的四元数,因此三角形将以其初始方向显示。
    }
  ],
  
  "meshes" : [
    {
      "primitives" : [ {
        "attributes" : {
          "POSITION" : 1
        },
        "indices" : 0
      } ]
    }
  ],
  
  "animations": [
    {
      "samplers" : [
        {
          "input" : 2,// 描述动画关键帧的时间
          "interpolation" : "LINEAR",
          "output" : 3//每个元素都是具有浮点分量的 4D 向量。
          //这些是对应于动画的 5 个关键帧的旋转,以四元数表示
        }
      ],
      "channels" : [ {
        "sampler" : 0,
        "target" : {
          "node" : 0,
          "path" : "rotation"
        }
      } ]
    }
  ],

  "buffers" : [
    {
      "uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
      "byteLength" : 44
    },
    {
      "uri" : "data:application/octet-stream;base64,AAAAAAAAgD4AAAA/AABAPwAAgD8AAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAD0/TQ/9P00PwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAAPT9ND/0/TS/AAAAAAAAAAAAAAAAAACAPw==",
      "byteLength" : 100
    }
  ],
  "bufferViews" : [
    {
      "buffer" : 0,
      "byteOffset" : 0,
      "byteLength" : 6,
      "target" : 34963
    },
    {
      "buffer" : 0,
      "byteOffset" : 8,
      "byteLength" : 36,
      "target" : 34962
    },
    {
      "buffer" : 1,
      "byteOffset" : 0,
      "byteLength" : 100
    }
  ],
  "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 ]
    },
    {
      "bufferView" : 2,
      "byteOffset" : 0,
      "componentType" : 5126,
      "count" : 5,
      "type" : "SCALAR",
      "max" : [ 1.0 ],
      "min" : [ 0.0 ]
    },
    {
      "bufferView" : 2,
      "byteOffset" : 20,
      "componentType" : 5126,
      "count" : 5,
      "type" : "VEC4",
      "max" : [ 0.0, 0.0, 1.0, 1.0 ],
      "min" : [ 0.0, 0.0, 0.0, -0.707 ]
    }
  ],
  
  "asset" : {
    "version" : "2.0"
  }
  
}

6.GLB

为了避免此文件大小和处理开销,引入了一种容器格式,即二进制 glTF,它使 glTF 资产(包括 JSON、缓冲区和图像)能够存储在单个二进制 blob 中。
Binary glTF 资产仍然可以引用外部资源。例如,想要将图像保存为单独文件的应用程序可能会将场景所需的所有内容(图像除外)嵌入到二进制 glTF 中。
用于二进制 glTF 的文件扩展名是 .glb。

结构

二进制 glTF(例如,可以是文件)具有以下结构:

  • 一个 12 字节的前导码,称为标头。
  • 包含 JSON 内容和二进制数据的一个或多个数据块。

包含 JSON 的数据块可以像往常一样引用外部资源,也可以引用存储在其他数据块中的资源。

二进制 glTF 布局

在这里插入图片描述

Header 标头
  • magic = 0x676c5446——>ASCII 字符串 glTF,可用于将数据标识为二进制 glTF。
  • version:表示二进制 glTF 容器格式的版本。
  • length:二进制 glTF 的总长度,包括 header 和所有块,以字节为单位。
chunk 块

每个块的开头和结尾必须与 4 字节边界对齐

  • chunkLength :是 chunkData 的长度,以字节为单位。
  • chunkType :表示 chunk 的类型。在这里插入图片描述

Structured JSON Content:

  • 此数据块必须是二进制 glTF 资源的第一个数据块。通过首先读取此 chunk,实现能够逐步从后续 chunk 中检索资源。这样,还可以从 Binary glTF 资产中仅读取选定的资源子集。
  • 此块必须用尾随空格字符 (0x20) 填充以满足对齐要求。参考glTF对齐规则。

Binary buffer:

  • 此数据块包含几何体、动画关键帧、皮肤和图像的二进制负载。
  • 此数据块必须是 Binary glTF 资产的第二个数据块。
  • 此块必须用尾随零 (0x00) 填充以满足对齐要求。
  • 当二进制缓冲区为空或通过其他方式存储时,应省略此块。

包含 GLB 存储的 BIN 区块提供的数据的缓冲区必须是 buffers 数组的第一个元素,并且它的 buffer.uri 属性必须未定义。

{
    "buffers": [
        {
            "byteLength": 35884// 引用 GLB 存储的数据
        },
        {
            "byteLength": 504,
            "uri": "external.bin"//指向外部资源
        }
  ]
}

网站公告

今日签到

点亮在社区的每一天
去签到