图形语言传输格式glTF和三维瓦片数据3Dtiles(b3dm、pnts)学习

文章目录

  • 一、3DTiles
  • 二、b3dm
  • 三、glTF
    • 1.glTF 3D模型格式有两种
    • 2.glTF 场景描述结构和坐标系
    • 3.glTF的索引访问与ID
    • 4.glTF asset
    • 5.glTF的JSON结构
      • scenes
        • scene.nodes
      • nodes
        • nodes.children
      • transformations
      • 对外部数据的引用
      • buffers 原始二进制数据块,没有固有的结构或含义
      • bufferViews 索引视图(buffer的数据的切片/缓冲区的子集)
      • accessors 访问器
        • Data type 数据类型
          • type (必需)
          • componentType (必需)
          • count (必需)
          • min 和 max 属性
          • 例子
        • Data alignment 数据对齐
        • Data interleaving 数据交错
          • 单属性bufferView
          • 多属性bufferView—— Array-Of-Structures
      • Sparse accessors 稀疏访问器(glTF 2.0)
      • meshes(primitives数组:必需)
        • primitives.attributes
        • primitives.mode —— default: 4 TRIANGLES
        • primitives.targets (Morph Targets 变形目标,glTF 2.0)
        • 例子:最小 glTF 文件
        • 例子:Simple Meshes
      • Skins(后补
      • Instantiation 实例化——同一网格可以由许多节点使用,这些节点可能具有不同的变换
      • Materials
      • Texture
      • images

一、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

原文
是一种针对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的姿势对网格的几何体(顶点)进行变形。
这对于为动画几何体(例如虚拟角色)提供逼真的外观至关重要。
1.0——Skins
教程——019_SimpleSkin
2.0——3.7.3. Skins
属性详解
辅助教程
在这里插入图片描述
在这里插入图片描述

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

Materials

材质定义为着色技术shading technique的实例以及参数化值,例如,光色、镜面反射度或光泽度。着色技术使用 JSON 属性来描述 GLSL 顶点和片段着色器程序的数据类型和语义
以下示例显示了具有环境光颜色、漫反射纹理、自发光颜色、光泽度和镜面反射颜色的 Blinn 着色器

"materials": {"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"}
},

Texture

images

"image01": {"uri": "image01.png"// 通常指向PNG或JPG文件
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/418845.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

表单项标签简单学习

目录 1. 单选框 radio​编辑​编辑​编辑​编辑 2. 复选框 checkbox ​编辑​编辑​编辑 3. 隐藏域 hidden 4. 多行文本框 textarea​编辑​编辑 5. 下拉框 select​编辑​编辑 6. 选择头像​编辑​编辑 <!DOCTYPE html> <html lang"en"> <head&…

自用NAS系列1-设备

拾光坞 拾光坞多账号绑定青龙面板SMBWebdav小雅alist下载到NASDocker安装迅雷功能利用qBittorrentEEJackett打造一站式下载工具安装jackett插件 外网访问内网拾光客户端拾光穿透公网ipv6路由器配置ipv6拾光坞公网验证拾光坞域名验证 拾光坞 多账号绑定 手机注册拾光坞账号&am…

GEE数据集:加拿大卫星森林资源调查 (SBFI)-2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分年龄以及 1985-2020 年林分替代干扰的信息

目录 简介 数据集后处理 数据下载链接 矢量属性 代码 代码链接 引用 许可 网址推荐 0代码在线构建地图应用 机器学习 加拿大卫星森林资源调查 (SBFI) 简介 卫星森林资源清查&#xff08;SBFI&#xff09;提供了 2020 年加拿大森林覆盖、干扰恢复、结构、物种、林分…

海外云手机是否适合运营TikTok?

随着科技的迅猛发展&#xff0c;海外云手机逐渐成为改变工作模式的重要工具。这种基于云端技术的虚拟手机&#xff0c;不仅提供了更加便捷、安全的使用体验&#xff0c;还在电商引流和海外社媒管理等领域展示了其巨大潜力。那么&#xff0c;海外云手机究竟能否有效用于运营TikT…

828华为云征文 | Flexus X 实例服务器网络性能深度评测

引言 随着互联网应用的快速发展&#xff0c;网络带宽和性能对云服务器的表现至关重要。在不同的云服务平台上&#xff0c;即便配置相同的带宽&#xff0c;实际的网络表现也可能有所差异。因此&#xff0c;了解并测试服务器的网络性能变得尤为重要。本文将以华为云X实例服务器为…

Open-Sora代码详细解读(1):解读DiT结构

Diffusion Models专栏文章汇总&#xff1a;入门与实战 前言&#xff1a;目前开源的DiT视频生成模型不是很多&#xff0c;Open-Sora是开发者生态最好的一个&#xff0c;涵盖了DiT、时空DiT、3D VAE、Rectified Flow、因果卷积等Diffusion视频生成的经典知识点。本篇博客从Open-S…

【MySQL】MySQL基础

目录 什么是数据库主流数据库基本使用MySQL的安装连接服务器服务器、数据库、表关系使用案例数据逻辑存储 MySQL的架构SQL分类什么是存储引擎 什么是数据库 mysql它是数据库服务的客户端mysqld它是数据库服务的服务器端mysql本质&#xff1a;基于C&#xff08;mysql&#xff09…

linux系统中,计算两个文件的相对路径

realpath --relative-to/home/itheima/smartnic/smartinc/blocks/ruby/seanet_diamond/tb/parser/test_parser_top /home/itheima/smartnic/smartinc/corundum/fpga/lib/eth/lib/axis/rtl/axis_fifo.v 检验方式就是直接在当前路径下&#xff0c;把输出的路径复制一份&#xff0…

Nginx跨域运行案例:云台控制http请求,通过 http server 代理转发功能,实现跨域运行。(基于大华摄像头WEB无插件开发包)

文章目录 引言I 跨域运行案例开发资源测试/生产环境,Nginx代理转发,实现跨域运行本机开发运行II nginx的location指令Nginx配置中, 获取自定义请求header头Nginx 配置中,获取URL参数引言 背景:全景监控 需求:感知站点由于云台相关操作为 http 请求,http 请求受浏览器…

Redis-主从集群

主从架构 单节点Redis的并发能力是有上限的&#xff0c;要进一步提高Redis的并发能力&#xff0c;就需要搭建主从集群&#xff0c;实现读写分离。 主从数据同步原理 全量同步 主从第一次建立连接时&#xff0c;会执行全量同步&#xff0c;将master节点的所有数据都拷贝给sla…

34465A-61/2 数字万用表(六位半)

34465A-61/2 数字万用表(六位半) 文章目录 34465A-61/2 数字万用表(六位半)前言一、测DC/AC电压二、测DC/AC电流四、测电阻五、测电容六、测二极管七、保存截图流程前言 1、6位半数字万用表通常具有200,000个计数器,可以显示最大为199999的数值。相比普通数字万用表,6位半…

注册安全分析报告:熊猫频道

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【笔记】Java | 三目运算符和Math函数的比较

实际效果 比较两数并赋值&#xff0c;如下两种方法的耗时不会有差异。 result Math.min(result, subLen);result result < subLen ? result : subLen; 源码解析 因为源码Math.min的源码本质就算三目运算符的比较&#xff0c;所以执行结果是一样的。 三目运算符简介 概…

怎么强制撤销excel工作表保护?

经常不是用的Excel文件设置了工作表保护&#xff0c;偶尔打开文件的时候想要编辑文件&#xff0c;但是发现忘记了密码&#xff0c;那么这种情况&#xff0c;我们怎么强制撤销excel工作表保护&#xff1f;今天分享两种解决方法。 方法一、 将excel文件转换为其他文件格式&…

新品上市丨科学级新款制冷相机sM4040A/sM4040B

sM4040B科学级显微制冷相机 特性 sM4040B搭载了 GSENSE4040BSI 3.2 英寸图像传感器&#xff0c;针对传感器固有的热噪声&#xff0c;专门设计了高效制冷模块&#xff0c;使得相机传感器的工作温度比环境温度低达 35-40 度。针对制冷相机常见的低温结雾现象设计了防结雾机制&a…

二百五十九、Java——采集Kafka数据,解析成一条条数据,写入另一Kafka中(一般JSON)

一、目的 由于部分数据类型频率为1s&#xff0c;从而数据规模特别大&#xff0c;因此完整的JSON放在Hive中解析起来&#xff0c;尤其是在单机环境下&#xff0c;效率特别慢&#xff0c;无法满足业务需求。 而Flume的拦截器并不能很好的转换数据&#xff0c;因为只能采用Java方…

鸿蒙自动化发布测试版本app

创建API客户端 API客户端是AppGallery Connect用于管理用户访问AppGallery Connect API的身份凭据&#xff0c;您可以给不同角色创建不同的API客户端&#xff0c;使不同角色可以访问对应权限的AppGallery Connect API。在访问某个API前&#xff0c;必须创建有权访问该API的API…

UE5.3_跟一个插件—Socket.IO Client

网上看到这个插件,挺好! 项目目前也没有忙到不可开交,索性跟着测一下吧: 商城可见,售价72.61人民币! 但是,git上有仓库哦,免费!! 跟着链接先准备起来: Documentation: GitHub - getnamo/SocketIOClient-Unreal: Socket.IO client plugin for the Unreal Engin…

数据仓库理论知识

1、数据仓库的概念 数据仓库&#xff08;英文&#xff1a;Date Warehouse&#xff0c;简称数仓、DW&#xff09;&#xff0c;是一个用于数据存储、分析、报告的数据系统。数据仓库的建设目的是面向分析的集成化数据环境&#xff0c;其数据来源于不同的外部系统&#…

【H2O2|全栈】Markdown | Md 笔记到底如何使用?【前端 · HTML前置知识】

Markdown的一些杂谈 目录 Markdown的一些杂谈 前言 准备工作 认识.Md文件 为什么使用Md&#xff1f; 怎么使用Md&#xff1f; ​编辑 怎么看别人给我的Md文件&#xff1f; Md文件命令 切换模式 粗体、倾斜、下划线、删除线和荧光标记 分级标题 水平线 引用 无序…