- 投稿日:2019-03-10T23:49:26+09:00
【Unity】EditorGUIUtility.SetIconSizeを使うよりIconSizeScopeを使おう
概要
EditorGUIUtilityにはGUILayout.LabelなどGUIContentで表示するアイコンのサイズを変更できるSetIconSizeという関数があります。この関数を呼ぶことで、この場面ではアイコンを小さくしたい、この場面では大きくしたいなど状況に応じて変更を行うことができます。
ただ、デフォルトのサイズに戻したいときに、変更前にGetIconSizeでデフォルトのサイズを取得して変数に保持しておくのは手間に感じました。これを改善できないか調べた所IconSizeScopeを使うことで、上記の問題が解決しそうだということがわかりました。
IconSizeScopeとは
IconSizeScopeとは、GUI.Scopeを継承したScopeです。
GUI.Scopeはusingを使うことでコンストラクタで初期化処理を、using内の処理が終わったあとに呼ばれるIDisposable.Dispose()で解放処理を呼ぶことができるものです。
IconSizeScopeではコンストラクタにVector2を渡すことでアイコンのサイズを設定し、Disposeで変更前のサイズに戻してくれます。実装
例として32x32の大きさでアイコンを表示し、それ以降はデフォルトのサイズで表示するように実装したいと思います。まずIconSizeScopeを使わなかった場合はこうなります。
NoneIconSizeScopeTest.cs//あらかじめデフォルトのサイズを取得 var defaultIconSize = EditorGUIUtility.GetIconSize(); //32x32で表示するように設定 EditorGUIUtility.SetIconSize(new Vector2(32,32)); //アセットの表示に使われているアイコンを持ってきて表示 var texture = AssetDatabase.GetCachedIcon("アセットのパス"); GUILayout.Label(texture); //デフォルトのサイズに戻す EditorGUIUtility.SetIconSize(defaultIconSize);事前にデフォルトのサイズを取得しないといけなかったり、最後に元のサイズに戻さないと行けなかったりと意識しないといけない所がありますね。
ではIconSizeScopeを使うとどうなるかというと、こうなります。
IconSizeScopeTest.cs//using内では32x32のサイズで表示するように設定 using(var iconSizeScope = new EditorGUIUtility.IconSizeScope(new Vector2(32,32))) { //アセットの表示に使われているアイコンを持ってきて表示 var texture = AssetDatabase.GetCachedIcon("アセットのパス"); GUILayout.Label(texture); } //usingの外に出たためDisposeが呼ばれ、以降はデフォルトのサイズで表示される意識しないといけなかった所がなくなって、呼び出すだけでよくなったためシンプルな構造になりました。
また、usingを使っているためこの中では32x32のサイズになっていると明示的に確認できるようになったため、他のアイコンも一緒に表示したいときにもこの中に入れれば表示されるというのがわかりやすくなったのも良い点だと思いました。まとめ
IconSizeScopeはGUI.Scopeを継承しているため、コンストラクタでアイコンのサイズを変更し、解放処理で元のサイズに戻すことができました。
Scope系は他にもあると思いますので、調べたらまた記事にしたいと思います。参考
- 投稿日:2019-03-10T22:43:25+09:00
【Unity(C#)】ゲームオブジェクトを毎回違う場所に配置する方法
この記事は『プログラミング完全未経験からUnityでの開発現場に迎え入れてもらえた世界一の幸せ者』
の記事です。そのつもりでお読みください。
ランダムではない
毎回違う場所に配置すると書きましたが、
ランダムとは少しだけ違います。私がやりたかったことは2回連続で同じ場所には絶対に出ないという実装です。
なのでちょっと面倒でした。
↓↓↓補足(2019.3/11)↓↓↓
同じエリアに連続出現しないだけで座標は毎回ランダムにしたい
これです!まさにこれ!
コメントありがとうございます!考え方
上のとてもわかりやすい図のように分けた場合、
もし0に出現したら次は必ず1、2、3のどこかに出現するようにします。もっと効率の良い方法があるのかもしれませんが、ちょっと急いでたのでこのやり方で実装しました。
値を返すメソッドを用意
ランダムな値を渡すとその値と同じ値を返すメソッドを用意しました。
これにより、一度出現したエリアの番号を記録できます。int? RandomArea(int patternNum) { if (patternNum == 0) { holeParentPosition = new Vector3(randomX_A, holeParentPosition.y, randomZ_A); this.gameObject.transform.localPosition = holeParentPosition; return 0; } if (patternNum == 1) { holeParentPosition = new Vector3(randomX_B, holeParentPosition.y, randomZ_B); this.gameObject.transform.localPosition = holeParentPosition; return 1; } if (patternNum == 2) { holeParentPosition = new Vector3(randomX_C, holeParentPosition.y, randomZ_C); this.gameObject.transform.localPosition = holeParentPosition; return 2; } if (patternNum == 3) { holeParentPosition = new Vector3(randomX_D, holeParentPosition.y, randomZ_D); this.gameObject.transform.localPosition = holeParentPosition; return 3; } return null; }最終的なコード
public GameObject hole; Vector3 holeParentPosition; int[] patternNumber = { 0, 1, 2, 3 }; int patternArray; float randomX_A; float randomZ_A; float randomX_B; float randomZ_B; float randomX_C; float randomZ_C; float randomX_D; float randomZ_D; void Start() { holeParentPosition = this.gameObject.transform.localPosition; } void Update() { patternArray = Random.Range(0, patternNumber.Length); randomX_A = Random.Range(0.5f, 4.0f); randomZ_A = Random.Range(-5f, -1.5f); randomX_B = Random.Range(0.5f, 4.0f); randomZ_B = Random.Range(-9f, -5.5f); randomX_C = Random.Range(-4.0f, -0.5f); randomZ_C = Random.Range(-9f, -5.5f); randomX_D = Random.Range(-4.0f, -0.5f); randomZ_D = Random.Range(-5f, -1.5f); //コルーチン開始(一回で抜ける) if (ThisProjectSingleton.Instance.isGameStart) { StartCoroutine(HoleRandomCoroutine()); ThisProjectSingleton.Instance.isGameStart = false; } } int? RandomArea(int patternNum) { if (patternNum == 0) { holeParentPosition = new Vector3(randomX_A, holeParentPosition.y, randomZ_A); this.gameObject.transform.localPosition = holeParentPosition; return 0; } if (patternNum == 1) { holeParentPosition = new Vector3(randomX_B, holeParentPosition.y, randomZ_B); this.gameObject.transform.localPosition = holeParentPosition; return 1; } if (patternNum == 2) { holeParentPosition = new Vector3(randomX_C, holeParentPosition.y, randomZ_C); this.gameObject.transform.localPosition = holeParentPosition; return 2; } if (patternNum == 3) { holeParentPosition = new Vector3(randomX_D, holeParentPosition.y, randomZ_D); this.gameObject.transform.localPosition = holeParentPosition; return 3; } return null; } IEnumerator HoleRandomCoroutine() { int? tmpNum = 0; int? memoryNum = 0; while (/*ゲームオーバーの条件を記述*/) { yield return new WaitForSeconds(0.5f); tmpNum= RandomArea(patternNumber[patternArray]); //もしランダムな数字( tmpNum)が前回(memoryNum)と一致したら通過。別の数字をtmpNumに代入して抜ける while (tmpNum == memoryNum) { yield return new WaitForEndOfFrame(); tmpNum = RandomArea(patternNumber[patternArray]); } memoryNum = tmpNum; hole.SetActive(true); //ホールにボールが入るまで待つ yield return new WaitUntil(() => ThisProjectSingleton.Instance.isHoleEnter); ScoreText.ScoreAdd(); //ホールが消える yield return new WaitForSeconds(0.5f); hole.SetActive(false); ThisProjectSingleton.Instance.isHoleEnter = false; } }いま自分で読み返しても読みづらいしもっといい方法がありそうです。
こんな方法もあるよ~って方、コメントください。unity1week
unity1weekという企画がありまして、
その名の通りUnityを用いて一週間でゲームを作ろうというおもしろい企画です。私も参加するつもりなのですが、
そこで作るのはWebGLというブラウザ上で起動する形式です。せっかく作ったのにビルドとかアップロードの仕方がわからない!
と本番でならないようにunity1dayと称して、
簡単なゲームを作りunityroomにテストアップロードしました。今回紹介したゲームオブジェクトを毎回違う場所に配置する方法も用いているので
よかったら覗いてみてください。↓人のコード見た後にそのゲームをプレイするの結構おもしろいです。
- 投稿日:2019-03-10T15:57:53+09:00
iOSに3D姿勢推定を実装してみた
昨年から機械学習の勉強として仕事にも使えるかと思い姿勢推定に挑戦しています。まだ全然理解できていないですが勢いで3Dの姿勢推定にも挑戦しています。Twitterに途中経過をアップしていますが、思いの外問い合わせが増えてきたので、まだモデルも自分も学習の途中ですが簡単にここにまとめます。
下の動画が2019/3/10時点での最新の結果です。昨年のゴールデンウイークから機械学習の勉強を初めて、今年の正月休みに3Dのコアになる所を一気に作りました(昨年進めてた2Dの環境を3D向けに改修した)。その為かなりバグやミスが多かったので、なおし直し(だましだまし)モデルの学習を進めてきたので、以下の説明でうまく行かなかった等の話はそれらのバグが原因も十分考えられますので、その点はご了承ください。
あれから一日学習したモデルで試してみました。一日経っても3epochしか進まない。。。少し足の動きが取れるようになったかな。フルスクリーンで見るとメールの通知が写り込んでしまってるけど、楽天ブックスだから気にしないw
— Yukihiko Aoyagi (@yukihiko_a) 2019年3月10日
アクション:ミソジサラリーマン様(@keriwaza
) pic.twitter.com/GDNsKiaGyB構成
学習環境は、Windows10でVS Code上でPyTorch0.4。
実行環境は、iPhone XSMaxを使用しています。XSMaxを使用しているのはA12プロセッサが非常に強力だからです。ですのでXSでもXRでも良いと思いますが、iPhone8等のA11プロセッサではCoreMLの実行速度が半分以下に落ちてしまうようです。コーディングでもっと速度を稼ぐことができるのかも知れませんが、今の所それに挑戦はしていません。Model
モデルはMobileNetV1をベースにしています。層が深い方が精度が上がるという話を聞いたので何層か追加して試してみました。目に見える結果はほとんどなかったのですが、なんとなくそのまま使っています。時間があれば色々比較してみたいんですが時間もないのでそのままです。
推定はSinglePersonに限定しています。MultiPersonは出力から座標を求めるのが結構面倒なのでまずはSingleのみです。
入力は224サイズの画像です。出力は2Dと3Dの両方を出力するようにしています。2Dは14x14x関節数のHeatMapと14x14x関節数x2(x,y座標)のオフセット値の出力です。このあたりはPoseNetを参考にしました。3Dも同様の発想で、14x14x14x関節数のHeatMapと14x14x14x関節数x3(x,y,z座標)のオフセットとなっています。3Dも回帰での推定です。今は関節数が24なのでかなり大きな出力になってます。3Dの姿勢の推定には、14x14の2DのHeatMapからx,y,zのオフセットで補正をかけて推定した方が出力サイズも小さく後の処理も楽で良いのですが、どうにも奥行き方向の感度が上がらなかったので、3DのHeatMapを使用するようにしました。Dataset
データセットも2Dと3Dのデータセットを用意しました。2DのデータセットはLeeds Sports Pose Dataset, Leeds Sports Pose Extended Training Dataset, MPII Human Pose Dataset, Microsoft COCOです。3Dのデータセットはオリジナルです。Unityで3Dのキャラクターのアニメーションを作り、カメラオブジェクトに写っているキャラクタの画像とボーンの各座標(肩・肘・手首・親指・中指の付根・足・膝・足首・爪先・耳・目・鼻・身体の中心(へそ位置))を出力するようにしました。キャラクタは十数体用意しました。フリーの物やAssetStoreで購入したデータ、もちろんUnityChanも含まれています。ライセンス的にややこしくなるのでこのデータセットは公開できません。UnityChanは問題ないと思うので下のような画像です。
学習
CGなのでキャラクタのテクスチャやポーズはかなり自由に変えれます。初めは各エポック毎にデータセットの内容が変わるようにすれば汎化性能が上がるかなと期待していたのですが、全然効果がなかった(毎回変わるとテストもしずらい)ので10万枚くらいの画像を作りその画像を学習に使用しています。
この3Dの画像でもそれなりには学習するのですが、どうしても似通った画像になってしまい期待した性能が得られません。”なんとか学習”という2つの学習をすると性能が上がるという話を聞いたので2Dの姿勢推定の学習も同時に行うようにしました。2Dのデータセットはその為に使っています。
学習はPyTorchを使っています。オプティマイザはAdam、なんかAdaBoundなんてものがあるそうなのでそのうち試してみたいです。実装
PyTorchで学習したモデルをonnxにexportして、coremltoolsでCoreMLのモデルに変換します。この時点で同じ画像の推定を行っても結果が異なっているので、精度がどこまで出ているのかわかりません(よくなってるって事はないと思う)。これをMacに持って行ってXCodeでiPhone用のアプリに実装します。バックカメラの画像をリアルタイムにキャプチャして3Dの推定を行うと、私のXSMaxでは40fpsくらいで動かせるくらいの速度で実行できます。ですが、しばらく使っていると本体があったかくなってきて30fpsくらいに落ちてきます。流石に重いんだと思います。2Dのみ学習したモデルだと100fps近くで動作しています。
3Dで表示する際にカメラから見えない部位も表示したい為、ヒートマップの判定の閾値をほぼ0に下げています。どういうことかと言うと、例えば普通に腕が見えている場合であればヒートマップの一番大きいところは0.5以上になります(Maxは1.0)。そして流石に腕が見えていないとそこにありそうと思っても0.2とか0.1になってしまいます。その為閾値を下げていますが、結果的にどこを見ても人がいると判定している状態になります。今後
動画を見ていただいたらわかると思いますが、それっぽく動いてますが細かい所は全然残念な感じです。もう少し精度をあげたいので、もう少し大きいモデルを使う、人間ぽさを出す為にGANを使うなどを考えています。あと、1epoch計算するのに7,8時間かかるのをなんとかしたい。これにGANとか入れたら何時間になるのか。。。
それとどこかで落ち着いたらswiftのコードだけでもGitにあげたいと思います。参考
Real-time Human Pose Estimation in the Browser with TensorFlow.js
PoseNetのBlog記事。これならできんじゃね?と思って機械学習の勉強を始めたので個人的に思い入れがあるページ。PyTorchでDeepPoseを実装してみた
そもそも機械学習どころかPythonでどう書くねんと言うときに参考にさせていただいたページ。なので必然的に今もPyTorchを使ってます。この記事がなかったら挑戦してなかったかも。PoseNetをマルチプラットフォームで実装してみた
この記事を読んで、ソースまで上げてくれてるしこれなら俺でもiPhoneで動かせるんじゃね?と思って試して見たページ。穴が開くほど読みました。Microsoft/human-pose-estimation.pytorch
Microsoftによる、PyTorchを使用した姿勢推定のコード。MPIIとCOCO用。とても参考になりました。DeepPose: Human Pose Estimation via Deep Neural Networks
DeepPoseの論文の説明。日本語なので論文読むよりわかりやすいです。apple/coremltools
Appleのcoremltoolsです。これがないとCoreMLのモデルになりません。願わくばもっと簡単に変換できるようになるとうれしいです。ミソジサラリーマンMisozi-Salaryman-game style action-
ミソジサラリーマン様のアクションの動画。フリー素材として使用可と言うことでありがたく使用させていただいています。アクションのキレが良すぎて姿勢推定にはなかなかハードルが高い。
- 投稿日:2019-03-10T13:16:27+09:00
UnityのHDRP環境でTerrainツールを使ってみたまとめ
概要
記事執筆時点
2019/03/09エンジニアがUnityのTerrainツール使って背景っぽいものを作るのにあたって書き残したメモ。
HDRPに途中から切り替えたので、そのとき当たった壁の解消法も残しています。作業環境
Platform Unity Version Windows 2018.3.8f1
- Terrainツール
- UnityTerrainEditor
- RenderPipeline
- HighDefinition Render-Pipeline
- PostProcess
- PostProcessStack
なんでUnityのTerrainツール?
なんとなく使ってみたかったので。
RenderPipelineとかShaderGraphとか使うならついでに勉強できるかなという期待参考にしたマニュアル
Unity - Manual: Terrain Engine
日本語マニュアルも存在するが、バージョンが古いためツールの操作の参考にはならない
- わからない単語とかTerrainオブジェクト設定のプロパティの確認に使うのがよさそう
Terrainオブジェクトを新しく作ったり高さ全リセットするとベイクが走る
- そこそこ時間がかかる
- とは言え広さと解像度によると思うけど数分で終わる
- HDRPにすると時間が増えた気がする
Unity - Manual: Terrain Layers
TextureのLayerの設定
下記で紹介しているTerrainToolkit使うとほとんどLayerを直接触らなくなった2018.3 Terrain Update: Getting Started – Unity Blog
2018.3でアップデート、追加されたTerrainの機能。
AssetStore, Packageでインポートしたアセット
Terrain Toolkit 2017 - Asset Store
Terrainのテクスチャとかディティールとか自動で作ったりするツール群
高さに応じたテクスチャのレイヤーのブレンドもやってくれるPost Processing Stack - Asset Store
Unity公式のPostProcessアセット。
ポストエフェクト。
レンダリング時に色調補正したりDOFを加えたりするのに使用する
Layer設定でDefaultのままだとパフォーマンスに影響出るかもって警告を出力されるのでとりあえず変えておくRenderPipelineの変更
HD レンダーパイプライン:アーティストのためのクイックスタートガイド – Unity Blog
手順は上記UnityBlogの記事が参考になります。
プロジェクトを途中からHDRPに変更する際にやることとしては、下記項目になります。
- PackageManagerでRenderPipelineのパッケージをインストールする
- Render-PipelineCore
- HighDefinition RenderPipeline
- ProjectSettingのRenderpipelineアセットにHDRenderpipelineアセットをアサイン
- マテリアルをHDRP対応したものにアップデートする
- メニューから一括でアップデート出来るようになっているので使う
- 出力するカラースペースをGammaからLinearに変更する
High Definition Render Pipeline overview · Unity-Technologies/ScriptableRenderPipeline Wiki
HDRPの機能リファレンス注意点
パッケージをインストールする順番
PackageManagerから入れるRenderpipelineは、最初にCoreをインストールしましょう。
.
RenderpipelineCore
↓
HDRenderPipeline
.
の順番になります。Consoleに下記のエラーが出力される
High Definition Render Pipeline doesn't support Gamma mode, change to Linear mode
Unity - Manual: Linear or gamma workflow
単純にHDRPがガンマ出力をサポートしてないみたいなので、Linear出力するようにプロジェクトの設定を変更しましょう。
プロジェクト作成時にHDRP選択してないとデフォルトはガンマ出力になってるっぽいです。作ってたTerrainオブジェクトが表示されなくなる
マテリアルがピンクになるでもなく、単純に表示されなくなりました。
試しに新規でTerrainオブジェクトを作ってみると表示されます。
新しく作ったところと古いオブジェクトの設定を見比べるとマテリアルに差がありました。ということで、HDRP対応のTerrainマテリアルをアサインする必要があります。
上図のようにTerrainのプロパティの設定からMaterialをCustomにしてHDTerrainMaterialを選択。AssetStoreの大体のアセットが対応してない
まだPreview版ですしね。
フォーラムに色々書き込んだらUnityの人とかが対応してくれるかもしれない。でもRenderPipelineが公式対応されるとアセットストアで配布してる人はRPの対応を迫られるんでしょうか。
疑問。ここまでの成果物
ポストプロセス適用
だいたいモデル完成
モデル作成中
ラフ絵
その他メモ
作業中のメモ書き
作業のメモ書きにQiitaを使用。
テキストが書ければ何でも良かったけど、WEB上で書いて勝手に下書き保存してくれるのでなんとなく選択。
あとでどうせQiitaに投稿するつもりでいたので最初からそこで書いてしまった方が早いなということで。WindowsのPCで実作業、MacbookとかiPhoneでQiitaとSlack見て振り返りとかする
ただし資料もだいたいWEBのものを見るのでChromeのタブが無限にできる。
メモリが!足りない!
メインメモリ最低16GBはエンジニアの人権に最低限本当に必要。自分との会話
若干怪しげな単語に見えますが、Qiitaにメモるまでもない思いついたこととかTodoを
Slackの自分だけのグループチャンネルにバンバン投稿してメモっています。
しばらくした後の自分がそのメモったスレッドに返信していく感じ。何するか、何をしようとしていたか、今の状況のスクショとかをSlackで書いていってます。
後で「なんだっけ・・・」「何しようとしたんだっけ・・・」ってなったときに一応見返せる。
自分用だから文章もかしこまらないでOK。
ちゃんとした作業ログを残すならそういう目的を持った別のサービスを使った方がいいとは思います。参考
Unity - Manual: Terrain Engine
UnityのTerrainで大地を創る - Qiita
Terrain Toolkit 2017 - Asset Store
【Unity】HDRPを使ってみる
- 投稿日:2019-03-10T09:56:42+09:00
Unity初心者やってみた2
前回の続き https://qiita.com/akagane99/items/92a1ca9bfb841d9b63a8
Unity 5でコインプッシャーゲームを作ろう(前編) | Think IT(シンクイット)
https://thinkit.co.jp/story/2015/07/22/6223
Unity 5の記事だけど、Unity最新版(2018.3.8f1)でも使える
AddComponent > [Physics]→[Rigidbody]
rigidbodyはオブジェクトに物理演算を適用するための機能です。これを追加するだけで、自然落下運動などの物理運動を再現してくれます。
行動予定: Unityで作った途中経過をWebで公開する。
参考記事
UnityのWebGLで書きだしたゲームをGitHubを使って公開する - Qiita
https://qiita.com/kenta71/items/c32760e1cc2ba01e8f9a操作
- メニューバー > File > Build Settings
- WebGLを選択 > Swich Platformボタン押下
- Player settingsボタン押下
- 設定変更
- Buildボタン押下
- ビルド中(結構時間かかる)
ビルド中
細かめメモ
- コーディングルールっぽいもの
- Hierarchyのオブジェクト名は、とりあえず頭大文字で統一
// 行動予定・行動結果
- 行動予定
- 記事投稿日は、随時更新
- 行動結果
- 30分行動した(1.5時間/20時間)
- 投稿日:2019-03-10T01:35:16+09:00
[Unity][ParticleSystem]3D座標を起点にuGUI上にパーティクルを発生・収束させる
サンプル動画
移動や連発にも対応してようやく納得いくものが出来た
— madoramu (@madoramu_f) 2019年3月8日
色々妥協してる部分もあるけど個人的には満足 pic.twitter.com/hWVOqxVhAw3Dアクションゲームなどで良くある、
「敵を攻撃したらパーティクルが発生して、UI上のゲージに向かって飛んでゲージが溜まる。」
というものを実装してみました。
(割と需要あると思っているのですが、どこにもサンプルが無かったので自作することに)サンプルプロジェクト
以下のGithubに上げてあります
https://github.com/madoramu/ParticleHorming
※サンプル動画は別プロジェクトの物なので、上記URLのプロジェクトは少し内容が異なります。環境
Unity2018.3
WindowsとAndroidで動作確認済み
重要:ScreenSpaceCamera設定のCanvasのみ対応しています実装方法
サンプルプロジェクトの中身を抜粋して説明していきます。
細かい部分などはプロジェクトを閲覧してください。メインカメラとUIカメラの用意・設定
メインカメラ
こちらはキャラクターの追尾、およびUI以外の描画を担当。
- CullingMaskで「UI」を除外する。
- Depthを「0」にする。
- UIカメラより低ければおk
UIカメラ
UIの描画のみ担当。
- メインカメラには絶対映らない場所に移動させる
- AudioListenerは外しておく
- ClearFlagsを「Depth Only」にする。
- CullingMaskで「UI」だけにする。
- Depthを「10」にする。
- メインカメラより高ければおk
上記二つのカメラ設定により、メインカメラの描画の後にUIレイヤーの情報が上に描画されます。
キャンバスの用意と設定(重要)
UI表示用・座標変換用で2つのScreenSpaceCamera設定Canvasを用意します。
- UI表示用にはUIカメラ、座標変換用にはメインカメラをそれぞれ設定する
- RectTransform以外のパラメーターは全て同じにする事
- 一応念のため
※何故設定カメラ以外同じパラメーターのCanvasを二つ使用したのかは感想に記載しています。
ParticleSystemの設定
ここは好みに合わせて弄って問題ありませんが、以下の2点は必須です。
- ParticleSystemオブジェクトのLayerは「必ず「UI」に設定する事」
- UI表示用のCanvas直下に配置する事
「何故World設定か?」
- 後述のパーティクル発生処理で解説しますが、ParticleSystemそのものを移動させるので、Localだとその移動にパーティクルも追従してしまうため。
「Rederer→Order in Layerについて」
- 上記画像には映っていませんが、今回はUIより前面に出したかったため値を増やしました。ここはお好みでおk。
パーティクル発生処理
ParticleSystem.Emitを使用して、意図的にパーティクルを発生させることが出来ます。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.Emit.html処理の流れ
- 3D座標からScreenSpaceCanvas上の2D座標に変換
- ゲームだと主に敵に攻撃が当たった時の、敵座標位置が3D座標になります。
- テラシュールブログを参考(というかほぼ丸パクリ)にして作成しました。
- 下記ページの「World Space を Screen Space Cameraへ」です。
- http://tsubakit1.hateblo.jp/entry/2016/03/01/020510
- 変換した2D座標にParticleSystemを移動
- Emitでパーティクル生成。
以下コード抜粋
ParticleHorming.cspublic void CreateParticle() { // 3D空間座標からカメラスクリーン上の座標に変換する Vector3 basePos = m_Emit3DTransformList.GetRandom().position; // GetRandom()についてはListExtensionsを参照 Vector2 screenPos = m_Camera.WorldToScreenPoint(basePos); // カメラスクリーン座標をキャンバス上のローカル座標に変換する Vector2 cameraCanvasPos = Vector2.zero; RectTransformUtility.ScreenPointToLocalPointInRectangle(m_RaycasterCameraCanvasRectTransform, screenPos, m_Camera, out cameraCanvasPos); // 座標確認 Debug.LogFormat("rectPos{0}", cameraCanvasPos); // ParticleSystemを放出位置に移動させてEmit m_ParticleSystem.transform.localPosition = cameraCanvasPos; m_ParticleSystem.Emit(m_EmitParticleCount); }パーティクル更新(収束)処理
普段パーティクルをスクリプト側で操作することは余り無いですが、今回は特定位置に収束させたかったのでググった結果、公式サイトで以下のページが出てきました。
https://docs.unity3d.com/ja/current/ScriptReference/ParticleSystem.GetParticles.htmlこのページを参考に以下の様な処理で更新させることにしました。
ParticleHorming.cs// 更新 for(int i = 0; i < m_ActiveParticleCount; ++i) { float rate = (1.0f - m_ParticleList[i].remainingLifetime / m_ParticleList[i].startLifetime); rate = Mathf.Pow(rate, m_ReactionDistance); // 指数関数を加えることにより、収束する勢いを変更できるようにしてる m_ParticleList[i].position = Vector3.Lerp(m_ParticleList[i].position, m_TargetTransform.position, rate); } m_ParticleSystem.SetParticles(m_ParticleList, m_ActiveParticleCount);今回は指数関数を使って、等速直線移動ではなく少しアレンジをしています。
ここに関しては書き方によって幾通りも表現が出来ると思います。感想
当初はScreenSpaceCameraのCanvas一つで解決できないか試行錯誤していましたが、キャラを追尾する = Canvasが移動する関係上、パーティクルが毎フレームぶれたり座標がおかしなことになったりした結果、今の形に落ち着きました。
冒頭でも言った通りScreenSpaceOverlay設定のCanvasには対応できないので、結構使いどころは限定的かも。
ですが、ParticleSystem上でパーティクルをいつも通り設定できるメリットは大きいので、個人的には満足度高めです。