recastJSPlugin.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  1. import { INavigationEnginePlugin, ICrowd, IAgentParameters, INavMeshParameters } from "../../Navigation/INavigationEngine";
  2. import { Logger } from "../../Misc/logger";
  3. import { VertexData } from "../../Meshes/mesh.vertexData";
  4. import { Mesh } from "../../Meshes/mesh";
  5. import { Scene } from "../../scene";
  6. import { Epsilon, Vector3 } from '../../Maths/math';
  7. import { TransformNode } from "../../Meshes/transformNode";
  8. import { Observer } from "../../Misc/observable";
  9. import { Nullable } from "../../types";
  10. import { VertexBuffer } from "../../Meshes/buffer";
  11. declare var Recast: any;
  12. /**
  13. * RecastJS navigation plugin
  14. */
  15. export class RecastJSPlugin implements INavigationEnginePlugin {
  16. /**
  17. * Reference to the Recast library
  18. */
  19. public bjsRECAST: any = {};
  20. /**
  21. * plugin name
  22. */
  23. public name: string = "RecastJSPlugin";
  24. /**
  25. * the first navmesh created. We might extend this to support multiple navmeshes
  26. */
  27. public navMesh: any;
  28. private _maximumSubStepCount: number = 10;
  29. private _timeStep: number = 1/60;
  30. /**
  31. * Initializes the recastJS plugin
  32. * @param recastInjection can be used to inject your own recast reference
  33. */
  34. public constructor(recastInjection: any = Recast) {
  35. if (typeof recastInjection === "function") {
  36. recastInjection(this.bjsRECAST);
  37. } else {
  38. this.bjsRECAST = recastInjection;
  39. }
  40. if (!this.isSupported()) {
  41. Logger.Error("RecastJS is not available. Please make sure you included the js file.");
  42. return;
  43. }
  44. this.setTimeStep();
  45. }
  46. setTimeStep(newTimeStep: number = 1./60.): void {
  47. this._timeStep = newTimeStep;
  48. }
  49. getTimeStep(): number {
  50. return this._timeStep;
  51. }
  52. setMaximumSubStepCount(newStepCount: number = 10): void {
  53. this._maximumSubStepCount = newStepCount;
  54. }
  55. getMaximumSubStepCount(): number
  56. {
  57. return this._maximumSubStepCount;
  58. }
  59. /**
  60. * Creates a navigation mesh
  61. * @param meshes array of all the geometry used to compute the navigatio mesh
  62. * @param parameters bunch of parameters used to filter geometry
  63. */
  64. createNavMesh(meshes: Array<Mesh>, parameters: INavMeshParameters): void {
  65. const rc = new this.bjsRECAST.rcConfig();
  66. rc.cs = parameters.cs;
  67. rc.ch = parameters.ch;
  68. rc.borderSize = 0;
  69. rc.tileSize = 0;
  70. rc.walkableSlopeAngle = parameters.walkableSlopeAngle;
  71. rc.walkableHeight = parameters.walkableHeight;
  72. rc.walkableClimb = parameters.walkableClimb;
  73. rc.walkableRadius = parameters.walkableRadius;
  74. rc.maxEdgeLen = parameters.maxEdgeLen;
  75. rc.maxSimplificationError = parameters.maxSimplificationError;
  76. rc.minRegionArea = parameters.minRegionArea;
  77. rc.mergeRegionArea = parameters.mergeRegionArea;
  78. rc.maxVertsPerPoly = parameters.maxVertsPerPoly;
  79. rc.detailSampleDist = parameters.detailSampleDist;
  80. rc.detailSampleMaxError = parameters.detailSampleMaxError;
  81. this.navMesh = new this.bjsRECAST.NavMesh();
  82. var index: number;
  83. var tri: number;
  84. var pt: number;
  85. var indices = [];
  86. var positions = [];
  87. var offset = 0;
  88. for (index = 0; index < meshes.length; index++) {
  89. if (meshes[index]) {
  90. var mesh = meshes[index];
  91. const meshIndices = mesh.getIndices();
  92. if (!meshIndices) {
  93. continue;
  94. }
  95. const meshPositions = mesh.getVerticesData(VertexBuffer.PositionKind, false, false);
  96. if (!meshPositions) {
  97. continue;
  98. }
  99. const wm = mesh.computeWorldMatrix(true);
  100. for (tri = 0; tri < meshIndices.length; tri++) {
  101. indices.push(meshIndices[tri] + offset);
  102. }
  103. var transformed = Vector3.Zero();
  104. var position = Vector3.Zero();
  105. for (pt = 0; pt < meshPositions.length; pt += 3) {
  106. Vector3.FromArrayToRef(meshPositions, pt, position);
  107. Vector3.TransformCoordinatesToRef(position, wm, transformed);
  108. positions.push(transformed.x, transformed.y, transformed.z);
  109. }
  110. offset += meshPositions.length / 3;
  111. }
  112. }
  113. this.navMesh.build(positions, offset, indices, indices.length, rc);
  114. }
  115. /**
  116. * Create a navigation mesh debug mesh
  117. * @param scene is where the mesh will be added
  118. * @returns debug display mesh
  119. */
  120. createDebugNavMesh(scene: Scene): Mesh {
  121. var tri: number;
  122. var pt: number;
  123. var debugNavMesh = this.navMesh.getDebugNavMesh();
  124. let triangleCount = debugNavMesh.getTriangleCount();
  125. var indices = [];
  126. var positions = [];
  127. for (tri = 0; tri < triangleCount * 3; tri++)
  128. {
  129. indices.push(tri);
  130. }
  131. for (tri = 0; tri < triangleCount; tri++)
  132. {
  133. for (pt = 0; pt < 3 ; pt++)
  134. {
  135. let point = debugNavMesh.getTriangle(tri).getPoint(pt);
  136. positions.push(point.x, point.y, point.z);
  137. }
  138. }
  139. var mesh = new Mesh("NavMeshDebug", scene);
  140. var vertexData = new VertexData();
  141. vertexData.indices = indices;
  142. vertexData.positions = positions;
  143. vertexData.applyToMesh(mesh, false);
  144. return mesh;
  145. }
  146. /**
  147. * Get a navigation mesh constrained position, closest to the parameter position
  148. * @param position world position
  149. * @returns the closest point to position constrained by the navigation mesh
  150. */
  151. getClosestPoint(position: Vector3) : Vector3
  152. {
  153. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  154. var ret = this.navMesh.getClosestPoint(p);
  155. var pr = new Vector3(ret.x, ret.y, ret.z);
  156. return pr;
  157. }
  158. /**
  159. * Get a navigation mesh constrained position, closest to the parameter position
  160. * @param position world position
  161. * @param result output the closest point to position constrained by the navigation mesh
  162. */
  163. getClosestPointToRef(position: Vector3, result: Vector3) : void {
  164. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  165. var ret = this.navMesh.getClosestPoint(p);
  166. result.set(ret.x, ret.y, ret.z);
  167. }
  168. /**
  169. * Get a navigation mesh constrained position, within a particular radius
  170. * @param position world position
  171. * @param maxRadius the maximum distance to the constrained world position
  172. * @returns the closest point to position constrained by the navigation mesh
  173. */
  174. getRandomPointAround(position: Vector3, maxRadius: number): Vector3 {
  175. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  176. var ret = this.navMesh.getRandomPointAround(p, maxRadius);
  177. var pr = new Vector3(ret.x, ret.y, ret.z);
  178. return pr;
  179. }
  180. /**
  181. * Get a navigation mesh constrained position, within a particular radius
  182. * @param position world position
  183. * @param maxRadius the maximum distance to the constrained world position
  184. * @param result output the closest point to position constrained by the navigation mesh
  185. */
  186. getRandomPointAroundToRef(position: Vector3, maxRadius: number, result: Vector3): void {
  187. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  188. var ret = this.navMesh.getRandomPointAround(p, maxRadius);
  189. result.set(ret.x, ret.y, ret.z);
  190. }
  191. /**
  192. * Compute the final position from a segment made of destination-position
  193. * @param position world position
  194. * @param destination world position
  195. * @returns the resulting point along the navmesh
  196. */
  197. moveAlong(position: Vector3, destination: Vector3): Vector3 {
  198. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  199. var d = new this.bjsRECAST.Vec3(destination.x, destination.y, destination.z);
  200. var ret = this.navMesh.moveAlong(p, d);
  201. var pr = new Vector3(ret.x, ret.y, ret.z);
  202. return pr;
  203. }
  204. /**
  205. * Compute the final position from a segment made of destination-position
  206. * @param position world position
  207. * @param destination world position
  208. * @param result output the resulting point along the navmesh
  209. */
  210. moveAlongToRef(position: Vector3, destination: Vector3, result: Vector3): void {
  211. var p = new this.bjsRECAST.Vec3(position.x, position.y, position.z);
  212. var d = new this.bjsRECAST.Vec3(destination.x, destination.y, destination.z);
  213. var ret = this.navMesh.moveAlong(p, d);
  214. result.set(ret.x, ret.y, ret.z);
  215. }
  216. /**
  217. * Compute a navigation path from start to end. Returns an empty array if no path can be computed
  218. * @param start world position
  219. * @param end world position
  220. * @returns array containing world position composing the path
  221. */
  222. computePath(start: Vector3, end: Vector3): Vector3[]
  223. {
  224. var pt: number;
  225. let startPos = new this.bjsRECAST.Vec3(start.x, start.y, start.z);
  226. let endPos = new this.bjsRECAST.Vec3(end.x, end.y, end.z);
  227. let navPath = this.navMesh.computePath(startPos, endPos);
  228. let pointCount = navPath.getPointCount();
  229. var positions = [];
  230. for (pt = 0; pt < pointCount; pt++)
  231. {
  232. let p = navPath.getPoint(pt);
  233. positions.push(new Vector3(p.x, p.y, p.z));
  234. }
  235. return positions;
  236. }
  237. /**
  238. * Create a new Crowd so you can add agents
  239. * @param maxAgents the maximum agent count in the crowd
  240. * @param maxAgentRadius the maximum radius an agent can have
  241. * @param scene to attach the crowd to
  242. * @returns the crowd you can add agents to
  243. */
  244. createCrowd(maxAgents: number, maxAgentRadius: number, scene: Scene) : ICrowd
  245. {
  246. var crowd = new RecastJSCrowd(this, maxAgents, maxAgentRadius, scene);
  247. return crowd;
  248. }
  249. /**
  250. * Set the Bounding box extent for doing spatial queries (getClosestPoint, getRandomPointAround, ...)
  251. * The queries will try to find a solution within those bounds
  252. * default is (1,1,1)
  253. * @param extent x,y,z value that define the extent around the queries point of reference
  254. */
  255. setDefaultQueryExtent(extent: Vector3): void
  256. {
  257. let ext = new this.bjsRECAST.Vec3(extent.x, extent.y, extent.z);
  258. this.navMesh.setDefaultQueryExtent(ext);
  259. }
  260. /**
  261. * Get the Bounding box extent specified by setDefaultQueryExtent
  262. * @returns the box extent values
  263. */
  264. getDefaultQueryExtent(): Vector3
  265. {
  266. let p = this.navMesh.getDefaultQueryExtent();
  267. return new Vector3(p.x, p.y, p.z);
  268. }
  269. /**
  270. * build the navmesh from a previously saved state using getNavmeshData
  271. * @param data the Uint8Array returned by getNavmeshData
  272. */
  273. buildFromNavmeshData(data: Uint8Array): void
  274. {
  275. var nDataBytes = data.length * data.BYTES_PER_ELEMENT;
  276. var dataPtr = this.bjsRECAST._malloc(nDataBytes);
  277. var dataHeap = new Uint8Array(this.bjsRECAST.HEAPU8.buffer, dataPtr, nDataBytes);
  278. dataHeap.set(data);
  279. let buf = new this.bjsRECAST.NavmeshData();
  280. buf.dataPointer = dataHeap.byteOffset;
  281. buf.size = data.length;
  282. this.navMesh = new this.bjsRECAST.NavMesh();
  283. this.navMesh.buildFromNavmeshData(buf);
  284. // Free memory
  285. this.bjsRECAST._free(dataHeap.byteOffset);
  286. }
  287. /**
  288. * returns the navmesh data that can be used later. The navmesh must be built before retrieving the data
  289. * @returns data the Uint8Array that can be saved and reused
  290. */
  291. getNavmeshData(): Uint8Array
  292. {
  293. let navmeshData = this.navMesh.getNavmeshData();
  294. var arrView = new Uint8Array(this.bjsRECAST.HEAPU8.buffer, navmeshData.dataPointer, navmeshData.size);
  295. var ret = new Uint8Array(navmeshData.size);
  296. ret.set(arrView);
  297. this.navMesh.freeNavmeshData(navmeshData);
  298. return ret;
  299. }
  300. /**
  301. * Get the Bounding box extent result specified by setDefaultQueryExtent
  302. * @param result output the box extent values
  303. */
  304. getDefaultQueryExtentToRef(result: Vector3): void
  305. {
  306. let p = this.navMesh.getDefaultQueryExtent();
  307. result.set(p.x, p.y, p.z);
  308. }
  309. /**
  310. * Disposes
  311. */
  312. public dispose() {
  313. }
  314. /**
  315. * If this plugin is supported
  316. * @returns true if plugin is supported
  317. */
  318. public isSupported(): boolean {
  319. return this.bjsRECAST !== undefined;
  320. }
  321. }
  322. /**
  323. * Recast detour crowd implementation
  324. */
  325. export class RecastJSCrowd implements ICrowd {
  326. /**
  327. * Recast/detour plugin
  328. */
  329. public bjsRECASTPlugin: RecastJSPlugin;
  330. /**
  331. * Link to the detour crowd
  332. */
  333. public recastCrowd: any = {};
  334. /**
  335. * One transform per agent
  336. */
  337. public transforms: TransformNode[] = new Array<TransformNode>();
  338. /**
  339. * All agents created
  340. */
  341. public agents: number[] = new Array<number>();
  342. /**
  343. * Link to the scene is kept to unregister the crowd from the scene
  344. */
  345. private _scene: Scene;
  346. /**
  347. * Observer for crowd updates
  348. */
  349. private _onBeforeAnimationsObserver: Nullable<Observer<Scene>> = null;
  350. /**
  351. * Constructor
  352. * @param plugin recastJS plugin
  353. * @param maxAgents the maximum agent count in the crowd
  354. * @param maxAgentRadius the maximum radius an agent can have
  355. * @param scene to attach the crowd to
  356. * @returns the crowd you can add agents to
  357. */
  358. public constructor(plugin: RecastJSPlugin, maxAgents: number, maxAgentRadius: number, scene: Scene) {
  359. this.bjsRECASTPlugin = plugin;
  360. this.recastCrowd = new this.bjsRECASTPlugin.bjsRECAST.Crowd(maxAgents, maxAgentRadius, this.bjsRECASTPlugin.navMesh.getNavMesh());
  361. this._scene = scene;
  362. this._onBeforeAnimationsObserver = scene.onBeforeAnimationsObservable.add(() => {
  363. this.update(scene.getEngine().getDeltaTime() * 0.001);
  364. });
  365. }
  366. /**
  367. * Add a new agent to the crowd with the specified parameter a corresponding transformNode.
  368. * You can attach anything to that node. The node position is updated in the scene update tick.
  369. * @param pos world position that will be constrained by the navigation mesh
  370. * @param parameters agent parameters
  371. * @param transform hooked to the agent that will be update by the scene
  372. * @returns agent index
  373. */
  374. addAgent(pos: Vector3, parameters: IAgentParameters, transform: TransformNode): number
  375. {
  376. var agentParams = new this.bjsRECASTPlugin.bjsRECAST.dtCrowdAgentParams();
  377. agentParams.radius = parameters.radius;
  378. agentParams.height = parameters.height;
  379. agentParams.maxAcceleration = parameters.maxAcceleration;
  380. agentParams.maxSpeed = parameters.maxSpeed;
  381. agentParams.collisionQueryRange = parameters.collisionQueryRange;
  382. agentParams.pathOptimizationRange = parameters.pathOptimizationRange;
  383. agentParams.separationWeight = parameters.separationWeight;
  384. agentParams.updateFlags = 7;
  385. agentParams.obstacleAvoidanceType = 0;
  386. agentParams.queryFilterType = 0;
  387. agentParams.userData = 0;
  388. var agentIndex = this.recastCrowd.addAgent(new this.bjsRECASTPlugin.bjsRECAST.Vec3(pos.x, pos.y, pos.z), agentParams);
  389. this.transforms.push(transform);
  390. this.agents.push(agentIndex);
  391. return agentIndex;
  392. }
  393. /**
  394. * Returns the agent position in world space
  395. * @param index agent index returned by addAgent
  396. * @returns world space position
  397. */
  398. getAgentPosition(index: number): Vector3 {
  399. var agentPos = this.recastCrowd.getAgentPosition(index);
  400. return new Vector3(agentPos.x, agentPos.y, agentPos.z);
  401. }
  402. /**
  403. * Returns the agent position result in world space
  404. * @param index agent index returned by addAgent
  405. * @param result output world space position
  406. */
  407. getAgentPositionToRef(index: number, result: Vector3): void {
  408. var agentPos = this.recastCrowd.getAgentPosition(index);
  409. result.set(agentPos.x, agentPos.y, agentPos.z);
  410. }
  411. /**
  412. * Returns the agent velocity in world space
  413. * @param index agent index returned by addAgent
  414. * @returns world space velocity
  415. */
  416. getAgentVelocity(index: number): Vector3 {
  417. var agentVel = this.recastCrowd.getAgentVelocity(index);
  418. return new Vector3(agentVel.x, agentVel.y, agentVel.z);
  419. }
  420. /**
  421. * Returns the agent velocity result in world space
  422. * @param index agent index returned by addAgent
  423. * @param result output world space velocity
  424. */
  425. getAgentVelocityToRef(index: number, result: Vector3): void {
  426. var agentVel = this.recastCrowd.getAgentVelocity(index);
  427. result.set(agentVel.x, agentVel.y, agentVel.z);
  428. }
  429. /**
  430. * Returns the agent next target point on the path
  431. * @param index agent index returned by addAgent
  432. * @returns world space position
  433. */
  434. getAgentNextTargetPath(index: number): Vector3 {
  435. var pathTargetPos = this.recastCrowd.getAgentNextTargetPath(index);
  436. return new Vector3(pathTargetPos.x, pathTargetPos.y, pathTargetPos.z);
  437. }
  438. /**
  439. * Returns the agent next target point on the path
  440. * @param index agent index returned by addAgent
  441. * @param result output world space position
  442. */
  443. getAgentNextTargetPathToRef(index: number, result: Vector3): void {
  444. var pathTargetPos = this.recastCrowd.getAgentNextTargetPath(index);
  445. result.set(pathTargetPos.x, pathTargetPos.y, pathTargetPos.z);
  446. }
  447. /**
  448. * Gets the agent state
  449. * @param index agent index returned by addAgent
  450. * @returns agent state
  451. */
  452. getAgentState(index: number): number {
  453. return this.recastCrowd.getAgentState(index);
  454. }
  455. /**
  456. * returns true if the agent in over an off mesh link connection
  457. * @param index agent index returned by addAgent
  458. * @returns true if over an off mesh link connection
  459. */
  460. overOffmeshConnection(index: number): boolean {
  461. return this.recastCrowd.overOffmeshConnection(index);
  462. }
  463. /**
  464. * Asks a particular agent to go to a destination. That destination is constrained by the navigation mesh
  465. * @param index agent index returned by addAgent
  466. * @param destination targeted world position
  467. */
  468. agentGoto(index: number, destination: Vector3): void {
  469. this.recastCrowd.agentGoto(index, new this.bjsRECASTPlugin.bjsRECAST.Vec3(destination.x, destination.y, destination.z));
  470. }
  471. /**
  472. * Teleport the agent to a new position
  473. * @param index agent index returned by addAgent
  474. * @param destination targeted world position
  475. */
  476. agentTeleport(index: number, destination: Vector3): void {
  477. this.recastCrowd.agentTeleport(index, new this.bjsRECASTPlugin.bjsRECAST.Vec3(destination.x, destination.y, destination.z));
  478. }
  479. /**
  480. * Update agent parameters
  481. * @param index agent index returned by addAgent
  482. * @param parameters agent parameters
  483. */
  484. updateAgentParameters(index: number, parameters: IAgentParameters): void {
  485. var agentParams = this.recastCrowd.getAgentParameters(index);
  486. if (parameters.radius !== undefined) {
  487. agentParams.radius = parameters.radius;
  488. }
  489. if (parameters.height !== undefined) {
  490. agentParams.height = parameters.height;
  491. }
  492. if (parameters.maxAcceleration !== undefined) {
  493. agentParams.maxAcceleration = parameters.maxAcceleration;
  494. }
  495. if (parameters.maxSpeed !== undefined) {
  496. agentParams.maxSpeed = parameters.maxSpeed;
  497. }
  498. if (parameters.collisionQueryRange !== undefined) {
  499. agentParams.collisionQueryRange = parameters.collisionQueryRange;
  500. }
  501. if (parameters.pathOptimizationRange !== undefined) {
  502. agentParams.pathOptimizationRange = parameters.pathOptimizationRange;
  503. }
  504. if (parameters.separationWeight !== undefined) {
  505. agentParams.separationWeight = parameters.separationWeight;
  506. }
  507. this.recastCrowd.setAgentParameters(index, agentParams);
  508. }
  509. /**
  510. * remove a particular agent previously created
  511. * @param index agent index returned by addAgent
  512. */
  513. removeAgent(index: number): void {
  514. this.recastCrowd.removeAgent(index);
  515. var item = this.agents.indexOf(index);
  516. if (item > -1) {
  517. this.agents.splice(item, 1);
  518. this.transforms.splice(item, 1);
  519. }
  520. }
  521. /**
  522. * get the list of all agents attached to this crowd
  523. * @returns list of agent indices
  524. */
  525. getAgents(): number[] {
  526. return this.agents;
  527. }
  528. /**
  529. * Tick update done by the Scene. Agent position/velocity/acceleration is updated by this function
  530. * @param deltaTime in seconds
  531. */
  532. update(deltaTime: number): void {
  533. // update crowd
  534. var timeStep = this.bjsRECASTPlugin.getTimeStep();
  535. var maxStepCount = this.bjsRECASTPlugin.getMaximumSubStepCount();
  536. if (timeStep <= Epsilon) {
  537. this.recastCrowd.update(deltaTime);
  538. } else {
  539. var iterationCount = deltaTime / timeStep;
  540. if (maxStepCount && iterationCount > maxStepCount) {
  541. iterationCount = maxStepCount
  542. }
  543. if (iterationCount < 1) {
  544. iterationCount = 1;
  545. }
  546. for (let i = 0; i < iterationCount; i++) {
  547. this.recastCrowd.update(timeStep);
  548. }
  549. }
  550. // update transforms
  551. for (let index = 0; index < this.agents.length; index++)
  552. {
  553. this.transforms[index].position = this.getAgentPosition(this.agents[index]);
  554. }
  555. }
  556. /**
  557. * Set the Bounding box extent for doing spatial queries (getClosestPoint, getRandomPointAround, ...)
  558. * The queries will try to find a solution within those bounds
  559. * default is (1,1,1)
  560. * @param extent x,y,z value that define the extent around the queries point of reference
  561. */
  562. setDefaultQueryExtent(extent: Vector3): void
  563. {
  564. let ext = new this.bjsRECASTPlugin.bjsRECAST.Vec3(extent.x, extent.y, extent.z);
  565. this.recastCrowd.setDefaultQueryExtent(ext);
  566. }
  567. /**
  568. * Get the Bounding box extent specified by setDefaultQueryExtent
  569. * @returns the box extent values
  570. */
  571. getDefaultQueryExtent(): Vector3
  572. {
  573. let p = this.recastCrowd.getDefaultQueryExtent();
  574. return new Vector3(p.x, p.y, p.z);
  575. }
  576. /**
  577. * Get the Bounding box extent result specified by setDefaultQueryExtent
  578. * @param result output the box extent values
  579. */
  580. getDefaultQueryExtentToRef(result: Vector3): void
  581. {
  582. let p = this.recastCrowd.getDefaultQueryExtent();
  583. result.set(p.x, p.y, p.z);
  584. }
  585. /**
  586. * Release all resources
  587. */
  588. dispose() : void
  589. {
  590. this.recastCrowd.destroy();
  591. this._scene.onBeforeAnimationsObservable.remove(this._onBeforeAnimationsObserver);
  592. this._onBeforeAnimationsObserver = null;
  593. }
  594. }