Skip to content

Commit c5efd65

Browse files
authored
fix: Use a more compatible texture format for stable-fluids example and add touch controls (#1251)
1 parent 0aa8c5c commit c5efd65

File tree

3 files changed

+51
-37
lines changed

3 files changed

+51
-37
lines changed

apps/typegpu-docs/src/content/examples/simulation/stable-fluid/index.ts

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,15 @@ import {
1313
renderLayout,
1414
} from './render.ts';
1515
import * as c from './simulation.ts';
16-
import type { BrushState, DisplayMode, FieldFormat } from './types.ts';
16+
import type { BrushState, DisplayMode } from './types.ts';
1717

1818
// Initialize
1919
const adapter = await navigator.gpu.requestAdapter();
2020
if (!adapter) {
2121
throw new Error('No GPU adapter found');
2222
}
23-
const device = await adapter.requestDevice({
24-
requiredFeatures: ['float32-filterable'],
25-
});
26-
const root = tgpu.initFromDevice({ device });
23+
const root = await tgpu.init();
24+
const device = root.device;
2725

2826
// Setup canvas
2927
const canvas = document.querySelector('canvas') as HTMLCanvasElement;
@@ -37,9 +35,9 @@ context.configure({
3735
});
3836

3937
// Helpers
40-
function createField(format: FieldFormat, name: string) {
38+
function createField(name: string) {
4139
return root['~unstable']
42-
.createTexture({ size: [p.SIM_N, p.SIM_N], format })
40+
.createTexture({ size: [p.SIM_N, p.SIM_N], format: 'rgba16float' })
4341
.$usage('storage', 'sampled')
4442
.$name(name);
4543
}
@@ -120,22 +118,13 @@ device.queue.copyExternalImageToTexture(
120118
);
121119

122120
// Create simulation textures
123-
const velTex = [
124-
createField('rg32float', 'velocity0'),
125-
createField('rg32float', 'velocity1'),
126-
];
127-
const inkTex = [
128-
createField('r32float', 'density0'),
129-
createField('r32float', 'density1'),
130-
];
131-
const pressureTex = [
132-
createField('r32float', 'pressure0'),
133-
createField('r32float', 'pressure1'),
134-
];
135-
136-
const newInkTex = createField('r32float', 'addedInk');
137-
const forceTex = createField('rg32float', 'force');
138-
const divergenceTex = createField('r32float', 'divergence');
121+
const velTex = [createField('velocity0'), createField('velocity1')];
122+
const inkTex = [createField('density0'), createField('density1')];
123+
const pressureTex = [createField('pressure0'), createField('pressure1')];
124+
125+
const newInkTex = createField('addedInk');
126+
const forceTex = createField('force');
127+
const divergenceTex = createField('divergence');
139128

140129
const linSampler = tgpu['~unstable'].sampler({
141130
magFilter: 'linear',
@@ -419,17 +408,43 @@ canvas.addEventListener('mousedown', (e) => {
419408
isDown: true,
420409
};
421410
});
411+
canvas.addEventListener('touchstart', (e) => {
412+
e.preventDefault();
413+
const touch = e.touches[0];
414+
const rect = canvas.getBoundingClientRect();
415+
const x = (touch.clientX - rect.left) * devicePixelRatio;
416+
const y = (touch.clientY - rect.top) * devicePixelRatio;
417+
brushState = {
418+
pos: toGrid(x, y),
419+
delta: [0, 0],
420+
isDown: true,
421+
};
422+
}, { passive: false });
423+
422424
window.addEventListener('mouseup', () => {
423425
brushState.isDown = false;
424426
});
427+
window.addEventListener('touchend', () => {
428+
brushState.isDown = false;
429+
});
430+
425431
canvas.addEventListener('mousemove', (e) => {
426432
const x = e.offsetX * devicePixelRatio;
427433
const y = e.offsetY * devicePixelRatio;
428-
429434
const [newX, newY] = toGrid(x, y);
430435
brushState.delta = [newX - brushState.pos[0], newY - brushState.pos[1]];
431436
brushState.pos = [newX, newY];
432437
});
438+
canvas.addEventListener('touchmove', (e) => {
439+
e.preventDefault();
440+
const touch = e.touches[0];
441+
const rect = canvas.getBoundingClientRect();
442+
const x = (touch.clientX - rect.left) * devicePixelRatio;
443+
const y = (touch.clientY - rect.top) * devicePixelRatio;
444+
const [newX, newY] = toGrid(x, y);
445+
brushState.delta = [newX - brushState.pos[0], newY - brushState.pos[1]];
446+
brushState.pos = [newX, newY];
447+
}, { passive: false });
433448

434449
function hideHelp() {
435450
const helpElem = document.getElementById('help');

apps/typegpu-docs/src/content/examples/simulation/stable-fluid/simulation.ts

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const getNeighbors = tgpu['~unstable'].fn(
1616
for (let i = 0; i < 4; i++) {
1717
adjacentOffsets[i] = std.clamp(
1818
std.add(coords, adjacentOffsets[i]),
19-
d.vec2i(0),
19+
d.vec2i(),
2020
std.sub(bounds, d.vec2i(1)),
2121
);
2222
}
@@ -25,8 +25,8 @@ const getNeighbors = tgpu['~unstable'].fn(
2525

2626
export const brushLayout = tgpu.bindGroupLayout({
2727
brushParams: { uniform: p.BrushParams },
28-
forceDst: { storageTexture: 'rg32float', access: 'writeonly' },
29-
inkDst: { storageTexture: 'r32float', access: 'writeonly' },
28+
forceDst: { storageTexture: 'rgba16float', access: 'writeonly' },
29+
inkDst: { storageTexture: 'rgba16float', access: 'writeonly' },
3030
});
3131

3232
export const brushFn = tgpu['~unstable'].computeFn({
@@ -67,7 +67,7 @@ export const brushFn = tgpu['~unstable'].computeFn({
6767

6868
export const addForcesLayout = tgpu.bindGroupLayout({
6969
src: { texture: 'float' },
70-
dst: { storageTexture: 'rg32float', access: 'writeonly' },
70+
dst: { storageTexture: 'rgba16float', access: 'writeonly' },
7171
force: { texture: 'float' },
7272
simParams: { uniform: p.ShaderParams },
7373
});
@@ -86,7 +86,7 @@ export const addForcesFn = tgpu['~unstable'].computeFn({
8686

8787
export const advectLayout = tgpu.bindGroupLayout({
8888
src: { texture: 'float' },
89-
dst: { storageTexture: 'rg32float', access: 'writeonly' },
89+
dst: { storageTexture: 'rgba16float', access: 'writeonly' },
9090
simParams: { uniform: p.ShaderParams },
9191
linSampler: { sampler: 'filtering' },
9292
});
@@ -131,7 +131,7 @@ export const advectFn = tgpu['~unstable'].computeFn({
131131

132132
export const diffusionLayout = tgpu.bindGroupLayout({
133133
in: { texture: 'float' },
134-
out: { storageTexture: 'rg32float', access: 'writeonly' },
134+
out: { storageTexture: 'rgba16float', access: 'writeonly' },
135135
simParams: { uniform: p.ShaderParams },
136136
});
137137

@@ -170,7 +170,7 @@ export const diffusionFn = tgpu['~unstable'].computeFn({
170170

171171
export const divergenceLayout = tgpu.bindGroupLayout({
172172
vel: { texture: 'float' },
173-
div: { storageTexture: 'r32float', access: 'writeonly' },
173+
div: { storageTexture: 'rgba16float', access: 'writeonly' },
174174
});
175175

176176
export const divergenceFn = tgpu['~unstable'].computeFn({
@@ -189,7 +189,7 @@ export const divergenceFn = tgpu['~unstable'].computeFn({
189189
const rightVel = std.textureLoad(divergenceLayout.$.vel, neighbors[2], 0);
190190
const downVel = std.textureLoad(divergenceLayout.$.vel, neighbors[3], 0);
191191

192-
const divergence = d.f32(0.5) *
192+
const divergence = 0.5 *
193193
(rightVel.x - leftVel.x + (downVel.y - upVel.y));
194194
std.textureStore(
195195
divergenceLayout.$.div,
@@ -201,7 +201,7 @@ export const divergenceFn = tgpu['~unstable'].computeFn({
201201
export const pressureLayout = tgpu.bindGroupLayout({
202202
x: { texture: 'float' },
203203
b: { texture: 'float' },
204-
out: { storageTexture: 'r32float', access: 'writeonly' },
204+
out: { storageTexture: 'rgba16float', access: 'writeonly' },
205205
});
206206

207207
export const pressureFn = tgpu['~unstable'].computeFn({
@@ -232,7 +232,7 @@ export const pressureFn = tgpu['~unstable'].computeFn({
232232
export const projectLayout = tgpu.bindGroupLayout({
233233
vel: { texture: 'float' },
234234
p: { texture: 'float' },
235-
out: { storageTexture: 'rg32float', access: 'writeonly' },
235+
out: { storageTexture: 'rgba16float', access: 'writeonly' },
236236
});
237237

238238
export const projectFn = tgpu['~unstable'].computeFn({
@@ -261,7 +261,7 @@ export const projectFn = tgpu['~unstable'].computeFn({
261261
export const advectInkLayout = tgpu.bindGroupLayout({
262262
vel: { texture: 'float' },
263263
src: { texture: 'float' },
264-
dst: { storageTexture: 'r32float', access: 'writeonly' },
264+
dst: { storageTexture: 'rgba16float', access: 'writeonly' },
265265
simParams: { uniform: p.ShaderParams },
266266
linSampler: { sampler: 'filtering' },
267267
});
@@ -297,7 +297,7 @@ export const advectInkFn = tgpu['~unstable'].computeFn({
297297

298298
export const addInkLayout = tgpu.bindGroupLayout({
299299
src: { texture: 'float' },
300-
dst: { storageTexture: 'r32float', access: 'writeonly' },
300+
dst: { storageTexture: 'rgba16float', access: 'writeonly' },
301301
add: { texture: 'float' },
302302
});
303303

apps/typegpu-docs/src/content/examples/simulation/stable-fluid/types.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export type FieldFormat = 'rg32float' | 'r32float';
21
export type DisplayMode = 'ink' | 'velocity' | 'image';
32

43
export type SimulationParams = {

0 commit comments

Comments
 (0)