お世話になってます。
ナビメッシュを利用して以下のような判定を行ないたいと考えております。
・2点の座標がそれぞれナビメッシュ上にある(指定座標の真下にナビメッシュがある)
・2点間のパスが直線である(パスが指定の2点のみで構成されている)
現在は、UNavigationSystem::FindPathToLocationSynchronously()を使用して判定していますが
指定した座標がナビメッシュ上に無い場合でも、ナビ上の近しい座標に変換され判定されてしまいます。
またパスが直線かどうかは、UNavigationPathの【PathPoints.Num() == 2】と【false == IsPartial()】の複合条件で判定しています。
正確に、指定した座標の真下でナビメッシュのパス検索を行なう方法があればご教授ください。
お世話になっております。
UNavigationSystem::FindPathToLocationSynchronously()を使用して判定していますが指定した座標がナビメッシュ上に無い場合でも、ナビ上の近しい座標に変換され判定されてしまいます。
現状この動作は仕様となります。まず歩行不可能(パスが存在しない)場合はそもそもパス検索に失敗します。A*検索では可能な限りパスを見つけようとしますが、検索の開始位置と終了位置が完全に投射された位置でない場合はIsPartial=trueとなり部分的なパスを形成します。ですので、【false == IsPartial()】が成立するのは「不完全なパスでない場合」であり「直線パスが形成されているか」とは限りません。おそらく上記で述べられているのはこの状況かと推測しています。
正確に指定座標の真下でパス検索を行う場合は、Navmeshの位置を投射して検索する上で不完全となる要因となるオブジェクトを除外することで、正しくパス検索可能になるかと思います。以下の図の場合は、ArrowComponentを持つActorで2点間のパス(白色線がパスのDrawDebug)を形成する例ですが、StaticMeshがパス検索を阻害しているので、StaticMeshのCanEverAffectNavigationをoffに設定することで直線を維持する例です。
ご返答ありがとうございます。
必要な機能としては、AIなどのルート検索用途では無く
A点とB点がともに地面があり(ナビ上に存在し)なおかつA点とB点の間に障害物が無い(パスが2点のみで繋がる)という判定を行う目的となります。
上記の判定を行なうために有効な関数がありましたらC++コードで構いませんのでご教授いただきたいです。
ご提案いただいた方法で、1点問題がありました。
ナビメッシュが上下に在る場合、ナビメッシュ自体は繋がって居なくてもRaycast=false(遮蔽されていない)判定が返ってきてしまいます。
横に並んでいる繋がっていないナビメッシュの場合はRaycast=true(遮蔽されている)判定が返ってきておりこちらは正常動作のように思えます。
Raycastチェックを行なった際に、ナビメッシュが繋がっていなければ必ず遮蔽されている判定が取れるようにしたいのですが、どうすればよいでしょうか?
要求を正しく把握できておらず失礼しました。
・2点の座標がそれぞれナビメッシュ上にある(指定座標の真下にナビメッシュがある)
UNavigationSystem::K2_ProjectPointToNavigation
もしくは
UNavigationSystem::ProjectPointToNavigation
を利用する方法はいかがでしょうか。開始地点や終了地点を入力(FVector& Point)として与えることで、投射した地点にナビメッシュ上に存在するかをboolで取得できます。
・2点間のパスが直線である(パスが指定の2点のみで構成されている)
UNavigationSystemV1::NavigationRaycast
を利用する方法はいかがでしょうか。開始地点と終了地点を入力(FVector& RayStart, FVector& RayEnd)として与えることで、障害物などで遮蔽されている場合は結果としてtrue、遮蔽されていない場合はfalseが取得できるかと思います。
FindPathToLocationSynchronouslyは障害物が無い場合においてもNavmesh上のコストの割り当て方によってはPathPointが3点以上になるケースがあるため、2点で直線かどうかを判定することが出来ないということから上記をご提案させて頂きました。もしご要望のものと相違がありましたらご連絡下さい。
よろしくお願いします。
ご返答ありがとうございます。
ご提案いただいた方法で目的の情報が得られることが確認できました。
UNavigationSystem::NavigationRaycast
で実行されるトレースには2D上でのみトレースを実行するという使用上での制限(詳細は dtNavMeshQuery::raycast
を参照下さい)がありますので、NavigationRaycastと併せて UNavigationSystem::FindPathToLocationSynchronously
で取得できるNavigationPathのIsPartialをチェックすると期待する結果が得られるかと思います。
まとめますと、 UNavigationSystem::NavigationRaycast
のReturnがfalseでかつ、 UNavigationSystem::FindPathToLocationSynchronously
のReturnのNavigationPathがfalseの場合に、障害物を挟まない完全なパスが取得できるはずです。
ご返答ありがとうございます。
ご提案いただいた方法を試してみたいと思います。
若干、処理負荷がどの程度か気になります。
対象の間をShpereTraceで障害物判定する方法と比較してどちらが高速か、もしご存知でしたらお教え頂けると幸いです。
高低差を考慮するためのチェック処理としてFindPathToLocationSynchronouslyとSphereTraceByChannelを比較する限りではSphereTraceByChannelの方がFindPathToLocationSynchronouslyと比較して約2倍ほど早い結果となることを確認しました。これは単に1フレーム中にそれぞれを100回実行したものの処理速度を計測したもので、計測条件(TraceのRadiusのサイズなど)によって変わりますので最終的にどちらを採用頂くかは実際にプロジェクトで計測頂くのが宜しいかと思いますが、いずれの処理も決してCPU処理が高速なものではないのではないため、毎フレーム実行するようなことは避けてご利用頂く必要があるかと思います。
検証までして頂きありがとうございます。
参考にさせて頂きます。