Skip to content

Commit

Permalink
feat: split NavMesh into multiple classes, update helpers (#24)
Browse files Browse the repository at this point in the history
  • Loading branch information
isaac-mason committed May 2, 2023
1 parent c1e1d38 commit 87e768b
Show file tree
Hide file tree
Showing 41 changed files with 2,395 additions and 1,272 deletions.
43 changes: 43 additions & 0 deletions .changeset/rude-schools-marry.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
---
'@recast-navigation/core': patch
'@recast-navigation/three': patch
'@recast-navigation/wasm': patch
---

feat: split NavMesh into multiple classes, update helpers

### New Core Classes

Functionality in the `NavMesh` class has been split into multiple classes that more closely mirror the recastnavigation api.
- `TileCache`
- Manages tiles and obstacles. Only used for tiled navmeshes.
- `NavMeshQuery`
- Provides methods for querying a navmesh.
- `NavMeshExporter`
- Methods for exporting a navmesh to a Uint8Array.
- `NavMeshImporter`
- Methods for importing a navmesh from a Uint8Array.
- `NavMeshGenerator`
- Methods for generating solo and tiled navmeshes.

### Changes to three.js utils and helpers

The usage for `threeToNavMesh` has changed slightly to include the TileCache when generating a tiled navmesh.

```ts
/* solo navmesh */
const { navMesh } = threeToNavMesh(meshes);

/* tiled navmesh */
const { navMesh, tileCache } = threeToNavMesh(meshes, { tileSize: 16 });
```

The `threeToNavMeshArgs` function has been renamed to `getPositionsAndIndices`.

The helpers have also been updated to align with the new core classes:
- `TileCacheHelper`
- New helper for visualising obstacles in a `TileCache`
- `NavMeshHelper`
- `updateObstacles` has been moved to `TileCacheHelper`
- `CrowdHelper`
- `update` has been renamed to `updateAgents`, following the naming convention of the other helpers
6 changes: 3 additions & 3 deletions apps/navmesh-website/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Environment, OrbitControls, useGLTF } from '@react-three/drei';
import { Canvas } from '@react-three/fiber';
import { button, Leva, useControls } from 'leva';
import { Suspense, useEffect, useState } from 'react';
import { Suspense, useState } from 'react';
import { NavMeshHelper, threeToNavMesh } from 'recast-navigation/three';
import styled from 'styled-components';
import { DoubleSide, Group, Mesh, MeshBasicMaterial, MeshStandardMaterial } from 'three';
import { Group, Mesh, MeshBasicMaterial } from 'three';
import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader';
import dungeonGltfUrl from './assets/dungeon.gltf?url';
import { DropZone } from './components/drop-zone';
Expand Down Expand Up @@ -113,7 +113,7 @@ const App = () => {
}
});

const navMesh = threeToNavMesh(meshes, navMeshConfig);
const { navMesh } = threeToNavMesh(meshes, navMeshConfig);

const navMeshHelper = new NavMeshHelper({
navMesh,
Expand Down
8 changes: 5 additions & 3 deletions examples/node-cjs-recast-navigation-example/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Promise.all([
Recast.init().then(() => {
console.log(RecastThree);

const navMesh = new Recast.NavMesh();
const navMeshGenerator = new Recast.NavMeshGenerator();

const groundMesh = new THREE.Mesh(new THREE.BoxGeometry(5, 0.5, 5));

Expand Down Expand Up @@ -35,9 +35,11 @@ Promise.all([
const positions = groundMesh.geometry.attributes.position.array;
const indices = groundMesh.geometry.index.array;

navMesh.build(positions, indices, config);
const { navMesh } = navMeshGenerator.generate(positions, indices, config);

const closestPoint = navMesh.getClosestPoint({ x: 2, y: 1, z: 2 });
const navMeshQuery = new Recast.NavMeshQuery({ navMesh });

const closestPoint = navMeshQuery.getClosestPoint({ x: 2, y: 1, z: 2 });

console.log(closestPoint.x, closestPoint.y, closestPoint.z);
});
Expand Down
12 changes: 7 additions & 5 deletions examples/node-esm-recast-navigation-example/src/index.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { init, NavMesh } from 'recast-navigation';
import { init, NavMeshGenerator, NavMeshQuery } from 'recast-navigation';
import * as RecastThree from 'recast-navigation/three';
import { BoxGeometry, Mesh } from 'three';

await init();

console.log(RecastThree)
console.log(RecastThree);

const navMesh = new NavMesh();
const navMeshGenerator = new NavMeshGenerator();

const groundMesh = new Mesh(new BoxGeometry(5, 0.5, 5));

Expand Down Expand Up @@ -34,8 +34,10 @@ const config = {
const positions = groundMesh.geometry.attributes.position.array;
const indices = groundMesh.geometry.index.array;

navMesh.build(positions, indices, config);
const { navMesh } = navMeshGenerator.generate(positions, indices, config);

const closestPoint = navMesh.getClosestPoint({ x: 2, y: 1, z: 2 });
const navMeshQuery = new NavMeshQuery({ navMesh });

const closestPoint = navMeshQuery.getClosestPoint({ x: 2, y: 1, z: 2 });

console.log(closestPoint.x, closestPoint.y, closestPoint.z);
18 changes: 8 additions & 10 deletions examples/vite-recast-navigation-three-example/src/app.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Environment, OrbitControls } from '@react-three/drei';
import { Canvas, useThree } from '@react-three/fiber';
import { useEffect, useRef } from 'react';
import { init, NavMesh } from 'recast-navigation';
import { NavMeshHelper, threeToNavMeshArgs } from 'recast-navigation/three';
import { init, NavMeshQuery } from 'recast-navigation';
import { NavMeshHelper, threeToNavMesh } from 'recast-navigation/three';
import { suspend } from 'suspend-react';
import { Color, Group, Mesh, MeshBasicMaterial, Vector2, Vector3 } from 'three';
import { Line2, LineGeometry, LineMaterial } from 'three-stdlib';
Expand All @@ -21,11 +21,7 @@ const App = () => {
}
});

const navMeshArgs = threeToNavMeshArgs(meshes);

const navMesh = new NavMesh();

navMesh.build(...navMeshArgs, {
const { navMesh } = threeToNavMesh(meshes, {
cs: 0.2,
ch: 0.2,
walkableSlopeAngle: 35,
Expand All @@ -41,6 +37,8 @@ const App = () => {
detailSampleMaxError: 1,
});

const navMeshQuery = new NavMeshQuery({ navMesh });

const debug = new NavMeshHelper({
navMesh,
navMeshMaterial: new MeshBasicMaterial({
Expand All @@ -51,9 +49,9 @@ const App = () => {

scene.add(debug.navMesh);

const path = navMesh.computePath(
navMesh.getClosestPoint(new Vector3(2, 1, 2)),
navMesh.getClosestPoint(new Vector3(-2, 1, -2))
const path = navMeshQuery.computePath(
navMeshQuery.getClosestPoint(new Vector3(2, 1, 2)),
navMeshQuery.getClosestPoint(new Vector3(-2, 1, -2))
);
console.log(path);

Expand Down
21 changes: 7 additions & 14 deletions packages/recast-navigation-core/src/crowd.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type R from '@recast-navigation/wasm';
import type { NavMesh } from './nav-mesh';
import { Raw } from './raw';
import type { NavPath, Vector3 } from './utils';
import { navPath, vec3 } from './utils';
import { Wasm } from './wasm';

export type CrowdParams = {
/**
Expand Down Expand Up @@ -143,11 +143,7 @@ export class Crowd {

constructor({ maxAgents, maxAgentRadius, navMesh }: CrowdParams) {
this.navMesh = navMesh;
this.raw = new Raw.Recast.Crowd(
maxAgents,
maxAgentRadius,
navMesh.raw.getNavMesh()
);
this.raw = new Wasm.Recast.Crowd(maxAgents, maxAgentRadius, navMesh.raw);
}

/**
Expand All @@ -162,7 +158,7 @@ export class Crowd {
...crowdAgentParams,
} as Required<CrowdAgentParams>;

const dtCrowdAgentParams = new Raw.Recast.dtCrowdAgentParams();
const dtCrowdAgentParams = new Wasm.Recast.dtCrowdAgentParams();
dtCrowdAgentParams.radius = params.radius;
dtCrowdAgentParams.height = params.height;
dtCrowdAgentParams.maxAcceleration = params.maxAcceleration;
Expand All @@ -188,9 +184,9 @@ export class Crowd {
removeAgent(agentIndex: number) {
this.raw.removeAgent(agentIndex);

const i = this.agents.indexOf(agentIndex);
if (i > -1) {
this.agents.splice(i, 1);
const index = this.agents.indexOf(agentIndex);
if (index !== -1) {
this.agents.splice(index, 1);
}
}

Expand Down Expand Up @@ -219,9 +215,6 @@ export class Crowd {
* Updates the crowd
*/
update(deltaTime: number) {
// update navmesh obstacles
this.navMesh.update();

if (deltaTime <= Epsilon) {
return;
}
Expand Down Expand Up @@ -353,7 +346,7 @@ export class Crowd {
...crowdAgentParams,
} as CrowdAgentParams;

const dtCrowdAgentParams = new Raw.Recast.dtCrowdAgentParams();
const dtCrowdAgentParams = new Wasm.Recast.dtCrowdAgentParams();

dtCrowdAgentParams.radius = params.radius;
dtCrowdAgentParams.height = params.height;
Expand Down
8 changes: 7 additions & 1 deletion packages/recast-navigation-core/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
export * from './crowd';
export * from './debug-nav-mesh';
export * from './nav-mesh';
export * from './nav-mesh-builder';
export * from './nav-mesh-exporter';
export * from './nav-mesh-generator';
export * from './nav-mesh-importer';
export * from './nav-mesh-query';
export * from './obstacle';
export * from './raw';
export * from './tile-cache';
export * from './utils';
export * from './wasm';
95 changes: 95 additions & 0 deletions packages/recast-navigation-core/src/nav-mesh-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import type R from '@recast-navigation/wasm';
import { Wasm } from './wasm';

export type NavMeshCreateParams = {
verts: number[];
vertCount: number;
polys: number[];
polyFlags: number[];
polyAreas: number[];
polyCount: number;
nvp: number;
detailMeshes: number[];
detailVerts: number[];
detailVertsCount: number;
detailTris: number[];
detailTriCount: number;
offMeshConVerts: number[];
offMeshConRad: number[];
offMeshConFlags: number[];
offMeshConAreas: number[];
offMeshConDir: number[];
offMeshConUserID: number[];
offMeshConCount: number;
userId: number;
tileX: number;
tileY: number;
tileLayer: number;
bmin: number[];
bmax: number[];
walkableHeight: number;
walkableRadius: number;
walkableClimb: number;
cs: number;
ch: number;
buildBvTree: boolean;
};

export type CreateNavMeshDataResult = {
success: boolean;
navMeshData: readonly number[];
navMeshDataSize: number;
};

export class NavMeshBuilder {
raw: R.NavMeshBuilder;

constructor() {
this.raw = new Wasm.Recast.NavMeshBuilder();
}

createNavMeshData(params: NavMeshCreateParams): CreateNavMeshDataResult {
const navMeshCreateParams = new Wasm.Recast.NavMeshCreateParams();

navMeshCreateParams.setVerts(params.verts);
navMeshCreateParams.setVertCount(params.vertCount);
navMeshCreateParams.setPolys(params.polys);
navMeshCreateParams.setPolyFlags(params.polyFlags);
navMeshCreateParams.setPolyAreas(params.polyAreas);
navMeshCreateParams.setPolyCount(params.polyCount);
navMeshCreateParams.setNvp(params.nvp);
navMeshCreateParams.setDetailMeshes(params.detailMeshes);
navMeshCreateParams.setDetailVerts(params.detailVerts);
navMeshCreateParams.setDetailVertsCount(params.detailVertsCount);
navMeshCreateParams.setDetailTris(params.detailTris);
navMeshCreateParams.setDetailTriCount(params.detailTriCount);
navMeshCreateParams.setOffMeshConVerts(params.offMeshConVerts);
navMeshCreateParams.setOffMeshConRad(params.offMeshConRad);
navMeshCreateParams.setOffMeshConFlags(params.offMeshConFlags);
navMeshCreateParams.setOffMeshConAreas(params.offMeshConAreas);
navMeshCreateParams.setOffMeshConDir(params.offMeshConDir);
navMeshCreateParams.setOffMeshConUserID(params.offMeshConUserID);
navMeshCreateParams.setOffMeshConCount(params.offMeshConCount);
navMeshCreateParams.setUserId(params.userId);
navMeshCreateParams.setTileX(params.tileX);
navMeshCreateParams.setTileY(params.tileY);
navMeshCreateParams.setTileLayer(params.tileLayer);
navMeshCreateParams.setBmin(params.bmin);
navMeshCreateParams.setBmax(params.bmax);
navMeshCreateParams.setWalkableHeight(params.walkableHeight);
navMeshCreateParams.setWalkableRadius(params.walkableRadius);
navMeshCreateParams.setWalkableClimb(params.walkableClimb);
navMeshCreateParams.setCs(params.cs);
navMeshCreateParams.setCh(params.ch);
navMeshCreateParams.setBuildBvTree(params.buildBvTree);

const { success, navMeshData, navMeshDataSize } =
this.raw.createNavMeshData(navMeshCreateParams);

return {
success,
navMeshData,
navMeshDataSize,
};
}
}
32 changes: 32 additions & 0 deletions packages/recast-navigation-core/src/nav-mesh-exporter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type R from '@recast-navigation/wasm';
import { NavMesh } from './nav-mesh';
import { TileCache } from './tile-cache';
import { Wasm } from './wasm';

export class NavMeshExporter {
raw: R.NavMeshExporter;

constructor() {
this.raw = new Wasm.Recast.NavMeshExporter();
}

/**
* Returns a NavMesh export that can be used later. The NavMesh must be built before retrieving the data
* @returns data the Uint8Array that can be saved and reused
*/
export(navMesh: NavMesh, tileCache?: TileCache): Uint8Array {
const navMeshExport = this.raw.exportNavMesh(navMesh.raw, tileCache?.raw!);

const arrView = new Uint8Array(
Wasm.Recast.HEAPU8.buffer,
navMeshExport.dataPointer,
navMeshExport.size
);

const data = new Uint8Array(navMeshExport.size);
data.set(arrView);
this.raw.freeNavMeshExport(navMeshExport);

return data;
}
}

0 comments on commit 87e768b

Please sign in to comment.