2018-04-15Boost.Spirit.QiによるXモデルパーザ実装の紹介1※先に断っておきますがバイナリフォーマット、スキンメッシュ及びアニメーションのパーズは未実装です。DirectX11からはD3DX系統の補助関数的なAPIはすべて排除されたため、シェーダーのコンパイル、テクスチャの読み込み、モデルの読み込みはユーザーが実装する必要がある。(Microsoftは別途ライブラリを用意する形にしてくれているが、結局外部ライブラリとリンクするなら、自分の好きなライブラリなりオレオレライブラリを作ったりする等、選択肢はいろいろある)3Dレンダリングエンジン開発において、プログラムの動作を確認するためには、やはりテストデータが必要である。そのため、レンダリングエンジンの開発の前に、3Dモデルのローダの実装は不可欠といえる。今回は、DirectX推奨の3Dモデルフォーマット、テキスト形式.xファイルのパーザ―の実装の紹介をする。C++でテキストファイルのパーズとなると、多くの人間が頭を悩ませることだろう。場合、文字列を線形探索して識別子を取得し、if文で分岐のような実装になるのだろうか。C++は文字列を言語でサポートしていないので、std::stringの恩恵を受けても中々に厳しい実装となることは想像に難くない。C++11でサポートされた正規表現を使うという手もある。正規表現でファイルフォーマットの解析というのは、少しばかり無理があるような気もする。正規表現には、ネストされた構文の表現が困難であるといった様々な特性がある。正規表現がダメという話ではない。Libraryには、おあつらえ向きの構文解析ライブラリがある。Boost.Spirit.Qiだ。Boost.Spirit.Qiは、構文解析をC++の文法で完結する闇のライブラリである。文法はBNF文法に近く、演算子のオーバーロードによって、C++の構文の範囲内で文法を定義することが出来る。簡単な例を挙げてみよう。}}Output1235,124Boost.Spirit.Qi(以降Qiと呼称する)では、一つの文法に相当するものをRuleと呼ぶ。上記のコードの場合、任意の整数+'_'という文字+任意の整数という構文をRuleと定義している。ちなみにBoost.Fusionシーケンスを内部で作る版の(疑似)可変長変数版のパーズもある。こちらの方が使いやすいだろう。}}RuleにはAttributeという概念があって、構文解析後の値をどのような型として振舞うのかを示す。qi::int_のAttributeはintである。qi::litはUnused。int」となり、そしてこのAttributeがqi::parseに渡されるバインド先の変数(これらもAttributesと呼ばれるようだ)と一致していなくてはならない。(実際には、Boost.Fusionシーケンスはスライシングを許容しているので、渡す変数が少ない分にはちゃんと機能する)これはQiの最も基本的な機能に過ぎない。Qiの機能をここで解説しきるには、残念ながら余白と私の知能が足りない。Xモデルパーザの実装の紹介をしていく。Xモデルのフォーマットは簡潔に述べると以下のようになる。・データボディ最終的なアウトプットとなるデータ構造を以下に示す。mesh;};まずはヘッダーのパーザを作ってみる。QiにはGrammerというRuleの集まりを表現する型がある。HeaderというGrammerを作ってみよう。Xモデルヘッダーの形式の例は以下。0064xofはマジックナンバーで固定。0302はバージョン番号。ほかにもバイナリやtzipなどがある。0064は浮動点小数精度。expr;};qi::symbolsで、文字列とEnum識別子のテーブルを作成している。これによって、特定の文字列にマッチするFileFormatのAtributeを持つRuleを定義することができる。'))は、空白を含まない文字の1個以上の繰り返しを意味する。先頭のxofにマッチする。+演算子によってAttributeはstd::vectorとして振舞われるため、ここでのAttributeはstd::vectorとなる。ちなみにstd::stringとしても振舞ってくれる。Qi内部ではこういった似た型をよしなに変換してくれる機能も提供している。')))は空白及びファイルフォーマットを含まない文字の一個以上の繰り返し。qi::omitは、[]の中のルールをパーズするが、それらをまとめて無視するディレクティブだ。任意のRuleのAttributeをUnusedとして扱う。全体のAtributeをまとめると、「std::string、std::string、FileFormat、int」となっている。これは、XHeaderの定義と一致している。XHeaderは独立したユーザー定義型であるので、このままではこのRuleにバインドできない。そのためには、Boost.Fusionのアダプトという機能を利用するのだが、これは次回解説する。次に、テンプレート定義のGrammerを定義しよう。テンプレート定義の例は以下。[Material]}MeshMaterialListというテンプレートを定義するよ、という宣言だ。ボディの一行目はUID。それ以降は、型と変数名の列挙だ。ここで面倒くさいことに、特定の配列がそれ以前のプロパティの値に依存することがある。今回の例でいうとfaceIndexesがそれにあたる。ここでデータの持ち方を動的配列と考えることで、豪快に配列のサイズを無視することにする。ちなみに[Material]はテンプレートの限定使用という宣言らしい。個人的にはMaterialというテンプレートを入れ語構造にもつよ、という宣言だと認識しているのだが、公式のMSDNではテンプレートの限定使用テンプレートは、開くか閉じることができ、限定使用も可能である。オブジェクトの直接階層で表示されるデータ型を決定できる。開かれたテンプレートには制約はなく、閉じられたテンプレートはすべてのデータ型を拒否する。限定使用テンプレートでは、指定したデータ型を使える。なにを言っているのか全然わからない。日本語でしゃべってくれ。ちなみにMSDNは大概クソみたいな翻訳(すべて原文は英語)なので、意味が通っていないどころが誤訳によりまったく意味が変わっていることも多々ある。DirectXの敷居が高いのもそのせいだといっても過言ではない。原文すら間違いがあることもある(実際、参照してるXファイルフォーマットのリファレンスは間違いだらけである。込み入ったAPIの仕様を確かめようとすると、基本的に絶望しか待っていない。今回もその系統だろうか。何が言いたいのかというと、編集リクエストボタンを用意していないくせにまともな解説も提供できないMSDNはクソということである。いうわけで意味がわかめすぎるので、このテンプレート限定使用とやらも無視する。qi::omitで消し飛ばしてやろう。prop;};ここで新たな概念が登場している。Grammerのテンプレート引数に、qi::space_typeが渡されている。これは、パースにおいてスキップ設定が有効な時に空白及び改行をすべて無視するよ、という宣言だ。BB"を+qi::char_でパースするとAABBという結果が返ってくることになる。テンプレートの識別子をパースする。qi::no_skipとは、[]内のRuleにおいてスキップ設定を無効化するというディレクティブである。いや無効化するのかよ!とツッコミをいれたいところだが、スペースを識別子のセパレータに使うケースは多々あるので仕方ない。識別子」のようにスペースで区切られている。今回は任意の回数のプロパティ宣言の繰り返しの表現を簡潔にするために、プロパティのRuleを別途定義して、それに+演算子を適用している。これに&演算子をつけると、「アルファベットにマッチするがイテレータは進めない」というRuleになる。存在確認みたいなものだ。}で終わるかプロパティの宣言が続いてるかの判定に使っている。ai::lexemeはまあ大体no_skipと一緒。qi::attr(1)は、[(int)]という表現にマッチする、もしくはマッチしない場合は1として扱うRuleだ。1のようにパースする。これでヘッダーとテンプレート識別子のパーズは終わりだ。ここまではファイルフォーマットの宣言部分に相当する。これから大量のデータボディに対するパーズが残っているわけだが....解説は次回に回そう。この記事を読んでいるあなたに、Boost.Spirit.Qiの魅力が伝わればと思う。16:41Boost.Spirit.QiによるXモデルパーザ実装の紹介1Tweet広告を非表示にする関連記事2018-05-088分木空間でのレイトレースのコリジョンリスト収集処理を見直して10倍速くしたフォトンマッピングの実装で、フォトンを1万~10万くらいバラま...2018-04-11ミップマップを使ってラフネスのある材質のリフレクションを実装した以前、環境マップを用いて、リフレクションを実装した。Ma...2018-03-28Hashed-Octree(ハッシュ化八分木)による空間分割を実装したそろそろレイトレがしたい。Maps(分散シャドウマップ)を実装しようと思...2018-03-09SkyBoxを実装したSkyBoxを実装した。»プロフィールid:riyaaaaasan東京で働くゲームエンジニア。結局オブジェクト指向とはいったいなんなのかとか、ゲームの設計に関して最近思うことグローバルイルミネーションのためのフォトンマップ実装18分木空間でのレイトレースのコリジョンリスト収集処理を見直して10倍速くしたその気になれば前提知識無し機材無しの無の状態から2週間で美少女VTuberになれたという話Boost.Spirit.QiによるXモデルパーザ実装の紹介1月別アーカイブはてなブログをはじめよう!riyaaaaasanさんは、はてなブログを使っています。ブログを報告するスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。