Unity Term Book
고급 기법

NavMesh

NavMesh(Navigation Mesh)는 씬 지오메트리에서 구운 이동 가능 메시로, AI Agent가 경로를 찾고 장애물을 피하며 자동 이동합니다. Bake·NavMeshAgent·NavMeshObstacle과 SetDestination 기초를 배우는 실전 가이드입니다.

상상해 보세요...

NavMesh는 3D 세계의 도로 지도입니다. 플레이 전에 Unity가 이동 가능 영역(파랑)과 막힌 곳(벽, 장애물)을 「칠」합니다. AI가 A에서 B로 가야 하면 그 지도를 보고 A-star로 최적 경로를 찾습니다——벽 주변, 계단 위, 절벽 회피. NavMeshAgent는 그 지도 위의 GPS 드라이버입니다.

개념 자세히

NavMesh Baking: Unity가 정적 씬 지오메트리 (“Navigation Static” 표시)를 이동 가능 메시로 분석합니다. 핵심 파라미터: Agent Radius(최소 벽 간격——에이전트는 반지름×2보다 좁은 틈을 통과 못 함), Agent Height(머리 높이——낮은 천장 아래 기어가기 불가), Max Slope (최대 경사), Step Height(최대 계단). Bake: Window → AI → Navigation → Bake.

NavMeshAgent는 NPC/AI에 붙어 NavMesh를 질의합니다. 주요 API: agent.SetDestination(target) 로 경로 탐색 시작; agent.remainingDistance 로 남은 거리; agent.pathStatus (Complete/Partial/Invalid). speed, acceleration, stoppingDistance 가 이동을 제어합니다.

NavMeshObstacle은 동적 차단물——재베이크 없음. Carve를 켜면 런타임에 NavMesh에 구멍을 깎습니다(CPU 더 씀). Carve를 끄면 회피만 (에이전트가 돌아가고 메시는 유지). 문 열기, 이동 차량에 적합합니다.

동적 NavMesh(런타임 재베이크)는 NavMesh Components package (Unity-Technologies, GitHub)의 NavMeshSurface 로 영역을 베이크하고 점진 갱신합니다. Unity 6는 다중 표면 NavMesh를 내장 패키지에 넣습니다.

NavMesh 시스템 구성

🗺️

NavMesh

씬 지오메트리에서 베이크한 이동 가능 메시. Static이며 베이크 후 변하지 않음.

Navigation Static flag
🤖

NavMeshAgent

AI용 컴포넌트 — 경로 조회, 자동 이동, 다른 에이전트 회피(avoidance).

SetDestination(target)
🚧

NavMeshObstacle

동적 장애물 — 재베이크 불필요. Carve 모드는 런타임에 NavMesh에 구멍을 뚫음.

Carve = true/false

실습 단계

1

정적 지오메트리 표시

정적 메시(벽, 바닥, 플랫폼) 선택 → Inspector → Static 드롭다운 → Navigation Static(라이트맵이 필요하면 Contribute GI도).

2

NavMesh Bake

Window → AI → Navigation → Bake 탭 → Agent Radius/Height/Slope 조정 → Bake. Scene 뷰에 파란 NavMesh가 나타납니다.

3

NPC에 NavMeshAgent 추가

Add Component → NavMeshAgent. Agent Size를 bake 설정에 맞춥니다. Rigidbody가 있으면 gravity를 끕니다(에이전트가 이동을 소유).

4

스크립트에서 Destination 설정

agent.SetDestination(target.position). agent.remainingDistance <= agent.stoppingDistance로 도착을 확인합니다.

5

이동 차단물에 NavMeshObstacle

Add Component → NavMeshObstacle → Shape: Capsule/Box → NavMesh를 실시간 갱신하려면 Carve 활성화(문, 주차 차량).

인터랙티브 시뮬레이터

지도를 클릭해 목적지를 설정——Agent가 NavMesh 위에서 A*로 경로를 찾습니다.

클릭하여 목적지 설정
NavMesh Agent Obstacle Path

코드 예제

기본

단순 NavMeshAgent AI——플레이어를 추격하고 stopping distance에서 정지.

using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
  public Transform player;
  public float chaseRange   = 15f;
  public float attackRange  = 2f;
  public float updateRate   = 0.2f; // Recompute path every 0.2s

  NavMeshAgent agent;
  Animator anim;
  float nextUpdate;

  void Awake()
  {
      agent = GetComponent<NavMeshAgent>();
      anim  = GetComponent<Animator>();
  }

  void Update()
  {
      float dist = Vector3.Distance(transform.position, player.position);

      if (dist < chaseRange && Time.time >= nextUpdate)
      {
          nextUpdate = Time.time + updateRate;
          agent.SetDestination(player.position);
      }

      // Drive Animator from agent speed
      anim.SetFloat("Speed", agent.velocity.magnitude);

      if (dist < attackRange)
      {
          agent.ResetPath(); // Stop moving
          anim.SetTrigger("Attack");
      }
  }
}

코드 예제

고급

NavMesh 순찰 AI——웨이포인트 루프와 플레이어 감지.

using UnityEngine;
using UnityEngine.AI;

public class PatrolAI : MonoBehaviour
{
  public Transform[] waypoints;
  public float detectRange = 8f;
  public Transform player;

  NavMeshAgent agent;
  int current = 0;
  enum State { Patrol, Chase, Investigate }
  State state = State.Patrol;

  void Awake() => agent = GetComponent<NavMeshAgent>();

  void Start() => GotoNextWaypoint();

  void Update()
  {
      float dist = Vector3.Distance(transform.position, player.position);

      switch (state)
      {
          case State.Patrol:
              if (dist < detectRange) { state = State.Chase; break; }
              if (!agent.pathPending && agent.remainingDistance < 0.5f)
                  GotoNextWaypoint();
              break;

          case State.Chase:
              agent.SetDestination(player.position);
              if (dist > detectRange * 1.5f)
                  state = State.Investigate;
              break;

          case State.Investigate:
              if (!agent.pathPending && agent.remainingDistance < 0.5f)
              { state = State.Patrol; GotoNextWaypoint(); }
              break;
      }
  }

  void GotoNextWaypoint()
  {
      if (waypoints.Length == 0) return;
      agent.SetDestination(waypoints[current].position);
      current = (current + 1) % waypoints.Length;
  }
}

📌 빠른 정리

  • ▸NavMesh = 정적 지오메트리에서 구운 이동 가능 지도
  • ▸매 프레임 SetDestination()은 비쌈——코루틴으로 스로틀
  • ▸remainingDistance: 남은 경로 길이
  • ▸NavMeshObstacle + Carve = 런타임 구멍
  • ▸NavMeshAgent 사용 시 Rigidbody.gravity 끄기

⚠️ 흔한 실수

  • ❌ SetDestination이 맞아도 Agent가 안 움직임

    목적지가 NavMesh 밖이거나 NavMesh를 베이크하지 않음

    ✅ NavMesh.SamplePosition()으로 메시 위 최근접점을 찾음

  • ❌ Agent가 벽을 통과하거나 끼임

    NavMeshAgent의 Agent Radius가 bake 반지름보다 작음

    ✅ NavMeshAgent Agent Radius를 bake Agent Radius에 맞춤