图形语言传输格式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文件
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Day09】

目录 Mybatis-基础操作-环境准备 Mybatis-基础操作-删除 Mybatis-基础操作-删除(预编译SQL) Mybatis-基础操作-新增 Mybatis-基础操作-新增(主键返回) Mybatis-基础操作-更新 Mybatis-基础操作-查询(根据ID查询) Mybatis-基…

Apache Pig

目录 一、配置说明1.本地模式2.集群模式 二、pig的数据模型三、pig的数据类型四、惰性执行五、pig的基本语法5.1语法说明5.2案例操作 六、pig的自定义函数 一、配置说明 1.本地模式 操作的是Linux系统文件 pig -x local关键日志 当前处于root目录下 2.集群模式 连接的是…

14.1 为什么说k8s中监控更复杂了

本节重点介绍 : k8s中监控变得复杂了,挑战如下 挑战1: 监控的目标种类多挑战2: 监控的目标数量多挑战3: 对象的变更和扩缩特别频繁挑战4: 监控对象访问权限问题 k8s架构图 k8s中监控变得复杂了,挑战如下 挑战1: 监控的目标种类多 对象举例 podnodese…

资料分析系统课-刘文超老师

1、考试大纲 2、解题的问题->解决方法 3、统计术语 基期量与现期量:作为对比参照的时期称为基期,而相对于基期的称为现期。描述具体数值时我们称之为基期量和现期量。 增长量:是指基期量与现期量增长(或减少)的绝对量。增长量是具体值&…

点云数据常见的坐标系有哪些,如何进行转换?

文章目录 一、点云坐标系分类1. 世界坐标系2. 相机坐标系3. 极坐标系4. 笛卡尔坐标系(直角坐标系):5. 传感器坐标系6. 地理坐标系二、坐标系转换方法1. 地理坐标系与投影坐标系之间的转换2. 投影坐标系与局部坐标系之间的转换3. 局部坐标系与3D模型坐标系之间的转换4. 相机坐…

【Grafana】Prometheus结合Grafana打造智能监控可视化平台

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,…

Jenkins+Svn+Vue自动化构建部署前端项目(保姆级图文教程)

目录 介绍 准备工作 配置jenkins 构建部署任务 常见问题 介绍 在平常开发前端vue项目时,我们通常需要将vue项目进行打包构建,将打包好的dist目录下的静态文件上传到服务器上,但是这种繁琐的操作是比较浪费时间的,可以使用jenkins进行自动化构建部署前端vue 准备工作 准备…

【论文阅读】CiteTracker: Correlating Image and Text for Visual Tracking

paper:[2308.11322] CiteTracker: Correlating Image and Text for Visual Tracking (arxiv.org) code:NorahGreen/CiteTracker: [ICCV23] CiteTracker: Correlating Image and Text for Visual Tracking (github.com) 简介 现有的视觉跟踪方法通常以…

[C#学习笔记]注释

官方文档&#xff1a;Documentation comments - C# language specification | Microsoft Learn 一、常用标记总结 1.1 将文本设置为代码风格的字体&#xff1a;<c> 1.2 源代码或程序输出:<code> 1.3 异常指示:<exception> 1.4 段落 <para> 1.5 换行&…

Ubuntu 22.04 make menuconfig 失败原因

先 安装一些配置 linux下使用menuconfig需要安装如下库_menuconfig 安装-CSDN博客 然后 cd 到指定源代码 需要在内核文件目录下编译 Linux 内核源码&#xff08;kernel source&#xff09;路径_--kernel-source-path-CSDN博客 make menuconfig 又报错 说是gcc 12什么什么&…

QT6聊天室项目 网络通信实现逻辑分析

实现逻辑 模块话网络通信设计分析 NetClient类 功能&#xff1a;负责与服务器进行通信httpClient:处理HTTP请求websocketClient&#xff1a;处理WebSocket通信 HTTP请求封装 设计请求和服务器响应的接口设计函数测试网络连接性设计处理的函数处理HTTP请求&#xff08;后期实现…

file | 某文件夹【解耦合】下的文件查找功能实现及功能单元测试

文件查找工具 概要思路OS模块 --- 学习版os.getcwd()os.path.dirname(os.getcwd())os.path.dirname() 和 os.path.basename() OS模块 — 实战版单元测试解耦合 概要 梳理业务主逻辑&#xff1a; 查看存放被采集JSON数据的文件夹内的文件列表【所有 包含文件夹下的文件夹下的文…

【软件工程】软件开发模型

三、瀑布模型 四、几种软件开发模型的主要特点 题目 判断题 选择题 小结

1233333333333

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &#x1f4e2;本文由 JohnKi 原创&#xff0c;首发于 CSDN&#x1f649; &#x1f4e2;未来很长&#…

【leetcode详解】爬楼梯:DP入门典例(附DP通用思路 同类进阶练习)

实战总结&#xff1a; vector常用方法&#xff1a; 创建一个长为n的vector&#xff0c;并将所有元素初始化为某一定值x vector<int> vec(len, x) 代码执行过程中将所有元素更新为某一值x fill(vec.begin(), vec.end(), x) // 更多实战方法欢迎参考文章&#xff1a;…

halcon 自定义距离10的一阶导数幅图,摆脱sobel的3掩码困境

一&#xff0c;为什么要摆脱3的掩码 在处理图像的过程中&#xff0c;会用到平滑算子&#xff0c;很容易破坏边际&#xff0c;所谓的一阶导数sobel只计算掩码为3的差分&#xff0c;在幅度图分割中&#xff0c;往往是很难把握的。 举个例子-现在图像头平滑好了&#xff0c;缺陷…

在亚马逊云科技上利用Graviton4代芯片构建高性能Java应用(上篇)

简介 在AI迅猛发展的时代&#xff0c;芯片算力对于模型性能起到了至关重要的作用。一款能够同时兼具高性能和低成本的芯片&#xff0c;能够帮助开发者快速构建性能稳定的生成式AI应用&#xff0c;同时降低开发成本。今天小李哥将介绍亚马逊推出的4代高性能计算处理器Gravition…

使用vscode上传git远程仓库流程(Gitee)

目录 参考附件 git远程仓库上传流程 1&#xff0c;先将文件夹用VScode打开 2&#xff0c;第一次进入要初始化一下仓库 3&#xff0c;通过这个&#xff08;.gitignore&#xff09;可以把一些不重要的文件不显示 注&#xff1a;&#xff08;.gitignore中&#xff09;可屏蔽…

如何将代理IP设置为ISP:详细指南

在当今互联网时代&#xff0c;代理IP已经成为许多用户保护隐私和提升网络体验的重要工具。而ISP&#xff08;Internet Service Provider&#xff09;的代理IP更是因为其高质量和稳定性备受青睐。本文将详细介绍如何将代理IP设置为ISP&#xff0c;让你在网络世界中享受更优质的上…

RISC-V (十一)软件定时器

主要的思想&#xff1a;硬件定时器是由硬件的定时器设备触发的。软件定时器在硬件定时器的基础上由软件控制实现多个定时器的效果。主要的思路是在trap_handler函数中加入软件代码&#xff0c;使其在设定的时间点 去执行想要执行的功能函数。 定时器的分类 硬件定时器&#xf…