@navaramap/three 0.0.0 → 0.0.1
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/dist/assets/fontWorker-CCWL5pbx.js +2 -0
- package/dist/assets/fontWorker-CCWL5pbx.js.map +1 -0
- package/dist/assets/index-BdtHOOT9.js +12 -0
- package/dist/assets/index-BdtHOOT9.js.map +1 -0
- package/dist/assets/{navara_wasm_font_worker_bg-665OLxjy.wasm → navara_wasm_font_worker_bg-Bnck8OGf.wasm} +0 -0
- package/dist/assets/{navara_wasm_worker_bg-BXhKC5bE.wasm → navara_wasm_worker_bg-DG9ORAmj.wasm} +0 -0
- package/dist/index.d.ts +142 -51
- package/dist/index.js +4772 -4510
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +226 -218
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +13 -13
- package/src/event/context.ts +5 -0
- package/src/index.ts +10 -2
- package/src/material/enhancer/tileComposite/tileCompositeBaseEnhancer/mutates.ts +6 -1
- package/src/material/enhancer/tileComposite/tileElevationHeatmapEnhancer/shader.ts +9 -2
- package/src/mesh/tile/drapeResolver.ts +76 -0
- package/src/mesh/{tile.test.ts → tile/index.test.ts} +16 -6
- package/src/mesh/{tile.ts → tile/index.ts} +124 -392
- package/src/mesh/tile/rasterDrapeResolver.ts +423 -0
- package/src/mesh/tile/vectorDrapeResolver.ts +404 -0
- package/src/tileTexture/TileTextureCache.test.ts +2 -0
- package/src/tileTexture/TileTextureCache.ts +1 -0
- package/src/tileTexture/TileTextureCompositor.test.ts +105 -0
- package/src/tileTexture/TileTextureCompositor.ts +241 -31
- package/src/tileTexture/__snapshots__/CompositeShader.snapshot.test.ts.snap +36 -16
- package/src/tileTexture/types.ts +7 -0
- package/src/utils/demNoDataColor.test.ts +47 -0
- package/src/utils/demNoDataColor.ts +48 -0
- package/dist/assets/fontWorker-CEJEfRpb.js +0 -2
- package/dist/assets/fontWorker-CEJEfRpb.js.map +0 -1
- package/dist/assets/index-BUB-ijMO.js +0 -12
- package/dist/assets/index-BUB-ijMO.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navaramap/three",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.1",
|
|
5
5
|
"main": "dist/index.umd.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "MIT OR Apache-2.0",
|
|
13
13
|
"repository": {
|
|
14
14
|
"type": "git",
|
|
15
|
-
"url": "git+https://github.com/
|
|
15
|
+
"url": "git+https://github.com/reearth/navara.git",
|
|
16
16
|
"directory": "web/navara_three"
|
|
17
17
|
},
|
|
18
18
|
"publishConfig": {
|
|
@@ -30,13 +30,13 @@
|
|
|
30
30
|
"astronomy-engine": "2.1.19",
|
|
31
31
|
"stats.js": "0.17.0",
|
|
32
32
|
"three-stdlib": "2.36.1",
|
|
33
|
-
"@navaramap/core": "0.0.
|
|
34
|
-
"@navaramap/
|
|
35
|
-
"@navaramap/engine": "0.0.
|
|
36
|
-
"@navaramap/
|
|
37
|
-
"@navaramap/
|
|
38
|
-
"@navaramap/
|
|
39
|
-
"@navaramap/
|
|
33
|
+
"@navaramap/core": "0.0.1",
|
|
34
|
+
"@navaramap/engine-api": "0.0.1",
|
|
35
|
+
"@navaramap/engine": "0.0.1",
|
|
36
|
+
"@navaramap/three_api": "0.0.1",
|
|
37
|
+
"@navaramap/three_csm": "0.0.1",
|
|
38
|
+
"@navaramap/font": "0.0.1",
|
|
39
|
+
"@navaramap/worker": "0.0.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@playwright/test": "1.59.1",
|
|
@@ -70,10 +70,10 @@
|
|
|
70
70
|
"tweakpane": "4.0.5",
|
|
71
71
|
"vite-plugin-glsl": "1.6.0",
|
|
72
72
|
"vite-plugin-static-copy": "4.1.0",
|
|
73
|
-
"@navaramap/three_default_descs": "0.0.
|
|
74
|
-
"@navaramap/three_default_plugin": "0.0.
|
|
75
|
-
"@navaramap/three_plugins": "0.0.
|
|
76
|
-
"@navaramap/three_react": "0.0.
|
|
73
|
+
"@navaramap/three_default_descs": "0.0.1",
|
|
74
|
+
"@navaramap/three_default_plugin": "0.0.1",
|
|
75
|
+
"@navaramap/three_plugins": "0.0.1",
|
|
76
|
+
"@navaramap/three_react": "0.0.1"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"start": "vite",
|
package/src/event/context.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
import type {
|
|
8
8
|
DelegatedWorkerTasksResult,
|
|
9
9
|
ElevationDecoder,
|
|
10
|
+
RasterTileState,
|
|
10
11
|
ReconstructableEntity,
|
|
11
12
|
ReturnedTransferablePolygonBatchedFeature,
|
|
12
13
|
ReturnedTransferablePolylineBatchedFeature,
|
|
@@ -106,6 +107,10 @@ export type TileHandler = {
|
|
|
106
107
|
getTileElevationDecoder: (handle: bigint) => ElevationDecoder | undefined;
|
|
107
108
|
getVectorTileStates: (handle: bigint) => VectorTileState[] | undefined;
|
|
108
109
|
vectorRevision: () => number;
|
|
110
|
+
/** The WM raster tiles to bake into per-layer drape render targets for a
|
|
111
|
+
* terrain tile (Geographic terrain only; empty on WebMercator terrain). */
|
|
112
|
+
getRasterTileStates: (handle: bigint) => RasterTileState[] | undefined;
|
|
113
|
+
rasterRevision: () => number;
|
|
109
114
|
/** Reports a terrain tile's drape render-target GPU footprint (bytes) so the
|
|
110
115
|
* memory ledger tracks clamp-to-ground vector bakes that scale with terrain
|
|
111
116
|
* subdivision past the vector `maxZoom`. Pass 0 to release on dispose. */
|
package/src/index.ts
CHANGED
|
@@ -632,6 +632,8 @@ export default class ThreeView<
|
|
|
632
632
|
};
|
|
633
633
|
// Per-frame snapshot of the WASM vector resolution revision, refreshed in `_render`.
|
|
634
634
|
private _vectorRevision = 0;
|
|
635
|
+
// Per-frame snapshot of the WASM raster drape resolution revision, refreshed in `_render`.
|
|
636
|
+
private _rasterRevision = 0;
|
|
635
637
|
private _tileHandler: TileHandler = {
|
|
636
638
|
getMartini: (id) => {
|
|
637
639
|
return this._core?.getMartini(id);
|
|
@@ -651,6 +653,10 @@ export default class ThreeView<
|
|
|
651
653
|
// Returns the per-frame cached revision (read once in `_render`), so per-tile
|
|
652
654
|
// `onBeforeRender` gating costs no WASM-boundary call.
|
|
653
655
|
vectorRevision: () => this._vectorRevision,
|
|
656
|
+
getRasterTileStates: (handle) => {
|
|
657
|
+
return this._core?.getRasterTileStates(handle);
|
|
658
|
+
},
|
|
659
|
+
rasterRevision: () => this._rasterRevision,
|
|
654
660
|
reportDrapeGpuBytes: (handle, bytes) => {
|
|
655
661
|
this._core?.reportTerrainDrapeGpuBytes(handle, bytes);
|
|
656
662
|
},
|
|
@@ -1739,9 +1745,11 @@ export default class ThreeView<
|
|
|
1739
1745
|
}
|
|
1740
1746
|
|
|
1741
1747
|
private _render(updatedAt: number) {
|
|
1742
|
-
// Read the vector resolution
|
|
1743
|
-
// `onBeforeRender` can gate its slot re-fetch against
|
|
1748
|
+
// Read the vector/raster resolution revisions once per frame so each terrain
|
|
1749
|
+
// tile's `onBeforeRender` can gate its slot re-fetch against them without its
|
|
1750
|
+
// own FFI calls.
|
|
1744
1751
|
this._vectorRevision = this._core?.vectorRevision() ?? this._vectorRevision;
|
|
1752
|
+
this._rasterRevision = this._core?.rasterRevision() ?? this._rasterRevision;
|
|
1745
1753
|
|
|
1746
1754
|
this._uniforms.time.value = updatedAt;
|
|
1747
1755
|
|
|
@@ -104,8 +104,13 @@ export function createCoreUniformMutates(): CoreUniformMutates {
|
|
|
104
104
|
refs.uLayerUvScale.value[k].set(1, 1);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// Reproject applies to color rasters and elevation heatmaps alike — the
|
|
108
|
+
// shader warps the per-slot UV before either sampler runs; hillshade is
|
|
109
|
+
// terrain-side and never reprojects.
|
|
107
110
|
const reproject =
|
|
108
|
-
layer && layer.kind === "raster"
|
|
111
|
+
layer && (layer.kind === "raster" || layer.kind === "elevationHeatmap")
|
|
112
|
+
? layer.reproject
|
|
113
|
+
: undefined;
|
|
109
114
|
if (reproject && layer) {
|
|
110
115
|
const [Ts, Tn] = reproject;
|
|
111
116
|
// Recover the source tile's latitude band [Rs, Rn] from the affine y
|
|
@@ -10,6 +10,12 @@ export const elevationIncludes = (): string => ElevationParsFragment;
|
|
|
10
10
|
/**
|
|
11
11
|
* Replaces the per-slot sampler with a DEM-decode + colormap lookup; non-heatmap
|
|
12
12
|
* slots fall back to the straight raster fetch in the else branch.
|
|
13
|
+
*
|
|
14
|
+
* The heatmap alpha derives from the decode's validity: a no-data (boundary)
|
|
15
|
+
* texel — including a baked drape render target's uncovered regions, which the
|
|
16
|
+
* bake paints with the boundary color — renders transparent instead of being
|
|
17
|
+
* colormapped as height 0. The DEM texel's alpha channel is never read: it is
|
|
18
|
+
* not part of any elevation encoding and stays reserved for future RGBA ones.
|
|
13
19
|
*/
|
|
14
20
|
export const elevationSampleProducer = ({
|
|
15
21
|
k,
|
|
@@ -17,8 +23,9 @@ export const elevationSampleProducer = ({
|
|
|
17
23
|
vec4 texColor${k};
|
|
18
24
|
if (uIsElevationHeatmaps[${k}]) {
|
|
19
25
|
ivec2 demTexSize = textureSize(uTextures[${k}], 0);
|
|
20
|
-
|
|
21
|
-
|
|
26
|
+
bool demValid${k};
|
|
27
|
+
float normalized_h = sampleElevationBilinear(uTextures[${k}], texUv${k}, demTexSize, demValid${k});
|
|
28
|
+
texColor${k} = vec4(texture2D(uColorMapTexture, vec2(normalized_h, 0.5)).rgb, demValid${k} ? 1.0 : 0.0);
|
|
22
29
|
} else {
|
|
23
30
|
texColor${k} = texture2D(uTextures[${k}], texUv${k}) * vec4(uColors[${k}], 1.0);
|
|
24
31
|
}`;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
MagnificationTextureFilter,
|
|
3
|
+
MinificationTextureFilter,
|
|
4
|
+
Texture,
|
|
5
|
+
} from "three";
|
|
6
|
+
|
|
7
|
+
import type { TextureOptions } from "../../textures";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A drape resolver owns one family of composite material slots for a terrain
|
|
11
|
+
* tile: how its layers' pixels reach those slots (direct texture binding or an
|
|
12
|
+
* offscreen bake into per-layer render targets), gated so the work only runs
|
|
13
|
+
* when the Rust-side resolve or the backing content actually changed.
|
|
14
|
+
*
|
|
15
|
+
* Three implementations, side by side, spell out the rendering differences:
|
|
16
|
+
* - {@link VectorDrapeResolver} (`vectorDrapeResolver.ts`) — clamp-to-ground
|
|
17
|
+
* vector layers. Always baked on every tiling scheme (vector content is an
|
|
18
|
+
* offscreen scene, so rasterizing is intrinsic); WebMercator terrain is the
|
|
19
|
+
* degenerate single-source identity case, Geographic terrain the N:M mosaic.
|
|
20
|
+
* - `DirectRasterDrapeResolver` (`rasterDrapeResolver.ts`) — raster layers on
|
|
21
|
+
* WebMercator terrain. Same-scheme 1:1: the fetched tile texture is bound
|
|
22
|
+
* straight to its slot by `setupTextures`; every hook is a no-op.
|
|
23
|
+
* - `BakedRasterDrapeResolver` (`rasterDrapeResolver.ts`) — raster layers on
|
|
24
|
+
* Geographic (quantized-mesh) terrain. Cross-scheme N:M mosaic bake with
|
|
25
|
+
* per-slot Mercator latitude reprojection.
|
|
26
|
+
*/
|
|
27
|
+
export type DrapeResolver = {
|
|
28
|
+
/**
|
|
29
|
+
* Per-frame hook (`_onBeforeRender`): refresh the Rust-resolved slots when
|
|
30
|
+
* the resolve revision moved, and re-bake when the slot/content signature
|
|
31
|
+
* changed (which also catches async content landing after the resolve).
|
|
32
|
+
*/
|
|
33
|
+
update(): void;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* `setupTextures` hook, after the material's per-slot arrays were rebuilt:
|
|
37
|
+
* re-derive the resolver's slot pairing and rebind (or invalidate) its
|
|
38
|
+
* textures. `textureFragments` holds the raster region's per-slot fragment
|
|
39
|
+
* ids; the vector resolver ignores it (its region is positional).
|
|
40
|
+
*/
|
|
41
|
+
syncMaterialSlots(
|
|
42
|
+
textureFragments: readonly (string | null | undefined)[] | undefined,
|
|
43
|
+
): void;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Mercator latitude reprojection band (`[south, north]`, radians) for one of
|
|
47
|
+
* this resolver's composite slots, or undefined when the slot samples
|
|
48
|
+
* without reprojection.
|
|
49
|
+
*/
|
|
50
|
+
slotReproject(absSlot: number): [number, number] | undefined;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Force a re-bake + re-bind on the next `update()` even though the resolved
|
|
54
|
+
* slots are unchanged (e.g. picking passes repaint the offscreen content).
|
|
55
|
+
*/
|
|
56
|
+
invalidate(): void;
|
|
57
|
+
|
|
58
|
+
/** Live drape render targets, counted into the tile's GPU byte report. */
|
|
59
|
+
liveRenderTargetCount(): number;
|
|
60
|
+
|
|
61
|
+
dispose(): void;
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/** Apply the shared texturized-slot sampler settings to a drape render target's
|
|
65
|
+
* texture. Returns the texture for call-site chaining. */
|
|
66
|
+
export function configureTexturizedTexture(
|
|
67
|
+
tex: Texture,
|
|
68
|
+
textureOptions: TextureOptions,
|
|
69
|
+
): Texture {
|
|
70
|
+
tex.minFilter = textureOptions.minFilter as MinificationTextureFilter;
|
|
71
|
+
tex.magFilter = textureOptions.magFilter as MagnificationTextureFilter;
|
|
72
|
+
tex.anisotropy = textureOptions.maxAnisotropy;
|
|
73
|
+
tex.generateMipmaps = textureOptions.useMipmaps;
|
|
74
|
+
tex.needsUpdate = true;
|
|
75
|
+
return tex;
|
|
76
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { Mesh, BoxGeometry, MeshBasicMaterial } from "three";
|
|
2
2
|
import { describe, expect, it, vi } from "vitest";
|
|
3
3
|
|
|
4
|
-
import { TexturizedSceneByTileCoordinates } from "
|
|
4
|
+
import { TexturizedSceneByTileCoordinates } from "../../scene";
|
|
5
5
|
|
|
6
|
-
import { TileMesh } from "
|
|
6
|
+
import { TileMesh } from ".";
|
|
7
7
|
|
|
8
8
|
// The package barrel pulled in by tile.ts initializes a worker pool at module
|
|
9
9
|
// load (os.cpus()), which is unavailable in the test environment. Stub it.
|
|
@@ -36,6 +36,7 @@ function state(layerId: string, tileHandle: bigint) {
|
|
|
36
36
|
uv_offset: new Float32Array([0, 0]),
|
|
37
37
|
uv_scale: new Float32Array([1, 1]),
|
|
38
38
|
reproject_terrain_lat: new Float32Array([]),
|
|
39
|
+
free: vi.fn(),
|
|
39
40
|
};
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -86,6 +87,9 @@ function makeTile(atlasSize = 512) {
|
|
|
86
87
|
|
|
87
88
|
const meshAdded = {
|
|
88
89
|
tile_handle: 1n,
|
|
90
|
+
// WebMercator tiling → the direct (no-op) raster drape resolver, keeping
|
|
91
|
+
// the baked-raster machinery out of these vector-drape tests.
|
|
92
|
+
globe: { isGeographicTiling: false, free: vi.fn() },
|
|
89
93
|
} as unknown as ConstructorParameters<typeof TileMesh>[1];
|
|
90
94
|
|
|
91
95
|
const tile = new TileMesh(ctx, meshAdded);
|
|
@@ -109,8 +113,11 @@ const RT_BYTES_SMALL = 256 * 256 * 4;
|
|
|
109
113
|
const ATLAS_BYTES_SMALL = 256 * 256 * 4 * 3;
|
|
110
114
|
|
|
111
115
|
function renderTargetCount(tile: TileMesh): number {
|
|
112
|
-
return (
|
|
113
|
-
|
|
116
|
+
return (
|
|
117
|
+
tile as unknown as {
|
|
118
|
+
vectorDrape: { liveRenderTargetCount(): number };
|
|
119
|
+
}
|
|
120
|
+
).vectorDrape.liveRenderTargetCount();
|
|
114
121
|
}
|
|
115
122
|
|
|
116
123
|
/** Invoke the private onBeforeRender hook (args are ignored by the impl). */
|
|
@@ -207,8 +214,11 @@ describe("TileMesh vector bake dirty-gating", () => {
|
|
|
207
214
|
|
|
208
215
|
frame(tile);
|
|
209
216
|
|
|
210
|
-
const slots = (
|
|
211
|
-
|
|
217
|
+
const slots = (
|
|
218
|
+
tile as unknown as {
|
|
219
|
+
vectorDrape: { vectorSlots: { layerId: string }[] };
|
|
220
|
+
}
|
|
221
|
+
).vectorDrape.vectorSlots;
|
|
212
222
|
expect(slots.map((s) => s.layerId).sort()).toEqual(["a", "c"]);
|
|
213
223
|
expect(renderVectorScenes).toHaveBeenCalledTimes(1);
|
|
214
224
|
});
|