@hello-terrain/three 0.0.0-alpha.1 → 0.0.0-alpha.11

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/index.d.cts CHANGED
@@ -1,13 +1,26 @@
1
- import { BufferGeometry } from 'three';
1
+ import { BufferGeometry, Ray, Vector3 as Vector3$1, Raycaster, Intersection } from 'three';
2
+ import * as three_webgpu from 'three/webgpu';
3
+ import { StorageArrayTexture, StorageTexture, Node, WebGPURenderer, StorageBufferAttribute, StorageBufferNode, UniformNode, Vector3, Vector3Like, InstancedMesh, NodeMaterial, ConstNode } from 'three/webgpu';
4
+ import Node$1 from 'three/src/nodes/core/Node.js';
2
5
  import * as three_src_nodes_TSL_js from 'three/src/nodes/TSL.js';
3
- import { Node } from 'three/webgpu';
6
+ import { ShaderCallNodeInternal } from 'three/src/nodes/TSL.js';
7
+ import * as _hello_terrain_work from '@hello-terrain/work';
8
+ import { TaskRef, Graph } from '@hello-terrain/work';
9
+ import * as three_tsl from 'three/tsl';
4
10
 
5
11
  /**
6
12
  * Custom geometry for terrain tiles with properly handled skirts.
7
13
  * This geometry ensures that corner triangles are subdivided correctly.
8
14
  */
9
15
  declare class TerrainGeometry extends BufferGeometry {
10
- constructor(innerSegments?: number, extendUV?: boolean);
16
+ /**
17
+ * @param flipWinding Reverse triangle winding so front faces point the
18
+ * opposite way. The default winding makes flat tiles front-face `+Y`; the
19
+ * cube-sphere maps `(u→right, v→up)`, which would otherwise leave the
20
+ * planet's outer shell back-facing, so it passes `flipWinding` to render
21
+ * the outer surface with `FrontSide`.
22
+ */
23
+ constructor(innerSegments?: number, extendUV?: boolean, flipWinding?: boolean);
11
24
  /**
12
25
  * Generate indices for terrain geometry with proper skirt corner handling.
13
26
  * The key improvement is in how corner triangles are subdivided.
@@ -28,17 +41,19 @@ declare class TerrainGeometry extends BufferGeometry {
28
41
  * | / | \ | / | \ |
29
42
  * o---o---o---o---o
30
43
  *
31
- * INNER GRID (consistent diagonal, no rotational symmetry):
32
- * o---o---o
33
- * | \ | \ |
34
- * o---o---o
35
- * | \ | \ |
36
- * o---o---o
44
+ * INNER GRID (alternating diagonals checkerboard pattern):
45
+ * o---o---o---o---o
46
+ * | \ | / | \ | / |
47
+ * o---o---o---o---o
48
+ * | / | \ | / | \ |
49
+ * o---o---o---o---o
50
+ * | \ | / | \ | / |
51
+ * o---o---o---o---o
37
52
  *
38
53
  * Where o = vertex
39
54
  * Each square cell is split into 2 triangles.
40
55
  * - Skirt cells (outer ring): diagonal flip based on quadrant for corner correctness
41
- * - Inner cells: consistent diagonal direction (all triangles "point" the same way)
56
+ * - Inner cells: alternating diagonal via (x+y)%2 to reduce interpolation artifacts
42
57
  *
43
58
  * Vertex layout (for innerSegments = 2):
44
59
  *
@@ -88,6 +103,1027 @@ declare class TerrainGeometry extends BufferGeometry {
88
103
  private generateNormals;
89
104
  }
90
105
 
106
+ declare const Dir: {
107
+ readonly LEFT: 0;
108
+ readonly RIGHT: 1;
109
+ readonly TOP: 2;
110
+ readonly BOTTOM: 3;
111
+ };
112
+ type Dir = (typeof Dir)[keyof typeof Dir];
113
+ declare const U32_EMPTY = 4294967295;
114
+ type TileId = {
115
+ /** 0 for flat terrain; 0..5 for cube-sphere faces */
116
+ space: number;
117
+ level: number;
118
+ /** tile coordinate at this level (signed to support infinite surfaces) */
119
+ x: number;
120
+ /** tile coordinate at this level (signed to support infinite surfaces) */
121
+ y: number;
122
+ };
123
+ type TileBounds = {
124
+ /** camera-relative center */
125
+ cx: number;
126
+ cy: number;
127
+ cz: number;
128
+ /** conservative radius */
129
+ r: number;
130
+ };
131
+ type TopologyProjection = "flat" | "cubeSphere";
132
+ type Topology = {
133
+ spaceCount: number;
134
+ /** maximum number of roots returned by `rootTiles` */
135
+ maxRootCount: number;
136
+ /**
137
+ * GPU position/normal assembly projection. Defaults to `flat` when absent.
138
+ * `cubeSphere` selects radial sphere mapping from cube faces.
139
+ */
140
+ projection?: TopologyProjection;
141
+ /** Sphere radius in world units (cube-sphere projection only). */
142
+ radius?: number;
143
+ /**
144
+ * Planet center in world space (cube-sphere projection only). Used to apply
145
+ * the camera elevation offset along the radial up-direction during LOD.
146
+ */
147
+ center?: {
148
+ x: number;
149
+ y: number;
150
+ z: number;
151
+ };
152
+ /**
153
+ * Compute the same-level neighbor TileId in the requested direction.
154
+ * Returns false if the neighbor is outside the valid topology.
155
+ *
156
+ * IMPORTANT: This must handle cross-space edges in the future (cube-sphere).
157
+ */
158
+ neighborSameLevel(tile: TileId, dir: Dir, out: TileId): boolean;
159
+ /**
160
+ * Conservative camera-relative bounds for LOD decisions.
161
+ * Avoids absolute world coordinates so Earth-scale worlds remain stable.
162
+ */
163
+ tileBounds(tile: TileId, cameraOrigin: {
164
+ x: number;
165
+ y: number;
166
+ z: number;
167
+ }, out: TileBounds): void;
168
+ /**
169
+ * Fill root tiles for the current frame and return the count.
170
+ * Implementations should write level-0 tiles into `out[0..count)`.
171
+ */
172
+ rootTiles(cameraOrigin: {
173
+ x: number;
174
+ y: number;
175
+ z: number;
176
+ }, out: TileId[]): number;
177
+ };
178
+ type LeafSet = {
179
+ /** maximum number of leaves that fit in the buffers */
180
+ capacity: number;
181
+ /** number of valid leaf entries in this frame */
182
+ count: number;
183
+ space: Uint8Array;
184
+ level: Uint8Array;
185
+ x: Int32Array;
186
+ y: Int32Array;
187
+ };
188
+ declare function allocLeafSet(capacity: number): LeafSet;
189
+ declare function resetLeafSet(leaves: LeafSet): void;
190
+ type SeamTable = {
191
+ /** maximum number of leaves the table can describe */
192
+ capacity: number;
193
+ /** number of leaves described (typically equals leaves.count) */
194
+ count: number;
195
+ /** fixed stride per leaf, in u32 entries */
196
+ stride: 8;
197
+ /**
198
+ * neighbors in leaf-list index space
199
+ * layout: neighbors[leafIndex * 8 + edge*2 + slot]
200
+ * edge order: LEFT, RIGHT, TOP, BOTTOM
201
+ * slot: 0..1 (at most 2 neighbors per edge under 2:1 balance)
202
+ */
203
+ neighbors: Uint32Array;
204
+ };
205
+ declare function allocSeamTable(capacity: number): SeamTable;
206
+ declare function resetSeamTable(seams: SeamTable): void;
207
+ type LodMode = "distance" | "screen";
208
+ type UpdateParams = {
209
+ cameraOrigin: {
210
+ x: number;
211
+ y: number;
212
+ z: number;
213
+ };
214
+ /**
215
+ * Terrain elevation beneath the camera (from the previous frame). During
216
+ * refinement it offsets the camera toward the terrain surface so LOD distance
217
+ * is measured relative to the surface rather than the datum:
218
+ * - flat: subtracted from `cameraOrigin.y`.
219
+ * - cube-sphere: subtracted along the radial up-direction from the planet center.
220
+ */
221
+ elevationAtCameraXZ?: number;
222
+ /**
223
+ * Controls how subdivision decisions are made.
224
+ * `distance` is the initial focus; `screen` is supported for future parity.
225
+ */
226
+ mode?: LodMode;
227
+ /**
228
+ * Distance-based refinement threshold.
229
+ * Interpretation is criteria-dependent; keep it stable across surfaces by using bounds.
230
+ */
231
+ distanceFactor?: number;
232
+ /** Screen-space projection factor = screenHeight / (2*tan(fovY/2)) */
233
+ projectionFactor?: number;
234
+ /** Target pixel radius/size threshold for screen-space refinement */
235
+ targetPixels?: number;
236
+ /** Prevent flicker by separating split/merge thresholds (0..1 typical) */
237
+ hysteresis?: number;
238
+ };
239
+ type QuadtreeConfig = {
240
+ maxNodes: number;
241
+ maxLevel: number;
242
+ };
243
+
244
+ type NodeStore = {
245
+ maxNodes: number;
246
+ nodesUsed: number;
247
+ /** generation stamping to avoid clearing buffers */
248
+ currentGen: number;
249
+ gen: Uint16Array;
250
+ space: Uint8Array;
251
+ level: Uint8Array;
252
+ x: Int32Array;
253
+ y: Int32Array;
254
+ /** sentinel U32_EMPTY means no children; otherwise children are [firstChild..firstChild+3] */
255
+ firstChild: Uint32Array;
256
+ flags: Uint8Array;
257
+ /** root node id per space */
258
+ roots: Uint32Array;
259
+ };
260
+
261
+ type SpatialIndex = {
262
+ size: number;
263
+ mask: number;
264
+ stampGen: number;
265
+ stamp: Uint16Array;
266
+ keysSpace: Uint8Array;
267
+ keysLevel: Uint8Array;
268
+ keysX: Uint32Array;
269
+ keysY: Uint32Array;
270
+ values: Uint32Array;
271
+ };
272
+ declare function createSpatialIndex(maxEntries: number): SpatialIndex;
273
+
274
+ /**
275
+ * Build a spatial index for the current LeafSet.
276
+ * Maps (space, level, x, y) -> leafIndex.
277
+ *
278
+ * Allocation-free if `out` is provided.
279
+ */
280
+ declare function buildLeafIndex(leaves: LeafSet, out?: SpatialIndex): SpatialIndex;
281
+
282
+ type QuadtreeState = {
283
+ cfg: QuadtreeConfig;
284
+ store: NodeStore;
285
+ /** default reusable leaf buffers (capacity = cfg.maxNodes) */
286
+ leaves: LeafSet;
287
+ /** internal: node id per leaf entry (parallel to leaves.* arrays) */
288
+ leafNodeIds: Uint32Array;
289
+ /** reusable leaf spatial index (capacity = cfg.maxNodes) */
290
+ leafIndex: SpatialIndex;
291
+ /** traversal scratch */
292
+ stack: Uint32Array;
293
+ /** root nodes for this frame */
294
+ rootNodeIds: Uint32Array;
295
+ rootCount: number;
296
+ /** split scheduling scratch (dedupe without allocations) */
297
+ splitQueue: Uint32Array;
298
+ splitStamp: Uint16Array;
299
+ splitGen: number;
300
+ /** scratch objects to avoid allocations */
301
+ scratchTile: TileId;
302
+ scratchNeighbor: TileId;
303
+ scratchBounds: TileBounds;
304
+ scratchRootTiles: TileId[];
305
+ /** topology space count is fixed for a given state */
306
+ spaceCount: number;
307
+ };
308
+ declare function createState(cfg: QuadtreeConfig, topology: Topology): QuadtreeState;
309
+ declare function beginUpdate(state: QuadtreeState, topology: Topology, params: UpdateParams): void;
310
+
311
+ /**
312
+ * Update the quadtree for the given topology + camera parameters.
313
+ *
314
+ * Produces a LeafSet of TileIds (SoA typed arrays).
315
+ */
316
+ declare function update(state: QuadtreeState, topology: Topology, params: UpdateParams, outLeaves?: LeafSet): LeafSet;
317
+
318
+ /**
319
+ * Build a fixed-width seam/neighbor table for balanced leaves (2:1).
320
+ *
321
+ * Output neighbors are leaf-list indices, with U32_EMPTY for missing entries.
322
+ * Layout: neighbors[leafIndex * 8 + edge*2 + slot].
323
+ */
324
+ declare function buildSeams2to1(topology: Topology, leaves: LeafSet, outSeams: SeamTable, outIndex?: SpatialIndex): SeamTable;
325
+
326
+ type FlatTopologyConfig = {
327
+ /**
328
+ * World-space size of the root tile edge.
329
+ * The root tile covers [-rootSize/2, +rootSize/2] around origin in X/Z.
330
+ */
331
+ rootSize: number;
332
+ origin: {
333
+ x: number;
334
+ y: number;
335
+ z: number;
336
+ };
337
+ /** optional conservative vertical extent, included in bounds radius */
338
+ maxHeight?: number;
339
+ };
340
+ declare function createFlatTopology(cfg: FlatTopologyConfig): Topology;
341
+
342
+ type InfiniteFlatTopologyConfig = {
343
+ rootSize: number;
344
+ origin: {
345
+ x: number;
346
+ y: number;
347
+ z: number;
348
+ };
349
+ /** optional conservative vertical extent, included in bounds radius */
350
+ maxHeight?: number;
351
+ /** half-width of root grid in root tiles (1 => 3x3 roots) */
352
+ rootGridRadius?: number;
353
+ };
354
+ declare function createInfiniteFlatTopology(cfg: InfiniteFlatTopologyConfig): Topology;
355
+
356
+ type CubeSphereTopologyConfig = {
357
+ /** Sphere radius in world units. */
358
+ radius: number;
359
+ /** Planet center in world space (defaults to origin). */
360
+ center?: {
361
+ x: number;
362
+ y: number;
363
+ z: number;
364
+ };
365
+ /** Optional conservative vertical extent, included in bounds radius. */
366
+ maxHeight?: number;
367
+ };
368
+ /**
369
+ * Cube-sphere topology: six quadtree faces wrapped onto a sphere.
370
+ *
371
+ * Topology (`neighborSameLevel`) is derived numerically from the shared
372
+ * `CUBE_FACES` basis so cross-face edges (including rotated pole edges)
373
+ * resolve to the correct neighbor tile without hand-coded transforms.
374
+ */
375
+ declare function createCubeSphereTopology(cfg: CubeSphereTopologyConfig): Topology;
376
+
377
+ /**
378
+ * Canonical cube-sphere face basis.
379
+ *
380
+ * Shared single source of truth between the CPU surface topology
381
+ * (`cubeSphere.ts`) and the GPU position/normal assembly (`tsl/cubeSphere.ts`)
382
+ * so both agree on geometry and faces seam correctly.
383
+ *
384
+ * Each face maps a face-local coordinate (u, v) in [0, 1] to a point on the
385
+ * cube `[-1, 1]^3` via:
386
+ *
387
+ * s = 2u - 1, t = 2v - 1
388
+ * cube = forward + s * right + t * up
389
+ *
390
+ * Normalizing `cube` yields the unit-sphere direction for that vertex.
391
+ *
392
+ * Bases are right-handed (`forward = right x up`) and outward-facing.
393
+ * Space indices: 0:+X 1:-X 2:+Y 3:-Y 4:+Z 5:-Z.
394
+ */
395
+ type Vec3 = readonly [number, number, number];
396
+ type CubeFace = {
397
+ forward: Vec3;
398
+ right: Vec3;
399
+ up: Vec3;
400
+ };
401
+ declare const CUBE_FACE_COUNT = 6;
402
+ declare const CUBE_FACES: readonly CubeFace[];
403
+
404
+ type Vec3Mutable = [number, number, number];
405
+ /**
406
+ * Cube-space point for a face-local coordinate (u, v) in [0, 1]:
407
+ * cube = forward + (2u-1) * right + (2v-1) * up
408
+ * The result is unnormalized; normalize it to obtain the sphere direction.
409
+ */
410
+ declare function faceUVToCube(face: number, u: number, v: number, out: Vec3Mutable): void;
411
+ /** Pick the cube face whose normal axis dominates the direction. */
412
+ declare function directionToFace(d: Vec3): number;
413
+ /** Face-local (u, v) in [0, 1] for a direction known to fall on `face`. */
414
+ declare function directionToFaceUV(face: number, d: Vec3, out: [number, number]): void;
415
+ /**
416
+ * Convert latitude/longitude (degrees) to a unit sphere direction.
417
+ *
418
+ * Convention matches `CUBE_FACES` (+Y is the north pole):
419
+ * - latitude is the angle above the equator, in `[-90, 90]`
420
+ * - longitude is the angle around the +Y axis, in `[-180, 180]`,
421
+ * measured from +Z toward +X (lon = 0 points along +Z).
422
+ */
423
+ declare function latLongToDirection(latDeg: number, lonDeg: number, out: Vec3Mutable): void;
424
+ /** Inverse of {@link latLongToDirection}; returns degrees. */
425
+ declare function directionToLatLong(d: Vec3): {
426
+ latitude: number;
427
+ longitude: number;
428
+ };
429
+
430
+ type TerrainFieldStorageBackendType = "array-texture" | "atlas" | "texture-3d";
431
+ type TerrainFieldStorageFormat = "rgba16float" | "rgba32float";
432
+ type TerrainFieldStorageOptions = {
433
+ backend?: TerrainFieldStorageBackendType;
434
+ filter?: "nearest" | "linear";
435
+ format?: TerrainFieldStorageFormat;
436
+ };
437
+ interface TerrainFieldStorage {
438
+ readonly backendType: TerrainFieldStorageBackendType;
439
+ readonly edgeVertexCount: number;
440
+ readonly tileCount: number;
441
+ readonly texture: StorageArrayTexture | StorageTexture;
442
+ uv(ix: Node, iy: Node, tileIndex: Node): Node;
443
+ texel(ix: Node, iy: Node, tileIndex: Node): Node;
444
+ /** UV-based filtered sample. `u, v` in [0, 1] tile-local space. */
445
+ sample(u: Node, v: Node, tileIndex: Node): Node;
446
+ resize(width: number, height: number, tileCount: number): void;
447
+ }
448
+ declare function ArrayTextureBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
449
+ declare function AtlasBackend(edgeVertexCount: number, tileCount: number, options: Required<Pick<TerrainFieldStorageOptions, "format" | "filter">>): TerrainFieldStorage;
450
+ declare function createTerrainFieldStorage(edgeVertexCount: number, tileCount: number, renderer?: WebGPURenderer, options?: TerrainFieldStorageOptions): TerrainFieldStorage;
451
+ declare function storeTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node, value: Node): Node;
452
+ declare function loadTerrainField(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
453
+ declare function loadTerrainFieldElevation(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
454
+ declare function loadTerrainFieldNormal(storage: TerrainFieldStorage, ix: Node, iy: Node, tileIndex: Node): Node;
455
+ /**
456
+ * UV-based filtered sample. `u, v` are in [0, 1] tile-local space.
457
+ * Respects the filter mode (nearest / linear) set on the storage.
458
+ */
459
+ declare function sampleTerrainField(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
460
+ declare function sampleTerrainFieldElevation(storage: TerrainFieldStorage, u: Node, v: Node, tileIndex: Node): Node;
461
+ declare function packTerrainFieldSample(height: Node, normalXZ: Node, extra?: Node): Node;
462
+
463
+ interface ElevationParams {
464
+ worldPosition: Node$1;
465
+ rootSize: Node$1;
466
+ rootUV: Node$1;
467
+ tileUV: Node$1;
468
+ tileLevel: Node$1;
469
+ tileSize: Node$1;
470
+ tileOriginVec2: Node$1;
471
+ nodeIndex: Node$1;
472
+ }
473
+ type ElevationCallback = (params: ElevationParams) => Node$1;
474
+
475
+ interface TerrainUniformsParams {
476
+ rootSize: number;
477
+ rootOrigin: Vector3Like;
478
+ innerTileSegments: number;
479
+ skirtScale: number;
480
+ elevationScale: number;
481
+ radius: number;
482
+ instanceId: string;
483
+ }
484
+ interface TerrainUniformsContext {
485
+ uRootOrigin: UniformNode<Vector3>;
486
+ uRootSize: UniformNode<number>;
487
+ uInnerTileSegments: UniformNode<number>;
488
+ uSkirtScale: UniformNode<number>;
489
+ uElevationScale: UniformNode<number>;
490
+ uRadius: UniformNode<number>;
491
+ }
492
+ interface LeafStorageState {
493
+ data: Int32Array<ArrayBuffer>;
494
+ attribute: StorageBufferAttribute;
495
+ node: StorageBufferNode;
496
+ }
497
+
498
+ interface GpuSpatialIndexContext {
499
+ data: Uint32Array<ArrayBuffer>;
500
+ size: number;
501
+ mask: number;
502
+ stampGen: UniformNode<number>;
503
+ attribute: StorageBufferAttribute;
504
+ node: StorageBufferNode;
505
+ }
506
+ interface TerrainSampler {
507
+ sampleElevation: (worldX: Node, worldZ: Node) => Node;
508
+ sampleNormal: (worldX: Node, worldZ: Node) => Node;
509
+ sampleTerrain: (worldX: Node, worldZ: Node) => Node;
510
+ sampleValidity: (worldX: Node, worldZ: Node) => Node;
511
+ evaluateElevation: (worldX: Node, worldZ: Node) => Node;
512
+ evaluateNormal: (worldX: Node, worldZ: Node, epsilon?: Node) => Node;
513
+ /** Packed `vec4(elevation, nx, ny, nz)` where the normal is tangent-space. */
514
+ sampleTerrainByDirection?: (direction: Node) => Node;
515
+ sampleElevationByDirection?: (direction: Node) => Node;
516
+ /** World-space surface normal reconstructed in the sphere tangent frame. */
517
+ sampleNormalByDirection?: (direction: Node) => Node;
518
+ sampleValidityByDirection?: (direction: Node) => Node;
519
+ }
520
+ interface CreateTerrainSamplerParams {
521
+ terrainFieldStorage: TerrainFieldStorage;
522
+ spatialIndex: GpuSpatialIndexContext;
523
+ uniforms: TerrainUniformsContext;
524
+ elevationCallback: ElevationCallback;
525
+ /** Maximum quadtree level to probe during tile lookup. */
526
+ maxLevel: number;
527
+ projection?: TopologyProjection;
528
+ }
529
+ interface TerrainSample {
530
+ elevation: number;
531
+ normal: Vector3$1;
532
+ valid: boolean;
533
+ }
534
+ interface TerrainSampleBatch {
535
+ elevations: Float32Array;
536
+ normals: Float32Array;
537
+ valid: Uint8Array;
538
+ generation: number;
539
+ }
540
+ /**
541
+ * Result of sampling a cube-sphere surface from a direction/position/lat-long.
542
+ *
543
+ * `elevation` is the radial displacement above the base radius (already scaled
544
+ * by `elevationScale`); `position` is the full world-space surface point
545
+ * `center + direction * (radius + elevation)`.
546
+ */
547
+ interface TerrainSurfaceSample {
548
+ position: Vector3$1;
549
+ normal: Vector3$1;
550
+ direction: Vector3$1;
551
+ elevation: number;
552
+ valid: boolean;
553
+ }
554
+ interface TerrainSurfaceSampleBatch {
555
+ positions: Float32Array;
556
+ normals: Float32Array;
557
+ elevations: Float32Array;
558
+ valid: Uint8Array;
559
+ generation: number;
560
+ }
561
+ interface TerrainTile {
562
+ /** Surface space index: 0 for flat terrain, 0..5 for cube-sphere faces. */
563
+ space: number;
564
+ level: number;
565
+ x: number;
566
+ y: number;
567
+ index: number;
568
+ }
569
+ interface TerrainTileBounds extends TerrainTile {
570
+ minElevation: number;
571
+ maxElevation: number;
572
+ }
573
+ interface ElevationRange {
574
+ min: number;
575
+ max: number;
576
+ }
577
+ /**
578
+ * Flat (heightfield) terrain query, keyed on world XZ. For cube-sphere
579
+ * surfaces use {@link TerrainSphereQuery} instead.
580
+ */
581
+ interface TerrainQuery {
582
+ getElevation(worldX: number, worldZ: number): number | null;
583
+ getNormal(worldX: number, worldZ: number): Vector3$1 | null;
584
+ getTile(worldX: number, worldZ: number): TerrainTile | null;
585
+ getTileBounds(worldX: number, worldZ: number): TerrainTileBounds | null;
586
+ getGlobalElevationRange(): ElevationRange | null;
587
+ sampleTerrain(worldX: number, worldZ: number): TerrainSample;
588
+ sampleTerrainBatch(positions: Float32Array): TerrainSampleBatch;
589
+ readonly generation: number;
590
+ }
591
+ /**
592
+ * Cube-sphere terrain query. A surface location is identified by a direction
593
+ * from the planet center (the canonical form); `ByPosition` projects any world
594
+ * point onto its direction, and `ByLatLong` takes degrees (latitude
595
+ * `[-90, 90]`, longitude `[-180, 180]`). Elevation is the radial displacement
596
+ * above the base radius.
597
+ *
598
+ * Exposed only when the active surface uses the `cubeSphere` projection
599
+ * (otherwise `null` on the query context / runtime).
600
+ */
601
+ interface TerrainSphereQuery {
602
+ readonly generation: number;
603
+ getElevationByDirection(direction: Vector3$1): number | null;
604
+ getElevationByPosition(position: Vector3$1): number | null;
605
+ getElevationByLatLong(latitudeDeg: number, longitudeDeg: number): number | null;
606
+ getNormalByDirection(direction: Vector3$1): Vector3$1 | null;
607
+ getNormalByPosition(position: Vector3$1): Vector3$1 | null;
608
+ getNormalByLatLong(latitudeDeg: number, longitudeDeg: number): Vector3$1 | null;
609
+ sampleTerrainByDirection(direction: Vector3$1): TerrainSurfaceSample;
610
+ sampleTerrainByPosition(position: Vector3$1): TerrainSurfaceSample;
611
+ sampleTerrainByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainSurfaceSample;
612
+ getTileByDirection(direction: Vector3$1): TerrainTile | null;
613
+ getTileByPosition(position: Vector3$1): TerrainTile | null;
614
+ getTileByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTile | null;
615
+ getTileBoundsByDirection(direction: Vector3$1): TerrainTileBounds | null;
616
+ getTileBoundsByPosition(position: Vector3$1): TerrainTileBounds | null;
617
+ getTileBoundsByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTileBounds | null;
618
+ /** Batch sample; `directions` is a Float32Array of xyz triples. */
619
+ sampleTerrainBatchByDirection(directions: Float32Array): TerrainSurfaceSampleBatch;
620
+ }
621
+ interface RaycastOptions {
622
+ maxSteps?: number;
623
+ refinementSteps?: number;
624
+ maxDistance?: number;
625
+ }
626
+ interface TerrainRaycastResult {
627
+ position: Vector3$1;
628
+ normal: Vector3$1;
629
+ distance: number;
630
+ }
631
+ interface TerrainRaycast {
632
+ pick(ray: Ray, options?: RaycastOptions): TerrainRaycastResult | null;
633
+ }
634
+
635
+ type TerrainMeshParams = {
636
+ innerTileSegments: number;
637
+ maxNodes: number;
638
+ material: NodeMaterial;
639
+ /**
640
+ * Reverse tile triangle winding. Cube-sphere surfaces set this so the
641
+ * planet's outer shell is front-facing and renders with `FrontSide`.
642
+ */
643
+ flipWinding: boolean;
644
+ };
645
+ declare class TerrainMesh extends InstancedMesh {
646
+ private _innerTileSegments;
647
+ private _maxNodes;
648
+ private _flipWinding;
649
+ terrainRaycast: TerrainRaycast | null;
650
+ constructor(params?: Partial<TerrainMeshParams>);
651
+ get innerTileSegments(): number;
652
+ set innerTileSegments(tileSegments: number);
653
+ get flipWinding(): boolean;
654
+ set flipWinding(flip: boolean);
655
+ get maxNodes(): number;
656
+ set maxNodes(maxNodes: number);
657
+ raycast(raycaster: Raycaster, intersects: Intersection[]): void;
658
+ }
659
+
660
+ interface TileBoundsContext {
661
+ data: Float32Array<ArrayBuffer>;
662
+ attribute: StorageBufferAttribute;
663
+ node: StorageBufferNode;
664
+ }
665
+
666
+ type ComputeStageCallback = (nodeIndex: Node, globalVertexIndex: Node, uv: Node, localCoordinates: Node, texelSize: Node) => void;
667
+ type ComputePipeline = ComputeStageCallback[];
668
+
669
+ /**
670
+ * Default compile + execute tasks — uses terrainFieldStageTask as the leaf.
671
+ * Derived from the same factory as user pipelines to avoid duplicated logic.
672
+ */
673
+ declare const compileComputeTask: _hello_terrain_work.Task<{
674
+ execute: (renderer: WebGPURenderer, instanceCount: number) => void;
675
+ }, string, unknown>;
676
+ declare const executeComputeTask: _hello_terrain_work.Task<any, string, {
677
+ renderer: WebGPURenderer;
678
+ }>;
679
+ /**
680
+ * Factory for user-extensible pipelines.
681
+ *
682
+ * Users who add custom compute stages create their own stage tasks using
683
+ * the accumulation pattern (`get()` predecessor, spread, append), then pass
684
+ * their leaf stage to this helper to get compile + execute tasks.
685
+ *
686
+ * @example
687
+ * ```ts
688
+ * const erosionStageTask = task((get, work) => {
689
+ * const upstream = get(elevationFieldStageTask);
690
+ * return work((): ComputePipeline => [
691
+ * ...upstream,
692
+ * (nodeIndex, globalVertexIndex, uv) => {
693
+ * // custom erosion logic
694
+ * },
695
+ * ]);
696
+ * });
697
+ *
698
+ * const { compile, execute } = createComputePipelineTasks(erosionStageTask);
699
+ * ```
700
+ */
701
+ declare function createComputePipelineTasks(leafStageTask: TaskRef<ComputePipeline>): {
702
+ compile: _hello_terrain_work.Task<{
703
+ execute: (renderer: WebGPURenderer, instanceCount: number) => void;
704
+ }, string, unknown>;
705
+ execute: _hello_terrain_work.Task<any, string, {
706
+ renderer: WebGPURenderer;
707
+ }>;
708
+ };
709
+
710
+ declare function createTileCompute(leafStorage: LeafStorageState, uniforms: TerrainUniformsContext, projection?: TopologyProjection): {
711
+ tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
712
+ tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
713
+ tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
714
+ tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
715
+ tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
716
+ rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
717
+ tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node, number | Node, number | Node]>;
718
+ };
719
+
720
+ type TerrainQueryConfig = {
721
+ rootSize: number;
722
+ originX: number;
723
+ originY: number;
724
+ originZ: number;
725
+ innerTileSegments: number;
726
+ elevationScale: number;
727
+ maxLevel: number;
728
+ /** Topology projection; `cubeSphere` enables the direction/lat-long queries. */
729
+ projection: TopologyProjection;
730
+ /** Sphere radius in world units (cube-sphere projection only). */
731
+ radius: number;
732
+ };
733
+ interface CpuTerrainCache {
734
+ readonly generation: number;
735
+ readonly ready: boolean;
736
+ updateConfig(config: TerrainQueryConfig): void;
737
+ triggerReadback(renderer: WebGPURenderer, attribute: StorageBufferAttribute, spatialIndex: SpatialIndex, boundsAttribute?: StorageBufferAttribute, activeLeafCount?: number): void;
738
+ getElevation(worldX: number, worldZ: number): number | null;
739
+ getNormal(worldX: number, worldZ: number): Vector3$1 | null;
740
+ getTile(worldX: number, worldZ: number): TerrainTile | null;
741
+ getTileBounds(worldX: number, worldZ: number): TerrainTileBounds | null;
742
+ getGlobalElevationRange(): ElevationRange | null;
743
+ sampleTerrainBatch(positions: Float32Array): TerrainSampleBatch;
744
+ sampleTerrain(worldX: number, worldZ: number): TerrainSample;
745
+ getElevationByDirection(direction: Vector3$1): number | null;
746
+ getElevationByPosition(position: Vector3$1): number | null;
747
+ getElevationByLatLong(latitudeDeg: number, longitudeDeg: number): number | null;
748
+ getNormalByDirection(direction: Vector3$1): Vector3$1 | null;
749
+ getNormalByPosition(position: Vector3$1): Vector3$1 | null;
750
+ getNormalByLatLong(latitudeDeg: number, longitudeDeg: number): Vector3$1 | null;
751
+ sampleTerrainByDirection(direction: Vector3$1): TerrainSurfaceSample;
752
+ sampleTerrainByPosition(position: Vector3$1): TerrainSurfaceSample;
753
+ sampleTerrainByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainSurfaceSample;
754
+ getTileByDirection(direction: Vector3$1): TerrainTile | null;
755
+ getTileByPosition(position: Vector3$1): TerrainTile | null;
756
+ getTileByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTile | null;
757
+ getTileBoundsByDirection(direction: Vector3$1): TerrainTileBounds | null;
758
+ getTileBoundsByPosition(position: Vector3$1): TerrainTileBounds | null;
759
+ getTileBoundsByLatLong(latitudeDeg: number, longitudeDeg: number): TerrainTileBounds | null;
760
+ sampleTerrainBatchByDirection(directions: Float32Array): TerrainSurfaceSampleBatch;
761
+ }
762
+
763
+ interface QuadtreeConfigState {
764
+ state: QuadtreeState;
765
+ topology: Topology;
766
+ }
767
+ interface LeafGpuBufferState extends LeafStorageState {
768
+ count: number;
769
+ }
770
+ interface ElevationFieldContext {
771
+ data: Float32Array<ArrayBuffer>;
772
+ attribute: StorageBufferAttribute;
773
+ node: StorageBufferNode;
774
+ }
775
+ interface TerrainQueryContext {
776
+ cache: CpuTerrainCache;
777
+ query: TerrainQuery;
778
+ /** Cube-sphere query; `null` unless the topology uses the cubeSphere projection. */
779
+ sphereQuery: TerrainSphereQuery | null;
780
+ shapeKey: string;
781
+ }
782
+ /** Task refs for the standard terrain pipeline. */
783
+ interface TerrainTasks {
784
+ instanceId: TaskRef<string>;
785
+ quadtreeConfig: TaskRef<QuadtreeConfigState>;
786
+ quadtreeUpdate: TaskRef<LeafSet>;
787
+ topology: TaskRef<Topology>;
788
+ leafStorage: TaskRef<LeafStorageState>;
789
+ leafGpuBuffer: TaskRef<LeafGpuBufferState>;
790
+ gpuSpatialIndexStorage: TaskRef<GpuSpatialIndexContext>;
791
+ gpuSpatialIndexUpload: TaskRef<GpuSpatialIndexContext>;
792
+ createUniforms: TaskRef<TerrainUniformsContext>;
793
+ updateUniforms: TaskRef<TerrainUniformsContext>;
794
+ positionNode: TaskRef<ShaderCallNodeInternal>;
795
+ createElevationFieldContext: TaskRef<ElevationFieldContext>;
796
+ createTileNodes: TaskRef<ReturnType<typeof createTileCompute>>;
797
+ createTerrainFieldTexture: TaskRef<TerrainFieldStorage>;
798
+ createTerrainSampler: TaskRef<TerrainSampler>;
799
+ elevationFieldStage: TaskRef<ComputePipeline>;
800
+ terrainFieldStage: TaskRef<ComputePipeline>;
801
+ compileCompute: TaskRef<{
802
+ execute: (renderer: WebGPURenderer, instanceCount: number) => void;
803
+ }>;
804
+ executeCompute: TaskRef<void | (() => void)>;
805
+ tileBoundsContext: TaskRef<TileBoundsContext & {
806
+ kernel: unknown;
807
+ }>;
808
+ tileBoundsReduction: TaskRef<TileBoundsContext>;
809
+ terrainQuery: TaskRef<TerrainQueryContext>;
810
+ terrainReadback: TaskRef<void>;
811
+ terrainRaycast: TaskRef<TerrainRaycast>;
812
+ }
813
+ type TerrainGraph = Graph<string, {
814
+ renderer: WebGPURenderer;
815
+ }>;
816
+
817
+ declare const createElevationFieldContextTask: _hello_terrain_work.Task<{
818
+ data: Float32Array<ArrayBuffer>;
819
+ attribute: StorageBufferAttribute;
820
+ node: three_webgpu.StorageBufferNode;
821
+ }, string, unknown>;
822
+ declare const tileNodesTask: _hello_terrain_work.Task<{
823
+ tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
824
+ tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
825
+ tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
826
+ tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
827
+ tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
828
+ rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
829
+ tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
830
+ }, string, unknown>;
831
+ /**
832
+ * Root compute stage — generates elevation data and writes to the
833
+ * elevation field storage buffer. Returns a single-element `ComputePipeline`.
834
+ */
835
+ declare const elevationFieldStageTask: _hello_terrain_work.Task<ComputePipeline, string, unknown>;
836
+
837
+ declare const gpuSpatialIndexStorageTask: _hello_terrain_work.Task<GpuSpatialIndexContext, string, unknown>;
838
+ declare const gpuSpatialIndexUploadTask: _hello_terrain_work.Task<GpuSpatialIndexContext, string, unknown>;
839
+
840
+ /** Generates a unique instance ID per graph (cached once). */
841
+ declare const instanceIdTask: _hello_terrain_work.Task<`${string}-${string}-${string}-${string}-${string}`, string, unknown>;
842
+
843
+ declare const createTerrainFieldTextureTask: _hello_terrain_work.Task<any, string, {
844
+ renderer: WebGPURenderer;
845
+ }>;
846
+ /**
847
+ * Normal field compute stage — reads height neighbors from the elevation field
848
+ * buffer, computes surface normals via central differences, packs XZ
849
+ * components into a u32 via `packHalf2x16`, and writes to the normal field
850
+ * storage buffer.
851
+ *
852
+ * Accumulates the upstream elevation pipeline via `get(elevationFieldStageTask)`.
853
+ */
854
+ declare const terrainFieldStageTask: _hello_terrain_work.Task<ComputePipeline, string, unknown>;
855
+
856
+ declare const createTerrainSamplerTask: _hello_terrain_work.Task<TerrainSampler, string, unknown>;
857
+
858
+ declare const terrainQueryTask: _hello_terrain_work.Task<TerrainQueryContext, string, unknown>;
859
+ declare const terrainReadbackTask: _hello_terrain_work.Task<any, string, {
860
+ renderer: WebGPURenderer;
861
+ }>;
862
+
863
+ declare const terrainRaycastTask: _hello_terrain_work.Task<TerrainRaycast, string, unknown>;
864
+
865
+ /** Root tile size in world units. */
866
+ declare const rootSize: _hello_terrain_work.ParamRef<number>;
867
+ /** World-space origin of the terrain. */
868
+ declare const origin: _hello_terrain_work.ParamRef<{
869
+ x: number;
870
+ y: number;
871
+ z: number;
872
+ }>;
873
+ /**
874
+ * Default number of segments per inner tile edge. The effective edge vertex
875
+ * count is `innerTileSegments + 3`
876
+ */
877
+ declare const innerTileSegments: _hello_terrain_work.ParamRef<number>;
878
+ /** Skirt scale factor. */
879
+ declare const skirtScale: _hello_terrain_work.ParamRef<number>;
880
+ /** Elevation vertical scale. */
881
+ declare const elevationScale: _hello_terrain_work.ParamRef<number>;
882
+ /** Sphere radius in world units (cube-sphere projection only). */
883
+ declare const radius: _hello_terrain_work.ParamRef<number>;
884
+ /** Maximum quadtree nodes. */
885
+ declare const maxNodes: _hello_terrain_work.ParamRef<number>;
886
+ /** Maximum quadtree subdivision level. */
887
+ declare const maxLevel: _hello_terrain_work.ParamRef<number>;
888
+ /** Quadtree update configuration (camera, mode, etc.). */
889
+ declare const quadtreeUpdate: _hello_terrain_work.ParamRef<UpdateParams>;
890
+ /** Optional custom terrain topology; defaults to bounded flat topology when null. */
891
+ declare const topology: _hello_terrain_work.ParamRef<Topology | null>;
892
+ /** Terrain field texture filter mode. */
893
+ declare const terrainFieldFilter: _hello_terrain_work.ParamRef<"nearest" | "linear">;
894
+ /** Terrain elevation control function (per vertex, in gpu compute) */
895
+ declare const elevationFn: _hello_terrain_work.ParamRef<ElevationCallback>;
896
+
897
+ /**
898
+ * Builds the TSL position node for the terrain shader.
899
+ *
900
+ * Depends on leafStorageTask (buffer objects), updateUniformsTask
901
+ * (uniform nodes), and createTerrainFieldTextureTask (combined terrain field storage).
902
+ *
903
+ * The position node reads packed terrain samples (height + normal.xz)
904
+ * per-vertex and assigns them to the vNormal
905
+ * varying for use in the fragment shader.
906
+ *
907
+ * These only change when their GPU resources are recreated
908
+ * (e.g. buffer resize), so this task stays cached during normal quadtree
909
+ * updates — no unnecessary shader rebuilds.
910
+ */
911
+ declare const positionNodeTask: _hello_terrain_work.Task<three_src_nodes_TSL_js.ShaderCallNodeInternal, string, unknown>;
912
+
913
+ /**
914
+ * Derives the terrain topology from `rootSize` and `origin`.
915
+ * Automatically recomputes when either param changes, keeping the
916
+ * quadtree refinement in sync with the GPU-side tile positioning.
917
+ */
918
+ declare const topologyTask: _hello_terrain_work.Task<Topology, string, unknown>;
919
+ declare const quadtreeConfigTask: _hello_terrain_work.Task<QuadtreeConfigState, string, unknown>;
920
+ declare const quadtreeUpdateTask: _hello_terrain_work.Task<LeafSet, string, unknown>;
921
+ /**
922
+ * Creates the GPU storage buffer objects. Recreated when maxNodes changes.
923
+ *
924
+ * positionNodeTask depends on this (not leafGpuBufferTask) so
925
+ * the shader is only rebuilt when the buffer is resized, not on every
926
+ * quadtree update.
927
+ */
928
+ declare const leafStorageTask: _hello_terrain_work.Task<LeafStorageState, string, unknown>;
929
+ declare const leafGpuBufferTask: _hello_terrain_work.Task<{
930
+ count: number;
931
+ data: Int32Array<ArrayBuffer>;
932
+ attribute: three_webgpu.StorageBufferAttribute;
933
+ node: three_webgpu.StorageBufferNode;
934
+ }, string, unknown>;
935
+
936
+ declare function createTerrainUniforms(params: TerrainUniformsParams): TerrainUniformsContext;
937
+
938
+ /**
939
+ * Creates the terrain uniform nodes once. Downstream tasks capture
940
+ * references to these nodes in shader graphs, so the same instances
941
+ * must persist across runs.
942
+ */
943
+ declare const createUniformsTask: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
944
+ /**
945
+ * Updates the terrain uniform values each run. Reads the persisted uniform
946
+ * nodes from createUniformsTask and writes the latest param values.
947
+ */
948
+ declare const updateUniformsTask: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
949
+
950
+ /** All terrain task refs for direct access. */
951
+ declare const terrainTasks: {
952
+ readonly instanceId: _hello_terrain_work.Task<`${string}-${string}-${string}-${string}-${string}`, string, unknown>;
953
+ readonly quadtreeConfig: _hello_terrain_work.Task<QuadtreeConfigState, string, unknown>;
954
+ readonly quadtreeUpdate: _hello_terrain_work.Task<LeafSet, string, unknown>;
955
+ readonly leafStorage: _hello_terrain_work.Task<LeafStorageState, string, unknown>;
956
+ readonly topology: _hello_terrain_work.Task<Topology, string, unknown>;
957
+ readonly leafGpuBuffer: _hello_terrain_work.Task<{
958
+ count: number;
959
+ data: Int32Array<ArrayBuffer>;
960
+ attribute: three_webgpu.StorageBufferAttribute;
961
+ node: three_webgpu.StorageBufferNode;
962
+ }, string, unknown>;
963
+ readonly gpuSpatialIndexStorage: _hello_terrain_work.Task<GpuSpatialIndexContext, string, unknown>;
964
+ readonly gpuSpatialIndexUpload: _hello_terrain_work.Task<GpuSpatialIndexContext, string, unknown>;
965
+ readonly createUniforms: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
966
+ readonly updateUniforms: _hello_terrain_work.Task<TerrainUniformsContext, string, unknown>;
967
+ readonly positionNode: _hello_terrain_work.Task<three_src_nodes_TSL_js.ShaderCallNodeInternal, string, unknown>;
968
+ readonly createElevationFieldContext: _hello_terrain_work.Task<{
969
+ data: Float32Array<ArrayBuffer>;
970
+ attribute: three_webgpu.StorageBufferAttribute;
971
+ node: three_webgpu.StorageBufferNode;
972
+ }, string, unknown>;
973
+ readonly createTileNodes: _hello_terrain_work.Task<{
974
+ tileLevel: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
975
+ tileFace: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
976
+ tileOriginVec2: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
977
+ tileSize: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node]>;
978
+ tileFaceUV: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
979
+ rootUVCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
980
+ tileVertexWorldPositionCompute: three_src_nodes_TSL_js.ShaderNodeFn<[number | three_webgpu.Node, number | three_webgpu.Node, number | three_webgpu.Node]>;
981
+ }, string, unknown>;
982
+ readonly createTerrainFieldTexture: _hello_terrain_work.Task<any, string, {
983
+ renderer: WebGPURenderer;
984
+ }>;
985
+ readonly createTerrainSampler: _hello_terrain_work.Task<TerrainSampler, string, unknown>;
986
+ readonly elevationFieldStage: _hello_terrain_work.Task<ComputePipeline, string, unknown>;
987
+ readonly terrainFieldStage: _hello_terrain_work.Task<ComputePipeline, string, unknown>;
988
+ readonly compileCompute: _hello_terrain_work.Task<{
989
+ execute: (renderer: WebGPURenderer, instanceCount: number) => void;
990
+ }, string, unknown>;
991
+ readonly executeCompute: _hello_terrain_work.Task<any, string, {
992
+ renderer: WebGPURenderer;
993
+ }>;
994
+ readonly tileBoundsContext: _hello_terrain_work.Task<TileBoundsContext & {
995
+ kernel: ReturnType<(elevationFieldNode: three_webgpu.StorageBufferNode, boundsNode: three_webgpu.StorageBufferNode, verticesPerNode: number) => three_webgpu.ComputeNode>;
996
+ }, string, unknown>;
997
+ readonly tileBoundsReduction: _hello_terrain_work.Task<any, string, {
998
+ renderer: WebGPURenderer;
999
+ }>;
1000
+ readonly terrainQuery: _hello_terrain_work.Task<TerrainQueryContext, string, unknown>;
1001
+ readonly terrainReadback: _hello_terrain_work.Task<any, string, {
1002
+ renderer: WebGPURenderer;
1003
+ }>;
1004
+ readonly terrainRaycast: _hello_terrain_work.Task<TerrainRaycast, string, unknown>;
1005
+ };
1006
+ declare function terrainGraph(): TerrainGraph;
1007
+
1008
+ type ComputeDeviceLimits = {
1009
+ maxWorkgroupSizeX: number;
1010
+ maxWorkgroupSizeY: number;
1011
+ maxWorkgroupInvocations: number;
1012
+ };
1013
+ declare function getDeviceComputeLimits(renderer: WebGPURenderer): ComputeDeviceLimits;
1014
+
1015
+ declare function createTerrainSampler(params: CreateTerrainSamplerParams): TerrainSampler;
1016
+
1017
+ /** Flat (heightfield) query, keyed on world XZ. */
1018
+ declare function createTerrainQuery(cache: CpuTerrainCache): TerrainQuery;
1019
+ /** Cube-sphere query, keyed on a direction / position / lat-long. */
1020
+ declare function createTerrainSphereQuery(cache: CpuTerrainCache): TerrainSphereQuery;
1021
+
1022
+ type CpuRaycastConfig = {
1023
+ rootSize: number;
1024
+ originX: number;
1025
+ originZ: number;
1026
+ minY: number;
1027
+ maxY: number;
1028
+ /** Topology projection; `cubeSphere` selects the radial sphere raycast. */
1029
+ projection?: TopologyProjection;
1030
+ /** Planet center (cube-sphere only). */
1031
+ centerX?: number;
1032
+ centerY?: number;
1033
+ centerZ?: number;
1034
+ /** Base sphere radius (cube-sphere only). */
1035
+ radius?: number;
1036
+ /** Inner/outer radial bounds of the terrain shell (cube-sphere only). */
1037
+ minRadius?: number;
1038
+ maxRadius?: number;
1039
+ };
1040
+
1041
+ type TerrainRaycastConfig = CpuRaycastConfig;
1042
+ declare function createTerrainRaycast(params: {
1043
+ getTerrainQuery: () => TerrainQuery | null;
1044
+ getSphereQuery: () => TerrainSphereQuery | null;
1045
+ getConfig: () => TerrainRaycastConfig;
1046
+ }): TerrainRaycast;
1047
+
1048
+ type CubeFaceBasis = {
1049
+ forward: Node;
1050
+ right: Node;
1051
+ up: Node;
1052
+ };
1053
+ /** Per-face basis vectors selected by the dynamic face index. */
1054
+ declare function cubeFaceBasis(face: Node): CubeFaceBasis;
1055
+ /**
1056
+ * Cube-space point for face-local (u, v) in [0, 1]:
1057
+ * cube = forward + (2u-1) * right + (2v-1) * up
1058
+ */
1059
+ declare function cubeFacePoint(basis: CubeFaceBasis, u: Node, v: Node): Node;
1060
+ /** Unit-sphere direction for face-local (u, v). */
1061
+ declare function cubeFaceDirection(basis: CubeFaceBasis, u: Node, v: Node): Node;
1062
+ /**
1063
+ * Project a basis axis onto the tangent plane at `dir` and normalize.
1064
+ * Used to build the sphere tangent frame for normal reconstruction.
1065
+ */
1066
+ declare function tangentFromAxis(dir: Node, axis: Node): Node;
1067
+ /**
1068
+ * Reconstruct a unit tangent-space normal from its packed horizontal
1069
+ * components: `ny = sqrt(max(0, 1 - nx² - nz²))`.
1070
+ */
1071
+ declare function unpackTangentNormal(nx: Node, nz: Node): Node;
1072
+ /**
1073
+ * Rotate a tangent-space normal into the sphere tangent frame
1074
+ * `(tu, dir, tv)` at `dir` and normalize.
1075
+ *
1076
+ * Mirrors: the CPU `computeSphereNormal` in `query/cpu-terrain-cache.ts`.
1077
+ */
1078
+ declare function sphereTangentFrameNormal(dir: Node, basis: CubeFaceBasis, tangentNormal: Node): Node;
1079
+ /**
1080
+ * Pick the cube face index (0..5) whose normal axis dominates `dir`.
1081
+ * GPU mirror of `directionToFace` in `quadtree/topology/cubeSphereInverse.ts`.
1082
+ */
1083
+ declare function cubeFaceFromDirection(dir: Node): Node;
1084
+ /**
1085
+ * Face-local (u, v) in [0, 1] for a direction known to fall on `face`.
1086
+ * GPU mirror of `directionToFaceUV` in `quadtree/topology/cubeSphereInverse.ts`.
1087
+ */
1088
+ declare function cubeFaceUVFromDirection(basis: CubeFaceBasis, dir: Node): Node;
1089
+
1090
+ /**
1091
+ * Maps a value or node from texture space [0, 1] to vector space [-1, 1].
1092
+ *
1093
+ * @param value - The node or value in the range [0, 1].
1094
+ * @returns A node mapping the input value to the range [-1, 1].
1095
+ */
1096
+ declare const textureSpaceToVectorSpace: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node$1]>;
1097
+ /**
1098
+ * Maps a value or node from vector space [-1, 1] to texture space [0, 1].
1099
+ *
1100
+ * @param value - The node or value in the range [-1, 1].
1101
+ * @returns A node mapping the input value to the range [0, 1].
1102
+ */
1103
+ declare const vectorSpaceToTextureSpace: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node$1]>;
1104
+ /**
1105
+ * Blends two normal maps using the Reoriented Normal Mapping technique.
1106
+ * This is the same algorithm used by Unreal Engine's BlendAngleCorrectedNormals node.
1107
+ *
1108
+ * Both inputs should be in vector space [-1, 1].
1109
+ *
1110
+ * @see https://blog.selfshadow.com/publications/blending-in-detail/
1111
+ */
1112
+ declare const blendAngleCorrectedNormals: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node$1, number | Node$1]>;
1113
+ /**
1114
+ * Reconstructs the Z component of a normal from the X and Y components.
1115
+ *
1116
+ * @param normalXY - A vec2 containing the X and Y components of the normal
1117
+ * @returns A vec3 with the reconstructed normal (X, Y, derived Z)
1118
+ */
1119
+ declare const deriveNormalZ: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node$1]>;
1120
+
1121
+ /**
1122
+ * Input type for segment count: either a JS number or a TSL integer node.
1123
+ * When a number is provided, it's automatically converted to an int node.
1124
+ * When a Node is provided, it should resolve to an integer value.
1125
+ */
1126
+ type IntNodeInput = number | ConstNode<number> | Node;
91
1127
  /**
92
1128
  * Returns a node that is true for skirt vertices in the vertex stage.
93
1129
  *
@@ -113,4 +1149,15 @@ declare const isSkirtVertex: three_src_nodes_TSL_js.ShaderNodeFn<[segments: numb
113
1149
  */
114
1150
  declare const isSkirtUV: three_src_nodes_TSL_js.ShaderNodeFn<[segments: number | Node]>;
115
1151
 
116
- export { TerrainGeometry, isSkirtUV, isSkirtVertex };
1152
+ declare const vGlobalVertexIndex: three_webgpu.PropertyNode;
1153
+ declare const vElevation: three_webgpu.PropertyNode;
1154
+
1155
+ declare const voronoiCells: three_src_nodes_TSL_js.ShaderNodeFn<[three_tsl.ProxiedObject<{
1156
+ scale: number;
1157
+ facet: number;
1158
+ seed: number;
1159
+ uv: Node;
1160
+ }>]>;
1161
+
1162
+ export { ArrayTextureBackend, AtlasBackend, CUBE_FACES, CUBE_FACE_COUNT, Dir, TerrainGeometry, TerrainMesh, U32_EMPTY, allocLeafSet, allocSeamTable, beginUpdate, blendAngleCorrectedNormals, buildLeafIndex, buildSeams2to1, compileComputeTask, createComputePipelineTasks, createCubeSphereTopology, createElevationFieldContextTask, createFlatTopology, createInfiniteFlatTopology, createSpatialIndex, createState, createTerrainFieldStorage, createTerrainFieldTextureTask, createTerrainQuery, createTerrainRaycast, createTerrainSampler, createTerrainSamplerTask, createTerrainSphereQuery, createTerrainUniforms, createUniformsTask, cubeFaceBasis, cubeFaceDirection, cubeFaceFromDirection, cubeFacePoint, cubeFaceUVFromDirection, deriveNormalZ, directionToFace, directionToFaceUV, directionToLatLong, elevationFieldStageTask, elevationFn, elevationScale, executeComputeTask, faceUVToCube, getDeviceComputeLimits, gpuSpatialIndexStorageTask, gpuSpatialIndexUploadTask, innerTileSegments, instanceIdTask, isSkirtUV, isSkirtVertex, latLongToDirection, leafGpuBufferTask, leafStorageTask, loadTerrainField, loadTerrainFieldElevation, loadTerrainFieldNormal, maxLevel, maxNodes, origin, packTerrainFieldSample, positionNodeTask, quadtreeConfigTask, quadtreeUpdate, quadtreeUpdateTask, radius, resetLeafSet, resetSeamTable, rootSize, sampleTerrainField, sampleTerrainFieldElevation, skirtScale, sphereTangentFrameNormal, storeTerrainField, tangentFromAxis, terrainFieldFilter, terrainFieldStageTask, terrainGraph, terrainQueryTask, terrainRaycastTask, terrainReadbackTask, terrainTasks, textureSpaceToVectorSpace, tileNodesTask, topology, topologyTask, unpackTangentNormal, update, updateUniformsTask, vElevation, vGlobalVertexIndex, vectorSpaceToTextureSpace, voronoiCells };
1163
+ export type { ComputePipeline, ComputeStageCallback, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodMode, QuadtreeConfig, QuadtreeConfigState, QuadtreeState, RaycastOptions, SeamTable, SpatialIndex, TerrainFieldStorage, TerrainFieldStorageBackendType, TerrainFieldStorageFormat, TerrainFieldStorageOptions, TerrainGraph, TerrainQuery, TerrainQueryContext, TerrainRaycast, TerrainRaycastConfig, TerrainRaycastResult, TerrainSample, TerrainSampleBatch, TerrainSampler, TerrainSphereQuery, TerrainSurfaceSample, TerrainSurfaceSampleBatch, TerrainTasks, TerrainTile, TerrainTileBounds, TerrainUniformsContext, TerrainUniformsParams, TileBounds, TileId, Topology, TopologyProjection, UpdateParams, Vec3, Vec3Mutable };