Getting Started
Most of the work will be done in a fragment shader, but we'll need an environment to give us a WebGL context. We'll use p5.js for the foundation. Let's get that setup first. Once we do...oh, boy it'll be exciting!
P5.js allows us to load shaders in two different ways. As strings that contain the actual code or as strings that point to paths, like such:
Using the latter is way better since we'll get the benefit of syntax highlighting. We can just open the glsl file and edit/save/reload....Its just that there's one small hurdle we need to get over. For JavaScript to start loading files from your filesystem poses a security risk, we'll need to setup a server. Once we get over that hurdle, it's smooth shader sailing.
Local Server
I'm not actually going to help you setup a server. The p5.js team has already created instructions on how to do that. So, hop on over to: their page and come back once you have it working.
Blank Slate
So you've got your server running. Let's go!
- Download the complete p5.js zip file and extract the folder. Open sketch.js and replace its contents with the following:
You should see a black canvas. This shows us your system is happy with WebGL.
As mentioned, I said I wasn't going to go into vertex shaders, so please blindly do the following:
- create a data folder in empty-example
- create 2 files: vert.glsl and frag.glsl
Your directory structure should now look like this:
p5 ├── empty-example │ ├── data │ │ ├── frag.glsl │ │ └── vert.glsl │ ├── index.html │ └── sketch.js ├── p5.js └── p5.min.js
Update the sketch code to load the non-yet-existing-shaders:
Paste this into vert.glsl:
Now the fragment shader:
Blue Screen
After you refresh the page, you should see a beautiful blue canvas. We just did quite a bit, so let's step back and go through what we just did. In preload we supplied loadShader the paths of the 2 shaders. Be careful when supplying the paths--don't get them swapped because you'll get a cryptic error!
shader tells Processing which shader we wanna use. Duh! But it's that interesting!? It means we could potentially have several shaders for different 'surfaces'..We'll get into this later down the road. Once we tell processing which shader to use, it will use that for all the primitives going forward until told otherwise. This should be no surprise. This is how Processing rolls.
Under the hood, p5.js asks the browser to compile the shaders into a program. The process involves compiling and linkng and is quite interesting. I'll leave you to google that if you wish.
Hello World
Go ahead and paste this into the frag.glsl file.
Let's break down what we're seeing. If you notice that the syntax looks strangely similar to C, you're right! GLSL is based on the C language because it was/is popular. Lots of developers were familiar with it, so the comittee decided to use it. There's some other 'non-C' looking stuff. The vec4 is part of the language that defines a 4-dimentional vector. And the constructor syntax is quite handy.
gl_FragColor is a built-in. You need to assign a value to this variable for the shader to make sense. After all, that's what a shader does. Computer some stuff and assign a color to a fragment/pixel.
Normalized Colours
The colours used in a shader range from 0 to 1. Maybe you're used to 0-255? Have you ever used colorModeRGB(1) in Processing? Similar idea.
Hello, Where is (0,0) !?
When I first start messing around with a graphics context, I need to know where 0,0 is. Sometimes its top left, sometimes bottom left...I could tell you where it is for shaders--but let's write some code to prove it ourselves!
What we'll do is tell the shader: Hey, can you draw a red box when the x pixel and y pixel are less then 10? From that we can infer where 0,0 is.
So it turns out that the 0,0 is at the bottom left. Maybe one day you'll take a break from shaders and come back a few months later. instead of doing a search, you can now just write this little snippet to prove it for yourself and jog your memory.
Play time!
- Replace the quad call to rect. What happens?
- Swap the arguments in loadShader. What's the error message say?
- What happens if you use ints instead of floats in vec4?
- What happens if you change the arguments of quad?