大家好,我是程式設計師 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 簡歷服務,職業規劃。
我的付費社群
推薦: