テラシュールブログ

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

【Unity】NavMeshのRaycastを非同期で撃つ!

http://cdn-ak.f.st-hatena.com/images/fotolife/t/tsubaki_t1/20150925/20150925014548.png

Unity 2018.3からNavMeshのRaycastを非同期で実行することが出来るようになったので、その方法についてです。
なおExperimentalなAPIを使用するので、今後変わるかもしれません。

NavMeshQuery経由で非同期でRaycastを実行

NavMeshの経路探索はNavMeshAgent経由ならば非同期で扱えるのですが、NavMeshAgent無しだと非同期で扱えません。 対してNavMeshQueryを利用したNavMeshに対する操作は、NavMeshAgentほど簡単には扱えませんが、非同期で使用することが出来ます。

そのNavMeshQueryでもRayCastを使用できるようになりました。これはNavMeshQueryを利用したNavMeshAgent自作より手軽に使えるので、覚えておいて損はないかなという感じです。

NavMeshのRayCastについてはこちら。主な用途としては「単純なNPCの視界判定」とかでしょうか。

tsubakit1.hateblo.jp

使ってみる

最も単純な使い方についてです。

最初に事前準備です。NavMeshWorld.GetDefaultWorld();でNavMeshの情報を取得します。確認していませんが、多分、NavMesh再構築したら再度取得しなきゃいけない系のやつです。次にNavMeshQuery query = new NavMeshQuery(world, Unity.Collections.Allocator.Persistent);でqueryの取得です。今回はパス検索しないので使い回すことにしていますが、本当はキャラクターや群体の単位で1queryくらいの扱いになりそうです。

次にLocationを取得します。キャラクターの開始座標はVector3ではなくNavMesh上の座標であるLocationを使用します。こちらも使い回す事も出来ますが、最初は使い捨てです。

あとはRayCastを実行するだけです。

gist.github.com

実行すると、以下の通り。間に障害物があってパスが通らなければTrue、何もなければFalseです。ただしNavMesh外といったパスが通らない場所からスタートした場合もFalseになります。query.Raycast戻り値のPathQueryStatusがSuccessかどうかは確認しといたほうが良いです。

f:id:tsubaki_t1:20181111224009j:plain

f:id:tsubaki_t1:20181111224019j:plain

f:id:tsubaki_t1:20181111224029j:plain

RaycastというよりはLinecastが近いですね

非同期で動かそう!

今度はコレを非同期で動かします。
NavMeshQueryが実行する処理は殆どジョブ上で動作させることが出来るので、やることは上で書いたようなコードをC# Job Systemに移すだけです。

結果は下のような感じになります。メインスレッドの仕事はジョブを発行するまでで、その他の仕事は別スレッドへ移行します。ついでにログの表示もジョブでやらせてるので、本当に殆ど処理時間がなくなっています。

f:id:tsubaki_t1:20181111231034j:plain

gist.github.com

結果をメインスレッドで扱いたい場合は、handle.Complete()と次のジョブを開始する間に処理を記述します。例えばUIに結果を格納したい場合は、下のような感じになります。要するにhandle.Complete()からjob.Schedule(handle)までがメインスレッドからパラメーターにアクセスしても良い時間です。
メインで行う処理が多岐に渡る場合、データを一旦コピーして即スレッド開始という手段も考慮に入れても良いかもしれません。

f:id:tsubaki_t1:20181111233130j:plain f:id:tsubaki_t1:20181111232908g:plain

関連

tsubakit1.hateblo.jp

tsubakit1.hateblo.jp