グラフィックの表示に成功した
こんな感じ
デモ用のスプライトを画面内に撒き散らしてみた
やっぱり絵が表示されると気分もあがるなあ。
あとドット絵っていいよねー
じつは、ざっくりしたグラフィックの表示自体は6月3日あたりで達成していたんだが、やっぱり公開するならちゃんと体裁を整えたい!…ということで色々やっていたら、なんやかんやてこずって時間がかかった。
だって、動きもしないただの市松模様を見せられてもおもんないでしょ…?
ハマりポインツ
DirectX11 定数バッファのパッキング規則
グラフィックの描画には DirectX11 を使っている。
ゲームエンジンとかは使わず、生の API を直接叩いて実装していくスタイル。
で、何にハマったかというと、DirectX11 の定数バッファの仕様だ。
頂点バッファにパラメータを送る際に、「四辺形だから4頂点あるし」とか思って配列を使ったんだが、このせいでドはまりしてしまった。
DirectX11 の定数バッファでは、16bytes を境界としてアラインメントの再配置が起こる。
これについてはネット上に情報がいっぱいあったし、筆者も警戒してコーディングしていたんだが…
問題は、配列の場合は このルールが1要素ずつ適用される ということ。
だから、パラメータとしてこのように定義していたとしても…
// D言語 struct VSNormalArg { float[2][4] vertexes; } // HLSL cbuffer VSNormalParams : register(b0) { float2 vertexes[4]; }
HLSL 側は(イメージとしては)パラメータをこのように解釈する。
// えぇ… cbuffer VSNormalParams : register(b0) { // 16bytes float2 vertex0; float2 dummy0; // 16bytes float2 vertex1; float2 dummy1; // 16bytes float2 vertex2; float2 dummy2; float2 vertex3; }
渡したつもりのデータは、まるっきりズレた領域に書き込まれるので、レンダリングがさっぱりうまくいかないのだ。
こんなん分かるか。
あたまおかしくなるかと思ったぞ。
解決方法としては至極単純で、16bytes に調整されてしまうなら最初っから1頂点を 16bytes として渡せばいい。
こんな風にね。
// D言語 struct VSNormalArg { float[4][4] vertexes; // float * 4 [2] と [3] は使わない } // HLSL cbuffer VSNormalParams : register(b0) { float4 vertexes[4]; // float4 'z' と 'w' は使わない }
使わない末尾 8bytes がもったいない気もするが、まあいいや。配列で処理できたほうが断然便利だし。
シンプルイズベスト。
いやはや、しかし、知ってる人には当たり前の話なのかもしれないが、大変だったぞ。
DUB の stringImportPaths
まあこれはしょうもない話かもしれない…
パスを複数指定していた場合、各パスに同じ名前のファイルがあると、一番先頭にあるパスのものを参照しちゃうっぽい。
// ディレクトリ構成 aaa\bbb\ccc\name.bin xxx\yyy\zzz\name.bin
// dub.json "stringImportPaths": [ "aaa/bbb/ccc", "xxx/yyy/zzz" ]
// Dソースコード import("name.bin"); // <- aaa\bbb\ccc のファイルが参照される。
これ、コンパイルエラーにならんのか…。まあならんよなー
でもさ、import
でシンボル名が被ったときは「どっちか分かんねえ!」ってコンパイルエラーになるやん…(´・ω・`)
この問題にも結構時間を食ってしまった。
以上
まあ色々と壁にはぶち当たったが、グラフィックを無事表示できて満足。
引き続き頑張っていきましょう。
うわああああああ!!
実装にあたっての参考文献
- https://ku6.jp/report/9.html
- https://qiita.com/mono_shoo/items/e4a45b7ed12114c04b51
- https://qiita.com/ousttrue/items/a4291fc996a063841bd7
本当に助かりました…。皆様ありがとうございます。