Three.js - 모듈을 이용한 길찾기

·2023년 5월 29일
0

Three.js

목록 보기
8/8

three-Pathfinding

캡스톤을 진행하다가(물론 지금은 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관(갈색건물)과 가장 가까운 지점을 이은 경로가 나타난다.

profile
백엔드 호소인

0개의 댓글