当前位置: 欣欣网 > 码农

OpenGL 3D 渲染技术:glTF 基础知识

2024-06-19码农

大家好,我是程序员 kenney,今天给大家介绍 glTF 的基础知识

glTF 是什么?

它是 GL Transmission Format 的缩写,是 khronos推 出的一种描述3D模型的格式,目标是使其成为一种通用的3D模型格式。它的官方github是 https://www.khronos.org/gltf/

我们知道3D模型有各种各样的格式,如obj、FBX、dea等, 格式的多种多样带来了一个问题的就是各种软件、渲染引擎、游戏引擎之间的3D模型的不通用

例如在3D设计软件中设计好一个3D模型之后,想把它放到一个渲染引擎中渲染,如果没有一个通用的格式,渲染引擎可能也有一套自己的格式,这样就要做格式转换,而有些格式是不开源的,需要官方提供转换工具,非常麻烦。

而如果有一个通用的格式大家都支持,这就好办了,就像图片中的jpeg一样,通常的图片编辑软件都能导出jpeg,通常的图片查看软件也都能打开,这就非常方便,而 glTF就是要成为3D模型界的 jpeg

glTF 是一用 json 格式编写的 ,目前现在推出了2.0版本,本篇文章也是讲解2.0版本,glTF格式中可以描述的信息相当丰富,本篇文章先给大家介绍一些基础的字段:

  • 场景和节点描述:scenes、nodes

  • 网格描述:meshes

  • 数据描述:buffers、bufferViews、accessors

  • 材质描述:materials

  • 纹理、图片和采样器描述:textures、images、samplers

  • 摄像机描述:cameras

  • 总览

    我们先来从一张图总体上看一下glTF文件的结构,每一种类型的字段,基本是都是用数组来组织,在每个字段中,又可以通过索引去引用其它字段。

    它类似一个树状,但又不是严格的树。

    最顶层的是场景,场景中包含了一些节点,节点中又可以套子节点,节点中可以有mesh、摄像机,如果是mesh,还可以为它指定材质及mesh网格数据,材质中可以指定纯色及图片纹理及其采样配置,还可以描述蒙皮及动画

    场景和节点

    场景和节点分别用scenes、nodes字段描述,场景就是代表要渲染的一些东西的集合,场景里面包含一些节点,每个节点可以认为是一个物体(也可以是摄像机),节点也可以是空的,节点中可以继续挂子结点。

    来看上面这个例子,scene字段指定了使用第0个场景,一般来说,同一时刻只会渲染一个场景。

    scenes字段是一个场景数组,描述所有场景,这个例子中场景只有一个,它里面的nodes字段描述这个场景中有哪些节点,这里是用索引为0、1、2的节点,它就对应了下面nodes数组中第0、1、2个节。nodes字段描述了所有节点,节点里可以用children描述子节点,子节点的描述方式也是索引号。这样,通过上图左中的这段json,我们就描述了如上图右中的那样一个场景结构。

    可以为每个结点指定它的变换参数,这个变换参数是它相对于父节点的变换,可以用变换矩阵描述,也可以分别指定平移、旋转和缩放。还可以指定它的mesh及摄像机,mesh就描述了这个节点是什么物体,而camera会影响这个节点被观察的样子

    网格描述

    有了节点之后,我们要描述节点的东西是什么,一个东西首先要有形状,比如一个立方体,或者一个圆柱,这就需要meshs来描述:

    meshs同样也是一个数组,每个mesh中由primitives描述图元,其中的mode是图元的种类,也就是点、线或者三角形,indices表示accessors中的索引,后面会讲到。

    attributes描述的是attribute的结构,里面可以有顶点坐标、纹理坐标、法向量等,同样也是以索引的方式引用accessors。最后的material表示这个mesh的材质,也是用索引来引用

    数据描述

    glTF中用buffers、bufferViews、accessors来描述数据:

    buffers是数据块数组,每个buffer由长度和路径描述,bufferViews同样也是数组,其中每个bufferView表示一个buffer的视图。这个怎么理解呢?buffer是一堆纯数据,它本身是不描述这堆数据用来做什么的,而bufferView就可以理解成如何去看待这堆数据。

    其中buffer表示它对应的buffers中的索引。

    target描述了它是用来干什么的,比如上图中的34963就对应了GL_ELEMENT_ARRAY_BUFFER,这个值是和OpenGL库里定义的值是一致的,这样使用起来就相当友好,glBindBuffer()可以直接传这里解析出来的target值而不用做映射转换。

    byteOffset描述的是这块buffer的偏移字节,byteLength是字节长度,bytteStride描述的是一个数据的开始距离下一个数据开始的跨度,如果相同语义的数据不是连续存在放的,bytteStride就会比一份数据的长度大,因为它要跨过其它类型的数据。

    再往下是accessors,它同样也是一个数组,其中每个accessor描述了对应bufferView中的数据以什么样的方式进行访问,在上图上,偏移了4个字段,以VEC2的方式取数据,即二维向量,向量每个成份的类型componentType是5126,它对应的是GL_FLOAT,count表示取数据的个数

    材质描述

    materials中每个元素是一个material

    例如上图中的例子通过金属度-粗糙度模型来描述材质,其中有一些材质纹理图,比如基础纹理图、法向图、遮挡纹理图等,每个纹理图通过index来对应纹理图数组中的索引,纹理坐标也是类似的

    纹理、图片和采样器描述

    纹理、图片和采样器分别通过textures、images、samplers描述,看下面的例子

    textures中每个元素通过source索引到images数组中,从而找到对应的纹理数据,images数组中的元素可以以图片路径的方式提供图片,也可以用bufferView的方式,bufferView最终又对应到一个数据块上。

    samplers则描述了采样器的配置,大家一看里面的字段就会很熟悉,同样的,它也是直接对应了OpenGL库里定义的值,解析出来直接使用,非常方便

    摄像机描述

    摄像机用cameras描述

    熟悉OpenGL的同学一眼就能看出里面定义了一个透视投影相机和正交投影相机,以及视角、近/远平面等参数,这个比较简单,没有太多好说的

    完整例子

    我们来看一下完整的例子,glTF官方提供了很多sample models:

    https://github.com/KhronosGroup/glTF-Sample-Models

    我选取了一个比较简单的立方体,大家看完文章可以尝试阅读一下它的glTF文件,看看是否能理解其中的描述

    {
    "accessors" : [
    {
    "bufferView" : 0,
    "byteOffset" : 0,
    "componentType" : 5123,
    "count" : 36,
    "max" : [
    35
    ],
    "min" : [
    0
    ],
    "type" : "SCALAR"
    },
    {
    "bufferView" : 1,
    "byteOffset" : 0,
    "componentType" : 5126,
    "count" : 36,
    "max" : [
    1.000000,
    1.000000,
    1.000001
    ],
    "min" : [
    -1.000000,
    -1.000000,
    -1.000000
    ],
    "type" : "VEC3"
    },
    {
    "bufferView" : 2,
    "byteOffset" : 0,
    "componentType" : 5126,
    "count" : 36,
    "max" : [
    1.000000,
    1.000000,
    1.000000
    ],
    "min" : [
    -1.000000,
    -1.000000,
    -1.000000
    ],
    "type" : "VEC3"
    },
    {
    "bufferView" : 3,
    "byteOffset" : 0,
    "componentType" : 5126,
    "count" : 36,
    "max" : [
    1.000000,
    -0.000000,
    -0.000000,
    1.000000
    ],
    "min" : [
    0.000000,
    -0.000000,
    -1.000000,
    -1.000000
    ],
    "type" : "VEC4"
    },
    {
    "bufferView" : 4,
    "byteOffset" : 0,
    "componentType" : 5126,
    "count" : 36,
    "max" : [
    1.000000,
    1.000000
    ],
    "min" : [
    -1.000000,
    -1.000000
    ],
    "type" : "VEC2"
    }
    ],
    "asset" : {
    "generator" : "VKTS glTF 2.0 exporter",
    "version" : "2.0"
    },
    "bufferViews" : [
    {
    "buffer" : 0,
    "byteLength" : 72,
    "byteOffset" : 0,
    "target" : 34963
    },
    {
    "buffer" : 0,
    "byteLength" : 432,
    "byteOffset" : 72,
    "target" : 34962
    },
    {
    "buffer" : 0,
    "byteLength" : 432,
    "byteOffset" : 504,
    "target" : 34962
    },
    {
    "buffer" : 0,
    "byteLength" : 576,
    "byteOffset" : 936,
    "target" : 34962
    },
    {
    "buffer" : 0,
    "byteLength" : 288,
    "byteOffset" : 1512,
    "target" : 34962
    }
    ],
    "buffers" : [
    {
    "byteLength" : 1800,
    "uri" : "Cube.bin"
    }
    ],
    "images" : [
    {
    "uri" : "Cube_BaseColor.png"
    },
    {
    "uri" : "Cube_MetallicRoughness.png"
    }
    ],
    "materials" : [
    {
    "name" : "Cube",
    "pbrMetallicRoughness" : {
    "baseColorTexture" : {
    "index" : 0
    },
    "metallicRoughnessTexture" : {
    "index" : 1
    }
    }
    }
    ],
    "meshes" : [
    {
    "name" : "Cube",
    "primitives" : [
    {
    "attributes" : {
    "NORMAL" : 2,
    "POSITION" : 1,
    "TANGENT" : 3,
    "TEXCOORD_0" : 4
    },
    "indices" : 0,
    "material" : 0,
    "mode" : 4
    }
    ]
    }
    ],
    "nodes" : [
    {
    "mesh" : 0,
    "name" : "Cube"
    }
    ],
    "samplers" : [
    {}
    ],
    "scene" : 0,
    "scenes" : [
    {
    "nodes" : [
    0
    ]
    }
    ],
    "textures" : [
    {
    "sampler" : 0,
    "source" : 0
    },
    {
    "sampler" : 0,
    "source" : 1
    }
    ]
    }

    glTF有很多方法能方便地查看效果,可以在线看,比如 gltf-viewer.donmccurdy.com ,上面那个glTF例子的渲染效果是这样的

    谢谢阅读!如有疑问,欢迎在评论区交流~

    欢迎关注我的 github:www.github.com/kenneycode

    原文链接: https://juejin.cn/post/6897480101177491463

    -- END --

    进技术交流群, 扫码添加我的微信:Byte-Flow

    获取相关资料和源码

    学习音视频、OpenGL ES、Vulkan 、Metal、图像滤镜、视频特效及相关渲染技术的付费社群,面试指导,1v1 简历服务,职业规划。

    我的付费社群

    推荐: