leaflet-city-mapper 0.0.1 → 0.0.2
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.
- package/README.md +15 -13
- package/cucumber.mjs +4 -0
- package/dist/leaflet-city-mapper.js +1 -1
- package/dist/leaflet-city-mapper.js.map +4 -4
- package/dist/utils/CELL.js +2 -0
- package/dist/utils/CELL.js.map +7 -0
- package/dist/utils/addBridges.js +2 -0
- package/dist/utils/addBridges.js.map +7 -0
- package/dist/utils/addRasterTile.js +2 -0
- package/dist/utils/addRasterTile.js.map +7 -0
- package/dist/utils/along.js +2 -0
- package/dist/utils/along.js.map +7 -0
- package/dist/utils/atmosphere.js +2 -0
- package/dist/utils/atmosphere.js.map +7 -0
- package/dist/utils/attach.js +2 -0
- package/dist/utils/attach.js.map +7 -0
- package/dist/utils/bindSunlight.js +2 -0
- package/dist/utils/bindSunlight.js.map +7 -0
- package/dist/utils/box.js +2 -0
- package/dist/utils/box.js.map +7 -0
- package/dist/utils/bridgeElevation.js +2 -0
- package/dist/utils/bridgeElevation.js.map +7 -0
- package/dist/utils/build.js +2 -0
- package/dist/utils/build.js.map +7 -0
- package/dist/utils/cameraControls.js +2 -0
- package/dist/utils/cameraControls.js.map +7 -0
- package/dist/utils/channel.js +2 -0
- package/dist/utils/channel.js.map +7 -0
- package/dist/utils/collider.js +2 -0
- package/dist/utils/collider.js.map +7 -0
- package/dist/utils/colliders.js +2 -0
- package/dist/utils/colliders.js.map +7 -0
- package/dist/utils/computeBounds.js +2 -0
- package/dist/utils/computeBounds.js.map +7 -0
- package/dist/utils/conformModelToTerrain.js +2 -0
- package/dist/utils/conformModelToTerrain.js.map +7 -0
- package/dist/utils/createMesh.js +2 -0
- package/dist/utils/createMesh.js.map +7 -0
- package/dist/utils/createProgram.js +3 -0
- package/dist/utils/createProgram.js.map +7 -0
- package/dist/utils/decodeDirectory.js +2 -0
- package/dist/utils/decodeDirectory.js.map +7 -0
- package/dist/utils/decodeHeader.js +2 -0
- package/dist/utils/decodeHeader.js.map +7 -0
- package/dist/utils/decodeModel.js +2 -0
- package/dist/utils/decodeModel.js.map +7 -0
- package/dist/utils/decompress.js +2 -0
- package/dist/utils/decompress.js.map +7 -0
- package/dist/utils/destroyTexture.js +2 -0
- package/dist/utils/destroyTexture.js.map +7 -0
- package/dist/utils/disposeMesh.js +2 -0
- package/dist/utils/disposeMesh.js.map +7 -0
- package/dist/utils/drawGeometry.js +2 -0
- package/dist/utils/drawGeometry.js.map +7 -0
- package/dist/utils/elevationWGSL.js +24 -0
- package/dist/utils/elevationWGSL.js.map +7 -0
- package/dist/utils/emptyNode.js +2 -0
- package/dist/utils/emptyNode.js.map +7 -0
- package/dist/utils/endZoom.js +2 -0
- package/dist/utils/endZoom.js.map +7 -0
- package/dist/utils/findFeature.js +2 -0
- package/dist/utils/findFeature.js.map +7 -0
- package/dist/utils/geometry.js +0 -1
- package/dist/utils/geometry.js.map +4 -4
- package/dist/utils/getElevation.js +2 -0
- package/dist/utils/getElevation.js.map +7 -0
- package/dist/utils/getHeader.js +2 -0
- package/dist/utils/getHeader.js.map +7 -0
- package/dist/utils/getZxy.js +2 -0
- package/dist/utils/getZxy.js.map +7 -0
- package/dist/utils/glass.js +2 -0
- package/dist/utils/glass.js.map +7 -0
- package/dist/utils/headlight.js +2 -0
- package/dist/utils/headlight.js.map +7 -0
- package/dist/utils/hit.js +2 -0
- package/dist/utils/hit.js.map +7 -0
- package/dist/utils/horizontalPosition.js +2 -0
- package/dist/utils/horizontalPosition.js.map +7 -0
- package/dist/utils/horizontalRay.js +2 -0
- package/dist/utils/horizontalRay.js.map +7 -0
- package/dist/utils/hull.js +2 -0
- package/dist/utils/hull.js.map +7 -0
- package/dist/utils/initSunlight.js +2 -0
- package/dist/utils/initSunlight.js.map +7 -0
- package/dist/utils/initTerrain.js +2 -0
- package/dist/utils/initTerrain.js.map +7 -0
- package/dist/utils/initTraffic.js +40 -0
- package/dist/utils/initTraffic.js.map +7 -0
- package/dist/utils/initWalk.js +2 -0
- package/dist/utils/initWalk.js.map +7 -0
- package/dist/utils/intersectMeshes.js +2 -0
- package/dist/utils/intersectMeshes.js.map +7 -0
- package/dist/utils/isClockWise.js +2 -0
- package/dist/utils/isClockWise.js.map +7 -0
- package/dist/utils/lampPostGeometry.js +2 -0
- package/dist/utils/lampPostGeometry.js.map +7 -0
- package/dist/utils/lightGeometry.js +2 -0
- package/dist/utils/lightGeometry.js.map +7 -0
- package/dist/utils/lightGrid.js +2 -0
- package/dist/utils/lightGrid.js.map +7 -0
- package/dist/utils/limbs.js +2 -0
- package/dist/utils/limbs.js.map +7 -0
- package/dist/utils/loadModel.js +2 -0
- package/dist/utils/loadModel.js.map +7 -0
- package/dist/utils/loadSource.js +2 -0
- package/dist/utils/loadSource.js.map +7 -0
- package/dist/utils/loadTerrain.js +2 -0
- package/dist/utils/loadTerrain.js.map +7 -0
- package/dist/utils/mapCamera.js +2 -0
- package/dist/utils/mapCamera.js.map +7 -0
- package/dist/utils/{shaders.js → materialShaders.js} +16 -8
- package/dist/utils/materialShaders.js.map +7 -0
- package/dist/utils/mirror.js +2 -0
- package/dist/utils/mirror.js.map +7 -0
- package/dist/utils/moonPosition.js +2 -0
- package/dist/utils/moonPosition.js.map +7 -0
- package/dist/utils/moves.js +2 -0
- package/dist/utils/moves.js.map +7 -0
- package/dist/utils/nativeEvents.js +2 -0
- package/dist/utils/nativeEvents.js.map +7 -0
- package/dist/utils/nativeGeometry.js +2 -0
- package/dist/utils/nativeGeometry.js.map +7 -0
- package/dist/utils/nativeLayer.js +2 -0
- package/dist/utils/nativeLayer.js.map +7 -0
- package/dist/utils/nodeMatrix.js +2 -0
- package/dist/utils/nodeMatrix.js.map +7 -0
- package/dist/utils/onAdd3DLayer.js +2 -0
- package/dist/utils/onAdd3DLayer.js.map +7 -0
- package/dist/utils/onAddSun.js +2 -0
- package/dist/utils/onAddSun.js.map +7 -0
- package/dist/utils/onClick.js +2 -0
- package/dist/utils/onClick.js.map +7 -0
- package/dist/utils/onMapChange.js +2 -0
- package/dist/utils/onMapChange.js.map +7 -0
- package/dist/utils/onPMTileAdd.js +2 -0
- package/dist/utils/onPMTileAdd.js.map +7 -0
- package/dist/utils/onPMTileRemove.js +2 -0
- package/dist/utils/onPMTileRemove.js.map +7 -0
- package/dist/utils/onPointerLeave.js +2 -0
- package/dist/utils/onPointerLeave.js.map +7 -0
- package/dist/utils/onPointerMove.js +2 -0
- package/dist/utils/onPointerMove.js.map +7 -0
- package/dist/utils/onRemove3DLayer.js +2 -0
- package/dist/utils/onRemove3DLayer.js.map +7 -0
- package/dist/utils/onRemoveSun.js +2 -0
- package/dist/utils/onRemoveSun.js.map +7 -0
- package/dist/utils/onTerrainAdd.js +2 -0
- package/dist/utils/onTerrainAdd.js.map +7 -0
- package/dist/utils/onTerrainChange.js +2 -0
- package/dist/utils/onTerrainChange.js.map +7 -0
- package/dist/utils/onTerrainRemove.js +2 -0
- package/dist/utils/onTerrainRemove.js.map +7 -0
- package/dist/utils/onZoomAnim.js +2 -0
- package/dist/utils/onZoomAnim.js.map +7 -0
- package/dist/utils/paints.js +2 -0
- package/dist/utils/paints.js.map +7 -0
- package/dist/utils/parseColor.js +2 -0
- package/dist/utils/parseColor.js.map +7 -0
- package/dist/utils/parts.js +2 -0
- package/dist/utils/parts.js.map +7 -0
- package/dist/utils/projectCelestialBody.js +2 -0
- package/dist/utils/projectCelestialBody.js.map +7 -0
- package/dist/utils/pump.js +2 -0
- package/dist/utils/pump.js.map +7 -0
- package/dist/utils/rasterTiles.js +2 -0
- package/dist/utils/rasterTiles.js.map +7 -0
- package/dist/utils/raycast.js +2 -0
- package/dist/utils/raycast.js.map +7 -0
- package/dist/utils/read.js +2 -0
- package/dist/utils/read.js.map +7 -0
- package/dist/utils/readAccessor.js +2 -0
- package/dist/utils/readAccessor.js.map +7 -0
- package/dist/utils/releaseArea.js +2 -0
- package/dist/utils/releaseArea.js.map +7 -0
- package/dist/utils/removeRasterTile.js +2 -0
- package/dist/utils/removeRasterTile.js.map +7 -0
- package/dist/utils/render.js +15 -0
- package/dist/utils/render.js.map +7 -0
- package/dist/utils/renderSunlight.js +13 -0
- package/dist/utils/renderSunlight.js.map +7 -0
- package/dist/utils/renderers.js +2 -0
- package/dist/utils/renderers.js.map +7 -0
- package/dist/utils/resizeSunlight.js +2 -0
- package/dist/utils/resizeSunlight.js.map +7 -0
- package/dist/utils/roofCoverage.js +2 -0
- package/dist/utils/roofCoverage.js.map +7 -0
- package/dist/utils/routeGeometry.js +2 -0
- package/dist/utils/routeGeometry.js.map +7 -0
- package/dist/utils/scheduledTrips.js +2 -0
- package/dist/utils/scheduledTrips.js.map +7 -0
- package/dist/utils/setGeoJSONData.js +2 -0
- package/dist/utils/setGeoJSONData.js.map +7 -0
- package/dist/utils/setHighlight.js +2 -0
- package/dist/utils/setHighlight.js.map +7 -0
- package/dist/utils/setPMTileOpacity.js +2 -0
- package/dist/utils/setPMTileOpacity.js.map +7 -0
- package/dist/utils/setPMTileZIndex.js +2 -0
- package/dist/utils/setPMTileZIndex.js.map +7 -0
- package/dist/utils/setParent.js +2 -0
- package/dist/utils/setParent.js.map +7 -0
- package/dist/utils/setTerrainHeight.js +2 -0
- package/dist/utils/setTerrainHeight.js.map +7 -0
- package/dist/utils/setVertexColor.js +2 -0
- package/dist/utils/setVertexColor.js.map +7 -0
- package/dist/utils/showFeature.js +2 -0
- package/dist/utils/showFeature.js.map +7 -0
- package/dist/utils/sizes.js +2 -0
- package/dist/utils/sizes.js.map +7 -0
- package/dist/utils/skin.js +2 -0
- package/dist/utils/skin.js.map +7 -0
- package/dist/utils/solarPosition.js +2 -0
- package/dist/utils/solarPosition.js.map +7 -0
- package/dist/utils/sortMeshes.js +2 -0
- package/dist/utils/sortMeshes.js.map +7 -0
- package/dist/utils/speed.js +2 -0
- package/dist/utils/speed.js.map +7 -0
- package/dist/utils/startZoom.js +2 -0
- package/dist/utils/startZoom.js.map +7 -0
- package/dist/utils/taillight.js +2 -0
- package/dist/utils/taillight.js.map +7 -0
- package/dist/utils/terrainAtlas.js +2 -0
- package/dist/utils/terrainAtlas.js.map +7 -0
- package/dist/utils/terrainElevation.js +2 -0
- package/dist/utils/terrainElevation.js.map +7 -0
- package/dist/utils/terrainGrid.js +2 -0
- package/dist/utils/terrainGrid.js.map +7 -0
- package/dist/utils/textureSampler.js +2 -0
- package/dist/utils/textureSampler.js.map +7 -0
- package/dist/utils/tileId.js +2 -0
- package/dist/utils/tileId.js.map +7 -0
- package/dist/utils/toLanes.js +2 -0
- package/dist/utils/toLanes.js.map +7 -0
- package/dist/utils/toSRGB.js +2 -0
- package/dist/utils/toSRGB.js.map +7 -0
- package/dist/utils/tooltip.js +3 -0
- package/dist/utils/tooltip.js.map +7 -0
- package/dist/utils/traffic.js +1 -1
- package/dist/utils/traffic.js.map +3 -3
- package/dist/utils/traverse.js +2 -0
- package/dist/utils/traverse.js.map +7 -0
- package/dist/utils/treeGeometry.js +2 -0
- package/dist/utils/treeGeometry.js.map +7 -0
- package/dist/utils/triangulate.js +2 -0
- package/dist/utils/triangulate.js.map +7 -0
- package/dist/utils/tripsAt.js +2 -0
- package/dist/utils/tripsAt.js.map +7 -0
- package/dist/utils/types.js +2 -0
- package/dist/utils/types.js.map +7 -0
- package/dist/utils/underEntry.js +2 -0
- package/dist/utils/underEntry.js.map +7 -0
- package/dist/utils/update.js +2 -0
- package/dist/utils/update.js.map +7 -0
- package/dist/utils/updateArea.js +2 -0
- package/dist/utils/updateArea.js.map +7 -0
- package/dist/utils/updateCamera.js +2 -0
- package/dist/utils/updateCamera.js.map +7 -0
- package/dist/utils/updatePointLights.js +2 -0
- package/dist/utils/updatePointLights.js.map +7 -0
- package/dist/utils/updateWorldMatrix.js +2 -0
- package/dist/utils/updateWorldMatrix.js.map +7 -0
- package/dist/utils/vehicleOffsets.js +2 -0
- package/dist/utils/vehicleOffsets.js.map +7 -0
- package/dist/utils/vehicles.js +1 -1
- package/dist/utils/vehicles.js.map +3 -3
- package/dist/utils/vertexNormals.js +2 -0
- package/dist/utils/vertexNormals.js.map +7 -0
- package/dist/utils/walk.js +1 -1
- package/dist/utils/walk.js.map +3 -3
- package/dist/utils/white.js +2 -0
- package/dist/utils/white.js.map +7 -0
- package/dist/utils/worldLights.js +2 -0
- package/dist/utils/worldLights.js.map +7 -0
- package/dist/utils/wrap.js +2 -0
- package/dist/utils/wrap.js.map +7 -0
- package/package.json +2 -4
- package/src/index.js +365 -50
- package/src/utils/CELL.js +4 -0
- package/src/utils/addBridges.js +66 -0
- package/src/utils/addRasterTile.js +112 -0
- package/src/utils/along.js +9 -0
- package/src/utils/atmosphere.js +20 -0
- package/src/utils/attach.js +255 -0
- package/src/utils/bindSunlight.js +12 -0
- package/src/utils/box.js +1 -0
- package/src/utils/bridgeElevation.js +18 -0
- package/src/utils/build.js +20 -0
- package/src/utils/cameraControls.js +287 -0
- package/src/utils/channel.js +4 -0
- package/src/utils/collider.js +62 -0
- package/src/utils/colliders.js +2 -0
- package/src/utils/computeBounds.js +17 -0
- package/src/utils/conformModelToTerrain.js +69 -0
- package/src/utils/createMesh.js +31 -0
- package/src/utils/createProgram.js +92 -0
- package/src/utils/decodeDirectory.js +40 -0
- package/src/utils/decodeHeader.js +15 -0
- package/src/utils/decodeModel.js +43 -0
- package/src/utils/decompress.js +5 -0
- package/src/utils/destroyTexture.js +7 -0
- package/src/utils/disposeMesh.js +13 -0
- package/src/utils/drawGeometry.js +122 -0
- package/src/utils/elevationWGSL.js +27 -0
- package/src/utils/emptyNode.js +9 -0
- package/src/utils/endZoom.js +15 -0
- package/src/utils/findFeature.js +49 -0
- package/src/utils/geometry.js +0 -254
- package/src/utils/getElevation.js +10 -0
- package/src/utils/getHeader.js +9 -0
- package/src/utils/getZxy.js +76 -0
- package/src/utils/glass.js +1 -0
- package/src/utils/headlight.js +1 -0
- package/src/utils/hit.js +41 -0
- package/src/utils/horizontalPosition.js +16 -0
- package/src/utils/horizontalRay.js +12 -0
- package/src/utils/hull.js +1 -0
- package/src/utils/initSunlight.js +9 -0
- package/src/utils/initTerrain.js +19 -0
- package/src/utils/initTraffic.js +93 -0
- package/src/utils/initWalk.js +72 -0
- package/src/utils/{picking.js → intersectMeshes.js} +121 -119
- package/src/utils/isClockWise.js +12 -0
- package/src/utils/lampPostGeometry.js +26 -0
- package/src/utils/lightGeometry.js +22 -0
- package/src/utils/{lighting.js → lightGrid.js} +50 -51
- package/src/utils/limbs.js +9 -0
- package/src/{scene/model.js → utils/loadModel.js} +37 -24
- package/src/utils/loadSource.js +17 -0
- package/src/utils/loadTerrain.js +65 -0
- package/src/utils/mapCamera.js +432 -0
- package/src/utils/{shaders.js → materialShaders.js} +243 -237
- package/src/utils/mirror.js +6 -0
- package/src/utils/moonPosition.js +17 -0
- package/src/utils/moves.js +11 -0
- package/src/utils/nativeEvents.js +77 -0
- package/src/utils/nativeGeometry.js +131 -0
- package/src/utils/nativeLayer.js +317 -0
- package/src/utils/nodeMatrix.js +22 -0
- package/src/utils/onAdd3DLayer.js +31 -0
- package/src/utils/onAddSun.js +147 -0
- package/src/utils/onClick.js +13 -0
- package/src/utils/onMapChange.js +16 -0
- package/src/utils/onPMTileAdd.js +15 -0
- package/src/utils/onPMTileRemove.js +8 -0
- package/src/utils/onPointerLeave.js +11 -0
- package/src/utils/onPointerMove.js +15 -0
- package/src/utils/onRemove3DLayer.js +78 -0
- package/src/utils/onRemoveSun.js +3 -0
- package/src/utils/onTerrainAdd.js +18 -0
- package/src/utils/onTerrainChange.js +13 -0
- package/src/utils/onTerrainRemove.js +40 -0
- package/src/utils/onZoomAnim.js +14 -0
- package/src/utils/paints.js +10 -0
- package/src/utils/parseColor.js +42 -0
- package/src/utils/parts.js +16 -0
- package/src/utils/projectCelestialBody.js +13 -0
- package/src/{scene/sources.js → utils/pump.js} +59 -98
- package/src/utils/rasterTiles.js +285 -0
- package/src/utils/raycast.js +60 -0
- package/src/utils/read.js +29 -0
- package/src/utils/readAccessor.js +68 -0
- package/src/utils/releaseArea.js +34 -0
- package/src/utils/removeRasterTile.js +13 -0
- package/src/{scene → utils}/render.js +112 -173
- package/src/utils/renderSunlight.js +170 -0
- package/src/utils/renderers.js +2 -0
- package/src/utils/resizeSunlight.js +15 -0
- package/src/utils/roofCoverage.js +47 -0
- package/src/utils/routeGeometry.js +22 -0
- package/src/utils/scheduledTrips.js +29 -0
- package/src/utils/setGeoJSONData.js +11 -0
- package/src/utils/setHighlight.js +13 -0
- package/src/utils/setPMTileOpacity.js +7 -0
- package/src/utils/setPMTileZIndex.js +7 -0
- package/src/utils/setParent.js +7 -0
- package/src/utils/setTerrainHeight.js +10 -0
- package/src/utils/setVertexColor.js +14 -0
- package/src/utils/showFeature.js +27 -0
- package/src/utils/sizes.js +1 -0
- package/src/utils/skin.js +2 -0
- package/src/utils/solarPosition.js +17 -0
- package/src/utils/sortMeshes.js +12 -0
- package/src/utils/speed.js +3 -0
- package/src/utils/startZoom.js +5 -0
- package/src/utils/taillight.js +1 -0
- package/src/utils/terrainAtlas.js +21 -0
- package/src/utils/terrainElevation.js +20 -0
- package/src/utils/terrainGrid.js +23 -0
- package/src/utils/textureSampler.js +10 -0
- package/src/utils/tileId.js +18 -0
- package/src/utils/toLanes.js +7 -0
- package/src/utils/toSRGB.js +1 -0
- package/src/utils/tooltip.js +6 -0
- package/src/utils/traffic.js +310 -85
- package/src/utils/traverse.js +6 -0
- package/src/utils/treeGeometry.js +45 -0
- package/src/utils/triangulate.js +100 -0
- package/src/utils/tripsAt.js +16 -0
- package/src/utils/types.js +8 -0
- package/src/utils/{control.js → underEntry.js} +1 -2
- package/src/utils/update.js +18 -0
- package/src/utils/updateArea.js +40 -0
- package/src/utils/updateCamera.js +32 -0
- package/src/utils/updatePointLights.js +38 -0
- package/src/utils/updateWorldMatrix.js +47 -0
- package/src/utils/vehicleOffsets.js +8 -0
- package/src/utils/vehicles.js +65 -69
- package/src/utils/vertexNormals.js +30 -0
- package/src/utils/walk.js +181 -66
- package/src/utils/white.js +1 -0
- package/src/utils/worldLights.js +25 -0
- package/src/utils/wrap.js +1 -0
- package/dist/scene/gpu.js +0 -3
- package/dist/scene/gpu.js.map +0 -7
- package/dist/scene/lighting.js +0 -9
- package/dist/scene/lighting.js.map +0 -7
- package/dist/scene/model.js +0 -2
- package/dist/scene/model.js.map +0 -7
- package/dist/scene/picking.js +0 -2
- package/dist/scene/picking.js.map +0 -7
- package/dist/scene/pmtiles.js +0 -2
- package/dist/scene/pmtiles.js.map +0 -7
- package/dist/scene/render.js +0 -15
- package/dist/scene/render.js.map +0 -7
- package/dist/scene/sources.js +0 -2
- package/dist/scene/sources.js.map +0 -7
- package/dist/types/3d.js +0 -2
- package/dist/types/3d.js.map +0 -7
- package/dist/types/geojson.js +0 -2
- package/dist/types/geojson.js.map +0 -7
- package/dist/types/pmtiles.js +0 -2
- package/dist/types/pmtiles.js.map +0 -7
- package/dist/types/sunlight.js +0 -2
- package/dist/types/sunlight.js.map +0 -7
- package/dist/types/terrain.js +0 -24
- package/dist/types/terrain.js.map +0 -7
- package/dist/types/traffic.js +0 -41
- package/dist/types/traffic.js.map +0 -7
- package/dist/types/walk.js +0 -2
- package/dist/types/walk.js.map +0 -7
- package/dist/utils/control.js +0 -2
- package/dist/utils/control.js.map +0 -7
- package/dist/utils/lighting.js +0 -2
- package/dist/utils/lighting.js.map +0 -7
- package/dist/utils/model.js +0 -2
- package/dist/utils/model.js.map +0 -7
- package/dist/utils/picking.js +0 -2
- package/dist/utils/picking.js.map +0 -7
- package/dist/utils/pmtiles.js +0 -2
- package/dist/utils/pmtiles.js.map +0 -7
- package/dist/utils/scene.js +0 -2
- package/dist/utils/scene.js.map +0 -7
- package/dist/utils/shaders.js.map +0 -7
- package/dist/utils/sun.js +0 -2
- package/dist/utils/sun.js.map +0 -7
- package/dist/utils/terrain.js +0 -2
- package/dist/utils/terrain.js.map +0 -7
- package/src/scene/gpu.js +0 -438
- package/src/scene/lighting.js +0 -193
- package/src/scene/picking.js +0 -150
- package/src/scene/pmtiles.js +0 -94
- package/src/types/3d.js +0 -337
- package/src/types/geojson.js +0 -42
- package/src/types/pmtiles.js +0 -143
- package/src/types/sunlight.js +0 -142
- package/src/types/terrain.js +0 -331
- package/src/types/traffic.js +0 -356
- package/src/types/walk.js +0 -219
- package/src/utils/model.js +0 -178
- package/src/utils/pmtiles.js +0 -79
- package/src/utils/scene.js +0 -102
- package/src/utils/sun.js +0 -71
- package/src/utils/terrain.js +0 -78
package/src/scene/gpu.js
DELETED
|
@@ -1,438 +0,0 @@
|
|
|
1
|
-
import { materialShaders } from '../utils/shaders.js';
|
|
2
|
-
import { emptyNode, setParent, traverse } from '../utils/scene.js';
|
|
3
|
-
|
|
4
|
-
/** WebGPU device attachment, materials/pipelines and draw calls. */
|
|
5
|
-
/**
|
|
6
|
-
* Join/create this map's shared scene and rebuild GPU objects if its context changed.
|
|
7
|
-
* Buffer/program handles belong to one context; typed arrays and decoded images do not.
|
|
8
|
-
* @private
|
|
9
|
-
*/
|
|
10
|
-
export async function attach(backend, map) {
|
|
11
|
-
let shared = L.Layer.types['3d']._renderers.get(map);
|
|
12
|
-
if (shared?._rendererReady) {
|
|
13
|
-
await shared._rendererReady.promise;
|
|
14
|
-
}
|
|
15
|
-
if (!shared) {
|
|
16
|
-
const rendererReady = Promise.withResolvers();
|
|
17
|
-
shared = backend;
|
|
18
|
-
backend._rendererReady = rendererReady;
|
|
19
|
-
rendererReady.promise.catch(() => {});
|
|
20
|
-
L.Layer.types['3d']._renderers.set(map, shared);
|
|
21
|
-
const fail = error => {
|
|
22
|
-
rendererReady.reject(error);
|
|
23
|
-
L.Layer.types['3d']._renderers.delete(map);
|
|
24
|
-
throw error;
|
|
25
|
-
};
|
|
26
|
-
const canvas = document.createElement('canvas');
|
|
27
|
-
if (!navigator.gpu) fail(new Error('Layer3D requires WebGPU'));
|
|
28
|
-
const adapter = await navigator.gpu.requestAdapter().catch(fail);
|
|
29
|
-
if (!adapter) fail(new Error('Unable to acquire a WebGPU adapter'));
|
|
30
|
-
const device = await adapter.requestDevice().catch(fail);
|
|
31
|
-
device.addEventListener('uncapturederror', event => {
|
|
32
|
-
const owner = L.Layer.types['3d']._renderers.get(map);
|
|
33
|
-
if (owner?.renderer?.device !== device) return;
|
|
34
|
-
for (const layer of owner?._layers || []) layer.fire('error', { error: event.error });
|
|
35
|
-
});
|
|
36
|
-
device.lost.then(info => {
|
|
37
|
-
const owner = L.Layer.types['3d']._renderers.get(map);
|
|
38
|
-
if (!owner || owner.renderer?.device !== device) return;
|
|
39
|
-
const error = new Error(`WebGPU device lost: ${info.message || info.reason}`);
|
|
40
|
-
for (const layer of owner._layers) layer.fire('error', { error });
|
|
41
|
-
});
|
|
42
|
-
const context = canvas.getContext('webgpu');
|
|
43
|
-
if (!context) {
|
|
44
|
-
device.destroy();
|
|
45
|
-
fail(new Error('Unable to create a WebGPU canvas context'));
|
|
46
|
-
}
|
|
47
|
-
const format = navigator.gpu.getPreferredCanvasFormat();
|
|
48
|
-
context.configure({ device, format, alphaMode: 'premultiplied' });
|
|
49
|
-
backend._shared = backend;
|
|
50
|
-
backend._layers = new Set();
|
|
51
|
-
backend._sceneOrigin = backend.location;
|
|
52
|
-
backend.scene = emptyNode();
|
|
53
|
-
// Perspective camera state: fov in degrees, near/far in scene metres.
|
|
54
|
-
backend.camera = {
|
|
55
|
-
position: [0, 0, 0],
|
|
56
|
-
up: [0, 1, 0],
|
|
57
|
-
target: [0, 0, 0],
|
|
58
|
-
viewMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
59
|
-
projectionMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
60
|
-
projectionViewMatrix: [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
|
|
61
|
-
fov: 45,
|
|
62
|
-
aspect: 1,
|
|
63
|
-
near: 0.1,
|
|
64
|
-
far: 10000,
|
|
65
|
-
};
|
|
66
|
-
backend.renderer = { device, context, format, canvas, dpr: Math.min(window.devicePixelRatio, 2) };
|
|
67
|
-
backend._initSunlight();
|
|
68
|
-
const emptyImage = document.createElement('canvas');
|
|
69
|
-
emptyImage.width = 1;
|
|
70
|
-
emptyImage.height = 1;
|
|
71
|
-
backend.renderer.roofFallbackTexture = {
|
|
72
|
-
device,
|
|
73
|
-
texture: device.createTexture({
|
|
74
|
-
size: [1, 1],
|
|
75
|
-
format: 'rgba8unorm',
|
|
76
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
77
|
-
}),
|
|
78
|
-
sampler: device.createSampler({
|
|
79
|
-
addressModeU: 'clamp-to-edge', addressModeV: 'clamp-to-edge',
|
|
80
|
-
}),
|
|
81
|
-
image: emptyImage, format: 'rgba8unorm', srgb: false, uploaded: null,
|
|
82
|
-
};
|
|
83
|
-
shared._size = null;
|
|
84
|
-
canvas.className = 'leaflet-3d';
|
|
85
|
-
canvas.style.cssText = 'position:absolute;top:0;left:0;pointer-events:none';
|
|
86
|
-
canvas.setAttribute('role', 'img');
|
|
87
|
-
canvas.setAttribute('aria-label', backend.options.ariaLabel);
|
|
88
|
-
let pane = map.getPane('webgpuPane');
|
|
89
|
-
if (!pane) {
|
|
90
|
-
pane = map.createPane('webgpuPane', map.getContainer());
|
|
91
|
-
pane.style.zIndex = 450;
|
|
92
|
-
}
|
|
93
|
-
pane.append(canvas);
|
|
94
|
-
map.on('move zoom rotate pitch resize viewreset layeradd layerremove', shared._onMapChange, shared);
|
|
95
|
-
map.on('zoomstart', shared._startZoom, shared);
|
|
96
|
-
map.on('zoomanim', shared.update, shared);
|
|
97
|
-
map.on('zoomend', shared._endZoom, shared);
|
|
98
|
-
rendererReady.resolve();
|
|
99
|
-
delete shared._rendererReady;
|
|
100
|
-
shared._render();
|
|
101
|
-
L.Layer.types['3d']._renderers.set(map, shared);
|
|
102
|
-
}
|
|
103
|
-
const origin = map.options.crs.project(shared._sceneOrigin);
|
|
104
|
-
const point = map.options.crs.project(backend.location);
|
|
105
|
-
const metres = Math.cos(shared._sceneOrigin.lat * Math.PI / 180);
|
|
106
|
-
backend._terrainBaseY ??= backend.root.position[1];
|
|
107
|
-
backend.root.position[0] = (point.x - origin.x) * metres;
|
|
108
|
-
backend.root.position[1] = backend._terrainBaseY;
|
|
109
|
-
backend.root.position[2] = -(point.y - origin.y) * metres;
|
|
110
|
-
backend._setTerrainHeight();
|
|
111
|
-
// Each group's metres are measured at its own latitude, not the shared camera origin.
|
|
112
|
-
backend.root.scale.fill(metres / Math.cos(backend.location.lat * Math.PI / 180));
|
|
113
|
-
backend._shared = shared;
|
|
114
|
-
backend.renderer = shared.renderer;
|
|
115
|
-
backend.scene = shared.scene;
|
|
116
|
-
backend.camera = shared.camera;
|
|
117
|
-
shared._layers.add(backend);
|
|
118
|
-
setParent(backend.root, shared.scene);
|
|
119
|
-
traverse(backend.root, object => {
|
|
120
|
-
if (object.geometry && object.geometry.device !== shared.renderer.device) {
|
|
121
|
-
const geometry = object.geometry;
|
|
122
|
-
const material = object.program._layerMaterial;
|
|
123
|
-
// Retain packed CPU attributes, never old-context GPU buffer handles.
|
|
124
|
-
const attributes = {};
|
|
125
|
-
for (const name of ['position', 'normal', 'color', 'uv', 'index']) {
|
|
126
|
-
const attribute = geometry.attributes[name];
|
|
127
|
-
if (!attribute) continue;
|
|
128
|
-
const { data, size, count, normalized } = attribute;
|
|
129
|
-
attributes[name] = { data: data.slice(0, count * size), size, normalized };
|
|
130
|
-
}
|
|
131
|
-
const device = shared.renderer.device;
|
|
132
|
-
if (attributes.index?.data instanceof Uint8Array) {
|
|
133
|
-
attributes.index.data = Uint16Array.from(attributes.index.data);
|
|
134
|
-
}
|
|
135
|
-
for (const [name, attribute] of Object.entries(attributes)) {
|
|
136
|
-
attribute.size ||= 1;
|
|
137
|
-
attribute.count = attribute.data.length / attribute.size;
|
|
138
|
-
attribute.indexFormat = attribute.data instanceof Uint32Array ? 'uint32' : 'uint16';
|
|
139
|
-
attribute.buffer = device.createBuffer({
|
|
140
|
-
size: Math.max(4, attribute.data.byteLength),
|
|
141
|
-
usage: name === 'index'
|
|
142
|
-
? GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST
|
|
143
|
-
: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
|
144
|
-
});
|
|
145
|
-
device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
|
|
146
|
-
}
|
|
147
|
-
object.geometry = {
|
|
148
|
-
device,
|
|
149
|
-
attributes,
|
|
150
|
-
drawRange: { start: 0, count: attributes.index?.count || attributes.position.count },
|
|
151
|
-
};
|
|
152
|
-
for (const attribute of Object.values(geometry.attributes)) attribute.buffer.destroy();
|
|
153
|
-
object.bindGroup = null;
|
|
154
|
-
object.boundTextures = [];
|
|
155
|
-
for (const key of ['baseTexture', 'metalTexture', 'emissiveTexture', 'occlusionTexture']) {
|
|
156
|
-
const texture = material[key];
|
|
157
|
-
if (!texture || texture.device === device) continue;
|
|
158
|
-
material[key] = {
|
|
159
|
-
...texture,
|
|
160
|
-
device,
|
|
161
|
-
texture: device.createTexture({
|
|
162
|
-
size: [texture.image.width, texture.image.height],
|
|
163
|
-
format: texture.format,
|
|
164
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
165
|
-
}),
|
|
166
|
-
sampler: device.createSampler(texture.samplerOptions),
|
|
167
|
-
uploaded: null,
|
|
168
|
-
};
|
|
169
|
-
}
|
|
170
|
-
backend._removeProgram(object.program);
|
|
171
|
-
object.program = backend._createProgram(material);
|
|
172
|
-
object.device = device;
|
|
173
|
-
}
|
|
174
|
-
if (object.texture && object.texture.device !== shared.renderer.device) {
|
|
175
|
-
object.texture = {
|
|
176
|
-
...object.texture,
|
|
177
|
-
device: shared.renderer.device,
|
|
178
|
-
texture: shared.renderer.device.createTexture({
|
|
179
|
-
size: [object.texture.image.width, object.texture.image.height],
|
|
180
|
-
format: object.texture.format,
|
|
181
|
-
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
182
|
-
}),
|
|
183
|
-
sampler: shared.renderer.device.createSampler(object.texture.samplerOptions),
|
|
184
|
-
uploaded: null,
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
});
|
|
188
|
-
shared.update();
|
|
189
|
-
if (backend.header || backend._geojson) backend._updateArea();
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export function destroyTexture(backend, texture) {
|
|
193
|
-
backend.renderer.device.queue.onSubmittedWorkDone().then(() => texture.destroy(), error => {
|
|
194
|
-
backend.fire('error', { error });
|
|
195
|
-
texture.destroy();
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export function createProgram(backend, material = {}) {
|
|
200
|
-
const device = backend.renderer.device;
|
|
201
|
-
const sparkle = Boolean(backend.options.nightSparkle);
|
|
202
|
-
const shaders = materialShaders(material, sparkle, material.terrain ? L.Layer.types.terrain.elevationWGSL : '');
|
|
203
|
-
const { bindings, textured, hasTerrain } = shaders;
|
|
204
|
-
const vertex = device.createShaderModule({ code: shaders.vertex });
|
|
205
|
-
const fragment = device.createShaderModule({ code: shaders.fragment });
|
|
206
|
-
Promise.all([vertex.getCompilationInfo(), fragment.getCompilationInfo()]).then(infos => {
|
|
207
|
-
const errors = infos.flatMap(info => info.messages).filter(message => message.type === 'error');
|
|
208
|
-
if (errors.length) {
|
|
209
|
-
backend.fire('error', {
|
|
210
|
-
error: new Error(`Unable to compile Layer3D WGSL: ${errors.map(error => error.message).join('\n')}`),
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
}).catch(error => backend.fire('error', { error }));
|
|
214
|
-
const vertexBuffers = [
|
|
215
|
-
{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] },
|
|
216
|
-
{ arrayStride: 12, attributes: [{ shaderLocation: 1, offset: 0, format: 'float32x3' }] },
|
|
217
|
-
material.vertexColors ? { arrayStride: 12, attributes: [{ shaderLocation: 2, offset: 0, format: 'float32x3' }] } : null,
|
|
218
|
-
textured ? { arrayStride: 8, attributes: [{ shaderLocation: 3, offset: 0, format: 'float32x2' }] } : null,
|
|
219
|
-
];
|
|
220
|
-
const bindGroupEntries = [{
|
|
221
|
-
binding: 0,
|
|
222
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
223
|
-
buffer: { type: 'uniform', hasDynamicOffset: true },
|
|
224
|
-
}, {
|
|
225
|
-
binding: 1,
|
|
226
|
-
visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
|
|
227
|
-
buffer: { type: 'uniform' },
|
|
228
|
-
}];
|
|
229
|
-
if (hasTerrain) {
|
|
230
|
-
bindGroupEntries.push({
|
|
231
|
-
binding: 2,
|
|
232
|
-
visibility: GPUShaderStage.VERTEX,
|
|
233
|
-
texture: { sampleType: 'unfilterable-float', viewDimension: '2d' },
|
|
234
|
-
});
|
|
235
|
-
}
|
|
236
|
-
for (const texture of bindings) {
|
|
237
|
-
bindGroupEntries.push({
|
|
238
|
-
binding: texture.texture,
|
|
239
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
240
|
-
texture: { sampleType: 'float', viewDimension: '2d' },
|
|
241
|
-
});
|
|
242
|
-
bindGroupEntries.push({
|
|
243
|
-
binding: texture.sampler,
|
|
244
|
-
visibility: GPUShaderStage.FRAGMENT,
|
|
245
|
-
sampler: { type: 'filtering' },
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
const bindGroupLayout = device.createBindGroupLayout({ entries: bindGroupEntries });
|
|
249
|
-
const pipelineLayout = device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout, backend.renderer.sunlight.layout] });
|
|
250
|
-
return {
|
|
251
|
-
device,
|
|
252
|
-
vertex,
|
|
253
|
-
fragment,
|
|
254
|
-
bindings,
|
|
255
|
-
vertexBuffers,
|
|
256
|
-
bindGroupLayout,
|
|
257
|
-
pipelineLayout,
|
|
258
|
-
pipelineCache: new Map(),
|
|
259
|
-
cullMode: material.doubleSided ? 'none' : 'back',
|
|
260
|
-
transparent: material.alphaMode === 'BLEND',
|
|
261
|
-
depthWrite: material.alphaMode !== 'BLEND',
|
|
262
|
-
depthTest: material.depthTest !== false,
|
|
263
|
-
terrain: material.terrain,
|
|
264
|
-
nightLight: Boolean(material.nightLight),
|
|
265
|
-
nightSparkle: sparkle,
|
|
266
|
-
uniforms: {
|
|
267
|
-
baseColor: { value: material.color || [1, 1, 1] },
|
|
268
|
-
metallic: { value: material.metallic ?? 0 },
|
|
269
|
-
roughness: { value: material.roughness ?? 0.85 },
|
|
270
|
-
opacity: { value: material.opacity ?? 1 },
|
|
271
|
-
alphaCutoff: { value: material.alphaCutoff ?? 0.5 },
|
|
272
|
-
occlusionStrength: { value: material.occlusionStrength ?? 1 },
|
|
273
|
-
emissive: { value: material.emissive || [0, 0, 0] },
|
|
274
|
-
...(material.baseTexture ? { baseTexture: { value: material.baseTexture } } : {}),
|
|
275
|
-
...(material.metalTexture ? { metalTexture: { value: material.metalTexture } } : {}),
|
|
276
|
-
...(material.emissiveTexture ? { emissiveTexture: { value: material.emissiveTexture } } : {}),
|
|
277
|
-
...(material.occlusionTexture ? { occlusionTexture: { value: material.occlusionTexture } } : {}),
|
|
278
|
-
...(material.roofTexture ? { roofTexture: { value: null } } : {}),
|
|
279
|
-
},
|
|
280
|
-
_layerMaterial: material,
|
|
281
|
-
};
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
export function removeProgram(program) {
|
|
285
|
-
program.pipelineCache.clear();
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* Add a non-indexed, vertex-coloured mesh from flat vec3 arrays `{ position, normal, color }` in layer-local metres.
|
|
290
|
-
* `usage` adds GPUBufferUsage flags to the vertex buffers (e.g. STORAGE for compute passes).
|
|
291
|
-
*/
|
|
292
|
-
export function createMesh(backend, data, material = {}, usage = 0) {
|
|
293
|
-
const { device } = backend.renderer, attributes = {};
|
|
294
|
-
for (const [name, values] of Object.entries(data)) {
|
|
295
|
-
const array = new Float32Array(values);
|
|
296
|
-
const buffer = device.createBuffer({ size: Math.max(4, array.byteLength), usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST | usage });
|
|
297
|
-
device.queue.writeBuffer(buffer, 0, array);
|
|
298
|
-
attributes[name] = { size: 3, data: array, count: array.length / 3, buffer };
|
|
299
|
-
}
|
|
300
|
-
const mesh = {
|
|
301
|
-
...emptyNode(),
|
|
302
|
-
device,
|
|
303
|
-
geometry: { device, attributes, drawRange: { start: 0, count: attributes.position.count } },
|
|
304
|
-
program: backend._createProgram({ vertexColors: true, doubleSided: true, ...material }),
|
|
305
|
-
id: L.Layer.types['3d']._nextId++, renderOrder: 0, extras: {},
|
|
306
|
-
};
|
|
307
|
-
backend.add(mesh);
|
|
308
|
-
return mesh;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
export function disposeMesh(backend, mesh) {
|
|
312
|
-
if (!mesh) return;
|
|
313
|
-
backend.remove(mesh);
|
|
314
|
-
for (const attribute of Object.values(mesh.geometry.attributes)) attribute.buffer.destroy();
|
|
315
|
-
backend._removeProgram(mesh.program);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/** Upload retained CPU data and draw one mesh in the active WebGPU render pass. */
|
|
319
|
-
export function drawGeometry(backend, mesh, pass, cullMode, frontFace) {
|
|
320
|
-
const { geometry, program } = mesh;
|
|
321
|
-
const device = backend.renderer.device;
|
|
322
|
-
const pipelineKey = `${cullMode}:${frontFace}`;
|
|
323
|
-
let pipeline = program.pipelineCache.get(pipelineKey);
|
|
324
|
-
if (!pipeline) {
|
|
325
|
-
pipeline = device.createRenderPipeline({
|
|
326
|
-
layout: program.pipelineLayout,
|
|
327
|
-
vertex: {
|
|
328
|
-
module: program.vertex,
|
|
329
|
-
entryPoint: 'vertexMain',
|
|
330
|
-
buffers: program.vertexBuffers,
|
|
331
|
-
},
|
|
332
|
-
fragment: {
|
|
333
|
-
module: program.fragment,
|
|
334
|
-
entryPoint: 'fragmentMain',
|
|
335
|
-
targets: [{
|
|
336
|
-
format: backend.renderer.format,
|
|
337
|
-
blend: program.transparent ? {
|
|
338
|
-
color: { srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
339
|
-
alpha: { srcFactor: 'one', dstFactor: 'one-minus-src-alpha', operation: 'add' },
|
|
340
|
-
} : undefined,
|
|
341
|
-
writeMask: GPUColorWrite.ALL,
|
|
342
|
-
}],
|
|
343
|
-
},
|
|
344
|
-
primitive: { topology: 'triangle-list', cullMode, frontFace },
|
|
345
|
-
depthStencil: {
|
|
346
|
-
format: 'depth24plus',
|
|
347
|
-
depthWriteEnabled: program.depthWrite,
|
|
348
|
-
depthCompare: program.depthTest === false ? 'always' : 'less-equal',
|
|
349
|
-
},
|
|
350
|
-
});
|
|
351
|
-
program.pipelineCache.set(pipelineKey, pipeline);
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const uniforms = program.uniforms;
|
|
355
|
-
const renderer = backend.renderer;
|
|
356
|
-
const offset = renderer.uniformSlot++ * 256;
|
|
357
|
-
const data = renderer.uniformData, base = offset / 4;
|
|
358
|
-
data.set(mesh.worldMatrix, base);
|
|
359
|
-
data.set(uniforms.baseColor.value, base + 16);
|
|
360
|
-
data[base + 19] = 1;
|
|
361
|
-
data[base + 20] = uniforms.metallic.value;
|
|
362
|
-
data[base + 21] = uniforms.roughness.value;
|
|
363
|
-
data[base + 22] = uniforms.opacity.value;
|
|
364
|
-
data[base + 23] = uniforms.alphaCutoff.value;
|
|
365
|
-
data.set(uniforms.emissive.value, base + 24);
|
|
366
|
-
data[base + 27] = uniforms.occlusionStrength.value;
|
|
367
|
-
data[base + 28] = mesh.terrain?.[0] ?? 0;
|
|
368
|
-
data[base + 29] = mesh.terrain?.[1] ?? 0;
|
|
369
|
-
data[base + 30] = mesh.terrain?.[2] ?? 0;
|
|
370
|
-
data[base + 31] = mesh.terrain?.[3] ?? 0;
|
|
371
|
-
data[base + 32] = mesh.highlight?.[0] ?? 0;
|
|
372
|
-
data[base + 33] = mesh.highlight?.[1] ?? 0;
|
|
373
|
-
data[base + 34] = program.nightSparkle ? data[55] : 0;
|
|
374
|
-
data[base + 35] = 0;
|
|
375
|
-
|
|
376
|
-
const textures = mesh._textures ||= [];
|
|
377
|
-
textures.length = 0;
|
|
378
|
-
for (const binding of program.bindings) {
|
|
379
|
-
const texture = uniforms[binding.name]?.value;
|
|
380
|
-
if (!texture) throw new Error(`Missing Layer3D texture: ${binding.name}`);
|
|
381
|
-
if (texture.uploaded !== texture.image) {
|
|
382
|
-
device.queue.copyExternalImageToTexture(
|
|
383
|
-
{ source: texture.image, flipY: Boolean(texture.flipY) },
|
|
384
|
-
{ texture: texture.texture },
|
|
385
|
-
[texture.image.width, texture.image.height],
|
|
386
|
-
);
|
|
387
|
-
texture.uploaded = texture.image;
|
|
388
|
-
}
|
|
389
|
-
textures.push(texture);
|
|
390
|
-
}
|
|
391
|
-
let bindingsChanged = !mesh.bindGroup || mesh.boundBuffer !== renderer.uniformBuffer ||
|
|
392
|
-
textures.length !== mesh.boundTextures.length;
|
|
393
|
-
for (let i = 0; !bindingsChanged && i < textures.length; i++) {
|
|
394
|
-
if (textures[i].texture !== mesh.boundTextures[i][0] ||
|
|
395
|
-
textures[i].sampler !== mesh.boundTextures[i][1]) bindingsChanged = true;
|
|
396
|
-
}
|
|
397
|
-
if (bindingsChanged) {
|
|
398
|
-
const entries = [
|
|
399
|
-
{ binding: 0, resource: { buffer: renderer.uniformBuffer, size: 144 } },
|
|
400
|
-
{ binding: 1, resource: { buffer: renderer.uniformBuffer, size: 240 } },
|
|
401
|
-
];
|
|
402
|
-
if (program.terrain) entries.push({ binding: 2, resource: program.terrain.texture.createView() });
|
|
403
|
-
mesh.boundBuffer = renderer.uniformBuffer;
|
|
404
|
-
const boundTextures = mesh.boundTextures ||= [];
|
|
405
|
-
boundTextures.length = textures.length;
|
|
406
|
-
for (let i = 0; i < textures.length; i++) {
|
|
407
|
-
const binding = program.bindings[i], texture = textures[i];
|
|
408
|
-
entries.push({ binding: binding.texture, resource: texture.texture.createView() });
|
|
409
|
-
entries.push({ binding: binding.sampler, resource: texture.sampler });
|
|
410
|
-
boundTextures[i] ||= [];
|
|
411
|
-
boundTextures[i][0] = texture.texture;
|
|
412
|
-
boundTextures[i][1] = texture.sampler;
|
|
413
|
-
}
|
|
414
|
-
mesh.bindGroup = device.createBindGroup({
|
|
415
|
-
layout: program.bindGroupLayout,
|
|
416
|
-
entries,
|
|
417
|
-
});
|
|
418
|
-
}
|
|
419
|
-
pass.setPipeline(pipeline);
|
|
420
|
-
pass.setBindGroup(0, mesh.bindGroup, [offset]);
|
|
421
|
-
pass.setVertexBuffer(0, geometry.attributes.position.buffer);
|
|
422
|
-
pass.setVertexBuffer(1, geometry.attributes.normal.buffer);
|
|
423
|
-
if (geometry.attributes.color) pass.setVertexBuffer(2, geometry.attributes.color.buffer);
|
|
424
|
-
if (geometry.attributes.uv) pass.setVertexBuffer(3, geometry.attributes.uv.buffer);
|
|
425
|
-
for (const attribute of Object.values(geometry.attributes)) {
|
|
426
|
-
if (!attribute.needsUpdate) continue;
|
|
427
|
-
device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
|
|
428
|
-
attribute.needsUpdate = false;
|
|
429
|
-
geometry.bounds = null;
|
|
430
|
-
}
|
|
431
|
-
const index = geometry.attributes.index;
|
|
432
|
-
if (index) {
|
|
433
|
-
pass.setIndexBuffer(index.buffer, index.indexFormat);
|
|
434
|
-
pass.drawIndexed(geometry.drawRange.count, 1, geometry.drawRange.start, 0, 0);
|
|
435
|
-
} else {
|
|
436
|
-
pass.draw(geometry.drawRange.count, 1, geometry.drawRange.start, 0);
|
|
437
|
-
}
|
|
438
|
-
}
|
package/src/scene/lighting.js
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
import { lightGrid, worldLights } from '../utils/lighting.js';
|
|
2
|
-
import { computeBounds } from '../utils/geometry.js';
|
|
3
|
-
import { traverse, updateCamera } from '../utils/scene.js';
|
|
4
|
-
|
|
5
|
-
/** Sunlight shadow maps and night point lights. */
|
|
6
|
-
export function initSunlight(backend) {
|
|
7
|
-
const device = backend.renderer.device;
|
|
8
|
-
const layout = device.createBindGroupLayout({ entries: [
|
|
9
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } },
|
|
10
|
-
{ binding: 1, visibility: GPUShaderStage.FRAGMENT, texture: { sampleType: 'depth' } },
|
|
11
|
-
{ binding: 2, visibility: GPUShaderStage.FRAGMENT, sampler: { type: 'comparison' } },
|
|
12
|
-
{ binding: 3, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'read-only-storage' } },
|
|
13
|
-
] });
|
|
14
|
-
const buffer = device.createBuffer({ size: 80, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST });
|
|
15
|
-
const sampler = device.createSampler({ compare: 'less-equal', minFilter: 'linear', magFilter: 'linear' });
|
|
16
|
-
const lights = device.createBuffer({ size: 32, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
|
|
17
|
-
backend.renderer.sunlight = { layout, buffer, sampler, lights, size: 0 };
|
|
18
|
-
const values = new Float32Array(20);
|
|
19
|
-
values.set([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
20
|
-
device.queue.writeBuffer(buffer, 0, values);
|
|
21
|
-
backend._resizeSunlight(1);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function resizeSunlight(backend, size) {
|
|
25
|
-
const device = backend.renderer.device, sun = backend.renderer.sunlight;
|
|
26
|
-
if (sun.size === size) return;
|
|
27
|
-
if (sun.texture) backend._destroyTexture(sun.texture);
|
|
28
|
-
sun.size = size;
|
|
29
|
-
sun.texture = device.createTexture({
|
|
30
|
-
size: [size, size], format: 'depth32float',
|
|
31
|
-
usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC,
|
|
32
|
-
});
|
|
33
|
-
backend._bindSunlight();
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function bindSunlight(backend) {
|
|
37
|
-
const sun = backend.renderer.sunlight;
|
|
38
|
-
sun.bindGroup = backend.renderer.device.createBindGroup({ layout: sun.layout, entries: [
|
|
39
|
-
{ binding: 0, resource: { buffer: sun.buffer } },
|
|
40
|
-
{ binding: 1, resource: sun.texture.createView() },
|
|
41
|
-
{ binding: 2, resource: sun.sampler },
|
|
42
|
-
{ binding: 3, resource: { buffer: sun.lights } },
|
|
43
|
-
] });
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** A cached spatial grid limits fragment lighting to nearby lamps, without dropping dense cells. */
|
|
47
|
-
export function updatePointLights(backend) {
|
|
48
|
-
const { device, sunlight: sun } = backend.renderer;
|
|
49
|
-
const meshes = [];
|
|
50
|
-
for (const layer of backend._layers) {
|
|
51
|
-
if (!layer.options.nightLight || !layer.root.visible) continue;
|
|
52
|
-
traverse(layer.root, mesh => {
|
|
53
|
-
if (!mesh.visible) return true;
|
|
54
|
-
if (mesh.extras?.lights) meshes.push(mesh);
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
if (sun.lightMeshes?.length === meshes.length && meshes.every((mesh, i) => sun.lightMeshes[i].mesh === mesh &&
|
|
58
|
-
sun.lightMeshes[i].lights === mesh.extras.lights && mesh.worldMatrix.every((v, j) => v === sun.lightMeshes[i].matrix[j]))) return;
|
|
59
|
-
// Per mesh, world-space [x, y, z, radius, r, g, b, intensity] per light: re-packed only when its lights or matrix change.
|
|
60
|
-
const packed = meshes.map(mesh => {
|
|
61
|
-
const cache = mesh._worldLights, m = mesh.worldMatrix, lights = mesh.extras.lights;
|
|
62
|
-
if (cache?.lights === lights && m.every((v, j) => v === cache.matrix[j])) return cache.data;
|
|
63
|
-
const values = worldLights(lights, m);
|
|
64
|
-
mesh._worldLights = { lights, matrix: [...m], data: values };
|
|
65
|
-
return values;
|
|
66
|
-
});
|
|
67
|
-
const { data, count } = lightGrid(packed, device.limits.maxStorageBufferBindingSize);
|
|
68
|
-
if (sun.lights.size < data.byteLength) {
|
|
69
|
-
backend._destroyTexture(sun.lights);
|
|
70
|
-
sun.lights = device.createBuffer({ size: data.byteLength, usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST });
|
|
71
|
-
backend._bindSunlight();
|
|
72
|
-
}
|
|
73
|
-
device.queue.writeBuffer(sun.lights, 0, data);
|
|
74
|
-
sun.lightCount = count;
|
|
75
|
-
sun.lightMeshes = meshes.map(mesh => ({ mesh, lights: mesh.extras.lights, matrix: [...mesh.worldMatrix] }));
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** One shared directional depth map. Off-screen but loaded geometry can cast shadows. */
|
|
79
|
-
export function renderSunlight(backend, encoder, meshes, sunlight) {
|
|
80
|
-
const renderer = backend.renderer, device = renderer.device, sun = renderer.sunlight;
|
|
81
|
-
if (!meshes.length || !sunlight || sunlight.altitude < 3) {
|
|
82
|
-
if (!sun.enabled) return;
|
|
83
|
-
const values = new Float32Array(20);
|
|
84
|
-
values.set([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
|
|
85
|
-
device.queue.writeBuffer(sun.buffer, 0, values);
|
|
86
|
-
sun.enabled = false;
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
const values = new Float32Array(20);
|
|
90
|
-
sun.enabled = true;
|
|
91
|
-
backend._resizeSunlight(Math.min(2048, device.limits.maxTextureDimension2D));
|
|
92
|
-
const min = [Infinity, Infinity, Infinity], max = [-Infinity, -Infinity, -Infinity];
|
|
93
|
-
for (const mesh of meshes) {
|
|
94
|
-
if (!mesh.geometry.bounds) computeBounds(mesh.geometry);
|
|
95
|
-
const bounds = mesh.geometry.bounds, matrix = new DOMMatrix(mesh.worldMatrix);
|
|
96
|
-
for (let i = 0; i < 8; i++) {
|
|
97
|
-
const point = new DOMPoint(...min.map((_, axis) => (i & (1 << axis)) ? bounds.max[axis] : bounds.min[axis]), 1)
|
|
98
|
-
.matrixTransform(matrix);
|
|
99
|
-
for (let axis = 0; axis < 3; axis++) {
|
|
100
|
-
const value = [point.x, point.y, point.z][axis] / point.w;
|
|
101
|
-
min[axis] = Math.min(min[axis], value);
|
|
102
|
-
max[axis] = Math.max(max[axis], value);
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
// Include ground receivers below/around the loaded buildings and trees.
|
|
107
|
-
min[1] = Math.min(0, min[1]);
|
|
108
|
-
const radius = Math.max(100, Math.hypot(...min.map((v, i) => max[i] - v)));
|
|
109
|
-
const center = min.map((v, i) => (v + max[i]) / 2);
|
|
110
|
-
const lightCamera = {
|
|
111
|
-
position: center.map((v, i) => v + sunlight.direction[i] * radius * 2),
|
|
112
|
-
target: center, up: [0, 0, -1], fov: 45, aspect: 1, near: 1, far: radius * 5,
|
|
113
|
-
viewMatrix: [], projectionMatrix: [], projectionViewMatrix: [],
|
|
114
|
-
};
|
|
115
|
-
updateCamera(lightCamera);
|
|
116
|
-
const view = new DOMMatrix(lightCamera.viewMatrix);
|
|
117
|
-
const low = [Infinity, Infinity, Infinity], high = [-Infinity, -Infinity, -Infinity];
|
|
118
|
-
for (let i = 0; i < 8; i++) {
|
|
119
|
-
const point = new DOMPoint(...min.map((v, axis) => (i & (1 << axis)) ? max[axis] : v), 1).matrixTransform(view);
|
|
120
|
-
[point.x, point.y, point.z].forEach((value, axis) => {
|
|
121
|
-
low[axis] = Math.min(low[axis], value - 20);
|
|
122
|
-
high[axis] = Math.max(high[axis], value + 20);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
const span = low.map((v, i) => high[i] - v);
|
|
126
|
-
const projection = new DOMMatrix([
|
|
127
|
-
2 / span[0], 0, 0, 0, 0, 2 / span[1], 0, 0, 0, 0, -1 / span[2], 0,
|
|
128
|
-
-(high[0] + low[0]) / span[0], -(high[1] + low[1]) / span[1], high[2] / span[2], 1,
|
|
129
|
-
]);
|
|
130
|
-
values.set(projection.multiply(view).toFloat32Array());
|
|
131
|
-
values[16] = 1;
|
|
132
|
-
device.queue.writeBuffer(sun.buffer, 0, values);
|
|
133
|
-
if (!sun.pipeline) {
|
|
134
|
-
sun.meshLayout = device.createBindGroupLayout({ entries: [
|
|
135
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform', hasDynamicOffset: true } },
|
|
136
|
-
] });
|
|
137
|
-
// Do not bind the sampled depth texture while it is a render attachment.
|
|
138
|
-
sun.depthLayout = device.createBindGroupLayout({ entries: [
|
|
139
|
-
{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
|
|
140
|
-
] });
|
|
141
|
-
sun.depthBindGroup = device.createBindGroup({
|
|
142
|
-
layout: sun.depthLayout, entries: [{ binding: 0, resource: { buffer: sun.buffer } }],
|
|
143
|
-
});
|
|
144
|
-
const shader = device.createShaderModule({ code: `
|
|
145
|
-
struct Mesh { world: mat4x4<f32> };
|
|
146
|
-
@group(0) @binding(0) var<uniform> mesh: Mesh;
|
|
147
|
-
@group(1) @binding(0) var<uniform> matrix: mat4x4<f32>;
|
|
148
|
-
@vertex fn main(@location(0) position: vec3<f32>) -> @builtin(position) vec4<f32> {
|
|
149
|
-
return matrix * mesh.world * vec4<f32>(position, 1.0);
|
|
150
|
-
}
|
|
151
|
-
` });
|
|
152
|
-
sun.pipeline = device.createRenderPipeline({
|
|
153
|
-
layout: device.createPipelineLayout({ bindGroupLayouts: [sun.meshLayout, sun.depthLayout] }),
|
|
154
|
-
vertex: { module: shader, entryPoint: 'main', buffers: [
|
|
155
|
-
{ arrayStride: 12, attributes: [{ shaderLocation: 0, offset: 0, format: 'float32x3' }] },
|
|
156
|
-
] },
|
|
157
|
-
primitive: { topology: 'triangle-list', cullMode: 'none' },
|
|
158
|
-
depthStencil: { format: 'depth32float', depthWriteEnabled: true, depthCompare: 'less',
|
|
159
|
-
depthBias: 2, depthBiasSlopeScale: 2 },
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
const pass = encoder.beginRenderPass({
|
|
163
|
-
colorAttachments: [],
|
|
164
|
-
depthStencilAttachment: { view: sun.texture.createView(), depthClearValue: 1,
|
|
165
|
-
depthLoadOp: 'clear', depthStoreOp: 'store' },
|
|
166
|
-
});
|
|
167
|
-
pass.setPipeline(sun.pipeline);
|
|
168
|
-
pass.setBindGroup(1, sun.depthBindGroup);
|
|
169
|
-
for (const mesh of meshes) {
|
|
170
|
-
const offset = renderer.uniformSlot++ * 256;
|
|
171
|
-
renderer.uniformData.set(mesh.worldMatrix, offset / 4);
|
|
172
|
-
if (mesh._shadowBuffer !== renderer.uniformBuffer) {
|
|
173
|
-
mesh._shadowBuffer = renderer.uniformBuffer;
|
|
174
|
-
mesh._shadowBindGroup = device.createBindGroup({ layout: sun.meshLayout, entries: [
|
|
175
|
-
{ binding: 0, resource: { buffer: renderer.uniformBuffer, size: 64 } },
|
|
176
|
-
] });
|
|
177
|
-
}
|
|
178
|
-
for (const attribute of Object.values(mesh.geometry.attributes)) {
|
|
179
|
-
if (attribute.needsUpdate) {
|
|
180
|
-
device.queue.writeBuffer(attribute.buffer, 0, attribute.data);
|
|
181
|
-
attribute.needsUpdate = false;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
pass.setBindGroup(0, mesh._shadowBindGroup, [offset]);
|
|
185
|
-
pass.setVertexBuffer(0, mesh.geometry.attributes.position.buffer);
|
|
186
|
-
const index = mesh.geometry.attributes.index, range = mesh.geometry.drawRange;
|
|
187
|
-
if (index) {
|
|
188
|
-
pass.setIndexBuffer(index.buffer, index.indexFormat);
|
|
189
|
-
pass.drawIndexed(range.count, 1, range.start, 0, 0);
|
|
190
|
-
} else pass.draw(range.count, 1, range.start, 0);
|
|
191
|
-
}
|
|
192
|
-
pass.end();
|
|
193
|
-
}
|