@buley/hexgrid-3d 3.1.0 → 3.2.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.
- package/dist/HexGridEnhanced.d.ts +15 -0
- package/dist/HexGridEnhanced.d.ts.map +1 -0
- package/dist/HexGridEnhanced.js +1 -0
- package/dist/Snapshot.d.ts +594 -0
- package/dist/Snapshot.d.ts.map +1 -0
- package/dist/Snapshot.js +757 -0
- package/dist/adapters/DashAdapter.d.ts +18 -0
- package/dist/adapters/DashAdapter.d.ts.map +1 -0
- package/dist/adapters/DashAdapter.js +42 -0
- package/dist/adapters.d.ts +53 -0
- package/dist/adapters.d.ts.map +1 -0
- package/dist/adapters.js +14 -0
- package/dist/algorithms/AdvancedStatistics.d.ts +52 -0
- package/dist/algorithms/AdvancedStatistics.d.ts.map +1 -0
- package/dist/algorithms/AdvancedStatistics.js +307 -0
- package/dist/algorithms/BayesianStatistics.d.ts +86 -0
- package/dist/algorithms/BayesianStatistics.d.ts.map +1 -0
- package/dist/algorithms/BayesianStatistics.js +263 -0
- package/dist/algorithms/FlowField.d.ts +55 -0
- package/dist/algorithms/FlowField.d.ts.map +1 -0
- package/dist/algorithms/FlowField.js +80 -0
- package/dist/algorithms/FlowField3D.d.ts +166 -0
- package/dist/algorithms/FlowField3D.d.ts.map +1 -0
- package/dist/algorithms/FlowField3D.js +327 -0
- package/dist/algorithms/FluidEngineFactory.d.ts +15 -0
- package/dist/algorithms/FluidEngineFactory.d.ts.map +1 -0
- package/dist/algorithms/FluidEngineFactory.js +41 -0
- package/dist/algorithms/FluidSimulation.d.ts +41 -0
- package/dist/algorithms/FluidSimulation.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation.js +74 -0
- package/dist/algorithms/FluidSimulation3D.d.ts +137 -0
- package/dist/algorithms/FluidSimulation3D.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation3D.js +464 -0
- package/dist/algorithms/FluidSimulation3DGPU.d.ts +41 -0
- package/dist/algorithms/FluidSimulation3DGPU.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulation3DGPU.js +328 -0
- package/dist/algorithms/FluidSimulationWebNN.d.ts +56 -0
- package/dist/algorithms/FluidSimulationWebNN.d.ts.map +1 -0
- package/dist/algorithms/FluidSimulationWebNN.js +84 -0
- package/dist/algorithms/GraphAlgorithms.d.ts +48 -0
- package/dist/algorithms/GraphAlgorithms.d.ts.map +1 -0
- package/dist/algorithms/GraphAlgorithms.js +122 -0
- package/dist/algorithms/OutlierDetection.d.ts +49 -0
- package/dist/algorithms/OutlierDetection.d.ts.map +1 -0
- package/dist/algorithms/OutlierDetection.js +284 -0
- package/dist/algorithms/ParticleSystem.d.ts +36 -0
- package/dist/algorithms/ParticleSystem.d.ts.map +1 -0
- package/dist/algorithms/ParticleSystem.js +59 -0
- package/dist/algorithms/ParticleSystem3D.d.ts +206 -0
- package/dist/algorithms/ParticleSystem3D.d.ts.map +1 -0
- package/dist/algorithms/ParticleSystem3D.js +371 -0
- package/dist/algorithms/index.d.ts +16 -0
- package/dist/algorithms/index.d.ts.map +1 -0
- package/{src/algorithms/index.ts → dist/algorithms/index.js} +0 -2
- package/dist/compat.d.ts +24 -0
- package/dist/compat.d.ts.map +1 -0
- package/dist/compat.js +88 -0
- package/dist/components/HexGrid.d.ts +5 -0
- package/dist/components/HexGrid.d.ts.map +1 -0
- package/dist/components/HexGrid.js +39 -0
- package/dist/components/NarrationOverlay.d.ts +16 -0
- package/dist/components/NarrationOverlay.d.ts.map +1 -0
- package/dist/components/NarrationOverlay.js +132 -0
- package/{src/components/index.ts → dist/components/index.d.ts} +1 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +1 -0
- package/dist/features.d.ts +54 -0
- package/dist/features.d.ts.map +1 -0
- package/dist/features.js +74 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +0 -9
- package/dist/lib/narration.d.ts +12 -0
- package/dist/lib/narration.d.ts.map +1 -0
- package/dist/lib/narration.js +8 -0
- package/dist/lib/stats-tracker.d.ts +7 -0
- package/dist/lib/stats-tracker.d.ts.map +1 -0
- package/dist/lib/stats-tracker.js +22 -0
- package/dist/lib/theme-colors.d.ts +7 -0
- package/dist/lib/theme-colors.d.ts.map +1 -0
- package/dist/lib/theme-colors.js +10 -0
- package/dist/math/HexCoordinates.d.ts +140 -0
- package/dist/math/HexCoordinates.d.ts.map +1 -0
- package/dist/math/HexCoordinates.js +741 -0
- package/dist/math/Matrix4.d.ts +9 -0
- package/dist/math/Matrix4.d.ts.map +1 -0
- package/dist/math/Matrix4.js +19 -0
- package/dist/math/Quaternion.d.ts +11 -0
- package/dist/math/Quaternion.d.ts.map +1 -0
- package/dist/math/Quaternion.js +23 -0
- package/dist/math/SpatialIndex.d.ts +34 -0
- package/dist/math/SpatialIndex.d.ts.map +1 -0
- package/dist/math/SpatialIndex.js +75 -0
- package/dist/math/Vector3.d.ts +110 -0
- package/dist/math/Vector3.d.ts.map +1 -0
- package/dist/math/Vector3.js +426 -0
- package/dist/math/index.d.ts +11 -0
- package/dist/math/index.d.ts.map +1 -0
- package/{src/math/index.ts → dist/math/index.js} +0 -1
- package/dist/note-adapter.d.ts +44 -0
- package/dist/note-adapter.d.ts.map +1 -0
- package/dist/note-adapter.js +86 -0
- package/dist/ontology-adapter.d.ts +13 -0
- package/dist/ontology-adapter.d.ts.map +1 -0
- package/dist/ontology-adapter.js +65 -0
- package/dist/stores/index.d.ts +2 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/uiStore.d.ts +18 -0
- package/dist/stores/uiStore.d.ts.map +1 -0
- package/dist/stores/uiStore.js +77 -0
- package/dist/types/index.d.ts +4 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types.d.ts +126 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +4 -0
- package/dist/utils/image-utils.d.ts +13 -0
- package/dist/utils/image-utils.d.ts.map +1 -0
- package/dist/utils/image-utils.js +23 -0
- package/dist/wasm/HexGridWasmWrapper.d.ts +131 -0
- package/dist/wasm/HexGridWasmWrapper.d.ts.map +1 -0
- package/dist/wasm/HexGridWasmWrapper.js +610 -0
- package/dist/wasm/index.d.ts +7 -0
- package/dist/wasm/index.d.ts.map +1 -0
- package/{src/wasm/index.ts → dist/wasm/index.js} +0 -1
- package/dist/webgpu/WebGPUContext.d.ts +20 -0
- package/dist/webgpu/WebGPUContext.d.ts.map +1 -0
- package/dist/webgpu/WebGPUContext.js +60 -0
- package/dist/webnn/WebNNContext.d.ts +38 -0
- package/dist/webnn/WebNNContext.d.ts.map +1 -0
- package/dist/webnn/WebNNContext.js +66 -0
- package/dist/workers/hexgrid-math.d.ts +79 -0
- package/dist/workers/hexgrid-math.d.ts.map +1 -0
- package/dist/workers/hexgrid-math.js +136 -0
- package/dist/workers/hexgrid-worker.worker.d.ts +35 -0
- package/dist/workers/hexgrid-worker.worker.d.ts.map +1 -0
- package/dist/workers/hexgrid-worker.worker.js +2014 -0
- package/package.json +20 -7
- package/.eslintrc.json +0 -28
- package/build_log.txt +0 -500
- package/build_src_log.txt +0 -8
- package/examples/basic-usage.tsx +0 -52
- package/public/hexgrid-worker.js +0 -2475
- package/rust/Cargo.toml +0 -41
- package/rust/src/lib.rs +0 -740
- package/rust/src/math.rs +0 -574
- package/rust/src/spatial.rs +0 -245
- package/rust/src/statistics.rs +0 -496
- package/site/.eslintrc.json +0 -3
- package/site/DEPLOYMENT.md +0 -196
- package/site/INDEX.md +0 -127
- package/site/QUICK_START.md +0 -86
- package/site/README.md +0 -85
- package/site/SITE_SUMMARY.md +0 -180
- package/site/next.config.js +0 -12
- package/site/package.json +0 -26
- package/site/src/app/docs/page.tsx +0 -272
- package/site/src/app/examples/page.tsx +0 -151
- package/site/src/app/globals.css +0 -160
- package/site/src/app/layout.tsx +0 -39
- package/site/src/app/page.tsx +0 -235
- package/site/tsconfig.json +0 -29
- package/site/vercel.json +0 -6
- package/src/HexGridEnhanced.ts +0 -16
- package/src/Snapshot.ts +0 -1607
- package/src/adapters/DashAdapter.ts +0 -57
- package/src/adapters.ts +0 -63
- package/src/algorithms/AdvancedStatistics.ts +0 -362
- package/src/algorithms/BayesianStatistics.ts +0 -348
- package/src/algorithms/FlowField.ts +0 -150
- package/src/algorithms/FlowField3D.ts +0 -573
- package/src/algorithms/FluidEngineFactory.ts +0 -44
- package/src/algorithms/FluidSimulation.ts +0 -115
- package/src/algorithms/FluidSimulation3D.ts +0 -664
- package/src/algorithms/FluidSimulation3DGPU.ts +0 -408
- package/src/algorithms/FluidSimulationWebNN.ts +0 -141
- package/src/algorithms/GraphAlgorithms.ts +0 -191
- package/src/algorithms/OutlierDetection.ts +0 -425
- package/src/algorithms/ParticleSystem.ts +0 -95
- package/src/algorithms/ParticleSystem3D.ts +0 -567
- package/src/compat.ts +0 -96
- package/src/components/HexGrid.tsx +0 -61
- package/src/components/NarrationOverlay.tsx +0 -309
- package/src/features.ts +0 -125
- package/src/lib/narration.ts +0 -17
- package/src/lib/stats-tracker.ts +0 -25
- package/src/lib/theme-colors.ts +0 -12
- package/src/math/HexCoordinates.ts +0 -863
- package/src/math/Matrix4.ts +0 -25
- package/src/math/Quaternion.ts +0 -37
- package/src/math/SpatialIndex.ts +0 -114
- package/src/math/Vector3.ts +0 -540
- package/src/note-adapter.ts +0 -132
- package/src/ontology-adapter.ts +0 -84
- package/src/stores/uiStore.ts +0 -85
- package/src/types/index.ts +0 -3
- package/src/types/shared-utils.d.ts +0 -10
- package/src/types/wgsl.d.ts +0 -4
- package/src/types.ts +0 -164
- package/src/utils/image-utils.ts +0 -28
- package/src/wasm/HexGridWasmWrapper.ts +0 -801
- package/src/webgpu/WebGPUContext.ts +0 -71
- package/src/webgpu/shaders/fluid_sim.wgsl +0 -140
- package/src/webnn/WebNNContext.ts +0 -99
- package/src/workers/hexgrid-math.ts +0 -182
- package/src/workers/hexgrid-worker.worker.ts +0 -2781
- package/tsconfig.json +0 -26
- /package/{src/stores/index.ts → dist/stores/index.js} +0 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 3D Stable Fluids Implementation
|
|
3
|
+
*
|
|
4
|
+
* Based on Jos Stam's "Stable Fluids" paper (SIGGRAPH 1999)
|
|
5
|
+
* Extended to 3D for the Pensieve particle visualization.
|
|
6
|
+
*
|
|
7
|
+
* Key operations:
|
|
8
|
+
* 1. Add sources (density, velocity)
|
|
9
|
+
* 2. Diffuse (spread quantities)
|
|
10
|
+
* 3. Advect (move quantities along velocity field)
|
|
11
|
+
* 4. Project (make velocity field divergence-free)
|
|
12
|
+
*/
|
|
13
|
+
import { Vector3 } from '../math/Vector3';
|
|
14
|
+
/**
|
|
15
|
+
* 3D Stable Fluids solver for realistic fluid dynamics
|
|
16
|
+
*/
|
|
17
|
+
export class StableFluids3D {
|
|
18
|
+
constructor(config) {
|
|
19
|
+
this.width = Math.max(1, Math.round(config.width));
|
|
20
|
+
this.height = Math.max(1, Math.round(config.height));
|
|
21
|
+
this.depth = Math.max(1, Math.round(config.depth));
|
|
22
|
+
this.size = this.width * this.height * this.depth;
|
|
23
|
+
this.viscosity = config.viscosity;
|
|
24
|
+
this.diffusion = config.diffusion;
|
|
25
|
+
this.iterations = config.iterations ?? 4;
|
|
26
|
+
// Allocate arrays
|
|
27
|
+
this.density = new Float32Array(this.size);
|
|
28
|
+
this.velocityX = new Float32Array(this.size);
|
|
29
|
+
this.velocityY = new Float32Array(this.size);
|
|
30
|
+
this.velocityZ = new Float32Array(this.size);
|
|
31
|
+
this.density0 = new Float32Array(this.size);
|
|
32
|
+
this.velocityX0 = new Float32Array(this.size);
|
|
33
|
+
this.velocityY0 = new Float32Array(this.size);
|
|
34
|
+
this.velocityZ0 = new Float32Array(this.size);
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Add density at a point with radius falloff
|
|
38
|
+
*/
|
|
39
|
+
addDensity(x, y, z, amount, radius) {
|
|
40
|
+
const r2 = radius * radius;
|
|
41
|
+
const ix0 = Math.max(0, Math.floor(x - radius));
|
|
42
|
+
const ix1 = Math.min(this.width - 1, Math.ceil(x + radius));
|
|
43
|
+
const iy0 = Math.max(0, Math.floor(y - radius));
|
|
44
|
+
const iy1 = Math.min(this.height - 1, Math.ceil(y + radius));
|
|
45
|
+
const iz0 = Math.max(0, Math.floor(z - radius));
|
|
46
|
+
const iz1 = Math.min(this.depth - 1, Math.ceil(z + radius));
|
|
47
|
+
for (let iz = iz0; iz <= iz1; iz++) {
|
|
48
|
+
for (let iy = iy0; iy <= iy1; iy++) {
|
|
49
|
+
for (let ix = ix0; ix <= ix1; ix++) {
|
|
50
|
+
const dx = ix - x;
|
|
51
|
+
const dy = iy - y;
|
|
52
|
+
const dz = iz - z;
|
|
53
|
+
const dist2 = dx * dx + dy * dy + dz * dz;
|
|
54
|
+
if (dist2 < r2) {
|
|
55
|
+
const falloff = 1 - dist2 / r2;
|
|
56
|
+
const idx = this.indexFor(ix, iy, iz);
|
|
57
|
+
this.density[idx] += amount * falloff;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Add force at a point with radius falloff
|
|
65
|
+
*/
|
|
66
|
+
addForce(pos, force, radius) {
|
|
67
|
+
const r2 = radius * radius;
|
|
68
|
+
const ix0 = Math.max(0, Math.floor(pos.x - radius));
|
|
69
|
+
const ix1 = Math.min(this.width - 1, Math.ceil(pos.x + radius));
|
|
70
|
+
const iy0 = Math.max(0, Math.floor(pos.y - radius));
|
|
71
|
+
const iy1 = Math.min(this.height - 1, Math.ceil(pos.y + radius));
|
|
72
|
+
const iz0 = Math.max(0, Math.floor(pos.z - radius));
|
|
73
|
+
const iz1 = Math.min(this.depth - 1, Math.ceil(pos.z + radius));
|
|
74
|
+
for (let iz = iz0; iz <= iz1; iz++) {
|
|
75
|
+
for (let iy = iy0; iy <= iy1; iy++) {
|
|
76
|
+
for (let ix = ix0; ix <= ix1; ix++) {
|
|
77
|
+
const dx = ix - pos.x;
|
|
78
|
+
const dy = iy - pos.y;
|
|
79
|
+
const dz = iz - pos.z;
|
|
80
|
+
const dist2 = dx * dx + dy * dy + dz * dz;
|
|
81
|
+
if (dist2 < r2) {
|
|
82
|
+
const falloff = 1 - dist2 / r2;
|
|
83
|
+
const idx = this.indexFor(ix, iy, iz);
|
|
84
|
+
this.velocityX[idx] += force.x * falloff;
|
|
85
|
+
this.velocityY[idx] += force.y * falloff;
|
|
86
|
+
this.velocityZ[idx] += force.z * falloff;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Step the simulation forward by dt seconds
|
|
94
|
+
*/
|
|
95
|
+
step(dt) {
|
|
96
|
+
// Velocity step
|
|
97
|
+
this.velocityStep(dt);
|
|
98
|
+
// Density step
|
|
99
|
+
this.densityStep(dt);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Get velocity at a point (with trilinear interpolation)
|
|
103
|
+
*/
|
|
104
|
+
getVelocityAt(pos) {
|
|
105
|
+
return new Vector3(this.sampleField(this.velocityX, pos.x, pos.y, pos.z), this.sampleField(this.velocityY, pos.x, pos.y, pos.z), this.sampleField(this.velocityZ, pos.x, pos.y, pos.z));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Get density at a point (with trilinear interpolation)
|
|
109
|
+
*/
|
|
110
|
+
getDensityAt(pos) {
|
|
111
|
+
return this.sampleField(this.density, pos.x, pos.y, pos.z);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get the raw velocity fields for direct access
|
|
115
|
+
*/
|
|
116
|
+
getVelocityFields() {
|
|
117
|
+
return { x: this.velocityX, y: this.velocityY, z: this.velocityZ };
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get the raw density field
|
|
121
|
+
*/
|
|
122
|
+
getDensityField() {
|
|
123
|
+
return this.density;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Get grid dimensions
|
|
127
|
+
*/
|
|
128
|
+
getDimensions() {
|
|
129
|
+
return { width: this.width, height: this.height, depth: this.depth };
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Clear all fields
|
|
133
|
+
*/
|
|
134
|
+
clear() {
|
|
135
|
+
this.density.fill(0);
|
|
136
|
+
this.velocityX.fill(0);
|
|
137
|
+
this.velocityY.fill(0);
|
|
138
|
+
this.velocityZ.fill(0);
|
|
139
|
+
}
|
|
140
|
+
// =========================================================================
|
|
141
|
+
// PRIVATE METHODS
|
|
142
|
+
// =========================================================================
|
|
143
|
+
velocityStep(dt) {
|
|
144
|
+
// Add sources
|
|
145
|
+
this.addSource(this.velocityX, this.velocityX0, dt);
|
|
146
|
+
this.addSource(this.velocityY, this.velocityY0, dt);
|
|
147
|
+
this.addSource(this.velocityZ, this.velocityZ0, dt);
|
|
148
|
+
// Diffuse
|
|
149
|
+
this.swap(this.velocityX0, this.velocityX);
|
|
150
|
+
this.swap(this.velocityY0, this.velocityY);
|
|
151
|
+
this.swap(this.velocityZ0, this.velocityZ);
|
|
152
|
+
this.diffuse(1, this.velocityX, this.velocityX0, this.viscosity, dt);
|
|
153
|
+
this.diffuse(2, this.velocityY, this.velocityY0, this.viscosity, dt);
|
|
154
|
+
this.diffuse(3, this.velocityZ, this.velocityZ0, this.viscosity, dt);
|
|
155
|
+
// Project to make divergence-free
|
|
156
|
+
this.project(this.velocityX, this.velocityY, this.velocityZ, this.velocityX0, this.velocityY0);
|
|
157
|
+
// Advect
|
|
158
|
+
this.swap(this.velocityX0, this.velocityX);
|
|
159
|
+
this.swap(this.velocityY0, this.velocityY);
|
|
160
|
+
this.swap(this.velocityZ0, this.velocityZ);
|
|
161
|
+
this.advect(1, this.velocityX, this.velocityX0, this.velocityX0, this.velocityY0, this.velocityZ0, dt);
|
|
162
|
+
this.advect(2, this.velocityY, this.velocityY0, this.velocityX0, this.velocityY0, this.velocityZ0, dt);
|
|
163
|
+
this.advect(3, this.velocityZ, this.velocityZ0, this.velocityX0, this.velocityY0, this.velocityZ0, dt);
|
|
164
|
+
// Project again
|
|
165
|
+
this.project(this.velocityX, this.velocityY, this.velocityZ, this.velocityX0, this.velocityY0);
|
|
166
|
+
}
|
|
167
|
+
densityStep(dt) {
|
|
168
|
+
// Add sources
|
|
169
|
+
this.addSource(this.density, this.density0, dt);
|
|
170
|
+
// Diffuse
|
|
171
|
+
this.swap(this.density0, this.density);
|
|
172
|
+
this.diffuse(0, this.density, this.density0, this.diffusion, dt);
|
|
173
|
+
// Advect
|
|
174
|
+
this.swap(this.density0, this.density);
|
|
175
|
+
this.advect(0, this.density, this.density0, this.velocityX, this.velocityY, this.velocityZ, dt);
|
|
176
|
+
}
|
|
177
|
+
addSource(target, source, dt) {
|
|
178
|
+
for (let i = 0; i < this.size; i++) {
|
|
179
|
+
target[i] += dt * source[i];
|
|
180
|
+
}
|
|
181
|
+
source.fill(0);
|
|
182
|
+
}
|
|
183
|
+
diffuse(b, x, x0, diff, dt) {
|
|
184
|
+
const a = dt * diff * this.width * this.height * this.depth;
|
|
185
|
+
this.linearSolve(b, x, x0, a, 1 + 6 * a);
|
|
186
|
+
}
|
|
187
|
+
advect(b, d, d0, u, v, w, dt) {
|
|
188
|
+
const dtx = dt * (this.width - 2);
|
|
189
|
+
const dty = dt * (this.height - 2);
|
|
190
|
+
const dtz = dt * (this.depth - 2);
|
|
191
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
192
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
193
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
194
|
+
const idx = this.indexFor(i, j, k);
|
|
195
|
+
// Trace back
|
|
196
|
+
let x = i - dtx * u[idx];
|
|
197
|
+
let y = j - dty * v[idx];
|
|
198
|
+
let z = k - dtz * w[idx];
|
|
199
|
+
// Clamp to grid
|
|
200
|
+
x = Math.max(0.5, Math.min(this.width - 1.5, x));
|
|
201
|
+
y = Math.max(0.5, Math.min(this.height - 1.5, y));
|
|
202
|
+
z = Math.max(0.5, Math.min(this.depth - 1.5, z));
|
|
203
|
+
// Trilinear interpolation
|
|
204
|
+
d[idx] = this.sampleField(d0, x, y, z);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
this.setBoundary(b, d);
|
|
209
|
+
}
|
|
210
|
+
project(u, v, w, p, div) {
|
|
211
|
+
const h = 1.0 / Math.max(this.width, this.height, this.depth);
|
|
212
|
+
// Calculate divergence
|
|
213
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
214
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
215
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
216
|
+
const idx = this.indexFor(i, j, k);
|
|
217
|
+
div[idx] =
|
|
218
|
+
-0.5 *
|
|
219
|
+
h *
|
|
220
|
+
(u[this.indexFor(i + 1, j, k)] -
|
|
221
|
+
u[this.indexFor(i - 1, j, k)] +
|
|
222
|
+
v[this.indexFor(i, j + 1, k)] -
|
|
223
|
+
v[this.indexFor(i, j - 1, k)] +
|
|
224
|
+
w[this.indexFor(i, j, k + 1)] -
|
|
225
|
+
w[this.indexFor(i, j, k - 1)]);
|
|
226
|
+
p[idx] = 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this.setBoundary(0, div);
|
|
231
|
+
this.setBoundary(0, p);
|
|
232
|
+
// Solve for pressure
|
|
233
|
+
this.linearSolve(0, p, div, 1, 6);
|
|
234
|
+
// Subtract pressure gradient from velocity
|
|
235
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
236
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
237
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
238
|
+
const idx = this.indexFor(i, j, k);
|
|
239
|
+
u[idx] -=
|
|
240
|
+
(0.5 *
|
|
241
|
+
(p[this.indexFor(i + 1, j, k)] - p[this.indexFor(i - 1, j, k)])) /
|
|
242
|
+
h;
|
|
243
|
+
v[idx] -=
|
|
244
|
+
(0.5 *
|
|
245
|
+
(p[this.indexFor(i, j + 1, k)] - p[this.indexFor(i, j - 1, k)])) /
|
|
246
|
+
h;
|
|
247
|
+
w[idx] -=
|
|
248
|
+
(0.5 *
|
|
249
|
+
(p[this.indexFor(i, j, k + 1)] - p[this.indexFor(i, j, k - 1)])) /
|
|
250
|
+
h;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
this.setBoundary(1, u);
|
|
255
|
+
this.setBoundary(2, v);
|
|
256
|
+
this.setBoundary(3, w);
|
|
257
|
+
}
|
|
258
|
+
linearSolve(b, x, x0, a, c) {
|
|
259
|
+
const cRecip = 1.0 / c;
|
|
260
|
+
for (let iter = 0; iter < this.iterations; iter++) {
|
|
261
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
262
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
263
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
264
|
+
const idx = this.indexFor(i, j, k);
|
|
265
|
+
x[idx] =
|
|
266
|
+
(x0[idx] +
|
|
267
|
+
a *
|
|
268
|
+
(x[this.indexFor(i + 1, j, k)] +
|
|
269
|
+
x[this.indexFor(i - 1, j, k)] +
|
|
270
|
+
x[this.indexFor(i, j + 1, k)] +
|
|
271
|
+
x[this.indexFor(i, j - 1, k)] +
|
|
272
|
+
x[this.indexFor(i, j, k + 1)] +
|
|
273
|
+
x[this.indexFor(i, j, k - 1)])) *
|
|
274
|
+
cRecip;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
this.setBoundary(b, x);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
setBoundary(b, x) {
|
|
282
|
+
// Set boundary conditions (reflective for velocity, continuous for density)
|
|
283
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
284
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
285
|
+
x[this.indexFor(0, j, k)] =
|
|
286
|
+
b === 1 ? -x[this.indexFor(1, j, k)] : x[this.indexFor(1, j, k)];
|
|
287
|
+
x[this.indexFor(this.width - 1, j, k)] =
|
|
288
|
+
b === 1
|
|
289
|
+
? -x[this.indexFor(this.width - 2, j, k)]
|
|
290
|
+
: x[this.indexFor(this.width - 2, j, k)];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
for (let k = 1; k < this.depth - 1; k++) {
|
|
294
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
295
|
+
x[this.indexFor(i, 0, k)] =
|
|
296
|
+
b === 2 ? -x[this.indexFor(i, 1, k)] : x[this.indexFor(i, 1, k)];
|
|
297
|
+
x[this.indexFor(i, this.height - 1, k)] =
|
|
298
|
+
b === 2
|
|
299
|
+
? -x[this.indexFor(i, this.height - 2, k)]
|
|
300
|
+
: x[this.indexFor(i, this.height - 2, k)];
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (let j = 1; j < this.height - 1; j++) {
|
|
304
|
+
for (let i = 1; i < this.width - 1; i++) {
|
|
305
|
+
x[this.indexFor(i, j, 0)] =
|
|
306
|
+
b === 3 ? -x[this.indexFor(i, j, 1)] : x[this.indexFor(i, j, 1)];
|
|
307
|
+
x[this.indexFor(i, j, this.depth - 1)] =
|
|
308
|
+
b === 3
|
|
309
|
+
? -x[this.indexFor(i, j, this.depth - 2)]
|
|
310
|
+
: x[this.indexFor(i, j, this.depth - 2)];
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
// Corner cases - average of neighbors
|
|
314
|
+
x[this.indexFor(0, 0, 0)] =
|
|
315
|
+
0.33 *
|
|
316
|
+
(x[this.indexFor(1, 0, 0)] +
|
|
317
|
+
x[this.indexFor(0, 1, 0)] +
|
|
318
|
+
x[this.indexFor(0, 0, 1)]);
|
|
319
|
+
x[this.indexFor(0, this.height - 1, 0)] =
|
|
320
|
+
0.33 *
|
|
321
|
+
(x[this.indexFor(1, this.height - 1, 0)] +
|
|
322
|
+
x[this.indexFor(0, this.height - 2, 0)] +
|
|
323
|
+
x[this.indexFor(0, this.height - 1, 1)]);
|
|
324
|
+
x[this.indexFor(0, 0, this.depth - 1)] =
|
|
325
|
+
0.33 *
|
|
326
|
+
(x[this.indexFor(1, 0, this.depth - 1)] +
|
|
327
|
+
x[this.indexFor(0, 1, this.depth - 1)] +
|
|
328
|
+
x[this.indexFor(0, 0, this.depth - 2)]);
|
|
329
|
+
x[this.indexFor(0, this.height - 1, this.depth - 1)] =
|
|
330
|
+
0.33 *
|
|
331
|
+
(x[this.indexFor(1, this.height - 1, this.depth - 1)] +
|
|
332
|
+
x[this.indexFor(0, this.height - 2, this.depth - 1)] +
|
|
333
|
+
x[this.indexFor(0, this.height - 1, this.depth - 2)]);
|
|
334
|
+
x[this.indexFor(this.width - 1, 0, 0)] =
|
|
335
|
+
0.33 *
|
|
336
|
+
(x[this.indexFor(this.width - 2, 0, 0)] +
|
|
337
|
+
x[this.indexFor(this.width - 1, 1, 0)] +
|
|
338
|
+
x[this.indexFor(this.width - 1, 0, 1)]);
|
|
339
|
+
x[this.indexFor(this.width - 1, this.height - 1, 0)] =
|
|
340
|
+
0.33 *
|
|
341
|
+
(x[this.indexFor(this.width - 2, this.height - 1, 0)] +
|
|
342
|
+
x[this.indexFor(this.width - 1, this.height - 2, 0)] +
|
|
343
|
+
x[this.indexFor(this.width - 1, this.height - 1, 1)]);
|
|
344
|
+
x[this.indexFor(this.width - 1, 0, this.depth - 1)] =
|
|
345
|
+
0.33 *
|
|
346
|
+
(x[this.indexFor(this.width - 2, 0, this.depth - 1)] +
|
|
347
|
+
x[this.indexFor(this.width - 1, 1, this.depth - 1)] +
|
|
348
|
+
x[this.indexFor(this.width - 1, 0, this.depth - 2)]);
|
|
349
|
+
x[this.indexFor(this.width - 1, this.height - 1, this.depth - 1)] =
|
|
350
|
+
0.33 *
|
|
351
|
+
(x[this.indexFor(this.width - 2, this.height - 1, this.depth - 1)] +
|
|
352
|
+
x[this.indexFor(this.width - 1, this.height - 2, this.depth - 1)] +
|
|
353
|
+
x[this.indexFor(this.width - 1, this.height - 1, this.depth - 2)]);
|
|
354
|
+
}
|
|
355
|
+
sampleField(field, x, y, z) {
|
|
356
|
+
// Trilinear interpolation
|
|
357
|
+
const i0 = Math.floor(x);
|
|
358
|
+
const i1 = i0 + 1;
|
|
359
|
+
const j0 = Math.floor(y);
|
|
360
|
+
const j1 = j0 + 1;
|
|
361
|
+
const k0 = Math.floor(z);
|
|
362
|
+
const k1 = k0 + 1;
|
|
363
|
+
const sx = x - i0;
|
|
364
|
+
const sy = y - j0;
|
|
365
|
+
const sz = z - k0;
|
|
366
|
+
const c000 = field[this.indexForClamped(i0, j0, k0)];
|
|
367
|
+
const c001 = field[this.indexForClamped(i0, j0, k1)];
|
|
368
|
+
const c010 = field[this.indexForClamped(i0, j1, k0)];
|
|
369
|
+
const c011 = field[this.indexForClamped(i0, j1, k1)];
|
|
370
|
+
const c100 = field[this.indexForClamped(i1, j0, k0)];
|
|
371
|
+
const c101 = field[this.indexForClamped(i1, j0, k1)];
|
|
372
|
+
const c110 = field[this.indexForClamped(i1, j1, k0)];
|
|
373
|
+
const c111 = field[this.indexForClamped(i1, j1, k1)];
|
|
374
|
+
// Interpolate along x
|
|
375
|
+
const c00 = c000 * (1 - sx) + c100 * sx;
|
|
376
|
+
const c01 = c001 * (1 - sx) + c101 * sx;
|
|
377
|
+
const c10 = c010 * (1 - sx) + c110 * sx;
|
|
378
|
+
const c11 = c011 * (1 - sx) + c111 * sx;
|
|
379
|
+
// Interpolate along y
|
|
380
|
+
const c0 = c00 * (1 - sy) + c10 * sy;
|
|
381
|
+
const c1 = c01 * (1 - sy) + c11 * sy;
|
|
382
|
+
// Interpolate along z
|
|
383
|
+
return c0 * (1 - sz) + c1 * sz;
|
|
384
|
+
}
|
|
385
|
+
indexFor(x, y, z) {
|
|
386
|
+
return z * this.width * this.height + y * this.width + x;
|
|
387
|
+
}
|
|
388
|
+
indexForClamped(x, y, z) {
|
|
389
|
+
const ix = Math.min(this.width - 1, Math.max(0, x));
|
|
390
|
+
const iy = Math.min(this.height - 1, Math.max(0, y));
|
|
391
|
+
const iz = Math.min(this.depth - 1, Math.max(0, z));
|
|
392
|
+
return this.indexFor(ix, iy, iz);
|
|
393
|
+
}
|
|
394
|
+
swap(a, b) {
|
|
395
|
+
// Swap contents efficiently
|
|
396
|
+
const temp = new Float32Array(a);
|
|
397
|
+
a.set(b);
|
|
398
|
+
b.set(temp);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Pensieve-specific fluid simulator with aesthetic presets
|
|
403
|
+
*/
|
|
404
|
+
export class PensieveFluidSimulator {
|
|
405
|
+
constructor(size = 64) {
|
|
406
|
+
this.time = 0;
|
|
407
|
+
this.fluid = new StableFluids3D({
|
|
408
|
+
width: size,
|
|
409
|
+
height: size,
|
|
410
|
+
depth: size,
|
|
411
|
+
viscosity: 0.0001,
|
|
412
|
+
diffusion: 0.00001,
|
|
413
|
+
iterations: 4,
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Add a "memory splash" - when a particle enters the pensieve
|
|
418
|
+
*/
|
|
419
|
+
addMemorySplash(position, intensity) {
|
|
420
|
+
this.fluid.addDensity(position.x, position.y, position.z, intensity * 10, 5);
|
|
421
|
+
// Add a slight upward swirl
|
|
422
|
+
this.fluid.addForce(position, new Vector3(0, intensity * 2, 0), 3);
|
|
423
|
+
}
|
|
424
|
+
/**
|
|
425
|
+
* Add ambient swirling motion
|
|
426
|
+
*/
|
|
427
|
+
addSwirl(dt) {
|
|
428
|
+
this.time += dt;
|
|
429
|
+
const dims = this.fluid.getDimensions();
|
|
430
|
+
const center = new Vector3(dims.width / 2, dims.height / 2, dims.depth / 2);
|
|
431
|
+
// Rotating force around Y axis
|
|
432
|
+
const angle = this.time * 0.5;
|
|
433
|
+
const radius = dims.width * 0.3;
|
|
434
|
+
const pos = new Vector3(center.x + Math.cos(angle) * radius, center.y, center.z + Math.sin(angle) * radius);
|
|
435
|
+
const tangent = new Vector3(-Math.sin(angle), 0, Math.cos(angle));
|
|
436
|
+
this.fluid.addForce(pos, tangent, radius * 0.5);
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Step the simulation
|
|
440
|
+
*/
|
|
441
|
+
step(dt) {
|
|
442
|
+
this.addSwirl(dt);
|
|
443
|
+
this.fluid.step(dt);
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Get velocity at a point for particle advection
|
|
447
|
+
*/
|
|
448
|
+
getVelocityAt(pos) {
|
|
449
|
+
return this.fluid.getVelocityAt(pos);
|
|
450
|
+
}
|
|
451
|
+
/**
|
|
452
|
+
* Get the underlying fluid for direct access
|
|
453
|
+
*/
|
|
454
|
+
getFluid() {
|
|
455
|
+
return this.fluid;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Clear the simulation
|
|
459
|
+
*/
|
|
460
|
+
clear() {
|
|
461
|
+
this.fluid.clear();
|
|
462
|
+
this.time = 0;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WebGPU Implementation of Fluid Simulation (Fallback)
|
|
3
|
+
*/
|
|
4
|
+
import { Vector3 } from '../math/Vector3';
|
|
5
|
+
import type { FluidConfig3D } from './FluidSimulation3D';
|
|
6
|
+
export declare class FluidSimulation3DGPU {
|
|
7
|
+
private width;
|
|
8
|
+
private height;
|
|
9
|
+
private depth;
|
|
10
|
+
private size;
|
|
11
|
+
private context;
|
|
12
|
+
private device;
|
|
13
|
+
private densityTextures;
|
|
14
|
+
private velocityTextures;
|
|
15
|
+
private pressureTextures;
|
|
16
|
+
private divergenceTexture;
|
|
17
|
+
private advectPipeline;
|
|
18
|
+
private diffusePipeline;
|
|
19
|
+
private divergencePipeline;
|
|
20
|
+
private subtractGradientPipeline;
|
|
21
|
+
private sampler;
|
|
22
|
+
private uniformBuffer;
|
|
23
|
+
private jacobiBuffer;
|
|
24
|
+
private viscosity;
|
|
25
|
+
private diffusion;
|
|
26
|
+
private iterations;
|
|
27
|
+
constructor(config: FluidConfig3D);
|
|
28
|
+
initialize(): Promise<boolean>;
|
|
29
|
+
step(dt: number): Promise<void>;
|
|
30
|
+
private dispatchAdvect;
|
|
31
|
+
private dispatchDiffuse;
|
|
32
|
+
private dispatchDivergence;
|
|
33
|
+
private dispatchPressure;
|
|
34
|
+
private dispatchSubtractGradient;
|
|
35
|
+
addDensity(x: number, y: number, z: number, amount: number, radius: number): void;
|
|
36
|
+
addForce(pos: Vector3, force: Vector3, radius: number): void;
|
|
37
|
+
getDensityAt(pos: Vector3): number;
|
|
38
|
+
getVelocityAt(pos: Vector3): Vector3;
|
|
39
|
+
clear(): void;
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=FluidSimulation3DGPU.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FluidSimulation3DGPU.d.ts","sourceRoot":"","sources":["../../src/algorithms/FluidSimulation3DGPU.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE1C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,IAAI,CAAS;IAErB,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,MAAM,CAA0B;IAGxC,OAAO,CAAC,eAAe,CAAyC;IAChE,OAAO,CAAC,gBAAgB,CAAyC;IACjE,OAAO,CAAC,gBAAgB,CAAyC;IACjE,OAAO,CAAC,iBAAiB,CAA2B;IAGpD,OAAO,CAAC,cAAc,CAAmC;IACzD,OAAO,CAAC,eAAe,CAAmC;IAC1D,OAAO,CAAC,kBAAkB,CAAmC;IAC7D,OAAO,CAAC,wBAAwB,CAAmC;IAEnE,OAAO,CAAC,OAAO,CAA2B;IAC1C,OAAO,CAAC,aAAa,CAA0B;IAC/C,OAAO,CAAC,YAAY,CAA0B;IAE9C,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAS;gBAEf,MAAM,EAAE,aAAa;IAY3B,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC;IAuE9B,IAAI,CAAC,EAAE,EAAE,MAAM;IAsCrB,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,eAAe;IAkDvB,OAAO,CAAC,kBAAkB;IAkB1B,OAAO,CAAC,gBAAgB;IAgExB,OAAO,CAAC,wBAAwB;IA2BhC,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAyB1E,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM;IAsBrD,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM;IAKlC,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO;IAIpC,KAAK;CAGN"}
|