@navaramap/three 0.1.0 → 0.1.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/README.md +4 -4
- package/dist/index.d.ts +91 -26
- package/dist/index.js +261 -213
- package/dist/index.js.map +1 -1
- package/dist/index.umd.cjs +31 -31
- package/dist/index.umd.cjs.map +1 -1
- package/package.json +12 -12
- package/src/core/BaseDesc.ts +25 -1
- package/src/core/MeshDesc.ts +2 -1
- package/src/index.ts +174 -77
- package/src/material/enhancer/model/modelBaseEnhancer/shader.ts +2 -2
- package/src/material/enhancer/polygon/polygonBaseEnhancer/shader.ts +2 -2
- package/src/pick/pickHelper.test.ts +182 -55
- package/src/pick/pickHelper.ts +144 -56
- package/src/plugins/AttributionPlugin/index.ts +1 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navaramap/three",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.1",
|
|
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/engine
|
|
35
|
-
"@navaramap/
|
|
36
|
-
"@navaramap/three-csm": "0.1.
|
|
37
|
-
"@navaramap/
|
|
38
|
-
"@navaramap/
|
|
39
|
-
"@navaramap/
|
|
33
|
+
"@navaramap/core": "0.1.1",
|
|
34
|
+
"@navaramap/engine": "0.1.1",
|
|
35
|
+
"@navaramap/three-api": "0.1.1",
|
|
36
|
+
"@navaramap/three-csm": "0.1.1",
|
|
37
|
+
"@navaramap/worker": "0.1.1",
|
|
38
|
+
"@navaramap/engine-api": "0.1.1",
|
|
39
|
+
"@navaramap/font": "0.1.1"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
42
|
"@playwright/test": "1.62.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-
|
|
75
|
-
"@navaramap/three-
|
|
76
|
-
"@navaramap/three-
|
|
77
|
-
"@navaramap/three-
|
|
74
|
+
"@navaramap/three-default-descs": "0.1.1",
|
|
75
|
+
"@navaramap/three-default-plugin": "0.1.1",
|
|
76
|
+
"@navaramap/three-react": "0.1.1",
|
|
77
|
+
"@navaramap/three-plugins": "0.1.1"
|
|
78
78
|
},
|
|
79
79
|
"scripts": {
|
|
80
80
|
"start": "vite",
|
package/src/core/BaseDesc.ts
CHANGED
|
@@ -76,6 +76,8 @@ export abstract class BaseDesc<
|
|
|
76
76
|
|
|
77
77
|
private _visible?: boolean;
|
|
78
78
|
|
|
79
|
+
private _destroyed = false;
|
|
80
|
+
|
|
79
81
|
constructor(
|
|
80
82
|
view: ThreeView,
|
|
81
83
|
ctx: ViewContext,
|
|
@@ -92,8 +94,20 @@ export abstract class BaseDesc<
|
|
|
92
94
|
/**
|
|
93
95
|
* Called when the this class is added to the scene. Override this to create the Three.js objects.
|
|
94
96
|
* This is where you should initialize `this._instance` and add it to the appropriate scene.
|
|
97
|
+
*
|
|
98
|
+
* May return a promise: a descriptor whose implementation loads lazily
|
|
99
|
+
* (e.g. an `await import(...)` of a heavy renderer dependency) can be
|
|
100
|
+
* `async`, awaiting the module before delegating to `super.onCreate()`
|
|
101
|
+
* (after checking {@link destroyed}). `addMesh`/`addLight`/`addEffect`
|
|
102
|
+
* still return their handle synchronously; the instance appears once the
|
|
103
|
+
* promise settles, and a rejection is reported through the descriptor's
|
|
104
|
+
* `error` event (when it declares one). Handle calls issued while the
|
|
105
|
+
* promise is pending are safe: `update()`/`visible` store their fields
|
|
106
|
+
* without touching the missing instance (the deferred `super.onCreate()`
|
|
107
|
+
* applies them), and per-frame/resize hooks are wired only after creation
|
|
108
|
+
* completes.
|
|
95
109
|
*/
|
|
96
|
-
abstract onCreate(): void
|
|
110
|
+
abstract onCreate(): void | Promise<void>;
|
|
97
111
|
|
|
98
112
|
/**
|
|
99
113
|
* Called when the configuration is updated via `BaseHandle.update()`.
|
|
@@ -122,9 +136,19 @@ export abstract class BaseDesc<
|
|
|
122
136
|
* Override this to clean up resources. Remember to call `super.onDestroy()`.
|
|
123
137
|
*/
|
|
124
138
|
onDestroy(): void {
|
|
139
|
+
this._destroyed = true;
|
|
125
140
|
this._instance = undefined;
|
|
126
141
|
}
|
|
127
142
|
|
|
143
|
+
/**
|
|
144
|
+
* True once {@link onDestroy} has run. An async {@link onCreate} (and the
|
|
145
|
+
* hook wiring that waits on it) checks this after its awaited module
|
|
146
|
+
* resolves, so a descriptor deleted mid-load creates nothing.
|
|
147
|
+
*/
|
|
148
|
+
get destroyed(): boolean {
|
|
149
|
+
return this._destroyed;
|
|
150
|
+
}
|
|
151
|
+
|
|
128
152
|
/**
|
|
129
153
|
* Gets whether this is currently visible.
|
|
130
154
|
*/
|
package/src/core/MeshDesc.ts
CHANGED
|
@@ -598,7 +598,6 @@ export abstract class MeshDesc<
|
|
|
598
598
|
assertNoTransformConflict(nextGeodetic, nextMatrix, nextMatrixWorld);
|
|
599
599
|
|
|
600
600
|
super.onUpdateConfig(updates);
|
|
601
|
-
invariant(this.raw);
|
|
602
601
|
|
|
603
602
|
const spatialChanged =
|
|
604
603
|
updates.matrix !== undefined ||
|
|
@@ -636,6 +635,8 @@ export abstract class MeshDesc<
|
|
|
636
635
|
this.applyLit();
|
|
637
636
|
}
|
|
638
637
|
|
|
638
|
+
if (!this.raw) return;
|
|
639
|
+
|
|
639
640
|
if (spatialChanged) {
|
|
640
641
|
// With a frame present, the effective transform depends on the
|
|
641
642
|
// combination of all stored fields — recompose the whole thing.
|
package/src/index.ts
CHANGED
|
@@ -118,7 +118,12 @@ import {
|
|
|
118
118
|
} from "./material";
|
|
119
119
|
import type { TileMesh } from "./mesh/tile";
|
|
120
120
|
import { RenderPassOrchestrator } from "./orchestrators/RenderPassOrchestrator";
|
|
121
|
-
import {
|
|
121
|
+
import {
|
|
122
|
+
CLICK_PIXEL_TOLERANCE,
|
|
123
|
+
isClickGesture,
|
|
124
|
+
PickHelper,
|
|
125
|
+
TAP_PIXEL_TOLERANCE,
|
|
126
|
+
} from "./pick/pickHelper";
|
|
122
127
|
import { TerrainPicker } from "./pick/pickTerrain";
|
|
123
128
|
import { AttributionPlugin, type AttributionPluginOptions } from "./plugins";
|
|
124
129
|
import { TexturizedSceneByTileCoordinates, type Scenes } from "./scene";
|
|
@@ -219,6 +224,12 @@ export * from "./layers";
|
|
|
219
224
|
export * from "./passes";
|
|
220
225
|
export * from "./evaluations";
|
|
221
226
|
export { SKY_RENDER_ORDER, STARS_RENDER_ORDER } from "./renderOrder";
|
|
227
|
+
export {
|
|
228
|
+
CLICK_PIXEL_TOLERANCE,
|
|
229
|
+
TAP_PIXEL_TOLERANCE,
|
|
230
|
+
PICK_RADIUS,
|
|
231
|
+
TOUCH_PICK_RADIUS,
|
|
232
|
+
} from "./pick/pickHelper";
|
|
222
233
|
export * from "@navaramap/three-api";
|
|
223
234
|
export * from "./Color";
|
|
224
235
|
export { type BlendMode, blendFunction, createReplacer } from "./utils";
|
|
@@ -311,8 +322,8 @@ export type Options = {
|
|
|
311
322
|
backgroundColor?: CoreColor;
|
|
312
323
|
/**
|
|
313
324
|
* Feature picking configuration (default: true). Enables the `featureClick`
|
|
314
|
-
* event (click) and the `featureHover` / `featureEnter` /
|
|
315
|
-
* events (
|
|
325
|
+
* event (click or touch tap) and the `featureHover` / `featureEnter` /
|
|
326
|
+
* `featureLeave` events (pointer hover).
|
|
316
327
|
*/
|
|
317
328
|
picking?: boolean;
|
|
318
329
|
/** When true, renders every frame. When false, renders only on changes or when forceUpdate() is called. */
|
|
@@ -404,12 +415,13 @@ export type Options = {
|
|
|
404
415
|
} & GlobeOptions;
|
|
405
416
|
|
|
406
417
|
/**
|
|
407
|
-
*
|
|
418
|
+
* Pointer event extended with map coordinates at the event location.
|
|
419
|
+
* Fired for every input type; `pointerType` tells them apart.
|
|
408
420
|
*/
|
|
409
|
-
export type
|
|
410
|
-
/** World coordinates (ECEF) at the
|
|
421
|
+
export type MapPointerEvent = {
|
|
422
|
+
/** World coordinates (ECEF) at the pointer position on the globe surface. */
|
|
411
423
|
map: XYZ;
|
|
412
|
-
} &
|
|
424
|
+
} & PointerEvent;
|
|
413
425
|
|
|
414
426
|
/**
|
|
415
427
|
* Event types emitted by ThreeView. Subscribe using `view.on(eventName, callback)`.
|
|
@@ -418,13 +430,13 @@ export type ViewEvents = {
|
|
|
418
430
|
/** Emitted when the view is resized. Receives width and height in pixels. */
|
|
419
431
|
resize: (w: number, h: number) => void;
|
|
420
432
|
/**
|
|
421
|
-
* Emitted when a feature is clicked (click-gesture GPU pick).
|
|
422
|
-
* clicked feature, or null when empty space was clicked. For
|
|
423
|
-
* coordinates use the `click` event instead.
|
|
433
|
+
* Emitted when a feature is clicked or tapped (click-gesture GPU pick).
|
|
434
|
+
* Receives the clicked feature, or null when empty space was clicked. For
|
|
435
|
+
* raw click coordinates use the `click` event instead.
|
|
424
436
|
*/
|
|
425
437
|
featureClick: (info: Nullable<PickedFeature>) => void;
|
|
426
438
|
/**
|
|
427
|
-
* Emitted when the hovered feature changes (
|
|
439
|
+
* Emitted when the hovered feature changes (hover picking). Receives
|
|
428
440
|
* the newly hovered feature, or null when the pointer leaves all pickable
|
|
429
441
|
* features. Hover picking runs a GPU pick per frame while the pointer
|
|
430
442
|
* moves, and is active only while at least one `featureHover` /
|
|
@@ -451,18 +463,26 @@ export type ViewEvents = {
|
|
|
451
463
|
postRender: (t: number) => void;
|
|
452
464
|
/** @private Emitted when terrain height sampling completes. */
|
|
453
465
|
_sample_terrain_height_received: (ev: TerrainHeightUpdatedEvent) => void;
|
|
454
|
-
/** Emitted on
|
|
455
|
-
|
|
456
|
-
/** Emitted when
|
|
457
|
-
|
|
458
|
-
/** Emitted when
|
|
459
|
-
|
|
460
|
-
/** Emitted on
|
|
461
|
-
|
|
462
|
-
/** Emitted on
|
|
463
|
-
|
|
464
|
-
/** Emitted
|
|
465
|
-
|
|
466
|
+
/** Emitted on pointerdown with map coordinates, for every input type. */
|
|
467
|
+
pointerdown: (event: MapPointerEvent) => void;
|
|
468
|
+
/** Emitted when a pointer enters the canvas with map coordinates, for every input type. */
|
|
469
|
+
pointerenter: (event: MapPointerEvent) => void;
|
|
470
|
+
/** Emitted when a pointer leaves the canvas with map coordinates, for every input type. */
|
|
471
|
+
pointerleave: (event: MapPointerEvent) => void;
|
|
472
|
+
/** Emitted on pointermove with map coordinates, for every input type. */
|
|
473
|
+
pointermove: (event: MapPointerEvent) => void;
|
|
474
|
+
/** Emitted on pointerup with map coordinates, for every input type. */
|
|
475
|
+
pointerup: (event: MapPointerEvent) => void;
|
|
476
|
+
/** Emitted when the browser cancels an active pointer (e.g. a system gesture takes over). */
|
|
477
|
+
pointercancel: (event: PointerEvent) => void;
|
|
478
|
+
/**
|
|
479
|
+
* Emitted on a click or touch tap with map coordinates: a primary-pointer
|
|
480
|
+
* press and release within the travel tolerance
|
|
481
|
+
* ({@link CLICK_PIXEL_TOLERANCE}, or {@link TAP_PIXEL_TOLERANCE} for
|
|
482
|
+
* touch). Camera drags and pinches never fire it. `pointerType` tells the
|
|
483
|
+
* input kinds apart.
|
|
484
|
+
*/
|
|
485
|
+
click: (event: MapPointerEvent) => void;
|
|
466
486
|
/** Emitted when the engine becomes idle (no Rust-side events for `idleThreshold` ms). */
|
|
467
487
|
idle: () => void;
|
|
468
488
|
};
|
|
@@ -1173,9 +1193,9 @@ export default class ThreeView<
|
|
|
1173
1193
|
}
|
|
1174
1194
|
|
|
1175
1195
|
/**
|
|
1176
|
-
*
|
|
1196
|
+
* Extend a pointer event with map coordinates at its location
|
|
1177
1197
|
*/
|
|
1178
|
-
private
|
|
1198
|
+
private convertToMapEvent(event: PointerEvent): MapPointerEvent | null {
|
|
1179
1199
|
const rect = this._renderer.domElement.getBoundingClientRect();
|
|
1180
1200
|
const x = event.clientX - rect.left;
|
|
1181
1201
|
const y = event.clientY - rect.top;
|
|
@@ -1188,7 +1208,7 @@ export default class ThreeView<
|
|
|
1188
1208
|
y: xyz.y,
|
|
1189
1209
|
z: xyz.z,
|
|
1190
1210
|
},
|
|
1191
|
-
})
|
|
1211
|
+
});
|
|
1192
1212
|
}
|
|
1193
1213
|
|
|
1194
1214
|
return null;
|
|
@@ -1624,47 +1644,75 @@ export default class ThreeView<
|
|
|
1624
1644
|
|
|
1625
1645
|
this._camera.core = this._core;
|
|
1626
1646
|
|
|
1627
|
-
|
|
1628
|
-
|
|
1647
|
+
// The map events are fed from pointer events; touch produces no
|
|
1648
|
+
// compatibility mouse events because the camera-input handlers call
|
|
1649
|
+
// preventDefault() on touch events. `click` is a gesture, not the DOM
|
|
1650
|
+
// event: a primary-pointer press and release within the travel
|
|
1651
|
+
// tolerance, with no pinch and no cancellation. Camera drags never
|
|
1652
|
+
// fire it.
|
|
1653
|
+
let clickStart: Vector2 | undefined;
|
|
1654
|
+
|
|
1655
|
+
this._renderer.domElement.addEventListener("pointerdown", (event) => {
|
|
1656
|
+
// A second finger turns the gesture into a pinch, not a tap.
|
|
1657
|
+
clickStart =
|
|
1658
|
+
event.isPrimary && event.button === 0
|
|
1659
|
+
? new Vector2(event.clientX, event.clientY)
|
|
1660
|
+
: undefined;
|
|
1661
|
+
const mapEvent = this.convertToMapEvent(event);
|
|
1629
1662
|
if (mapEvent) {
|
|
1630
|
-
this.emit("
|
|
1663
|
+
this.emit("pointerdown", mapEvent);
|
|
1631
1664
|
}
|
|
1632
1665
|
});
|
|
1633
1666
|
|
|
1634
|
-
this._renderer.domElement.addEventListener("
|
|
1635
|
-
const mapEvent = this.
|
|
1667
|
+
this._renderer.domElement.addEventListener("pointerenter", (event) => {
|
|
1668
|
+
const mapEvent = this.convertToMapEvent(event);
|
|
1636
1669
|
if (mapEvent) {
|
|
1637
|
-
this.emit("
|
|
1670
|
+
this.emit("pointerenter", mapEvent);
|
|
1638
1671
|
}
|
|
1639
1672
|
});
|
|
1640
1673
|
|
|
1641
|
-
this._renderer.domElement.addEventListener("
|
|
1642
|
-
const mapEvent = this.
|
|
1674
|
+
this._renderer.domElement.addEventListener("pointerleave", (event) => {
|
|
1675
|
+
const mapEvent = this.convertToMapEvent(event);
|
|
1643
1676
|
if (mapEvent) {
|
|
1644
|
-
this.emit("
|
|
1677
|
+
this.emit("pointerleave", mapEvent);
|
|
1645
1678
|
}
|
|
1646
1679
|
});
|
|
1647
1680
|
|
|
1648
|
-
this._renderer.domElement.addEventListener("
|
|
1649
|
-
const mapEvent = this.
|
|
1681
|
+
this._renderer.domElement.addEventListener("pointermove", (event) => {
|
|
1682
|
+
const mapEvent = this.convertToMapEvent(event);
|
|
1650
1683
|
if (mapEvent) {
|
|
1651
|
-
this.emit("
|
|
1684
|
+
this.emit("pointermove", mapEvent);
|
|
1652
1685
|
}
|
|
1653
1686
|
});
|
|
1654
1687
|
|
|
1655
|
-
this._renderer.domElement.addEventListener("
|
|
1656
|
-
const mapEvent = this.
|
|
1688
|
+
this._renderer.domElement.addEventListener("pointerup", (event) => {
|
|
1689
|
+
const mapEvent = this.convertToMapEvent(event);
|
|
1657
1690
|
if (mapEvent) {
|
|
1658
|
-
this.emit("
|
|
1691
|
+
this.emit("pointerup", mapEvent);
|
|
1659
1692
|
}
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1693
|
+
if (!event.isPrimary || event.button !== 0) return;
|
|
1694
|
+
const start = clickStart;
|
|
1695
|
+
clickStart = undefined;
|
|
1696
|
+
if (!start || !mapEvent) return;
|
|
1697
|
+
const tolerance =
|
|
1698
|
+
event.pointerType === "touch"
|
|
1699
|
+
? TAP_PIXEL_TOLERANCE
|
|
1700
|
+
: CLICK_PIXEL_TOLERANCE;
|
|
1701
|
+
if (
|
|
1702
|
+
isClickGesture(
|
|
1703
|
+
start,
|
|
1704
|
+
new Vector2(event.clientX, event.clientY),
|
|
1705
|
+
tolerance,
|
|
1706
|
+
)
|
|
1707
|
+
) {
|
|
1665
1708
|
this.emit("click", mapEvent);
|
|
1666
1709
|
}
|
|
1667
1710
|
});
|
|
1711
|
+
|
|
1712
|
+
this._renderer.domElement.addEventListener("pointercancel", (event) => {
|
|
1713
|
+
clickStart = undefined;
|
|
1714
|
+
this.emit("pointercancel", event);
|
|
1715
|
+
});
|
|
1668
1716
|
}
|
|
1669
1717
|
|
|
1670
1718
|
/**
|
|
@@ -2074,6 +2122,33 @@ export default class ThreeView<
|
|
|
2074
2122
|
return new Source(sourceId, s.type, this._core);
|
|
2075
2123
|
}
|
|
2076
2124
|
|
|
2125
|
+
/**
|
|
2126
|
+
* Tracks a possibly-async `onCreate()` (see `BaseDesc.onCreate`): the
|
|
2127
|
+
* `add*` methods still return their handle synchronously, the descriptor's
|
|
2128
|
+
* instance appears when the promise settles, and a rejection is logged and
|
|
2129
|
+
* reported through the descriptor's `error` event (when it declares one).
|
|
2130
|
+
*
|
|
2131
|
+
* `wire` binds the descriptor's lifecycle hooks (per-frame `update`,
|
|
2132
|
+
* `onResize`, `needsUpdate`). It runs immediately for a synchronous
|
|
2133
|
+
* creation, and only after the promise resolves for an async one — the
|
|
2134
|
+
* hooks must not fire while the descriptor has no instance yet.
|
|
2135
|
+
*/
|
|
2136
|
+
private _trackAsyncCreate(
|
|
2137
|
+
kind: "mesh" | "light" | "effect",
|
|
2138
|
+
desc: { emit: (event: never, ...args: never[]) => void },
|
|
2139
|
+
result: void | Promise<void>,
|
|
2140
|
+
wire: () => void,
|
|
2141
|
+
): void {
|
|
2142
|
+
if (!(result instanceof Promise)) {
|
|
2143
|
+
wire();
|
|
2144
|
+
return;
|
|
2145
|
+
}
|
|
2146
|
+
result.then(wire, (error: unknown) => {
|
|
2147
|
+
console.error(`Failed to create ${kind} descriptor:`, error);
|
|
2148
|
+
(desc.emit as (event: string, payload: unknown) => void)("error", error);
|
|
2149
|
+
});
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2077
2152
|
/**
|
|
2078
2153
|
* Adds a 3D mesh to the scene.
|
|
2079
2154
|
* The mesh kind is determined by the nested key (e.g., `{ box: { width: 200 } }`).
|
|
@@ -2092,28 +2167,35 @@ export default class ThreeView<
|
|
|
2092
2167
|
// Create mesh descriptor instance
|
|
2093
2168
|
const meshDesc = this.registries.mesh.create(meshType, config);
|
|
2094
2169
|
|
|
2095
|
-
// Initialize the mesh
|
|
2096
|
-
meshDesc.onCreate()
|
|
2170
|
+
// Initialize the mesh; hooks are wired once the instance exists.
|
|
2171
|
+
this._trackAsyncCreate("mesh", meshDesc, meshDesc.onCreate(), () => {
|
|
2172
|
+
// If deleted while an async creation was loading, nothing to wire.
|
|
2173
|
+
if (meshDesc.destroyed) return;
|
|
2097
2174
|
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2175
|
+
// Set up update listener
|
|
2176
|
+
if (meshDesc.update) {
|
|
2177
|
+
this.on("preRender", meshDesc.update.bind(meshDesc));
|
|
2178
|
+
}
|
|
2102
2179
|
|
|
2103
|
-
|
|
2104
|
-
|
|
2180
|
+
if (meshDesc.onResize) {
|
|
2181
|
+
this.on("resize", meshDesc.onResize.bind(meshDesc));
|
|
2105
2182
|
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2183
|
+
const canvasSize = this._getCanvasSize();
|
|
2184
|
+
if (canvasSize) {
|
|
2185
|
+
meshDesc.onResize(canvasSize.width, canvasSize.height);
|
|
2186
|
+
}
|
|
2109
2187
|
}
|
|
2110
|
-
}
|
|
2111
2188
|
|
|
2112
|
-
|
|
2113
|
-
|
|
2189
|
+
// Trigger re-render
|
|
2190
|
+
meshDesc.on("needsUpdate", this.forceUpdate);
|
|
2191
|
+
|
|
2192
|
+
this.forceUpdate();
|
|
2193
|
+
});
|
|
2114
2194
|
|
|
2115
2195
|
const l = new MeshHandle(meshDesc);
|
|
2116
2196
|
|
|
2197
|
+
l.on("deleted", this.forceUpdate);
|
|
2198
|
+
|
|
2117
2199
|
// Store the mesh descriptor
|
|
2118
2200
|
this.layersManager.add(l);
|
|
2119
2201
|
|
|
@@ -2139,19 +2221,26 @@ export default class ThreeView<
|
|
|
2139
2221
|
// Create light descriptor instance
|
|
2140
2222
|
const lightDesc = this.registries.light.create(lightType, config);
|
|
2141
2223
|
|
|
2142
|
-
// Initialize the light
|
|
2143
|
-
lightDesc.onCreate()
|
|
2224
|
+
// Initialize the light; hooks are wired once the instance exists.
|
|
2225
|
+
this._trackAsyncCreate("light", lightDesc, lightDesc.onCreate(), () => {
|
|
2226
|
+
// Deleted while an async creation was loading — nothing to wire.
|
|
2227
|
+
if (lightDesc.destroyed) return;
|
|
2144
2228
|
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2229
|
+
// Set up update listener if the descriptor has an update method
|
|
2230
|
+
if (lightDesc.update) {
|
|
2231
|
+
this.on("preRender", lightDesc.update.bind(lightDesc));
|
|
2232
|
+
}
|
|
2149
2233
|
|
|
2150
|
-
|
|
2151
|
-
|
|
2234
|
+
// Trigger re-render
|
|
2235
|
+
lightDesc.on("needsUpdate", this.forceUpdate);
|
|
2236
|
+
|
|
2237
|
+
this.forceUpdate();
|
|
2238
|
+
});
|
|
2152
2239
|
|
|
2153
2240
|
const l = new LightHandle(lightDesc);
|
|
2154
2241
|
|
|
2242
|
+
l.on("deleted", this.forceUpdate);
|
|
2243
|
+
|
|
2155
2244
|
// Store the light descriptor
|
|
2156
2245
|
this.layersManager.add(l);
|
|
2157
2246
|
|
|
@@ -2194,18 +2283,26 @@ export default class ThreeView<
|
|
|
2194
2283
|
// and recompiles shaders when the derived configuration actually changes,
|
|
2195
2284
|
// so tune effects via `update()` rather than re-adding them.
|
|
2196
2285
|
this._syncGBuffers();
|
|
2197
|
-
l.on("deleted",
|
|
2286
|
+
l.on("deleted", () => {
|
|
2287
|
+
this._syncGBuffers();
|
|
2288
|
+
this.forceUpdate();
|
|
2289
|
+
});
|
|
2198
2290
|
|
|
2199
|
-
// Initialize the effect
|
|
2200
|
-
effectDesc.onCreate()
|
|
2291
|
+
// Initialize the effect; hooks are wired once the instance exists.
|
|
2292
|
+
this._trackAsyncCreate("effect", effectDesc, effectDesc.onCreate(), () => {
|
|
2293
|
+
// Deleted while an async creation was loading — nothing to wire.
|
|
2294
|
+
if (effectDesc.destroyed) return;
|
|
2201
2295
|
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2296
|
+
// Set up update listener if the descriptor has an update method
|
|
2297
|
+
if (effectDesc.update) {
|
|
2298
|
+
this.on("preRender", effectDesc.update.bind(effectDesc));
|
|
2299
|
+
}
|
|
2206
2300
|
|
|
2207
|
-
|
|
2208
|
-
|
|
2301
|
+
// Trigger re-render
|
|
2302
|
+
effectDesc.on("needsUpdate", this.forceUpdate);
|
|
2303
|
+
|
|
2304
|
+
this.forceUpdate();
|
|
2305
|
+
});
|
|
2209
2306
|
|
|
2210
2307
|
// Return handle for imperative access
|
|
2211
2308
|
return l as EffectHandle<L>;
|
|
@@ -52,7 +52,7 @@ export const transformShader = (
|
|
|
52
52
|
#include <packing>
|
|
53
53
|
|
|
54
54
|
in float batchId;
|
|
55
|
-
out float nvr_vBatchId;
|
|
55
|
+
flat out float nvr_vBatchId;
|
|
56
56
|
out vec3 vPosition;
|
|
57
57
|
|
|
58
58
|
${ShowParsVertex}
|
|
@@ -93,7 +93,7 @@ uniform float nvr_uPickable;
|
|
|
93
93
|
// uEffectIdsMask is declared by overrideMaterialsForMRT (#ifdef USE_SELECTIVE_EFFECT block)
|
|
94
94
|
${MODEL_BASE_SHADER_MARKERS.fragment.UNIFORM_END}
|
|
95
95
|
|
|
96
|
-
in float nvr_vBatchId;
|
|
96
|
+
flat in float nvr_vBatchId;
|
|
97
97
|
|
|
98
98
|
${ShowParsFragment}
|
|
99
99
|
|
|
@@ -68,7 +68,7 @@ in float attrBatchId;
|
|
|
68
68
|
in vec4 scaleNormalAndCap;
|
|
69
69
|
|
|
70
70
|
uniform vec2 uMinMaxHeight;
|
|
71
|
-
out float nvr_vBatchId;
|
|
71
|
+
flat out float nvr_vBatchId;
|
|
72
72
|
|
|
73
73
|
${useRTE ? RteParsVertex : ""}
|
|
74
74
|
${ShowParsVertex}
|
|
@@ -162,7 +162,7 @@ uniform float nvr_uPickable;
|
|
|
162
162
|
uniform bool uIsTexturized;
|
|
163
163
|
${POLYGON_BASE_SHADER_MARKERS.fragment.UNIFORM_END}
|
|
164
164
|
|
|
165
|
-
in float nvr_vBatchId;
|
|
165
|
+
flat in float nvr_vBatchId;
|
|
166
166
|
|
|
167
167
|
${ShowParsFragment}
|
|
168
168
|
|