了解 glTF 2.0 格式

news2024/11/29 13:35:37
推荐:使用 NSDT场景编辑器快速搭建3D应用场景

介绍

glTF 代表 GL 传输格式。

glTF 是一种用于存储和加载 3D 场景的标准化文件格式,其基本目的是由 3D 创建工具轻松生成并被任何图形应用程序使用,无论使用何种 API,处理最少。

它与其他格式的主要区别在于,glTF 将其数据作为 GPU 就绪的首要任务。这意味着在将文件数据馈送到 GPU 之前,格式化/调整/解释文件上的数据所需的处理步骤更少。

了解文件格式后,您将欣赏整个资产生成流程的点击效果;从 3D 编辑工具到如何将其输出输入图形管线,在我看来,这就是 glTF 的魔力,它以可移植和标准化的方式弥合了设计和实现之间的差距。

文件格式

glTF包括:

  • JSON 文件:描述场景、节点及其层次结构;网格、材质、相机、光源。它还包含指向二进制和图像数据的指针。
  • 二进制数据:场景中的实际几何体和动画数据。
  • 图像文件: 图像数据存储为 JPG 或 PNG。

图 1:来自 Khronos glTF 2.0 规范的 glTF2.0 概述,打开gltf编辑器,查看glb模型文件。

生成或第一个 glTF 2.0 文件

Blender 2.8,一个免费的3D建模工具,有一个一流的glTF 2.0导出器:

https://docs.blender.org/manual/en/2.80/addons/io_scene_gltf2.html

使用它的导出器,我从起始场景生成了一个 glTF 2.0 文件:

场景描述为:

1.- 每边 2m 的立方体,其中心位于原点,它有 8 个顶点(导出者可能会增加顶点的数量和顺序):

  1. (-1, -1, 1)
  2. (1, -1, 1)
  3. (-1, -1, -1)
  4. (1, -1, -1)
  5. (-1, 1, 1)
  6. (1, 1, 1)
  7. (-1, 1, -1)
  8. (1, 1, -1)

立方体具有默认材料分配。

2.- 具有以下功能的相机:

  1. 位置在 (7.35889 m, -6.92579 m, 4.95831 m)
  2. 旋转 (0.483536, 0.208704, 0.336872, 0.780483)

3.- 光源具有:

  1. 位置在 (4.07625 m, 1.00545 m, 5.90386 m)
  2. 旋转 (0.169076, 0.272171, 0.75588, 0.570948)

图 2:Blender 的开始场景、立方体、摄像机和光源

图3.导出此场景时,我使用了以下配置: 请注意 +Y 向上设置。Blender在+Z向上配置下工作,因此导出器将为我们更改它。

按下导出按钮后,您将拥有 2 个文件:

*.gltf

*。.bin

打开gltf文件看一看,它会分为几个部分:

资产和场景

"asset" : {        "generator" : "Khronos glTF Blender I/O v1.1.46",        "version" : "2.0"    },    "scene" : 0,    "scenes" : [        {            "name" : "Scene",            "nodes" : [                0,                1,                2            ]        }    ],

  • “asset”描述了用于创建文件的生成器和glTF的版本,在我们的例子中它将是2.0
  • “scene”指定在加载时将显示场景数组中的哪些可用场景。在我们刚刚生成的文件中,我们只有一个场景,所以它将是0。
  • “scenes”是描述需要渲染以显示该场景的对象的场景数组。这些对象称为“节点”,我们在“场景”中的“节点”标签以 [0, 1, 2] 作为其值。

节点

"nodes" : [        {            "mesh" : 0,            "name" : "Cube"        },        {            "name" : "Light",            "rotation" : [                0.16907551884651184,                0.7558804154396057,                -0.2721710503101349,                0.5709475874900818            ],            "translation" : [                4.076250076293945,                5.903860092163086,                -1.0054500102996826            ]        },        {            "name" : "Camera",            "rotation" : [                0.483536034822464,                0.33687159419059753,                -0.20870360732078552,                0.7804827094078064            ],            "translation" : [                7.358890056610107,                4.958310127258301,                6.925789833068848            ]        }    ],

  • “节点”是将要渲染的实际对象,“name”字段是可选的,但大多数 3D 建模工具会为每个对象生成一个名称。请注意这些名称如何与搅拌机场景中的名称相对应。
  • “网格”是我们节点的第一个属性,“网格”是我们对象的几何体,稍后会描述。在这里,我们指定此场景的节点中包含哪个网格。
  • 它还包含有关这些物体的初始转换的信息,特别是对于我们的相机和光线,还记得两者都有位置和旋转吗?好吧,它们也包括在这里,只需注意 3 件事:
  • Y 轴和 Z 轴已从 -Y 更改为 +Z。
  • 在 Json 文件中,旋转的顺序为 X、Y、Z、W,在 Blender 中为 W、X、Y、Z。
  • 旋转存储为四元数,而不是矩阵或欧拉角。在编写渲染器代码时,我们需要牢记这一点。

材料

推荐使用GTLF编辑器来3D模型的材质属性。

"materials" : [        {            "doubleSided" : true,            "emissiveFactor" : [                0,                0,                0            ],            "name" : "Material",            "pbrMetallicRoughness" : {                "baseColorFactor" : [                    0.800000011920929,                    0.800000011920929,                    0.800000011920929,                    1                ],                "metallicFactor" : 0,                "roughnessFactor" : 0.4000000059604645            }        }    ],

  • “材料”是下一个条目,它将指定我们的几何构成的表面的属性。
  • “双面”指定我们的多边形面是否将被剔除,具体取决于它们的缠绕顺序。此设置可以直接在建模工具中指定,在Blender中,它在材料设置中

图4.在搅拌机中指定剔除参数

  • 我们的样本未使用“发射因子”
  • “名称”是材料,名称,它与您在Blender中分配的材料名称相匹配。
  • “pbr金属粗糙度”是 PBR 渲染中使用的基色、金属和粗糙度的参数值,它们与材质节点的设置相匹配:

图5.搅拌机的材料描述;基色为:R: 0.8克: 0.8深: 0.8A: 1.0 金属色设置为 0 粗糙度设置为 0.4

网 格

"meshes" : [        {            "name" : "Cube",            "primitives" : [                {                    "attributes" : {                        "POSITION" : 0,                        "NORMAL" : 1,                        "TEXCOORD_0" : 2                    },                    "indices" : 3,                    "material" : 0                }            ]        }    ],

  • “网格”:此属性将我们的几何体描述为由多个属性构建的基元;我们的立方体将具有:
  • 属性:
  • 顶点位置:“位置”
  • 顶点法线:“正常”
  • 纹理坐标:“TEXCOORD_0”
  • 将定义创建每个三角形的顶点的索引。
  • 我们的网格将使用的材料。

访问

"accessors" : [        {            "bufferView" : 0,            "componentType" : 5126,            "count" : 24,            "max" : [                1,                1,                1            ],            "min" : [                -1,                -1,                -1            ],            "type" : "VEC3"        },        {            "bufferView" : 1,            "componentType" : 5126,            "count" : 24,            "type" : "VEC3"        },        {            "bufferView" : 2,            "componentType" : 5126,            "count" : 24,            "type" : "VEC2"        },        {            "bufferView" : 3,            "componentType" : 5123,            "count" : 36,            "type" : "SCALAR"        }    ],

  • “访问器”是我们访问存储所有强大数据的二进制文件的方式,并检索渲染几何体所需的数据。多维数据集的二进制文件具有:
  • 顶点位置、法线、纹理坐标和索引。
  • 每个访问器从缓冲区视图中获取数据,它将获取数据类型“类型”的数字“计数”,该数据类型的每个组件也具有特定的“组件类型”。
  • 第一个访问器将获取 24(“计数”)VEC3(“类型”),该 VEC3 的每个组件都是一个浮点数(“componentType”),因此总共它将获取 24*3 个浮点数
  • 第二个访问器获取相同数量的数据,但从不同的缓冲区视图中,这对应于我们的顶点法线
  • 第三个访问器获取 24 个浮点型 VEC2,这些是纹理坐标
  • 最后一个访问器获取 36 个短整数,这些是将组装我们的三角形的索引的标量。
  • 有关访问器类型的详细信息:https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#accessors

缓冲区和缓冲区视图

"bufferViews" : [        {            "buffer" : 0,            "byteLength" : 288,            "byteOffset" : 0        },        {            "buffer" : 0,            "byteLength" : 288,            "byteOffset" : 288        },        {            "buffer" : 0,            "byteLength" : 192,            "byteOffset" : 576        },        {            "buffer" : 0,            "byteLength" : 72,            "byteOffset" : 768        }    ],

  • bufferViews”表示缓冲区中包含的数据块。它们使用索引“缓冲区”指向特定的缓冲区,并且该缓冲区中的数据由“byteOffset”和“byteLength”分隔。
  • bufferView 0 指向缓冲区 0,它的偏移量为 0,长度为 288 字节。将此数据与我们的访问器结构匹配,您可以看到顶点位置存储在缓冲区的这一部分中,并使用此缓冲区视图进行访问。

"buffers" : [        {            "byteLength" : 840,            "uri" : "DefaultCube.bin"        }    ]

缓冲区”指定我们的数据所在的位置及其大小。这意味着我们的立方体的几何形状存储在“DefaultCube.bin”

将数据提取到C++应用程序 – 使用 nlohmann/json

我们现在知道我们需要获取的数据在哪里,但我们仍然需要一种方法来获取它。

市面上有多个 Json 解释器,但我决定使用这个:

https://github.com/nlohmann/json

因为它可以用作单个标头并且易于使用。

包含“nlohmann/json.hpp”标头并添加命名空间后,可以使用下面的代码将整个 json 文件填充到可解析的 json 对象中。

#include "nlohmann/json.hpp" using json = nlohmann::json; int main(){    std::ifstream input("Content/DefaultCube.gltf");    if (!input)    {        std::cout << "Could not find gltf file" << std::endl;        return -1;    } json cubeFile;    input >> cubeFile;

拥有此对象后,如果需要,可以逐个访问属性:

例如,要提取“场景”属性:

json scenes = cubeFile["scenes"];

如果你打印出场景的内容,你会得到这个:

[{“名称”:“场景”,“节点”:[0,1,2]}]

该库还使您可以轻松访问存储在其中的各个值,假设您想从“scenes”属性访问节点索引并将它们存储在int向量中:

json nodeOverview = scenes[0]["nodes"];    std::vector<uint32_t> nodeIndices;    nodeIndices.resize(nodeOverview.size());    for (uint32_t i = 0; i < nodeIndices.size(); i++)    {        nodeIndices[i] = nodeOverview[i];    }

使用Niels Lohmann的这个很酷的json工具,我们可以继续开始从Json和bin文件中填充数据结构。

对于此项目,我们将提取:

网格 – 位置、法线、坐标、索引和材料。

相机 – 位置和旋转。

光 – 位置和旋转。

唯一需要从.bin文件中提取其他信息的是网格。

存储数据

现在,我们将它存储在易于访问的结构中,我使用 glm (https://glm.g-truc.net/0.9.9/index.html ) 作为它们的向量和矩阵结构及其各种数学函数;glm 很方便,因为它已经包含了 vec3 和 vec2 的定义,可以直接与我们的 glTF 文件中的 VEC3 和 VEC2 匹配。从下面的结构中可以看出,我将使用这些类型的向量来存储我的网格数据。

struct pbrMaterial {    glm::vec4 color;    float metallicFactor;    float roughnessFactor;}; struct mesh {    std::string name;    std::vector<glm::vec3> positions;    std::vector<glm::vec3> normals;    std::vector<glm::vec2> texCoords;    std::vector<uint16_t> indices;    std::vector<pbrMaterial> materials;

从文件中获取网格数据需要我们:

  • 读取 nodes 属性并解析它以检查其中的“mesh”属性:

json nodes = cubeFile["nodes"];for (uint32_t i = 0; i < nodes.size(); i++){  if (nodes[i].find("mesh") != nodes[i].end())  {    //There is a mesh in this node:

  • 如果 “nodes” 属性中有一个 mesh 属性,然后存储它指向的网格索引,这个索引会让你知道你会从 “meshes” 属性中选择哪个数组元素:

json node = nodes[i];int meshIndex = node["mesh"];

  • 使用此索引,您现在可以解析 “meshes” 属性,并在 “mesh” 的 “primives” 属性中查找我们想要查找的相应“属性”;找到要查找的属性后,它将为您提供“accessor”属性的索引
  • 日清

json meshes = cubeFile["meshes"];json meshPrimitives = meshes[meshIndex]["primitives"];if (meshPrimitives[0]["attributes"].find("POSITION") !=    meshPrimitives[0]["attributes"].end()){  positionAccessorIndex = meshPrimitives[0]["attributes"]["POSITION"];}

  • 现在您知道了访问器索引,您已经拥有了从二进制文件中获取实际数据所需的一切!!
  • accessor[positionAccessorIndex][“count”] 会让你知道你需要为多少个数据类型的元素分配。
  • accessor[positionAccessorIndex][“bufferView”] 会告诉你要访问哪个缓冲区视图索引,bufferViewIndex。
  • bufferView[bufferViewIndex][“byteLength”] 将为您提供将从缓冲区获取的字节数。
  • bufferView[bufferViewIndex][“byteOffset”] 提供偏移量,您可以在缓冲区中找到属性。

json accessors = cubeFile["accessors"];json bufferViews = cubeFile["bufferViews"]; std::ifstream binFile("Content/DefaultCube.bin", std::ios_base::binary); meshes.positions.resize(accessors[cubeScene.meshes[0].positionAccessorIndex]["count"]); uint32_t bufferViewIndex = accessors[positionAccessorIndex]["bufferView"];uint32_t bytesCount = bufferViews[bufferViewIndex]["byteLength"];uint32_t byteOffset = bufferViews[bufferViewIndex]["byteOffset"];binFile.seekg(0);binFile.seekg(byteOffset);binFile.read((char *)meshes.positions.data(), bytesCount);

完成此步骤后,您的仓位即可发送到任何图形 API。

将数据馈送到 Vulkan 图形管道

大部分代码是直接从以下位置窃取的:

https://github.com/Overv/VulkanTutorial/blob/master/code/27_model_loading.cpp

删除了他们的tinyobjloader依赖项,并添加了我们自己的原始glTF解析器来获取顶点和正常数据。

图6.由 Vulkan 图形管道呈现的默认立方体。

由3D建模学习工作室 整理翻译,转载请注明出处!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

软考(1)-面向对象的概念

目录 一. 软考基本信息 1. 软考时间&#xff1a; 2. 软考科目&#xff1a; 3.专业知识介绍 -- 综合知识考点分布 4. 专业介绍 -- 软件设计考点分布 二. 面向对象概念 1. 封装 考点一&#xff1a;对象 考点二&#xff1a;封装private 2. 继承 考点三&#xff1a;类 考…

python初阶

基本类型 int float str bool list--列表 [1,2,3] tuple--元组 (1,2,3) set---集合 {1,2,3} dict---字典 {1&#xff1a;”python","acwing":2,3:4.0}int支持高精度&#xff0c;没有大小限制 赋值 a3 b3.0 c‘s’ d“asdf” 单引号和双引号是没有区别…

macos 不支持svn安装

macos 10.13可能不支持svn命令,所以要安装 xcode-select --install 弹窗在线安装失败的话只能手动下载安装 打开:Sign In - Apple 搜索Command Line Tools (macOS 10.13) 下载9.4.1版本直接安装后即可

每天一个工业通信协议(4)2023.8.30 (I2C接口)

文章目录 参考文献1.I2C介绍2.I2C接口2.1 位传输,识别2.2 传输数据3.I2C的电气连接参考文献 广州周立功单片机发展有限公司 《I2C总线规范》 1.I2C介绍 为了使这些相似之处对系统设计者和器件厂商都得益 而且使硬件效益最大电路最简单 Philips 开发了一个简单的双向两线总线…

L1-012 计算指数 C++

#include<iostream> #include<math.h> using namespace std; int main() {int n;int ret;cin >> n;if (n < 10) {ret pow(2, n);cout << "2^" << n << " " << ret<<endl;}return 0; } 所用知识点 …

入选VLDB 2023! OceanBase 4.0单机分布式一体化研究成果获国际顶会认可

近日&#xff0c;国际顶级数据库学术会议 VLDB 2023 在加拿大温哥华开幕。OceanBase 研究成果论文 “OceanBase Paetica: A Hybrid Shared-nothing/Shared-everything Database for Supporting Single Machine and Distributed Cluster” 被 VLDB 2023 收录&#xff01;相继 20…

pytorch搭建squeezenet网络的整套工程,及其转tensorrt进行cuda加速

本来&#xff0c;前辈们用caffe搭建了一个squeezenet的工程&#xff0c;用起来也还行&#xff0c;但考虑到caffe的停更后续转trt应用在工程上时可能会有版本的问题所以搭建了一个pytorch版本的。 以下的环境搭建不再细说&#xff0c;主要就是pyorch&#xff0c;其余的需要什么p…

Stable Diffusion stable-diffusion-webui开发笔记

https://lexica.art/ lexica.art 该网站拥有数百万Stable Diffusion案例的文字描述和图片&#xff0c;可以为大家提供足够的创作灵感。可以提供promt灵感 https://civitai.com/ Civitai是一个聚集AI绘图爱好者的社区&#xff0c;在此网站上有许多定制化的模型&#xff0c;特…

【PyGame/PyQy5】get-start 快速入门

1.windows、linux&#xff0c;mac 安装python3 2.PC系统安装pygame, 指令&#xff1a;pip install pygame 3. 保存如下文件&#xff1a; test_game.py 4.PC上运行 python test_game.py import pygame# 初始化Pygame pygame.init()# 创建游戏窗口 window pygame.display.s…

SAP FI 之定义利润中心(Profit Center)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么&#xff1f;二、使用步骤 1.引入库2.读入数据总结 前言 SAP中的利润中心是SAP Controlling内部控制的一个组织单元。它帮助组织管理成本和收…

基于snat+dnat发布内网K8S及Jenkins+gitlab+Harbor模拟CI/CD的综合项目

目录 项目名称 项目架构图 项目环境 项目概述 项目准备 项目步骤 一、修改每台主机的ip地址&#xff0c;同时设置永久关闭防火墙和selinux&#xff0c;修改好主机名&#xff0c;在firewalld服务器上开启路由功能并配置snat策略。 1. 在firewalld服务器上配置ip地址、设…

blender基本操作

文章目录 引言一、选择二、移动1. xyz轴移动2. xyz平面移动3. 精确移动4. 快捷键移动G 三、旋转四、缩放五、变换1. 变换坐标系2. 变换轴心&#xff1a; 六、吸附七、模式切换八、物体的合并和分离1. 合并2.分离 九、设置父子级关系十、叠加层和快速收藏夹1. 叠加层2. 快速收藏…

【python基础知识】2.if条件判断与条件嵌套

文章目录 前言条件判断单向判断&#xff1a;if双向判断&#xff1a;if…else…多向判断&#xff1a;if…elif…else… if嵌套if嵌套的执行顺序 如何写嵌套代码 前言 在上一关&#xff0c;我带领你攻克了如何与Python沟通的语言大关——通过三种数据类型&#xff08;字符串、整…

【ALM工具软件】上海道宁与Perforce为您带来用于整个生命周期的应用程序生命周期管理软件

Helix ALM是 用于整个生命周期的 应用程序生命周期管理的ALM软件 具有专用于 需求管理&#xff08;Helix RM&#xff09;、测试用例管理&#xff08;Helix TCM&#xff09; 问题管理&#xff08;Helix IM&#xff09;的功能模块 Helix ALM提供了 无与伦比的可追溯性 您将…

【MySQL学习笔记】(十)使用索引的操作

简单使用索引 创建索引创建主键索引创建唯一键索引普通索引的创建 查询索引删除索引索引创建原则 数据库中的索引与书籍中的索引类似&#xff0c;在一本书中&#xff0c;利用索引可以快速地查找所需信息&#xff0c; 而无须阅读整本书。在数据库中&#xff0c;索引使数据库程序…

跨专业可读的免统考双证的中国社科院-美国杜兰大学金融硕士

跨专业可读的免统考双证的中国社科院-美国杜兰大学金融硕士 项目优势 一、跨专业申请优势 中国社科院-美国杜兰大学金融硕士的招生对象不仅仅是金融行业的高端人才&#xff0c;因为金融业门槛相对较高&#xff0c;进入者往往已经具备了硕士晋升的学习能力&#xff0c;所以我…

【Github】git本地仓库建立与远程连接

文章目录 前言一、git简介二、git下载2.1下载地址 三、git安装3.1安装3.2 配置3.3 config设置&#xff08;增删改查&#xff09; 四.github与git连接——本地Git仓库4.1 建本地的版本库4.2 源代码放入本地仓库4.3提交仓库 五、github与git的连接——远程连接5.1 创建SSH Key5.2…

奥本海默

&#xff08;1&#xff09;命 电影一开头&#xff0c;奥本海默不擅长做实验。但你看宿命凑巧不凑巧&#xff0c;奥本海默成了曼哈顿计划的工程负责人&#xff0c;偏偏要他一次性爆炸成功。 电影一开头&#xff0c;奥本海默因为不擅长做实验被导师指出引起其他同学哄堂大笑&…

LiveNVR监控流媒体Onvif/RTSP功能-支持数据库切换为高斯数据库信创瀚高数据信创数据库

LiveNVR监控流媒体Onvif/RTSP支持数据库切换为高斯数据库信创瀚高数据信创数据库 1、如何配置切换高斯数据库&#xff1f;2、如何配置切换信创瀚高数据库&#xff1f;3、RTSP/HLS/FLV/RTMP拉流Onvif流媒体服务 1、如何配置切换高斯数据库&#xff1f; livenvr.ini -> [db]下…

Qt之事件过滤—筛选处理对象

文章目录 事件过滤完整代码 事件过滤 事件过滤是当事件发生时&#xff0c;可以对不同对象&#xff0c;实现不同操作&#xff0c;以达到筛选的效果。 步骤&#xff1a; 1、首先安装一个事件过滤器&#xff0c;为对象安装事件过滤&#xff0c;指定“谁”来监控这些事件对象 //给…