一、文件結(jié)構(gòu)
一個gltf模型一般包含一下幾個文件:
.bin 二進制文件存放頂點咬最、法線翎嫡、面、uv等數(shù)據(jù)
.gltf 描述模型的綜合信息
img文件夾 存放模型貼圖
二永乌、gltf模型信息詳解
1惑申、數(shù)據(jù)結(jié)構(gòu):
{
scene:0,
scenes:[{nodes:0}],
nodes:[
{
name:"rootModel",
children:[1]
},
{
name:"floor1",
children:[2]
},
{
name:"room1",
mesh:0
}
],
meshes:[
{
name:"mesh1",
primitives:[
{attributes:{POSITION:0, NORMAL :1,TEXCOORD_0:0},indices:0, material:0,mode:4}
]
}
],
accessors:[
{name:"postions_0", componentType:5126, count:100, bufferView:0, byteOffset:0,type:"VEC3",max:[],min:[]},
{name:"texcoods_0", componentType:5126, count:100, bufferView:0, byteOffset:0,type:"VEC2",max:[],min:[]},
{name:"indices_0", componentType:5123, count:100, bufferView:0, byteOffset:0,type:"SCALAR",max:[],min:[]}
],
bufferViews:[
{name:"view0",buffer:0,byteLength: 144, byteOffset: 0, byteStride: 12, target: 34962},
{name:"view1",buffer:0,byteLength: 100, byteOffset: 144, byteStride: 8, target: 34962},
{name:"view2",buffer:0,byteLength: 100, byteOffset: 244, byteStride: 8, target: 34962}
],
buffers:[{name:1,uri:"1.bin"}],
materials:[
{name:"m0", pbrMetallicRoughness:{baseColorTexture:{index:0}}}
],
textures:[{name:"t0",source:0}],
images:[{name:"img0",uri:"1.jpg"]
animations:[]
}
2、概述
模型加載順序為铆遭,先加載gltf文件硝桩,然后解析依次讀取scenes、nodes枚荣、meshes碗脊、accessors、bufferViews橄妆、buffers衙伶、materials、textures害碾、images矢劲。其中每個mesh包括一個bufferViews和一個materials。每一層的遞進都有數(shù)組下標(biāo)來確定慌随。
3芬沉、各字段詳解
scenes 場景
scenes:[{nodes:0}],
scene:0
一般模型只有一個也是默認(rèn)場景阁猜,如果是多個丸逸,則根據(jù)對應(yīng)的scene字段確定哪一個是默認(rèn)場景,參考數(shù)據(jù)結(jié)構(gòu)部分的數(shù)據(jù)剃袍,每一個scene都包含一個nodes字段黄刚,指定了scene的根結(jié)點。本例中nodes對應(yīng)的值為0民效,代表根節(jié)點為nodes字段下對應(yīng)的第一個元素憔维。
nodes 節(jié)點
nodes:[
{
name:"rootModel",
children:[1]
},
{
name:"floor1",
children:[2]
},
{
name:"room1",
mesh:0
}
]
nodes用來組裝模型層級涛救,第一個節(jié)點是父節(jié)點,children字段指定它所包含的子節(jié)點业扒。
nodes節(jié)點分為倆種检吆,一種是有children字段的,最終會渲染成group凶赁,一種是有mesh字段的最終渲染為mesh咧栗,mesh字段的值為meshes數(shù)組的小標(biāo)。
meshes 網(wǎng)絡(luò)
meshes:[
{
name:"mesh1",
primitives:[
{attributes:{POSITION:0, NORMAL :1,TEXCOORD_0:0},indices:0, material:0,mode:4}
]
}
]
網(wǎng)虱肄,由多個面和材質(zhì)組成致板,通過primitives字段指定。
- attributes 指定了頂點咏窿、頂點法線斟或、uv坐標(biāo)在accessors數(shù)組的對應(yīng)數(shù)據(jù)的下標(biāo)。
POSITION - 頂點
NORMAL - 頂點法線集嵌,頂點法線不是必須萝挤,導(dǎo)入引擎 時可生成
TEXCOORD_0 - uv坐標(biāo) - indices 指定了面在accessors數(shù)組的對應(yīng)數(shù)據(jù)的下標(biāo)
- material 指定了該mesh的材質(zhì)在materials數(shù)組中的下標(biāo)
accessors 訪問器
accessors:[
{name:"postions_0", componentType:5126, count:100, bufferView:0, byteOffset:0,type:"VEC3",max:[],min:[]}
]
訪問器是鏈接bufferView和mesh之間的橋梁,主要作用是對bufferView中數(shù)據(jù)進行進一步描述
- componentType 數(shù)據(jù)類型浮點或者整形
- count 數(shù)量總和(頂點總數(shù)或者面總數(shù)根欧,通過此字段可計算模型的總頂點數(shù)怜珍、總面數(shù),對于模型性能分析和優(yōu)化有很大作用
- bufferView 對應(yīng)數(shù)據(jù)在bufferViews中的下標(biāo)
bufferViews 緩沖區(qū)視圖
bufferViews:[
{name:"view0",buffer:0,byteLength: 144, byteOffset: 0, byteStride: 12, target: 34962}
]
- buffer 對應(yīng)的數(shù)據(jù)在buffers數(shù)組中的下標(biāo)
- byteLength 該緩沖區(qū)對于的數(shù)據(jù)長度
- byteOffset 在buffer中的起始位置
buffers 緩沖區(qū)
buffers:[{name:1,uri:"1.bin"}]
- uri 該緩沖區(qū)對于的bin文件凤粗,bin文件的作用參考第一部分的介紹
從mesh走到bin文件酥泛,模型的骨骼已經(jīng)確定了,頂點嫌拣、法線柔袁、面、都有了异逐,剩下的就是給模型添加材質(zhì)貼圖捶索,這一部分也是從mesh出發(fā),由mesh下的material字段指定對應(yīng)的材質(zhì)
materials 材質(zhì)
materials:[
{name:"m0", pbrMetallicRoughness:{baseColorTexture:{index:0}}}
]
- baseColorTexture 對應(yīng)textures數(shù)組下標(biāo)
textures 紋理
textures:[{name:"t0",source:0}],
- source 對應(yīng)images數(shù)組下標(biāo)
images 貼圖
images:[{name:"img0",uri:"1.jpg"]
總的流程如下圖
三灰瞻、內(nèi)存占用
模型的內(nèi)存占用主要包括四個部分腥例,分別是內(nèi)存、gpu酝润、圖片緩存燎竖、cpu,其中主要決定性能的是gpu和圖片緩存
-
gpu :
對于gpu占用主要有一個問題袍祖,如何計算一個模型的gpu占用底瓣,有沒有公式可以算出來谢揪?針對這個問題就需要搞明白那些因素決定gpu占用蕉陋。
通過上圖很容易看出捐凭,gpu主要有面數(shù)、頂點數(shù)凳鬓、和紋理數(shù)茁肠、圖片尺寸有關(guān),仔細(xì)觀察頂點和面其實存在正相關(guān)的缩举,紋理數(shù)和圖片尺寸其實都屬于材質(zhì)垦梆,進而可以得出gpu=f(geomotry)+f(材質(zhì))。
對于材質(zhì)我們很容易得出
分析f(geomotry)仅孩,實際是有點托猩、面、法線辽慕、uv等數(shù)據(jù)決定京腥,其中大致可分為三部分,原始數(shù)據(jù)占用溅蛉、頂點著色器運行占用公浪、片元著色器占有。第一部分物理內(nèi)存占用可精確算出船侧,但后倆者只能粗略估算欠气,因為三角面可能共用頂點,gpu的計算能力也有波動镜撩,著色器程序更不可能相同预柒,因此我們只能估算,但面可能存在共點的情況琐鲁,因此我們可用一個頂點的最大內(nèi)存占用*頂點數(shù)估計一個這部分的最大gpu占用卫旱,所以
為了方便計算,我們用面替換點围段,一個最多對應(yīng)3個點因此可得
仔細(xì)觀察數(shù)據(jù)表顾翼,大致可以得出繪制一個面的所占有的內(nèi)存在0.8kb-3.1kb之間,我們?nèi)∽畲笾挡⑾蛏先≌卫幔梢源笾掳疵總€面3.1k的內(nèi)存去估算
最終可得出:
(T代表單個材質(zhì)适贸,faces代表模型總面數(shù))
-
圖片緩存 :
圖片緩存有很多文章說明,基本公式是
圖片緩存其實是紋理緩存涝桅,對于場景切換拜姿,需要注意注銷紋理,釋放圖片緩存冯遂。
四蕊肥、性能優(yōu)化
有了上面的內(nèi)存占用,性能優(yōu)化的點就比較清晰了
- 模型面數(shù)優(yōu)化
可以在制作模型時,通過原始數(shù)據(jù)減少模型面數(shù)壁却,也可以通過腳本動態(tài)減面批狱,例如threejs的SimplifyModifier。 -
紋理優(yōu)化
紋理渲染流程圖
如果不追求過高的效果展东,可以直接減小圖片尺寸赔硫,如果對與效果要求很高,可以采用壓縮紋理技術(shù)
壓縮紋理方法主要是以上幾種盐肃,優(yōu)點是可以減少gpu占用提高渲染效率和初次渲染速度爪膊,缺點是這幾種文件通常會大于png圖片,而且兼容性很差砸王,這個問題直到去年有了比較好的解決方案 - basis_universal(https://github.com/BinomialLLC/basis_universal)推盛,谷歌聯(lián)合各大廠商解決了兼容性問題,原理參考下圖谦铃,basis文件在gpu端可根據(jù)不同設(shè)備的情況快速轉(zhuǎn)換為它支持的壓縮格式
- 減少drawcall
減少cpu與gpu通信次數(shù)小槐,類似于雪碧圖技術(shù),可通過合并mesh合并材質(zhì)等方法達(dá)到
(附上一個查看工具:spector) - 光照
適當(dāng)減少光源數(shù)荷辕,盡量用貼圖代替光照效果凿跳,如不需要光照剔除法線亦可減小模型物理內(nèi)存,提供渲染效率