Game Engine/Unity

[Unity] Navigation - NavMesh, OffMeshLink

  • -

유니티에서 최단 거리를 탐색하여 추적할 수 있는 캐릭터를 생성하는데에 사용되는 Navigation에 대해 알아보자.

 

그 중, 이번 포스팅은 NavMesh 와 OffMeshLink를 중점적으로 알아보고자 한다.

 

 

개념

유니티Navigation 시스템을 사용하면 씬 내에서 지능적으로 탐색하여 이동할 수 있는 캐릭터를 만들 수 있다.

 

이때, 자동으로 씬에 생성되는 NavMesh는 Navigation Mesh의 줄임말로, 게임 월드에서 걸을 수 있는 표면을 뜻하며,

 

NavMesh를 사용하여 게임 월드 안의 한 위치에서 다른 위치로 이동할 수 있는 경로를 찾을 수 있다.

 

(출처 : https://docs.unity3d.com/kr/2020.3/Manual/nav-InnerWorkings.html)

 

NavMesh는 이 표면을 Convex 폴리곤으로 저장한다.

 

Convex 폴리곤은 폴리곤 안의 두 지점 사이에 아무런 장애물이 없기 때문에 이런한 목적으로 유용하게 사용된다.

 

폴리곤의 경계를 비롯하여 서로 이웃한 폴리곤에 대한 정보도 저장하며 걸을 수 있는 모든 영역을 탐색할 수 있다.

 

 

사용법

Navigation 시스템의 사용법부터 간단하게 알아보자.

 

 

먼저, Window - AI - Navigation을 눌러주면  Navigation 창이 하나 생긴다.

 

 

그 후, Navigation 창의 Object 탭에서 Scene Filter를 All로 해주고

 

Hierarchy 창에서 탐색에 사용할 맵 오브젝트를 모두 선택해준 후, Navigation Static을 체크해준다.

 

 

캐릭터가 이동 가능하게 할 오브젝트는 Navigation Area를 Walkable로 두고,

 

이동할 수 없게 할 오브젝트는 따로 선택 후 Not Walkable로 바꿔준다.

 

 

Bake 탭으로 넘어가서 Bake 버튼을 눌러주면, Scene 창에 하늘색으로 된 NavMesh가 자동으로 생성된다.

 

 

이동시킬 캐릭터에 NavMeshAgent 컴포넌트를 추가하고 이를 조종할 스크립트도 추가한다.

 

MyAgent 스크립트는 다음과 같다.

 

using UnityEngine;
using UnityEngine.AI;

public class MyAgent : MonoBehaviour
{
    NavMeshAgent nav;
    [SerializeField] Transform target;

    void Start()
    {
        nav = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
            nav.SetDestination(target.position);
    }
}

 

마우스 왼쪽 클릭시, Agent가 target 위치를 추적하게 하는 코드다.

 

Start나 Awake에서 NavMeshAgent 컴포넌트를 가져오고

 

SetDestination()으로 타겟 위치를 설정해주면 된다.

 

NavMeshAgent를 사용하려면 UnityEngine.AI 라이브러리를 불러와야 한다.

 

실행 결과는 다음과 같다.

 

 

NavMeshAgent에 대한 자세한 글은 Navigation에 대한 고찰 2편 에 마련되어 있다.

 

 

Scene 창을 보면 NavMesh가 잘 연결되어 있는 곳도 있지만, 사진과 같이 끊어져 있는 부분도 보인다.

 

이를 더욱 세부적으로 설정할 수 있게 여러 탭들이 하는 역할과, 속성값들을 알아보자.

 

 

Agents

 

각각의 타입에 따라 갈 수 있는 경로를 다르게 하기 위한 설정이지만,

 

사용시 "SetDestination" can only be called on an active agent that has been placed on a NavMesh 라는 에러가 발생한다.

 

해당 기능을 정상적으로 이용하기 위해서는 NavMeshSurface 컴포넌트를 이용해야하고,

 

해당 컴포넌트는 유니티 GitHub에서 따로 다운로드하여 설치해야한다.

 

더욱 자세한 사항은 유니티 공식 문서 참고

 

 

Areas

 

이름과 비용을 커스텀하여 구역별로 설정해두면, 비용이 적은 경로로 최단거리 탐색을 하게 된다.

 

, 같은 거리일 때 비용이 많은 구역보다 적은 구역으로 이동하게할 수 있다.

 

 

Areas 실험

 

타겟 위치를 다음과 같이 옮겨두고 실행했을 때, 캐릭터는 좌측 경로로 이동한다.

 

 

Areas 실험을 위해 출구 지점에 두 개의 타일을 설치해둔다.

 

캐릭터가 최단거리로 탐색했던 좌측 지점의 타일의 Navigation AreaJump로 바꿔준다.

 

이후 Jump의 비용을 5로 늘려주고 Bake한 후 실행해본다.

 

 

Jump 타일의 NavMesh가 붉게 변한 것을 볼 수 있고,

 

Agent는 Jump 타일의 비용을 고려하여 우측 경로를 선택하였다.

 

Bake

 

기본적인 Agent의 속성을 정하여 현재 맵에 NavMesh를 생성하여 굽는 작업이다.

 

1. Agent Radius

 

Agent의 반지름, 커질수록 Agent가 좁은 길을 갈 수 없다.

 

 

2. Agent Height

 

Agent의 높이, 커질수록 Agent가 높이가 낮은 지형을 지나다닐 수 없다.

 

 

3. Max Slope

 

Agent가 갈 수 있는 경사면 한계, 커질수록 더 가파른 곳을 갈 수 있다.

 

 

4. Step Height

 

Agent가 오를 수 있는 오브젝트의 높이, 커질수록 더 큰 폭의 높이를 오르내릴 수 있다.

 

 

Object         

     

씬에 존재하는 게임오브젝트의 Navigation 설정을 하는 부분이다.

 

Navigation Static으로 설정된 오브젝트에 한해서 NavMesh가 생성된다.

 

Generate OffMeshLinks로 점프, 드랍이 가능한 오브젝트를 설정한다.

 

Navigation Area 해당 오브젝트에 어떠한 Area를 부여할지 설정한다.

 

 

OffMeshLink

Agent가 일반적인 경로가 아닌 지형을 JumpDrop으로 이동할 수 있는 기능이다.

 

 

Jump나 Drop이 필요한 경로의 오브젝트를 선택 후, 

 

Navigation 창의 Object 탭에서 Generate OffMeshLinks를 체크한다.

 

이후 Bake 탭에서 Drop HeightJump Distance 속성값을 설정하고 Bake 한다.

 

 

1. Drop Height

 

Agent가 떨어질 수 있는 높이, 커질수록더 높은 곳에서 떨어질 수 있다.

 

Bake시, 시작점과 끝점에 원이 생성되고, 화살표가 그려지게 된다.

 

 

2. Jump Distance

 

Agent가 점프할 수 있는 거리, 커질수록 더 멀리 점프가 가능하다.

 

Bake시, 시작점과 끝점에 원이 생성되고, 화살표가 그려지게 된다.

 

 

3.  실험을 통한 이해

 

위와 같이 Jump를 하지 않으면 이동하지 못하는 경우는 Jump를 하여 이동하는 모습이다.

 

 

 

하지만, 구간이 이어져있을 경우는 다르다.

 

Jump 구간을 이용하면 더 빠르게 이동할 수 있지만, Agent는 일반적인 경로로 움직였다.

 

 

 

두 오브젝트를 더 가까이 붙여보았더니, Jump를 하는 모습을 볼 수 있다.

 

이로써 OffMeshLinks를 이용한 구간은 비용이 더 크다는 점을 알 수 있다.

 

자동으로 생성하는 OffMeshLinks는 비용을 따로 설정할 수 없지만,

 

수동으로 설정하게 되면 비용을 따로 설정이 가능하다.

 

 

4. 수동 Off Mesh Link

 

Navigation 창의 Object 탭에서 Generate OffMeshLinks를 체크 해제하고,

 

이동하고자 하는 곳의 시작 부분과 끝 부분에 오브젝트를 생성해준다.

 

단, 해당 오브젝트는 NavMesh 위에 존재해야 한다.

 

Renderer와 Collider는 비활성화 해도 무관하다.

 

 

새로운 GameObject(Empty 무관)를 생성하여 Start, End에 위에서 생성했던 오브젝트를 연결시켜주고 실행한다.

 

Cost Override 값이 양수이면, 경로 비용을 계산한다. 아래의 Navigation Area의 비용 Override
Bidirectional Start 지점과 End 지점을 양측에서 모두 이용할 것인지에 대한 여부
Activated 해당 OffMeshLink를 이용할 것인지에 대한 여부
Auto Update Positions End 지점이 이동하면 자동으로 NavMesh에 다시 연결할 것인지에 대한 여부
Navigation Area Areas 탭에서 설정했던 구역을 해당 OffMeshLink에 적용

 

 

좌측은 자동 생성 OffMeshLink 이고, 우측은 수동 생성 OffMeshLink 이다.

 

같은 거리지만 수동으로 생성시, 비용 설정이 가능하기 때문에 원하는 경로로 이동시킬 수 있다.

 

 

 

수동 OffMeshLink를 이용하면 아래에서 위로 올라갈 수도 있다.

 

 

참고 문헌

https://docs.unity3d.com/kr/2020.3/Manual/nav-InnerWorkings.html
https://docs.unity3d.com/kr/2021.3/Manual/nav-NavigationSystem.html
https://docs.unity3d.com/kr/2021.3/Manual/nav-BuildingNavMesh.html
https://docs.unity3d.com/Manual/class-OffMeshLink.html
https://www.youtube.com/watch?v=gLSPJattS64 
https://www.youtube.com/watch?v=LezP4pzylIg&t=132s 
https://www.youtube.com/watch?v=YoYtIMT380E&t=4s 

 

 

개인 공부용 포스팅인 점을 참고하시고, 잘못된 부분이 있다면 댓글로 남겨주시면 감사드리겠습니다.

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.