Vulkanでモデルを読み込んで表示したいなと思い、glTFを調べた。tinygltfなるライブラリがあるのでそれを使って読み込んでみた。
glTFといっても大別して2種類あるようで、一つが.gltf形式。こちらは3Dモデルのテクスチャ画像や頂点データなどをそれぞれ別ファイルとする形式で、.gltfファイルにJSON形式でモデルの基本情報、付随するファイルの情報などが記録されている。もう一つは.glb形式で、こちらはバイナリ圧縮された.glbファイルにすべての情報が入っている。tinygltfはどちらも対応している。
このライブラリで読み込むとtinygltf::Model構造体にすべてのモデル情報を詰めて返してもらえるのだが、初見では結構データの意味が分かりづらい。サンプルコードをちゃんと読んでようやく理解できた。
まず頂点バッファやインデックスバッファのデータをどう取り出すかだが、全体で共有しているバッファデータ群としてModel::buffersがある。こいつは特定の意味を持った情報の塊ではない。ただのバイト列でしかない。Model::bufferViewsという別のメンバがあり、ここにバッファからの情報の切り出し方が記録されている。例えばbuffersの何番目のバッファの何バイト目から何バイト目を何バイト刻みで読み取れ、みたいなのが記録されている。で、話はこれで終わりではない。
さらにそれとは別に、モデルを構成する部品の情報が階層構造的に記録されている。「シーン」>「ノード」>「メッシュ」>「プリミティブ」という階層構造になっていて、ノードはさらに任意の数の子ノードを含む。ちゃんとモデルを読み込もうと思ったらこの階層構造をしっかり再帰的に読み込まねばならない。
各プリミティブという単位になってようやく頂点データなどにありつける。プリミティブの持っている情報としては「マテリアル」「インデックスバッファ」「アトリビュート(種々の頂点バッファ)」などがある。
インデックスバッファやアトリビュートはModel::accessors配列の添え字として表される。さらにAccessors::bufferViewがModel::bufferViews配列の添え字になっていて、これを用いてようやく頂点データが実際に取り出せる。長かった…
もうここに説明を書く気力も湧かないが、マテリアルもこのように「全体共有データの添え字」という形式で主に表されている。この異様なまでの間接参照への括りは何なのかみたいに思われるが、実際にVulkanなどで実装するとなると「バッファを作ってその位置を指定してバインドする」みたいなコードを書いていくことになるので結局のところAPIを叩く側としては便利な作りになっている。
ノードをはじめとした高度な階層構造も、複雑な3Dモデルの情報を整理するためには割と理にかなった構造なのかもしれない。しかしこれ、実際にドローコールを呼び出して描画するときのことを考えると、単純に再帰でやっていった場合にマテリアルを無駄に何度も切り替えて描画してしまうことになる可能性を感じる。同じマテリアルの描画処理はまとめるとかそういうことをした方が良かったりするのだろうか?
今日解いた競プロの問題。
ABC211-E: 解説AC。DPでなんとかしようと思ったが、想定解はメモ化DFSだった。間に合うのか…
既にカウントした盤面を飛ばしながら、各マスを起点とした連結な塗り方をDFSで愚直に全探索すると間に合う。「意外と全探索で間に合う」に気付けなかったのが敗因。割と最後まで「いい感じにまとめてカウントする計算をしないと間に合わない」という思考に縛られていた。
今日でatcoder problemsのstreakが100日に達した。だからどうということもないが。
なんかこう、習慣になったのでそこまで面倒にも感じなくなった。最近は青diff~黄diff下位あたりを一日1~2問ほど何とかやっていく感じになって来たので、割と当初目指していた精進の感覚に落ち着いてきた気がする。
6時間睡眠だったのに昼に眠気が来ないな、と思ったら夕方に来た。仕方なく寝て起きたら頭が痛くて喉が渇いていて最悪の寝覚めだった。
早寝はちゃんとしないとな、といいつつ出来ていない。なんだかんだ競プロにそれなりの時間を割いている。そしてOpenXR開発が楽しいので割と遅くまで起きてしまう。早起きして続きをやることのインセンティブを頭に染み付けないと。
Categories: 未分類