关于GLTF格式的综述、结构与TS解析

目录

三维格式

GLTF总概

GLTF历史

gltf1.0

gltf2.0

为什么是GLTF

GLTF生态

GLTF业界支持

GLTF目的

GLTF优势

GLTF基础结构

一句话总结

三维数据简述

数据分区

Json节点简述

外部数据简述

GLTF基础示例

scenes和nodes结构

meshes

accessor

bufferView

buffer

asset

GLTF结构解析实践

关键代码

每篇一句


三维格式

关于GLTF格式的综述、结构与TS解析

 

 

 在讲gltf之前,我们先来聊一聊三维格式。三维格式存储的是用于构建三维场景的实时或非实时的渲染三维数据,一般作为传输与用户数据存储的标准。不同的格式(*上罗列了不下70多种)有不同的定位与目的,如只描绘三维对象几何格式(.ply,.vtk,.obj,.dae)、描绘三维视图格式(.x3d,.jvx,.vrml)、描绘模型和渲染格式(.maya,.pov,.lwo)以及CAD相关的格式(.dxf,.stl,.zpr)等等。

GLTF总概

GLTF历史

gltf1.0

 

关于GLTF格式的综述、结构与TS解析

 部分大事件回顾:

  • gltf1.0是COLLADA(.dae)工作组的成员在2012年提出的。  
  • 在SIGGRAPH 2012上,Khronos展示了glTF的演示,然后将其称为WebGL传输格式(WebGL TF)。  
  • 2015年10月19日,发布了glTF 1.0规范。  
  • 在SIGGRAPH 2016上,Oculus以与ovrscene格式的相似之处宣布采用glTF。  
  • 2016年10月,微软加入了Khronos的3D格式工作组,就glTF进行合作。

gltf2.0

关于GLTF格式的综述、结构与TS解析

 

 部分大事件回顾:

  • 第二个版本glTF 2.0于2017年6月发布,是对1.0版文件格式的完整检查,大多数工具都采用2.0版。  
  • 添加了基于物理的渲染(PBR),取代了glTF 1.0中使用的WebGL 着色器。  
  • (其他升级包括稀疏访问器和面向对象的变形目标,例如面部动画,模式调整以及针对极端情况或性能的重大更改,例如将数组替换顶层glTF对象属性以实现基于索引的访问更快。  在Unity 和集成的多引擎查看器/验证器中,正在进行着导入和导出的工作。)  
  • 3.2017年3月3日,Microsoft宣布他们将在其整个产品线中使用glTF 2.0作为3D资产格式,包括Paint 3D,3D Viewer,Remix 3D,Babylon.js和Microsoft Office。Sketchfab还宣布了对glTF 2.0的支持。  
  • 截至2019年,glTF和GLB格式已在UX3D,Sketchfab,Facebook,Microsoft,Oculus,Google,Adobe,Box,TurboSquid和Unreal Engine等公司使用并受其支持。该格式已被视为增强现实的重要标准,并与Autodesk Maya,Autodesk 3ds Max和Poly等建模软件集成在一起。  
  • 2020年2月,史密森学会(Smithsonian Institution)发起了开放访问计划(Open Access Initiative),将约280万个2D图像和3D模型发布到公共领域,并以glTF形式提供了3D模型。

为什么是GLTF

 gltf的创始者在互联网的兴起中意识到需要一种有效的现代三维格式来传输三维模型和场景信息数据。    

 在gltf出现前,三维圈子也流行着一些标准化的格式,如FBX、OBJ等等。FBX格式具有非常多的功能,不过其中有些在目前的渲染中是已经被时代淘汰了,而且它是私有的,AutoDesk提供的SDK封装好了,我们并不能在官方查看到其内部结构(不过网上有很多分析FBX文件内部结构的文章),并且它是针对建模工具之间交互数据使用的。再说OBJ,文件格式虽然是公开的,但OBJ的功能集有限且由于是文本格式,数据量大,在存储空间和快速读写数据的能力效率极低。虽然可在Web浏览器中传输加载OBJ文件,但这是一个非常不好的体验。    

 总而言之,在gltf之前,大家都要花较长的的时间来处理模型的载入或者花较大代价进行模型的传输。很多的游戏引擎或者3D渲染引擎,都使用的是插件的方式来载入各种格式的模型,繁多的格式插件增大了引擎本身体积。并且,各种格式的模型总是会包含了一些与当前加载无关的信息,例如一些过程数据。

GLTF生态

关于GLTF格式的综述、结构与TS解析

 

GLTF业界支持

关于GLTF格式的综述、结构与TS解析

 

GLTF目的

关于GLTF格式的综述、结构与TS解析

 

来自官方原文:

  • 紧凑的文件大小。尽管Web开发人员希望尽可能多地使用纯文本,但是由于其巨大的尺寸,纯文本编码对于传输3D数据根本不切实际。glTF JSON文件本身是纯文本,但结构紧凑且解析迅速。所有大数据(例如几何图形和动画)都存储在二进制文件中,该二进制文件比等效的文本表示形式小得多。  
  • 快速加载。glTF数据结构已被设计为尽可能接近JSON和二进制文件中的GPU API数据,以减少加载时间。例如,网格的二进制数据可以看作是JavaScript类型数组,并可以通过简单的数据副本直接加载到GPU缓冲区中。无需解析或进一步处理。  
  • 运行时独立。glTF对目标应用程序或3D引擎不做任何假设。glTF除了渲染和动画外没有指定任何运行时行为。 完整的3D场景表示。对于许多应用程序而言,从建模包中导出单个对象是不够的。通常,作者希望将整个场景(包括节点,变换,变换层次结构,网格,材质,摄影机和动画)加载到其应用程序中。glTF努力保留所有这些信息,以供下游应用程序使用。  
  • 可扩展性。尽管最初的基本规范支持丰富的功能集,但仍会有许多增长和改进的机会。glTF定义了一种机制,该机制允许添加通用扩展和特定于供应商的扩展。

目的决定了优势,下面我们来看看GLTF到底有哪些优势

GLTF优势

关于GLTF格式的综述、结构与TS解析

 

  • 对于那些对加载格式不是非常重要的软件,可以显著地减少代码量,所以也有人说,最大的受益者是那些对程序大小敏感的3D Web渲染引擎,只需要很少的代码就可以顺利地载入各种模型了。    
  • 使用JSON来描述场景结构,可以方便地被应用程序分析处理与预留一般支持以及特定供应商的扩展。    
  • 设计是面向实时渲染应用的,尽量提供可以直接传输给图形API的数据形式,不再需要二次转换。  

例如:将模型数据表示为简单的二进制缓冲区。“访问者”允许根据上下文解释该数据。这特别适合在OpenGL中加载这些文件,您可以在其中使用glBufferData将每个缓冲区加载到GPU中,然后使用glVertexAttribPointer解析每个访问器,以绑定到缓冲区中每个顶点元素的位置。  

  • glTF是对近年来各类三维格式的总结,可以包括场景、摄像机、动画等,也可以包括网格、材质、纹理,甚至包括了渲染技术、着色器以及着色器程序。使用目前最优的数据结构,来保证最大的兼容性以及可伸缩性。

GLTF基础结构

一句话总结

关于GLTF格式的综述、结构与TS解析

 

三维数据简述

关于GLTF格式的综述、结构与TS解析

 

  • 场景数据:gltf使用的的是场景图的形式,也就是用树来定义场景,其中的各类节点说明着节点的父子关系、节点的transform(位置,旋转,缩放)矩阵和节点的功能(如mesh、camera);  
  • 真实mesh和skin数据:用来加载静态模型与骨骼模型的;  
  • 材质数据:mesh的渲染信息数据用于渲染模型效果。  
  • animation数据:通过场景中的节点定义组成骨架结构,用以控制mesh做刚体运动;  
  • Morph Target(也称作Blend Shape)模型动画数据:控制逐顶点动画运动;

数据分区

关于GLTF格式的综述、结构与TS解析

 

Json节点简述

关于GLTF格式的综述、结构与TS解析

 

  • scene:glTF格式的场景结构描述条目。它通过引用node来定义场景图。
  • node:场景图中的一个结点。它可以包含一个变换(比如旋转或平移),引用更多的子结点。它可以引用网格和相机,以及描述网格变换的蒙皮。

补充:

glTF格式使用scene对象来描述场景。对glTF数据的JSON文件进行解析时,对场景结构的遍历也是从scene对象开始。每个scene对象引用了一个nodes数组,nodes数组通过索引引用了场景的根结点。

  • camera:定义了用于渲染场景的视锥体配置。
  • mesh:描述了场景中出现的3D对象的网格数据。它引用的accessor对象可以用来访问真实的几何数据。它引用的material对象定义了3D对象的外观。  
  • skin:定义了用于蒙皮的参数,参数的值通过一个accessor对象获得。
  • animation:描述了一些结点如何随时间进行变换(比如旋转或平移)。
  • accessor:一个访问任意数据的抽象数据源。被mesh、skin和animation元素使用来提供几何数据,蒙皮参数和基于时间的动画值。它通过引用一个bufferView对象,来引用实际的二进制数据。
  • material:包含了定义3D对象外观的参数。它通常引用了用于3D对象渲染的texture对象。
  • texture:定义了一个sampler对象和一个image对象。sampler对象定义了image对象在3D对象上的张贴方式。 buffer,bufferView和accessor:提供了对mesh对象实际的几何数据的描述。

外部数据简述

关于GLTF格式的综述、结构与TS解析

 

 外部数据基本为二进制数据与图片数据。二进制数据,比如3D对象的几何数据和纹理数据通常不被包含在JSON文件中,它们被存储在外部的文件中。JSON文件中只包含了到这些外部文件的链接。这使得二进制数据可以以非常紧凑的形式进行存储方便互联网传输,并且可以直接被渲染程序使用,无需额外的解码、预处理。  

 在JSON结构被分析完后,就可以使用buffers和images数组来索引访问buffer和image对象。每个buffer和image对象引用了一块二进制数据。通常会将二进制数据读取到内存中,以它们在原来buffers和images数组中的索引顺序进行存储,以便使用相同的索引来访问对象对应的二进制数据。

GLTF基础示例

scenes和nodes结构

关于GLTF格式的综述、结构与TS解析

 

示例包含了一个scene对象,这一scene对象引用了一个索引为0的node对象,这个node对象引用了索引为0的mesh对象。

meshes

关于GLTF格式的综述、结构与TS解析

 示例只包含了一个mesh对象,这一mesh对象只包含了一个primitive对象。primitive对象包含了一个attribute对象数组,存储了mesh对象的几何数据信息。

 对于这个示例来说,只包含了一个POSITION属性,用于描述mesh对象的顶点位置信息。primitive对象的indices属性描述了用于渲染的顶点索引数据,默认情况下,连续3个顶点索引构成一个三角形。

accessor

关于GLTF格式的综述、结构与TS解析

 

  •  第一个accessor对象描述了顶点的索引数据,它引用了索引为0的bufferView对象,这一bufferView对象引用了顶点索引数据。accessor对象还包含了count,type和componentType3个属性,用来对数据进行描述。对于示例来说,这3个属性描述的的数据元素包含了3个类型为unsigned short的标量。  
  •  第二个accessor对象描述了顶点位置数据。它引用了索引为1的bufferView对象,这一bufferView对象引用了顶点位置数据。对于示例来说,这一accessor对象的count,type和componentType属性描述的数据元素的个数为3,每个数据元素是一个包含3个分量,每个分量类型为float的3D向量。

bufferView

关于GLTF格式的综述、结构与TS解析

 

 包含了2个bufferView对象,它们引用了同一个buffer对象的不同部分数据。

 第一个bufferView对象引用了三角形的索引数据,数据位置从偏移值byteOffset(0)开始,长度为6字节。

 第二个bufferView对象引用了三角形的顶点位置数据,数据位置从偏移值byteOffset(8)开始,长度为36字节。

补充:

bufferview target属性,此属性是在GPU渲染过程中,区分bufferview指向数据的类型。例如34962代表ARRAY_BUFFER,34963代表ELEMENT_ARRAY_BUFFER

buffer

关于GLTF格式的综述、结构与TS解析

 

 示例中我们使用数据URI直接在JSON文件中编码长度44字节的buffer数据。

asset

关于GLTF格式的综述、结构与TS解析

 

 对于glTF数据格式的1.0版本,asset对象是可选的,对于之后版本的glTF数据格式,必须包含asset对象,使用version属性指定glTF数据格式的版本。示例表示数据使用glTF数据格式的2.0版本进行描述。

附:关于gltf数据结构,如想了解更多可以去看一下KhronosGroup的glTF-torials

GLTF结构解析实践

关键代码

关于GLTF格式的综述、结构与TS解析

 

 左侧代码是读取gltfJson树状结构代码,如代码所示是一个不断递归过程,例如loadScene方法在访问scene节点时需要访问其他节点也会使用getDependency接着递归到其他节点上。

 右侧代码展现的是gltf设计所可以带来的扩展能力,当我们想在gltf实现一个扩展时,我们可以很方便地将这个扩展独立出来与引用进去,不会破坏原先的json结构;当基础json结构在某个节点要用这个扩展时,只要去查询目前我们之前独立出来的扩展类就可以了。

每篇一句

 没有人不爱惜他的生命,但很少人珍视他的时间。——梁实秋 出自《时间与生命》

 

上一篇:M3D - 一个想突破又还有很多包袱的新生三维数据格式杂谈


下一篇:GLTF格式说明