みかづきブログ・カスタム

基本的にはちょちょいのほいです。

VoxelでThree.jsに読み込み可能な3Dモデルをつくる 📦

f:id:kimizuka:20201105142358g:plain


はじめに

ちょっと前からVRのゲームを作っていまして、ゲームのロジックはなんとなくできてきたのですが、モデリングが一向に進まずに困ってました。
適当な3Dモデルを購入してしまうのも一つの手ではあるのですが、今後の拡張性を考えると己の手でVoxcelでつくるのが良かろうと思い、Voxelのモデリングに挑戦しました。

ちなみに僕のVoxelのレベルですが、つい先日まで、ボクセルをBoxelだと思っていたぐらいの初心者です。
Boxを積み上げるからボクセルだと思ってました。Volumeを持ったPixelでVoxelなんですね。勉強になりました。

己のスキル

❌ Blenderは嗜む程度に触れる(美味しそうなドーナッツぐらいなら作れる)
❌ Vocelは経験無し(マインクラフトも経験無し)
❌ ドット絵の経験無し(本当に簡単なものなら描ける)
⭕️ Three.jsは触れる

という感じです。

己のスキルで実行可能な作戦を考える

❶ ドット絵で三面図を描く
❷ ドット絵の情報を配列にする
❸ 配列を元にThree.js上でモデルを組み立てる

己のスキルを鑑みて上記の作戦を立てました。
ドット絵を書くときもわざわざ画像ファイルで書き出さなくとも、配列を元にCanvas上で描画していたので、それの3D版というイメージです。
VoxelのモデルであればわざわざBlenderでモデリングするまでもないでしょう。
リギングとかも面倒だし、ドット絵をアニメーションさせる感じで毎フレームごとのVoxelを作ってしまおうかなと考えております。(のちに後悔するかもしれません)

ドット絵の三面図の大きさを決める

まずはPhotoShopをつかってドット絵を描きました。
鉛筆ツールを使えば1px × 1pxでアンチエイリアス無しの■を描くことができるので、それでドットを描いていきましょう。

その際、まず決めなければならないのはキャンバスの大きさです。
今回は弓矢を使うゲームということを決めていたので、なんとなくで弓矢を引いているっぽいドット絵を描いてみました。

f:id:kimizuka:20201105143610p:plain

おそらくこのポーズが一番面積を食うドット絵になるでしょう。なので、10 × 10あれば納まりそうです。

本当は立方体にする必要はないのですが、以前作った仕組みを流用することを考え、10 × 10 × 10 のスペースでモデルをつくることを決めました。

blog.kimizuka.org

ドット絵で三面図を描いて輪切りにする

f:id:kimizuka:20201105143959p:plain

えいや!という感じで、弓を引いているポーズとAポーズの三面図を描きました。

その下の10個のドット絵は、高さ方向に輪切りにして下から並べていったものです。
この作業をするとき、輪切りのソルベを思い出さずにはいられませんでした。

また、このタイミングで10 × 10 だと偶数なのでセンターが無いことに気づきましたが、まあちょいとどちらかに寄せれば良いということにしました。

輪切りの情報を配列にする

ここは頑張れば自動化できると思うのですが、現状は手で書いてます。
ドットがある部分を0以外、無い部分を0で表現し、輪切りを下から並べた配列です。
色をつける可能性があるので、弓は2、人は1で表現しました。

const boxes = [
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,1,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,1,1,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,1,1,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,1,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,2,0,1,1,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,2,2,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,1,
  0,0,0,0,0,0,0,1,0,0,
  0,0,2,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,1,1,
  0,0,0,0,0,0,0,1,0,0,
  2,2,2,2,1,1,1,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,2,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,2,2,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,2,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0
];

Aポーズ

const boxes = [
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,0,0,
  0,0,0,0,0,0,1,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,0,0,
  0,0,0,0,0,0,1,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,1,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,

  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,1,1,1,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0,
  0,0,0,0,0,0,0,0,0,0
];


配列をThree.jsでレンダリングする


Aポーズ

Aポーズの方はキーボードでポーズを変えられるようにしてみました。
「A」でAポーズ、「T」でTポーズ、「スペース」で弓を構えます。

レンダリング結果はイメージ通りですが、回転していると3D感があって良いですね。
ものすごくシンプルですが、このレベルであればゲームに必要な素材をガシガシ作れそうです。