読者です 読者をやめる 読者になる 読者になる

テラシュールブログ

旧テラシュールウェアブログUnity記事。主にUnityのTipsやAR・VR、ニコニコ動画についてのメモを残します。

【Unity】タップした位置にエフェクトを表示する

f:id:tsubaki_t1:20160428002851g:plain

スマホでよくあるような、タップした位置にエフェクトを表示させる表現の作り方について、少しメモします。

タップした位置(カメラから見た3D座標)を取得

今回はパーティクルを使用してエフェクトを表現したいので、タップした位置を取得します。
タップした位置を取得するには、マウスのスクリーン座標を指定のカメラから見たワールド座標(3D空間の座標)に変換します。

 var pos = _camera.ScreenToWorldPoint(Input.mousePosition + _camera.transform.forward * 10);

Input.mousePositionはマウスの現在の座標を取得します。タッチパネルでやるならば、Touchクラスから取得すると指を何本か取得出来そうです。

ScreenToWorldPointは、単純にスクリーン座標をワールド座標へ変換しています。ここにInput.mousePositionを設定することでクリックした位置の3D座標が取れる訳です。但し、そのまま座標を指定すると「カメラの原点」を取ってしまうので、奥に10mほど進めた位置を取得しています。

f:id:tsubaki_t1:20160428000500p:plain

タップエフェクトを表示

次にタップ時に表示するエフェクトを表示します。

イメージ的には「タップ時に」「タップした位置の中央」に「1つだけ」「波紋のような感じ」で表示するエフェクトです。

f:id:tsubaki_t1:20160428001353g:plain

まず、波紋っぽい表現を行います。
パーティクルの基本設定です。
とりあえずStart lifetime(パーティクルの生存時間)は1秒、Start Size(初回サイズ)は5mとします。
パーティクルを生成するオブジェクトを移動させたいのでSimulation SpaceはWorkdを選択、Max Particlesは100くらいにします。
スクリプトで制御したいのでPlay On Awakeも使用しません。

f:id:tsubaki_t1:20160428002405p:plain

Color Over Lifetime(パーティクルが生きてる内の色変化)で最初はαが45(最大255)、最後は0になるように設定します。

次に、Size Ofer Lifetime(パーティクルが生きている内のスケールの変化)で、最初にグイっと大きくして、あとは緩やかに大きくなる感じにします。

f:id:tsubaki_t1:20160428001958p:plain

なお、今回のエフェクトは「単発」かつ「指定位置に生成」なエフェクトなので、EmissionとShapeの設定は使用しません。

f:id:tsubaki_t1:20160428003249p:plain

エフェクトだけを表示するカメラの設定

エフェクトを表示する際、できれば最前面で表示したいものです。なので、最前面に表示されるようにします。

やり方は2つあります。1つはエフェクトを表示するシェーダーを変更し最前面に表示する方法。これはある意味楽ですが、ローディング等でカメラが消えたりする際に例外ルールを設けなければいけないので若干面倒です。

なので、第二案、パーティクルのみを表示するカメラを用意する事にします。

 

カメラにはタップ時のエフェクト以外表示しないように設定します。Dont ClearとDepth 99で、最前面に描画し拝啓をクリアしないように設定するのも忘れません。

f:id:tsubaki_t1:20160428010801p:plain

エフェクトはTransparentFXに所属させておきます。

f:id:tsubaki_t1:20160428011129p:plain

おまけ:最前面にパーティクルを表示する

カメラを二つ用意したくない場合は、独自のシェーダーを設定しパーティクルを最前面に表示するアイディアもあるにはあります。

やってる事は「ZTest Alwaysty 」(奥にあるオブジェクトを描画しない…を無効)し、「 "Queue" = "Overlay"」(できるだけ最前面に表示)を設定しているだけです。

最前面に表示するParticles/Additiveなシェーダー · GitHub

但し、CanvasのScreenSpace-Overlayより前に表示することは出来ません。

f:id:tsubaki_t1:20160428011955p:plain

タップした位置にエフェクトを表示

タップした位置にエフェクトを表示させます。
パーティクルを生成・破棄を繰り返しても良いといえばよいのですが、余りにも無駄なので、パーティクルのエフェクトのみを生成します。

gist.github.com

シーン内の適当なオブジェクトに上のコードをアタッチし、TapEffectに先ほど作成したパーティクルを設定します。
勿論Cameraには、先ほど作成した「エフェクトだけを表示するカメラ」を設定します。

f:id:tsubaki_t1:20160428011037p:plain

おまけ:何故ParticleStstem.Emitを使うのか

オブジェクトの生成・破棄は結構負荷が高いです。また、ParticleSystemは結構多くのパラメータを持つオブジェクトであり、インスタンス化・破棄で結構多くのCPU・メモリを喰います。

その点、ParticleStstem.Emitでパーティクルを生成しまくる場合、ParticleSystemを量産するよりかなり安くパーティクル表現出来るっぽいです。

例えば100個のパーティクル(各Max Particleは1)で100個のエフェクトを表示した場合と1個のパーティクル(Max Particleは100)で100個のエフェクトを表示した場合では、パフォーマンスにソコソコの違いが見て取れます。

f:id:tsubaki_t1:20160428022051p:plainf:id:tsubaki_t1:20160428021143p:plainなおEmitで生成する場合はMax Particle以上のパーティクルを生成出来ないので注意です。(内部的にオブジェクトプールしてるっぽいです)

いとおかし。

関連

unitech.hatenablog.com

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp