mesh.js
主要流程
- 在websocket建立连接成功后,将烘焙的
navmesh
数据发送至服务器 - 服务器在收到数据后直接返回(模拟通信过程,实际上服务器也可以从文件读取然后返回给前端)
- 前端接收到数据后通过
importNavMesh
接口初始化新的navmesh
- 使用
threejs
重新绘制新的navmesh
import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';
import {
init as initRecastNavigation,
NavMeshQuery,
} from '@recast-navigation/core';
import { generateSoloNavMesh } from '@recast-navigation/generators';
import {
DebugDrawer,
getPositionsAndIndices,
} from '@recast-navigation/three';
import { exportNavMesh, importNavMesh } from '@recast-navigation/core';
await initRecastNavigation();
var ws = new WebSocket("ws://127.0.0.1:8080/ws");
ws.binaryType = "arraybuffer";
ws.onopen = function () {
console.log("websocket connected.");
meshInit();
};
ws.onmessage = function (e) {
console.log("websockt data:", e);
var uint8_msg = new Uint8Array(e.data);
meshDraw(uint8_msg);
};
ws.onerror = function () {
console.log("websocket error.");
};
const renderer = new THREE.WebGLRenderer();
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera();
camera.position.set(10, 10, -10);
const orbitControls = new OrbitControls(camera, renderer.domElement);
const ground = new THREE.Mesh(
new THREE.BoxGeometry(10, 1, 10),
new THREE.MeshBasicMaterial({ color: '#333' })
);
ground.position.set(0, -0.5, 0);
scene.add(ground);
const boxOne = new THREE.Mesh(
new THREE.BoxGeometry(8, 2, 1),
new THREE.MeshBasicMaterial({ color: '#555' })
);
boxOne.rotation.y = Math.PI / 4;
boxOne.position.set(-2, 1, 0);
scene.add(boxOne);
const boxTwo = new THREE.Mesh(
new THREE.BoxGeometry(8, 2, 1),
new THREE.MeshBasicMaterial({ color: '#555' })
);
boxTwo.rotation.y = Math.PI / 4;
boxTwo.position.set(2, 1, 0);
scene.add(boxTwo);
const [positions, indices] = getPositionsAndIndices([
ground,
boxOne,
boxTwo,
]);
const cs = 0.05;
const ch = 0.05;
const walkableRadius = 0.2;
const { success, navMesh } = generateSoloNavMesh(positions, indices, {
cs,
ch,
walkableRadius: Math.round(walkableRadius / ch),
});
const debugDrawer = new DebugDrawer();
debugDrawer.drawNavMesh(navMesh);
scene.add(debugDrawer);
const start = { x: -4, y: 0, z: -4 };
const end = { x: 4, y: 0, z: 4 };
const navMeshQuery = new NavMeshQuery(navMesh);
const { path } = navMeshQuery.computePath(start, end);
const startMarker = new THREE.Mesh(
new THREE.BoxGeometry(0.1, 0.1, 0.1),
new THREE.MeshBasicMaterial({ color: 'blue' })
);
startMarker.position.set(start.x, start.y + 0.1, start.z);
scene.add(startMarker);
const endMarker = new THREE.Mesh(
new THREE.BoxGeometry(0.1, 0.1, 0.1),
new THREE.MeshBasicMaterial({ color: 'green' })
);
endMarker.position.set(end.x, end.y + 0.1, end.z);
scene.add(endMarker);
const line = new THREE.Line(
new THREE.BufferGeometry().setFromPoints(
path.map(({ x, y, z }) => new THREE.Vector3(x, y, z))
),
new THREE.LineBasicMaterial({ color: 'blue' })
);
line.position.y += 0.1;
scene.add(line);
const onWindowResize = () => {
debugDrawer.resize(window.innerWidth, window.innerHeight);
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
};
onWindowResize();
window.addEventListener('resize', onWindowResize);
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
function meshInit() {
const navMeshExport = exportNavMesh(navMesh);
ws.send(navMeshExport);
}
function meshDraw(bin) {
const tmpNavMesh = importNavMesh(bin);
const tmpDebugDrawer = new DebugDrawer();
tmpDebugDrawer.drawNavMesh(tmpNavMesh.navMesh);
tmpDebugDrawer.position.z += 10;
scene.add(tmpDebugDrawer);
}