@hello-terrain/three 0.0.0-alpha.13 → 0.0.0-alpha.14

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,6 +1,6 @@
1
- import { BufferGeometry, Vector3 as Vector3$1, Ray, Raycaster, Intersection } from 'three';
1
+ import { BufferGeometry, Vector3 as Vector3$1, Ray, Raycaster, Intersection, Texture } from 'three';
2
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';
3
+ import { StorageArrayTexture, StorageTexture, Node, WebGPURenderer, StorageBufferNode, StorageBufferAttribute, UniformNode, Vector3, Vector3Like, InstancedMesh, NodeMaterial, ConstNode } from 'three/webgpu';
4
4
  import Node$1 from 'three/src/nodes/core/Node.js';
5
5
  import * as _hello_terrain_work from '@hello-terrain/work';
6
6
  import { TaskRef, Graph } from '@hello-terrain/work';
@@ -105,6 +105,14 @@ declare class TerrainGeometry extends BufferGeometry {
105
105
 
106
106
  type TerrainFieldStorageBackendType = "array-texture" | "atlas" | "texture-3d";
107
107
  type TerrainFieldStorageFormat = "rgba16float" | "rgba32float";
108
+ /** Floats stored per tile in the tile bounds GPU buffer. */
109
+ declare const TILE_BOUNDS_FLOATS_PER_TILE = 4;
110
+ declare const TILE_BOUNDS_LOD_MIN_OFFSET = 0;
111
+ declare const TILE_BOUNDS_LOD_MAX_OFFSET = 1;
112
+ declare const TILE_BOUNDS_PACK_MIN_OFFSET = 2;
113
+ declare const TILE_BOUNDS_PACK_MAX_OFFSET = 3;
114
+ /** Minimum elevation span (meters) when normalizing flat tiles. */
115
+ declare const TERRAIN_FIELD_PACK_EPSILON = 0.0001;
108
116
  type TerrainFieldStorageOptions = {
109
117
  backend?: TerrainFieldStorageBackendType;
110
118
  filter?: "nearest" | "linear";
@@ -142,6 +150,14 @@ declare function sampleTerrainFieldElevation(storage: TerrainFieldStorage, u: No
142
150
  * normal through their own parametric tangent frame.
143
151
  */
144
152
  declare function packTerrainFieldSample(height: Node, normal: Node): Node;
153
+ declare function loadTilePackBounds(boundsNode: StorageBufferNode, tileIndex: Node): {
154
+ packMin: three_webgpu.StorageArrayElementNode;
155
+ packMax: three_webgpu.StorageArrayElementNode;
156
+ };
157
+ /** Normalize elevation into [0, 1] for rgba16float terrain-field storage. */
158
+ declare function packNormalizedTerrainFieldSample(height: Node, normal: Node, packMin: Node, packMax: Node): Node;
159
+ /** Restore absolute elevation (meters) from a normalized terrain-field sample. */
160
+ declare function denormalizeTerrainFieldElevation(normalized: Node, packMin: Node, packMax: Node): Node;
145
161
 
146
162
  interface TerrainUniformsParams {
147
163
  rootSize: number;
@@ -329,23 +345,6 @@ type QuadtreeConfig = {
329
345
  maxLevel: number;
330
346
  };
331
347
 
332
- type NodeStore = {
333
- maxNodes: number;
334
- nodesUsed: number;
335
- /** generation stamping to avoid clearing buffers */
336
- currentGen: number;
337
- gen: Uint16Array;
338
- space: Uint8Array;
339
- level: Uint8Array;
340
- x: Int32Array;
341
- y: Int32Array;
342
- /** sentinel U32_EMPTY means no children; otherwise children are [firstChild..firstChild+3] */
343
- firstChild: Uint32Array;
344
- flags: Uint8Array;
345
- /** root node id per space */
346
- roots: Uint32Array;
347
- };
348
-
349
348
  type SpatialIndex = {
350
349
  size: number;
351
350
  mask: number;
@@ -359,222 +358,6 @@ type SpatialIndex = {
359
358
  };
360
359
  declare function createSpatialIndex(maxEntries: number): SpatialIndex;
361
360
 
362
- /**
363
- * Build a spatial index for the current LeafSet.
364
- * Maps (space, level, x, y) -> leafIndex.
365
- *
366
- * Allocation-free if `out` is provided.
367
- */
368
- declare function buildLeafIndex(leaves: LeafSet, out?: SpatialIndex): SpatialIndex;
369
-
370
- type QuadtreeState = {
371
- cfg: QuadtreeConfig;
372
- store: NodeStore;
373
- /** default reusable leaf buffers (capacity = cfg.maxNodes) */
374
- leaves: LeafSet;
375
- /** internal: node id per leaf entry (parallel to leaves.* arrays) */
376
- leafNodeIds: Uint32Array;
377
- /** reusable leaf spatial index (capacity = cfg.maxNodes) */
378
- leafIndex: SpatialIndex;
379
- /** traversal scratch */
380
- stack: Uint32Array;
381
- /** root nodes for this frame */
382
- rootNodeIds: Uint32Array;
383
- rootCount: number;
384
- /** split scheduling scratch (dedupe without allocations) */
385
- splitQueue: Uint32Array;
386
- splitStamp: Uint16Array;
387
- splitGen: number;
388
- /** scratch objects to avoid allocations */
389
- scratchTile: TileId;
390
- scratchNeighbor: TileId;
391
- scratchBounds: TileBounds;
392
- scratchElevationRange: ElevationRangeOut;
393
- scratchRootTiles: TileId[];
394
- /** topology space count is fixed for a given state */
395
- spaceCount: number;
396
- };
397
- declare function createState(cfg: QuadtreeConfig, topology: Topology): QuadtreeState;
398
- declare function beginUpdate(state: QuadtreeState, topology: Topology, params: UpdateParams): void;
399
-
400
- /**
401
- * Update the quadtree for the given topology + camera parameters.
402
- *
403
- * Produces a LeafSet of TileIds (SoA typed arrays).
404
- */
405
- declare function update(state: QuadtreeState, topology: Topology, params: UpdateParams, outLeaves?: LeafSet): LeafSet;
406
-
407
- /**
408
- * Build a fixed-width seam/neighbor table for balanced leaves (2:1).
409
- *
410
- * Output neighbors are leaf-list indices, with U32_EMPTY for missing entries.
411
- * Layout: neighbors[leafIndex * 8 + edge*2 + slot].
412
- */
413
- declare function buildSeams2to1(topology: Topology, leaves: LeafSet, outSeams: SeamTable, outIndex?: SpatialIndex): SeamTable;
414
-
415
- type FlatTopologyConfig = {
416
- /**
417
- * World-space size of the root tile edge.
418
- * The root tile covers [-rootSize/2, +rootSize/2] around origin in X/Z.
419
- */
420
- rootSize: number;
421
- origin: {
422
- x: number;
423
- y: number;
424
- z: number;
425
- };
426
- };
427
- declare function createFlatTopology(cfg: FlatTopologyConfig): Topology;
428
-
429
- type InfiniteFlatTopologyConfig = {
430
- rootSize: number;
431
- origin: {
432
- x: number;
433
- y: number;
434
- z: number;
435
- };
436
- /** half-width of root grid in root tiles (1 => 3x3 roots) */
437
- rootGridRadius?: number;
438
- };
439
- declare function createInfiniteFlatTopology(cfg: InfiniteFlatTopologyConfig): Topology;
440
-
441
- type CubeSphereTopologyConfig = {
442
- /** Sphere radius in world units. */
443
- radius: number;
444
- /** Planet center in world space (defaults to origin). */
445
- center?: {
446
- x: number;
447
- y: number;
448
- z: number;
449
- };
450
- /** When true, elevation displaces inward and skirts point outward. */
451
- invert?: boolean;
452
- };
453
- /**
454
- * Cube-sphere topology: six quadtree faces wrapped onto a sphere.
455
- *
456
- * Topology (`neighborSameLevel`) is derived numerically from the shared
457
- * `CUBE_FACES` basis so cross-face edges (including rotated pole edges)
458
- * resolve to the correct neighbor tile without hand-coded transforms.
459
- */
460
- declare function createCubeSphereTopology(cfg: CubeSphereTopologyConfig): Topology;
461
-
462
- /**
463
- * Canonical cube-sphere face basis.
464
- *
465
- * Shared single source of truth between the CPU surface topology
466
- * (`cubeSphere.ts`) and the GPU position/normal assembly (`tsl/cubeSphere.ts`)
467
- * so both agree on geometry and faces seam correctly.
468
- *
469
- * Each face maps a face-local coordinate (u, v) in [0, 1] to a point on the
470
- * cube `[-1, 1]^3` via:
471
- *
472
- * s = 2u - 1, t = 2v - 1
473
- * cube = forward + s * right + t * up
474
- *
475
- * Normalizing `cube` yields the unit-sphere direction for that vertex.
476
- *
477
- * Bases are right-handed (`forward = right x up`) and outward-facing.
478
- * Space indices: 0:+X 1:-X 2:+Y 3:-Y 4:+Z 5:-Z.
479
- */
480
- type Vec3 = readonly [number, number, number];
481
- type CubeFace = {
482
- forward: Vec3;
483
- right: Vec3;
484
- up: Vec3;
485
- };
486
- declare const CUBE_FACE_COUNT = 6;
487
- declare const CUBE_FACES: readonly CubeFace[];
488
-
489
- type Vec3Mutable$1 = [number, number, number];
490
- /**
491
- * Cube-space point for a face-local coordinate (u, v) in [0, 1]:
492
- * cube = forward + (2u-1) * right + (2v-1) * up
493
- * The result is unnormalized; normalize it to obtain the sphere direction.
494
- */
495
- declare function faceUVToCube(face: number, u: number, v: number, out: Vec3Mutable$1): void;
496
- /** Pick the cube face whose normal axis dominates the direction. */
497
- declare function directionToFace(d: Vec3): number;
498
- /** Face-local (u, v) in [0, 1] for a direction known to fall on `face`. */
499
- declare function directionToFaceUV(face: number, d: Vec3, out: [number, number]): void;
500
- /**
501
- * Convert latitude/longitude (degrees) to a unit sphere direction.
502
- *
503
- * Convention matches `CUBE_FACES` (+Y is the north pole):
504
- * - latitude is the angle above the equator, in `[-90, 90]`
505
- * - longitude is the angle around the +Y axis, in `[-180, 180]`,
506
- * measured from +Z toward +X (lon = 0 points along +Z).
507
- */
508
- declare function latLongToDirection(latDeg: number, lonDeg: number, out: Vec3Mutable$1): void;
509
- /** Inverse of {@link latLongToDirection}; returns degrees. */
510
- declare function directionToLatLong(d: Vec3): {
511
- latitude: number;
512
- longitude: number;
513
- };
514
-
515
- type TorusTopologyConfig = {
516
- /** Distance from the torus center to the tube center (the donut radius). */
517
- majorRadius: number;
518
- /** Radius of the tube cross-section. */
519
- minorRadius: number;
520
- /** Torus center in world space (defaults to origin). */
521
- center?: {
522
- x: number;
523
- y: number;
524
- z: number;
525
- };
526
- /** When true, elevation displaces inward and skirts point outward. */
527
- invert?: boolean;
528
- };
529
- /**
530
- * Torus (donut) topology: a single quadtree space whose `(u, v)` axes wrap
531
- * around the major circle and the tube cross-section. Both axes are periodic,
532
- * so every same-level neighbor exists (wrapping modulo the level resolution).
533
- *
534
- * Level-0 resolution is anisotropic: `baseU = round(major/minor)` tiles along
535
- * `u` and `baseV = 1` along `v`, so root tiles are approximately square in
536
- * world space before isotropic LOD subdivision.
537
- */
538
- declare function createTorusTopology(cfg: TorusTopologyConfig): Topology;
539
-
540
- type Vec3Mutable = [number, number, number];
541
- /** Wrap a value into [0, 1). */
542
- declare function wrap01(t: number): number;
543
- /**
544
- * Torus surface point for parameters (u, v) in [0, 1].
545
- *
546
- * Convention (matches `latLongToDirection`'s longitude axis):
547
- * - `theta = 2*pi*u` sweeps around the +Y axis, measured from +Z toward +X.
548
- * - `phi = 2*pi*v` sweeps around the tube cross-section, `phi = 0` pointing
549
- * radially outward in the XZ plane and `phi = pi/2` pointing toward +Y.
550
- *
551
- * `displacement` is the elevation added to the tube (minor) radius.
552
- */
553
- declare function torusUVToPoint(u: number, v: number, majorRadius: number, minorRadius: number, displacement: number, center: {
554
- x: number;
555
- y: number;
556
- z: number;
557
- }, out: Vec3Mutable, invert?: boolean): void;
558
- /** Outward unit surface normal of the base (undisplaced) torus at (u, v). */
559
- declare function torusOutwardNormal(u: number, v: number, out: Vec3Mutable, invert?: boolean): void;
560
- type TorusSurfaceParams = {
561
- /** Wrapped major-circle parameter in [0, 1). */
562
- u: number;
563
- /** Wrapped tube parameter in [0, 1). */
564
- v: number;
565
- /** Distance from the point to the tube center circle. */
566
- tubeDistance: number;
567
- };
568
- /**
569
- * Map a world point to torus surface parameters. `tubeDistance - minorRadius`
570
- * is the signed radial displacement of the point relative to the base torus.
571
- */
572
- declare function positionToTorusParams(px: number, py: number, pz: number, majorRadius: number, center: {
573
- x: number;
574
- y: number;
575
- z: number;
576
- }, out: TorusSurfaceParams): void;
577
-
578
361
  type TerrainQueryConfig = {
579
362
  rootSize: number;
580
363
  originX: number;
@@ -651,6 +434,7 @@ interface RenderVertexPositionContext {
651
434
  leafStorage: LeafStorageState;
652
435
  uniforms: TerrainUniformsContext;
653
436
  terrainFieldStorage?: TerrainFieldStorage;
437
+ tileBoundsNode?: StorageBufferNode;
654
438
  }
655
439
  interface FieldNormalContext {
656
440
  elevationFieldNode: Node;
@@ -794,6 +578,7 @@ interface TerrainSampler {
794
578
  }
795
579
  interface CreateTerrainSamplerParams {
796
580
  terrainFieldStorage: TerrainFieldStorage;
581
+ tileBoundsNode: StorageBufferNode;
797
582
  spatialIndex: GpuSpatialIndexContext;
798
583
  uniforms: TerrainUniformsContext;
799
584
  elevationCallback: ElevationCallback;
@@ -965,6 +750,13 @@ interface TileBoundsContext {
965
750
  attribute: StorageBufferAttribute;
966
751
  node: StorageBufferNode;
967
752
  }
753
+ declare function buildReductionKernel(elevationFieldNode: StorageBufferNode, boundsNode: StorageBufferNode, verticesPerNode: number, edgeVertexCount: number): three_webgpu.ComputeNode;
754
+ declare function runTileBoundsReduction(renderer: WebGPURenderer, boundsContext: TileBoundsContext & {
755
+ kernel: ReturnType<typeof buildReductionKernel>;
756
+ }, leafCount: number): void;
757
+ declare const tileBoundsContextTask: _hello_terrain_work.Task<TileBoundsContext & {
758
+ kernel: ReturnType<typeof buildReductionKernel>;
759
+ }, string, unknown>;
968
760
 
969
761
  type ComputeStageCallback = (nodeIndex: Node, globalVertexIndex: Node, uv: Node, localCoordinates: Node, texelSize: Node) => void;
970
762
  type ComputePipeline = ComputeStageCallback[];
@@ -986,6 +778,10 @@ declare const executeComputeTask: _hello_terrain_work.Task<any, string, {
986
778
  * the accumulation pattern (`get()` predecessor, spread, append), then pass
987
779
  * their leaf stage to this helper to get compile + execute tasks.
988
780
  *
781
+ * When the pipeline has multiple stages, elevation (and any custom upstream
782
+ * stages) run first, tile bounds are reduced, then the final stage (typically
783
+ * terrain-field pack) runs. Keep terrain-field pack as the last stage.
784
+ *
989
785
  * @example
990
786
  * ```ts
991
787
  * const erosionStageTask = task((get, work) => {
@@ -1009,6 +805,243 @@ declare function createComputePipelineTasks(leafStageTask: TaskRef<ComputePipeli
1009
805
  renderer: WebGPURenderer;
1010
806
  }>;
1011
807
  };
808
+ /** Bounds are reduced mid-pipeline inside {@link executeComputeTask}. */
809
+ declare const tileBoundsReductionTask: _hello_terrain_work.Task<any, string, {
810
+ renderer: WebGPURenderer;
811
+ }>;
812
+
813
+ type NodeStore = {
814
+ maxNodes: number;
815
+ nodesUsed: number;
816
+ /** generation stamping to avoid clearing buffers */
817
+ currentGen: number;
818
+ gen: Uint16Array;
819
+ space: Uint8Array;
820
+ level: Uint8Array;
821
+ x: Int32Array;
822
+ y: Int32Array;
823
+ /** sentinel U32_EMPTY means no children; otherwise children are [firstChild..firstChild+3] */
824
+ firstChild: Uint32Array;
825
+ flags: Uint8Array;
826
+ /** root node id per space */
827
+ roots: Uint32Array;
828
+ };
829
+
830
+ /**
831
+ * Build a spatial index for the current LeafSet.
832
+ * Maps (space, level, x, y) -> leafIndex.
833
+ *
834
+ * Allocation-free if `out` is provided.
835
+ */
836
+ declare function buildLeafIndex(leaves: LeafSet, out?: SpatialIndex): SpatialIndex;
837
+
838
+ type QuadtreeState = {
839
+ cfg: QuadtreeConfig;
840
+ store: NodeStore;
841
+ /** default reusable leaf buffers (capacity = cfg.maxNodes) */
842
+ leaves: LeafSet;
843
+ /** internal: node id per leaf entry (parallel to leaves.* arrays) */
844
+ leafNodeIds: Uint32Array;
845
+ /** reusable leaf spatial index (capacity = cfg.maxNodes) */
846
+ leafIndex: SpatialIndex;
847
+ /** traversal scratch */
848
+ stack: Uint32Array;
849
+ /** root nodes for this frame */
850
+ rootNodeIds: Uint32Array;
851
+ rootCount: number;
852
+ /** split scheduling scratch (dedupe without allocations) */
853
+ splitQueue: Uint32Array;
854
+ splitStamp: Uint16Array;
855
+ splitGen: number;
856
+ /** scratch objects to avoid allocations */
857
+ scratchTile: TileId;
858
+ scratchNeighbor: TileId;
859
+ scratchBounds: TileBounds;
860
+ scratchElevationRange: ElevationRangeOut;
861
+ scratchRootTiles: TileId[];
862
+ /** topology space count is fixed for a given state */
863
+ spaceCount: number;
864
+ };
865
+ declare function createState(cfg: QuadtreeConfig, topology: Topology): QuadtreeState;
866
+ declare function beginUpdate(state: QuadtreeState, topology: Topology, params: UpdateParams): void;
867
+
868
+ /**
869
+ * Update the quadtree for the given topology + camera parameters.
870
+ *
871
+ * Produces a LeafSet of TileIds (SoA typed arrays).
872
+ */
873
+ declare function update(state: QuadtreeState, topology: Topology, params: UpdateParams, outLeaves?: LeafSet): LeafSet;
874
+
875
+ /**
876
+ * Build a fixed-width seam/neighbor table for balanced leaves (2:1).
877
+ *
878
+ * Output neighbors are leaf-list indices, with U32_EMPTY for missing entries.
879
+ * Layout: neighbors[leafIndex * 8 + edge*2 + slot].
880
+ */
881
+ declare function buildSeams2to1(topology: Topology, leaves: LeafSet, outSeams: SeamTable, outIndex?: SpatialIndex): SeamTable;
882
+
883
+ type FlatTopologyConfig = {
884
+ /**
885
+ * World-space size of the root tile edge.
886
+ * The root tile covers [-rootSize/2, +rootSize/2] around origin in X/Z.
887
+ */
888
+ rootSize: number;
889
+ origin: {
890
+ x: number;
891
+ y: number;
892
+ z: number;
893
+ };
894
+ };
895
+ declare function createFlatTopology(cfg: FlatTopologyConfig): Topology;
896
+
897
+ type InfiniteFlatTopologyConfig = {
898
+ rootSize: number;
899
+ origin: {
900
+ x: number;
901
+ y: number;
902
+ z: number;
903
+ };
904
+ /** half-width of root grid in root tiles (1 => 3x3 roots) */
905
+ rootGridRadius?: number;
906
+ };
907
+ declare function createInfiniteFlatTopology(cfg: InfiniteFlatTopologyConfig): Topology;
908
+
909
+ type CubeSphereTopologyConfig = {
910
+ /** Sphere radius in world units. */
911
+ radius: number;
912
+ /** Planet center in world space (defaults to origin). */
913
+ center?: {
914
+ x: number;
915
+ y: number;
916
+ z: number;
917
+ };
918
+ /** When true, elevation displaces inward and skirts point outward. */
919
+ invert?: boolean;
920
+ };
921
+ /**
922
+ * Cube-sphere topology: six quadtree faces wrapped onto a sphere.
923
+ *
924
+ * Topology (`neighborSameLevel`) is derived numerically from the shared
925
+ * `CUBE_FACES` basis so cross-face edges (including rotated pole edges)
926
+ * resolve to the correct neighbor tile without hand-coded transforms.
927
+ */
928
+ declare function createCubeSphereTopology(cfg: CubeSphereTopologyConfig): Topology;
929
+
930
+ /**
931
+ * Canonical cube-sphere face basis.
932
+ *
933
+ * Shared single source of truth between the CPU surface topology
934
+ * (`cubeSphere.ts`) and the GPU position/normal assembly (`tsl/cubeSphere.ts`)
935
+ * so both agree on geometry and faces seam correctly.
936
+ *
937
+ * Each face maps a face-local coordinate (u, v) in [0, 1] to a point on the
938
+ * cube `[-1, 1]^3` via:
939
+ *
940
+ * s = 2u - 1, t = 2v - 1
941
+ * cube = forward + s * right + t * up
942
+ *
943
+ * Normalizing `cube` yields the unit-sphere direction for that vertex.
944
+ *
945
+ * Bases are right-handed (`forward = right x up`) and outward-facing.
946
+ * Space indices: 0:+X 1:-X 2:+Y 3:-Y 4:+Z 5:-Z.
947
+ */
948
+ type Vec3 = readonly [number, number, number];
949
+ type CubeFace = {
950
+ forward: Vec3;
951
+ right: Vec3;
952
+ up: Vec3;
953
+ };
954
+ declare const CUBE_FACE_COUNT = 6;
955
+ declare const CUBE_FACES: readonly CubeFace[];
956
+
957
+ type Vec3Mutable$1 = [number, number, number];
958
+ /**
959
+ * Cube-space point for a face-local coordinate (u, v) in [0, 1]:
960
+ * cube = forward + (2u-1) * right + (2v-1) * up
961
+ * The result is unnormalized; normalize it to obtain the sphere direction.
962
+ */
963
+ declare function faceUVToCube(face: number, u: number, v: number, out: Vec3Mutable$1): void;
964
+ /** Pick the cube face whose normal axis dominates the direction. */
965
+ declare function directionToFace(d: Vec3): number;
966
+ /** Face-local (u, v) in [0, 1] for a direction known to fall on `face`. */
967
+ declare function directionToFaceUV(face: number, d: Vec3, out: [number, number]): void;
968
+ /**
969
+ * Convert latitude/longitude (degrees) to a unit sphere direction.
970
+ *
971
+ * Convention matches `CUBE_FACES` (+Y is the north pole):
972
+ * - latitude is the angle above the equator, in `[-90, 90]`
973
+ * - longitude is the angle around the +Y axis, in `[-180, 180]`,
974
+ * measured from +Z toward +X (lon = 0 points along +Z).
975
+ */
976
+ declare function latLongToDirection(latDeg: number, lonDeg: number, out: Vec3Mutable$1): void;
977
+ /** Inverse of {@link latLongToDirection}; returns degrees. */
978
+ declare function directionToLatLong(d: Vec3): {
979
+ latitude: number;
980
+ longitude: number;
981
+ };
982
+
983
+ type TorusTopologyConfig = {
984
+ /** Distance from the torus center to the tube center (the donut radius). */
985
+ majorRadius: number;
986
+ /** Radius of the tube cross-section. */
987
+ minorRadius: number;
988
+ /** Torus center in world space (defaults to origin). */
989
+ center?: {
990
+ x: number;
991
+ y: number;
992
+ z: number;
993
+ };
994
+ /** When true, elevation displaces inward and skirts point outward. */
995
+ invert?: boolean;
996
+ };
997
+ /**
998
+ * Torus (donut) topology: a single quadtree space whose `(u, v)` axes wrap
999
+ * around the major circle and the tube cross-section. Both axes are periodic,
1000
+ * so every same-level neighbor exists (wrapping modulo the level resolution).
1001
+ *
1002
+ * Level-0 resolution is anisotropic: `baseU = round(major/minor)` tiles along
1003
+ * `u` and `baseV = 1` along `v`, so root tiles are approximately square in
1004
+ * world space before isotropic LOD subdivision.
1005
+ */
1006
+ declare function createTorusTopology(cfg: TorusTopologyConfig): Topology;
1007
+
1008
+ type Vec3Mutable = [number, number, number];
1009
+ /** Wrap a value into [0, 1). */
1010
+ declare function wrap01(t: number): number;
1011
+ /**
1012
+ * Torus surface point for parameters (u, v) in [0, 1].
1013
+ *
1014
+ * Convention (matches `latLongToDirection`'s longitude axis):
1015
+ * - `theta = 2*pi*u` sweeps around the +Y axis, measured from +Z toward +X.
1016
+ * - `phi = 2*pi*v` sweeps around the tube cross-section, `phi = 0` pointing
1017
+ * radially outward in the XZ plane and `phi = pi/2` pointing toward +Y.
1018
+ *
1019
+ * `displacement` is the elevation added to the tube (minor) radius.
1020
+ */
1021
+ declare function torusUVToPoint(u: number, v: number, majorRadius: number, minorRadius: number, displacement: number, center: {
1022
+ x: number;
1023
+ y: number;
1024
+ z: number;
1025
+ }, out: Vec3Mutable, invert?: boolean): void;
1026
+ /** Outward unit surface normal of the base (undisplaced) torus at (u, v). */
1027
+ declare function torusOutwardNormal(u: number, v: number, out: Vec3Mutable, invert?: boolean): void;
1028
+ type TorusSurfaceParams = {
1029
+ /** Wrapped major-circle parameter in [0, 1). */
1030
+ u: number;
1031
+ /** Wrapped tube parameter in [0, 1). */
1032
+ v: number;
1033
+ /** Distance from the point to the tube center circle. */
1034
+ tubeDistance: number;
1035
+ };
1036
+ /**
1037
+ * Map a world point to torus surface parameters. `tubeDistance - minorRadius`
1038
+ * is the signed radial displacement of the point relative to the base torus.
1039
+ */
1040
+ declare function positionToTorusParams(px: number, py: number, pz: number, majorRadius: number, center: {
1041
+ x: number;
1042
+ y: number;
1043
+ z: number;
1044
+ }, out: TorusSurfaceParams): void;
1012
1045
 
1013
1046
  interface QuadtreeConfigState {
1014
1047
  state: QuadtreeState;
@@ -1149,9 +1182,10 @@ declare const elevationFn: _hello_terrain_work.ParamRef<ElevationCallback>;
1149
1182
  * Builds the TSL position node for the terrain shader.
1150
1183
  *
1151
1184
  * Depends on leafStorageTask (buffer objects), updateUniformsTask
1152
- * (uniform nodes), and createTerrainFieldTextureTask (combined terrain field storage).
1185
+ * (uniform nodes), createTerrainFieldTextureTask (combined terrain field storage),
1186
+ * and tileBoundsContextTask (per-tile pack bounds for denormalization).
1153
1187
  *
1154
- * The position node reads packed terrain samples (height + normal.xz)
1188
+ * The position node reads packed terrain samples (normalized height + normal)
1155
1189
  * per-vertex and assigns them to the vNormal
1156
1190
  * varying for use in the fragment shader.
1157
1191
  *
@@ -1324,6 +1358,22 @@ declare function cubeFaceFromDirection(dir: Node): Node;
1324
1358
  */
1325
1359
  declare function cubeFaceUVFromDirection(basis: CubeFaceBasis, dir: Node): Node;
1326
1360
 
1361
+ /**
1362
+ * Decode an RG-packed 16-bit heightmap sample (R/G in [0, 1]) to a normalized
1363
+ * value in [0, 1].
1364
+ */
1365
+ declare const decodeUint16RG: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node]>;
1366
+ /**
1367
+ * Bilinearly sample an RG-packed 16-bit heightmap and return elevation in meters.
1368
+ *
1369
+ * @param heightmapTexture - Texture or texture node (RG encoding).
1370
+ * @param uv - Sample coordinates in [0, 1].
1371
+ * @param minM - Minimum elevation in meters.
1372
+ * @param maxM - Maximum elevation in meters (unused; kept for API symmetry with range-based callers).
1373
+ * @param rangeM - Elevation span in meters (`maxM - minM`).
1374
+ */
1375
+ declare const sampleHeightmapMeters: three_src_nodes_TSL_js.ShaderNodeFn<[number | Node | Texture<unknown>, number | Node, number | Node, number | Node, number | Node]>;
1376
+
1327
1377
  /**
1328
1378
  * Maps a value or node from texture space [0, 1] to vector space [-1, 1].
1329
1379
  *
@@ -1422,5 +1472,5 @@ interface TorusProjectionConfig {
1422
1472
  /** Torus (donut) projection: a single closed surface periodic in both axes. */
1423
1473
  declare function createTorusProjection(config: TorusProjectionConfig): SurfaceProjection;
1424
1474
 
1425
- export { ArrayTextureBackend, AtlasBackend, CUBE_FACES, CUBE_FACE_COUNT, Dir, TerrainGeometry, TerrainMesh, U32_EMPTY, allocLeafSet, allocSeamTable, augmentCubeSphereSampler, beginUpdate, blendAngleCorrectedNormals, buildLeafIndex, buildSeams2to1, compileComputeTask, createComputePipelineTasks, createCubeSphereProjection, createCubeSphereTopology, createElevationFieldContextTask, createFlatProjection, createFlatTopology, createInfiniteFlatTopology, createSpatialIndex, createState, createTerrainFieldStorage, createTerrainFieldTextureTask, createTerrainQuery, createTerrainRaycast, createTerrainSampler, createTerrainSamplerTask, createTerrainSurfaceQuery, createTerrainUniforms, createTorusProjection, createTorusTopology, 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, positionToTorusParams, quadtreeConfigTask, quadtreeUpdate, quadtreeUpdateTask, radius, resetLeafSet, resetSeamTable, rootSize, sampleTerrainField, sampleTerrainFieldElevation, skirtScale, sphereTangentFrameNormal, storeTerrainField, tangentFromAxis, terrainFieldFilter, terrainFieldStageTask, terrainGraph, terrainQueryTask, terrainRaycastTask, terrainReadbackTask, terrainTasks, textureSpaceToVectorSpace, tileNodesTask, topology, topologyTask, torusOutwardNormal, torusUVToPoint, unpackTangentNormal, update, updateUniformsTask, vElevation, vGlobalVertexIndex, vectorSpaceToTextureSpace, voronoiCells, wrap01 };
1426
- export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodCriteria, LodMode, ProjectionKind, ProjectionRaycastContext, QuadtreeConfig, QuadtreeConfigState, QuadtreeState, RaycastOptions, RenderVertexPositionContext, RuntimeQueries, SeamTable, SpatialIndex, SurfaceKey, SurfaceNormalContext, SurfaceProjection, SurfaceProjectionCpu, SurfaceProjectionGpu, TerrainFieldStorage, TerrainFieldStorageBackendType, TerrainFieldStorageFormat, TerrainFieldStorageOptions, TerrainGraph, TerrainQuery, TerrainQueryContext, TerrainRaycast, TerrainRaycastConfig, TerrainRaycastResult, TerrainSample, TerrainSampleBatch, TerrainSampler, TerrainSphereQuery, TerrainSurfaceQuery, TerrainSurfaceSample, TerrainSurfaceSampleBatch, TerrainTasks, TerrainTile, TerrainTileBounds, TerrainUniformsContext, TerrainUniformsParams, TileBounds, TileElevationRangeFn, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };
1475
+ export { ArrayTextureBackend, AtlasBackend, CUBE_FACES, CUBE_FACE_COUNT, Dir, TERRAIN_FIELD_PACK_EPSILON, TILE_BOUNDS_FLOATS_PER_TILE, TILE_BOUNDS_LOD_MAX_OFFSET, TILE_BOUNDS_LOD_MIN_OFFSET, TILE_BOUNDS_PACK_MAX_OFFSET, TILE_BOUNDS_PACK_MIN_OFFSET, TerrainGeometry, TerrainMesh, U32_EMPTY, allocLeafSet, allocSeamTable, augmentCubeSphereSampler, beginUpdate, blendAngleCorrectedNormals, buildLeafIndex, buildSeams2to1, compileComputeTask, createComputePipelineTasks, createCubeSphereProjection, createCubeSphereTopology, createElevationFieldContextTask, createFlatProjection, createFlatTopology, createInfiniteFlatTopology, createSpatialIndex, createState, createTerrainFieldStorage, createTerrainFieldTextureTask, createTerrainQuery, createTerrainRaycast, createTerrainSampler, createTerrainSamplerTask, createTerrainSurfaceQuery, createTerrainUniforms, createTorusProjection, createTorusTopology, createUniformsTask, cubeFaceBasis, cubeFaceDirection, cubeFaceFromDirection, cubeFacePoint, cubeFaceUVFromDirection, decodeUint16RG, denormalizeTerrainFieldElevation, deriveNormalZ, directionToFace, directionToFaceUV, directionToLatLong, elevationFieldStageTask, elevationFn, elevationScale, executeComputeTask, faceUVToCube, getDeviceComputeLimits, gpuSpatialIndexStorageTask, gpuSpatialIndexUploadTask, innerTileSegments, instanceIdTask, isSkirtUV, isSkirtVertex, latLongToDirection, leafGpuBufferTask, leafStorageTask, loadTerrainField, loadTerrainFieldElevation, loadTerrainFieldNormal, loadTilePackBounds, maxLevel, maxNodes, origin, packNormalizedTerrainFieldSample, packTerrainFieldSample, positionNodeTask, positionToTorusParams, quadtreeConfigTask, quadtreeUpdate, quadtreeUpdateTask, radius, resetLeafSet, resetSeamTable, rootSize, runTileBoundsReduction, sampleHeightmapMeters, sampleTerrainField, sampleTerrainFieldElevation, skirtScale, sphereTangentFrameNormal, storeTerrainField, tangentFromAxis, terrainFieldFilter, terrainFieldStageTask, terrainGraph, terrainQueryTask, terrainRaycastTask, terrainReadbackTask, terrainTasks, textureSpaceToVectorSpace, tileBoundsContextTask, tileBoundsReductionTask, tileNodesTask, topology, topologyTask, torusOutwardNormal, torusUVToPoint, unpackTangentNormal, update, updateUniformsTask, vElevation, vGlobalVertexIndex, vectorSpaceToTextureSpace, voronoiCells, wrap01 };
1476
+ export type { ComputePipeline, ComputeStageCallback, CpuSurfaceOps, CreateTerrainSamplerParams, CubeFace, CubeFaceBasis, CubeSphereProjectionConfig, CubeSphereTopologyConfig, ElevationCallback, ElevationFieldContext, ElevationParams, ElevationRange, ElevationRangeOut, FieldNormalContext, FieldNormalFn, FlatTopologyConfig, GpuSpatialIndexContext, InfiniteFlatTopologyConfig, IntNodeInput, LeafGpuBufferState, LeafSet, LeafStorageState, LodCriteria, LodMode, ProjectionKind, ProjectionRaycastContext, QuadtreeConfig, QuadtreeConfigState, QuadtreeState, RaycastOptions, RenderVertexPositionContext, RuntimeQueries, SeamTable, SpatialIndex, SurfaceKey, SurfaceNormalContext, SurfaceProjection, SurfaceProjectionCpu, SurfaceProjectionGpu, TerrainFieldStorage, TerrainFieldStorageBackendType, TerrainFieldStorageFormat, TerrainFieldStorageOptions, TerrainGraph, TerrainQuery, TerrainQueryContext, TerrainRaycast, TerrainRaycastConfig, TerrainRaycastResult, TerrainSample, TerrainSampleBatch, TerrainSampler, TerrainSphereQuery, TerrainSurfaceQuery, TerrainSurfaceSample, TerrainSurfaceSampleBatch, TerrainTasks, TerrainTile, TerrainTileBounds, TerrainUniformsContext, TerrainUniformsParams, TileBounds, TileBoundsContext, TileElevationRangeFn, TileId, Topology, TorusProjectionConfig, TorusSurfaceParams, TorusTopologyConfig, UpdateParams, Vec3, Vec3Like, Vec3Mutable$1 as Vec3Mutable };