-
스파르타) The Last Rollback (D-12, Node.js 게임 서버 최종 프로젝트) - DotRecast (2)TIL-sparta 2024. 8. 16. 00:40
> 프로젝트 진행 간 DotRecast 관련 학습 내용을 정리해보았다.학습 키워드: C#, .NET, Recast & Detour, DotRecast, DtNavMesh
1. Progress
1) DtNavMesh Loader 기능 추가:
이전 TIL에서는 Wavefront .obj 파일으로 변환하는 과정을 다뤘는데, 이번에는 이 obj 파일을 Detour가 사용할 DtNavMesh로 변환하는 과정을 학습했다. 거의 하루 종일 라이브러리 코드만 들여다 보다가 결국 Demo Scene에서 힌트를 얻어서 메쉬 로드에 성공했다.
이전에 언급했듯이 Demo Scene에 불러온 obj 파일은 Unity에서 이미 NavMesh로 생성된 파일을 변환한 mesh다. 그렇기 때문에 Recast를 통해 새로운 NavMesh를 생성할 경우 결과적으로 최종 NavMesh는 조정이 두 번 이루어진 형태가 되어 맵이 기존 의도했던 것 보다 좁아지는 현상이 생긴다. 마땅한 해결 방법이 떠오르지 않아서 workaround로 진행했는데, 우선 Unity에서 생성한 NavMesh를 최대한 깔끔하게 세팅하여 export하고, Recast의 config 값에서 agent radius를 0으로 설정하여 불러온 mesh와 최대한 동일한 형태로 NavMesh가 생성될 수 있도록 했다.
이렇게 만들어진 NavMesh는 좌측 메뉴의 하단에 있는 'Save NavMesh' 버튼을 눌러 '.NAVMESH' 확장자를 가진 파일로 저장할 수 있다. 이렇게 저장된 파일이 바로 DtNavMesh가 될 파일이다.
// RecastDemo.cs (DotRecast) ... private void LoadNavMesh(FileStream file, string filename) { try { DtNavMesh mesh = null; if (filename.EndsWith(".zip")) { UnityAStarPathfindingImporter importer = new UnityAStarPathfindingImporter(); mesh = importer.Load(file)[0]; } else { using var br = new BinaryReader(file); DtMeshSetReader reader = new DtMeshSetReader(); mesh = reader.Read(br, 6); } if (null != mesh) { _sample.Update(_sample.GetInputGeom(), ImmutableArray<RcBuilderResult>.Empty, mesh); _toolsetView.SetEnabled(true); } } catch (Exception e) { Logger.Error(e, ""); } }
DotRecast Demo의 RecastDemo 클래스에는 LoadNavMesh 라는 method가 존재한다. 이 중에서 실제로 필요한 else 부분만 떼어서 새로운 함수를 작성했다.
// NavMeshLoader.cs ... private const string ASSETS_REL_PATH_PREFIX = "./Assets/"; /// <summary> /// Loads NavMesh from Assets directory. /// </summary> /// <param name="filename">name of the navmesh file with extension included</param> /// <returns>DtNavMesh, or null if loading failed</returns> public static DtNavMesh? LoadNavMesh(string filename) { try { ArgumentNullException.ThrowIfNull(filename); FileStream fs = File.OpenRead(ASSETS_REL_PATH_PREFIX + filename); BinaryReader br = new (fs); DtMeshSetReader reader = new(); DtNavMesh navMesh = reader.Read(br, VERTS_PER_POLY); if (navMesh == null) { throw new InvalidOperationException("LoadNavMesh failed to read NavMesh."); } return navMesh; } catch (Exception e) { Console.WriteLine("LoadNavMesh Error: " + e.Message); return null; } } ...
.NAVMESH 파일을 읽을 준비가 완료됐다. 이제 프로그램 시작 시 이 함수를 호출해서 파일 이름을 넘겨주면 된다.
// Program.cs ... DtNavMesh? mesh = NavMeshLoader.LoadNavMesh(NavMeshConstants.DUNGEON_01_NAVMESH_FILENAME); if (mesh != null) { Console.WriteLine($"{NavMeshConstants.DUNGEON_01_NAVMESH_FILENAME} loaded succesfully."); Console.WriteLine("MaxTiles: " + mesh.GetMaxTiles()); Console.WriteLine("MaxVertsPerPoly: " + mesh.GetMaxVertsPerPoly()); } ...
이 짧은 코드를 알아내는데 정말 하루 종일 걸렸다. 불과 몇 시간 전까지 obj 파일을 다이렉트로 DtNavMesh로 변환할 방법이 없나 고민도 해보고 아예 IInputGeomProvider를 implement한 것 부터 출발하는 코드를 작성하고 있었는데, 라이브러리 코드를 여기저기 돌아다니다가 Demo Scene을 한 번 더 볼 생각을 하지 않았으면 일주일 내내 DtNavMesh 만드는 법만 찾고 있을 뻔 했다. 아무튼 이제 메쉬 로드도 완료했으니 다음은 Detour의 Crowd 관련 기능을 알아봐야겠다.
--
REFERENCES:> 프로젝트 repo
> Pathfinding Dedicated Server repo
> 이전 TIL (DotRecast 첫 사용)
728x90'TIL-sparta' 카테고리의 다른 글
스파르타) The Last Rollback (D-10, Node.js 게임 서버 최종 프로젝트) - DotRecast (4) (0) 2024.08.18 스파르타) The Last Rollback (D-11, Node.js 게임 서버 최종 프로젝트) - DotRecast (3) (0) 2024.08.16 스파르타) The Last Rollback (D-13, Node.js 게임 서버 최종 프로젝트) - DotRecast (0) 2024.08.14 스파르타) The Last Rollback (D-14, Node.js 게임 서버 최종 프로젝트) (0) 2024.08.13 [.NET] C# DotNet으로 TCP 소켓 서버 열어보기 (0) 2024.08.12