Shader Explorations 2


The above four images show is a sequence of animated shader stills from left to right and top to bottom.

For this week’s homework shader explorations I decided to integrate my first shader, a Piet Mondrian inspired shader (created when I was exploring rectangle placement and layering effects for the Book of Shaders’ “recreate a Piet Mondrian painting” exercise), as I felt the design would make for a cool tile effect. The original colours followed Mondrian’s primary colour scheme (similar to the last still, but the small rectangle was yellow), but I felt that it needed to be more dynamic so I decided to animate a colour shifting gradient using u_time and smoothstep.

I still felt like I needed to add more variety of shapes, as I took the effort to make functions based on all of the shape exercises, so I decided on adding a polar shape. I found experimenting with the different parameters of polar shapes extremely fun, therefore I created a polar shape function that allowed me to control everything from position to length and width of spokes. Although I could have gone for a more complicated shape, I decided against it because the tiling pattern was also complex. It was an awesome moment when I realized I was able to layer the tile pattern over the polar design and see the solar shapes through the gap made with one of the rectangles.

Overall, I had a lot of fun learning about shapes and creating my own functions for them.

// Author: Madelaine Fischer-Bernhut
// Title: Animated Piet Mondrian Pattern v2

#ifdef GL_ES
precision mediump float;

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

#define PI 3.14159265358979323846

//rotation and tile 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 tile(vec2 st, float zoom){
 //scale up space
 st *= zoom;
 //wrap around 1.0
 return fract(st);

vec2 rotateTilePattern(vec2 st){
 //scale coordinate system by 2x2
 st *= 2.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 drawRect(vec2 st, vec2 size, vec2 pos){
 float result = 1.0;
 //invert size so the size variables will controle 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;

float createPolShape(vec2 st, float size, float spokesNum, vec2 spokeSize, vec2 pos, float rot, float blur){
 float result = 1.0;
 //control the position of the shape
 pos -= st;
 //control the size of the shape
 float r = length(pos)*size;
 float a = atan(pos.y, pos.x);
 //control the number of "spokes" and their shape
 //rotate and animate the shape by adding or subtracting from the "a" in cos or sin
 float f = cos(a*spokesNum + rot)*spokeSize.y+spokeSize.x;
 f = abs(cos(a*spokesNum+rot)*sin(a*spokesNum+rot))*spokeSize.y+spokeSize.x;
 // f = smoothstep(-.5,1.0, cos(a*spokesNum+rot))*spokeSize.y+spokeSize.x;
 //changing f+value effects focus of shape (blurred)
 result = 1.0-smoothstep(f,f+blur,r);

 return result;

void main() {
 //st are texture coordinates, s is along the horizontal axis and t along the vertical axis (surface)
 vec2 st = gl_FragCoord.xy/u_resolution.xy;
 st.x *= u_resolution.x/u_resolution.y;

 float outline = 0.05;
 //for testing: centre of polar shape position is based on mouse
 vec2 pos = u_mouse/u_resolution;
 pos = vec2(0.5);
 vec3 color = vec3(0.0);
 //polar shape will appear underneath Piet Mondrian pattern
 color = vec3(createPolShape(st, 2.15, 10.0, vec2(0.350,0.860), pos, u_time*2.0, -0.260));

 //divide space by value
 st = tile(st, 1.0);
 //first rotate entire space by 90 deg
 st += rotate2D(st,PI*0.5);
 //then rotate title patterns based on index/location
 st = rotateTilePattern(st);

 //create bordered rectangles
 //white rectangles
 //adding the initial rectangle layer instead of multiplying results in the Piet Mondrian Pattern being masked by the polar shape
 // color += vec3(drawRect(st, vec2(0.360,0.590) - vec2(outline), vec2(-0.320,0.210)));
 //multiplying a rectangle layer in with the other two added results in that rectangle becoming "transparent"
 color *= vec3(drawRect(st, vec2(0.360,0.590) - vec2(outline), vec2(-0.320,0.210)));
 color += vec3(drawRect(st, vec2(0.480,0.585) - vec2(outline), vec2(0.259,-0.067)));
 color += vec3(drawRect(st, vec2(1.0,0.165) - vec2(outline), vec2(0.000,-0.417)));
 //coloured rectangles (with animated gradient overlay effect using smoothstep to control placement, and offsetting those colour gradients by overlaying sin & cos time animations)
 color.r += drawRect(st, vec2(0.540,0.300) - vec2(outline), vec2(0.105,0.350)) * smoothstep(sin(u_time*0.4)*0.9,1.1,st.x) ;
 color.g += drawRect(st, vec2(0.540,0.300) - vec2(outline), vec2(0.105,0.350)) * smoothstep(cos(u_time*0.4)*0.9,1.1,st.x) ;
 color.r += drawRect(st, vec2(0.150,0.3) - vec2(outline), vec2(0.425,0.35))* smoothstep(cos(u_time*0.4)*0.9,1.5, st.y);
 color.g += drawRect(st, vec2(0.150,0.3) - vec2(outline), vec2(0.425,0.35))* smoothstep(sin(u_time*0.4)*0.9,1.5, st.y);
 color.b += drawRect(st, vec2(0.540,0.300) - vec2(outline), vec2(-0.230,-0.210)) * smoothstep(sin(u_time*0.4)*0.95,1.2, 1.0-st.x);
 color.g += drawRect(st, vec2(0.540,0.300) - vec2(outline), vec2(-0.230,-0.210)) * smoothstep(cos(u_time*0.4)*0.95,1.2, 1.0-st.x);

 gl_FragColor = vec4(color,1.0);

Leave a Reply