@navaramap/three 0.0.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.
- package/LICENSE +8 -0
- package/dist/assets/atmosphere/README.md +1 -0
- package/dist/assets/atmosphere/higher_order_scattering.bin +0 -0
- package/dist/assets/atmosphere/higher_order_scattering.exr +0 -0
- package/dist/assets/atmosphere/irradiance.bin +0 -0
- package/dist/assets/atmosphere/irradiance.exr +0 -0
- package/dist/assets/atmosphere/scattering.bin +0 -0
- package/dist/assets/atmosphere/scattering.exr +0 -0
- package/dist/assets/atmosphere/single_mie_scattering.bin +0 -0
- package/dist/assets/atmosphere/single_mie_scattering.exr +0 -0
- package/dist/assets/atmosphere/stars.bin +0 -0
- package/dist/assets/atmosphere/transmittance.bin +0 -0
- package/dist/assets/atmosphere/transmittance.exr +0 -0
- package/dist/assets/cloud/README.md +1 -0
- package/dist/assets/cloud/local_weather.png +0 -0
- package/dist/assets/cloud/shape.bin +1 -0
- package/dist/assets/cloud/shape_detail.bin +1 -0
- package/dist/assets/cloud/turbulence.png +0 -0
- package/dist/assets/fontWorker-CEJEfRpb.js +2 -0
- package/dist/assets/fontWorker-CEJEfRpb.js.map +1 -0
- package/dist/assets/index-BUB-ijMO.js +12 -0
- package/dist/assets/index-BUB-ijMO.js.map +1 -0
- package/dist/assets/navara_wasm_font_worker_bg-665OLxjy.wasm +0 -0
- package/dist/assets/navara_wasm_worker_bg-BXhKC5bE.wasm +0 -0
- package/dist/assets/noise/README.md +1 -0
- package/dist/assets/noise/stbn.bin +0 -0
- package/dist/assets/water/README.md +3 -0
- package/dist/assets/water/waternormals.jpg +0 -0
- package/dist/index.d.ts +10114 -0
- package/dist/index.js +34481 -0
- package/dist/index.js.map +1 -0
- package/dist/index.umd.cjs +6345 -0
- package/dist/index.umd.cjs.map +1 -0
- package/package.json +95 -0
- package/src/Color.ts +111 -0
- package/src/ShadowMapViewers.ts +49 -0
- package/src/atmosphere.test.ts +76 -0
- package/src/atmosphere.ts +364 -0
- package/src/bufferView.ts +90 -0
- package/src/camera.ts +182 -0
- package/src/concurrency.ts +15 -0
- package/src/constants/assets.ts +30 -0
- package/src/constants/decoder.ts +7 -0
- package/src/constants/index.ts +2 -0
- package/src/core/BaseDesc.ts +142 -0
- package/src/core/BaseHandle.ts +126 -0
- package/src/core/DescRegistry.ts +88 -0
- package/src/core/EffectDesc.ts +343 -0
- package/src/core/EffectDescRegistry.ts +31 -0
- package/src/core/InstancedMeshDesc.ts +413 -0
- package/src/core/LightDesc.ts +216 -0
- package/src/core/LightDescRegistry.ts +32 -0
- package/src/core/MeshDesc.ts +457 -0
- package/src/core/MeshDescRegistry.ts +32 -0
- package/src/core/MeshDescWithSelectiveEffect.ts +129 -0
- package/src/core/Registries.ts +59 -0
- package/src/core/SelectiveEffectRegistry.ts +90 -0
- package/src/core/ViewContext.ts +235 -0
- package/src/core/errors.ts +16 -0
- package/src/core/index.ts +50 -0
- package/src/device.ts +414 -0
- package/src/effects/CustomEffectPass.ts +28 -0
- package/src/effects/copy.ts +10 -0
- package/src/effects/effect.ts +87 -0
- package/src/effects/index.ts +4 -0
- package/src/effects/render.ts +10 -0
- package/src/evaluations/FeatureEvaluator.ts +529 -0
- package/src/evaluations/index.ts +1 -0
- package/src/event/HillshadeContext.test.ts +232 -0
- package/src/event/HillshadeContext.ts +299 -0
- package/src/event/context.ts +279 -0
- package/src/event/feature.ts +357 -0
- package/src/event/featureEvent.ts +81 -0
- package/src/event/features/billboard.ts +30 -0
- package/src/event/features/model.ts +192 -0
- package/src/event/features/modelGpuBytes.test.ts +69 -0
- package/src/event/features/modelGpuBytes.ts +87 -0
- package/src/event/features/point.ts +25 -0
- package/src/event/features/polygon.ts +23 -0
- package/src/event/features/polygonOutline.ts +19 -0
- package/src/event/features/polyline.ts +19 -0
- package/src/event/features/text.ts +71 -0
- package/src/event/hillshade.test.ts +842 -0
- package/src/event/hillshade.ts +588 -0
- package/src/event/index.ts +700 -0
- package/src/event/loaders.ts +53 -0
- package/src/event/tile.ts +19 -0
- package/src/event/worker.ts +999 -0
- package/src/event/workerTaskSettlement.test.ts +243 -0
- package/src/event/workerTaskSettlement.ts +128 -0
- package/src/inMemoryBufferStore.test.ts +60 -0
- package/src/inMemoryBufferStore.ts +67 -0
- package/src/index.iife.ts +11 -0
- package/src/index.ts +2556 -0
- package/src/input.ts +144 -0
- package/src/layer.ts +183 -0
- package/src/layers/effect/FinalCopyEffectDesc.ts +29 -0
- package/src/layers/effect/MRTPassEffectDesc.ts +105 -0
- package/src/layers/effect/README.md +9 -0
- package/src/layers/effect/SelectiveEffectDesc.ts +113 -0
- package/src/layers/effect/SkyEnvMapEffectDesc.ts +58 -0
- package/src/layers/effect/TransparentPassEffectDesc.ts +62 -0
- package/src/layers/effect/index.ts +5 -0
- package/src/layers/index.ts +1 -0
- package/src/layersManager.ts +63 -0
- package/src/light.ts +15 -0
- package/src/loaders/AbortableImageLoader.ts +203 -0
- package/src/loaders/AbortableTextureLoader.ts +74 -0
- package/src/loaders/index.ts +5 -0
- package/src/material/enhancer/DESIGN.md +300 -0
- package/src/material/enhancer/MaterialEnhancer.ts +112 -0
- package/src/material/enhancer/ShaderReplacer.test.ts +114 -0
- package/src/material/enhancer/ShaderReplacer.ts +97 -0
- package/src/material/enhancer/batchTexture.ts +8 -0
- package/src/material/enhancer/index.ts +46 -0
- package/src/material/enhancer/instancedSprite/index.ts +7 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.test.ts +214 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/index.ts +134 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/markers.ts +21 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/material.ts +32 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.test.ts +277 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.ts +151 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.test.ts +114 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/shader.ts +49 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.test.ts +82 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/state.ts +80 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/types.ts +146 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteMaterialEnhancer.ts +105 -0
- package/src/material/enhancer/model/index.ts +25 -0
- package/src/material/enhancer/model/modelBaseEnhancer/index.test.ts +74 -0
- package/src/material/enhancer/model/modelBaseEnhancer/index.ts +110 -0
- package/src/material/enhancer/model/modelBaseEnhancer/markers.ts +27 -0
- package/src/material/enhancer/model/modelBaseEnhancer/material.test.ts +66 -0
- package/src/material/enhancer/model/modelBaseEnhancer/material.ts +44 -0
- package/src/material/enhancer/model/modelBaseEnhancer/mutates.test.ts +84 -0
- package/src/material/enhancer/model/modelBaseEnhancer/mutates.ts +47 -0
- package/src/material/enhancer/model/modelBaseEnhancer/shader.test.ts +24 -0
- package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +162 -0
- package/src/material/enhancer/model/modelBaseEnhancer/state.test.ts +103 -0
- package/src/material/enhancer/model/modelBaseEnhancer/state.ts +52 -0
- package/src/material/enhancer/model/modelBaseEnhancer/types.ts +89 -0
- package/src/material/enhancer/model/modelMaterialEnhancer.ts +91 -0
- package/src/material/enhancer/model/modelWaterEnhancer/index.test.ts +71 -0
- package/src/material/enhancer/model/modelWaterEnhancer/index.ts +175 -0
- package/src/material/enhancer/model/modelWaterEnhancer/material.test.ts +48 -0
- package/src/material/enhancer/model/modelWaterEnhancer/material.ts +25 -0
- package/src/material/enhancer/model/modelWaterEnhancer/mutates.test.ts +89 -0
- package/src/material/enhancer/model/modelWaterEnhancer/mutates.ts +89 -0
- package/src/material/enhancer/model/modelWaterEnhancer/shader.test.ts +34 -0
- package/src/material/enhancer/model/modelWaterEnhancer/shader.ts +111 -0
- package/src/material/enhancer/model/modelWaterEnhancer/state.test.ts +105 -0
- package/src/material/enhancer/model/modelWaterEnhancer/state.ts +59 -0
- package/src/material/enhancer/model/modelWaterEnhancer/types.ts +141 -0
- package/src/material/enhancer/model/pntsEnhancer/index.test.ts +96 -0
- package/src/material/enhancer/model/pntsEnhancer/index.ts +82 -0
- package/src/material/enhancer/model/pntsEnhancer/markers.ts +6 -0
- package/src/material/enhancer/model/pntsEnhancer/material.test.ts +37 -0
- package/src/material/enhancer/model/pntsEnhancer/material.ts +21 -0
- package/src/material/enhancer/model/pntsEnhancer/mutates.test.ts +80 -0
- package/src/material/enhancer/model/pntsEnhancer/mutates.ts +29 -0
- package/src/material/enhancer/model/pntsEnhancer/shader.test.ts +32 -0
- package/src/material/enhancer/model/pntsEnhancer/shader.ts +56 -0
- package/src/material/enhancer/model/pntsEnhancer/state.test.ts +87 -0
- package/src/material/enhancer/model/pntsEnhancer/state.ts +29 -0
- package/src/material/enhancer/model/pntsEnhancer/types.ts +38 -0
- package/src/material/enhancer/polygon/index.ts +22 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/index.test.ts +101 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/index.ts +130 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/markers.ts +23 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/material.test.ts +19 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/material.ts +38 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.test.ts +75 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +122 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.test.ts +25 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +249 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/state.test.ts +102 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/state.ts +92 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +150 -0
- package/src/material/enhancer/polygon/polygonMaterialEnhancer.ts +97 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/index.test.ts +72 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/index.ts +164 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/material.test.ts +48 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/material.ts +35 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/mutates.ts +61 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.test.ts +34 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/shader.ts +96 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/state.test.ts +98 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/state.ts +57 -0
- package/src/material/enhancer/polygon/polygonWaterEnhancer/types.ts +115 -0
- package/src/material/enhancer/polyline/index.ts +7 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/index.test.ts +157 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/index.ts +154 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/markers.ts +19 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/material.test.ts +42 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/material.ts +38 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.test.ts +120 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.ts +169 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.test.ts +67 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/shader.ts +75 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/state.test.ts +55 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/state.ts +91 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/types.ts +170 -0
- package/src/material/enhancer/polyline/polylineMaterialEnhancer.ts +102 -0
- package/src/material/enhancer/sdfText/index.ts +7 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/index.ts +125 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/markers.ts +19 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.test.ts +35 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/material.ts +32 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.test.ts +381 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +232 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/shader.ts +36 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.test.ts +118 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/state.ts +107 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +184 -0
- package/src/material/enhancer/sdfText/sdfTextMaterialEnhancer.ts +100 -0
- package/src/material/enhancer/shadowMap/index.ts +7 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/index.ts +97 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/markers.ts +10 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/material.ts +31 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/mutates.ts +8 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.test.ts +17 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/shader.ts +53 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/state.ts +17 -0
- package/src/material/enhancer/shadowMap/shadowMapDepthEnhancer/types.ts +26 -0
- package/src/material/enhancer/test-utils/shaderCompatibility.ts +124 -0
- package/src/material/enhancer/tileComposite/compose.test.ts +95 -0
- package/src/material/enhancer/tileComposite/compose.ts +112 -0
- package/src/material/enhancer/tileComposite/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/index.ts +11 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +132 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/shader.ts +245 -0
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/types.ts +43 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/index.ts +29 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/mutates.ts +68 -0
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/shader.ts +24 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/index.ts +29 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/mutates.ts +34 -0
- package/src/material/enhancer/tileComposite/tileHillshadeEnhancer/shader.ts +36 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/mutates.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWaterEnhancer/shader.ts +8 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/index.ts +23 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/mutates.ts +34 -0
- package/src/material/enhancer/tileComposite/tileWatermaskEnhancer/shader.ts +13 -0
- package/src/material/enhancer/tileComposite/types.ts +58 -0
- package/src/material/index.ts +3 -0
- package/src/material/macro/index.ts +1 -0
- package/src/material/macro/tileShader.test.ts +136 -0
- package/src/material/macro/tileShader.ts +287 -0
- package/src/material/overrideMaterialsForMRT.ts +439 -0
- package/src/material/selectiveEffectMaterialSetup.test.ts +52 -0
- package/src/material/selectiveEffectMaterialSetup.ts +53 -0
- package/src/material/types/index.ts +1 -0
- package/src/material/types/uniform.ts +1 -0
- package/src/mesh/DrapedMesh.ts +101 -0
- package/src/mesh/batchTexture.test.ts +646 -0
- package/src/mesh/batchTexture.ts +437 -0
- package/src/mesh/batchedFeature.ts +186 -0
- package/src/mesh/batchedSdfText.ts +484 -0
- package/src/mesh/featureMesh.ts +43 -0
- package/src/mesh/index.ts +16 -0
- package/src/mesh/instanced.ts +117 -0
- package/src/mesh/model.ts +483 -0
- package/src/mesh/pickableMesh.ts +55 -0
- package/src/mesh/pickableMeshWrapper.ts +529 -0
- package/src/mesh/polygon.ts +699 -0
- package/src/mesh/polygonOutline.ts +393 -0
- package/src/mesh/polyline.ts +523 -0
- package/src/mesh/releaseGeometryArrays.ts +57 -0
- package/src/mesh/rtcRteHelper.ts +211 -0
- package/src/mesh/sdfText.test.ts +200 -0
- package/src/mesh/sdfText.ts +1019 -0
- package/src/mesh/sprite/billboardAtlas.test.ts +177 -0
- package/src/mesh/sprite/billboardAtlas.ts +210 -0
- package/src/mesh/sprite/billboardAtlasImageLoader.ts +29 -0
- package/src/mesh/sprite/index.ts +1 -0
- package/src/mesh/sprite/instancedSprite.ts +694 -0
- package/src/mesh/tile.test.ts +393 -0
- package/src/mesh/tile.ts +1790 -0
- package/src/object3DEvent.ts +6 -0
- package/src/orchestrators/RenderPassOrchestrator.ts +147 -0
- package/src/orchestrators/index.ts +1 -0
- package/src/passes/AllDepthCopyPass.ts +165 -0
- package/src/passes/CustomRenderPass.ts +279 -0
- package/src/passes/NormalCopyPass.ts +125 -0
- package/src/passes/RenderTargetCopyPass.ts +91 -0
- package/src/passes/SkyEnvMapPass.ts +58 -0
- package/src/passes/index.ts +5 -0
- package/src/pick/pickHelper.ts +273 -0
- package/src/pick/pickTerrain.ts +254 -0
- package/src/plugins/AttributionPlugin/AttributionPlugin.test.ts +210 -0
- package/src/plugins/AttributionPlugin/attribution.test.ts +225 -0
- package/src/plugins/AttributionPlugin/attribution.ts +355 -0
- package/src/plugins/AttributionPlugin/attributionStyles.ts +163 -0
- package/src/plugins/AttributionPlugin/index.ts +702 -0
- package/src/plugins/index.ts +1 -0
- package/src/quality.ts +1 -0
- package/src/renderOrder.ts +3 -0
- package/src/scene.test.ts +164 -0
- package/src/scene.ts +127 -0
- package/src/shaders/index.ts +1 -0
- package/src/solar.test.ts +81 -0
- package/src/solar.ts +101 -0
- package/src/source.ts +80 -0
- package/src/stats.ts +102 -0
- package/src/tasks/computeVertexNormalsAsync.ts +15 -0
- package/src/tasks/constructPolygonBatchedFeature.ts +34 -0
- package/src/tasks/constructPolylineBatchedFeature.ts +27 -0
- package/src/tasks/constructQuantizedMeshTerrainMesh.ts +24 -0
- package/src/tasks/constructTerrainMesh.ts +25 -0
- package/src/tasks/getImageDataFromBlob.ts +13 -0
- package/src/tasks/getImageDataFromImageBitmap.ts +12 -0
- package/src/tasks/parseMvtTile.ts +22 -0
- package/src/tasks/queueTask.ts +19 -0
- package/src/tasks/toCreasedNormalsAsync.ts +18 -0
- package/src/tasks/upsampleQuantizedMeshTerrainMesh.ts +44 -0
- package/src/tasks/upsampleTerrainMesh.ts +39 -0
- package/src/texture.ts +19 -0
- package/src/textures.ts +13 -0
- package/src/tileTexture/CompositeShader.snapshot.test.ts +59 -0
- package/src/tileTexture/CompositeShader.test.ts +168 -0
- package/src/tileTexture/CompositeShader.ts +53 -0
- package/src/tileTexture/SlotPlanner.test.ts +105 -0
- package/src/tileTexture/SlotPlanner.ts +102 -0
- package/src/tileTexture/TileTextureCache.test.ts +227 -0
- package/src/tileTexture/TileTextureCache.ts +192 -0
- package/src/tileTexture/TileTextureCompositor.test.ts +260 -0
- package/src/tileTexture/TileTextureCompositor.ts +421 -0
- package/src/tileTexture/__snapshots__/CompositeShader.snapshot.test.ts.snap +2649 -0
- package/src/tileTexture/index.ts +8 -0
- package/src/tileTexture/types.ts +150 -0
- package/src/type/index.ts +261 -0
- package/src/uniforms.ts +20 -0
- package/src/utils/arraysEqual.ts +9 -0
- package/src/utils/blendModes.ts +80 -0
- package/src/utils/geometry.ts +53 -0
- package/src/utils/hillshadeNormalMapGenerator.ts +193 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/object.test.ts +14 -0
- package/src/utils/object.ts +7 -0
- package/src/utils/replacer.test.ts +42 -0
- package/src/utils/replacer.ts +89 -0
- package/src/utils/screen.ts +29 -0
- package/src/utils/textureFragmentIndex.test.ts +224 -0
- package/src/utils/textureFragmentIndex.ts +97 -0
- package/src/utils/worker.ts +3 -0
- package/src/vite-env.d.ts +2 -0
- package/src/worker/index.ts +13 -0
- package/src/worker/tasks/computeVertexNormals.ts +15 -0
- package/src/worker/tasks/toCreasedNormals.ts +22 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import { Mesh, BoxGeometry, MeshBasicMaterial } from "three";
|
|
2
|
+
import { describe, expect, it, vi } from "vitest";
|
|
3
|
+
|
|
4
|
+
import { TexturizedSceneByTileCoordinates } from "../scene";
|
|
5
|
+
|
|
6
|
+
import { TileTextureCompositor } from "./TileTextureCompositor";
|
|
7
|
+
import type { AtlasFactory, CompositeAtlas } from "./types";
|
|
8
|
+
|
|
9
|
+
// Minimal renderer mock — only the methods the compositor touches need to
|
|
10
|
+
// exist. We track `render` so tests can assert which scenes were drawn.
|
|
11
|
+
function makeRenderer() {
|
|
12
|
+
return {
|
|
13
|
+
autoClear: true,
|
|
14
|
+
getRenderTarget: vi.fn().mockReturnValue(null),
|
|
15
|
+
setRenderTarget: vi.fn(),
|
|
16
|
+
getClearColor: vi.fn().mockImplementation((c) => c),
|
|
17
|
+
getClearAlpha: vi.fn().mockReturnValue(1),
|
|
18
|
+
setClearColor: vi.fn(),
|
|
19
|
+
clear: vi.fn(),
|
|
20
|
+
render: vi.fn(),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function makeFakeAtlas(): CompositeAtlas {
|
|
25
|
+
const tex = (n: string) =>
|
|
26
|
+
({ name: n, needsUpdate: false }) as unknown as CompositeAtlas["color"];
|
|
27
|
+
return {
|
|
28
|
+
target: { dispose: vi.fn() } as unknown as CompositeAtlas["target"],
|
|
29
|
+
color: tex("color"),
|
|
30
|
+
attr: tex("attr"),
|
|
31
|
+
normal: tex("normal"),
|
|
32
|
+
dispose: vi.fn(),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const fakeFactory: AtlasFactory = () => makeFakeAtlas();
|
|
37
|
+
|
|
38
|
+
function setup() {
|
|
39
|
+
const renderer = makeRenderer();
|
|
40
|
+
const texturizedScenes = new TexturizedSceneByTileCoordinates(
|
|
41
|
+
renderer as unknown as ConstructorParameters<
|
|
42
|
+
typeof TexturizedSceneByTileCoordinates
|
|
43
|
+
>[0],
|
|
44
|
+
);
|
|
45
|
+
const compositor = new TileTextureCompositor({
|
|
46
|
+
renderer: renderer as unknown as ConstructorParameters<
|
|
47
|
+
typeof TileTextureCompositor
|
|
48
|
+
>[0]["renderer"],
|
|
49
|
+
texturizedSceneByTileCoordinates: texturizedScenes,
|
|
50
|
+
atlasFactory: fakeFactory,
|
|
51
|
+
});
|
|
52
|
+
return { compositor, renderer, texturizedScenes };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function mesh() {
|
|
56
|
+
return new Mesh(new BoxGeometry(1, 1, 1), new MeshBasicMaterial());
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
describe("TileTextureCompositor.acquire/release", () => {
|
|
60
|
+
it("acquire returns CompositeOutputs and dedupes by handle", () => {
|
|
61
|
+
const { compositor } = setup();
|
|
62
|
+
const out = compositor.acquire(1n);
|
|
63
|
+
expect(out.color).toBeDefined();
|
|
64
|
+
expect(out.attr).toBeDefined();
|
|
65
|
+
expect(out.normal).toBeDefined();
|
|
66
|
+
// Re-acquire returns same outputs (cache dedupes).
|
|
67
|
+
const again = compositor.acquire(1n);
|
|
68
|
+
expect(again.color).toBe(out.color);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it("release pools the atlas once refCount drops to zero", () => {
|
|
72
|
+
const { compositor } = setup();
|
|
73
|
+
compositor.acquire(1n);
|
|
74
|
+
compositor.acquire(1n);
|
|
75
|
+
const entry = compositor.cache.getEntry(1n);
|
|
76
|
+
if (!entry) throw new Error("expected entry");
|
|
77
|
+
const atlas = entry.atlas;
|
|
78
|
+
|
|
79
|
+
compositor.release(1n);
|
|
80
|
+
expect(atlas.dispose).not.toHaveBeenCalled();
|
|
81
|
+
expect(compositor.cache.pooledCount).toBe(0);
|
|
82
|
+
compositor.release(1n);
|
|
83
|
+
// The entry is gone but its atlas goes to the reuse pool, not dispose.
|
|
84
|
+
expect(compositor.cache.getEntry(1n)).toBeUndefined();
|
|
85
|
+
expect(atlas.dispose).not.toHaveBeenCalled();
|
|
86
|
+
expect(compositor.cache.pooledCount).toBe(1);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
describe("TileTextureCompositor.renderVectorScenes", () => {
|
|
91
|
+
const fakeRT = (): unknown => ({ texture: { needsUpdate: false } });
|
|
92
|
+
|
|
93
|
+
it("bakes each layer's resolved source into its render target", () => {
|
|
94
|
+
const { compositor, renderer, texturizedScenes } = setup();
|
|
95
|
+
texturizedScenes.add(1n, "layer-a", mesh(), 0);
|
|
96
|
+
texturizedScenes.add(2n, "layer-b", mesh(), 1);
|
|
97
|
+
|
|
98
|
+
const rt0 = fakeRT();
|
|
99
|
+
const rt1 = fakeRT();
|
|
100
|
+
compositor.renderVectorScenes(
|
|
101
|
+
[
|
|
102
|
+
{
|
|
103
|
+
layerId: "layer-a",
|
|
104
|
+
sources: [{ tileHandle: 1n, uvOffset: [0, 0], uvScale: [1, 1] }],
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
layerId: "layer-b",
|
|
108
|
+
sources: [{ tileHandle: 2n, uvOffset: [0, 0], uvScale: [1, 1] }],
|
|
109
|
+
},
|
|
110
|
+
],
|
|
111
|
+
[rt0 as never, rt1 as never],
|
|
112
|
+
);
|
|
113
|
+
|
|
114
|
+
// One render per populated slot; every target cleared and flagged.
|
|
115
|
+
expect(renderer.render).toHaveBeenCalledTimes(2);
|
|
116
|
+
expect(renderer.clear).toHaveBeenCalledTimes(2);
|
|
117
|
+
expect(
|
|
118
|
+
(rt0 as { texture: { needsUpdate: boolean } }).texture.needsUpdate,
|
|
119
|
+
).toBe(true);
|
|
120
|
+
expect(
|
|
121
|
+
(rt1 as { texture: { needsUpdate: boolean } }).texture.needsUpdate,
|
|
122
|
+
).toBe(true);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it("accumulates a layer's N:M sources into one render target, clearing once", () => {
|
|
126
|
+
const { compositor, renderer, texturizedScenes } = setup();
|
|
127
|
+
// Two WM source tiles overlapping one Geographic terrain tile, both backing
|
|
128
|
+
// the same layer (west half and east half).
|
|
129
|
+
texturizedScenes.add(1n, "layer-a", mesh(), 0);
|
|
130
|
+
texturizedScenes.add(2n, "layer-a", mesh(), 0);
|
|
131
|
+
|
|
132
|
+
compositor.renderVectorScenes(
|
|
133
|
+
[
|
|
134
|
+
{
|
|
135
|
+
layerId: "layer-a",
|
|
136
|
+
sources: [
|
|
137
|
+
{ tileHandle: 1n, uvOffset: [0, 0], uvScale: [0.5, 1] },
|
|
138
|
+
{ tileHandle: 2n, uvOffset: [0.5, 0], uvScale: [0.5, 1] },
|
|
139
|
+
],
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
[fakeRT() as never],
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Both sources drawn into the single RT, which was cleared exactly once so
|
|
146
|
+
// the second source mosaics with the first instead of wiping it. autoClear
|
|
147
|
+
// is disabled across the draws and restored afterwards.
|
|
148
|
+
expect(renderer.render).toHaveBeenCalledTimes(2);
|
|
149
|
+
expect(renderer.clear).toHaveBeenCalledTimes(1);
|
|
150
|
+
expect(renderer.autoClear).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("frames the terrain sub-rect when the source resolves to a coarser ancestor", () => {
|
|
154
|
+
const { compositor, renderer, texturizedScenes } = setup();
|
|
155
|
+
texturizedScenes.add(1n, "layer-a", mesh(), 0);
|
|
156
|
+
|
|
157
|
+
// NW quadrant of the ancestor: uvOffset=(0,0.5), uvScale=(0.5,0.5).
|
|
158
|
+
compositor.renderVectorScenes(
|
|
159
|
+
[
|
|
160
|
+
{
|
|
161
|
+
layerId: "layer-a",
|
|
162
|
+
sources: [
|
|
163
|
+
{ tileHandle: 1n, uvOffset: [0, 0.5], uvScale: [0.5, 0.5] },
|
|
164
|
+
],
|
|
165
|
+
},
|
|
166
|
+
],
|
|
167
|
+
[fakeRT() as never],
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
expect(renderer.render).toHaveBeenCalledTimes(1);
|
|
171
|
+
const cam = renderer.render.mock.calls[0][1] as {
|
|
172
|
+
left: number;
|
|
173
|
+
right: number;
|
|
174
|
+
bottom: number;
|
|
175
|
+
top: number;
|
|
176
|
+
};
|
|
177
|
+
// Matches ortho_camera_transform for the NW sub-tile: [-1,0]×[0,1].
|
|
178
|
+
expect(cam.left).toBe(-1);
|
|
179
|
+
expect(cam.right).toBe(0);
|
|
180
|
+
expect(cam.bottom).toBe(0);
|
|
181
|
+
expect(cam.top).toBe(1);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it("clears but does not render a source whose scene was removed", () => {
|
|
185
|
+
const { compositor, renderer, texturizedScenes } = setup();
|
|
186
|
+
const m = mesh();
|
|
187
|
+
texturizedScenes.add(1n, "layer-a", m, 0);
|
|
188
|
+
texturizedScenes.removeMesh(1n, "layer-a", m);
|
|
189
|
+
|
|
190
|
+
const rt = fakeRT();
|
|
191
|
+
compositor.renderVectorScenes(
|
|
192
|
+
[
|
|
193
|
+
{
|
|
194
|
+
layerId: "layer-a",
|
|
195
|
+
sources: [{ tileHandle: 1n, uvOffset: [0, 0], uvScale: [1, 1] }],
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
[rt as never],
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
expect(renderer.render).not.toHaveBeenCalled();
|
|
202
|
+
expect(renderer.clear).toHaveBeenCalledTimes(1);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
it("skips a never-touched render target that has no slot (no GPU allocation)", () => {
|
|
206
|
+
const { compositor, renderer } = setup();
|
|
207
|
+
|
|
208
|
+
const rt = fakeRT();
|
|
209
|
+
compositor.renderVectorScenes([], [rt as never]);
|
|
210
|
+
|
|
211
|
+
// Render-targeting the RT would create its GL framebuffer; an empty slot
|
|
212
|
+
// whose target was never baked must not pay that cost.
|
|
213
|
+
expect(renderer.setRenderTarget).not.toHaveBeenCalledWith(rt);
|
|
214
|
+
expect(renderer.render).not.toHaveBeenCalled();
|
|
215
|
+
expect(renderer.clear).not.toHaveBeenCalled();
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("clears a previously-baked render target whose slot went away", () => {
|
|
219
|
+
const { compositor, renderer, texturizedScenes } = setup();
|
|
220
|
+
texturizedScenes.add(1n, "layer-a", mesh(), 0);
|
|
221
|
+
|
|
222
|
+
const rt = fakeRT();
|
|
223
|
+
compositor.renderVectorScenes(
|
|
224
|
+
[
|
|
225
|
+
{
|
|
226
|
+
layerId: "layer-a",
|
|
227
|
+
sources: [{ tileHandle: 1n, uvOffset: [0, 0], uvScale: [1, 1] }],
|
|
228
|
+
},
|
|
229
|
+
],
|
|
230
|
+
[rt as never],
|
|
231
|
+
);
|
|
232
|
+
expect(renderer.clear).toHaveBeenCalledTimes(1);
|
|
233
|
+
|
|
234
|
+
// The slot disappeared: the stale bake must be wiped so the atlas doesn't
|
|
235
|
+
// composite outdated content.
|
|
236
|
+
compositor.renderVectorScenes([], [rt as never]);
|
|
237
|
+
expect(renderer.render).toHaveBeenCalledTimes(1);
|
|
238
|
+
expect(renderer.clear).toHaveBeenCalledTimes(2);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("clears (does not render) a source whose scene hasn't reached the cache yet", () => {
|
|
242
|
+
const { compositor, renderer } = setup();
|
|
243
|
+
|
|
244
|
+
// The sub-rect stays transparent during the transition window; a coarser
|
|
245
|
+
// ancestor backs the gap via the Rust scene-ready walk-up.
|
|
246
|
+
const rt = fakeRT();
|
|
247
|
+
compositor.renderVectorScenes(
|
|
248
|
+
[
|
|
249
|
+
{
|
|
250
|
+
layerId: "pending",
|
|
251
|
+
sources: [{ tileHandle: 99n, uvOffset: [0, 0], uvScale: [1, 1] }],
|
|
252
|
+
},
|
|
253
|
+
],
|
|
254
|
+
[rt as never],
|
|
255
|
+
);
|
|
256
|
+
|
|
257
|
+
expect(renderer.render).not.toHaveBeenCalled();
|
|
258
|
+
expect(renderer.clear).toHaveBeenCalledTimes(1);
|
|
259
|
+
});
|
|
260
|
+
});
|
|
@@ -0,0 +1,421 @@
|
|
|
1
|
+
import { type TileHandle } from "@navaramap/core";
|
|
2
|
+
import {
|
|
3
|
+
Color,
|
|
4
|
+
DataTexture,
|
|
5
|
+
GLSL3,
|
|
6
|
+
Mesh,
|
|
7
|
+
OrthographicCamera,
|
|
8
|
+
PlaneGeometry,
|
|
9
|
+
RGBAFormat,
|
|
10
|
+
Scene,
|
|
11
|
+
ShaderMaterial,
|
|
12
|
+
type Texture,
|
|
13
|
+
UnsignedByteType,
|
|
14
|
+
WebGLRenderTarget,
|
|
15
|
+
type WebGLRenderer,
|
|
16
|
+
} from "three";
|
|
17
|
+
|
|
18
|
+
import {
|
|
19
|
+
buildCompositeFragmentShader,
|
|
20
|
+
composeCompositeContributions,
|
|
21
|
+
compositeFeatureKey,
|
|
22
|
+
COMPOSITE_VERTEX_SHADER,
|
|
23
|
+
createCoreUniformMutates,
|
|
24
|
+
createCompositeLayerEnhancers,
|
|
25
|
+
type CompositeLayerEnhancer,
|
|
26
|
+
type CompositeUniformTarget,
|
|
27
|
+
type CoreUniformMutates,
|
|
28
|
+
} from "../material/enhancer/tileComposite";
|
|
29
|
+
import { type TexturizedSceneByTileCoordinates } from "../scene";
|
|
30
|
+
|
|
31
|
+
import type { SlotPlan } from "./SlotPlanner";
|
|
32
|
+
import { TileTextureCache } from "./TileTextureCache";
|
|
33
|
+
import type {
|
|
34
|
+
AtlasFactory,
|
|
35
|
+
CompositeAtlas,
|
|
36
|
+
CompositeFeatures,
|
|
37
|
+
CompositeGlobals,
|
|
38
|
+
CompositeOutputs,
|
|
39
|
+
DirtyReason,
|
|
40
|
+
} from "./types";
|
|
41
|
+
|
|
42
|
+
const PREV_CLEAR_COLOR = new Color();
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Default atlas factory: a single MRT WebGLRenderTarget (count=3) sized
|
|
46
|
+
* `size × size` with RGBA8 textures. All three attachments share format —
|
|
47
|
+
* three.js's MRT API doesn't allow per-attachment formats — so we trade some
|
|
48
|
+
* attr-channel precision for one draw call to populate color/attr/normal.
|
|
49
|
+
*/
|
|
50
|
+
export const defaultAtlasFactory =
|
|
51
|
+
(renderer: WebGLRenderer | null): AtlasFactory =>
|
|
52
|
+
(size: number): CompositeAtlas => {
|
|
53
|
+
void renderer;
|
|
54
|
+
const target = new WebGLRenderTarget(size, size, {
|
|
55
|
+
count: 3,
|
|
56
|
+
format: RGBAFormat,
|
|
57
|
+
type: UnsignedByteType,
|
|
58
|
+
depthBuffer: false,
|
|
59
|
+
stencilBuffer: false,
|
|
60
|
+
});
|
|
61
|
+
const [color, attr, normal] = target.textures;
|
|
62
|
+
return {
|
|
63
|
+
target,
|
|
64
|
+
color,
|
|
65
|
+
attr,
|
|
66
|
+
normal,
|
|
67
|
+
dispose: () => target.dispose(),
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type TileTextureCompositorOptions = {
|
|
72
|
+
renderer: WebGLRenderer;
|
|
73
|
+
texturizedSceneByTileCoordinates: TexturizedSceneByTileCoordinates;
|
|
74
|
+
/** Atlas RT side length (defaults to 512). */
|
|
75
|
+
size?: number;
|
|
76
|
+
/** Test seam: replace MRT RT creation. */
|
|
77
|
+
atlasFactory?: AtlasFactory;
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
type CachedMaterial = {
|
|
81
|
+
material: ShaderMaterial;
|
|
82
|
+
/** Number of compact slots (rasterCount + vectorCount). */
|
|
83
|
+
numTextures: number;
|
|
84
|
+
/** Owns the core per-slot uniforms (shows/colors/opacities/textures/uv). */
|
|
85
|
+
core: CoreUniformMutates;
|
|
86
|
+
/** Active composite layer enhancers — each owns its own uniforms. */
|
|
87
|
+
chain: CompositeLayerEnhancer[];
|
|
88
|
+
/** 1×1 fallback so unbound texture array slots stay valid samplers. */
|
|
89
|
+
placeholderTexture: Texture;
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Integration layer for per-tile texture composition.
|
|
94
|
+
*
|
|
95
|
+
* Responsibilities:
|
|
96
|
+
* - Owns the per-tile composite atlas via TileTextureCache.
|
|
97
|
+
* - Runs the per-layer vector-scene offscreen render (ported wholesale from
|
|
98
|
+
* the previous TileMesh._onBeforeRender so behaviour is unchanged).
|
|
99
|
+
* - Runs the MRT composite pass that bakes N source textures (raster + vector
|
|
100
|
+
* + hillshade) into the atlas (color + attr + normal). The TileMesh main
|
|
101
|
+
* shader then samples each atlas attachment once instead of looping over N
|
|
102
|
+
* slots per fragment.
|
|
103
|
+
* - Tracks dirty handles so the composite pass only runs when something
|
|
104
|
+
* actually changes (tile add, layer update, hillshade backfill, vector
|
|
105
|
+
* revision bump, …).
|
|
106
|
+
*/
|
|
107
|
+
export class TileTextureCompositor {
|
|
108
|
+
readonly renderer: WebGLRenderer;
|
|
109
|
+
readonly cache: TileTextureCache;
|
|
110
|
+
/** Atlas / drape RT side length in texels (device-dependent). TileMesh reads
|
|
111
|
+
* this to size its lazily-allocated drape render targets and to compute the
|
|
112
|
+
* per-tile GPU byte cost it reports to the memory ledger. */
|
|
113
|
+
readonly size: number;
|
|
114
|
+
private readonly texturizedScenes: TexturizedSceneByTileCoordinates;
|
|
115
|
+
// Single fixed [-1, 1] camera shared by every vector-scene bake. Ancestor
|
|
116
|
+
// fallback is resolved in Rust, so no per-tile camera transform is needed.
|
|
117
|
+
private readonly vectorCamera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
118
|
+
|
|
119
|
+
// Composite-pass machinery (lazily created on first use so tests that
|
|
120
|
+
// don't render don't pay the allocation).
|
|
121
|
+
private readonly quadScene = new Scene();
|
|
122
|
+
private readonly quadCamera = new OrthographicCamera(-1, 1, 1, -1, 0, 1);
|
|
123
|
+
private readonly quadMesh: Mesh;
|
|
124
|
+
private readonly materialCache = new Map<string, CachedMaterial>();
|
|
125
|
+
// Vector render targets this compositor has ever rendered to. three.js
|
|
126
|
+
// allocates a render target's GL framebuffer on first setRenderTarget, so
|
|
127
|
+
// an empty slot whose target was never touched must be skipped entirely —
|
|
128
|
+
// clearing it would allocate size² × 4 bytes of GPU memory for nothing.
|
|
129
|
+
private readonly touchedVectorTargets = new WeakSet<WebGLRenderTarget>();
|
|
130
|
+
|
|
131
|
+
constructor(opts: TileTextureCompositorOptions) {
|
|
132
|
+
this.renderer = opts.renderer;
|
|
133
|
+
this.texturizedScenes = opts.texturizedSceneByTileCoordinates;
|
|
134
|
+
this.size = opts.size ?? 512;
|
|
135
|
+
this.cache = new TileTextureCache({
|
|
136
|
+
size: this.size,
|
|
137
|
+
atlasFactory: opts.atlasFactory ?? defaultAtlasFactory(opts.renderer),
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Single shared fullscreen quad — material is swapped per render.
|
|
141
|
+
this.quadMesh = new Mesh(new PlaneGeometry(2, 2));
|
|
142
|
+
this.quadScene.add(this.quadMesh);
|
|
143
|
+
this.quadCamera.position.z = 1;
|
|
144
|
+
this.vectorCamera.position.z = 1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ---------------------------------------------------------------------
|
|
148
|
+
// Cache-facing API
|
|
149
|
+
// ---------------------------------------------------------------------
|
|
150
|
+
|
|
151
|
+
acquire(handle: TileHandle): CompositeOutputs {
|
|
152
|
+
return this.cache.acquire(handle);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
release(handle: TileHandle): void {
|
|
156
|
+
this.cache.release(handle);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/** Refcount-neutral accessor for an already-acquired handle's atlas. */
|
|
160
|
+
acquireOutputs(handle: TileHandle): CompositeOutputs {
|
|
161
|
+
const out = this.cache.getOutputs(handle);
|
|
162
|
+
if (!out) {
|
|
163
|
+
throw new Error(
|
|
164
|
+
`TileTextureCompositor: handle not acquired before requesting outputs`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
return out;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
markDirty(handle: TileHandle, reason: DirtyReason): void {
|
|
171
|
+
this.cache.markDirty(handle, reason);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ---------------------------------------------------------------------
|
|
175
|
+
// Vector-scene render
|
|
176
|
+
// ---------------------------------------------------------------------
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Bake each resolved vector layer's WM source scenes into its per-layer render
|
|
180
|
+
* target (slot `i` → `renderTargets[i]`). A layer can be backed by several WM
|
|
181
|
+
* vector tiles when the terrain is Geographic (N:M); every source is drawn into
|
|
182
|
+
* the one render target, each framed by the Rust-supplied mercator affine
|
|
183
|
+
* `uvOffset`/`uvScale` so it lands in its sub-rect. Since the affine maps the
|
|
184
|
+
* terrain tile's `[0, 1]` UV into the source frame, the render-target UV ends up
|
|
185
|
+
* equal to the terrain UV — i.e. the RT spans the terrain tile's extent, ready
|
|
186
|
+
* for the composite paste's latitude reprojection. `(0,0)/(1,1)` (an exact
|
|
187
|
+
* same-tile drape, WebMercator terrain) maps a single source to the full RT.
|
|
188
|
+
*
|
|
189
|
+
* The render target is cleared once, then each source is drawn additively
|
|
190
|
+
* (autoClear off) so the sources mosaic instead of overwriting one another. A
|
|
191
|
+
* source whose scene hasn't reached the cache yet is skipped; its sub-rect stays
|
|
192
|
+
* transparent until it arrives (no flashing — coarser ancestors back the gaps
|
|
193
|
+
* via the Rust scene-ready walk-up). The caller owns the dirty gate and only
|
|
194
|
+
* calls this when the resolved slots or scenes change.
|
|
195
|
+
*/
|
|
196
|
+
renderVectorScenes(
|
|
197
|
+
slots: {
|
|
198
|
+
layerId: string;
|
|
199
|
+
sources: {
|
|
200
|
+
tileHandle: TileHandle;
|
|
201
|
+
uvOffset: [number, number];
|
|
202
|
+
uvScale: [number, number];
|
|
203
|
+
}[];
|
|
204
|
+
}[],
|
|
205
|
+
renderTargets: WebGLRenderTarget[],
|
|
206
|
+
): void {
|
|
207
|
+
const camera = this.vectorCamera;
|
|
208
|
+
const prevTarget = this.renderer.getRenderTarget();
|
|
209
|
+
const prevClear = this.renderer.getClearColor(PREV_CLEAR_COLOR);
|
|
210
|
+
const prevClearAlpha = this.renderer.getClearAlpha();
|
|
211
|
+
const prevAutoClear = this.renderer.autoClear;
|
|
212
|
+
// Accumulate multiple sources into one RT: clear once, never per render.
|
|
213
|
+
this.renderer.autoClear = false;
|
|
214
|
+
|
|
215
|
+
for (let i = 0; i < renderTargets.length; i++) {
|
|
216
|
+
const renderTarget = renderTargets[i];
|
|
217
|
+
if (!renderTarget) continue;
|
|
218
|
+
|
|
219
|
+
const slot = slots[i];
|
|
220
|
+
// An empty slot only needs a clear when the target holds stale content
|
|
221
|
+
// from a previous bake; a never-touched target has no GL storage yet
|
|
222
|
+
// and must not be render-targeted (that would allocate it).
|
|
223
|
+
if (!slot && !this.touchedVectorTargets.has(renderTarget)) continue;
|
|
224
|
+
this.touchedVectorTargets.add(renderTarget);
|
|
225
|
+
|
|
226
|
+
this.renderer.setRenderTarget(renderTarget);
|
|
227
|
+
this.renderer.setClearColor(0x000, 0);
|
|
228
|
+
this.renderer.clear();
|
|
229
|
+
|
|
230
|
+
if (slot) {
|
|
231
|
+
for (const source of slot.sources) {
|
|
232
|
+
const scene = this.texturizedScenes.findSceneByLayerId(
|
|
233
|
+
source.tileHandle,
|
|
234
|
+
slot.layerId,
|
|
235
|
+
);
|
|
236
|
+
if (!scene || scene.removed || !scene.children.length) continue;
|
|
237
|
+
// Frame the terrain tile's sub-rect of this source tile from the
|
|
238
|
+
// mercator uvOffset/uvScale: meshUv ∈ [0,1] → vectorUv = uvOffset +
|
|
239
|
+
// meshUv·uvScale, source scene NDC = 2·vectorUv − 1. A source finer than
|
|
240
|
+
// the terrain tile yields a camera wider than [-1, 1], so it draws into
|
|
241
|
+
// only its sub-rect and leaves the rest of the RT transparent.
|
|
242
|
+
const [ox, oy] = source.uvOffset;
|
|
243
|
+
const [sx, sy] = source.uvScale;
|
|
244
|
+
camera.left = 2 * ox - 1;
|
|
245
|
+
camera.right = 2 * (ox + sx) - 1;
|
|
246
|
+
camera.bottom = 2 * oy - 1;
|
|
247
|
+
camera.top = 2 * (oy + sy) - 1;
|
|
248
|
+
camera.updateProjectionMatrix();
|
|
249
|
+
this.renderer.render(scene, camera);
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
renderTarget.texture.needsUpdate = true;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
this.renderer.autoClear = prevAutoClear;
|
|
257
|
+
this.renderer.setRenderTarget(prevTarget);
|
|
258
|
+
this.renderer.setClearColor(prevClear, prevClearAlpha);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ---------------------------------------------------------------------
|
|
262
|
+
// MRT composite pass
|
|
263
|
+
// ---------------------------------------------------------------------
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Run the composite MRT pass for a handle if (and only if) its atlas is
|
|
267
|
+
* dirty. Consumes the dirty flags on success so the next frame skips work
|
|
268
|
+
* unless something marks it dirty again.
|
|
269
|
+
*
|
|
270
|
+
* The pass writes:
|
|
271
|
+
* color attachment = alpha-composited diffuse over N slots
|
|
272
|
+
* attr attachment = water + texturized-layer flags + winning slot idx
|
|
273
|
+
* normal attachment = hillshade normal (or neutral)
|
|
274
|
+
*
|
|
275
|
+
* Returns true when a render happened.
|
|
276
|
+
*/
|
|
277
|
+
runCompositePassIfDirty(
|
|
278
|
+
handle: TileHandle,
|
|
279
|
+
plan: SlotPlan,
|
|
280
|
+
globals: CompositeGlobals,
|
|
281
|
+
features: CompositeFeatures,
|
|
282
|
+
): boolean {
|
|
283
|
+
if (!this.cache.isDirty(handle)) return false;
|
|
284
|
+
const entry = this.cache.getEntry(handle);
|
|
285
|
+
if (!entry) return false;
|
|
286
|
+
|
|
287
|
+
const prevTarget = this.renderer.getRenderTarget();
|
|
288
|
+
const prevClear = this.renderer.getClearColor(PREV_CLEAR_COLOR);
|
|
289
|
+
const prevClearAlpha = this.renderer.getClearAlpha();
|
|
290
|
+
|
|
291
|
+
// No active slots → either clear (nothing to bake) or fall through to the
|
|
292
|
+
// shader path when a slot-independent feature still needs to write the
|
|
293
|
+
// atlas. Currently that's watermask only: it samples a per-tile texture
|
|
294
|
+
// and bakes the result into attr.r so water reflection works on tiles
|
|
295
|
+
// that have no raster/vector layers (e.g. open-ocean quantized-mesh).
|
|
296
|
+
const noSlots = plan.rasterCount + plan.vectorCount === 0;
|
|
297
|
+
if (noSlots && !features.hasWatermask) {
|
|
298
|
+
this.renderer.setRenderTarget(entry.atlas.target);
|
|
299
|
+
this.renderer.setClearColor(0x000000, 0);
|
|
300
|
+
this.renderer.clear();
|
|
301
|
+
this.renderer.setRenderTarget(prevTarget);
|
|
302
|
+
this.renderer.setClearColor(prevClear, prevClearAlpha);
|
|
303
|
+
entry.atlas.color.needsUpdate = true;
|
|
304
|
+
entry.atlas.attr.needsUpdate = true;
|
|
305
|
+
entry.atlas.normal.needsUpdate = true;
|
|
306
|
+
this.cache.consumeDirty(handle);
|
|
307
|
+
return true;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const mat = this.getOrCreateMaterial(plan, features);
|
|
311
|
+
|
|
312
|
+
this.bindUniforms(mat, plan, globals);
|
|
313
|
+
this.quadMesh.material = mat.material;
|
|
314
|
+
|
|
315
|
+
this.renderer.setRenderTarget(entry.atlas.target);
|
|
316
|
+
this.renderer.setClearColor(0x000000, 0);
|
|
317
|
+
this.renderer.clear();
|
|
318
|
+
this.renderer.render(this.quadScene, this.quadCamera);
|
|
319
|
+
|
|
320
|
+
this.renderer.setRenderTarget(prevTarget);
|
|
321
|
+
this.renderer.setClearColor(prevClear, prevClearAlpha);
|
|
322
|
+
|
|
323
|
+
entry.atlas.color.needsUpdate = true;
|
|
324
|
+
entry.atlas.attr.needsUpdate = true;
|
|
325
|
+
entry.atlas.normal.needsUpdate = true;
|
|
326
|
+
|
|
327
|
+
this.cache.consumeDirty(handle);
|
|
328
|
+
return true;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
private getOrCreateMaterial(
|
|
332
|
+
plan: SlotPlan,
|
|
333
|
+
features: CompositeFeatures,
|
|
334
|
+
): CachedMaterial {
|
|
335
|
+
const { rasterCount, vectorCount, boundary } = plan;
|
|
336
|
+
const numTextures = rasterCount + vectorCount;
|
|
337
|
+
const key = `${rasterCount}|${vectorCount}|${boundary}|${compositeFeatureKey(features)}`;
|
|
338
|
+
const cached = this.materialCache.get(key);
|
|
339
|
+
if (cached) return cached;
|
|
340
|
+
|
|
341
|
+
// 1×1 transparent placeholder. A bare `new Texture()` has no image and
|
|
342
|
+
// triggers a "Texture marked for update but no image data found" warning
|
|
343
|
+
// when three.js tries to upload it.
|
|
344
|
+
const placeholderTexture = new DataTexture(
|
|
345
|
+
new Uint8Array([0, 0, 0, 0]),
|
|
346
|
+
1,
|
|
347
|
+
1,
|
|
348
|
+
RGBAFormat,
|
|
349
|
+
UnsignedByteType,
|
|
350
|
+
);
|
|
351
|
+
placeholderTexture.needsUpdate = true;
|
|
352
|
+
|
|
353
|
+
// Build the enhancer chain once and use it for both shader generation and
|
|
354
|
+
// uniform ownership: each active enhancer attaches its own uniform refs and
|
|
355
|
+
// contributes the matching GLSL, so a new expression touches only its module.
|
|
356
|
+
const chain = createCompositeLayerEnhancers(features);
|
|
357
|
+
const core = createCoreUniformMutates();
|
|
358
|
+
|
|
359
|
+
const uniforms: CompositeUniformTarget = {};
|
|
360
|
+
core.attachUniforms(uniforms, numTextures, placeholderTexture);
|
|
361
|
+
let defines: Record<string, number> = {};
|
|
362
|
+
for (const enhancer of chain) {
|
|
363
|
+
enhancer.attachUniforms?.(uniforms, numTextures, placeholderTexture);
|
|
364
|
+
if (enhancer.defines) defines = { ...defines, ...enhancer.defines };
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const material = new ShaderMaterial({
|
|
368
|
+
glslVersion: GLSL3,
|
|
369
|
+
defines,
|
|
370
|
+
uniforms,
|
|
371
|
+
vertexShader: COMPOSITE_VERTEX_SHADER,
|
|
372
|
+
fragmentShader: buildCompositeFragmentShader(
|
|
373
|
+
rasterCount,
|
|
374
|
+
vectorCount,
|
|
375
|
+
boundary,
|
|
376
|
+
composeCompositeContributions(chain, numTextures),
|
|
377
|
+
),
|
|
378
|
+
depthTest: false,
|
|
379
|
+
depthWrite: false,
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
const entry: CachedMaterial = {
|
|
383
|
+
material,
|
|
384
|
+
numTextures,
|
|
385
|
+
core,
|
|
386
|
+
chain,
|
|
387
|
+
placeholderTexture,
|
|
388
|
+
};
|
|
389
|
+
this.materialCache.set(key, entry);
|
|
390
|
+
return entry;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
private bindUniforms(
|
|
394
|
+
mat: CachedMaterial,
|
|
395
|
+
plan: SlotPlan,
|
|
396
|
+
globals: CompositeGlobals,
|
|
397
|
+
): void {
|
|
398
|
+
// Single pass over the compact slots: the base binds the core uniforms and
|
|
399
|
+
// each active enhancer fills its own per-slot ref for the same slot.
|
|
400
|
+
for (let k = 0; k < mat.numTextures; k++) {
|
|
401
|
+
const layer = plan.slots[k]?.layer;
|
|
402
|
+
mat.core.bindSlot(k, layer);
|
|
403
|
+
for (const enhancer of mat.chain) enhancer.bindSlot?.(k, layer);
|
|
404
|
+
}
|
|
405
|
+
for (const enhancer of mat.chain) enhancer.bindGlobal?.(globals);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// ---------------------------------------------------------------------
|
|
409
|
+
// Lifecycle
|
|
410
|
+
// ---------------------------------------------------------------------
|
|
411
|
+
|
|
412
|
+
dispose(): void {
|
|
413
|
+
this.cache.disposeAll();
|
|
414
|
+
for (const m of this.materialCache.values()) {
|
|
415
|
+
m.material.dispose();
|
|
416
|
+
m.placeholderTexture.dispose();
|
|
417
|
+
}
|
|
418
|
+
this.materialCache.clear();
|
|
419
|
+
this.quadMesh.geometry.dispose();
|
|
420
|
+
}
|
|
421
|
+
}
|