@navaramap/three 0.0.2 → 0.0.3
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-8oWvyvwL.js → fontWorker-wz61edjR.js} +2 -2
- package/dist/assets/{fontWorker-8oWvyvwL.js.map → fontWorker-wz61edjR.js.map} +1 -1
- package/dist/assets/{index-D9G7kIEj.js → index-ywHSGImj.js} +3 -3
- package/dist/assets/{index-D9G7kIEj.js.map → index-ywHSGImj.js.map} +1 -1
- package/dist/assets/{navara_wasm_font_worker_bg-CkZP9l2i.wasm → navara_wasm_font_worker_bg-Du9nb2Pn.wasm} +0 -0
- package/dist/assets/{navara_wasm_worker_bg-Q8zrkLCR.wasm → navara_wasm_worker_bg-Xadu67fw.wasm} +0 -0
- package/dist/index.d.ts +133 -2
- package/dist/index.js +4309 -4288
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +223 -210
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +12 -12
- package/src/atmosphere.ts +43 -1
- package/src/event/feature.ts +43 -13
- package/src/event/features/polygon.ts +2 -1
- package/src/input.ts +48 -15
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.test.ts +1 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/mutates.ts +2 -0
- package/src/material/enhancer/instancedSprite/instancedSpriteBaseEnhancer/types.ts +2 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/mutates.ts +2 -0
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +5 -1
- package/src/material/enhancer/polygon/polygonBaseEnhancer/types.ts +2 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/mutates.ts +2 -0
- package/src/material/enhancer/polyline/polylineBaseEnhancer/types.ts +2 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/mutates.ts +2 -0
- package/src/material/enhancer/sdfText/sdfTextBaseEnhancer/types.ts +2 -0
- package/src/material/overrideMaterialsForMRT.ts +7 -2
- package/src/mesh/batchedSdfText.ts +234 -70
- package/src/mesh/instanced.ts +1 -1
- package/src/mesh/polygon.ts +11 -4
- package/src/mesh/polyline.ts +10 -2
- package/src/mesh/sdfText.ts +6 -1
- package/src/solar.test.ts +33 -0
- package/src/solar.ts +31 -0
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.3",
|
|
5
5
|
"main": "dist/index.umd.cjs",
|
|
6
6
|
"module": "dist/index.js",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -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/
|
|
34
|
-
"@navaramap/
|
|
35
|
-
"@navaramap/
|
|
36
|
-
"@navaramap/
|
|
37
|
-
"@navaramap/
|
|
38
|
-
"@navaramap/
|
|
39
|
-
"@navaramap/
|
|
33
|
+
"@navaramap/core": "0.0.3",
|
|
34
|
+
"@navaramap/engine": "0.0.3",
|
|
35
|
+
"@navaramap/font": "0.0.3",
|
|
36
|
+
"@navaramap/three_api": "0.0.3",
|
|
37
|
+
"@navaramap/engine-api": "0.0.3",
|
|
38
|
+
"@navaramap/worker": "0.0.3",
|
|
39
|
+
"@navaramap/three_csm": "0.0.3"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@playwright/test": "1.61.1",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"tweakpane": "4.0.5",
|
|
72
72
|
"vite-plugin-glsl": "1.6.0",
|
|
73
73
|
"vite-plugin-static-copy": "4.1.1",
|
|
74
|
-
"@navaramap/three_default_descs": "0.0.
|
|
75
|
-
"@navaramap/three_default_plugin": "0.0.
|
|
76
|
-
"@navaramap/three_plugins": "0.0.
|
|
77
|
-
"@navaramap/three_react": "0.0.
|
|
74
|
+
"@navaramap/three_default_descs": "0.0.3",
|
|
75
|
+
"@navaramap/three_default_plugin": "0.0.3",
|
|
76
|
+
"@navaramap/three_plugins": "0.0.3",
|
|
77
|
+
"@navaramap/three_react": "0.0.3"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"start": "vite",
|
package/src/atmosphere.ts
CHANGED
|
@@ -14,7 +14,13 @@ import invariant from "tiny-invariant";
|
|
|
14
14
|
|
|
15
15
|
import { type ThreeViewCamera } from "./camera";
|
|
16
16
|
import { ATMOSPHERE_ASSETS_URL, STBN_URL } from "./constants";
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
dateForSolarTime,
|
|
19
|
+
getSolarTime as solarTimeAt,
|
|
20
|
+
getSunElevation as sunElevationAt,
|
|
21
|
+
shiftDateToElevation,
|
|
22
|
+
shiftDateToHourAngle,
|
|
23
|
+
} from "./solar";
|
|
18
24
|
|
|
19
25
|
/**
|
|
20
26
|
* Events emitted by the {@link Atmosphere} class.
|
|
@@ -258,6 +264,42 @@ export class Atmosphere extends EventHandler<AtmosphereEvents> {
|
|
|
258
264
|
return dotProduct < 0;
|
|
259
265
|
}
|
|
260
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Returns the sun's elevation angle in degrees above the local horizon at
|
|
269
|
+
* `location` for the current {@link date}. Positive is above the horizon,
|
|
270
|
+
* negative below (night); includes atmospheric refraction.
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* const elevation = view.atmosphere.getSunElevation(view.camera.positionGeographic);
|
|
274
|
+
* if (elevation < 0) console.log("The sun has set.");
|
|
275
|
+
*/
|
|
276
|
+
getSunElevation(location: { lat: number; lng: number }): number {
|
|
277
|
+
return sunElevationAt(this.date, location.lat, location.lng);
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Returns the local apparent solar time at `lng` for the current
|
|
282
|
+
* {@link date}, in hours in the range [0, 24) where 12 is solar noon.
|
|
283
|
+
* Accounts for the equation of time.
|
|
284
|
+
*
|
|
285
|
+
* @example
|
|
286
|
+
* const hours = view.atmosphere.getSolarTime({ lng: 139.69 }); // e.g. 6.3 = 06:18
|
|
287
|
+
*/
|
|
288
|
+
getSolarTime(location: { lng: number }): number {
|
|
289
|
+
return solarTimeAt(this.date, location.lng);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Sets {@link date} so the local apparent solar time at `lng` equals `hours`
|
|
294
|
+
* (0–24), keeping the same solar day. Inverse of {@link getSolarTime}.
|
|
295
|
+
*
|
|
296
|
+
* @example
|
|
297
|
+
* view.atmosphere.setSolarTime({ lng: 139.69 }, 6.3); // sunrise over Tokyo
|
|
298
|
+
*/
|
|
299
|
+
setSolarTime(location: { lng: number }, hours: number): void {
|
|
300
|
+
this.date = dateForSolarTime(this.date, location.lng, hours);
|
|
301
|
+
}
|
|
302
|
+
|
|
261
303
|
/**
|
|
262
304
|
* Gets the current date used for calculating sun/moon positions.
|
|
263
305
|
*/
|
package/src/event/feature.ts
CHANGED
|
@@ -118,6 +118,20 @@ export async function processRenderableFeatureAdded(
|
|
|
118
118
|
|
|
119
119
|
const featureLayerId = ev.layer_id;
|
|
120
120
|
|
|
121
|
+
// Captured once: the render-completion report is deferred until the mesh is
|
|
122
|
+
// in its render/bake scene (see below), by which point `ev` may be gone.
|
|
123
|
+
const bits = ev.bits;
|
|
124
|
+
const renderedType =
|
|
125
|
+
point || billboard || text
|
|
126
|
+
? "point"
|
|
127
|
+
: model
|
|
128
|
+
? "model"
|
|
129
|
+
: polyline
|
|
130
|
+
? "polyline"
|
|
131
|
+
: polygon
|
|
132
|
+
? "polygon"
|
|
133
|
+
: undefined;
|
|
134
|
+
|
|
121
135
|
const useParallel = checkFeatureParallel(feature);
|
|
122
136
|
|
|
123
137
|
if (useParallel) {
|
|
@@ -127,15 +141,6 @@ export async function processRenderableFeatureAdded(
|
|
|
127
141
|
|
|
128
142
|
const obj = await renderFeature(ctx, feature, tileHandle, featureLayerId)
|
|
129
143
|
?.then((r) => {
|
|
130
|
-
const type = (() => {
|
|
131
|
-
if (point || billboard || text) return "point";
|
|
132
|
-
else if (model) return "model";
|
|
133
|
-
else if (polyline) return "polyline";
|
|
134
|
-
else if (polygon) return "polygon";
|
|
135
|
-
})();
|
|
136
|
-
if (type) {
|
|
137
|
-
featureHandler.markFeatureIsRendered(type, ev.bits);
|
|
138
|
-
}
|
|
139
144
|
// The glTF/Draco decode happened on the JS side, so report the actual
|
|
140
145
|
// decoded GPU size back to the ledger (its compressed-payload estimate
|
|
141
146
|
// undercounts Draco content). Draco decode inflates geometry markedly.
|
|
@@ -164,7 +169,12 @@ export async function processRenderableFeatureAdded(
|
|
|
164
169
|
}
|
|
165
170
|
});
|
|
166
171
|
|
|
167
|
-
if (!obj)
|
|
172
|
+
if (!obj) {
|
|
173
|
+
// renderFeature produced no mesh (e.g. empty geometry); still report
|
|
174
|
+
// rendered so the tile's LOD/activation can advance, as before.
|
|
175
|
+
if (renderedType) featureHandler.markFeatureIsRendered(renderedType, bits);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
168
178
|
|
|
169
179
|
// Sprite should be handled by mesh itself.
|
|
170
180
|
const transform = (polyline ?? polygon ?? model)?.transform;
|
|
@@ -185,7 +195,10 @@ export async function processRenderableFeatureAdded(
|
|
|
185
195
|
|
|
186
196
|
meshes.set(id, obj);
|
|
187
197
|
|
|
188
|
-
|
|
198
|
+
// `!= null` (not truthiness): the root vector tile's handle is 0, which is
|
|
199
|
+
// falsy — a truthy check silently dropped root-tile draped meshes from the
|
|
200
|
+
// texturized scene cache, leaving small datasets that render at z0 blank.
|
|
201
|
+
if (isDraped && tileHandle != null) {
|
|
189
202
|
// Insert the bakeable draped mesh into the per-tile cache now (it is fully built at
|
|
190
203
|
// this point). Readiness/ancestor-fallback is decided entirely on the Rust side from
|
|
191
204
|
// the ECS lifecycle, so no `scene_ready` is reported. Insert even when invisible —
|
|
@@ -213,6 +226,14 @@ export async function processRenderableFeatureAdded(
|
|
|
213
226
|
});
|
|
214
227
|
}
|
|
215
228
|
|
|
229
|
+
// Report render-completion to Rust only now that the mesh is in its render
|
|
230
|
+
// (MRT) or bake (texturized) scene. For draped features this must follow the
|
|
231
|
+
// `texturizedSceneByTileCoordinates.add` above: the Rust drape resolve flips a
|
|
232
|
+
// terrain tile's vector source to this tile once its features report rendered,
|
|
233
|
+
// so reporting before the offscreen scene existed left the terrain tile's
|
|
234
|
+
// vector drape blank until a camera-move re-traverse.
|
|
235
|
+
if (renderedType) featureHandler.markFeatureIsRendered(renderedType, bits);
|
|
236
|
+
|
|
216
237
|
if (obj instanceof PolygonMesh && polygon && polygon.outline_geometry) {
|
|
217
238
|
const outline = await renderPolygonOutline(ctx, polygon);
|
|
218
239
|
outline.renderOrder = FEATURE_RENDER_ORDER;
|
|
@@ -320,7 +341,7 @@ export async function processRenderableFeatureChanged(
|
|
|
320
341
|
if (
|
|
321
342
|
((obj instanceof PolygonMesh && obj.clampToGround) ||
|
|
322
343
|
(obj instanceof PolylineMesh && obj.draped)) &&
|
|
323
|
-
tileHandle
|
|
344
|
+
tileHandle != null // the root tile's handle is 0 (falsy)
|
|
324
345
|
) {
|
|
325
346
|
texturizedSceneByTileCoordinates.markDirty(tileHandle, layerId);
|
|
326
347
|
}
|
|
@@ -345,7 +366,16 @@ export async function processRenderableFeatureChanged(
|
|
|
345
366
|
|
|
346
367
|
obj.updateMatrix();
|
|
347
368
|
|
|
348
|
-
|
|
369
|
+
// Re-emit `featureUpdated` (which re-runs the layer's registered evaluator
|
|
370
|
+
// over this whole feature set) only when the set is actually displayed at the
|
|
371
|
+
// current LOD. `obj.visible` is not that signal for draped meshes: they stay
|
|
372
|
+
// visible while built so they remain stable bakeable drape sources (see
|
|
373
|
+
// PolygonMesh._update), so gating on it alone re-evaluated every built draped
|
|
374
|
+
// tile on every activation flip during zoom. The evaluator's per-feature
|
|
375
|
+
// values persist in the batch data texture, and user-driven restyles reach
|
|
376
|
+
// inactive sets through `Layer.forceUpdate`, so skipping inactive sets here
|
|
377
|
+
// is safe.
|
|
378
|
+
if (obj.visible && active) {
|
|
349
379
|
handleFeatureUpdatedEventByLayerId(
|
|
350
380
|
viewEvents,
|
|
351
381
|
layersManager,
|
|
@@ -19,5 +19,6 @@ export function processPolygonChanged(
|
|
|
19
19
|
active: boolean,
|
|
20
20
|
tileHandle: TileHandle | undefined,
|
|
21
21
|
) {
|
|
22
|
-
|
|
22
|
+
// `!= null`, not truthiness: the root vector tile's handle is 0.
|
|
23
|
+
obj._update(m.material, active, tileHandle != null);
|
|
23
24
|
}
|
package/src/input.ts
CHANGED
|
@@ -15,6 +15,21 @@ export function registerInputEvents(
|
|
|
15
15
|
|
|
16
16
|
let lastTerrainDistance: number | undefined;
|
|
17
17
|
|
|
18
|
+
// Mousedown and mousemove must share the same coordinate space: the engine
|
|
19
|
+
// re-anchors its cursor position from the mousedown coordinates so the first
|
|
20
|
+
// drag delta is never computed against a stale position (e.g. after the
|
|
21
|
+
// window lost focus while the OS cursor kept moving).
|
|
22
|
+
const normalizePosition = (event: MouseEvent) => {
|
|
23
|
+
const rect = element.getBoundingClientRect();
|
|
24
|
+
const width = element.clientWidth;
|
|
25
|
+
const height = element.clientHeight;
|
|
26
|
+
const aspectRatio = width / height;
|
|
27
|
+
return {
|
|
28
|
+
x: ((event.clientX - rect.left) / width) * aspectRatio,
|
|
29
|
+
y: (event.clientY - rect.top) / height,
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
|
|
18
33
|
const mousedown = (event: MouseEvent) => {
|
|
19
34
|
mouseEvent = {
|
|
20
35
|
type: "mousedown",
|
|
@@ -22,7 +37,11 @@ export function registerInputEvents(
|
|
|
22
37
|
};
|
|
23
38
|
const terrainDistance = getTerrainDistance?.() ?? undefined;
|
|
24
39
|
lastTerrainDistance = terrainDistance;
|
|
25
|
-
core.input({
|
|
40
|
+
core.input({
|
|
41
|
+
...mouseEvent,
|
|
42
|
+
...normalizePosition(event),
|
|
43
|
+
terrain_distance: terrainDistance,
|
|
44
|
+
});
|
|
26
45
|
};
|
|
27
46
|
const mouseup = () => {
|
|
28
47
|
core.input({
|
|
@@ -33,13 +52,9 @@ export function registerInputEvents(
|
|
|
33
52
|
};
|
|
34
53
|
|
|
35
54
|
const mousemove = (event: MouseEvent) => {
|
|
36
|
-
const width = element.clientWidth;
|
|
37
|
-
const height = element.clientHeight;
|
|
38
|
-
const aspectRatio = width / height;
|
|
39
55
|
core.input({
|
|
40
56
|
type: "mousemove",
|
|
41
|
-
|
|
42
|
-
y: event.clientY / height,
|
|
57
|
+
...normalizePosition(event),
|
|
43
58
|
});
|
|
44
59
|
};
|
|
45
60
|
|
|
@@ -109,36 +124,54 @@ export function registerInputEvents(
|
|
|
109
124
|
key: event?.key,
|
|
110
125
|
});
|
|
111
126
|
};
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
127
|
+
|
|
128
|
+
// Releases every pressed button and modifier key. When the window loses
|
|
129
|
+
// focus or visibility the matching mouseup/keyup fires in another window, so
|
|
130
|
+
// without this the engine would keep acting on stale pressed state after the
|
|
131
|
+
// user comes back.
|
|
132
|
+
const releaseInputs = () => {
|
|
133
|
+
for (const button of [0, 1, 2]) {
|
|
134
|
+
core.input({ type: "mouseup", button });
|
|
135
|
+
}
|
|
136
|
+
mouseEvent = undefined;
|
|
137
|
+
core.input({ type: "keyup", key_code: "ControlLeft", key: "Control" });
|
|
138
|
+
core.input({ type: "keyup", key_code: "ControlRight", key: "Control" });
|
|
139
|
+
};
|
|
140
|
+
const visibilitychange = () => {
|
|
141
|
+
if (document.visibilityState === "hidden") {
|
|
142
|
+
releaseInputs();
|
|
143
|
+
}
|
|
117
144
|
};
|
|
118
145
|
|
|
119
146
|
element.addEventListener("mousedown", mousedown);
|
|
120
147
|
element.addEventListener("mouseup", mouseup);
|
|
121
|
-
element.addEventListener("mouseleave",
|
|
122
|
-
element.addEventListener("mouseleave", keyupEmpty);
|
|
148
|
+
element.addEventListener("mouseleave", releaseInputs);
|
|
123
149
|
element.addEventListener("mousemove", mousemove);
|
|
124
150
|
element.addEventListener("touchstart", touchstart);
|
|
125
151
|
element.addEventListener("touchend", touchend);
|
|
152
|
+
// The browser cancels active touches on app switches and system gestures;
|
|
153
|
+
// treat them as ended so no stale touch stays in the engine.
|
|
154
|
+
element.addEventListener("touchcancel", touchend);
|
|
126
155
|
element.addEventListener("touchmove", touchmove);
|
|
127
156
|
element.addEventListener("wheel", wheel);
|
|
128
157
|
document.addEventListener("keydown", keydown);
|
|
129
158
|
document.addEventListener("keyup", keyup);
|
|
159
|
+
window.addEventListener("blur", releaseInputs);
|
|
160
|
+
document.addEventListener("visibilitychange", visibilitychange);
|
|
130
161
|
|
|
131
162
|
return () => {
|
|
132
163
|
element.removeEventListener("mousedown", mousedown);
|
|
133
164
|
element.removeEventListener("mouseup", mouseup);
|
|
134
|
-
element.removeEventListener("mouseleave",
|
|
135
|
-
element.removeEventListener("mouseleave", keyupEmpty);
|
|
165
|
+
element.removeEventListener("mouseleave", releaseInputs);
|
|
136
166
|
element.removeEventListener("mousemove", mousemove);
|
|
137
167
|
element.removeEventListener("touchstart", touchstart);
|
|
138
168
|
element.removeEventListener("touchend", touchend);
|
|
169
|
+
element.removeEventListener("touchcancel", touchend);
|
|
139
170
|
element.removeEventListener("touchmove", touchmove);
|
|
140
171
|
element.removeEventListener("wheel", wheel);
|
|
141
172
|
document.removeEventListener("keydown", keydown);
|
|
142
173
|
document.removeEventListener("keyup", keyup);
|
|
174
|
+
window.removeEventListener("blur", releaseInputs);
|
|
175
|
+
document.removeEventListener("visibilitychange", visibilitychange);
|
|
143
176
|
};
|
|
144
177
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { encodePosition } from "@navaramap/engine-api";
|
|
2
|
+
import { RTE_ONE_UNIFORM } from "@navaramap/three_api";
|
|
2
3
|
import {
|
|
3
4
|
type Matrix4,
|
|
4
5
|
type Texture,
|
|
@@ -82,6 +83,7 @@ export const createBaseMutates = (
|
|
|
82
83
|
uniforms.uRTCCenterView = refs.uRTCCenterView;
|
|
83
84
|
uniforms.uEyeRTELow = refs.uEyeRTELow;
|
|
84
85
|
uniforms.uEyeRTEHigh = refs.uEyeRTEHigh;
|
|
86
|
+
uniforms.u_rteOne = RTE_ONE_UNIFORM;
|
|
85
87
|
uniforms.uScale = refs.uScale;
|
|
86
88
|
uniforms.uCenter = refs.uCenter;
|
|
87
89
|
uniforms.uSizeInMeters = refs.uSizeInMeters;
|
|
@@ -77,6 +77,8 @@ export type InstancedSpriteBaseRefs = {
|
|
|
77
77
|
uRTCCenterView: UniformValue<Vector3>;
|
|
78
78
|
uEyeRTELow: UniformValue<Vector3>;
|
|
79
79
|
uEyeRTEHigh: UniformValue<Vector3>;
|
|
80
|
+
/** Always 1.0 — blocks fast-math reassociation of the RTE recombination. */
|
|
81
|
+
u_rteOne?: UniformValue<number>;
|
|
80
82
|
uScale: UniformValue<number>;
|
|
81
83
|
uCenter: UniformValue<Vector2>;
|
|
82
84
|
uSizeInMeters: UniformValue<boolean>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RTE_ONE_UNIFORM } from "@navaramap/three_api";
|
|
1
2
|
import type { Matrix4, Texture, Vector3 } from "three";
|
|
2
3
|
import { Matrix4 as ThreeMatrix4, Vector3 as ThreeVector3 } from "three";
|
|
3
4
|
|
|
@@ -78,6 +79,7 @@ export const createBaseMutates = (useRTE: boolean): PolygonBaseMutates => {
|
|
|
78
79
|
uniforms.u_cameraPositionHigh = refs.u_cameraPositionHigh;
|
|
79
80
|
uniforms.u_cameraPositionLow = refs.u_cameraPositionLow;
|
|
80
81
|
uniforms.modelViewMatrixRTE = refs.modelViewMatrixRTE;
|
|
82
|
+
uniforms.u_rteOne = RTE_ONE_UNIFORM;
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
// Height uniforms
|
|
@@ -115,7 +115,11 @@ ${ShadowMapDepthVertex}
|
|
|
115
115
|
#include <envmap_vertex>
|
|
116
116
|
|
|
117
117
|
vPosition = absTransformed.xyz;
|
|
118
|
-
|
|
118
|
+
// mvPosition comes from the RTE projection (modelViewMatrixRTE * camera-relative
|
|
119
|
+
// position), so it is precise at any distance. Deriving vViewPosition from
|
|
120
|
+
// modelViewMatrix * absTransformed instead would suffer f32 cancellation at
|
|
121
|
+
// ECEF magnitude and make view-dependent shading wobble as the camera moves.
|
|
122
|
+
vViewPosition = -mvPosition.xyz;
|
|
119
123
|
`,
|
|
120
124
|
useRTE,
|
|
121
125
|
)
|
|
@@ -108,6 +108,8 @@ export type PolygonBaseRefs = {
|
|
|
108
108
|
modelViewMatrixRTE?: UniformValue<Matrix4>;
|
|
109
109
|
u_cameraPositionHigh?: UniformValue<Vector3>;
|
|
110
110
|
u_cameraPositionLow?: UniformValue<Vector3>;
|
|
111
|
+
/** Always 1.0 — blocks fast-math reassociation of the RTE recombination. */
|
|
112
|
+
u_rteOne?: UniformValue<number>;
|
|
111
113
|
};
|
|
112
114
|
|
|
113
115
|
export type PolygonBaseUniforms = Partial<PolygonBaseRefs>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RTE_ONE_UNIFORM } from "@navaramap/three_api";
|
|
1
2
|
import {
|
|
2
3
|
Color as ThreeColor,
|
|
3
4
|
Matrix4 as ThreeMatrix4,
|
|
@@ -101,6 +102,7 @@ export const createBaseMutates = (useRTE: boolean): PolylineBaseMutates => {
|
|
|
101
102
|
uniforms.u_cameraPositionHigh = refs.u_cameraPositionHigh;
|
|
102
103
|
uniforms.u_cameraPositionLow = refs.u_cameraPositionLow;
|
|
103
104
|
uniforms.modelViewMatrixRTE = refs.modelViewMatrixRTE;
|
|
105
|
+
uniforms.u_rteOne = RTE_ONE_UNIFORM;
|
|
104
106
|
}
|
|
105
107
|
|
|
106
108
|
// Batch texture
|
|
@@ -114,6 +114,8 @@ export type PolylineBaseRefs = {
|
|
|
114
114
|
modelViewMatrixRTE?: UniformValue<Matrix4>;
|
|
115
115
|
u_cameraPositionHigh?: UniformValue<Vector3>;
|
|
116
116
|
u_cameraPositionLow?: UniformValue<Vector3>;
|
|
117
|
+
/** Always 1.0 — blocks fast-math reassociation of the RTE recombination. */
|
|
118
|
+
u_rteOne?: UniformValue<number>;
|
|
117
119
|
};
|
|
118
120
|
|
|
119
121
|
export type PolylineBaseUniforms = Partial<PolylineBaseRefs>;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { encodePosition } from "@navaramap/engine-api";
|
|
2
|
+
import { RTE_ONE_UNIFORM } from "@navaramap/three_api";
|
|
2
3
|
import { Color, DataTexture, type Matrix4, Vector2, Vector3 } from "three";
|
|
3
4
|
|
|
4
5
|
import type { UniformValue } from "../../../types";
|
|
@@ -119,6 +120,7 @@ export const createBaseMutates = (
|
|
|
119
120
|
uniforms.uRTCCenterView = refs.uRTCCenterView;
|
|
120
121
|
uniforms.uEyeRTELow = refs.uEyeRTELow;
|
|
121
122
|
uniforms.uEyeRTEHigh = refs.uEyeRTEHigh;
|
|
123
|
+
uniforms.u_rteOne = RTE_ONE_UNIFORM;
|
|
122
124
|
uniforms.nvr_uBatchId = refs.nvr_uBatchId;
|
|
123
125
|
uniforms.nvr_uPickable = refs.nvr_uPickable;
|
|
124
126
|
uniforms.uAtlas = refs.uAtlas;
|
|
@@ -111,6 +111,8 @@ export type SdfTextBaseRefs = {
|
|
|
111
111
|
uRTCCenterView: UniformValue<Vector3>;
|
|
112
112
|
uEyeRTELow: UniformValue<Vector3>;
|
|
113
113
|
uEyeRTEHigh: UniformValue<Vector3>;
|
|
114
|
+
/** Always 1.0 — blocks fast-math reassociation of the RTE recombination. */
|
|
115
|
+
u_rteOne?: UniformValue<number>;
|
|
114
116
|
nvr_uBatchId: UniformValue<number>;
|
|
115
117
|
nvr_uPickable: UniformValue<number>;
|
|
116
118
|
uAtlas: UniformValue<DataTexture | null>;
|
|
@@ -431,8 +431,13 @@ export function setupMaterialForMRT(
|
|
|
431
431
|
material: ShaderMaterial,
|
|
432
432
|
options?: SetupMaterialForMRTOptions,
|
|
433
433
|
): void {
|
|
434
|
-
|
|
435
|
-
|
|
434
|
+
// Detect LineMaterial by `type`, not only `instanceof`: callers may construct
|
|
435
|
+
// it from `three/examples/jsm/lines` while this module's `LineMaterial` comes
|
|
436
|
+
// from `three-stdlib`, so a bare `instanceof` misses those cross-copy
|
|
437
|
+
// instances and would wrongly route them through the ShaderMaterial path
|
|
438
|
+
// (whose normal-buffer write references an undeclared `normal`).
|
|
439
|
+
if (material instanceof LineMaterial || material.type === "LineMaterial") {
|
|
440
|
+
injectGBufferToLineMaterial(material as LineMaterial);
|
|
436
441
|
return;
|
|
437
442
|
}
|
|
438
443
|
injectGBufferToShaderMaterial(material, options?.normal);
|