Week 3 HW

For this week, I expanded upon my week 2 shader by adding noise and distorting it.

ripple

I first started by adding noise to the colour of my circles, and I experimented with the effects using different values would give me. I also applied noise to the entire canvas by using st.x, distorting the entire sketch.

 


#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

vec2 createGrid( in vec2 st, in vec2 grid, out vec2 indices ){

// multiply by the number of cells
// [0,1] range => [0,10] (for example)
st *= grid;

// get the cell indices
// for example, in a grid of 10x10:
// 0, 1, 2, 3, 4, 5, 6, 7, 8, 9
indices = floor(st);

// use fract to get the fractional amount of st
// 9.5 => 0.5
// shows the xy coordinate in each cell
st = fract(st);

return st;
}

float drawCircle (vec2 st, vec2 pos, float size){
float result = distance (st, pos);
result=1.-step(size,result);


return result;
}

float random (vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }

float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

void main() {

vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;

st.x += snoise(st*0.4);
// good practice to take a copy of the original st
// before you change it
vec2 st0 = st;

vec2 indices;

// This divides the result of the sin function, changing the final size of the circle
float size = 3.;

// This changes the period of the sin function, changing the speed at which the circles animate
float speed = 3.;

vec3 color;

color.r = snoise(st*2. + vec2(0., u_time*.5)) * 0.5+0.5;
color.g = snoise(st*2. + vec2(100., u_time*.5)) * 0.5+0.5;
color.b = snoise(st*2. + vec2(200., u_time*.5)) * 0.5+0.5;
// Create grid for circles
st = createGrid( st, vec2(5., 5.), indices);

// Set bg colour
// Change the colour and sin function of each column
if(indices.x == 0.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);

}else if(indices.x == 1.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+1.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 2.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+2.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 3.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+3.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 4.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+4.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}

gl_FragColor = vec4(color,1.0);
}

Week 3 Shaders

I used the sample 2d noise from the book of shaders to mix into my existing shader, and applied sin and cos functions to add movement to its position. As for scaling the canvas, I kept it low at 4 times. Combined with the existing time dependent shaping functions I had used previously, they formed soft organic looking shapes that slowly evolved and morphed and moved. Together with the back and forth motion, I think it really captures the feeling of a living organism – almost as if it’s breathing. You can view a live example here

hsv-oraganic-1

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.14159265359
#define TWO_PI 6.28318530718
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

// random and noise code from https://thebookofshaders.com/11/
float random(vec2 co){
    return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}

float noise (in vec2 st) {
    vec2 i = floor(st);
    vec2 f = fract(st);

    // Four corners in 2D of a tile
    float a = random(i);
    float b = random(i + vec2(1.0, 0.0));
    float c = random(i + vec2(0.0, 1.0));
    float d = random(i + vec2(1.0, 1.0));

    // Smooth Interpolation

    // Cubic Hermine Curve.  Same as SmoothStep()
    vec2 u = f*f*(3.0-2.0*f);
    // u = smoothstep(0.,1.,f);

    // Mix 4 coorners percentages
    return mix(a, b, u.x) +
            (c - a)* u.y * (1.0 - u.x) +
            (d - b) * u.x * u.y;
}

float plot(vec2 st, float pct){
  return  smoothstep( pct-0.1, pct, st.y) -
          smoothstep( pct, pct+0.5, st.y);
}

//  Function from Iñigo Quiles
//  https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb( in vec3 c ){
    vec3 rgb = clamp(abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),
                             6.0)-3.0)-1.0,
                     0.0,
                     1.0 );
    rgb = rgb*rgb*(3.0-2.0*rgb);
    return c.z * mix( vec3(1.0), rgb, c.y);
}

vec3 rgb2hsb( in vec3 c ){
    vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
    vec4 p = mix(vec4(c.bg, K.wz),
                 vec4(c.gb, K.xy),
                 step(c.b, c.g));
    vec4 q = mix(vec4(p.xyw, c.r),
                 vec4(c.r, p.yzx),
                 step(p.x, c.r));
    float d = q.x - min(q.w, q.y);
    float e = 1.0e-10;
    return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)),
                d / (q.x + e),
                q.x);
}

void main() {
    vec2 st = gl_FragCoord.xy/u_resolution;

    // time dependent shaping equations
    float y = sin(PI*st.x+u_time/40.)/0.8 + cos(PI*st.y+ u_time/40.)/2.;
    float yz = sin(PI*st.x+u_time/30.)/1. + cos(PI*st.y+ u_time/10.)/0.8;

    // various colours to mix
    vec3 color = vec3(y);
    vec3 colorA = vec3(0.545,0.169,0.000);
    vec3 colorB = vec3(0.565,0.435,0.121);
    vec3 colorC = vec3(0.126,0.490,0.171);
    vec3 colorD = vec3(0.362,0.237,0.820);
    float pct = plot(st,y);

    // Use polar coordinates instead of cartesian
    vec2 toCenter = vec2(0.5)-st;
    float angle = atan(toCenter.y,toCenter.x);
    float radius = length(toCenter)*2.0;
    // circle equation
    float z = radius * 10.*sin(u_time/2.+ atan(st.y, st.x));

    // scale the canvas for noise
    vec2 pos = vec2(st*4.);
    
    // move the noise values back and forth
    float n = noise(pos + sin(u_time) + cos(u_time));

    // now mix it all
    color = mix(colorA, colorB, y);
    color = mix(color, colorC, n);
    color = mix(color, colorD, yz);
    vec3 hsbtemp = rgb2hsb(color);
    color = hsb2rgb(vec3(hsbtemp[0], hsbtemp[1]*0.5, hsbtemp[2]*0.5));

    gl_FragColor = vec4(color,1.0);
}

I’ve been trying to get a sense of how scaling the canvas changes the overall noise effect. As the canvas is scaled larger, many familiar noise textures seem to emerge (pixelation, white noise, stripes like on a tuning VHS). I think it’s interesting that artificially adding noise in these ways provides windows into understanding noise found in the imperfect conversions between mediums (ex analog to digital).

hsv-grungehsv-texture-noise-2

Shader practice week 3

For this excersize I took my grid from last week and implemented the noise effect. I also added a distorted circle to the grid that warps and moves. I thought the grid effect  looked interesting with its psychedelic colour scheme.

noise-grid


// Author: Emily Flood
// Title: Noise grid
/* Code used from "Patterns" from The Book of Shaders
> @patriciogv ( patriciogonzalezvivo.com ) - 2015
*/

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

#define PI 3.14159265358979323846

//function to tile the image
vec2 tile(vec2 _st, float _zoom){
_st *= _zoom;
return fract(_st);
}

//function to draw a rectangle
float drawRect(vec2 st, vec2 pos, vec2 size){
float result = 1.0;

vec2 border = (1.0-size)/2.;

st = st - pos + vec2(0.5);

result = step(border.x,st.x);
result *= step(border.x,1.0-st.x);
result *= step(border.y,st.y);
result *= step(border.y,1.-st.y);

return result;
}

//function to draw a circle
float drawCircle(vec2 st, vec2 pos, float size){

float result = distance(st,pos);
result = 1.0-step(size,result);
return result;
}

float drawRectangle(vec2 st, vec2 pos, vec2 size){
float result = 1.0;

vec2 border = (1.0-size)/2.;

st = st - pos +vec2(0.5);

result = step( border.x, st.x);
result *= step( border.x, 1.-st.x);
result *= step( border.y, st.y);
result *= step( border.y, 1.-st.y);

return result;
}

vec3 permute(vec3 x) {return mod(((x*34.0)+1.0)*x, 289.0);}

float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v+ dot(v, C.yy));
vec2 x0 = v - i + dot(i, C.xx);
vec2 il;
il = (x0.x > x0.y) ? vec2(1.0,0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= il;
i = mod(i, 289.0);
vec3 p = permute( permute(i.y + vec3(0.0, il.y, 1.0))
+ i.x + vec3(0.0, il.x, 1.0));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m;
m = m*m;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

float random (vec2 st){
return fract(sin(dot(st.xy, vec2(12.9898,78.233)))*43758.5453123);
}

float map (float value, float min1, float max1, float min2, float max2){

return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}


void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
vec3 color = vec3(0.);

//tiling the image and animating it
st *= 5.;
st = mod(st,1.3);
st = tile(st,0.952);
st.x += sin(st.y *2. + u_time) * 0.1;
st.y -= cos(st.x *2. + u_time) * 0.1;
float size = 0.416;

//drawing out the rectangle and circle
float r1 = drawRect(st, vec2(0.5), vec2(0.5));

float c1 = drawCircle(st, vec2(0.5), size);

color = vec3(st,0.048);

//applying colour
color.r = snoise( st * 3. + vec2(100., -u_time*0.5)) * 0.5 + 0.5;
color.g = snoise( st * 3. + vec2(200., -u_time*0.4)) * 0.5 + 0.5;
color.b = snoise( st * 3. + vec2(300., -u_time*0.4)) * 0.5 + 0.5;

color.r = snoise( st * 2. + vec2(400., u_time)) * 0.5 + 0.5;
color.g = snoise( st * 2. + vec2(500., u_time)) * 0.5 + 0.5;
color.b = snoise( st * 2. + vec2(600., u_time)) * 0.5 + 0.5;


vec2 index = floor( st);

float cs = (snoise(st + vec2(0, u_time*0.2))*0.5 + 0.5) * 0.3 + 0.1;

float circ = drawCircle( st, vec2(0.5), cs);

vec3 circColor;
circColor.r = random( index + vec2(10.));
circColor.g = random( index + vec2(20.));
circColor.b = random( index + vec2(30.));

color = mix ( color, circColor, circ);

float cs2 = (snoise(st + vec2(0, u_time*0.2))*0.5 + 0.5) * 0.3 + 0.1;

float circ2 = drawCircle( st, vec2(0.5), cs2);

vec3 circColor2;
circColor2.r = random( index + vec2(10.));
circColor2.g = random( index + vec2(20.));
circColor2.b = random( index + vec2(30.));

color = mix ( color, circColor, circ);



float rectSize = random(index);


gl_FragColor = vec4(color,1.0);
}

Shader Explorations Week 3

screenshot-928screenshot-934 screenshot-931screenshot-935

The above 4 images show several iterations of my code below. I had a lot of fun experimenting with creating a kaleidoscope effect by overlapping several dynamic circles (their shapes were altered/deformed using noise) at varying opacities, colour schemes/noise-based gradients, and offsets. Like in the noise tutorial from class, I decided to create the background with a dynamic gradient of colours also controlled by offset noise. Originally the circles used a similar rainbow noise gradient, but I felt that I wanted to create more contrast between the background and circles. I experimented (as shown above) with white, black, grey, and blue. It appeared that using other solid colours like red, green, and yellow didn’t create enough contrast.

I find it really cool how the circles are not the “main” kaleidoscope shapes but are used to create negative space that cuts through the background in order to create the effect. I added a basic outlined square to the tile pattern to add more-dynamic overlay effects. The brightness and opacity of the squares are controlled using horizontal mouse movements.


// Author: Madelaine Fischer-Bernhut
// Title: 2D Perlin Simplex Noise V12

#ifdef GL_ES
precision mediump float;
#endif

#define PI 3.142

uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

//Book of Shaders Simplex Noise (based off Ian McEwan, Ashima Arts)
// Some useful functions
vec3 mod289(vec3 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec2 mod289(vec2 x) { return x - floor(x * (1.0 / 289.0)) * 289.0; }
vec3 permute(vec3 x) { return mod289(((x*34.0)+1.0)*x); }

float snoise(vec2 v){
const vec4 C = vec4(0.211324865405187, 0.366025403784439,
-0.577350269189626, 0.024390243902439);
vec2 i = floor(v + dot(v, C.yy) );
vec2 x0 = v - i + dot(i, C.xx);
vec2 i1;
i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
vec4 x12 = x0.xyxy + C.xxzz;
x12.xy -= i1;
i = mod(i, 289.0);
vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))
+ i.x + vec3(0.0, i1.x, 1.0 ));
vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy),
dot(x12.zw,x12.zw)), 0.0);
m = m*m ;
m = m*m ;
vec3 x = 2.0 * fract(p * C.www) - 1.0;
vec3 h = abs(x) - 0.5;
vec3 ox = floor(x + 0.5);
vec3 a0 = x - ox;
m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );
vec3 g;
g.x = a0.x * x0.x + h.x * x0.y;
g.yz = a0.yz * x12.xz + h.yz * x12.yw;
return 130.0 * dot(m, g);
}

float map (float value, float min1, float max1, float min2, float max2){
return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

//rotation functions from the Book of Shaders "Patterns"
vec2 rotate2D(vec2 st, float angle){
st -= 0.5;
st = mat2(cos(angle), -sin(angle),
sin(angle), cos(angle))*st;
st += 0.5;
return st;

}

vec2 rotateTilePattern(vec2 st){

//scale coordinate system by 2x2
st *= 6.0;

//give each cell and index number according to its position
float i = 0.0;
i += step(1.0, mod(st.x,2.0));
i += step(1.0, mod(st.y,2.0))*2.0;

//each cell between 0.0 -1.0
st = fract(st);

//rotate each cell according to index
//use matrix to rotate the space

if(i == 1.0){
st = rotate2D(st, PI*-0.5);
} else if (i == 2.0){
st = rotate2D(st, PI*0.5);
} else if (i == 3.0){
st = rotate2D(st, PI*2.0);
} else if (i== 0.0){
st = rotate2D(st, PI);
}

return st;

}

float drawCircle(vec2 st, vec2 position, float size){

float result = distance(st, position);
result = 1.0 - step (size, result);

return result;

}

float drawRect(vec2 st, vec2 pos, vec2 size){
float result = 1.0;

//invert size so the size variables will control the size based on the white dimensions
vec2 border = (1.0-size)/2.0;

result = step(border.x + pos.x, st.x);
result *= step(border.x - pos.x, 1.0-st.x);
result *= step(border.y + pos.y, st.y);
result *= step(border.y - pos.y, 1.0-st.y);

return result;
}
void main() {
vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;

vec3 color = vec3(0.0);

//scale coordinate system to see noise
vec2 pos = vec2(st.x*1.0 - sin(u_time*0.2), st.y*1.0 + cos(u_time*0.2));

//BACKGROUND
//background gradient color
color.r = snoise(pos) * 0.5 + 0.5;
color.b = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
// color.r = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
// color.g = snoise(pos + vec2(u_time*0.3)) * 0.5 + 0.5;
color.g = snoise(pos + vec2(u_time*0.1)) * 0.5 + 0.5;

//TILE and ROTATE
st *= vec2(0.5, 0.5);
st += rotate2D(st,PI*0.5);

//then rotate title patterns based on index/location
st = rotateTilePattern(st+0.25);

//CIRCLE SETUP
//Animated circle size with noise function, add "st" in vector with noise to create a dynamic shape
//create an offset in size and opacity for each subsequent circle
float circle = drawCircle(st, vec2(0.580,0.550), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 0.5 + 0.1)*1.0;
float circle2 = drawCircle(st, vec2(0.500,0.500), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 1.0 + 0.1)*0.75;
float circle3 = drawCircle(st, vec2(0.710,0.330), (snoise(st + vec2(u_time*0.2))*0.5 +0.5) * 1.5 + 0.1)*0.5;

vec3 circleColor = vec3(0.005,0.005,0.005);

//circle color gradient
// circleColor.r = snoise(pos) * 0.5 + 0.5;
// circleColor.b = snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5;
// circleColor.g = snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5;

//circle color blue gradient
// circleColor.b *= (snoise(pos) * 0.5 + 0.5)*0.2;
// circleColor.b += (snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5)*0.2;
// circleColor.b += (snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5)*0.2;

//circle color normal black and white gradient
circleColor = vec3(snoise(pos) * 0.5 + 0.5)*0.2;
circleColor += vec3(snoise(pos + vec2(-u_time*0.3)) * 0.5 + 0.5)*0.2;
circleColor += vec3(snoise(pos + vec2(-u_time*0.1)) * 0.5 + 0.5)*0.2;


//RECTANGLE OVERLAY
//solid black outline
// float rectangle = drawRect(st, vec2(0.0), vec2(0.9)-0.1);

//low opacity outline
float rectangle = drawRect(st, vec2(0.0), vec2(0.6)-0.1);
rectangle -= drawRect(st, vec2(0.0), vec2(0.8)-0.1);

//full opactity fill of rectangle
// rectangle = drawRect(st, vec2(0.0), vec2(0.8)-0.1);

//MIX/LAYER CIRCLES
//second mix parameter controls color of shape (circle)
color = vec3(mix(color, circleColor, circle));
color = vec3(mix(color, circleColor, circle2));
color = vec3(mix(color, circleColor, circle3));

//second mix parameter controls brightness/opacity of rectangular overlay
color = vec3(mix(color, vec3(u_mouse.x/u_resolution.x), rectangle));

gl_FragColor = vec4(color,1.0);
}