Repository navigation
Add Shaders examples section + some new examples #1635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
eec8b9d
91aec09
cd815a1
ae276a7
a161b3b
f8feb52
2e5851a
497ec6a
7625bc3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| let gradientShader; | ||
| function setup() { | ||
| createCanvas(400, 400, WEBGL); | ||
| gradientShader = buildFilterShader(gradient); | ||
| } | ||
|
|
||
| // This function is p5.strands code: it's like JavaScript, but | ||
| // where you can write vectors as arrays and use math oeprators on them | ||
| function gradient() { | ||
| // filterColor is an example of a *hook* in a strands shader, which | ||
| // lets you control different parts of the shader's job | ||
| filterColor.begin(); | ||
| // Texture coordinates like filterColor.texCoord go from [0,0] in the | ||
| // top left to [1,1] in the bottom right | ||
| let start = [0.1, 0.1]; | ||
| // Convert mouse coords to texture coordinate range by dividing | ||
| // by canvas size | ||
| let end = [mouseX, mouseY] / [width, height]; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Every place where the sketch author needs to switch to [0,1] range logic could also use a comment imo |
||
| let startToPixel = length(filterColor.texCoord - start); | ||
| let startToEnd = length(end - start); | ||
| let gradientProgress = map( | ||
| startToPixel, | ||
| 0, | ||
| startToEnd, | ||
| 0, | ||
| 1, | ||
| true | ||
| ); | ||
| let outColor = lerpColor( | ||
| color('#F00'), | ||
| color('#0214f3'), | ||
| gradientProgress | ||
| ); | ||
| filterColor.set(outColor); | ||
| filterColor.end(); | ||
| } | ||
|
|
||
| function draw() { | ||
| filter(gradientShader); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --- | ||
| featuredImage: "../../../images/featured/11_3D_09_gradient.png" | ||
| featuredImageAlt: A gradient from red to blue. | ||
| title: Gradient (p5.strands) | ||
| oneLineDescription: Draw a radial gradient between two points in p5.strands. | ||
| featured: false | ||
|
|
||
| remix: | ||
| - description: Created by | ||
| attribution: | ||
| - name: Dave Pagurek | ||
| URL: https://www.davepagurek.com/ | ||
| code: | ||
| - label: Code | ||
| URL: https://github.com/processing/p5.js-website/tree/main/src/content/examples/en/16_Shaders/05_Strands_Gradient | ||
| - collectivelyAttributedSince: 2026 | ||
| --- | ||
|
|
||
| This demonstrates a radial gradient, `lerp`ing between two colors, based on two points. It runs in a full-screen filter shader. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| let ditherGradientShader; | ||
| function setup() { | ||
| createCanvas(400, 400, WEBGL); | ||
| ditherGradientShader = buildFilterShader(ditherGradient); | ||
| } | ||
|
|
||
| // This function is p5.strands code: it's like JavaScript, but | ||
| // where you can write vectors as arrays and use math oeprators on them | ||
| function ditherGradient() { | ||
| // filterColor is an example of a *hook* in a strands shader, which | ||
| // lets you control different parts of the shader's job | ||
| filterColor.begin(); | ||
| randomSeed(0); // Comment out for a flickery output | ||
| // Or use the one below to use a low frame rate flicker | ||
| // randomSeed(floor(frameCount / 5)) | ||
|
|
||
| // Texture coordinates like filterColor.texCoord go from [0,0] in the | ||
| // top left to [1,1] in the bottom right | ||
| let start = [0.1, 0.1]; | ||
| // Convert mouse coords to texture coordinate range by dividing | ||
| // by canvas size | ||
| let end = [mouseX, mouseY] / [width, height]; | ||
| let startToPixel = length(filterColor.texCoord - start); | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. explaining what texCoord here is, maybe spelling out "tex" is for "texture" in the comment? |
||
| let startToEnd = length(end - start); | ||
| let gradientProgress = map( | ||
| startToPixel, | ||
| 0, | ||
| startToEnd, | ||
| 0, | ||
| 1, | ||
| true | ||
| ); | ||
| let outColor = color('#F00'); | ||
| if (gradientProgress + random(-0.3, 0.3) > 0.5) { | ||
| outColor = color('#0214f3'); | ||
| } | ||
| filterColor.set(outColor); | ||
| filterColor.end(); | ||
| } | ||
|
|
||
| function draw() { | ||
| filter(ditherGradientShader); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --- | ||
| featuredImage: "../../../images/featured/11_3D_10_dithered_gradient.png" | ||
| featuredImageAlt: A dithered gradient from red to blue. | ||
| title: Dithered Gradient (p5.strands) | ||
| oneLineDescription: Draw a dithered radial gradient between two points in p5.strands. | ||
| featured: false | ||
|
|
||
| remix: | ||
| - description: Created by | ||
| attribution: | ||
| - name: Dave Pagurek | ||
| URL: https://www.davepagurek.com/ | ||
| code: | ||
| - label: Code | ||
| URL: https://github.com/processing/p5.js-website/tree/main/src/content/examples/en/16_Shaders/06_Dithered_Strands_Gradient | ||
| - collectivelyAttributedSince: 2026 | ||
| --- | ||
|
|
||
| This demonstrates a radial gradient based on two points, but where it picks one color or the other without mixing between them. It runs in a full-screen filter shader. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| let layer; | ||
| let blur; | ||
|
|
||
| function setup() { | ||
| createCanvas(windowWidth, windowHeight, WEBGL); | ||
| angleMode(DEGREES); | ||
| noStroke(); | ||
|
|
||
| // Create framebuffer and shader objects | ||
| layer = createFramebuffer(); | ||
| blur = buildFilterShader(blurCallback); | ||
|
|
||
| describe( | ||
| 'A row of five spheres rotating in front of the camera. The closest and farthest spheres from the camera appear blurred.' | ||
| ); | ||
| } | ||
|
|
||
| // This function is p5.strands code: it's like JavaScript, but | ||
| // where you can write vectors as arrays and use math oeprators on them | ||
| function blurCallback() { | ||
| // In draw, the depth info is passed in with setUniform | ||
| let depth = uniformTexture('depth'); | ||
|
|
||
| // A helper function to tell us how blurry something a given | ||
| // distance away should be | ||
| function howBlurry(d) { | ||
| // Blur more the farther away we go from the | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. minor - naming: |
||
| // focal point at depth=0.909 | ||
| return min(abs(d - 0.909) * 200, 4); | ||
| } | ||
|
|
||
| function maxBlurDistance(blurriness) { | ||
| return blurriness * 0.01; | ||
| } | ||
|
|
||
| // filterColor is an example of a *hook* in a strands shader, which | ||
| // lets you control different parts of the shader's job | ||
| filterColor.begin(); | ||
| let coord = filterColor.texCoord; | ||
| let color = getTexture(filterColor.canvasContent, coord); | ||
| let samples = 1; | ||
| let centerDepth = getTexture(depth, coord).r; | ||
| let blurriness = howBlurry(centerDepth); | ||
|
|
||
| for (let i = 0; i < 20; i++) { | ||
| // Sample nearby pixels in a spiral going out from the | ||
| // current pixel | ||
| let angle = i; | ||
| let distance = (i / 20) * maxBlurDistance(blurriness); | ||
| let offset = [cos(angle), sin(angle)] * distance; | ||
|
|
||
| // How close is the object at the nearby pixel? | ||
| let sampleDepth = getTexture(depth, coord + offset).r; | ||
|
|
||
| // How far should its blur reach? | ||
| let sampleBlurDistance = maxBlurDistance(getBlurriness(sampleDepth)); | ||
|
|
||
| // If it's in front of the current pixel, or its blur overlaps | ||
| // with the current pixel, add its color to the average | ||
| if (sampleDepth >= centerDepth || sampleBlurDistance >= distance) { | ||
| color += getTexture(filterColor.canvasContent, coord + offset); | ||
| samples++; | ||
| } | ||
| } | ||
|
|
||
| filterColor.set(color / samples); | ||
| filterColor.end(); | ||
| } | ||
|
|
||
| function draw() { | ||
| // Start drawing to framebuffer | ||
| layer.begin(); | ||
| background(255); | ||
| ambientLight(100); | ||
| directionalLight(255, 255, 255, -1, 1, -1); | ||
| ambientMaterial(255, 0, 0); | ||
| fill(255, 255, 100); | ||
| specularMaterial(255); | ||
| shininess(150); | ||
|
|
||
| // Rotate 1° per frame | ||
| rotateY(frameCount); | ||
|
|
||
| // Place 5 spheres across canvas at equal distance | ||
| let sphereDistance = width / 4; | ||
| for (let x = -width / 2; x <= width / 2; x += sphereDistance) { | ||
| push(); | ||
| translate(x, 0, 0); | ||
| sphere(width / 16); | ||
| pop(); | ||
| } | ||
|
|
||
| // Stop drawing to framebuffer | ||
| layer.end(); | ||
|
|
||
| // Draw the framebuffer to the canvas, then blur the canvas using | ||
| // the framebuffer's depth information | ||
| imageMode(CENTER); | ||
| image(layer, 0, 0); | ||
| blur.setUniform('depth', layer.depth); | ||
| filter(blur); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| --- | ||
| featuredImage: "../../../images/featured/11_3D-06_Framebuffer_Blur-thumbnail.png" | ||
| featuredImageAlt: A row of five orange spheres. The closest and farthest spheres from the camera appear blurred. | ||
| title: Depth Blur (p5.strands) | ||
| oneLineDescription: Simulate a camera's depth of field, with a shader written in p5.strands. | ||
|
|
||
| remix: | ||
| - description: Created by | ||
| attribution: | ||
| - name: Dave Pagurek | ||
| URL: https://www.davepagurek.com/ | ||
| code: | ||
| - label: pre-2023 example | ||
| URL: https://github.com/processing/p5.js-website-legacy/blob/main/src/data/examples/en/20_3D/12_framebuffer_blur.js | ||
|
|
||
| - description: Revised by | ||
| attribution: | ||
| - name: Caleb Foss | ||
| URL: https://github.com/calebfoss | ||
| code: | ||
| - label: 2023 code | ||
| URL: https://github.com/processing/p5.js-example/tree/main/examples/11_3D/06_Framebuffer_Blur | ||
|
|
||
| - description: Remixed by | ||
| attribution: | ||
| - name: Dave Pagurek | ||
| URL: https://www.davepagurek.com/ | ||
| code: | ||
| - label: 2026 p5.strands translation | ||
| URL: https://github.com/processing/p5.js-website/tree/main/src/content/examples/en/16_Shaders/07_Framebuffer_Blur_p5strands | ||
|
|
||
| - collectivelyAttributedSince: 2026 | ||
| --- | ||
|
|
||
| The | ||
| <a href="https://www.khronos.org/opengl/wiki/Shader" target="_blank">shader</a> | ||
| in this example uses depth information from a | ||
| <a href="https://p5js.org/reference/p5/p5.Framebuffer" target="_blank">p5.Framebuffer</a> | ||
| to apply a blur. On a real camera, objects appear blurred if they | ||
| are closer or farther than the lens's focus. This simulates that | ||
| effect. First, the sketch renders five spheres to the framebuffer. | ||
| Then, it renders the framebuffer to the canvas and applies the blur | ||
| shader, which is written in p5.strands. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| let video; | ||
| let blurShader; | ||
| function setup() { | ||
| createCanvas(400, 400, WEBGL); | ||
| video = createVideo( | ||
| '/assets/DiagonalCrosswalkYongeDundas.mp4' | ||
| ); | ||
| video.volume(0); | ||
| video.hide(); | ||
| video.loop(); | ||
| blurShader = buildFilterShader(myBlur); | ||
| } | ||
|
|
||
| // This function is p5.strands code: it's like JavaScript, but | ||
| // where you can write vectors as arrays and use math oeprators on them | ||
| function myBlur() { | ||
| // filterColor is an example of a *hook* in a strands shader, which | ||
| // lets you control different parts of the shader's job | ||
| filterColor.begin(); | ||
| // The range of texture coordinates is [0,0] in the top left to [1,1] in | ||
| // the bottom right. These are the units shaders use to tell you where you | ||
| // are on the canvas for filter shaders, or on a shape for a material shader. | ||
| let coord = filterColor.texCoord; | ||
| let distFromCenter = length(coord - [0.5, 0.5]); | ||
| // Map distance from center to blurriness, also in texture coordinate units. | ||
| // Since the whole canvas is only 1 unit across, a max blurriness of 0.1 is | ||
| // actually pretty blurry (10% of the canvas size!) | ||
| let blurAmount = map(distFromCenter, 0.2, 1, 0, 0.1, true); | ||
| coord += blurAmount * [random(-1, 1), random(-1, 1)]; | ||
| filterColor.set(getTexture(filterColor.canvasContent, coord)); | ||
| filterColor.end(); | ||
| } | ||
|
|
||
| function draw() { | ||
| imageMode(CENTER); | ||
| image(video, 0, 0, width, height, 0, 0, video.width, video.height, COVER); | ||
| filter(blurShader); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --- | ||
| featuredImage: "../../../images/featured/11_3D_11_variable_blur.jpg" | ||
| featuredImageAlt: A city scene blurred around the edges of the frame | ||
| title: Variable Blur (p5.strands) | ||
| oneLineDescription: Create a blur shader with a different amount of blur at different parts of the canvas. | ||
| featured: false | ||
|
|
||
| remix: | ||
| - description: Created by | ||
| attribution: | ||
| - name: Dave Pagurek | ||
| URL: https://www.davepagurek.com/ | ||
| code: | ||
| - label: Code | ||
| URL: https://github.com/processing/p5.js-website/tree/main/src/content/examples/en/16_Shaders/09_Strands_Variable_Blur | ||
| - collectivelyAttributedSince: 2026 | ||
| --- | ||
|
|
||
| This demonstrates a custom blur shader in p5.strands. The blur is accomplished by adding a random offset to the coordinate at which the texture is sampled. By using only one sample, the blur ends up noisy. Try averaging a few samples to get a smoother blur! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be helpful to add some comments (same for all them) that demonstrate how we talk abotu p5.sstrands eg: the code inside gradient() is p5.strands code, which is not quite normal JavaScript: here GLSL can be used as well as p5.js, and these define shades. filterColor is a hook, and is used to define shader behavior. Tiny notes about that.