캡스톤을 진행하다가(물론 지금은 Unity로 작업 엔진을 바꾸었으나...)
현재 캐릭터의 위치에서 특정 건물까지의 경로를 표시해주는 기능이 필요했다.
그러다 발견한 것이 three-pathfinding 모듈
해당 영상에서는 raycast를 이용해 클릭한 좌표에 대한 길찾기를 했지만,
나같은 경우는 메타버스 개발을 하고 있었으므로, 특정 모델의 위치까지의 경로를 찾아야했다.
따라서 이 글에는 특정 모델의 위치까지의 경로를 찾는 법을 회고한다.
https://github.com/donmccurdy/three-pathfinding
모듈 깃허브는 다음과 같음
위에 보는 것 처럼 플레이어가 이동 가능한 구역을 나타내는 navmesh를 굽고(위 사진에서 연보라인 부분이 navmesh이다), navmesh에서 특정 위치에서 가장 가까운 노드의 경로를 나타내는 식이다.
npm install --save three-pathfinding
모듈을 우선 설치하고, navmesh를 구워야한다.
navmesh의 경우, 유니티에서 navmesh를 구워 외부 패키지로 이를 obj로 바꾸는 방법을 시도해보았으나, 모듈에서 잘 인식하지 않았다.
최근 블렌더에는 navmesh등을 굽는 걸 도와주는 게임엔진(?) 기능이 없다.
대신, 블렌더의 기능은 유지한채 일부 게임엔진에서 구현할 수 있는 기능이 추가된 UPBGE를 사용하면 된다!
UPBGE를 통해 navmesh를 굽는 법은 다음 영상을 참고하자.
길을 찾기 위해서는 다음과 같은 변수들이 필요하므로, 미리 추가하자.
const pathfinding = new Pathfinding();
const pathfindinghelper = new PathfindingHelper();
scene.add(pathfindinghelper);
const ZONE = 'campus'; //이 부분은 무엇으로 하던 상관이 없다.
let navmesh;
let groupID;
let navpath;
let target;
let targetName;
let agentpos;
그 다음, 구운 navmesh를 glb로 뽑아 프로젝트에 불러와주자.
navmesh는 길을 찾는데만 이용하므로, scene에는 추가하지 않는다.
function InitPathFinding(){
gltfLoader.load(
'/models/nav.glb',
gltf=>{
//scene.add(gltf.scene);
gltf.scene.traverse((node) => {
if (!navmesh && node.isObject3D && node.children && node.children.length > 0) {
navmesh = node.children[0];
pathfinding.setZoneData(ZONE, Pathfinding.createZone(navmesh.geometry));
}
});
});
}
그 다음, 플레이어가 찾고자 하는 모델(건물)의 위치를 getObjectByName을 이용해 받아온다.
agentPos의 경우 플레이어 캐릭터의 포지션을 받아오면 된다.
나의 경우는 플레이어 캐릭터를 characterControl으로 객체화 시켰다.
function FindNav(){
target = scene.getObjectByName(targetName).position;
agentpos = characterControls.model.position;
groupID = pathfinding.getGroup(ZONE, agentpos);
// find closest node to agent, just in case agent is out of bounds
const closest1 = pathfinding.getClosestNode(agentpos, ZONE, groupID);//navmesh에서 target위치와 가장 가까운 노드
const closest2 = pathfinding.getClosestNode(target,ZONE,groupID);//navmesh에서 건물 위치와 가장 가까운 노드
navpath = pathfinding.findPath(closest1.centroid, closest2.centroid, ZONE, groupID);
if (navpath) {
// console.log(`navpath: ${JSON.stringify(navpath)}`);
pathfindinghelper.reset();
pathfindinghelper.setPlayerPosition(agentpos);
pathfindinghelper.setTargetPosition(target);
pathfindinghelper.setPath(navpath);
}}
그 다음, GUI를 이용해 찾고자 하는 건물명을 입력받았다.(우측 위)
//GUI는 미리 라이브러리를 import해와야함!
const params = {
textField: "찾을 건물을 입력하세요"
}
const gui = new dat.GUI();
gui.add(params, "textField").onFinishChange(function (value) {
targetName=value;
FindNav(value);//getObjectByName(value)
});
그러면 다음과 같이 플레이어 위치와 navmesh에서 609관(갈색건물)과 가장 가까운 지점을 이은 경로가 나타난다.