Skip to content

Commit 5f8a19a

Browse files
authored
Merge pull request #8531 from processing/compute-shaders
WebGPU compute shaders
2 parents 24a08dc + 458ce4d commit 5f8a19a

File tree

50 files changed

+3153
-683
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+3153
-683
lines changed

docs/parameterData.json

Lines changed: 525 additions & 477 deletions
Large diffs are not rendered by default.

preview/index.html

Lines changed: 75 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@
3232
let env;
3333
let instance;
3434

35+
// Compute shader variables
36+
let computeShader;
37+
let particleBuffer;
38+
let bouncingCirclesShader;
39+
let circleGeometry;
40+
const NUM_CIRCLES = 100;
41+
const RADIUS = 2;
42+
3543
p.setup = async function () {
3644
await p.createCanvas(400, 400, p.WEBGPU);
3745
env = await p.loadImage('img/spheremap.jpg');
@@ -41,6 +49,7 @@
4149
fbo = p.createFramebuffer();
4250

4351
instance = p.buildGeometry(() => p.sphere(5));
52+
circleGeometry = p.buildGeometry(() => p.sphere(RADIUS));
4453

4554
redFilter = p.baseFilterShader().modify(() => {
4655
p.getColor((inputs, canvasContent) => {
@@ -64,22 +73,10 @@
6473
}
6574
tex.updatePixels();
6675
fbo.draw(() => {
67-
//p.clear();
68-
//p.background('orange');
6976
p.imageMode(p.CENTER);
7077
p.image(tex, 0, 0, p.width, p.height);
7178
});
7279

73-
/*sh = p.baseMaterialShader().modify({
74-
uniforms: {
75-
'f32 time': () => p.millis(),
76-
},
77-
'Vertex getWorldInputs': `(inputs: Vertex) {
78-
var result = inputs;
79-
result.position.y += 40.0 * sin(uniforms.time * 0.005);
80-
return result;
81-
}`,
82-
})*/
8380
sh = p.baseMaterialShader().modify(() => {
8481
const time = p.uniformFloat(() => p.millis());
8582
p.getWorldInputs((inputs) => {
@@ -93,19 +90,67 @@
9390
return inputs;
9491
});
9592
}, { p })
96-
/*ssh = p.baseStrokeShader().modify({
97-
uniforms: {
98-
'f32 time': () => p.millis(),
99-
},
100-
'StrokeVertex getWorldInputs': `(inputs: StrokeVertex) {
101-
var result = inputs;
102-
result.position.y += 40.0 * sin(uniforms.time * 0.005);
103-
return result;
104-
}`,
105-
})*/
93+
94+
// Initialize storage buffers with random positions and velocities
95+
const initialParticles = [];
96+
for (let i = 0; i < NUM_CIRCLES; i++) {
97+
initialParticles.push({
98+
position: [p.random(-150, 150), p.random(-150, 150)],
99+
velocity: [
100+
0.1 * p.random(1, 3) * (p.random() > 0.5 ? 1 : -1),
101+
0.1 * p.random(1, 3) * (p.random() > 0.5 ? 1 : -1)
102+
]
103+
})
104+
}
105+
106+
particleBuffer = p.createStorage(initialParticles);
107+
108+
// Create compute shader for physics simulation
109+
computeShader = p.buildComputeShader(() => {
110+
const particles = p.uniformStorage('particles', particleBuffer);
111+
const bounds = p.uniformVec2(() => [p.width / 2 - RADIUS, p.height / 2 - RADIUS]);
112+
const deltaTime = p.uniformFloat(() => p.deltaTime * 0.1);
113+
114+
const idx = p.index.x;
115+
116+
// Read current position and velocity
117+
let position = particles[idx].position;
118+
let velocity = particles[idx].velocity;
119+
120+
// Update position
121+
position += velocity * deltaTime;
122+
123+
// Bounce off boundaries
124+
if (position.x > bounds.x || position.x < -bounds.x) {
125+
velocity.x = -velocity.x;
126+
position.x = p.clamp(position.x, -bounds.x, bounds.x);
127+
}
128+
if (position.y > bounds.y || position.y < -bounds.y) {
129+
velocity.y = -velocity.y;
130+
position.y = p.clamp(position.y, -bounds.y, bounds.y);
131+
}
132+
133+
particles[idx].position = position;
134+
particles[idx].velocity = velocity;
135+
}, { p, RADIUS, particleBuffer });
136+
137+
// Shader for rendering bouncing circles from storage buffer
138+
bouncingCirclesShader = p.baseMaterialShader().modify(() => {
139+
const particles = p.uniformStorage('particles', particleBuffer);
140+
141+
p.getWorldInputs((inputs) => {
142+
const instanceIdx = p.instanceID();
143+
inputs.position.xy += particles[instanceIdx].position;
144+
return inputs;
145+
});
146+
}, { p, particleBuffer });
106147
};
107148

108149
p.draw = function () {
150+
// Run compute shader to update physics
151+
debugger
152+
p.compute(computeShader, NUM_CIRCLES);
153+
109154
p.clear();
110155
p.rotateY(p.millis() * 0.001);
111156
p.push();
@@ -168,6 +213,14 @@
168213
p.model(instance, 10);
169214
p.pop();
170215

216+
// Draw compute shader-driven bouncing circles
217+
p.push();
218+
p.shader(bouncingCirclesShader);
219+
p.noStroke();
220+
p.fill('#4ECDC4');
221+
p.model(circleGeometry, NUM_CIRCLES);
222+
p.pop();
223+
171224
// Test beginShape/endShape with immediate mode shapes
172225
p.push();
173226
p.translate(0, 100, 0);

src/color/p5.Color.js

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,13 @@ class Color {
6161
static #colorjsMaxes = {};
6262
static #grayscaleMap = {};
6363

64+
// This property is here where duck typing (checking if obj.isColor) needs
65+
// to be used over more standard type checking (obj instanceof Color). This
66+
// needs to happen where we are building multiple files, such as in p5.webgpu.js,
67+
// where if we `import { Color }` directly, it will be a separate copy of the
68+
// Color class from the one imported in the main p5.js bundle.
69+
isColor = true;
70+
6471
// Used to add additional color modes to p5.js
6572
// Uses underlying library's definition
6673
static addColorMode(mode, definition){
@@ -364,7 +371,7 @@ class Color {
364371
if (format === undefined && this._defaultStringValue !== undefined) {
365372
return this._defaultStringValue;
366373
}
367-
374+
368375
let outputFormat = format;
369376
if (format === '#rrggbb') {
370377
outputFormat = 'hex';
@@ -377,10 +384,10 @@ class Color {
377384
colorString = serialize(this._color, {
378385
format: outputFormat
379386
});
380-
387+
381388
if (format === '#rrggbb') {
382389
colorString = String(colorString);
383-
if (colorString.length === 4) {
390+
if (colorString.length === 4) {
384391
const r = colorString[1];
385392
const g = colorString[2];
386393
const b = colorString[3];

0 commit comments

Comments
 (0)