Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/timclicks/glsl-shader-intro
An introduction to the OpenGL Shader Language (GLSL) and using it within a webpage with WebGL and the <canvas> tag.
https://github.com/timclicks/glsl-shader-intro
Last synced: 3 days ago
JSON representation
An introduction to the OpenGL Shader Language (GLSL) and using it within a webpage with WebGL and the <canvas> tag.
- Host: GitHub
- URL: https://github.com/timclicks/glsl-shader-intro
- Owner: timClicks
- Created: 2023-03-19T03:08:22.000Z (almost 2 years ago)
- Default Branch: main
- Last Pushed: 2023-03-19T03:13:50.000Z (almost 2 years ago)
- Last Synced: 2025-01-19T11:15:14.690Z (7 days ago)
- Language: HTML
- Size: 7.81 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# glsl-intro-tutorial
![](https://img.youtube.com/vi/sMkgXh7ThT4/maxresdefault.jpg)
# About
An introduction to using the OpenGL Shading Language (GLSL) language
on the web via WebGL.# Usage
You should load the `glsl.html` file via a local web server.
For example, Python should work fine to start a server:```console
$ python3 -m http.server
```Now open a browser at .
# Discussion
I've always wanted to create a "shader" -- a graphics program that works really fast (it runs on your GPU) -- but I've always been put off because they seemed really difficult.
Shaders come in two forms: fragment shaders and vertex shaders. Fragment shaders are what we care about here, because they're more useful for drawing. A fragment shader is a type of shader that processes individual fragments (pixels) on the screen. It is responsible for determining the color of each pixel in the final rendered image. GLSL is a C-like language used for writing shaders in OpenGL.
All of this complexity has kept me away for a long time. Today I managed to put that fear aside and create this - a fun dynamic gradient background:
## Running the shader yourself..
### .. in ShaderToy
ShaderToy is an interactive web playground for running shaders.
```glsl
void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord / iResolution.xy;// Time-based variables for smooth animation
float t = iTime * 1.5;
float t1 = sin(t) * 0.5 + 0.5;
float t2 = cos(t) * 0.5 + 0.5;// Color components
float r = sin(3.0 * uv.x + t1) * 0.5 + 0.5;
float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;// Output the final color
fragColor = vec4(r, g, b, 1.0);
}
```To use this shader, follow these steps:
1. Go to .
1. Replace the existing code in the "`mainImage`" function with the code provided above.
1. Click the "Play" button.### .. locally
If you want to learn how to use a shader in your own projects, you'll need to do a little more work to set things up.
The project has two files:
- `glsl.html` - the main webpage
- `shader.frag` - a _fragment shader_`glsl.html`:
```html
GLSL/WebGL Shader Example
html, body {
width: 100%;
height: 100%;
margin: 0;
}
canvas {
display: block;
width: 100%;
height: 100%;
}
const canvas = document.querySelector('.glslCanvas');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
const sandbox = new GlslCanvas(canvas);
```
`shader.frag`:
```glsl
#ifdef GL_ES
precision mediump float;
#endifuniform float u_time;
uniform vec2 u_resolution;void mainImage(out vec4 fragColor, in vec2 fragCoord)
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord / u_resolution.xy;// Time-based variables for smooth animation
float t = u_time * 1.5;
float t1 = sin(t) * 0.5 + 0.5;
float t2 = cos(t) * 0.5 + 0.5;// Color components
float r = sin(2.0 * uv.x + t1) * 0.5 + 0.5;
float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;// Output the final color
fragColor = vec4(r, g, b, 1.0);
}void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
```Note: the variables in WebGL are different than those available in ShaderToy. ShaderToy's `iResolution` becomes `u_resolution` and its `iTime` becomes `u_time`.
## Explaining the code
The GLSL code in `shader.frag` is relatively short, but still fairly off-putting. Let's break it down.
**Preprocessor**
To start, we have a "Preprocessor directive". The compiler has stages, and one of the initial stages is called the "Preprocessor".
```glsl
#ifdef GL_ES
precision mediump float;
#endif
```This part checks if the shader is running on OpenGL ES (Embedded Systems), a subset of OpenGL for mobile and embedded devices. If so, it sets the default floating-point precision to "medium." Precision indicates the accuracy and range of floating-point variables. "Medium" precision offers a balance between performance and accuracy.
**Creating two "uniform" (global) variables**
```glsl
uniform float u_time;
uniform vec2 u_resolution;
```Uniform variables are global variables that can be set from outside the shader, usually from the application code. In this case, `u_time` represents the elapsed time, and `u_resolution` represents the screen resolution as a 2D vector (width, height).
**mainImage function**
```glsl
void mainImage(out vec4 fragColor, in vec2 fragCoord)
```The `mainImage` function processes the fragment color (`fragColor`) based on the fragment coordinates (`fragCoord`). It takes an "output variable" `fragColor` of type `vec4` rather than use a return value to set the color of the fragment (pixel) and an input variable `fragCoord` of type `vec2` that describes the fragment's coordinates.
**Normalize pixel coordinates**
```glsl
vec2 uv = fragCoord / u_resolution.xy;
```
This line translates the fragment's coordinates between absolute position and a relative position between 0 and 100%. I use the term normalized because the coordinates `uv` are independent from the device that is rendering the shader, whereas `fragCoord` is device-specific. The code calculates `uv` by dividing the fragment coordinates by the resolution. The uv coordinates will range from (0, 0) to (1, 1), representing the bottom-left and top-right corners of the screen, respectively.**Changing what's displayed over time**
```glsl
float t = u_time * 1.5;
float t1 = sin(t) * 0.5 + 0.5;
float t2 = cos(t) * 0.5 + 0.5;
```These lines create time-based variables for smooth animation. The `t` variable scales the elapsed time (`u_time`), while `t1` and `t2` use sine and cosine functions to create smoothly changing values that oscillate between 0 and 1.
Changing the constant being multiplied with `u_time` changes how quickly the image changes. Adjusting how `t1` and `t2` behave will affect the cycle that produces the colors.
**Calculate color components (red, green, blue)**
```glsl
float r = sin(2.0 * uv.x + t1) * 0.5 + 0.5;
float g = cos(3.0 * uv.y + t2) * 0.5 + 0.5;
float b = sin(4.0 * (uv.x + uv.y) + t1 + t2) * 0.5 + 0.5;
```These lines calculate the red, green, and blue color components for each fragment using the time-based variables and the normalized pixel coordinates. The sine and cosine functions generate smoothly varying values, creating color gradients on the screen.
**Set the pixel's color**
```glsl
fragColor = vec4(r, g, b, 1.0);
```This line sets the output `fragColor` with the calculated color components (`r`, `g`, `b`) and an alpha (transparency) value of 1.0 (fully opaque).
**Main function**
```glsl
void main() {
mainImage(gl_FragColor, gl_FragCoord.xy);
}
```The `main` function is the entry point of the shader. Its only job is to call the `mainImage` function that we've just chatted about. I've included `mainImage` to simplify refactoring and translating between your own HTML and ShaderToy's hosted environment.
## Expanding the shader
You can further experiment with this shader by adjusting the parameters, such as the coefficients in the sine (`sin`) and cosine (`cos`) functions that produce color components, to create different effects.
# Legal
Copyright owner: Tim McNamara
Code available for re-use under the MIT-0 licence.
Documentation available for re-use under the CC-BY-4.0 licence.