@certe/atmos-terrain 0.1.0

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.
Files changed (60) hide show
  1. package/LICENCE +674 -0
  2. package/README.md +155 -0
  3. package/dist/chunk-key.d.ts +10 -0
  4. package/dist/chunk-key.d.ts.map +1 -0
  5. package/dist/chunk-key.js +27 -0
  6. package/dist/chunk-key.js.map +1 -0
  7. package/dist/chunk.d.ts +36 -0
  8. package/dist/chunk.d.ts.map +1 -0
  9. package/dist/chunk.js +128 -0
  10. package/dist/chunk.js.map +1 -0
  11. package/dist/density-field.d.ts +34 -0
  12. package/dist/density-field.d.ts.map +1 -0
  13. package/dist/density-field.js +68 -0
  14. package/dist/density-field.js.map +1 -0
  15. package/dist/index.d.ts +15 -0
  16. package/dist/index.d.ts.map +1 -0
  17. package/dist/index.js +22 -0
  18. package/dist/index.js.map +1 -0
  19. package/dist/lod-chunk.d.ts +20 -0
  20. package/dist/lod-chunk.d.ts.map +1 -0
  21. package/dist/lod-chunk.js +256 -0
  22. package/dist/lod-chunk.js.map +1 -0
  23. package/dist/lod-extract.d.ts +21 -0
  24. package/dist/lod-extract.d.ts.map +1 -0
  25. package/dist/lod-extract.js +178 -0
  26. package/dist/lod-extract.js.map +1 -0
  27. package/dist/marching-cubes-tables.d.ts +28 -0
  28. package/dist/marching-cubes-tables.d.ts.map +1 -0
  29. package/dist/marching-cubes-tables.js +344 -0
  30. package/dist/marching-cubes-tables.js.map +1 -0
  31. package/dist/marching-cubes.d.ts +17 -0
  32. package/dist/marching-cubes.d.ts.map +1 -0
  33. package/dist/marching-cubes.js +200 -0
  34. package/dist/marching-cubes.js.map +1 -0
  35. package/dist/register-builtins.d.ts +2 -0
  36. package/dist/register-builtins.d.ts.map +1 -0
  37. package/dist/register-builtins.js +34 -0
  38. package/dist/register-builtins.js.map +1 -0
  39. package/dist/terrain-editor.d.ts +15 -0
  40. package/dist/terrain-editor.d.ts.map +1 -0
  41. package/dist/terrain-editor.js +85 -0
  42. package/dist/terrain-editor.js.map +1 -0
  43. package/dist/terrain-normals.d.ts +13 -0
  44. package/dist/terrain-normals.d.ts.map +1 -0
  45. package/dist/terrain-normals.js +96 -0
  46. package/dist/terrain-normals.js.map +1 -0
  47. package/dist/terrain-volume.d.ts +42 -0
  48. package/dist/terrain-volume.d.ts.map +1 -0
  49. package/dist/terrain-volume.js +146 -0
  50. package/dist/terrain-volume.js.map +1 -0
  51. package/dist/terrain-world.d.ts +67 -0
  52. package/dist/terrain-world.d.ts.map +1 -0
  53. package/dist/terrain-world.js +344 -0
  54. package/dist/terrain-world.js.map +1 -0
  55. package/dist/types.d.ts +65 -0
  56. package/dist/types.d.ts.map +1 -0
  57. package/dist/types.js +23 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +29 -0
  60. package/src/index.ts +42 -0
package/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # 🏔️ @certe/atmos-terrain
2
+
3
+ Voxel-based terrain system for the Atmos Engine. Provides density field primitives, marching cubes surface extraction, multi-level LOD streaming, and optional splat texturing with 3-layer blending.
4
+
5
+ ---
6
+
7
+ ## 🔑 Key Concepts
8
+
9
+ - **Density Field** — A function `(x, y, z) → number` where negative = solid, positive = air, surface at `isoLevel`
10
+ - **Marching Cubes** — Polygonizes the density field into triangle meshes per chunk
11
+ - **LOD Streaming** — `TerrainWorld` streams chunks around a camera with 3 LOD levels
12
+ - **Splat Texturing** — Blend 3 terrain textures based on surface normal and height
13
+
14
+ ---
15
+
16
+ ## 🚀 Quick Start
17
+
18
+ ```ts
19
+ import { TerrainWorld, noiseTerrain, registerTerrainBuiltins } from '@certe/atmos-terrain';
20
+ import { perlinNoise3D } from '@certe/atmos-math';
21
+
22
+ registerTerrainBuiltins();
23
+
24
+ const terrain = gameObject.addComponent(TerrainWorld);
25
+ terrain.setDensityFn(noiseTerrain(perlinNoise3D, 32, 0));
26
+ terrain.init(device, pipelineResources, scene);
27
+ terrain.cameraTarget = cameraGameObject;
28
+ ```
29
+
30
+ ---
31
+
32
+ ## 📖 API Overview
33
+
34
+ ### Density Primitives
35
+
36
+ Build terrain shapes with CSG composition:
37
+
38
+ ```ts
39
+ import { sphereDensity, planeDensity, boxDensity,
40
+ unionDensity, subtractDensity, noiseTerrain } from '@certe/atmos-terrain';
41
+
42
+ const ground = planeDensity(0);
43
+ const hill = sphereDensity(10, 0, 10, 8);
44
+ const cave = sphereDensity(10, -2, 10, 4);
45
+
46
+ const density = subtractDensity(unionDensity(ground, hill), cave);
47
+ ```
48
+
49
+ | Function | Description |
50
+ |---|---|
51
+ | `sphereDensity(cx, cy, cz, r)` | SDF sphere |
52
+ | `planeDensity(height)` | Half-space below Y |
53
+ | `boxDensity(cx, cy, cz, hx, hy, hz)` | SDF box |
54
+ | `unionDensity(a, b)` | CSG union |
55
+ | `intersectDensity(a, b)` | CSG intersection |
56
+ | `subtractDensity(a, b)` | CSG subtraction |
57
+ | `noiseTerrain(noiseFn, amp, baseY)` | Noise-based heightmap |
58
+
59
+ ### TerrainWorld (Infinite Streaming)
60
+
61
+ Streams chunks around a focus point with 3 LOD levels:
62
+
63
+ | Property | Description |
64
+ |---|---|
65
+ | `loadRadius` / `unloadRadius` | Chunk-distance thresholds |
66
+ | `maxBuildsPerFrame` / `buildBudgetMs` | Amortized build limits |
67
+ | `cameraTarget` | GameObject to track for streaming |
68
+ | `config` | `TerrainConfig` (chunkSize, voxelSize, smoothNormals) |
69
+ | `lodConfig` | `LODConfig` with distance thresholds |
70
+
71
+ | Method | Description |
72
+ |---|---|
73
+ | `setDensityFn(fn)` | Set the terrain density function |
74
+ | `init(device, pipeline, scene)` | Initialize GPU context |
75
+ | `setSplatMaterials(pipeline, textures, weightFn)` | Enable 3-layer splat blending |
76
+ | `edit(op)` | Apply brush edit (sphere/cube) |
77
+
78
+ LOD levels: **LOD 0** (step=1, near) → **LOD 1** (step=2, medium) → **LOD 2** (step=4, far)
79
+
80
+ ### TerrainVolume (Bounded Grid)
81
+
82
+ Fixed N×M×P chunk grid for smaller terrains:
83
+
84
+ ```ts
85
+ const volume = gameObject.addComponent(TerrainVolume);
86
+ volume.chunksX = 4; volume.chunksY = 2; volume.chunksZ = 4;
87
+ volume.setDensityFn(myDensity);
88
+ volume.init(device, pipelineResources, scene);
89
+ volume.build();
90
+ ```
91
+
92
+ ### Brush Editing
93
+
94
+ ```ts
95
+ terrain.edit({
96
+ shape: 'sphere',
97
+ x: hitPoint[0], y: hitPoint[1], z: hitPoint[2],
98
+ radius: 3,
99
+ strength: -0.5, // negative = add, positive = remove
100
+ falloff: 1,
101
+ });
102
+ ```
103
+
104
+ ### Splat Texturing
105
+
106
+ Blend 3 textures based on surface normal and world height:
107
+
108
+ ```ts
109
+ terrain.setSplatMaterials(terrainPipeline, [grassTex, rockTex, snowTex],
110
+ (nx, ny, nz, worldY) => {
111
+ const slope = 1 - ny;
112
+ const snow = worldY > 20 ? 1 : 0;
113
+ return [1 - slope - snow, slope]; // [grass, rock], snow = remainder
114
+ }
115
+ );
116
+ ```
117
+
118
+ ---
119
+
120
+ ## 🧠 Implementation Details
121
+
122
+ - **Vertex format**: 8 floats (pos+normal+uv) standard, 10 floats (+ weights) for splat
123
+ - **Skirt geometry**: Chunks extend 1 voxel past boundaries to hide LOD seams
124
+ - **Pooled buffers**: Scratch vertex/index/density arrays reused across builds
125
+ - **Deferred removal**: Old chunks kept 1 frame for smooth transitions
126
+ - **Chunk keys**: 30-bit packed coordinates (10 bits per axis)
127
+
128
+ ---
129
+
130
+ ## 📁 Structure
131
+
132
+ ```
133
+ packages/terrain/src/
134
+ index.ts # Public API
135
+ types.ts # TerrainConfig, DensityFn, ChunkCoord, etc.
136
+ density-field.ts # Density primitives + CSG
137
+ marching-cubes.ts # Full-resolution surface extraction
138
+ lod-extract.ts # LOD-stepped marching cubes
139
+ terrain-normals.ts # Gradient + triangle normal computation
140
+ chunk.ts # TerrainChunk (density grid + mesh)
141
+ chunk-key.ts # Coordinate packing utilities
142
+ lod-chunk.ts # buildLODMesh / buildLODSplatMesh
143
+ terrain-world.ts # TerrainWorld streaming component
144
+ terrain-volume.ts # TerrainVolume bounded grid component
145
+ terrain-editor.ts # Brush edit system
146
+ register-builtins.ts # Component registry integration
147
+ ```
148
+
149
+ ---
150
+
151
+ ## 🔗 Dependencies
152
+
153
+ - `@certe/atmos-core` — Component, GameObject, Scene
154
+ - `@certe/atmos-math` — Noise functions for terrain generation
155
+ - `@certe/atmos-renderer` — Mesh, Material, terrain pipeline, textures
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Bit-packs chunk coordinates into a single number for use as a Map key.
3
+ * Supports coordinates in the range [-511, 512] per axis (10 bits each).
4
+ */
5
+ export declare function chunkKey(cx: number, cy: number, cz: number): number;
6
+ /** Unpack a chunk key back into [cx, cy, cz]. */
7
+ export declare function fromChunkKey(key: number): [number, number, number];
8
+ /** Convert world position to chunk coordinates. */
9
+ export declare function worldToChunk(wx: number, wy: number, wz: number, chunkWorldSize: number): [number, number, number];
10
+ //# sourceMappingURL=chunk-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-key.d.ts","sourceRoot":"","sources":["../src/chunk-key.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAMnE;AAED,iDAAiD;AACjD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAKlE;AAED,mDAAmD;AACnD,wBAAgB,YAAY,CAC1B,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAClC,cAAc,EAAE,MAAM,GACrB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAM1B"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Bit-packs chunk coordinates into a single number for use as a Map key.
3
+ * Supports coordinates in the range [-511, 512] per axis (10 bits each).
4
+ */
5
+ export function chunkKey(cx, cy, cz) {
6
+ // Offset to make values positive, then mask to 10 bits
7
+ const x = (cx + 512) & 0x3FF;
8
+ const y = (cy + 512) & 0x3FF;
9
+ const z = (cz + 512) & 0x3FF;
10
+ return (x << 20) | (y << 10) | z;
11
+ }
12
+ /** Unpack a chunk key back into [cx, cy, cz]. */
13
+ export function fromChunkKey(key) {
14
+ const x = ((key >>> 20) & 0x3FF) - 512;
15
+ const y = ((key >>> 10) & 0x3FF) - 512;
16
+ const z = (key & 0x3FF) - 512;
17
+ return [x, y, z];
18
+ }
19
+ /** Convert world position to chunk coordinates. */
20
+ export function worldToChunk(wx, wy, wz, chunkWorldSize) {
21
+ return [
22
+ Math.floor(wx / chunkWorldSize),
23
+ Math.floor(wy / chunkWorldSize),
24
+ Math.floor(wz / chunkWorldSize),
25
+ ];
26
+ }
27
+ //# sourceMappingURL=chunk-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk-key.js","sourceRoot":"","sources":["../src/chunk-key.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU;IACzD,uDAAuD;IACvD,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC;IAC7B,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC;IAC7B,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,GAAG,KAAK,CAAC;IAC7B,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC;AACnC,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,YAAY,CAAC,GAAW;IACtC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;IACvC,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;IACvC,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC,GAAG,GAAG,CAAC;IAC9B,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AACnB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,YAAY,CAC1B,EAAU,EAAE,EAAU,EAAE,EAAU,EAClC,cAAsB;IAEtB,OAAO;QACL,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,cAAc,CAAC;KAChC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,36 @@
1
+ import type { Mesh } from '@certe/atmos-renderer';
2
+ import type { DensityFn, TerrainConfig, MeshData } from './types.js';
3
+ import { ChunkState } from './types.js';
4
+ /**
5
+ * A single terrain chunk: owns a density grid, scratch buffers, and a GPU mesh.
6
+ */
7
+ export declare class TerrainChunk {
8
+ readonly cx: number;
9
+ readonly cy: number;
10
+ readonly cz: number;
11
+ readonly densityGrid: Float32Array;
12
+ state: ChunkState;
13
+ mesh: Mesh | null;
14
+ lastMeshData: MeshData | null;
15
+ lodLevel: number;
16
+ skirtFaces: number;
17
+ private readonly _size;
18
+ private readonly _gridLen;
19
+ private _scratchVerts;
20
+ private _scratchIdx;
21
+ constructor(cx: number, cy: number, cz: number, size: number);
22
+ /** Fill the density grid by sampling the density function. */
23
+ sampleDensity(fn: DensityFn, voxelSize: number): void;
24
+ /**
25
+ * Run marching cubes + normals + UVs and create a GPU mesh.
26
+ * Returns the Mesh, or null if the chunk produced no geometry.
27
+ */
28
+ buildMesh(device: GPUDevice, config: TerrainConfig, densityFn?: DensityFn): Mesh | null;
29
+ /** Destroy the GPU mesh, keeping density data intact. */
30
+ destroyMesh(): void;
31
+ /** Release CPU-side scratch buffers (keeps GPU mesh alive). */
32
+ destroyCPU(): void;
33
+ /** Full cleanup: GPU + CPU resources. */
34
+ destroy(): void;
35
+ }
36
+ //# sourceMappingURL=chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.d.ts","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlD,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACrE,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAcxC;;GAEG;AACH,qBAAa,YAAY;IACvB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IAEnC,KAAK,aAAoB;IACzB,IAAI,EAAE,IAAI,GAAG,IAAI,CAAQ;IACzB,YAAY,EAAE,QAAQ,GAAG,IAAI,CAAQ;IACrC,QAAQ,SAAK;IACb,UAAU,SAAK;IAEf,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,aAAa,CAA6B;IAClD,OAAO,CAAC,WAAW,CAA4B;gBAEnC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAS5D,8DAA8D;IAC9D,aAAa,CACX,EAAE,EAAE,SAAS,EACb,SAAS,EAAE,MAAM,GAChB,IAAI;IAoBP;;;OAGG;IACH,SAAS,CACP,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,aAAa,EACrB,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,GAAG,IAAI;IAmEd,yDAAyD;IACzD,WAAW,IAAI,IAAI;IAQnB,+DAA+D;IAC/D,UAAU,IAAI,IAAI;IAMlB,yCAAyC;IACzC,OAAO,IAAI,IAAI;CAIhB"}
package/dist/chunk.js ADDED
@@ -0,0 +1,128 @@
1
+ import { createMesh } from '@certe/atmos-renderer';
2
+ import { computeBoundingSphere, VERTEX_STRIDE_FLOATS } from '@certe/atmos-renderer';
3
+ import { extractSurface, computeTriplanarUVs } from './marching-cubes.js';
4
+ import { computeGradientNormals, computeTriangleNormals } from './terrain-normals.js';
5
+ import { ChunkState } from './types.js';
6
+ /**
7
+ * Maximum triangles per chunk (worst case: ~5 triangles per voxel).
8
+ * Used to pre-allocate scratch buffers.
9
+ */
10
+ function maxTriangles(size) {
11
+ return size * size * size * 5;
12
+ }
13
+ function maxVertices(size) {
14
+ return maxTriangles(size) * 3;
15
+ }
16
+ /**
17
+ * A single terrain chunk: owns a density grid, scratch buffers, and a GPU mesh.
18
+ */
19
+ export class TerrainChunk {
20
+ cx;
21
+ cy;
22
+ cz;
23
+ densityGrid;
24
+ state = ChunkState.Empty;
25
+ mesh = null;
26
+ lastMeshData = null;
27
+ lodLevel = 0;
28
+ skirtFaces = 0;
29
+ _size;
30
+ _gridLen;
31
+ _scratchVerts = null;
32
+ _scratchIdx = null;
33
+ constructor(cx, cy, cz, size) {
34
+ this.cx = cx;
35
+ this.cy = cy;
36
+ this.cz = cz;
37
+ this._size = size;
38
+ this._gridLen = (size + 1) ** 3;
39
+ this.densityGrid = new Float32Array(this._gridLen);
40
+ }
41
+ /** Fill the density grid by sampling the density function. */
42
+ sampleDensity(fn, voxelSize) {
43
+ const s = this._size;
44
+ const s1 = s + 1;
45
+ const originX = this.cx * s * voxelSize;
46
+ const originY = this.cy * s * voxelSize;
47
+ const originZ = this.cz * s * voxelSize;
48
+ for (let z = 0; z <= s; z++) {
49
+ for (let y = 0; y <= s; y++) {
50
+ for (let x = 0; x <= s; x++) {
51
+ const wx = originX + x * voxelSize;
52
+ const wy = originY + y * voxelSize;
53
+ const wz = originZ + z * voxelSize;
54
+ this.densityGrid[z * s1 * s1 + y * s1 + x] = fn(wx, wy, wz);
55
+ }
56
+ }
57
+ }
58
+ this.state = ChunkState.Sampled;
59
+ }
60
+ /**
61
+ * Run marching cubes + normals + UVs and create a GPU mesh.
62
+ * Returns the Mesh, or null if the chunk produced no geometry.
63
+ */
64
+ buildMesh(device, config, densityFn) {
65
+ const s = this._size;
66
+ // Lazy-allocate scratch buffers
67
+ if (!this._scratchVerts) {
68
+ this._scratchVerts = new Float32Array(maxVertices(s) * VERTEX_STRIDE_FLOATS);
69
+ }
70
+ if (!this._scratchIdx) {
71
+ this._scratchIdx = new Uint32Array(maxTriangles(s) * 3);
72
+ }
73
+ const meshData = extractSurface(this.densityGrid, s, config.voxelSize, config.isoLevel, this._scratchVerts, this._scratchIdx);
74
+ if (meshData.vertexCount === 0 || meshData.indexCount === 0) {
75
+ this.destroyMesh();
76
+ this.lastMeshData = null;
77
+ this.state = ChunkState.Meshed;
78
+ return null;
79
+ }
80
+ // Compute normals
81
+ if (config.smoothNormals && densityFn) {
82
+ const voxelSize = config.voxelSize;
83
+ const originX = this.cx * s * voxelSize;
84
+ const originY = this.cy * s * voxelSize;
85
+ const originZ = this.cz * s * voxelSize;
86
+ // Offset density function to chunk-local coords → world coords
87
+ const worldDensity = (x, y, z) => densityFn(x + originX, y + originY, z + originZ);
88
+ computeGradientNormals(meshData.vertices, meshData.vertexCount, worldDensity, config.normalEpsilon);
89
+ }
90
+ else {
91
+ computeTriangleNormals(meshData.vertices, meshData.indices, meshData.vertexCount, meshData.indexCount);
92
+ }
93
+ // Compute triplanar UVs after normals are ready
94
+ computeTriplanarUVs(meshData.vertices, meshData.vertexCount);
95
+ // Trim to actual size for GPU upload
96
+ const trimmedVerts = meshData.vertices.subarray(0, meshData.vertexCount * VERTEX_STRIDE_FLOATS);
97
+ const trimmedIdx = meshData.indices.subarray(0, meshData.indexCount);
98
+ // Detach old mesh reference (caller is responsible for destroying old
99
+ // GPU buffers via MeshRenderer.destroyMesh() after submit completes).
100
+ this.mesh = null;
101
+ const gpuMesh = createMesh(device, trimmedVerts, trimmedIdx, VERTEX_STRIDE_FLOATS);
102
+ gpuMesh.bounds = computeBoundingSphere(trimmedVerts, VERTEX_STRIDE_FLOATS);
103
+ this.mesh = gpuMesh;
104
+ this.lastMeshData = meshData;
105
+ this.state = ChunkState.Meshed;
106
+ return gpuMesh;
107
+ }
108
+ /** Destroy the GPU mesh, keeping density data intact. */
109
+ destroyMesh() {
110
+ if (this.mesh) {
111
+ this.mesh.vertexBuffer.destroy();
112
+ this.mesh.indexBuffer.destroy();
113
+ this.mesh = null;
114
+ }
115
+ }
116
+ /** Release CPU-side scratch buffers (keeps GPU mesh alive). */
117
+ destroyCPU() {
118
+ this._scratchVerts = null;
119
+ this._scratchIdx = null;
120
+ this.lastMeshData = null;
121
+ }
122
+ /** Full cleanup: GPU + CPU resources. */
123
+ destroy() {
124
+ this.destroyMesh();
125
+ this.destroyCPU();
126
+ }
127
+ }
128
+ //# sourceMappingURL=chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chunk.js","sourceRoot":"","sources":["../src/chunk.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { DensityFn, DensityWithWeightsFn } from './types.js';
2
+ /** Adapt a simple DensityFn to DensityWithWeightsFn (no weights). */
3
+ export declare function adaptDensityFn(fn: DensityFn): DensityWithWeightsFn;
4
+ /**
5
+ * Signed distance field for a sphere.
6
+ * Negative inside, positive outside (solid inside).
7
+ * Returns a DensityFn where negative = solid.
8
+ */
9
+ export declare function sphereDensity(cx: number, cy: number, cz: number, radius: number): DensityFn;
10
+ /**
11
+ * Half-space density: solid below the plane at y = height.
12
+ * Returns negative (solid) when y < height, positive (air) when y > height.
13
+ */
14
+ export declare function planeDensity(height: number): DensityFn;
15
+ /**
16
+ * Axis-aligned box density. Solid inside the box.
17
+ * @param cx,cy,cz Center of the box
18
+ * @param hx,hy,hz Half-extents
19
+ */
20
+ export declare function boxDensity(cx: number, cy: number, cz: number, hx: number, hy: number, hz: number): DensityFn;
21
+ /** Union: solid where either A or B is solid (min of two SDFs). */
22
+ export declare function unionDensity(a: DensityFn, b: DensityFn): DensityFn;
23
+ /** Intersection: solid where both A and B are solid (max of two SDFs). */
24
+ export declare function intersectDensity(a: DensityFn, b: DensityFn): DensityFn;
25
+ /** Subtraction: solid where A is solid but B is not (A minus B). */
26
+ export declare function subtractDensity(a: DensityFn, b: DensityFn): DensityFn;
27
+ /**
28
+ * Noise-based terrain: creates a heightmap-style density using an external noise function.
29
+ * @param noiseFn 2D noise function (x, z) => value in [-1, 1]
30
+ * @param amplitude Height amplitude of the noise
31
+ * @param baseHeight Base terrain height (y)
32
+ */
33
+ export declare function noiseTerrain(noiseFn: (x: number, z: number) => number, amplitude: number, baseHeight: number): DensityFn;
34
+ //# sourceMappingURL=density-field.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"density-field.d.ts","sourceRoot":"","sources":["../src/density-field.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElE,qEAAqE;AACrE,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,GAAG,oBAAoB,CAElE;AAKD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAClC,MAAM,EAAE,MAAM,GACb,SAAS,CAOX;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAClC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GACjC,SAAS,CAYX;AAID,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAElE;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAEtE;AAED,oEAAoE;AACpE,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,SAAS,CAErE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,OAAO,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,KAAK,MAAM,EACzC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,GACjB,SAAS,CAKX"}
@@ -0,0 +1,68 @@
1
+ /** Adapt a simple DensityFn to DensityWithWeightsFn (no weights). */
2
+ export function adaptDensityFn(fn) {
3
+ return (x, y, z) => ({ density: fn(x, y, z) });
4
+ }
5
+ // --- Primitives ---
6
+ // Convention: positive = air, negative = solid, surface at 0
7
+ /**
8
+ * Signed distance field for a sphere.
9
+ * Negative inside, positive outside (solid inside).
10
+ * Returns a DensityFn where negative = solid.
11
+ */
12
+ export function sphereDensity(cx, cy, cz, radius) {
13
+ return (x, y, z) => {
14
+ const dx = x - cx;
15
+ const dy = y - cy;
16
+ const dz = z - cz;
17
+ return Math.sqrt(dx * dx + dy * dy + dz * dz) - radius;
18
+ };
19
+ }
20
+ /**
21
+ * Half-space density: solid below the plane at y = height.
22
+ * Returns negative (solid) when y < height, positive (air) when y > height.
23
+ */
24
+ export function planeDensity(height) {
25
+ return (_x, y, _z) => y - height;
26
+ }
27
+ /**
28
+ * Axis-aligned box density. Solid inside the box.
29
+ * @param cx,cy,cz Center of the box
30
+ * @param hx,hy,hz Half-extents
31
+ */
32
+ export function boxDensity(cx, cy, cz, hx, hy, hz) {
33
+ return (x, y, z) => {
34
+ const dx = Math.abs(x - cx) - hx;
35
+ const dy = Math.abs(y - cy) - hy;
36
+ const dz = Math.abs(z - cz) - hz;
37
+ // Exact SDF for an AABB
38
+ const outsideDist = Math.sqrt(Math.max(dx, 0) ** 2 + Math.max(dy, 0) ** 2 + Math.max(dz, 0) ** 2);
39
+ const insideDist = Math.min(Math.max(dx, dy, dz), 0);
40
+ return outsideDist + insideDist;
41
+ };
42
+ }
43
+ // --- CSG Combinators ---
44
+ /** Union: solid where either A or B is solid (min of two SDFs). */
45
+ export function unionDensity(a, b) {
46
+ return (x, y, z) => Math.min(a(x, y, z), b(x, y, z));
47
+ }
48
+ /** Intersection: solid where both A and B are solid (max of two SDFs). */
49
+ export function intersectDensity(a, b) {
50
+ return (x, y, z) => Math.max(a(x, y, z), b(x, y, z));
51
+ }
52
+ /** Subtraction: solid where A is solid but B is not (A minus B). */
53
+ export function subtractDensity(a, b) {
54
+ return (x, y, z) => Math.max(a(x, y, z), -b(x, y, z));
55
+ }
56
+ /**
57
+ * Noise-based terrain: creates a heightmap-style density using an external noise function.
58
+ * @param noiseFn 2D noise function (x, z) => value in [-1, 1]
59
+ * @param amplitude Height amplitude of the noise
60
+ * @param baseHeight Base terrain height (y)
61
+ */
62
+ export function noiseTerrain(noiseFn, amplitude, baseHeight) {
63
+ return (x, y, z) => {
64
+ const terrainHeight = baseHeight + noiseFn(x, z) * amplitude;
65
+ return y - terrainHeight;
66
+ };
67
+ }
68
+ //# sourceMappingURL=density-field.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"density-field.js","sourceRoot":"","sources":["../src/density-field.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type { DensityFn, DensityWithWeightsFn, DensitySample, SplatWeightFn, SplatTextures } from './types.js';
2
+ export type { ChunkCoord, TerrainConfig, MeshData, TerrainEdit, LODConfig } from './types.js';
3
+ export { BrushShape, ChunkState, DEFAULT_TERRAIN_CONFIG, DEFAULT_LOD_CONFIG } from './types.js';
4
+ export { chunkKey, fromChunkKey, worldToChunk } from './chunk-key.js';
5
+ export { extractSurface, computeTriplanarUVs } from './marching-cubes.js';
6
+ export { computeGradientNormals, computeTriangleNormals } from './terrain-normals.js';
7
+ export { adaptDensityFn, sphereDensity, planeDensity, boxDensity, unionDensity, intersectDensity, subtractDensity, noiseTerrain, } from './density-field.js';
8
+ export { TerrainChunk } from './chunk.js';
9
+ export { applyEdit } from './terrain-editor.js';
10
+ export { extractSurfaceLOD } from './lod-extract.js';
11
+ export { buildLODMesh, buildLODSplatMesh } from './lod-chunk.js';
12
+ export { TerrainVolume } from './terrain-volume.js';
13
+ export { TerrainWorld } from './terrain-world.js';
14
+ export { registerTerrainBuiltins } from './register-builtins.js';
15
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EAAE,SAAS,EAAE,oBAAoB,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC/G,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,QAAQ,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9F,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGhG,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG1E,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAGtF,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAGhD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGjE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ export { BrushShape, ChunkState, DEFAULT_TERRAIN_CONFIG, DEFAULT_LOD_CONFIG } from './types.js';
2
+ // Chunk key utilities
3
+ export { chunkKey, fromChunkKey, worldToChunk } from './chunk-key.js';
4
+ // Marching cubes
5
+ export { extractSurface, computeTriplanarUVs } from './marching-cubes.js';
6
+ // Normals
7
+ export { computeGradientNormals, computeTriangleNormals } from './terrain-normals.js';
8
+ // Density primitives & CSG
9
+ export { adaptDensityFn, sphereDensity, planeDensity, boxDensity, unionDensity, intersectDensity, subtractDensity, noiseTerrain, } from './density-field.js';
10
+ // Chunk
11
+ export { TerrainChunk } from './chunk.js';
12
+ // Editor (brush system)
13
+ export { applyEdit } from './terrain-editor.js';
14
+ // LOD
15
+ export { extractSurfaceLOD } from './lod-extract.js';
16
+ export { buildLODMesh, buildLODSplatMesh } from './lod-chunk.js';
17
+ // Components
18
+ export { TerrainVolume } from './terrain-volume.js';
19
+ export { TerrainWorld } from './terrain-world.js';
20
+ // Registration
21
+ export { registerTerrainBuiltins } from './register-builtins.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAEhG,sBAAsB;AACtB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEtE,iBAAiB;AACjB,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE1E,UAAU;AACV,OAAO,EAAE,sBAAsB,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEtF,2BAA2B;AAC3B,OAAO,EACL,cAAc,EACd,aAAa,EACb,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,YAAY,GACb,MAAM,oBAAoB,CAAC;AAE5B,QAAQ;AACR,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,wBAAwB;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM;AACN,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAEjE,aAAa;AACb,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,eAAe;AACf,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import type { Mesh } from '@certe/atmos-renderer';
2
+ import type { TerrainChunk } from './chunk.js';
3
+ import type { DensityFn, TerrainConfig, SplatWeightFn } from './types.js';
4
+ /**
5
+ * Build a mesh at the given LOD level with grid overlap
6
+ * to hide cracks at LOD transitions.
7
+ *
8
+ * When `skirtFaces` is non-zero and `densityFn` is provided, the MC grid
9
+ * is extended by 1 cell (step voxels) past each boundary. The resulting
10
+ * mesh naturally overlaps with neighbors and the depth buffer hides seams.
11
+ * No extra skirt geometry — just real terrain surface past the boundary.
12
+ */
13
+ export declare function buildLODMesh(chunk: TerrainChunk, device: GPUDevice, config: TerrainConfig, lodLevel: number, skirtFaces: number, densityFn?: DensityFn): Mesh | null;
14
+ /**
15
+ * Build a terrain mesh with splat weights (10-float stride).
16
+ * Runs the normal 8-float mesh build, then repacks into 10-float stride
17
+ * adding splat weights computed from surface normal + world height.
18
+ */
19
+ export declare function buildLODSplatMesh(chunk: TerrainChunk, device: GPUDevice, config: TerrainConfig, lodLevel: number, skirtFaces: number, densityFn: DensityFn, weightFn: SplatWeightFn): Mesh | null;
20
+ //# sourceMappingURL=lod-chunk.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lod-chunk.d.ts","sourceRoot":"","sources":["../src/lod-chunk.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAIlD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkG1E;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAC1B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,CAAC,EAAE,SAAS,GACpB,IAAI,GAAG,IAAI,CA0Gb;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,aAAa,GACtB,IAAI,GAAG,IAAI,CAwGb"}