diff --git a/public/assets/mont-photo-low.jpg b/public/assets/mont-photo-low.jpg new file mode 100644 index 0000000000..01a1b98002 Binary files /dev/null and b/public/assets/mont-photo-low.jpg differ diff --git a/src/content/tutorials/en/hello-color-world-p5-strands.mdx b/src/content/tutorials/en/hello-color-world-p5-strands.mdx new file mode 100644 index 0000000000..2fdd864dbd --- /dev/null +++ b/src/content/tutorials/en/hello-color-world-p5-strands.mdx @@ -0,0 +1,995 @@ +--- +title: "Hello Color World: p5.strands" +description: A tutorial that introduces fragment shaders and guides you through three ways to use color with p5.strands +category: "2.0" +categoryIndex: 0 +featuredImage: ../images/featured/hello-color-world-p5-strands.jpg +featuredImageAlt: Colorful clouds with a floating cube reflecting the clouds +relatedContent: + references: + - en/p5/p5shader +authors: + - ilithya +--- + +import { Columns, Column } from "../../../components/Columns"; +import EditableSketch from "../../../components/EditableSketch/index.astro"; +import Callout from "../../../components/Callout/index.astro"; + +## 3 Ways to Work with Color in Shaders + +Let's discover a few techniques for manipulating color using p5.strands, and learn a bit of fragment shader fundamentals in the process. + +We'll explore color in shaders to enhance our p5.js sketches with more sophisticated effects that JavaScript alone wouldn't let us do. + + +A new way of writing shaders using JavaScript in p5.js version 2. +- [p5.strands: Writing Shaders in JavaScript](https://www.davepagurek.com/blog/writing-shaders-in-js/), blog post by Dave Pagurek +- [p5.strands: Introduction to Shaders](/tutorials/intro-to-p5-strands), tutorial by Luke Plowden + + +To understand what advantages p5.strands brings to us when dealing with shaders, we'll look at each technique through p5.js examples. One sketch will show an approach in p5.strands, while another will compare it with GLSL, a popular language for writing shaders in the browser. + +Each technique will present a few ideas for working with p5.js syntax that you can try in the p5.strands sketches. This can help you learn how to combine them. + +Here's an overview with a skip link to every technique we'll cover: +1. [Solid colors](#1-solid-colors) +2. [Textured colors](#2-textured-colors) +3. [Image color filters](#3-image-color-filters) + +You can skip to the [conclusion](#wrapping-up) as well, if you prefer to read from end to beginning. + + +A set of instructions implementing algorithms that control how a mesh is rendered into pixels on the screen. It runs on the GPU. In the browser when working with WebGL, it's written in GLSL and there are two types: vertex and fragment. +- [Introduction to GLSL](https://p5js.org/tutorials/intro-to-glsl/), tutorial by Dave Pagurek, Austin Lee Slominski, Adam Ferriss + + +Although GLSL can be used alongside JavaScript in a p5.js sketch, it is a separate shader language that shaders require. With p5.strands you can focus only on JavaScript, given that the GLSL is handled by p5.js. + +Let's start from simple to complex, like having a three-course meal, by first dipping our toes into an appetizer. + +
+ +### 1. Solid Colors + +We'll begin by simply painting the canvas of our sketch and one 3D primitive. + + +The number of pixels packed into a given area of a computer display. Screens with smaller pixels (e.g. Retina displays) have a higher pixel density and create sharper images. +- [pixelDensity()](/reference/p5/pixelDensity/), p5.js reference + + +Because all of our sketches will be running shaders, the p5.js built-in function `pixelDensity(1)` is always implemented inside the [`setup()`](/reference/p5/setup/). We set the pixel density to `1`, making the shaders run faster by reducing the number of pixels they need to process, since the default is often `2` on high-density displays. + + +A shader that sets the color of each pixel on the screen by outputting RGBA values, each ranging from 0.0 to 1.0. +- [RGBA Color](https://hughsk.io/fragment-foundry/chapters/03-rgb.html), self-guided workshop on fragment shaders by Hugh Kennedy +- [RGB Color Model](https://courses.ilithya.rocks/p/courses/intro-to-shaders/3486602-module-02-color/11410544-07-rgb-color-model), fragment shader course by ilithya + + +With p5.strands we can modify the color of a shader while benefiting from several color notations and models that we already know from p5.js, since it translates them for us into the RGB representation used by GLSL with hooks (e.g. [`finalColor`](/reference/p5/finalColor/)). + +These hooks allow us to speak GLSL when we use them with familiar p5.js syntax. The following table shows a p5.strands equivalent: + + + + + + + + + + + + + + +
p5.strandsGLSL (fragment)
hook.set(val)gl_FragColor = val
+ + +We can use p5.js built-in functions like [`color()`](/reference/p5/color) to paint with the shader: +- named color, `color('blue')` +- hex color value, `color('#0000ff')` +- hsl values, `color('hsl(40, 100%, 50%)')` +- RGB 8-bit values, `color(0, 255, 0)` + + + + + +#### sketch with p5.strands + + + + + + +#### sketch with GLSL +{/* Make this sketch scrollable matching the p5.strands sketch (left column) height */} + + + + + +### 2. Textured Colors +We'll continue evolving our canvas and 3D primitive sketch as we learn more techniques to color with our fragment shaders. Let's add a colored texture to them. + + +An access point into a shader that connects p5.js with GLSL to modify its behavior. +- `Cheat sheet link?` + + +With p5.strands we can apply randomness to a color equation, creating visually smooth organic textures like clouds, as well as rougher textures found in crystals, by using the [`noise()`](/reference/p5/noise) p5.js built-in function with a hook (e.g. [`pixelInputs`](/reference/p5/pixelInputs/)) instead of implementing GLSL algorithms from scratch. + +We can also add the time elapsed with [`millis()`](/reference/p5/millis) to our textures to simulate natural-looking movements. This value becomes a GLSL uniform, useful to adjust the shader. + + +A global variable that allows the CPU (JavaScript) and GPU (GLSL) to communicate. The shader cannot change it, only read its value to control a specific feature, such as size or motion. It's set and updated in JavaScript. +- [Uniforms Chapter](https://thebookofshaders.com/03/), The Book of Shaders by Patricio Gonzalez Vivo, Jen Lowe +- [setUniform()](/reference/p5.Shader/setUniform/), p5.js reference + + +p5.strands lets us set shader uniforms with p5.js elements we know, providing a bridge between JavaScript and GLSL. + +Here are other p5.strands syntax examples we'll use, and their GLSL translations: + + + + + + + + + + + + + + + + + + +
p5.strandsGLSL (fragment)
hook.texCoord varying vec2 uv
hook.colorgl_FragColor
+ + +Experiment with different inputs for the cloud texture: +- static, `noise(uv);` +- animated, `noise(uv + millis() * 0.00015);` +- horizontal mouse movement, `noise(uv + mouseX / width);` +- vertical mouse movement, `noise(uv + mouseY / height);` + + + + + +#### sketch with p5.strands + + + + + + +#### sketch with GLSL +{/* Make this sketch scrollable matching the p5.strands sketch (left column) height */} + + + + + +### 3. Image Color Filters +Let's add an image to our canvas and 3D primitive and learn how we can create a color filter with adjustments in the fragment shader. To simplify things, we’ll use the same image for both. + + +It's a color distortion that occurs when the colors of light don't focus on the same point. The RGB channels appear to be separated, making the colors of an image appear shifted. +- [Chromatic aberration](https://en.wikipedia.org/wiki/Chromatic_aberration), wikipedia +- [Filter Shader (p5.strands)](/examples/3D-Filter-Shader-p5strands/), example by Dave Pagurek +- [Filter Shader (GLSL)](/examples/3D-Filter-Shader/), example by Dave Pagurek + + +With p5.strands we can customize an image filter to our liking and create a chromatic aberration effect by using p5.js elements with a hook (e.g. [`filterColor`](/reference/p5/filterColor/)). We can displace the image colors vertically and horizontally with the p5.js built-in variables [`mouseX`](/reference/p5/mouseX) and [`mouseY`](/reference/p5/mouseY), which are translated into GLSL uniforms to control the shader. + +We'll add these p5.strands vs. GLSL translations to our knowledge base: + + + + + + + + + + + + + + + + + + + + + + +
p5.strandsGLSL (fragment)
hook.canvasContentuniform sampler2D u_texture
uniformTexture(texture)uniform sampler2D u_texture
getTexture(texture, uv)texture2D(u_texture, uv)
+ + +Explore different offsets in both axes `(x, y)` for the image displacement: +- animated, `noise(uv + millis() * 0.00025)` +- linear animation, `sin(millis() * 0.001) * 0.5` +- centered horizontal mouse movement, `(0.5 - mouseX / width) * 0.5` +- centered vertical mouse movement, `(0.5 - mouseY / height) * 0.5` + + + + + +#### sketch with p5.strands + + + + + + +#### sketch with GLSL +{/* Make this sketch scrollable matching the p5.strands sketch (left column) height */} + + + + + +### Wrapping Up +We learned three ways to work with color in fragment shaders with p5.strands, which can be practical in your p5.js sketches, as you can keep on writing JavaScript using familiar p5.js syntax and type less code. + +We can do this: +```js +// p5.js with p5.strands +function fragmentColor() { + finalColor.begin(); + + finalColor.set(color('blue')); + + finalColor.end(); +} +``` + +Instead of this: +```js +// p5.js with GLSL +let vertex = ` +precision highp float; + +attribute vec3 aPosition; + +uniform mat4 uModelViewMatrix; +uniform mat4 uProjectionMatrix; + +void main() { + gl_Position = uProjectionMatrix * uModelViewMatrix * vec4(aPosition, 1.0); +} +`; + +let fragment = ` +precision highp float; + +void main() { + vec3 color = vec3(0.0, 0.0, 1.0); + + gl_FragColor = vec4(color, 1.0); +} +`; +``` + + +It might be ideal for certain shader techniques or features where you want to avoid writing the GLSL needed from scratch, and instead use p5.strands hooks alongside p5.js built-in functions and variables. +- [p5.strands Overview](/contribute/p5.strands/), technical contributor documentation +- [p5.js Reference](/reference/), easy explanations for every piece of p5.js code + + +If instead of being comfortable with p5.js, you come from GLSL, p5.strands also enables you to use GLSL built-in functions, as for example `step()` and `mix()`. Check out our list of supported [GLSL built-ins](https://github.com/processing/p5.js/blob/main/src/strands/strands_builtins.js). + +Even when we're in the p5.js ecosystem, learning some GLSL fundamentals might unlock future possibilities to additionally work with other web-based creative coding tools that offer more advanced shader capabilities with equally friendly communities, including [Three.js](https://threejs.org) and [shadertoy](https://www.shadertoy.com). + +You can continue exploring color in shaders with p5.strands using more p5.js elements we didn't cover in our examples, such as [`random()`](/reference/p5/random/). + + +Feel free to submit your p5.strands explorations here: +- [p5.strands Community Workshop](https://openprocessing.org/curation/90883), OpenProcessing Curation + + +p5.strands is in [active development](https://processingfoundation.org/blog/p5js-21-and-22-expanding-graphics-avenues-with-p5strands-improvements-and-webgpu/) by the community. If you want to get involve, join our [discord server](https://discord.com/invite/gH3VcRKhen), we'll be happy to meet you! \ No newline at end of file diff --git a/src/content/tutorials/images/featured/hello-color-world-p5-strands.jpg b/src/content/tutorials/images/featured/hello-color-world-p5-strands.jpg new file mode 100644 index 0000000000..6b840c7d7d Binary files /dev/null and b/src/content/tutorials/images/featured/hello-color-world-p5-strands.jpg differ