剣の攻撃エフェクト(軌跡エフェクト)を自作してみたお話
こんにちは!見障子ゆきです!
今回は3Dゲームでよくある、剣のエフェクトをシステムから自作してみたお話です!
上記のエフェクトの中でも、剣についてくる軌跡のエフェクトをシステムから実装しました。
昨年のGWに試作として実装してみたものですが、知見増えつつも反省点も多かったので今回記事にします。
「去年のGWなのに今更?」とは言わないで!
さっそく紹介やっていきまっしょい!
■はじめに
今回はUnityで実装しています。
・Unity2019.4.19f1
ちょっとVerが古いですが、特に理由はありません。更新が面倒でした。
試される方はお好みのVer.あるいはツールをご利用頂いて問題ないかと思います。
また、実装したプログラムの配布等は行っていません。
本作は試作であり、反省点が多いためです。
あと今回は「剣の攻撃モーションに特化した」システムにしました。スマブラの剣エフェクトに感化されたためです。
■エフェクトの構成について
今回のGifサンプルには軌跡エフェクト(トレイルエフェクト)以外にも複数のエフェクトが含まれているのでいったん切り分けます。
今回の構成は下記のようになっています。
・軌跡エフェクト(トレイルエフェクト)
・切り裂きエフェクト(Hitエフェクト)
・キャラの残像エフェクト
◇軌跡エフェクト(トレイルエフェクト)
剣の軌跡についているエフェクトです。
これ、剣じゃなくても何かの軌跡に対して広く使われるためか、名前が統一されてない類のシロモノな気がします。
残像エフェクトとか軌跡エフェクトとか剣閃・剣戟エフェクトとか風切りエフェクトとか。
大判焼きみたいですね。ベイクドモチョチョ。
UnityではTrailエフェクト(TrailRenderer)という形のシステムがあるので、自分はそれに合わせてトレイルエフェクトと呼んでいます。
(以降、トレイルエフェクトと呼びます)
◇切り裂きエフェクト(Hitエフェクト)
完全に適当につけた呼び名です。
どちらかというと、剣以外も総称してHitエフェクトと呼ばれる事が多い気がしますが、剣の場合なんか"Hit"エフェクトという気がしなくて……。
ちなみに、アニメーションのさせ方は各社いろいろあると思いますが、本件ではBlendShapeで動きのパラメーターを持たせました。
ついでに、Shaderで合成の仕方を「通常(半透明)合成」+「加算合成」で2パス合成しています。明るい背景でもそこそこ色が見えるようにしたかったので。
◇キャラの残像エフェクト
キャラの動きをトレースするように残って発光しているEFです。
時間経過とともに薄くして消しています。
用途としては、素早いモーションを見やすくするための残像の意味合いが多いでしょうか。
本当はポリゴンの重なり方が見えないようにした方が良いのですが、今回はおまけ程度なのでちょっと手抜きです。
こんな感じの3つのエフェクトから構成されています。
今回はこの中のトレイルエフェクトについての解説となります。
切り裂きエフェクトと残像エフェクトの話は本記事では以降登場しません。
■本件のシステムの超概要
開発ご経験者の方など、人によっては本記事の続きを読む時間を省略出来るかもしれないので、先に今回実装したシステムの超ざっくりな概要を記載します。
<本件システムの超概要>
・トレイルエフェクトと剣攻撃モーションは非同期です。
・剣攻撃モーションを元に、軌道の参照用座標を事前に生成しています。
(剣先・剣根本から生成される2本のベジェ曲線に同期しています)
・↑の参照用座標をトレイルエフェクトと同期しています。
・生成した参照用座標からポリゴンを生成して制御しています。
剣の動きとエフェクトを一致させていない理由や、そもそものトレイルエフェクトの仕組みや実装の解説などを、本項以降で記載します。
興味のある方はぜひどうぞ!
■一般的なトレイルエフェクトの仕組み
基本的には「1フレーム前の座標と現在の座標を繋ぐ」というのがトレイルエフェクトの仕組みです。
1フレームとは画面の描画1回分の事です。静止画状態1枚分。
パラパラ漫画でいうところの1ページ分です。
ここで重要なのは、動いた過去の座標との差を描画するという事。
つまり過去形です。未来予測しての描画は性質上できません。
これが今回の記事のキーとなります。
■参考:UnityのTrailRenderer
参考として、Unityの汎用的なシステムとして用意されてる「TrailRenderer」はこんな感じ。
張られているテクスチャは適当な仮のものです。
これはこれで悪くないように見えます。
しかし、汎用的システムであるがゆえに2つ難点があります。
◇難点1:動きがエフェクトの形状に影響する
1つ目は動きがクォリティに直結する、ということです。
単調な動きなら破綻は少ないんですが、アクション強めの攻撃モーションなんかは簡単に破綻します。
素早い攻撃はモーションのフレームを間引いたりもするので、モーション側で調整を抑えるのにも限界があります。
◇難点2:FPSに依存する
2つ目は滑らかさがFPSに依存する、ということです。
(FPS=「フレーム パー セカンド」。1秒間に何フレーム描画できるか)
毎フレーム座標を記録してポリゴン生成に利用されるので、フレーム更新の速度や滑らかさ(=FPS)で左右される、ということですね。
プレイヤーの環境によってクォリティにバラつきが出てしまいます。
激しい動きをしない範囲であれば、十分役に立ってくれるシステムです。
が、今回はアクション強めということもあり、システム自作に踏み切りました。
■綺麗・滑らかな曲線を作るには
剣の軌跡を作るなら綺麗で滑らかにしたい!
ということで、曲線の仕組みから実装します。
代表的なのはベジェ曲線でしょうか。
PhotoshopやIllsutratorを使った事のある方ならピンとくるかもしれないアレです。
ベジェ曲線の実装については、先達の方がUnity実装をサンプル付きで公開されていたのでそちらをご紹介します。
こういうの本当にとてもありがたいです。感謝!!
■あれ、ベジェ曲線って……
ここで「あれっ…」と気付いた方はベジェ曲線マスターの方でしょう。
ベジェ曲線は、綺麗にデザインするなら1つ先の座標を想定してベジェハンドルをコントロールする必要があります。
1つ未来が分かっていないと綺麗な曲線にならないベジェ曲線と、
過去しか描画できないトレイルエフェクトの仕組みは微妙に噛み合わせが悪いです。
というより、未来によってそれまでの理想的なカーブが変わるならベジェ曲線でなくてもこの問題は発生します。
トレイルエフェクトの基本(=汎用性)を活かそうとすると綺麗なカーブに支障が出る、ということですね。
そのため、
・綺麗な曲線を諦める(多少の歪みを許容する)
・汎用的なトレイルエフェクトの仕組みを諦める
のどちらかの対応は必要になってきます。
(中間のフレームを細かく多めに取る、として滑らかにする事で解決を目指す事もあります。が、中間フレームが多い分、動きが少しもっさりしがちになったりも。)
■本件のトレイルエフェクトの仕組み(概要)
前置きが長くなってしまいましたが、上記までの理由により、
今回は綺麗な曲線を再現する(=汎用的な仕組みを諦める)形での実装を行いました。
理由は単純で、攻撃モーションに紐づく形のエフェクトであるため、既にモーションが決まっている(=未来が決まっている)形式でのエフェクトだからです。
具体的には、
×:剣の座標を追従
○:事前に剣が通る座標を生成(記録)しておいて、その記録を追従
する仕組みとなります。
攻撃モーションを元にあらかじめ座標を生成しておく事により、ベジェ曲線のところで触れた「未来が分からないと綺麗な曲線が作れない」問題を回避しています。
すごく簡単に言うと、モーション関係なくエフェクトが再生されます。
モーションと同時に再生することで、追従しているように見せかけているという事ですね。
見せかけの手法には不便もありますが、悪い事だけではありません。
剣の動きに追従する必要がなくなるということは、誇張表現が出来る(デザイン性を出せる)ということでもあるからです。
■本件のトレイルエフェクトの仕組み(詳細)
そんなわけで、今回実装したのは
・事前に剣の軌跡の座標を生成できる仕組み
・生成した座標を基に、エフェクトを生成&再生するシステム
の2点となります。
◇事前に剣の軌跡の座標を生成できる仕組み
事前に座標を生成するとは言ったものの、0から手作業で座標(+ベジェ曲線のハンドル)を生成するのはすごく手間。
ということで、アニメーションウィンドウのフレーム合わせからハンドルを生成できる仕組みを用意しました。
生成したらベジェ用のハンドルを好きなように調整します。
生成された座標は同スクリプト内で管理&別のスクリプトで取得され、エフェクトアニメーション制御に用いられます。
◇生成した座標を基に、エフェクトを生成&再生するシステム
ハンドルの調整後、アニメーション側で「生成座標のN番目まで表示する」パラメータを調整します。
この数値を元に、同プログラム内でMeshの生成やマテリアルの貼り付け、MeshのUVの調整などが更新されます。
また、ポリゴンの滑らかさ(=分割数)もここで指定できます。
これらをアニメーションで指定して、表示から消去までの流れを組めば完成です!
■やってみての反省点
記事の冒頭のとおり、思ったよりも反省点が多かったのでそちらも紹介します。
◇生成・管理が手間
楽にできる事を想定して実装したつもりでしたが、それでも手間でした。
・事前に剣に専用のコンポーネントを仕込んでおく手間
・1フレームずつベジェ用ハンドルを生成する手間
・ハンドルの角度を一つずつ調整する手間
・アニメーション制御の手間(出現~消えるまでの制御が手動)
なんといっても、先ほど仕組み詳細で掲載した、座標の事前生成のGif。
このGifのままだとまだロクに使えない形状なのですよね。
これ、Photoshop等とは違って3次元でのベジェ調整が必要。
しかもサンプルではたった3フレーム分。長い尺はもっとつらい。
せめて、フレーム範囲を指定して一括生成できるようにしたり、生成時にベジェの角度をある程度でも曲線に合わせておいてくれる仕組みだったり、を実装すべきだったかなぁ、という反省です。
◇トレイルエフェクトがずれる
これが一番良くなかったです。
非同期処理の定めというべきか、UnityのAnimator実行内容の理解不足というべきか、トレイルエフェクトと実際のモーションに乖離が生じました。
通常速度だと分かりにくいのでスロー再生にします。
1/10の速度の映像がこちら。
これによって何が困るかっていうと、スクショが撮れない。
あと、スローモーション演出ができない。
どちらもゲーム開発としては致命的です。
これ、1フレーム単位でアニメーションを合わせてもズレました。
予想される理由はいくつかありますが、
・今何フレーム目?の計算が、Animatorだと小数点まで用いられる
(例:4.7フレーム目、というポーズを平気で描画します。
PCの実挙動におけるFPSが一定ではないからかなと予想)
・小数点のアニメーションまで揃えるのは非常に困難
・Animatorによるキャラポーズ更新とエフェクトMesh更新の時間差
あたり(?)が原因でしょうか。
フレーム数が少ないほど完全な一致が出来ませんでした。
たぶん、ちゃんとやるならキャラクター側のAnimation制御処理も自前で実装しないとダメっぽさそう?な気がしています。
少なくとも、全体のMeshの更新とレンダリングのタイミングを揃える必要がありそう。
(数社でAnimatorあまり使わない、と小耳に挟んだことはありますがこの辺りが理由かなぁ……?便利ではあるんですが…。)
◇マテリアルの描画順の制御が必要
トレイルエフェクトを2つ以上同時に描画する際、どちらかが画面から正しく描画されなくなりやすいです。
(トレイルエフェクトというより、マテリアル・シェーダーの話ですが)
ちょっと小難しい話ですが、3Dにおける半透明(エフェクトetc)の描画が、そうでない不透明の描画とはちょっとルールが異なるために起こりやすい現象です。
いや、まぁこれ単体は制御出来るんですが、
・ゲーム想定だと他にも半透明のエフェクトは出てくる
(それらを想定して制御する必要がある)
・「◇トレイルエフェクトがずれる」がショック過ぎた
ので見て見ぬふりをしてましたすみませんでした!!!
■最後に
反省点は多かれど、エフェクトのカーブにケレン味やデザイン性を出してカッコよく出来るのは超楽しかったです!!!
いつかAnimatorの自作をする事があったらリベンジしてみたいなぁ。
#ゲーム
#ゲーム開発
#プログラミング
#3DCG
#エフェクト
#Unity
#解説
#作ってみた