MagicaVoxelデータをWebGLのポイント・リスト(ポイント・スプライト)で疑似表示する
mwasmのプリプロセッサをある程度完成させたところで、それ使ってゲームを作ろうとしている。wasmでゲームを作ろうと思ったら、リソースをメモリにマップしてアクセスできるようにしてやるか、JS側でリソースアクセスのための関数を作ってwasmにエクスポートする必要がある。JS側の関数を呼び出すのは安直でよいが、呼び出しのオーバーヘッドが気になるのでメモリにマップしてそこにwasmに書き込ませ、JS側でメモリをデコードして各種リソースにアクセスするようにすることにした。
内容はレトロ風の横スクロールシューティングである。パワーアップ可能な自機が敵をなぎ倒して進めるようなタイプのやつである。グラディウスとかR-TYPEとかそのたぐいのやつだ。
解像度は160x100で名機PC8001の疑似グラフィックレベルとした。色はフルカラー表示である。強烈な低解像度ではあるが、私には手に余るくらいである。なぜなら私は2Dのドット絵を描くのが大の苦手だからだ。上のR-TYPEのオプションは回転している。この回転は1フレームずつピクセルを描きこんだ静止画で表現している。絵心のない私は解像度を下げてこの敷居を下げようと思ったのだ。解像度を下げると表現力は下がるからへたくそな私側に近づくのだ。「N-TYPE」というゲームを見て160x100でも十分遊べると思ったし。
これにフルカラーの表現力があれば十分いけると思った。
だがしかし、160x100であってもグラフィックを描くのは難しいし、面倒くさい。昔Blenderを使ってローポリでモデリングしたキャラクターを表示すれば多少楽なんじゃないか?と思ってチャレンジしたがBlenderは本格的なツールすぎるので使い方を覚えるだけでへとへとになってしまった。しかも爺なのですぐ使い方を忘れてしまう。
それにポリゴンキャラクターだとある程度の解像度がないとキャラがつぶれてしまう。解像度を上げると今回の要件を満たさない。
もっとモデリングが簡単にできるものがないかな。。と思ってググって見つけたのが「MagicaVoxel」というツールである。
使ってみるとわかるが、操作が非常に簡単。でこれをいじってみて「1ボクセル=1ピクセルにすればいけるんじゃないか?」と思った。
WebGLのシェーダはポリゴンを描画する以外に「線分」と「点」を描画することができる。点描画は頂点をそのまま指定の大きさの正方形として描くというもので、頂点シェーダーの「gl_PointSize」で指定できる。これは一般的には「ポイント・スプライト」と呼ばれていて、パーティクルの描画などで使われている。わたしはかつてこれを使ってスプライトエンジンを試作してみたことがある。
https://www.sfpgmr.net/test/twgl/004/
これは「1ポイント・スプライト=1スプライト」としてみたものである。頂点ごとに設定できる正方形はフラグメント・シェーダーでテクスチャ・マッピングできるのでこのようなことができる。この経験からもヒントを得て「1ポイント・スプライト=1ボクセル」として表示しようと思ったのである。本来はボクセル・モデルなので立方体で表示しなければ正確ではないのだが、そこは「独特な表現法」として許容することにした(笑)。
MagicaVoxelのファイル・フォーマットは公開されていて、見るとRIFF形式であった。読み込みのコードを書こうかなと思ったが、すでに読み込み・three.jsで表示するためのライブラリ「vox.js」があったので、読み込み部分を使わせていただくことにした。
そしてボクセルデータを読み込んでそれを描画するシェーダーコードを書いてみて表示してみたのが以下である。
とりあえず表示はできたのだが、ライティングが不自然というか、思ってるような感じにするのに少し考える必要があった。もともとボクセルデータなので、立方体として描画すれば普通にライティングすればよいが、今回はそれを1枚のポイント・スプライトで代替するので普通にライティングしても所望の結果にはならない。考えた結果、仮想的な立方体にライティングし、その結果をポイント・スプライトの表面の輝度とすることにした。その際隠れて見えないボクセルのデータを間引くようにした。その結果が以下の動画である。
ちょっと変わった表現になるのも想定通り(笑)。
そしてオブジェクトを複数表示にしてみたのが以下。混沌としてる(笑)
ここまででだいたい思い通りのものになった。とりあえずこれで進めることにする。あとは入力とサウンド周りを整備してwasmでメインコードを書こうかなと思っている。
この記事が気に入ったらサポートをしてみませんか?