Ithaca High School Math Seminar Lesson 2-6

Date: 2023.11.17

We've already covered a lot in the last five lessons, so today serves two purposes: catch-up for people who'd like to revisit / tinker / finish content from the previous lessons, otherwise exploring (and adapting) shaders other people have made.

We'll make an animation which looks like the following image by adapting a fragment shader made by supah on Shadertoy.

Step 1: Copy in the code, renaming variables if necessary.

Shadertoy has an incredible collection of fragment shaders, and reading / tinkering with the code of these is a great way to learn tricks and principals for writing fragment shaders. (And sometimes, the only way to learn!)

Let's say we click on the link to the fragment shader illustrated above ("Discotech 2"), open up a blank Kodelife window, and then cut and paste the code from Shadertoy into Kodelife. Does everything compile? No, we instead get the following error messages.

Let's deal with the time issue first. In the previous lesson we used a built-in uniform time to create a basic animation. We can make a similar setup here.

Specifically, adding in the line

uniform float time;

before the Line procedure, and replacing iTime words with time eliminates the error.

Task: Similar to the iTimetime replacement, modify the code to use the resolution uniform we used in the recent lessons, thereby removing the iResolution compile error.

We're not done yet. The main procedures in Shadertoy take in the position of a pixel and return its color. If we replace the first main procedure line with

void main(void) {
    vec2 I = gl_FragCoord.xy;
    vec4 O;

and before the final bracket include

gl_FragColor = O;

then we have basically adapted the fragment shader code to use the uniforms that KodeLife sends to shader programs, so the shader should compile.

Even though the code we copied just illustrates simple geometry and is therefore likely to be ineligible for copywrite, supah (presumably) invested time into the shader to make the geometry very pretty! in the shader code we should at least acknowledge who first made the shader, and where we copied it from. Doing this in general is important; not doing this is in general plagiarism.

In total, we end up with the following shader:

#define S smoothstep

//
// "Discotecq 2" by supah, available at: https://www.shadertoy.com/view/DtXfDr
//

uniform float time;
uniform vec2  resolution;

vec4 Line(vec2 uv, float speed, float height, vec3 col) {
    uv.y += S(1., 0., abs(uv.x)) * sin(time * speed + uv.x * height) * .2;
    return vec4(S(.06 * S(.2, .9, abs(uv.x)), 0., abs(uv.y) - .004) * col, 1.0)
    * S(1., .3, abs(uv.x));
}

void main(void) {
    vec2 I = gl_FragCoord.xy;
    vec4 O;
    vec2 uv = (I - .5 * resolution.xy) / resolution.y;
    O = vec4 (0.);
    for (float i = 0.; i <= 5.; i += 1.) {
        float t = i / 5.;
        O += Line(uv, 1. + t, 4. + t, vec3(.2 + t * .7, .2 + t * .4, 0.3));
    }
    gl_FragColor = O;
}

Task: Copy the code above into a blank KodeLife session, and tinker with the numbers. How can you get three sine waves on the screen? How can you make the waves slower? Can you make the waves have a higher amplitude?

Step 2: Browse Shadertoy!

Final Task: Find at least three interesting (and small in terms of number of lines of code) examples on shadertoy.com, and try to get them running within KodeLife. Make some small changes to their code, and observe how such changes affect the pattern.