Skip to content

Commit 9723d3e

Browse files
committed
docs: Vector field example
1 parent 08fb40f commit 9723d3e

4 files changed

Lines changed: 158 additions & 0 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<canvas></canvas>
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import {
2+
caps,
3+
endCapSlot,
4+
LineControlPoint,
5+
lineSegmentIndices,
6+
lineSegmentVariableWidth,
7+
startCapSlot,
8+
} from '@typegpu/geometry';
9+
import tgpu, { d, std } from 'typegpu';
10+
import { defineControls } from '../../common/defineControls.ts';
11+
12+
const root = await tgpu.init();
13+
14+
const context = root.configureContext({
15+
canvas: document.querySelector('canvas')!,
16+
alphaMode: 'premultiplied',
17+
});
18+
19+
const GRID_SIZE = 4;
20+
21+
const MAX_JOIN_COUNT = 0; // I assume it's zero, as I want the line to be straight
22+
const indices = lineSegmentIndices(MAX_JOIN_COUNT);
23+
const indexBuffer = root.createBuffer(d.arrayOf(d.u16, indices.length), indices).$usage('index');
24+
25+
const mainVertex = tgpu.vertexFn({
26+
in: {
27+
instanceIndex: d.builtin.instanceIndex,
28+
vertexIndex: d.builtin.vertexIndex,
29+
},
30+
out: {
31+
outPos: d.builtin.position,
32+
},
33+
})(({ vertexIndex, instanceIndex: arrowIdx }) => {
34+
'use gpu';
35+
const arrowX = arrowIdx % GRID_SIZE;
36+
const arrowY = d.u32(arrowIdx / GRID_SIZE);
37+
// An arrow pointing to the top-right corner
38+
const startPos = d.vec2f(arrowX, arrowY) / GRID_SIZE;
39+
const endPos = (d.vec2f(arrowX, arrowY) + 1) / GRID_SIZE;
40+
41+
const A = LineControlPoint({
42+
position: startPos,
43+
radius: 0.02,
44+
});
45+
const B = LineControlPoint({
46+
position: std.mix(startPos, endPos, 0.25),
47+
radius: 0.02,
48+
});
49+
const C = LineControlPoint({
50+
position: std.mix(startPos, endPos, 0.75),
51+
radius: 0.02,
52+
});
53+
const D = LineControlPoint({
54+
position: endPos,
55+
radius: 0.02,
56+
});
57+
58+
const result = lineSegmentVariableWidth(vertexIndex, A, B, C, D, MAX_JOIN_COUNT);
59+
60+
return {
61+
outPos: d.vec4f(result.vertexPosition, 0, 1),
62+
};
63+
});
64+
65+
const mainFragment = tgpu.fragmentFn({
66+
out: d.vec4f,
67+
})(() => {
68+
'use gpu';
69+
return d.vec4f(1, 0, 0, 1);
70+
});
71+
72+
const pipeline = root
73+
.with(startCapSlot, caps.butt)
74+
.with(endCapSlot, caps.arrow)
75+
.createRenderPipeline({
76+
vertex: mainVertex,
77+
fragment: mainFragment,
78+
})
79+
.withIndexBuffer(indexBuffer)
80+
.withColorAttachment({
81+
view: context,
82+
clearValue: [1, 1, 1, 1],
83+
});
84+
85+
const draw = () => {
86+
pipeline.drawIndexed(indices.length, GRID_SIZE * GRID_SIZE);
87+
};
88+
89+
function frame() {
90+
draw();
91+
frameId = requestAnimationFrame(frame);
92+
}
93+
94+
let frameId = requestAnimationFrame(frame);
95+
96+
// #region Example controls & Cleanup
97+
98+
export const controls = defineControls({
99+
Randomize: {
100+
onButtonClick() {},
101+
},
102+
});
103+
104+
export function onCleanup() {
105+
root.destroy();
106+
cancelAnimationFrame(frameId);
107+
}
108+
109+
// #endregion
110+
111+
/*
112+
import tgpu, { d, std } from 'typegpu';
113+
import { randf } from '@typegpu/noise';
114+
import type { AnyWgslData } from 'typegpu/data';
115+
116+
// { device: { optionalFeatures: ['shader-f16'] } }
117+
const root = await tgpu.init();
118+
119+
const size = 4;
120+
121+
const arrayNxN = <T extends AnyWgslData>(element: T, w: number, h: number) =>
122+
d.arrayOf(d.arrayOf(element, w), h);
123+
124+
const displacementBuffer = root.createBuffer(arrayNxN(d.vec2h, size, size)).$usage('storage');
125+
const displacementPackedBuffer = root
126+
.createBuffer(arrayNxN(d.u32, size, size), root.unwrap(displacementBuffer))
127+
.$usage('storage');
128+
129+
const displacementView = displacementBuffer.as('mutable');
130+
const displacementPackedView = displacementPackedBuffer.as('mutable');
131+
132+
function main(x: number, y: number) {
133+
'use gpu';
134+
135+
const dir = randf.onUnitCircle();
136+
137+
if (std.extensionEnabled('f16')) {
138+
displacementView.$[x][y] = d.vec2h(dir);
139+
} else {
140+
displacementPackedView.$[x][y] = std.pack2x16float(dir);
141+
}
142+
}
143+
144+
const pipeline = root.createGuardedComputePipeline(main);
145+
146+
pipeline.dispatchThreads(size, size);
147+
148+
console.log(await displacementBuffer.read());
149+
150+
*/
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"title": "Vector Field",
3+
"category": "simulation",
4+
"tags": ["ecosystem", "line-rendering", "particles", "vector field"],
5+
"dev": true,
6+
"coolFactor": 7
7+
}
524 KB
Loading

0 commit comments

Comments
 (0)