|
23 | 23 | p5.registerAddon(rendererWebGPU); |
24 | 24 |
|
25 | 25 | const sketch = function (p) { |
26 | | - p.setup = async function() { |
| 26 | + let fbo; |
| 27 | + let sh, sh2; |
| 28 | + let ssh; |
| 29 | + let tex; |
| 30 | + let font; |
| 31 | + let redFilter; |
| 32 | + let env; |
| 33 | + let instance; |
| 34 | + |
| 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 | + |
| 43 | + p.setup = async function () { |
27 | 44 | await p.createCanvas(400, 400, p.WEBGPU); |
28 | | - p.background(0) |
29 | | - } |
30 | | - p.draw = function() { |
| 45 | + env = await p.loadImage('img/spheremap.jpg'); |
| 46 | + font = await p.loadFont( |
| 47 | + 'font/PlayfairDisplay.ttf' |
| 48 | + ); |
| 49 | + fbo = p.createFramebuffer(); |
| 50 | + |
| 51 | + instance = p.buildGeometry(() => p.sphere(5)); |
| 52 | + circleGeometry = p.buildGeometry(() => p.sphere(RADIUS)); |
| 53 | + |
| 54 | + redFilter = p.baseFilterShader().modify(() => { |
| 55 | + p.getColor((inputs, canvasContent) => { |
| 56 | + let col = p.getTexture(canvasContent, inputs.texCoord); |
| 57 | + col.g = col.r; |
| 58 | + col.b = col.r; |
| 59 | + return col; |
| 60 | + }) |
| 61 | + }, { p }) |
| 62 | + |
| 63 | + tex = p.createImage(100, 100); |
| 64 | + tex.loadPixels(); |
| 65 | + for (let x = 0; x < tex.width; x++) { |
| 66 | + for (let y = 0; y < tex.height; y++) { |
| 67 | + const off = (x + y * tex.width) * 4; |
| 68 | + tex.pixels[off] = p.round((x / tex.width) * 255); |
| 69 | + tex.pixels[off + 1] = p.round((y / tex.height) * 255); |
| 70 | + tex.pixels[off + 2] = 0; |
| 71 | + tex.pixels[off + 3] = 255; |
| 72 | + } |
| 73 | + } |
| 74 | + tex.updatePixels(); |
| 75 | + fbo.draw(() => { |
| 76 | + p.imageMode(p.CENTER); |
| 77 | + p.image(tex, 0, 0, p.width, p.height); |
| 78 | + }); |
| 79 | + |
| 80 | + sh = p.baseMaterialShader().modify(() => { |
| 81 | + const time = p.uniformFloat(() => p.millis()); |
| 82 | + p.getWorldInputs((inputs) => { |
| 83 | + inputs.position.y += 40 * p.sin(time * 0.005); |
| 84 | + return inputs; |
| 85 | + }); |
| 86 | + }, { p }) |
| 87 | + sh2 = p.baseMaterialShader().modify(() => { |
| 88 | + p.getWorldInputs((inputs) => { |
| 89 | + inputs.position.x += 20 * p.instanceID(); |
| 90 | + return inputs; |
| 91 | + }); |
| 92 | + }, { p }) |
| 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 }); |
| 147 | + }; |
| 148 | + |
| 149 | + p.draw = function () { |
| 150 | + // Run compute shader to update physics |
31 | 151 | debugger |
32 | | - p.push() |
33 | | - p.fill(0, 1) |
| 152 | + p.compute(computeShader, NUM_CIRCLES); |
| 153 | + |
| 154 | + p.clear(); |
| 155 | + p.rotateY(p.millis() * 0.001); |
| 156 | + p.push(); |
| 157 | + //p.clip(() => p.rect(-50, -50, 200, 200)); |
| 158 | + /*p.orbitControl(); |
| 159 | + p.push(); |
| 160 | + p.textAlign(p.CENTER, p.CENTER); |
| 161 | + p.textFont(font); |
| 162 | + p.textSize(85) |
| 163 | + p.fill('red') |
34 | 164 | p.noStroke() |
35 | | - //p.plane(p.width, p.height) |
36 | | - p.rectMode(p.CENTER) |
37 | | - p.rect(0, 0, p.width, p.height) |
| 165 | + p.rect(0, 0, 100, 100); |
| 166 | + p.fill(0); |
| 167 | + p.push() |
| 168 | + p.rotate(p.millis() * 0.001) |
| 169 | + p.text('Hello!', 0, 0); |
38 | 170 | p.pop() |
39 | | - |
40 | | - p.fill(255) |
41 | | - p.noStroke() |
42 | | - p.circle( |
43 | | - 100 * p.sin(p.frameCount * 0.1), |
44 | | - 0, |
45 | | - 50 |
46 | | - ) |
47 | | - } |
| 171 | + p.pop(); |
| 172 | + return;*/ |
| 173 | + p.orbitControl(); |
| 174 | + const t = p.millis() * 0.002; |
| 175 | + p.background(200); |
| 176 | + p.panorama(env); |
| 177 | + p.push(); |
| 178 | + p.imageLight(env); |
| 179 | + p.shader(sh); |
| 180 | + // p.strokeShader(ssh) |
| 181 | + p.ambientLight(10); |
| 182 | + //p.directionalLight(100, 100, 100, 0, 1, -1); |
| 183 | + //p.pointLight(155, 155, 155, 0, -200, 500); |
| 184 | + p.specularMaterial(255); |
| 185 | + p.shininess(50); |
| 186 | + p.metalness(100); |
| 187 | + //p.stroke('white'); |
| 188 | + p.noStroke(); |
| 189 | + for (const [i, c] of ['red', 'gray', 'blue'].entries()) { |
| 190 | + p.push(); |
| 191 | + p.fill(c); |
| 192 | + p.translate( |
| 193 | + p.width/3 * p.sin(t + i * Math.E), |
| 194 | + 0, //p.width/3 * p.sin(t * 0.9 + i * Math.E + 0.2), |
| 195 | + p.width/3 * p.sin(t * 1.2 + i * Math.E + 0.3), |
| 196 | + ) |
| 197 | + if (i % 2 === 0) { |
| 198 | + if (i === 0) { |
| 199 | + p.texture(fbo) |
| 200 | + } |
| 201 | + p.box(30); |
| 202 | + } else { |
| 203 | + p.sphere(30); |
| 204 | + } |
| 205 | + p.pop(); |
| 206 | + } |
| 207 | + p.pop(); |
| 208 | + |
| 209 | + p.push(); |
| 210 | + p.shader(sh2); |
| 211 | + p.noStroke(); |
| 212 | + p.fill('red'); |
| 213 | + p.model(instance, 10); |
| 214 | + p.pop(); |
| 215 | + |
| 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 | + |
| 224 | + // Test beginShape/endShape with immediate mode shapes |
| 225 | + p.push(); |
| 226 | + p.translate(0, 100, 0); |
| 227 | + p.fill('yellow'); |
| 228 | + p.noStroke(); |
| 229 | + |
| 230 | + // Draw a circle using beginShape/endShape |
| 231 | + p.beginShape(); |
| 232 | + const numPoints = 16; |
| 233 | + for (let i = 0; i < numPoints; i++) { |
| 234 | + const angle = (i / numPoints) * Math.PI * 2; |
| 235 | + const x = Math.cos(angle) * 50; |
| 236 | + const y = Math.sin(angle) * 50; |
| 237 | + p.vertex(x, y); |
| 238 | + } |
| 239 | + p.endShape(p.CLOSE); |
| 240 | + |
| 241 | + p.translate(100, 0, 0); |
| 242 | + p.fill('purple'); |
| 243 | + |
| 244 | + // Draw a square using beginShape/endShape |
| 245 | + p.beginShape(); |
| 246 | + p.vertex(-30, -30); |
| 247 | + p.vertex(30, -30); |
| 248 | + p.vertex(30, 30); |
| 249 | + p.vertex(-30, 30); |
| 250 | + p.endShape(p.CLOSE); |
| 251 | + |
| 252 | + p.pop(); |
| 253 | + |
| 254 | + // p.filter(p.BLUR, 10) |
| 255 | + p.pop(); |
| 256 | + }; |
48 | 257 | }; |
49 | 258 |
|
50 | 259 | new p5(sketch); |
|
0 commit comments