いぬおさんのおもしろ数学実験室

おいしい紅茶でも飲みながら数学、物理、工学、プログラミング、そして読書を楽しみましょう

Unityで、オブジェクトに動的にマテリアルを設定する

 作成中のシューティングゲーム、「これは解決しとかなきゃまずいだろ……」という問題が。PCで実行するときは大丈夫なのですが、実機(スマホ)だと場面によってはFPS(1秒間に描画する回数)が10台になってしまいます。人間が見たとき、30を切っていると動きがカクカクしてしまいます。10台なのでカクカクどころか照準の操作もうまくいかない状態。問題の場面は、爆発が続けて(5回とか6回とか)起こったときです。ぼくは爆発の表現にはパーティクルを使っています。キレイでよいのですが、多分負荷は大きいんだろう、となんとなく思ってはいました。何しろ細かな点(小さなオブジェクト?)を何千も出しているんでしょう? パーティクルを使い続けるならパラメータを変えるなどして負荷を小さくしなければなりません。しばらくあれこれ試したんですが結局うまくいかず、爆発にパーティクルは使わないことにしました。
 古いゲームではこんなカットをアニメーションしていました。今回はこの方法でいきます。

f:id:Inuosann:20210514201115p:plain:w400
爆発シーン

しかしさらに派手にしたいと思って新しく作りました。今使っている爆発シーンを録画して、何十枚かのカットを用意します。背景が透過して見えるように、pngファイルにします。この画像をUnityに取り込んで、何十かのマテリアルを作ります(マテリアルには画像をセットする)。そしてスクリプトで、爆発シーン描画用の例えば3DオブジェクトのQuadなどに必要なマテリアルを順にセットしてアニメーションさせるのです。

 この「マテリアルをセット」が今回のテーマです。何十ミリ秒かそこら毎にマテリアルをセットし直すだけなので簡単にできるだろうと思っていたら躓きました。何時間か格闘してたどり着いた結論をお知らせします。

 手作業で作ったマテリアル(マテリアルには手作業で画像もセットしておく)の名前を Inuosann としましょう。それを Asset フォルダ内の Resources フォルダにコピーしておきます。マテリアルを貼り付けたいオブジェクトは Quad だとします。このとき、次のスクリプトを実行すれば Quad に画像が表示されます。

 Material mat = (Material)Resources.Load("Inuosann");
 GameObject go = GameObject.Find("Quad");
 go.GetComponent<Renderer>().material = mat;
f:id:Inuosann:20210514204131p:plain:w250
実行前
f:id:Inuosann:20210514204252p:plain:w250
実行後

 実際には、マテリアルは必要な個数、手作業で作っておきます。マテリアル1には爆発シーンの1枚目、マテリアル2には2枚目、……とセットします(マテリアルの作成は Assets → Create → Material)。そうした上でさっきのスクリプトを繰り返し実行すればよいのです。

 続けて爆発するようなシチュエーションがなければいいんですが、そうもいきません。みんな、どうしてるんだろ……。

追記:
スクリプトのmat、goは必要な分、あらかじめロード、生成しておくと速いと思います。