@babylonjs/lite 1.14.0 → 1.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/index.js +326 -326
  3. package/dist/index.js.map +1 -1
  4. package/index.d.ts +72 -6
  5. package/lib/camera/arc-rotate.js +2 -20
  6. package/lib/camera/arc-rotate.js.map +1 -1
  7. package/lib/camera/camera.js +21 -4
  8. package/lib/camera/camera.js.map +1 -1
  9. package/lib/camera/free-camera.js +2 -19
  10. package/lib/camera/free-camera.js.map +1 -1
  11. package/lib/camera/geospatial-camera.js +2 -19
  12. package/lib/camera/geospatial-camera.js.map +1 -1
  13. package/lib/camera/orthographic.js +70 -0
  14. package/lib/camera/orthographic.js.map +1 -0
  15. package/lib/engine/engine.js +1 -1
  16. package/lib/frame-graph/render-task.js +2 -2
  17. package/lib/frame-graph/render-task.js.map +1 -1
  18. package/lib/index.js +4 -1
  19. package/lib/index.js.map +1 -1
  20. package/lib/light/clustered.js +19 -6
  21. package/lib/light/clustered.js.map +1 -1
  22. package/lib/material/shader/shader-renderable.js +2 -2
  23. package/lib/material/shader/shader-renderable.js.map +1 -1
  24. package/lib/material/standard/enable-standard-mesh-features.js.map +1 -1
  25. package/lib/math/index.js +1 -0
  26. package/lib/math/index.js.map +1 -1
  27. package/lib/math/mat4-look-at-world-lh.js +55 -0
  28. package/lib/math/mat4-look-at-world-lh.js.map +1 -0
  29. package/lib/math/mat4-ortho-lh-to-ref.js +22 -0
  30. package/lib/math/mat4-ortho-lh-to-ref.js.map +1 -0
  31. package/lib/math/mat4.js +1 -0
  32. package/lib/math/mat4.js.map +1 -1
  33. package/lib/navigation/index.js +1 -1
  34. package/lib/navigation/navigation.js +12 -1
  35. package/lib/navigation/navigation.js.map +1 -1
  36. package/lib/post-process/taa.js +2 -1
  37. package/lib/post-process/taa.js.map +1 -1
  38. package/lib/shadow/csm-shadow-task-hooks.js +13 -6
  39. package/lib/shadow/csm-shadow-task-hooks.js.map +1 -1
  40. package/lib/shadow/shadow-base.js +3 -2
  41. package/lib/shadow/shadow-base.js.map +1 -1
  42. package/lib/text/text-renderable.js +2 -2
  43. package/lib/text/text-renderable.js.map +1 -1
  44. package/package.json +3 -11
  45. package/material/standard/enable-standard-mesh-features.d.ts +0 -4
  46. package/material/standard/enable-standard-vertex-colors.d.ts +0 -2
@@ -380,6 +380,17 @@ function raycast(plugin, start, end) {
380
380
  }
381
381
  };
382
382
  }
383
+ function navRayBlocked(plugin, start, end) {
384
+ _assertReady(plugin);
385
+ const q = plugin._navMeshQuery;
386
+ const nearest = q.findNearestPoly(start, { halfExtents: _tmpHalfExtents });
387
+ if (!nearest.success || nearest.nearestRef === 0) {
388
+ return true;
389
+ }
390
+ const r = q.raycast(nearest.nearestRef, start, end);
391
+ const t = r?.t;
392
+ return !(r?.success === true && typeof t === "number" && Number.isFinite(t) && t > 1);
393
+ }
383
394
  function addBoxObstacle(plugin, position, halfExtents, angle) {
384
395
  _assertTileCache(plugin);
385
396
  const r = plugin._tileCache.addBoxObstacle(position, halfExtents, angle);
@@ -421,5 +432,5 @@ function _assertTileCache(plugin) {
421
432
  }
422
433
  }
423
434
 
424
- export { addAgent, addBoxObstacle, addCylinderObstacle, agentGoto, computePath, createDebugNavMeshGeometry, createNavCrowd, createNavMesh, createNavMeshFromSources, createNavigationPluginAsync, disposeNavigationPlugin, findClosestPointWithin, findRandomPoint, findRandomPointAroundCircle, getAgentPosition, getAgentVelocity, getClosestPoint, getNavigationRandomSeed, raycast, removeObstacle, setNavigationRandomSeed, updateNavCrowd, updateNavMeshObstacles };
435
+ export { addAgent, addBoxObstacle, addCylinderObstacle, agentGoto, computePath, createDebugNavMeshGeometry, createNavCrowd, createNavMesh, createNavMeshFromSources, createNavigationPluginAsync, disposeNavigationPlugin, findClosestPointWithin, findRandomPoint, findRandomPointAroundCircle, getAgentPosition, getAgentVelocity, getClosestPoint, getNavigationRandomSeed, navRayBlocked, raycast, removeObstacle, setNavigationRandomSeed, updateNavCrowd, updateNavMeshObstacles };
425
436
  //# sourceMappingURL=navigation.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"navigation.js","sources":["../../../src/navigation/navigation.ts"],"sourcesContent":["/**\n * Recast Navigation V2 integration for Babylon Lite.\n *\n * Pure-state interfaces + standalone factory functions, matching Lite conventions.\n * The recast wasm is loaded lazily inside `createNavigationPluginAsync` so scenes\n * that do not use navigation pay zero bundle cost.\n *\n * Usage:\n * ```ts\n * const nav = await createNavigationPluginAsync();\n * createNavMesh(nav, [ground, sphere, box], params);\n * const debug = createDebugNavMeshGeometry(nav);\n * const closest = getClosestPoint(nav, { x, y, z });\n * const crowd = createNavCrowd(nav, 10, 0.1);\n * const idx = addAgent(crowd, spawnPos, agentParams);\n * updateNavCrowd(crowd, 1 / 60);\n * ```\n *\n * For obstacles (tile-cache navmesh):\n * ```ts\n * createNavMesh(nav, [...], { ..., maxObstacles: 32, tileSize: 32 });\n * const ref = addBoxObstacle(nav, { x, y, z }, { x: 1, y: 1, z: 1 }, angle);\n * removeObstacle(nav, ref);\n * ```\n *\n * For off-mesh connections:\n * ```ts\n * createNavMesh(nav, [...], { ..., offMeshConnections: [...] });\n * ```\n *\n * For raycast:\n * ```ts\n * const r = raycast(nav, start, end);\n * if (r.hit) console.log(r.hitPoint);\n * ```\n */\n\nimport { F32, U32 } from \"../engine/typed-arrays.js\";\nimport type { Vec3 } from \"../math/types.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\n\n// ─── Public types ────────────────────────────────────────────────────\n\n/** NavMesh build parameters (Recast solo / tiled / tile-cache navmesh config). */\nexport interface NavMeshParameters {\n cs?: number;\n ch?: number;\n walkableSlopeAngle?: number;\n walkableHeight?: number;\n walkableClimb?: number;\n walkableRadius?: number;\n maxEdgeLen?: number;\n maxSimplificationError?: number;\n minRegionArea?: number;\n mergeRegionArea?: number;\n maxVertsPerPoly?: number;\n detailSampleDist?: number;\n detailSampleMaxError?: number;\n /** Skip reversing winding when extracting positions (right-handed input). */\n doNotReverseIndices?: boolean;\n /** Tile size for tiled / tile-cache navmesh. Recommended 32-64 for tile cache. */\n tileSize?: number;\n /**\n * Maximum number of obstacles. If `> 0` the navmesh is built with a tile cache\n * so obstacles can be added/removed dynamically.\n */\n maxObstacles?: number;\n /** Expected layers per tile for tile-cache navmesh. Default 1. */\n expectedLayersPerTile?: number;\n /** Off-mesh connection segments (teleports) baked into the navmesh. */\n offMeshConnections?: OffMeshConnection[];\n /** Keep intermediates for debug visualization. */\n keepIntermediates?: boolean;\n}\n\n/** Off-mesh connection (teleport segment) baked into the navmesh. */\nexport interface OffMeshConnection {\n startPosition: Vec3;\n endPosition: Vec3;\n radius: number;\n bidirectional: boolean;\n /** @defaultValue 0 */\n area?: number;\n /** @defaultValue 1 */\n flags?: number;\n userId?: number;\n}\n\n/** Crowd agent parameters. */\nexport interface AgentParameters {\n radius: number;\n height: number;\n maxAcceleration: number;\n maxSpeed: number;\n collisionQueryRange: number;\n pathOptimizationRange: number;\n separationWeight: number;\n updateFlags?: number;\n obstacleAvoidanceType?: number;\n queryFilterType?: number;\n reachRadius?: number;\n}\n\n/** A single mesh source for navmesh construction. */\nexport interface NavMeshSource {\n positions: ArrayLike<number>;\n indices: ArrayLike<number>;\n}\n\n/** Pure-state handle for the navigation plugin. */\nexport interface NavigationPlugin {\n /** @internal */ readonly _recast: any;\n /** @internal */ readonly _generators: any;\n /** @internal */ _navMesh?: any;\n /** @internal */ _navMeshQuery?: any;\n /** @internal */ _tileCache?: any;\n}\n\n/** Opaque handle returned by `addBoxObstacle` / `addCylinderObstacle`. */\nexport interface ObstacleHandle {\n /** @internal */ readonly _obstacle: any;\n}\n\n/** Pure-state handle for a crowd. */\nexport interface NavCrowd {\n /** @internal */ readonly _plugin: NavigationPlugin;\n /** @internal */ readonly _crowd: any;\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────\n\nlet _coreModule: any = null;\nlet _generatorsModule: any = null;\nlet _initPromise: Promise<void> | null = null;\n\nasync function _ensureRecast(locateFile?: (url: string) => string): Promise<{ core: any; gens: any }> {\n if (!_coreModule || !_generatorsModule) {\n if (!_initPromise) {\n _initPromise = (async () => {\n const core = await import(\"@recast-navigation/core\");\n const gens = await import(\"@recast-navigation/generators\");\n if (locateFile) {\n const wasmFactory = (await import(\"@recast-navigation/wasm/wasm\")).default;\n // core.init types impl as typeof Recast but calls it as impl() at runtime;\n // bind pre-fills locateFile and cast to satisfy the declaration.\n await core.init(wasmFactory.bind(null, { locateFile }) as typeof wasmFactory);\n } else {\n await core.init();\n }\n _coreModule = core;\n _generatorsModule = gens;\n })();\n }\n await _initPromise;\n }\n return { core: _coreModule, gens: _generatorsModule };\n}\n\n/**\n * Create a navigation plugin. Loads the Recast wasm internally on first call;\n * subsequent calls reuse the loaded module.\n *\n * Pass `locateFile` to serve the wasm from a public path instead of bundling\n * it inline — same pattern as `HavokPhysics({ locateFile: () => \"/HavokPhysics.wasm\" })`.\n *\n * @example\n * ```ts\n * const nav = await createNavigationPluginAsync({ locateFile: () => \"/recast-navigation.wasm\" });\n * ```\n */\nexport async function createNavigationPluginAsync(options?: { locateFile?: (url: string) => string }): Promise<NavigationPlugin> {\n const { core, gens } = await _ensureRecast(options?.locateFile);\n return {\n _recast: core,\n _generators: gens,\n };\n}\n\n/**\n * Release the native navmesh resources a plugin holds: the navmesh query, the navmesh, and the tile cache (if\n * one was built). These are Detour objects living on the wasm heap — they are NOT reclaimed by JS garbage\n * collection, so dropping the plugin reference alone leaks them. Call this when a navmesh is rebuilt or a\n * plugin is discarded. Idempotent and safe on a plugin that never built a navmesh.\n */\nexport function disposeNavigationPlugin(plugin: NavigationPlugin): void {\n const internal = plugin as { _navMesh?: any; _navMeshQuery?: any; _tileCache?: any };\n internal._navMeshQuery?.destroy?.();\n internal._tileCache?.destroy?.();\n internal._navMesh?.destroy?.();\n internal._navMeshQuery = undefined;\n internal._tileCache = undefined;\n internal._navMesh = undefined;\n}\n\n// ─── NavMesh ─────────────────────────────────────────────────────────\n\n/**\n * Build a navmesh from one or more meshes. Each mesh's CPU positions are\n * transformed by its worldMatrix (matching BJS GetPositionsAndIndices), merged\n * into a single stream, and index winding is reversed (left-handed convention)\n * unless `doNotReverseIndices` is set.\n *\n * - Solo navmesh by default.\n * - If `maxObstacles > 0`, builds a tile-cache navmesh so obstacles can be\n * added/removed dynamically.\n * - Off-mesh connections can be supplied for either solo or tile-cache.\n */\nexport function createNavMesh(plugin: NavigationPlugin, meshes: Mesh[], params: NavMeshParameters): void {\n const { positions, indices } = _mergeMeshes(meshes, params.doNotReverseIndices === true);\n _createNavMeshFromMerged(plugin, positions, indices, params);\n}\n\n/** Build a navmesh from raw CPU geometry sources. This is the non-rendering twin of\n * `createNavMesh`: callers that already own procedural navigation geometry can avoid\n * creating hidden GPU meshes just to feed Recast. */\nexport function createNavMeshFromSources(plugin: NavigationPlugin, sources: NavMeshSource[], params: NavMeshParameters): void {\n const { positions, indices } = _mergeSources(sources, params.doNotReverseIndices === true);\n _createNavMeshFromMerged(plugin, positions, indices, params);\n}\n\nfunction _createNavMeshFromMerged(plugin: NavigationPlugin, positions: Float32Array, indices: Uint32Array, params: NavMeshParameters): void {\n const cfg: Record<string, unknown> = {};\n if (params.cs !== undefined) {\n cfg.cs = params.cs;\n }\n if (params.ch !== undefined) {\n cfg.ch = params.ch;\n }\n if (params.walkableSlopeAngle !== undefined) {\n cfg.walkableSlopeAngle = params.walkableSlopeAngle;\n }\n if (params.walkableHeight !== undefined) {\n cfg.walkableHeight = params.walkableHeight;\n }\n if (params.walkableClimb !== undefined) {\n cfg.walkableClimb = params.walkableClimb;\n }\n if (params.walkableRadius !== undefined) {\n cfg.walkableRadius = params.walkableRadius;\n }\n if (params.maxEdgeLen !== undefined) {\n cfg.maxEdgeLen = params.maxEdgeLen;\n }\n if (params.maxSimplificationError !== undefined) {\n cfg.maxSimplificationError = params.maxSimplificationError;\n }\n if (params.minRegionArea !== undefined) {\n cfg.minRegionArea = params.minRegionArea;\n }\n if (params.mergeRegionArea !== undefined) {\n cfg.mergeRegionArea = params.mergeRegionArea;\n }\n if (params.maxVertsPerPoly !== undefined) {\n cfg.maxVertsPerPoly = params.maxVertsPerPoly;\n }\n if (params.detailSampleDist !== undefined) {\n cfg.detailSampleDist = params.detailSampleDist;\n }\n if (params.detailSampleMaxError !== undefined) {\n cfg.detailSampleMaxError = params.detailSampleMaxError;\n }\n if (params.offMeshConnections !== undefined && params.offMeshConnections.length > 0) {\n cfg.offMeshConnections = params.offMeshConnections;\n }\n\n const internal = plugin as { _navMesh: any; _navMeshQuery: any; _tileCache?: any };\n const needsTileCache = (params.maxObstacles ?? 0) > 0;\n const needsTiled = (params.tileSize ?? 0) > 0;\n\n if (needsTileCache) {\n // Tile cache config: requires tileSize, expectedLayersPerTile, maxObstacles,\n // and a tile cache mesh process. Mirrors BJS Addons CreateTileCacheNavMeshConfig.\n cfg.tileSize = params.tileSize ?? 32;\n cfg.expectedLayersPerTile = params.expectedLayersPerTile ?? 1;\n cfg.maxObstacles = params.maxObstacles!;\n\n if (params.offMeshConnections !== undefined && params.offMeshConnections.length > 0) {\n cfg.tileCacheMeshProcess = _createDefaultTileCacheMeshProcess(plugin._recast, params.offMeshConnections);\n }\n\n const result = plugin._generators.generateTileCache(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh (tile cache) failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._tileCache = result.tileCache;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n return;\n }\n\n if (needsTiled) {\n cfg.tileSize = params.tileSize;\n const result = plugin._generators.generateTiledNavMesh(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh (tiled) failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n return;\n }\n\n const result = plugin._generators.generateSoloNavMesh(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n}\n\n/**\n * Default tile-cache mesh process that copies area/flags from input polys and\n * appends off-mesh connections. Mirrors BJS Addons CreateDefaultTileCacheMeshProcess.\n */\nfunction _createDefaultTileCacheMeshProcess(recast: any, offMeshConnections: OffMeshConnection[]): any {\n const area = 0;\n const flags = 1;\n return new recast.TileCacheMeshProcess((navMeshCreateParams: any, polyAreas: any, polyFlags: any) => {\n for (let i = 0; i < navMeshCreateParams.polyCount(); ++i) {\n polyAreas.set(i, area);\n polyFlags.set(i, flags);\n }\n if (offMeshConnections.length > 0) {\n navMeshCreateParams.setOffMeshConnections(offMeshConnections);\n }\n });\n}\n\nfunction _mergeMeshes(meshes: Mesh[], doNotReverseIndices: boolean): { positions: Float32Array; indices: Uint32Array } {\n let totalVerts = 0;\n let totalIdx = 0;\n for (const mesh of meshes) {\n if (!mesh._cpuPositions || !mesh._cpuIndices) {\n throw new Error(`Mesh \"${mesh.name}\" missing CPU geometry for navmesh`);\n }\n totalVerts += mesh._cpuPositions.length;\n totalIdx += mesh._cpuIndices.length;\n }\n const positions = new F32(totalVerts);\n const indices = new U32(totalIdx);\n\n let pOff = 0;\n let iOff = 0;\n let vertBase = 0;\n for (const mesh of meshes) {\n const src = mesh._cpuPositions!;\n const wm = mesh.worldMatrix;\n\n for (let i = 0; i < src.length; i += 3) {\n const x = src[i]!,\n y = src[i + 1]!,\n z = src[i + 2]!;\n positions[pOff++] = x * wm[0]! + y * wm[4]! + z * wm[8]! + wm[12]!;\n positions[pOff++] = x * wm[1]! + y * wm[5]! + z * wm[9]! + wm[13]!;\n positions[pOff++] = x * wm[2]! + y * wm[6]! + z * wm[10]! + wm[14]!;\n }\n\n const meshIdx = mesh._cpuIndices!;\n const n = meshIdx.length;\n if (doNotReverseIndices) {\n for (let i = 0; i < n; i++) {\n indices[iOff++] = meshIdx[i]! + vertBase;\n }\n } else {\n for (let i = 0; i < n; i += 3) {\n indices[iOff++] = meshIdx[i]! + vertBase;\n indices[iOff++] = meshIdx[i + 2]! + vertBase;\n indices[iOff++] = meshIdx[i + 1]! + vertBase;\n }\n }\n vertBase += src.length / 3;\n }\n\n return { positions, indices };\n}\n\nfunction _mergeSources(sources: NavMeshSource[], doNotReverseIndices: boolean): { positions: Float32Array; indices: Uint32Array } {\n let totalVerts = 0;\n let totalIdx = 0;\n for (const source of sources) {\n totalVerts += source.positions.length;\n totalIdx += source.indices.length;\n }\n const positions = new F32(totalVerts);\n const indices = new U32(totalIdx);\n\n let pOff = 0;\n let iOff = 0;\n let vertBase = 0;\n for (const source of sources) {\n for (let i = 0; i < source.positions.length; i++) {\n positions[pOff++] = source.positions[i]!;\n }\n if (doNotReverseIndices) {\n for (let i = 0; i < source.indices.length; i++) {\n indices[iOff++] = source.indices[i]! + vertBase;\n }\n } else {\n for (let i = 0; i < source.indices.length; i += 3) {\n indices[iOff++] = source.indices[i]! + vertBase;\n indices[iOff++] = source.indices[i + 2]! + vertBase;\n indices[iOff++] = source.indices[i + 1]! + vertBase;\n }\n }\n vertBase += source.positions.length / 3;\n }\n\n return { positions, indices };\n}\n\n// ─── Debug navmesh geometry ──────────────────────────────────────────\n\n/**\n * Extract debug visualization geometry from the generated navmesh.\n * Faces are detached (each triangle gets its own 3 vertices) and per-vertex\n * normals are set to the face normal — yielding flat shading without the need\n * for a separate normal-computation pass in callers.\n * Returns positions, normals, indices, and a hash of the positions for\n * cross-engine parity checks.\n */\nexport function createDebugNavMeshGeometry(plugin: NavigationPlugin): { positions: Float32Array; normals: Float32Array; indices: Uint32Array; positionsHash: number } {\n if (!plugin._navMesh) {\n throw new Error(\"No navmesh generated. Call createNavMesh first.\");\n }\n const [positionsArr, indicesArr] = plugin._recast.getNavMeshPositionsAndIndices(plugin._navMesh);\n const triCount = (indicesArr.length / 3) | 0;\n const vertCount = triCount * 3;\n const positions = new F32(vertCount * 3);\n const normals = new F32(vertCount * 3);\n const indices = new U32(vertCount);\n\n for (let t = 0; t < triCount; t++) {\n // Recast outputs triangles with original winding such that the face\n // normal computed from (i0,i1,i2) order points UP. We reverse the\n // stored winding to match BJS CreateDebugNavMesh for back-face culling\n // parity (stored as i0,i2,i1) — but compute the face normal from the\n // ORIGINAL winding so it still points UP.\n const i0 = indicesArr[t * 3]! * 3;\n const i1Orig = indicesArr[t * 3 + 1]! * 3;\n const i2Orig = indicesArr[t * 3 + 2]! * 3;\n\n const ax = positionsArr[i0]!,\n ay = positionsArr[i0 + 1]!,\n az = positionsArr[i0 + 2]!;\n const b1x = positionsArr[i1Orig]!,\n b1y = positionsArr[i1Orig + 1]!,\n b1z = positionsArr[i1Orig + 2]!;\n const c1x = positionsArr[i2Orig]!,\n c1y = positionsArr[i2Orig + 1]!,\n c1z = positionsArr[i2Orig + 2]!;\n\n const e1x = b1x - ax,\n e1y = b1y - ay,\n e1z = b1z - az;\n const e2x = c1x - ax,\n e2y = c1y - ay,\n e2z = c1z - az;\n let nx = e1y * e2z - e1z * e2y;\n let ny = e1z * e2x - e1x * e2z;\n let nz = e1x * e2y - e1y * e2x;\n const len = Math.hypot(nx, ny, nz);\n if (len > 0) {\n nx /= len;\n ny /= len;\n nz /= len;\n }\n\n // Store positions in reversed winding (i0, i2, i1) for back-face parity.\n const v = t * 9;\n positions[v] = ax;\n positions[v + 1] = ay;\n positions[v + 2] = az;\n positions[v + 3] = c1x;\n positions[v + 4] = c1y;\n positions[v + 5] = c1z;\n positions[v + 6] = b1x;\n positions[v + 7] = b1y;\n positions[v + 8] = b1z;\n\n normals[v] = nx;\n normals[v + 1] = ny;\n normals[v + 2] = nz;\n normals[v + 3] = nx;\n normals[v + 4] = ny;\n normals[v + 5] = nz;\n normals[v + 6] = nx;\n normals[v + 7] = ny;\n normals[v + 8] = nz;\n\n const idx = t * 3;\n indices[idx] = idx;\n indices[idx + 1] = idx + 1;\n indices[idx + 2] = idx + 2;\n }\n\n let hash = 0x811c9dc5;\n for (let i = 0; i < positions.length; i++) {\n hash ^= Math.round(positions[i]! * 100000);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return { positions, normals, indices, positionsHash: hash };\n}\n\n// ─── Queries ─────────────────────────────────────────────────────────\n\nconst _tmpHalfExtents = { x: 1, y: 1, z: 1 };\n\n/** Snap a position to the closest point on the navmesh. */\nexport function getClosestPoint(plugin: NavigationPlugin, position: Vec3): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findClosestPoint(position, { halfExtents: _tmpHalfExtents });\n return { x: res.point.x, y: res.point.y, z: res.point.z };\n}\n\n/** Snap a position to the closest point on the navmesh within a search box, or null when no part of the\n * mesh lies inside it. Unlike getClosestPoint — which does not inspect the query's success flag, so a\n * position outside its fixed ±1-unit box returns an UNSPECIFIED point (whatever the query left in its\n * output) rather than signalling a miss — the search extent is explicit here and a failed query is\n * reported as null, so callers can distinguish \"snapped\" from \"nothing nearby\". */\nexport function findClosestPointWithin(plugin: NavigationPlugin, position: Vec3, halfExtents: Vec3): Vec3 | null {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findClosestPoint(position, { halfExtents });\n if (!res.success) {\n return null;\n }\n return { x: res.point.x, y: res.point.y, z: res.point.z };\n}\n\n/** Compute a path between two world positions, snapped to the navmesh. */\nexport function computePath(plugin: NavigationPlugin, start: Vec3, end: Vec3): Vec3[] {\n _assertReady(plugin);\n const q = plugin._navMeshQuery;\n const startSnap = q.findClosestPoint(start, { halfExtents: _tmpHalfExtents });\n const endSnap = q.findClosestPoint(end, { halfExtents: _tmpHalfExtents });\n const res = q.computePath(startSnap.point, endSnap.point);\n if (!res.success) {\n return [];\n }\n const out: Vec3[] = [];\n for (const p of res.path) {\n out.push({ x: p.x, y: p.y, z: p.z });\n }\n return out;\n}\n\nfunction _assertReady(plugin: NavigationPlugin): void {\n if (!plugin._navMesh || !plugin._navMeshQuery) {\n throw new Error(\"Navmesh not ready. Call createNavMesh first.\");\n }\n}\n\n// ─── Crowd ───────────────────────────────────────────────────────────\n\n/**\n * Create a crowd attached to the navmesh. The crowd is NOT auto-updated;\n * call `updateNavCrowd(crowd, dt)` each frame for full determinism.\n */\nexport function createNavCrowd(plugin: NavigationPlugin, maxAgents: number, maxAgentRadius: number): NavCrowd {\n _assertReady(plugin);\n const Crowd = plugin._recast.Crowd;\n const crowd = new Crowd(plugin._navMesh, { maxAgents, maxAgentRadius });\n return { _plugin: plugin, _crowd: crowd };\n}\n\n/** Add an agent to the crowd. Returns the agent index. */\nexport function addAgent(crowd: NavCrowd, position: Vec3, params: AgentParameters): number {\n const agentParams = {\n radius: params.radius,\n height: params.height,\n maxAcceleration: params.maxAcceleration,\n maxSpeed: params.maxSpeed,\n collisionQueryRange: params.collisionQueryRange,\n pathOptimizationRange: params.pathOptimizationRange,\n separationWeight: params.separationWeight,\n updateFlags: params.updateFlags ?? 7,\n obstacleAvoidanceType: params.obstacleAvoidanceType ?? 0,\n queryFilterType: params.queryFilterType ?? 0,\n userData: 0,\n };\n const agent = crowd._crowd.addAgent({ x: position.x, y: position.y, z: position.z }, agentParams);\n return agent.agentIndex;\n}\n\n/** Get the current world position of an agent. */\nexport function getAgentPosition(crowd: NavCrowd, index: number): Vec3 {\n const p = crowd._crowd.getAgent(index)?.position();\n return p ? { x: p.x, y: p.y, z: p.z } : { x: 0, y: 0, z: 0 };\n}\n\n/** Get the current world-space velocity of an agent. */\nexport function getAgentVelocity(crowd: NavCrowd, index: number): Vec3 {\n const v = crowd._crowd.getAgent(index)?.velocity();\n return v ? { x: v.x, y: v.y, z: v.z } : { x: 0, y: 0, z: 0 };\n}\n\n/** Request the agent to move toward a world target (constrained by navmesh). */\nexport function agentGoto(crowd: NavCrowd, index: number, destination: Vec3): void {\n crowd._crowd.getAgent(index)?.requestMoveTarget(destination);\n}\n\n/** Advance the crowd simulation by `dt` seconds. */\nexport function updateNavCrowd(crowd: NavCrowd, dt: number): void {\n crowd._crowd.update(dt);\n}\n\n// ─── Random queries ──────────────────────────────────────────────────\n\n/**\n * Return a random point on the navmesh inside a circle of `radius` around `position`.\n * Determinism: seeded by Recast's internal RNG; call `setNavigationRandomSeed`\n * to make results reproducible across runs.\n */\nexport function findRandomPointAroundCircle(plugin: NavigationPlugin, position: Vec3, radius: number): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findRandomPointAroundCircle(position, radius, { halfExtents: _tmpHalfExtents });\n return { x: res.randomPoint.x, y: res.randomPoint.y, z: res.randomPoint.z };\n}\n\n/** Return any random point on the navmesh. */\nexport function findRandomPoint(plugin: NavigationPlugin): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findRandomPoint();\n return { x: res.randomPoint.x, y: res.randomPoint.y, z: res.randomPoint.z };\n}\n\n/** Set the seed used by Recast's randomized queries (e.g. `findRandomPointAroundCircle`). */\nexport function setNavigationRandomSeed(plugin: NavigationPlugin, seed: number): void {\n plugin._recast.setRandomSeed(seed);\n}\n\n/** Get the current seed used by Recast's randomized queries. */\nexport function getNavigationRandomSeed(plugin: NavigationPlugin): number {\n return plugin._recast.getRandomSeed();\n}\n\n// ─── Raycast ────────────────────────────────────────────────────────\n\n/**\n * Cast a 'walkability' ray on the navmesh from `start` to `end`.\n * Matches BJS Addons semantics: `hit` is true only when `0 < t < 1` and\n * `hitPoint` is the linear interpolation between start and end at parameter t.\n *\n * Recast's raycast ignores the y component of the end position (2D check).\n */\nexport function raycast(plugin: NavigationPlugin, start: Vec3, end: Vec3): { hit: boolean; hitPoint?: Vec3 } {\n _assertReady(plugin);\n const q = plugin._navMeshQuery;\n const nearest = q.findNearestPoly(start, { halfExtents: _tmpHalfExtents });\n if (!nearest.success || nearest.nearestRef === 0) {\n return { hit: false };\n }\n const r = q.raycast(nearest.nearestRef, start, end);\n const t = r?.t ?? 0;\n if (!(t > 0 && t < 1)) {\n return { hit: false };\n }\n return {\n hit: true,\n hitPoint: {\n x: start.x + (end.x - start.x) * t,\n y: start.y + (end.y - start.y) * t,\n z: start.z + (end.z - start.z) * t,\n },\n };\n}\n\n// ─── Obstacles (tile-cache navmeshes only) ───────────────────────────\n\n/**\n * Add a box obstacle to a tile-cache navmesh. The navmesh must have been\n * built with `maxObstacles > 0`. The tile cache is fully updated before\n * returning (matching BJS Addons default behavior).\n *\n * @param halfExtents - box half-size on each axis\n * @param angle - rotation around the Y axis, in radians\n */\nexport function addBoxObstacle(plugin: NavigationPlugin, position: Vec3, halfExtents: Vec3, angle: number): ObstacleHandle | null {\n _assertTileCache(plugin);\n const r = plugin._tileCache.addBoxObstacle(position, halfExtents, angle);\n if (!r.success) {\n return null;\n }\n _waitForFullTileCacheUpdate(plugin);\n return { _obstacle: r.obstacle };\n}\n\n/**\n * Add a cylinder obstacle to a tile-cache navmesh.\n *\n * @param radius - cylinder radius\n * @param height - cylinder height\n */\nexport function addCylinderObstacle(plugin: NavigationPlugin, position: Vec3, radius: number, height: number): ObstacleHandle | null {\n _assertTileCache(plugin);\n const r = plugin._tileCache.addCylinderObstacle(position, radius, height);\n if (!r.success) {\n return null;\n }\n _waitForFullTileCacheUpdate(plugin);\n return { _obstacle: r.obstacle };\n}\n\n/** Remove an obstacle previously added by `addBoxObstacle` / `addCylinderObstacle`. */\nexport function removeObstacle(plugin: NavigationPlugin, obstacle: ObstacleHandle): void {\n _assertTileCache(plugin);\n plugin._tileCache.removeObstacle(obstacle._obstacle);\n _waitForFullTileCacheUpdate(plugin);\n}\n\n/** Run `tileCache.update()` until all pending obstacle requests are resolved. */\nexport function updateNavMeshObstacles(plugin: NavigationPlugin): void {\n _assertTileCache(plugin);\n _waitForFullTileCacheUpdate(plugin);\n}\n\nfunction _waitForFullTileCacheUpdate(plugin: NavigationPlugin): void {\n let upToDate = false;\n while (!upToDate) {\n const r = plugin._tileCache.update(plugin._navMesh);\n upToDate = r.upToDate;\n }\n}\n\nfunction _assertTileCache(plugin: NavigationPlugin): void {\n _assertReady(plugin);\n if (!plugin._tileCache) {\n throw new Error(\"Navmesh has no tile cache. Build with `maxObstacles > 0` to enable obstacles.\");\n }\n}\n"],"names":["result"],"mappings":"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"}
1
+ {"version":3,"file":"navigation.js","sources":["../../../src/navigation/navigation.ts"],"sourcesContent":["/**\n * Recast Navigation V2 integration for Babylon Lite.\n *\n * Pure-state interfaces + standalone factory functions, matching Lite conventions.\n * The recast wasm is loaded lazily inside `createNavigationPluginAsync` so scenes\n * that do not use navigation pay zero bundle cost.\n *\n * Usage:\n * ```ts\n * const nav = await createNavigationPluginAsync();\n * createNavMesh(nav, [ground, sphere, box], params);\n * const debug = createDebugNavMeshGeometry(nav);\n * const closest = getClosestPoint(nav, { x, y, z });\n * const crowd = createNavCrowd(nav, 10, 0.1);\n * const idx = addAgent(crowd, spawnPos, agentParams);\n * updateNavCrowd(crowd, 1 / 60);\n * ```\n *\n * For obstacles (tile-cache navmesh):\n * ```ts\n * createNavMesh(nav, [...], { ..., maxObstacles: 32, tileSize: 32 });\n * const ref = addBoxObstacle(nav, { x, y, z }, { x: 1, y: 1, z: 1 }, angle);\n * removeObstacle(nav, ref);\n * ```\n *\n * For off-mesh connections:\n * ```ts\n * createNavMesh(nav, [...], { ..., offMeshConnections: [...] });\n * ```\n *\n * For raycast:\n * ```ts\n * const r = raycast(nav, start, end);\n * if (r.hit) console.log(r.hitPoint);\n * ```\n */\n\nimport { F32, U32 } from \"../engine/typed-arrays.js\";\nimport type { Vec3 } from \"../math/types.js\";\nimport type { Mesh } from \"../mesh/mesh.js\";\n\n// ─── Public types ────────────────────────────────────────────────────\n\n/** NavMesh build parameters (Recast solo / tiled / tile-cache navmesh config). */\nexport interface NavMeshParameters {\n cs?: number;\n ch?: number;\n walkableSlopeAngle?: number;\n walkableHeight?: number;\n walkableClimb?: number;\n walkableRadius?: number;\n maxEdgeLen?: number;\n maxSimplificationError?: number;\n minRegionArea?: number;\n mergeRegionArea?: number;\n maxVertsPerPoly?: number;\n detailSampleDist?: number;\n detailSampleMaxError?: number;\n /** Skip reversing winding when extracting positions (right-handed input). */\n doNotReverseIndices?: boolean;\n /** Tile size for tiled / tile-cache navmesh. Recommended 32-64 for tile cache. */\n tileSize?: number;\n /**\n * Maximum number of obstacles. If `> 0` the navmesh is built with a tile cache\n * so obstacles can be added/removed dynamically.\n */\n maxObstacles?: number;\n /** Expected layers per tile for tile-cache navmesh. Default 1. */\n expectedLayersPerTile?: number;\n /** Off-mesh connection segments (teleports) baked into the navmesh. */\n offMeshConnections?: OffMeshConnection[];\n /** Keep intermediates for debug visualization. */\n keepIntermediates?: boolean;\n}\n\n/** Off-mesh connection (teleport segment) baked into the navmesh. */\nexport interface OffMeshConnection {\n startPosition: Vec3;\n endPosition: Vec3;\n radius: number;\n bidirectional: boolean;\n /** @defaultValue 0 */\n area?: number;\n /** @defaultValue 1 */\n flags?: number;\n userId?: number;\n}\n\n/** Crowd agent parameters. */\nexport interface AgentParameters {\n radius: number;\n height: number;\n maxAcceleration: number;\n maxSpeed: number;\n collisionQueryRange: number;\n pathOptimizationRange: number;\n separationWeight: number;\n updateFlags?: number;\n obstacleAvoidanceType?: number;\n queryFilterType?: number;\n reachRadius?: number;\n}\n\n/** A single mesh source for navmesh construction. */\nexport interface NavMeshSource {\n positions: ArrayLike<number>;\n indices: ArrayLike<number>;\n}\n\n/** Pure-state handle for the navigation plugin. */\nexport interface NavigationPlugin {\n /** @internal */ readonly _recast: any;\n /** @internal */ readonly _generators: any;\n /** @internal */ _navMesh?: any;\n /** @internal */ _navMeshQuery?: any;\n /** @internal */ _tileCache?: any;\n}\n\n/** Opaque handle returned by `addBoxObstacle` / `addCylinderObstacle`. */\nexport interface ObstacleHandle {\n /** @internal */ readonly _obstacle: any;\n}\n\n/** Pure-state handle for a crowd. */\nexport interface NavCrowd {\n /** @internal */ readonly _plugin: NavigationPlugin;\n /** @internal */ readonly _crowd: any;\n}\n\n// ─── Factory ─────────────────────────────────────────────────────────\n\nlet _coreModule: any = null;\nlet _generatorsModule: any = null;\nlet _initPromise: Promise<void> | null = null;\n\nasync function _ensureRecast(locateFile?: (url: string) => string): Promise<{ core: any; gens: any }> {\n if (!_coreModule || !_generatorsModule) {\n if (!_initPromise) {\n _initPromise = (async () => {\n const core = await import(\"@recast-navigation/core\");\n const gens = await import(\"@recast-navigation/generators\");\n if (locateFile) {\n const wasmFactory = (await import(\"@recast-navigation/wasm/wasm\")).default;\n // core.init types impl as typeof Recast but calls it as impl() at runtime;\n // bind pre-fills locateFile and cast to satisfy the declaration.\n await core.init(wasmFactory.bind(null, { locateFile }) as typeof wasmFactory);\n } else {\n await core.init();\n }\n _coreModule = core;\n _generatorsModule = gens;\n })();\n }\n await _initPromise;\n }\n return { core: _coreModule, gens: _generatorsModule };\n}\n\n/**\n * Create a navigation plugin. Loads the Recast wasm internally on first call;\n * subsequent calls reuse the loaded module.\n *\n * Pass `locateFile` to serve the wasm from a public path instead of bundling\n * it inline — same pattern as `HavokPhysics({ locateFile: () => \"/HavokPhysics.wasm\" })`.\n *\n * @example\n * ```ts\n * const nav = await createNavigationPluginAsync({ locateFile: () => \"/recast-navigation.wasm\" });\n * ```\n */\nexport async function createNavigationPluginAsync(options?: { locateFile?: (url: string) => string }): Promise<NavigationPlugin> {\n const { core, gens } = await _ensureRecast(options?.locateFile);\n return {\n _recast: core,\n _generators: gens,\n };\n}\n\n/**\n * Release the native navmesh resources a plugin holds: the navmesh query, the navmesh, and the tile cache (if\n * one was built). These are Detour objects living on the wasm heap — they are NOT reclaimed by JS garbage\n * collection, so dropping the plugin reference alone leaks them. Call this when a navmesh is rebuilt or a\n * plugin is discarded. Idempotent and safe on a plugin that never built a navmesh.\n */\nexport function disposeNavigationPlugin(plugin: NavigationPlugin): void {\n const internal = plugin as { _navMesh?: any; _navMeshQuery?: any; _tileCache?: any };\n internal._navMeshQuery?.destroy?.();\n internal._tileCache?.destroy?.();\n internal._navMesh?.destroy?.();\n internal._navMeshQuery = undefined;\n internal._tileCache = undefined;\n internal._navMesh = undefined;\n}\n\n// ─── NavMesh ─────────────────────────────────────────────────────────\n\n/**\n * Build a navmesh from one or more meshes. Each mesh's CPU positions are\n * transformed by its worldMatrix (matching BJS GetPositionsAndIndices), merged\n * into a single stream, and index winding is reversed (left-handed convention)\n * unless `doNotReverseIndices` is set.\n *\n * - Solo navmesh by default.\n * - If `maxObstacles > 0`, builds a tile-cache navmesh so obstacles can be\n * added/removed dynamically.\n * - Off-mesh connections can be supplied for either solo or tile-cache.\n */\nexport function createNavMesh(plugin: NavigationPlugin, meshes: Mesh[], params: NavMeshParameters): void {\n const { positions, indices } = _mergeMeshes(meshes, params.doNotReverseIndices === true);\n _createNavMeshFromMerged(plugin, positions, indices, params);\n}\n\n/** Build a navmesh from raw CPU geometry sources. This is the non-rendering twin of\n * `createNavMesh`: callers that already own procedural navigation geometry can avoid\n * creating hidden GPU meshes just to feed Recast. */\nexport function createNavMeshFromSources(plugin: NavigationPlugin, sources: NavMeshSource[], params: NavMeshParameters): void {\n const { positions, indices } = _mergeSources(sources, params.doNotReverseIndices === true);\n _createNavMeshFromMerged(plugin, positions, indices, params);\n}\n\nfunction _createNavMeshFromMerged(plugin: NavigationPlugin, positions: Float32Array, indices: Uint32Array, params: NavMeshParameters): void {\n const cfg: Record<string, unknown> = {};\n if (params.cs !== undefined) {\n cfg.cs = params.cs;\n }\n if (params.ch !== undefined) {\n cfg.ch = params.ch;\n }\n if (params.walkableSlopeAngle !== undefined) {\n cfg.walkableSlopeAngle = params.walkableSlopeAngle;\n }\n if (params.walkableHeight !== undefined) {\n cfg.walkableHeight = params.walkableHeight;\n }\n if (params.walkableClimb !== undefined) {\n cfg.walkableClimb = params.walkableClimb;\n }\n if (params.walkableRadius !== undefined) {\n cfg.walkableRadius = params.walkableRadius;\n }\n if (params.maxEdgeLen !== undefined) {\n cfg.maxEdgeLen = params.maxEdgeLen;\n }\n if (params.maxSimplificationError !== undefined) {\n cfg.maxSimplificationError = params.maxSimplificationError;\n }\n if (params.minRegionArea !== undefined) {\n cfg.minRegionArea = params.minRegionArea;\n }\n if (params.mergeRegionArea !== undefined) {\n cfg.mergeRegionArea = params.mergeRegionArea;\n }\n if (params.maxVertsPerPoly !== undefined) {\n cfg.maxVertsPerPoly = params.maxVertsPerPoly;\n }\n if (params.detailSampleDist !== undefined) {\n cfg.detailSampleDist = params.detailSampleDist;\n }\n if (params.detailSampleMaxError !== undefined) {\n cfg.detailSampleMaxError = params.detailSampleMaxError;\n }\n if (params.offMeshConnections !== undefined && params.offMeshConnections.length > 0) {\n cfg.offMeshConnections = params.offMeshConnections;\n }\n\n const internal = plugin as { _navMesh: any; _navMeshQuery: any; _tileCache?: any };\n const needsTileCache = (params.maxObstacles ?? 0) > 0;\n const needsTiled = (params.tileSize ?? 0) > 0;\n\n if (needsTileCache) {\n // Tile cache config: requires tileSize, expectedLayersPerTile, maxObstacles,\n // and a tile cache mesh process. Mirrors BJS Addons CreateTileCacheNavMeshConfig.\n cfg.tileSize = params.tileSize ?? 32;\n cfg.expectedLayersPerTile = params.expectedLayersPerTile ?? 1;\n cfg.maxObstacles = params.maxObstacles!;\n\n if (params.offMeshConnections !== undefined && params.offMeshConnections.length > 0) {\n cfg.tileCacheMeshProcess = _createDefaultTileCacheMeshProcess(plugin._recast, params.offMeshConnections);\n }\n\n const result = plugin._generators.generateTileCache(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh (tile cache) failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._tileCache = result.tileCache;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n return;\n }\n\n if (needsTiled) {\n cfg.tileSize = params.tileSize;\n const result = plugin._generators.generateTiledNavMesh(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh (tiled) failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n return;\n }\n\n const result = plugin._generators.generateSoloNavMesh(positions, indices, cfg, params.keepIntermediates === true);\n if (!result.success) {\n throw new Error(`createNavMesh failed: ${result.error}`);\n }\n internal._navMesh = result.navMesh;\n internal._navMeshQuery = new plugin._recast.NavMeshQuery(result.navMesh);\n}\n\n/**\n * Default tile-cache mesh process that copies area/flags from input polys and\n * appends off-mesh connections. Mirrors BJS Addons CreateDefaultTileCacheMeshProcess.\n */\nfunction _createDefaultTileCacheMeshProcess(recast: any, offMeshConnections: OffMeshConnection[]): any {\n const area = 0;\n const flags = 1;\n return new recast.TileCacheMeshProcess((navMeshCreateParams: any, polyAreas: any, polyFlags: any) => {\n for (let i = 0; i < navMeshCreateParams.polyCount(); ++i) {\n polyAreas.set(i, area);\n polyFlags.set(i, flags);\n }\n if (offMeshConnections.length > 0) {\n navMeshCreateParams.setOffMeshConnections(offMeshConnections);\n }\n });\n}\n\nfunction _mergeMeshes(meshes: Mesh[], doNotReverseIndices: boolean): { positions: Float32Array; indices: Uint32Array } {\n let totalVerts = 0;\n let totalIdx = 0;\n for (const mesh of meshes) {\n if (!mesh._cpuPositions || !mesh._cpuIndices) {\n throw new Error(`Mesh \"${mesh.name}\" missing CPU geometry for navmesh`);\n }\n totalVerts += mesh._cpuPositions.length;\n totalIdx += mesh._cpuIndices.length;\n }\n const positions = new F32(totalVerts);\n const indices = new U32(totalIdx);\n\n let pOff = 0;\n let iOff = 0;\n let vertBase = 0;\n for (const mesh of meshes) {\n const src = mesh._cpuPositions!;\n const wm = mesh.worldMatrix;\n\n for (let i = 0; i < src.length; i += 3) {\n const x = src[i]!,\n y = src[i + 1]!,\n z = src[i + 2]!;\n positions[pOff++] = x * wm[0]! + y * wm[4]! + z * wm[8]! + wm[12]!;\n positions[pOff++] = x * wm[1]! + y * wm[5]! + z * wm[9]! + wm[13]!;\n positions[pOff++] = x * wm[2]! + y * wm[6]! + z * wm[10]! + wm[14]!;\n }\n\n const meshIdx = mesh._cpuIndices!;\n const n = meshIdx.length;\n if (doNotReverseIndices) {\n for (let i = 0; i < n; i++) {\n indices[iOff++] = meshIdx[i]! + vertBase;\n }\n } else {\n for (let i = 0; i < n; i += 3) {\n indices[iOff++] = meshIdx[i]! + vertBase;\n indices[iOff++] = meshIdx[i + 2]! + vertBase;\n indices[iOff++] = meshIdx[i + 1]! + vertBase;\n }\n }\n vertBase += src.length / 3;\n }\n\n return { positions, indices };\n}\n\nfunction _mergeSources(sources: NavMeshSource[], doNotReverseIndices: boolean): { positions: Float32Array; indices: Uint32Array } {\n let totalVerts = 0;\n let totalIdx = 0;\n for (const source of sources) {\n totalVerts += source.positions.length;\n totalIdx += source.indices.length;\n }\n const positions = new F32(totalVerts);\n const indices = new U32(totalIdx);\n\n let pOff = 0;\n let iOff = 0;\n let vertBase = 0;\n for (const source of sources) {\n for (let i = 0; i < source.positions.length; i++) {\n positions[pOff++] = source.positions[i]!;\n }\n if (doNotReverseIndices) {\n for (let i = 0; i < source.indices.length; i++) {\n indices[iOff++] = source.indices[i]! + vertBase;\n }\n } else {\n for (let i = 0; i < source.indices.length; i += 3) {\n indices[iOff++] = source.indices[i]! + vertBase;\n indices[iOff++] = source.indices[i + 2]! + vertBase;\n indices[iOff++] = source.indices[i + 1]! + vertBase;\n }\n }\n vertBase += source.positions.length / 3;\n }\n\n return { positions, indices };\n}\n\n// ─── Debug navmesh geometry ──────────────────────────────────────────\n\n/**\n * Extract debug visualization geometry from the generated navmesh.\n * Faces are detached (each triangle gets its own 3 vertices) and per-vertex\n * normals are set to the face normal — yielding flat shading without the need\n * for a separate normal-computation pass in callers.\n * Returns positions, normals, indices, and a hash of the positions for\n * cross-engine parity checks.\n */\nexport function createDebugNavMeshGeometry(plugin: NavigationPlugin): { positions: Float32Array; normals: Float32Array; indices: Uint32Array; positionsHash: number } {\n if (!plugin._navMesh) {\n throw new Error(\"No navmesh generated. Call createNavMesh first.\");\n }\n const [positionsArr, indicesArr] = plugin._recast.getNavMeshPositionsAndIndices(plugin._navMesh);\n const triCount = (indicesArr.length / 3) | 0;\n const vertCount = triCount * 3;\n const positions = new F32(vertCount * 3);\n const normals = new F32(vertCount * 3);\n const indices = new U32(vertCount);\n\n for (let t = 0; t < triCount; t++) {\n // Recast outputs triangles with original winding such that the face\n // normal computed from (i0,i1,i2) order points UP. We reverse the\n // stored winding to match BJS CreateDebugNavMesh for back-face culling\n // parity (stored as i0,i2,i1) — but compute the face normal from the\n // ORIGINAL winding so it still points UP.\n const i0 = indicesArr[t * 3]! * 3;\n const i1Orig = indicesArr[t * 3 + 1]! * 3;\n const i2Orig = indicesArr[t * 3 + 2]! * 3;\n\n const ax = positionsArr[i0]!,\n ay = positionsArr[i0 + 1]!,\n az = positionsArr[i0 + 2]!;\n const b1x = positionsArr[i1Orig]!,\n b1y = positionsArr[i1Orig + 1]!,\n b1z = positionsArr[i1Orig + 2]!;\n const c1x = positionsArr[i2Orig]!,\n c1y = positionsArr[i2Orig + 1]!,\n c1z = positionsArr[i2Orig + 2]!;\n\n const e1x = b1x - ax,\n e1y = b1y - ay,\n e1z = b1z - az;\n const e2x = c1x - ax,\n e2y = c1y - ay,\n e2z = c1z - az;\n let nx = e1y * e2z - e1z * e2y;\n let ny = e1z * e2x - e1x * e2z;\n let nz = e1x * e2y - e1y * e2x;\n const len = Math.hypot(nx, ny, nz);\n if (len > 0) {\n nx /= len;\n ny /= len;\n nz /= len;\n }\n\n // Store positions in reversed winding (i0, i2, i1) for back-face parity.\n const v = t * 9;\n positions[v] = ax;\n positions[v + 1] = ay;\n positions[v + 2] = az;\n positions[v + 3] = c1x;\n positions[v + 4] = c1y;\n positions[v + 5] = c1z;\n positions[v + 6] = b1x;\n positions[v + 7] = b1y;\n positions[v + 8] = b1z;\n\n normals[v] = nx;\n normals[v + 1] = ny;\n normals[v + 2] = nz;\n normals[v + 3] = nx;\n normals[v + 4] = ny;\n normals[v + 5] = nz;\n normals[v + 6] = nx;\n normals[v + 7] = ny;\n normals[v + 8] = nz;\n\n const idx = t * 3;\n indices[idx] = idx;\n indices[idx + 1] = idx + 1;\n indices[idx + 2] = idx + 2;\n }\n\n let hash = 0x811c9dc5;\n for (let i = 0; i < positions.length; i++) {\n hash ^= Math.round(positions[i]! * 100000);\n hash = Math.imul(hash, 0x01000193);\n }\n\n return { positions, normals, indices, positionsHash: hash };\n}\n\n// ─── Queries ─────────────────────────────────────────────────────────\n\nconst _tmpHalfExtents = { x: 1, y: 1, z: 1 };\n\n/** Snap a position to the closest point on the navmesh. */\nexport function getClosestPoint(plugin: NavigationPlugin, position: Vec3): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findClosestPoint(position, { halfExtents: _tmpHalfExtents });\n return { x: res.point.x, y: res.point.y, z: res.point.z };\n}\n\n/** Snap a position to the closest point on the navmesh within a search box, or null when no part of the\n * mesh lies inside it. Unlike getClosestPoint — which does not inspect the query's success flag, so a\n * position outside its fixed ±1-unit box returns an UNSPECIFIED point (whatever the query left in its\n * output) rather than signalling a miss — the search extent is explicit here and a failed query is\n * reported as null, so callers can distinguish \"snapped\" from \"nothing nearby\". */\nexport function findClosestPointWithin(plugin: NavigationPlugin, position: Vec3, halfExtents: Vec3): Vec3 | null {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findClosestPoint(position, { halfExtents });\n if (!res.success) {\n return null;\n }\n return { x: res.point.x, y: res.point.y, z: res.point.z };\n}\n\n/** Compute a path between two world positions, snapped to the navmesh. */\nexport function computePath(plugin: NavigationPlugin, start: Vec3, end: Vec3): Vec3[] {\n _assertReady(plugin);\n const q = plugin._navMeshQuery;\n const startSnap = q.findClosestPoint(start, { halfExtents: _tmpHalfExtents });\n const endSnap = q.findClosestPoint(end, { halfExtents: _tmpHalfExtents });\n const res = q.computePath(startSnap.point, endSnap.point);\n if (!res.success) {\n return [];\n }\n const out: Vec3[] = [];\n for (const p of res.path) {\n out.push({ x: p.x, y: p.y, z: p.z });\n }\n return out;\n}\n\nfunction _assertReady(plugin: NavigationPlugin): void {\n if (!plugin._navMesh || !plugin._navMeshQuery) {\n throw new Error(\"Navmesh not ready. Call createNavMesh first.\");\n }\n}\n\n// ─── Crowd ───────────────────────────────────────────────────────────\n\n/**\n * Create a crowd attached to the navmesh. The crowd is NOT auto-updated;\n * call `updateNavCrowd(crowd, dt)` each frame for full determinism.\n */\nexport function createNavCrowd(plugin: NavigationPlugin, maxAgents: number, maxAgentRadius: number): NavCrowd {\n _assertReady(plugin);\n const Crowd = plugin._recast.Crowd;\n const crowd = new Crowd(plugin._navMesh, { maxAgents, maxAgentRadius });\n return { _plugin: plugin, _crowd: crowd };\n}\n\n/** Add an agent to the crowd. Returns the agent index. */\nexport function addAgent(crowd: NavCrowd, position: Vec3, params: AgentParameters): number {\n const agentParams = {\n radius: params.radius,\n height: params.height,\n maxAcceleration: params.maxAcceleration,\n maxSpeed: params.maxSpeed,\n collisionQueryRange: params.collisionQueryRange,\n pathOptimizationRange: params.pathOptimizationRange,\n separationWeight: params.separationWeight,\n updateFlags: params.updateFlags ?? 7,\n obstacleAvoidanceType: params.obstacleAvoidanceType ?? 0,\n queryFilterType: params.queryFilterType ?? 0,\n userData: 0,\n };\n const agent = crowd._crowd.addAgent({ x: position.x, y: position.y, z: position.z }, agentParams);\n return agent.agentIndex;\n}\n\n/** Get the current world position of an agent. */\nexport function getAgentPosition(crowd: NavCrowd, index: number): Vec3 {\n const p = crowd._crowd.getAgent(index)?.position();\n return p ? { x: p.x, y: p.y, z: p.z } : { x: 0, y: 0, z: 0 };\n}\n\n/** Get the current world-space velocity of an agent. */\nexport function getAgentVelocity(crowd: NavCrowd, index: number): Vec3 {\n const v = crowd._crowd.getAgent(index)?.velocity();\n return v ? { x: v.x, y: v.y, z: v.z } : { x: 0, y: 0, z: 0 };\n}\n\n/** Request the agent to move toward a world target (constrained by navmesh). */\nexport function agentGoto(crowd: NavCrowd, index: number, destination: Vec3): void {\n crowd._crowd.getAgent(index)?.requestMoveTarget(destination);\n}\n\n/** Advance the crowd simulation by `dt` seconds. */\nexport function updateNavCrowd(crowd: NavCrowd, dt: number): void {\n crowd._crowd.update(dt);\n}\n\n// ─── Random queries ──────────────────────────────────────────────────\n\n/**\n * Return a random point on the navmesh inside a circle of `radius` around `position`.\n * Determinism: seeded by Recast's internal RNG; call `setNavigationRandomSeed`\n * to make results reproducible across runs.\n */\nexport function findRandomPointAroundCircle(plugin: NavigationPlugin, position: Vec3, radius: number): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findRandomPointAroundCircle(position, radius, { halfExtents: _tmpHalfExtents });\n return { x: res.randomPoint.x, y: res.randomPoint.y, z: res.randomPoint.z };\n}\n\n/** Return any random point on the navmesh. */\nexport function findRandomPoint(plugin: NavigationPlugin): Vec3 {\n _assertReady(plugin);\n const res = plugin._navMeshQuery.findRandomPoint();\n return { x: res.randomPoint.x, y: res.randomPoint.y, z: res.randomPoint.z };\n}\n\n/** Set the seed used by Recast's randomized queries (e.g. `findRandomPointAroundCircle`). */\nexport function setNavigationRandomSeed(plugin: NavigationPlugin, seed: number): void {\n plugin._recast.setRandomSeed(seed);\n}\n\n/** Get the current seed used by Recast's randomized queries. */\nexport function getNavigationRandomSeed(plugin: NavigationPlugin): number {\n return plugin._recast.getRandomSeed();\n}\n\n// ─── Raycast ────────────────────────────────────────────────────────\n\n/**\n * Cast a 'walkability' ray on the navmesh from `start` to `end`.\n * Matches BJS Addons semantics: `hit` is true only when `0 < t < 1` and\n * `hitPoint` is the linear interpolation between start and end at parameter t.\n *\n * Recast's raycast ignores the y component of the end position (2D check).\n */\nexport function raycast(plugin: NavigationPlugin, start: Vec3, end: Vec3): { hit: boolean; hitPoint?: Vec3 } {\n _assertReady(plugin);\n const q = plugin._navMeshQuery;\n const nearest = q.findNearestPoly(start, { halfExtents: _tmpHalfExtents });\n if (!nearest.success || nearest.nearestRef === 0) {\n return { hit: false };\n }\n const r = q.raycast(nearest.nearestRef, start, end);\n const t = r?.t ?? 0;\n if (!(t > 0 && t < 1)) {\n return { hit: false };\n }\n return {\n hit: true,\n hitPoint: {\n x: start.x + (end.x - start.x) * t,\n y: start.y + (end.y - start.y) * t,\n z: start.z + (end.z - start.z) * t,\n },\n };\n}\n\n/**\n * Strict walkability ray: `true` when the straight segment from `start` to `end` is NOT provably\n * clear on the navmesh. Unlike {@link raycast} (BJS Addons parity: `hit` only for `0 < t < 1`),\n * an unresolvable start polygon and a wall at the very origin (Detour reports `t = 0`, which\n * happens whenever the probe origin lies on a boundary edge - e.g. a funnel corner) are BLOCKED:\n * \"cannot prove clear\" is blocked. Recast's raycast ignores the y component (2D check).\n */\nexport function navRayBlocked(plugin: NavigationPlugin, start: Vec3, end: Vec3): boolean {\n _assertReady(plugin);\n const q = plugin._navMeshQuery;\n const nearest = q.findNearestPoly(start, { halfExtents: _tmpHalfExtents });\n if (!nearest.success || nearest.nearestRef === 0) {\n return true;\n }\n const r = q.raycast(nearest.nearestRef, start, end);\n // Detour t semantics: t in [0,1] = wall at parameter t (0 = blocked at the origin);\n // Finite FLT_MAX = the end was reached unobstructed. Fail closed: only a\n // successful query with that \"reached the end\" value proves clear.\n const t = r?.t;\n return !(r?.success === true && typeof t === \"number\" && Number.isFinite(t) && t > 1);\n}\n\n// ─── Obstacles (tile-cache navmeshes only) ───────────────────────────\n\n/**\n * Add a box obstacle to a tile-cache navmesh. The navmesh must have been\n * built with `maxObstacles > 0`. The tile cache is fully updated before\n * returning (matching BJS Addons default behavior).\n *\n * @param halfExtents - box half-size on each axis\n * @param angle - rotation around the Y axis, in radians\n */\nexport function addBoxObstacle(plugin: NavigationPlugin, position: Vec3, halfExtents: Vec3, angle: number): ObstacleHandle | null {\n _assertTileCache(plugin);\n const r = plugin._tileCache.addBoxObstacle(position, halfExtents, angle);\n if (!r.success) {\n return null;\n }\n _waitForFullTileCacheUpdate(plugin);\n return { _obstacle: r.obstacle };\n}\n\n/**\n * Add a cylinder obstacle to a tile-cache navmesh.\n *\n * @param radius - cylinder radius\n * @param height - cylinder height\n */\nexport function addCylinderObstacle(plugin: NavigationPlugin, position: Vec3, radius: number, height: number): ObstacleHandle | null {\n _assertTileCache(plugin);\n const r = plugin._tileCache.addCylinderObstacle(position, radius, height);\n if (!r.success) {\n return null;\n }\n _waitForFullTileCacheUpdate(plugin);\n return { _obstacle: r.obstacle };\n}\n\n/** Remove an obstacle previously added by `addBoxObstacle` / `addCylinderObstacle`. */\nexport function removeObstacle(plugin: NavigationPlugin, obstacle: ObstacleHandle): void {\n _assertTileCache(plugin);\n plugin._tileCache.removeObstacle(obstacle._obstacle);\n _waitForFullTileCacheUpdate(plugin);\n}\n\n/** Run `tileCache.update()` until all pending obstacle requests are resolved. */\nexport function updateNavMeshObstacles(plugin: NavigationPlugin): void {\n _assertTileCache(plugin);\n _waitForFullTileCacheUpdate(plugin);\n}\n\nfunction _waitForFullTileCacheUpdate(plugin: NavigationPlugin): void {\n let upToDate = false;\n while (!upToDate) {\n const r = plugin._tileCache.update(plugin._navMesh);\n upToDate = r.upToDate;\n }\n}\n\nfunction _assertTileCache(plugin: NavigationPlugin): void {\n _assertReady(plugin);\n if (!plugin._tileCache) {\n throw new Error(\"Navmesh has no tile cache. Build with `maxObstacles > 0` to enable obstacles.\");\n }\n}\n"],"names":["result"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { F32 } from '../engine/typed-arrays.js';
2
+ import { _cameraChangeKey } from '../camera/camera.js';
2
3
  import { createRenderTarget, disposeRenderTarget, buildRenderTarget } from '../engine/render-target.js';
3
4
  import { createPostProcessTask } from '../frame-graph/post-process-task.js';
4
5
 
@@ -96,7 +97,7 @@ function createTaaPostProcessTask(config, engine, scene) {
96
97
  },
97
98
  execute() {
98
99
  const cam = task._sourceRenderTask.scene.camera;
99
- const camVer = cam ? cam.worldMatrixVersion : 0;
100
+ const camVer = cam ? _cameraChangeKey(cam) : 0;
100
101
  const moved = camVer !== task._lastCamVer;
101
102
  task._lastCamVer = camVer;
102
103
  const reset = task._firstUpdate || moved && task.disableOnCameraMove;
@@ -1 +1 @@
1
- {"version":3,"file":"taa.js","sources":["../../../src/post-process/taa.ts"],"sourcesContent":["// Temporal Anti-Aliasing (TAA) — a frame-graph post-process task.\n//\n// TAA jitters the camera projection by a sub-pixel Halton offset every frame and\n// accumulates a moving average of consecutive (jittered) frames. Spreading the\n// supersampling over time yields high-quality edge anti-aliasing without rendering\n// the scene multiple times per frame. The accumulated history converges to a\n// supersampled image after a few dozen frames.\n//\n// This task is a pure frame-graph node: add it at the END of a chain whose source\n// render task draws the scene into `sourceTexture`. Each frame it:\n// 1. blend : temp = mix(history, current, factor) (history bound as extra)\n// 2. present : temp -> targetTexture (e.g. the swapchain)\n// 3. historyUpd : temp -> history (becomes next frame's history)\n// 4. advances the Halton sequence and writes the jittered viewProjection into the\n// *source render task's* scene UBO so the NEXT frame renders sub-pixel shifted.\n//\n// `factor` is the blend weight of the current frame (BJS default 0.05). On the first\n// frame and on a camera-move reset it is forced to 1 (output == current) so no stale\n// history bleeds in.\n//\n// The jitter is injected by overwriting only the viewProjection slice (bytes 0..63)\n// of the source task's already-packed scene UBO. The source task's UBO write is\n// cached on the camera's worldMatrixVersion, so with a static camera our jittered\n// matrix survives each frame; when the camera moves the source re-packs a clean\n// matrix (a natural reset) and we set factor=1 for that frame. This needs zero\n// changes to the shared camera / scene-uniform hot path — so scenes that do not use\n// TAA pay nothing.\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget, createRenderTarget, disposeRenderTarget } from \"../engine/render-target.js\";\nimport { createPostProcessTask, type PostProcessTask, type PostProcessTaskSettings } from \"../frame-graph/post-process-task.js\";\nimport type { RenderTask } from \"../frame-graph/render-task.js\";\nimport type { Task } from \"../frame-graph/task.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\n\n/** Configuration for `createTaaPostProcessTask`. */\nexport interface TaaPostProcessTaskConfig extends PostProcessTaskSettings {\n /** The render task that draws the scene into `sourceTexture`. TAA jitters this\n * task's camera projection each frame (mirrors BJS `FrameGraphTAATask.objectRendererTask`). */\n sourceRenderTask: RenderTask;\n /** Blend weight of the current frame against the accumulated history (default: 0.05). */\n factor?: number;\n /** Number of jitter samples in the Halton sequence (default: 8). */\n samples?: number;\n /** Force a one-frame reset (output == current) whenever the camera moves (default: true).\n * Avoids ghosting while the view changes. */\n disableOnCameraMove?: boolean;\n}\n\n/** A Temporal Anti-Aliasing post-process task: accumulates jittered frames into an\n * anti-aliased image. Inject at the end of a frame-graph chain. */\nexport interface TaaPostProcessTask extends Task, PostProcessTaskSettings {\n readonly name: string;\n sourceTexture: RenderTarget;\n targetTexture: RenderTarget | null;\n outputTexture: RenderTarget;\n /** Blend weight of the current frame (smaller = smoother / slower convergence). */\n factor: number;\n /** Number of Halton jitter samples. */\n readonly samples: number;\n /** Reset to the current frame whenever the camera moves. */\n disableOnCameraMove: boolean;\n /** Recompute and upload the blend pass uniforms from current settings. */\n updateUniforms(): void;\n}\n\ninterface TaaTaskInternal extends TaaPostProcessTask {\n _blend: PostProcessTask;\n _present: PostProcessTask;\n _historyUpdate: PostProcessTask;\n _history: RenderTarget;\n _temp: RenderTarget;\n _sourceRenderTask: RenderTask;\n /** Raw Halton offsets in [-0.5, 0.5): [x0,y0, x1,y1, ...]. Scaled per-frame by source size. */\n _halton: Float32Array;\n _haltonIndex: number;\n _jitterScratch: Float32Array;\n _firstUpdate: boolean;\n _lastCamVer: number;\n _factor: number;\n}\n\nconst TAA_HISTORY_TEXTURE_WGSL = `@group(0) @binding(2) var taaHistory:texture_2d<f32>;`;\n\nconst TAA_UNIFORM_WGSL = `struct TaaParams{factor:f32,p0:f32,p1:f32,p2:f32}\n@group(0) @binding(3) var<uniform> taaParams:TaaParams;`;\n\n// mix(history, current, factor): factor=1 -> current only (first frame / reset).\nconst TAA_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{let h=textureSample(taaHistory,sourceSampler,uv);return mix(h,color,taaParams.factor);}`;\n\n// Identity passthrough used by the present + history-update copies.\nconst TAA_COPY_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{return color;}`;\n\n/**\n * Create a Temporal Anti-Aliasing post-process task.\n * @param config - Source texture + source render task, blend factor, sample count.\n * @param engine - The owning engine.\n * @param scene - Optional owning scene.\n * @returns The TAA post-process task. Add it at the end of the frame-graph chain.\n */\nexport function createTaaPostProcessTask(config: TaaPostProcessTaskConfig, engine: EngineContext, scene?: SceneContext): TaaPostProcessTask {\n const name = config.name ?? \"taa\";\n const source = config.sourceTexture;\n const target = config.targetTexture ?? null;\n // Clamp to >= 1: a zero/negative sample count would make `generateHalton` return an\n // empty sequence and `advanceJitter` write NaN jitter offsets into the source UBO.\n const samples = Math.max(1, Math.floor(config.samples ?? 8));\n const sizeRef = source._descriptor.size;\n\n // History accumulates at RGBA16F so the 0.05 moving average does not band on\n // an 8-bit buffer (matches BJS half-float history).\n const history = createRenderTarget({ lbl: `${name}-history`, format: \"rgba16float\", samples: 1, size: sizeRef });\n const temp = createRenderTarget({ lbl: `${name}-temp`, format: \"rgba16float\", samples: 1, size: sizeRef });\n\n const blend = createPostProcessTask(\n {\n name: `${name}-blend`,\n sourceTexture: source,\n // Nearest sampling reads the exact co-located texel of both the current\n // frame and the history (all three targets share a resolution).\n sourceSamplingMode: \"nearest\",\n targetTexture: temp,\n _shader: {\n extraTextureWGSL: TAA_HISTORY_TEXTURE_WGSL,\n extraTextures: [history],\n uniformWGSL: TAA_UNIFORM_WGSL,\n uniformBinding: 3,\n uniformByteLength: 16,\n writeUniforms(data) {\n data[0] = task._factor;\n },\n fragmentWGSL: TAA_FRAGMENT_WGSL,\n },\n },\n engine,\n scene\n );\n const present = createPostProcessTask(\n {\n name: `${name}-present`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: target ?? engine.scRT,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n const historyUpdate = createPostProcessTask(\n {\n name: `${name}-history-update`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: history,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n\n const task: TaaTaskInternal = {\n name,\n engine,\n scene,\n _passes: [],\n sourceTexture: source,\n targetTexture: target,\n outputTexture: target ?? engine.scRT,\n factor: config.factor ?? 0.05,\n samples,\n disableOnCameraMove: config.disableOnCameraMove ?? true,\n _blend: blend,\n _present: present,\n _historyUpdate: historyUpdate,\n _history: history,\n _temp: temp,\n _sourceRenderTask: config.sourceRenderTask,\n _halton: generateHalton(samples),\n _haltonIndex: 0,\n _jitterScratch: new F32(16),\n _firstUpdate: true,\n _lastCamVer: -1,\n _factor: 1,\n record(): void {\n // History + temp are persistent ping-pong buffers: allocate them once\n // (eager), sized to the source, and only reallocate on a real size change.\n // Marking them eager makes the sub-tasks' internal `buildRenderTarget`\n // no-op on them — critical because `historyUpdate` targets `history`, and a\n // rebuild there would destroy the texture `blend`'s bind group references.\n const { width: w, height: h } = resolveSourceSize(task.sourceTexture);\n ensurePersistentTarget(history, engine, w, h);\n ensurePersistentTarget(temp, engine, w, h);\n blend.record();\n present.record();\n historyUpdate.record();\n task._firstUpdate = true;\n task._haltonIndex = 0;\n task._lastCamVer = -1;\n },\n execute(): number {\n const cam = task._sourceRenderTask.scene.camera;\n const camVer = cam ? cam.worldMatrixVersion : 0;\n const moved = camVer !== task._lastCamVer;\n task._lastCamVer = camVer;\n\n // factor=1 on the first frame and on camera-move reset: take the current\n // (un-jittered) frame verbatim, discarding stale history.\n const reset = task._firstUpdate || (moved && task.disableOnCameraMove);\n task._factor = reset ? 1 : task.factor;\n blend.updateUniforms();\n\n let draws = blend.execute?.() ?? 0;\n draws += present.execute?.() ?? 0;\n draws += historyUpdate.execute?.() ?? 0;\n\n task._firstUpdate = false;\n\n // Prepare the NEXT frame's jitter: advance the Halton sequence and write the\n // jittered viewProjection into the source task's UBO. Always done — even on a\n // reset frame — so accumulation starts immediately on the following frame.\n // The blend `factor` reset already prevents stale-history bleed, and a still-\n // moving camera re-packs a clean matrix next frame anyway (overwriting this).\n advanceJitter(task);\n return draws;\n },\n updateUniforms(): void {\n blend.updateUniforms();\n },\n dispose(): void {\n task._passes.length = 0;\n blend.dispose();\n present.dispose();\n historyUpdate.dispose();\n // Clear the eager flag so the persistent buffers are actually freed.\n history._eager = false;\n temp._eager = false;\n disposeRenderTarget(history);\n disposeRenderTarget(temp);\n },\n };\n return task;\n}\n\n/** Allocate (or, on a size change, reallocate) a persistent ping-pong target sized\n * `width`×`height`. The target is marked `_eager` so the post-process sub-tasks'\n * internal `buildRenderTarget` no-ops on it, keeping accumulated history alive across\n * frames and preventing a rebuild from destroying a texture still bound elsewhere. */\nfunction ensurePersistentTarget(rt: RenderTarget, engine: EngineContext, width: number, height: number): void {\n if (rt._eager && rt._width === width && rt._height === height) {\n return;\n }\n rt._eager = false;\n disposeRenderTarget(rt);\n rt._descriptor.size = { width, height };\n buildRenderTarget(rt, engine);\n rt._eager = true;\n}\n\n/** Resolve a render target's pixel size: prefer its allocated dimensions, falling back\n * to the descriptor's surface (multi-surface safe — does not assume the engine canvas)\n * or explicit pixel size before the target has been built. */\nfunction resolveSourceSize(source: RenderTarget): { width: number; height: number } {\n if (source._width > 0 && source._height > 0) {\n return { width: source._width, height: source._height };\n }\n const size = source._descriptor.size;\n if (\"canvas\" in size) {\n return { width: size.canvas.width, height: size.canvas.height };\n }\n return { width: size.width, height: size.height };\n}\n\n/** Generate `samples` 2D Halton offsets (base 2 / base 3) centered on [-0.5, 0.5). */\nfunction generateHalton(samples: number): Float32Array {\n const seq = new F32(samples * 2);\n for (let i = 1; i <= samples; i++) {\n seq[(i - 1) * 2] = halton(i, 2) - 0.5;\n seq[(i - 1) * 2 + 1] = halton(i, 3) - 0.5;\n }\n return seq;\n}\n\nfunction halton(index: number, base: number): number {\n let fraction = 1;\n let result = 0;\n while (index > 0) {\n fraction /= base;\n result += fraction * (index % base);\n index = Math.floor(index / base);\n }\n return result;\n}\n\n/** Advance the Halton sequence and overwrite the source task's viewProjection\n * (column-major bytes 0..63 of its scene UBO) with a sub-pixel jittered matrix. */\nfunction advanceJitter(task: TaaTaskInternal): void {\n const src = task._sourceRenderTask;\n const clean = src._suData;\n const w = task.sourceTexture._width;\n const h = task.sourceTexture._height;\n if (w <= 0 || h <= 0) {\n return;\n }\n\n // NDC sub-pixel offset: one pixel spans 2/size in NDC, so size/2 is the denominator.\n const jx = task._halton[task._haltonIndex]! / (w / 2);\n const jy = task._halton[task._haltonIndex + 1]! / (h / 2);\n task._haltonIndex += 2;\n if (task._haltonIndex >= task._halton.length) {\n task._haltonIndex = 0;\n }\n\n // Translate the projected image by (jx, jy) in NDC: clip.xy += (jx,jy)*clip.w.\n // Column-major: row r, col c lives at c*4+r. Add j*row3 to row0 / row1.\n const out = task._jitterScratch;\n for (let c = 0; c < 4; c++) {\n const b = c * 4;\n const w3 = clean[b + 3]!;\n out[b] = clean[b]! + jx * w3;\n out[b + 1] = clean[b + 1]! + jy * w3;\n out[b + 2] = clean[b + 2]!;\n out[b + 3] = w3;\n }\n task.engine._device.queue.writeBuffer(src._sceneUBO, 0, out as Float32Array<ArrayBuffer>);\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"taa.js","sources":["../../../src/post-process/taa.ts"],"sourcesContent":["// Temporal Anti-Aliasing (TAA) — a frame-graph post-process task.\n//\n// TAA jitters the camera projection by a sub-pixel Halton offset every frame and\n// accumulates a moving average of consecutive (jittered) frames. Spreading the\n// supersampling over time yields high-quality edge anti-aliasing without rendering\n// the scene multiple times per frame. The accumulated history converges to a\n// supersampled image after a few dozen frames.\n//\n// This task is a pure frame-graph node: add it at the END of a chain whose source\n// render task draws the scene into `sourceTexture`. Each frame it:\n// 1. blend : temp = mix(history, current, factor) (history bound as extra)\n// 2. present : temp -> targetTexture (e.g. the swapchain)\n// 3. historyUpd : temp -> history (becomes next frame's history)\n// 4. advances the Halton sequence and writes the jittered viewProjection into the\n// *source render task's* scene UBO so the NEXT frame renders sub-pixel shifted.\n//\n// `factor` is the blend weight of the current frame (BJS default 0.05). On the first\n// frame and on a camera-move reset it is forced to 1 (output == current) so no stale\n// history bleeds in.\n//\n// The jitter is injected by overwriting only the viewProjection slice (bytes 0..63)\n// of the source task's already-packed scene UBO. The source task's UBO write is\n// cached on the camera's worldMatrixVersion, so with a static camera our jittered\n// matrix survives each frame; when the camera moves the source re-packs a clean\n// matrix (a natural reset) and we set factor=1 for that frame. This needs zero\n// changes to the shared camera / scene-uniform hot path — so scenes that do not use\n// TAA pay nothing.\n\nimport { F32 } from \"../engine/typed-arrays.js\";\nimport { _cameraChangeKey } from \"../camera/camera.js\";\nimport type { EngineContext } from \"../engine/engine.js\";\nimport type { RenderTarget } from \"../engine/render-target.js\";\nimport { buildRenderTarget, createRenderTarget, disposeRenderTarget } from \"../engine/render-target.js\";\nimport { createPostProcessTask, type PostProcessTask, type PostProcessTaskSettings } from \"../frame-graph/post-process-task.js\";\nimport type { RenderTask } from \"../frame-graph/render-task.js\";\nimport type { Task } from \"../frame-graph/task.js\";\nimport type { SceneContext } from \"../scene/scene-core.js\";\n\n/** Configuration for `createTaaPostProcessTask`. */\nexport interface TaaPostProcessTaskConfig extends PostProcessTaskSettings {\n /** The render task that draws the scene into `sourceTexture`. TAA jitters this\n * task's camera projection each frame (mirrors BJS `FrameGraphTAATask.objectRendererTask`). */\n sourceRenderTask: RenderTask;\n /** Blend weight of the current frame against the accumulated history (default: 0.05). */\n factor?: number;\n /** Number of jitter samples in the Halton sequence (default: 8). */\n samples?: number;\n /** Force a one-frame reset (output == current) whenever the camera moves (default: true).\n * Avoids ghosting while the view changes. */\n disableOnCameraMove?: boolean;\n}\n\n/** A Temporal Anti-Aliasing post-process task: accumulates jittered frames into an\n * anti-aliased image. Inject at the end of a frame-graph chain. */\nexport interface TaaPostProcessTask extends Task, PostProcessTaskSettings {\n readonly name: string;\n sourceTexture: RenderTarget;\n targetTexture: RenderTarget | null;\n outputTexture: RenderTarget;\n /** Blend weight of the current frame (smaller = smoother / slower convergence). */\n factor: number;\n /** Number of Halton jitter samples. */\n readonly samples: number;\n /** Reset to the current frame whenever the camera moves. */\n disableOnCameraMove: boolean;\n /** Recompute and upload the blend pass uniforms from current settings. */\n updateUniforms(): void;\n}\n\ninterface TaaTaskInternal extends TaaPostProcessTask {\n _blend: PostProcessTask;\n _present: PostProcessTask;\n _historyUpdate: PostProcessTask;\n _history: RenderTarget;\n _temp: RenderTarget;\n _sourceRenderTask: RenderTask;\n /** Raw Halton offsets in [-0.5, 0.5): [x0,y0, x1,y1, ...]. Scaled per-frame by source size. */\n _halton: Float32Array;\n _haltonIndex: number;\n _jitterScratch: Float32Array;\n _firstUpdate: boolean;\n _lastCamVer: number;\n _factor: number;\n}\n\nconst TAA_HISTORY_TEXTURE_WGSL = `@group(0) @binding(2) var taaHistory:texture_2d<f32>;`;\n\nconst TAA_UNIFORM_WGSL = `struct TaaParams{factor:f32,p0:f32,p1:f32,p2:f32}\n@group(0) @binding(3) var<uniform> taaParams:TaaParams;`;\n\n// mix(history, current, factor): factor=1 -> current only (first frame / reset).\nconst TAA_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{let h=textureSample(taaHistory,sourceSampler,uv);return mix(h,color,taaParams.factor);}`;\n\n// Identity passthrough used by the present + history-update copies.\nconst TAA_COPY_FRAGMENT_WGSL = `fn applyPostProcess(color:vec4f, uv:vec2f)->vec4f{return color;}`;\n\n/**\n * Create a Temporal Anti-Aliasing post-process task.\n * @param config - Source texture + source render task, blend factor, sample count.\n * @param engine - The owning engine.\n * @param scene - Optional owning scene.\n * @returns The TAA post-process task. Add it at the end of the frame-graph chain.\n */\nexport function createTaaPostProcessTask(config: TaaPostProcessTaskConfig, engine: EngineContext, scene?: SceneContext): TaaPostProcessTask {\n const name = config.name ?? \"taa\";\n const source = config.sourceTexture;\n const target = config.targetTexture ?? null;\n // Clamp to >= 1: a zero/negative sample count would make `generateHalton` return an\n // empty sequence and `advanceJitter` write NaN jitter offsets into the source UBO.\n const samples = Math.max(1, Math.floor(config.samples ?? 8));\n const sizeRef = source._descriptor.size;\n\n // History accumulates at RGBA16F so the 0.05 moving average does not band on\n // an 8-bit buffer (matches BJS half-float history).\n const history = createRenderTarget({ lbl: `${name}-history`, format: \"rgba16float\", samples: 1, size: sizeRef });\n const temp = createRenderTarget({ lbl: `${name}-temp`, format: \"rgba16float\", samples: 1, size: sizeRef });\n\n const blend = createPostProcessTask(\n {\n name: `${name}-blend`,\n sourceTexture: source,\n // Nearest sampling reads the exact co-located texel of both the current\n // frame and the history (all three targets share a resolution).\n sourceSamplingMode: \"nearest\",\n targetTexture: temp,\n _shader: {\n extraTextureWGSL: TAA_HISTORY_TEXTURE_WGSL,\n extraTextures: [history],\n uniformWGSL: TAA_UNIFORM_WGSL,\n uniformBinding: 3,\n uniformByteLength: 16,\n writeUniforms(data) {\n data[0] = task._factor;\n },\n fragmentWGSL: TAA_FRAGMENT_WGSL,\n },\n },\n engine,\n scene\n );\n const present = createPostProcessTask(\n {\n name: `${name}-present`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: target ?? engine.scRT,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n const historyUpdate = createPostProcessTask(\n {\n name: `${name}-history-update`,\n sourceTexture: temp,\n sourceSamplingMode: \"nearest\",\n targetTexture: history,\n _shader: { fragmentWGSL: TAA_COPY_FRAGMENT_WGSL },\n },\n engine,\n scene\n );\n\n const task: TaaTaskInternal = {\n name,\n engine,\n scene,\n _passes: [],\n sourceTexture: source,\n targetTexture: target,\n outputTexture: target ?? engine.scRT,\n factor: config.factor ?? 0.05,\n samples,\n disableOnCameraMove: config.disableOnCameraMove ?? true,\n _blend: blend,\n _present: present,\n _historyUpdate: historyUpdate,\n _history: history,\n _temp: temp,\n _sourceRenderTask: config.sourceRenderTask,\n _halton: generateHalton(samples),\n _haltonIndex: 0,\n _jitterScratch: new F32(16),\n _firstUpdate: true,\n _lastCamVer: -1,\n _factor: 1,\n record(): void {\n // History + temp are persistent ping-pong buffers: allocate them once\n // (eager), sized to the source, and only reallocate on a real size change.\n // Marking them eager makes the sub-tasks' internal `buildRenderTarget`\n // no-op on them — critical because `historyUpdate` targets `history`, and a\n // rebuild there would destroy the texture `blend`'s bind group references.\n const { width: w, height: h } = resolveSourceSize(task.sourceTexture);\n ensurePersistentTarget(history, engine, w, h);\n ensurePersistentTarget(temp, engine, w, h);\n blend.record();\n present.record();\n historyUpdate.record();\n task._firstUpdate = true;\n task._haltonIndex = 0;\n task._lastCamVer = -1;\n },\n execute(): number {\n const cam = task._sourceRenderTask.scene.camera;\n const camVer = cam ? _cameraChangeKey(cam) : 0;\n const moved = camVer !== task._lastCamVer;\n task._lastCamVer = camVer;\n\n // factor=1 on the first frame and on camera-move reset: take the current\n // (un-jittered) frame verbatim, discarding stale history.\n const reset = task._firstUpdate || (moved && task.disableOnCameraMove);\n task._factor = reset ? 1 : task.factor;\n blend.updateUniforms();\n\n let draws = blend.execute?.() ?? 0;\n draws += present.execute?.() ?? 0;\n draws += historyUpdate.execute?.() ?? 0;\n\n task._firstUpdate = false;\n\n // Prepare the NEXT frame's jitter: advance the Halton sequence and write the\n // jittered viewProjection into the source task's UBO. Always done — even on a\n // reset frame — so accumulation starts immediately on the following frame.\n // The blend `factor` reset already prevents stale-history bleed, and a still-\n // moving camera re-packs a clean matrix next frame anyway (overwriting this).\n advanceJitter(task);\n return draws;\n },\n updateUniforms(): void {\n blend.updateUniforms();\n },\n dispose(): void {\n task._passes.length = 0;\n blend.dispose();\n present.dispose();\n historyUpdate.dispose();\n // Clear the eager flag so the persistent buffers are actually freed.\n history._eager = false;\n temp._eager = false;\n disposeRenderTarget(history);\n disposeRenderTarget(temp);\n },\n };\n return task;\n}\n\n/** Allocate (or, on a size change, reallocate) a persistent ping-pong target sized\n * `width`×`height`. The target is marked `_eager` so the post-process sub-tasks'\n * internal `buildRenderTarget` no-ops on it, keeping accumulated history alive across\n * frames and preventing a rebuild from destroying a texture still bound elsewhere. */\nfunction ensurePersistentTarget(rt: RenderTarget, engine: EngineContext, width: number, height: number): void {\n if (rt._eager && rt._width === width && rt._height === height) {\n return;\n }\n rt._eager = false;\n disposeRenderTarget(rt);\n rt._descriptor.size = { width, height };\n buildRenderTarget(rt, engine);\n rt._eager = true;\n}\n\n/** Resolve a render target's pixel size: prefer its allocated dimensions, falling back\n * to the descriptor's surface (multi-surface safe — does not assume the engine canvas)\n * or explicit pixel size before the target has been built. */\nfunction resolveSourceSize(source: RenderTarget): { width: number; height: number } {\n if (source._width > 0 && source._height > 0) {\n return { width: source._width, height: source._height };\n }\n const size = source._descriptor.size;\n if (\"canvas\" in size) {\n return { width: size.canvas.width, height: size.canvas.height };\n }\n return { width: size.width, height: size.height };\n}\n\n/** Generate `samples` 2D Halton offsets (base 2 / base 3) centered on [-0.5, 0.5). */\nfunction generateHalton(samples: number): Float32Array {\n const seq = new F32(samples * 2);\n for (let i = 1; i <= samples; i++) {\n seq[(i - 1) * 2] = halton(i, 2) - 0.5;\n seq[(i - 1) * 2 + 1] = halton(i, 3) - 0.5;\n }\n return seq;\n}\n\nfunction halton(index: number, base: number): number {\n let fraction = 1;\n let result = 0;\n while (index > 0) {\n fraction /= base;\n result += fraction * (index % base);\n index = Math.floor(index / base);\n }\n return result;\n}\n\n/** Advance the Halton sequence and overwrite the source task's viewProjection\n * (column-major bytes 0..63 of its scene UBO) with a sub-pixel jittered matrix. */\nfunction advanceJitter(task: TaaTaskInternal): void {\n const src = task._sourceRenderTask;\n const clean = src._suData;\n const w = task.sourceTexture._width;\n const h = task.sourceTexture._height;\n if (w <= 0 || h <= 0) {\n return;\n }\n\n // NDC sub-pixel offset: one pixel spans 2/size in NDC, so size/2 is the denominator.\n const jx = task._halton[task._haltonIndex]! / (w / 2);\n const jy = task._halton[task._haltonIndex + 1]! / (h / 2);\n task._haltonIndex += 2;\n if (task._haltonIndex >= task._halton.length) {\n task._haltonIndex = 0;\n }\n\n // Translate the projected image by (jx, jy) in NDC: clip.xy += (jx,jy)*clip.w.\n // Column-major: row r, col c lives at c*4+r. Add j*row3 to row0 / row1.\n const out = task._jitterScratch;\n for (let c = 0; c < 4; c++) {\n const b = c * 4;\n const w3 = clean[b + 3]!;\n out[b] = clean[b]! + jx * w3;\n out[b + 1] = clean[b + 1]! + jy * w3;\n out[b + 2] = clean[b + 2]!;\n out[b + 3] = w3;\n }\n task.engine._device.queue.writeBuffer(src._sceneUBO, 0, out as Float32Array<ArrayBuffer>);\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { removeMeshFromTask, createRenderTask } from '../frame-graph/render-task.js';
2
- import { getViewProjectionMatrix } from '../camera/camera.js';
2
+ import { _cameraChangeKey, getEffectiveAspectRatio, getViewProjectionMatrix } from '../camera/camera.js';
3
3
  import { mat4Invert } from '../math/mat4-invert.js';
4
4
  import { createShadowCamera, casterVersionSum, updateShadowCameraBase, buildLightViewMatrix, multiply4x4 } from './shadow-base.js';
5
5
  import { preloadPcfShadowTaskState, getNoColorView } from './pcf-shadow-task-hooks.js';
@@ -139,6 +139,7 @@ function ensureCsmShadowTaskState(engine, scene, sg, cfg, casterMeshes, existing
139
139
  _lastCasterVersion: -1,
140
140
  _lastLightVersion: -1,
141
141
  _lastCamVersion: -1,
142
+ _lastCamAspect: -1,
142
143
  _uboData: new Float32Array(80),
143
144
  _casterMeshes: casterMeshes,
144
145
  _renderableVersion: scene._renderableVersion,
@@ -156,11 +157,12 @@ function renderCsmShadowMap(engine, sg, state, cfg) {
156
157
  }
157
158
  const casterVersion = casterVersionSum(casterMeshes);
158
159
  const lightVersion = sg._light.worldMatrixVersion;
159
- const camVersion = camera.worldMatrixVersion;
160
- if (!cfg._forceRefreshEveryFrame && casterVersion === state._lastCasterVersion && lightVersion === state._lastLightVersion && camVersion === state._lastCamVersion) {
160
+ const camVersion = _cameraChangeKey(camera);
161
+ const camAspect = csmCameraAspect(state._scene, camera);
162
+ if (!cfg._forceRefreshEveryFrame && casterVersion === state._lastCasterVersion && lightVersion === state._lastLightVersion && camVersion === state._lastCamVersion && camAspect === state._lastCamAspect) {
161
163
  return 0;
162
164
  }
163
- const cascades = _computeCsmCascades(engine, camera, sg._light, cfg, casterMeshes);
165
+ const cascades = _computeCsmCascades(state._scene, camera, sg._light, cfg, casterMeshes);
164
166
  _writeCsmUbo(state._uboData, cascades, cfg);
165
167
  sg._version++;
166
168
  engine._device.queue.writeBuffer(sg._shadowUBO, 0, state._uboData);
@@ -180,6 +182,7 @@ function renderCsmShadowMap(engine, sg, state, cfg) {
180
182
  state._lastCasterVersion = casterVersion;
181
183
  state._lastLightVersion = lightVersion;
182
184
  state._lastCamVersion = camVersion;
185
+ state._lastCamAspect = camAspect;
183
186
  return state._task.execute?.() ?? 0;
184
187
  }
185
188
  const FRUSTUM_NDC = [
@@ -210,7 +213,11 @@ function orthoOffCenterLH(l, r, b, t, n, f) {
210
213
  m[15] = 1;
211
214
  return m;
212
215
  }
213
- function _computeCsmCascades(engine, camera, light, cfg, casterMeshes) {
216
+ function csmCameraAspect(scene, camera) {
217
+ const rt = scene.surface.scRT;
218
+ return getEffectiveAspectRatio(camera, rt._width, rt._height);
219
+ }
220
+ function _computeCsmCascades(scene, camera, light, cfg, casterMeshes) {
214
221
  const near = camera.nearPlane;
215
222
  const far = camera.farPlane;
216
223
  const cameraRange = far - near;
@@ -245,7 +252,7 @@ function _computeCsmCascades(engine, camera, light, cfg, casterMeshes) {
245
252
  if (Math.abs(dy) >= 1) {
246
253
  dz = 1e-13;
247
254
  }
248
- const aspect = engine.canvas.width / engine.canvas.height;
255
+ const aspect = csmCameraAspect(scene, camera);
249
256
  const vp = getViewProjectionMatrix(camera, aspect);
250
257
  const inv = mat4Invert(vp);
251
258
  const invViewProj = inv ?? vp;