Week 9 Homework

I ported a few GLSL shaders to unity. It was pretty difficult for me as I can’t really do the complicated UI of those sorts of programs. I prefer to just stick to code. I was able to follow some other tutorials and get some help and got this scene working. You can tap and select a shader to view. Eventually, I want this to become a full app where I can show my shader and motion art. It’s a long way from there though.

Here’s some screenshots of the scene:

_week9

I also tried (and succeeded) to do this in glslViewer directly, and here is a GIF of that… (its my circles moving back and forth thing)

Week 10 Homework

I progressed on my gold shader to include cubemaps and reflections. This was a bit challenging for me. I used GlslViewer to code and compile/render. Some notes:

– I had to use 3D noise instead of 2D noise. This allowed for the flow of the noise to go around the corner of the cube. When using 3D shapes for this shader, up until now I had been using just 2D noise on each face, sort of “cheating”. Now it is a proper flowing 3D noise cube.

– I took away the gold colouring so that only the reflections remained, this caused me to have to really amp the specular value so that you could actually see the reflections

– I would like it if each face of the cube, the noise animated not in any direction but just on the face itself. it’s hard for me to describe. on the top and bottom faces, the noise animates exactly how I want, but on the other sides it sort of “flows” toward an edge. i’d rather it not do this but I couldn’t figure out how

to run this shader, you need glslViewer installed on your machine and then just run this command from within the shaders file folder

glslviewer shader.frag cube.obj -C cubemap.png

View the code and file son gitlab:
https://gitlab.com/nicolevella_ocad/cubemap-shader

screenshot

Just for funsies….

Here’s a P5 shader that pulls a random image from unsplash every 10ish seconds.

It’s using a 3D object of a flat plane with vertices x,y.

It sends this image as a texture to the fragment shader.

The vertices are then displaced based on a noise field which is animated over time.

By not clearing the screen on every draw() loop (aka, not setting the background() color within draw()), we get some really interesting glitches at the edges. Pixel stretching and other artifacts.

Some screenshots:
1

2

Code:
https://editor.p5js.org/nicoleannevella/sketches/xMrgZfUbg

View fullscreen:
https://editor.p5js.org/nicoleannevella/present/xMrgZfUbg

////////////////////

And here is another P5 shader using the same noise distortion effects, but rather than pull in an image as texture, it’s using the screen coordinates to color the displaced vertices.

Some screenshots:

screen-shot-2021-03-30-at-9-37-00-pm

screen-shot-2021-03-30-at-9-37-05-pm

Code:
https://editor.p5js.org/nicoleannevella/sketches/6cdlHDIot

View fullscreen:
https://editor.p5js.org/nicoleannevella/present/6cdlHDIot

Week 8 Homework

Life is pretty hectic right now, sorry for the delay in getting to this!

Here’s a sketch that explores the rotate and translate functions:
https://editor.p5js.org/nicoleannevella/sketches/C_zaN7RZk

JS Code:

let d, a = 0;

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  noStroke();
  background(0);
  colorMode(HSB, 360, 100, 100);
}

function draw() {
  rotateX(a/QUARTER_PI);
  rotateY(a/HALF_PI);
  rotateZ(a/PI);

  fill(frameCount % 360, 35, 100, 100);
  translate(cos(a)*250, sin(a)*250);

  d=tan(a)*(width/12);
  sphere(d);
  
  a+= 0.015;
}

Here’s a sketch that attempts to do the same but with moving a camera object:
https://editor.p5js.org/nicoleannevella/sketches/CE3m6hUmo

JS Code:

// camera object and position
let cam;
let camPos;

// set min and max depth of field
let maxdof = 1500;
let mindof = 1;

let a = 0; // angle used for cos/sin animations

function setup() {
  createCanvas(windowWidth, windowHeight, WEBGL);
  
  // use the HSB coloe mode because it makes most sense to me
  colorMode(HSB, 360, 100, 100);

  // init our camera and use a vector for its position
  cam = createCamera();
  camPos = createVector();
  
  // strokes can be ugly sometimes, lets not use one
  noStroke();
}

function draw() {

  // animate the fov with cos() by an increasing angle value
  let fov = cos(a)*2;
  let aspect = width / height;

  // animate the camera look at positions using the same
  // increasing angle value and some cos/sin functions
  // if we divide the angle by some number we can add
  // a sense of "randomness" to it
  let camLookX = cos(a) * sin(a / HALF_PI) * maxdof * 0.1;
  let camLookY = cos(a) * sin(a / PI) * maxdof * 0.1;
  let camLookZ = cos(a) * sin(a / QUARTER_PI) * maxdof * 0.1;

  // set the perspective, position, and lookAt for our 3D camera
  cam.perspective(fov, aspect, mindof, maxdof);
  cam.setPosition(cos(a) * maxdof, 0, -10);
  cam.lookAt(camLookX, camLookY, camLookZ);

  // animate that fill nicely with the Hue based on framecount
  fill(frameCount % 360, 35, 100, 100);

  // draw a sphere
  sphere(10);
  
  // the magic value used to caluclate cos/sin that's resposible for all our animations
  a += 0.015;
}

Here’s a sketch where I add my liquid gold frag shader to the blob obj file that Jeremy made in Blender. Hope it’s ok that I stole your .obj (obviously I am going to try to get my delicious gold involved somehow).

Getting my gold fragment shader to map onto the 3D object was not trivial. I had to try out all the possible mappings like vEyePosition, vModelView, etc … I set the st to vScreenPosition.xy/vNormal.xy and that showed progress.

The larger issue was how to get my circles drawn in the right place. As it’s no longer a vec2, but a vec3. So, in the drawCircle function, I had to add the three xyz values of vNormal to get it to draw correctly onto the shape.

#define drawCircle(st,pos,size)smoothstep(0.,5./(vNormal.x+vNormal.y+vNormal.z),size-length(pos-st))

https://editor.p5js.org/nicoleannevella/sketches/sEj2HwGv3

Frag Shader Code:

#ifdef GL_ES
precision mediump float;
#endif
  
uniform float uTime;

varying vec3 vScreenPosition;
varying vec3 vNormal;

#define drawCircle(st,pos,size)smoothstep(0.,5./(vNormal.x+vNormal.y+vNormal.z),size-length(pos-st))

#define PI 3.14159265358979323846
#define TWO_PI 6.283185307179586
#define BUTTER TWO_PI/TWO_PI/TWO_PI/TWO_PI/TWO_PI/TWO_PI

vec3 permute(vec3 x){return mod(((x*34.)+1.)*x,289.);}

float snoise(vec2 v){
    const vec4 C=vec4(.211324865405187,.366025403784439,
    -.577350269189626,.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.):vec2(0.,1.);
    vec4 x12=x0.xyxy+C.xxzz;
    x12.xy-=i1;
    i=mod(i,289.);
    vec3 p=permute(permute(i.y+vec3(0.,i1.y,1.))
    +i.x+vec3(0.,i1.x,1.));
    vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),
    dot(x12.zw,x12.zw)),0.);
    m=m*m;
    m=m*m;
    vec3 x=2.*fract(p*C.www)-1.;
    vec3 h=abs(x)-.5;
    vec3 ox=floor(x+.5);
    vec3 a0=x-ox;
    m*=1.79284291400159-.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.*dot(m,g);
}

void main() {
  
    vec2 st=vScreenPosition.xy/vNormal.xy;
    st.y=vScreenPosition.x/vScreenPosition.y;
  
    st.x/=snoise(st+vec2(uTime*BUTTER,0.))*.5+.5;
  
    float cs=snoise(st+uTime*BUTTER)*.5+.5;
  
    float circ=drawCircle(st,vec2(.5),cs*TWO_PI);
    
    vec3 red  =vec3(1.0,0.0,0.0);
    vec3 green=vec3(0.0,1.0,0.0);
    vec3 blue =vec3(0.0,0.0,1.0);
  
    vec3 color = vec3(0.0);
  
    color+=mix(color,red,circ);
    color+=mix(color,green,circ);
    color+=mix(color,blue,circ);
  
    gl_FragColor = vec4(color, 1.0);
}

As a bonus, I added audio reactivity:
https://nicolevella.com/_beta/shaders/goldblob/

Mid Term

My mid-term combines randomness, simplex noise, brownian motion, images as textures, and also colour blending as texture (to look like gold). It will react to the device microphone/amplitude of audio input.

It’s using 2 shaders in the p5.js sketch. One for the gold cube, and one for the background lines. The cube is using p5’s texture() function to wrap the texture around a p5 3D object, in this instance a box().

The gold shader specifically is one I have been working a lot on, constantly refining and tweaking. In the process, I made a shader that can take two images and “blend” them together as blobs, without overlapping or interference/distortion from the other image. To separate images, within blobs of noise flowing down the screen. That is the background, using two images of diagonal lines as textures.

P5 Sketch: https://editor.p5js.org/nicoleannevella/sketches/8reUPwf22
Images:

untitled-1

untitled-2

untitled-3

untitled-4

Week 5 Homework

I worked with Sara Boo. We each worked on our own ideas and then discussed and added to each others through chats.

I wanted to take two images and blend/distort/animate them together as blobs using noise. I really didn’t want one image to overlap with another, I wanted them to look like separate blobs, but as much as I tried, there is still a bit of an overlap. It was pretty tricky, but using a combination of -= or += and white, grey, or black as an overlaying color on the image, I could sort of “mask” out certain areas of each image. I’m very happy with the end result.

Some screenshots:

screenshot-2021-02-20-221308

screenshot-2021-02-20-221324

View it on p5 here

Using two shaders might fix the slight overlap issue. In this exercise I really started to grasp the position vs the color of things and how the two can be used to mask or create effects.

Shader code:

#ifdef GL_ES
precision lowp float;
#endif
  
uniform vec2 u_resolution;

uniform sampler2D u_tex0;
uniform sampler2D u_tex1;
uniform float u_time;
  
varying vec2 v_texcoord;

vec3 permute(vec3 x){return mod(((x*34.)+1.)*x,289.);}

float snoise(vec2 v){
    const vec4 C=vec4(.211324865405187,.366025403784439,
    -.577350269189626,.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.):vec2(0.,1.);
    vec4 x12=x0.xyxy+C.xxzz;
    x12.xy-=i1;
    i=mod(i,289.);
    vec3 p=permute(permute(i.y+vec3(0.,i1.y,1.))
    +i.x+vec3(0.,i1.x,1.));
    vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),
    dot(x12.zw,x12.zw)),0.);
    m=m*m;
    m=m*m;
    vec3 x=2.*fract(p*C.www)-1.;
    vec3 h=abs(x)-.5;
    vec3 ox=floor(x+.5);
    vec3 a0=x-ox;
    m*=1.79284291400159-.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.*dot(m,g);
}

#define drawCircle(st,pos,size)smoothstep(0.,1./u_resolution.y,size-length(pos-st))

void main() {
  float n = snoise((v_texcoord)-u_time*0.2);
  vec2 uv = vec2(-v_texcoord.x*n, -v_texcoord.y);
  vec4 canvas = vec4(1.);
  
  vec4 color0 = texture2D(u_tex0, fract(uv*3.));
  vec4 color1 = texture2D(u_tex1, fract(uv*3.));
  
  vec4 grey=vec4(vec3(0.5),1.);
  vec4 white=vec4(vec3(1.0),1.);
  vec4 black=vec4(vec3(0.0),1.);

  float circ0=drawCircle(uv,vec2(cos(u_time*0.33)*n,n),.75);

// by using -= and then += with white and black overlays we can effectively mirror blending modes in photoshop
  color1-=mix(color0,white,circ0);
  color0+=mix(color1,black,circ0);
// so that when mixing the two layers, we can use grey as a neutral color which masks the lays from one another
  canvas= mix(color0,grey,color1); 
  
  gl_FragColor = vec4(canvas);
}

For my palette generator, since Sara had done one which uses an input image to generate a palette, I made one which takes some input or random colour and generates a triadic palette based off of the input color.

It then uses noise and blending to generate the blobs I love so much.

Some screenshots:

screen-shot-2021-02-24-at-11-30-26-am

screen-shot-2021-02-24-at-11-30-36-am

screen-shot-2021-02-24-at-11-31-22-am

View it on p5 here

Script.js

let randomImage,
    myShader,
    url,
    m,
    s,
    startPos,
    baseColor,
    triadic1,
    triadic2;

let w = 300;
let h = 300;
let keywords = "palm tree";

function MyColor (h, s, b) {
    this.h = h;
    this.s = s;
    this.b = b;
}

function preload() {
  myShader = loadShader('displayTexture.vert', 'displayTexture.frag');
}

function setup() {
  colorMode(HSB,360,100,100);
  
  baseColor = new MyColor(random(360), random(30,60), 100);
  triadic1 = new MyColor((baseColor.h+120)%360, baseColor.s, baseColor.b);
  triadic2 = new MyColor((baseColor.h+240)%360, baseColor.s, baseColor.b);
  
  startPos=random(1000);

  createCanvas(windowWidth, windowHeight, WEBGL);
  
  // url = "https://source.unsplash.com/random/" + width + "x" + height + "/?" + keywords;
  // randomImage = loadImage(url, "png");
  // baseColor = randomImage.get(random(randomImage.width),random(randomImage.height));
}

function draw() {
  shader(myShader);

  // if (frameCount % 600 == 0) {
  // url = "https://source.unsplash.com/random/" + w + "x" + h;
  // randomImage = loadImage(url, "png");
  // myShader.setUniform("uTexture0", randomImage);
  //   console.log('switch');
  // }

  myShader.setUniform("uTexture0", randomImage);
  myShader.setUniform("uResolution", [width, height]);
  myShader.setUniform("uTime", millis() / 1000);
  myShader.setUniform("uStartPos", startPos);
  myShader.setUniform("uColorBase", [baseColor.h/360,baseColor.s/100,baseColor.b/100]);
  myShader.setUniform("uColorTri1", [triadic1.h/360,triadic1.s/100,triadic1.b/100]);
  myShader.setUniform("uColorTri2", [triadic2.h/360,triadic2.s/100,triadic2.b/100]);

  rect(0, 0, width, height);
}

GLSL Code:

#ifdef GL_ES
precision mediump float;
#endif
  
uniform vec2 uResolution;
uniform sampler2D uTexture0;
uniform float uTime;
uniform float uStartPos;

uniform vec3 uColorBase;
uniform vec3 uColorTri1;
uniform vec3 uColorTri2;
  
varying vec2 vTexCoord;

#define drawCircle(vTexCoord,pos,size,blur)smoothstep(0.,blur/uResolution.y,size-length(pos-vTexCoord));

float drawRectangle(vec2 st,vec2 pos,vec2 size){
    float result=1.;
    vec2 border=(1.-size)/2.200;  
    st=st-pos+vec2(.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;
}

// simplex 2D noise
vec3 permute(vec3 x){return mod(((x*34.)+1.)*x,289.);}
float snoise(vec2 v){
    const vec4 C=vec4(.211324865405187,.366025403784439,
    -.577350269189626,.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.):vec2(0.,1.);
    vec4 x12=x0.xyxy+C.xxzz;
    x12.xy-=i1;
    i=mod(i,289.);
    vec3 p=permute(permute(i.y+vec3(0.,i1.y,1.))
    +i.x+vec3(0.,i1.x,1.));
    vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),
    dot(x12.zw,x12.zw)),0.);
    m=m*m;
    m=m*m;
    vec3 x=2.*fract(p*C.www)-1.;
    vec3 h=abs(x)-.5;
    vec3 ox=floor(x+.5);
    vec3 a0=x-ox;
    m*=1.79284291400159-.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.*dot(m,g);
}

//brownian motion noise
float fbm(vec2 x) {
	float v = 0.0;
	float a = 0.5;
	vec2 shift = vec2(100);
	// Rotate to reduce axial bias
    mat2 rot = mat2(cos(0.5), sin(0.5), -sin(0.5), cos(0.50));
	for (int i = 0; i < 5; ++i) {
		v += a * snoise(x);
		x = rot * x * 2.0 + shift;
		a *= 0.5;
	}
	return v;
}

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

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);
}

void main() {
  
  vec4 color = vec4(1.0);
  float circSize=.5;

  float n = snoise(vec2(vTexCoord+uStartPos+uTime*.1))*.5+.5;
  float b = fbm(vec2(vTexCoord.x,vTexCoord.y+uTime*.1))*0.35;
  
  float rect=drawRectangle(vTexCoord*b,vec2(0.),vec2(0.25));

  float circleC1=drawCircle(vTexCoord,vec2(cos(uTime*0.22)*n+.8,n),circSize,500.*n);
  float circleC2=drawCircle(vTexCoord,vec2(cos(uTime*0.66)*n,n*0.5),circSize,500.*n);

  color=mix(color,vec4(hsb2rgb(vec3(uColorBase)),1.),rect);
  color=mix(color,vec4(hsb2rgb(vec3(uColorTri1)),1.),circleC1*20.);
  color=mix(color,vec4(hsb2rgb(vec3(uColorTri2)),1.),circleC2*10.);
 
  gl_FragColor = vec4(color);
}

Week 3 Shaders (Noise/Random)

First, using the tips from last weeks coding session, I got my black and white circle grid to animate the way I wanted it to. See here:

screen-shot-2021-02-11-at-6-38-01-pmClick to play

I used the same animation of circles moving in a clockwise manner around a square. I added noise to the circles, which was affecting their shape and making for interesting patterns.

I then started to introduce color and play with different blending modes. Here are some animations taken throughout the exploration process (click to play them in a new window):

screen-shot-2021-02-11-at-6-40-47-pm
Click to play

screen-shot-2021-02-11-at-6-48-12-pm
Click to play

screen-shot-2021-02-11-at-6-42-11-pmClick to play

Then I tried exploring with creating a chromatic aberration by stacking three circles in an additive blending mode and then using smoothstep to really blur the edges. Here is that result:

screen-shot-2021-02-11-at-6-44-23-pmClick to play

 

I preferred the look of more distinct and separate blobs. So I went back a step and then changed the background to white and the blending to be subtractive blending mode. I also explored different shaping functions as opposed to using the staged animation of Up, Down, Left, Right. Here it is combining the tan() function with snoise() to some very pleasing results.

This is the final submission:

screen-shot-2021-02-11-at-6-49-34-pmClick to play

 

 

Bonus? I was able to get my shaders to render in the browser using a node.js package called GLSL-Canvas-JS. (https://www.npmjs.com/package/glsl-canvas-js). So you can view my circle grid OpArt inspired loop and the final blended RGB blobs using noise in full screen at these links:

Circle Grid: https://nicolevella.com/_beta/shaders/001/

RGBlobs: https://nicolevella.com/_beta/shaders/002/

 

Code:

// Nicole Vella
// 2021

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

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

vec3 permute(vec3 x){return mod(((x*34.)+1.)*x,289.);}

float snoise(vec2 v){
    const vec4 C=vec4(.211324865405187,.366025403784439,
    -.577350269189626,.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.):vec2(0.,1.);
    vec4 x12=x0.xyxy+C.xxzz;
    x12.xy-=i1;
    i=mod(i,289.);
    vec3 p=permute(permute(i.y+vec3(0.,i1.y,1.))
    +i.x+vec3(0.,i1.x,1.));
    vec3 m=max(.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),
    dot(x12.zw,x12.zw)),0.);
    m=m*m;
    m=m*m;
    vec3 x=2.*fract(p*C.www)-1.;
    vec3 h=abs(x)-.5;
    vec3 ox=floor(x+.5);
    vec3 a0=x-ox;
    m*=1.79284291400159-.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.*dot(m,g);
}

float drawRectangle(vec2 st,vec2 pos,vec2 size){
    float result=1.;
    vec2 border=(1.-size)/2.200;
    st=st-pos+vec2(.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;
}

#define drawCircle(st,pos,size)smoothstep(0.,250./u_resolution.y,size-length(pos-st))

void main(){
    vec2 st=gl_FragCoord.xy/u_resolution.xy;
    st.x*=u_resolution.x/u_resolution.y;
    
    float circSize=.5;            
    vec3 white=vec3(1.);
    vec3 black=vec3(0.);
    vec3 red=vec3(1.,0.,0.);
    vec3 green=vec3(0.,1.,0.);
    vec3 blue=vec3(0.,0.,1.);
    vec3 canvas=vec3(0.);
    
    float n=snoise(vec2(st.x-u_time*.1,0.))*.5+.5;
    
    float rect=drawRectangle(st,vec2(0.),vec2(4.));
    
    float circleC1=drawCircle(st,vec2(cos(u_time*.33)*n+n+.03,n),circSize);
    float circleC2=drawCircle(st,vec2(cos(u_time*.44)*n+n+.02,n),circSize);
    float circleC3=drawCircle(st,vec2(cos(u_time*.66)*n+n+.01,n),circSize);
    
    canvas=mix(canvas,white,rect);
    
    canvas*=mix(canvas,green,circleC3);
    canvas/=mix(canvas,blue,circleC1);
    canvas*=mix(canvas,red,circleC2);
    
    gl_FragColor=vec4(canvas,1.);
}

Animating my tile shader

I pushed my week 2 tiled/grid shader further by animating it.

I also refactored the code into less lines while making it more semantically legible.

screen-shot-2021-02-05-at-10-34-54-am screen-shot-2021-02-05-at-10-34-59-am screen-shot-2021-02-05-at-10-35-03-am

Code:

// Nicole Vella
// 2021
// Metaball Grid Shader

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;

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

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 drawRectangle(vec2 st,vec2 pos,vec2 size){
    
    float result=1.;
    vec2 border=(1.-size)/2.200;
    
    // border animations
    // vec2 border = (1.0t-size)/2.200 + cos(st.x *6. + u_time)*0.508;
    // border.x =  0.25*sin(st.x*u_time);
    // border.y = -0.25*cos(st.y*u_time);
    
    st=st-pos+vec2(.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;
}

float drawCircle(vec2 st,vec2 pos,float size){
    float d=distance(st,pos);
    // step shows values > argument 1, and we want the opposite
    // so we invert the results by subtraction 1.0 - the value
    return 1.-step(size,d);
}

void main(){
    vec2 st=gl_FragCoord.xy/u_resolution.xy;
    st.x*=u_resolution.x/u_resolution.y;
    
    vec2 st0=st;
    vec2 indices;
    st=createGrid(st,vec2(10.,10.),indices);
    
    float delay=.45;
    float circSize=.5;
    
    vec2 size=vec2(.25,.25);
    vec2 pos=vec2(.5,.5);
    
    vec3 white=vec3(1.);
    vec3 black=vec3(0.);
    vec3 canvas=vec3(0.);
    
    // animations
    // 0 to 1
    float animation0to1=map(sin(u_time*delay),-1.,1.,0.,1.);
    // 1 to 0
    float animation1to0=map(sin(u_time*delay),-1.,1.,1.,0.);
    
    // bg rect
    float rect=drawRectangle(st,vec2(.5),vec2(1.));
    
    // top edge, Left To Right circle
    float circleTLTR=drawCircle(st,vec2(animation0to1,1.),circSize);
    
    // bottom edge, Right To Left circle
    float circleBRTL=drawCircle(st,vec2(animation1to0,0.),circSize);
    
    // left edge, Top To Bottom circle
    float circleLTTB=drawCircle(st,vec2(0.,animation1to0),circSize);
    
    // right edge, Bottom To Top circle
    float circleRBTT=drawCircle(st,vec2(1.,animation0to1),circSize);
    
    if((mod(indices.x,2.)==0.&&mod(indices.y,2.)==1.)||(mod(indices.x,2.)==1.&&mod(indices.y,2.)==0.)){
        
        canvas=mix(canvas,white,rect);
        canvas=mix(canvas,black,circleTLTR);
        canvas=mix(canvas,black,circleBRTL);
        
    }else{
        
        canvas=mix(canvas,black,rect);
        canvas=mix(canvas,white,circleRBTT);
        canvas=mix(canvas,white,circleLTTB);
        
    }
    
    gl_FragColor=vec4(canvas,1.);
}

Week 2 Shader

I wanted to explore creating textures through black and white gradients. As well as using the idea of truchet tiles.

I began with simple shapes and gradients.

 

screenshot-2021-02-03-181448

 

Tiling them generates a texture.

screenshot-2021-02-03-181431

 

Moving the location of the circles will create different patterns, some becoming almost seamless.

screenshot-2021-02-03-181344

 

Code:

#ifdef GL_ES
precision mediump float;
#endif

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

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

vec2 createGrid(in vec2 st,in vec2 grid,out vec2 indices){
st*=grid;
indices=floor(st);
st=fract(st);
return st;
}

float drawRectangle(vec2 st,vec2 pos,vec2 size){
float result=1.;
vec2 border=(1.-size)/2.200;
st=st-pos+vec2(.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;
}

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

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

// good practice to take a copy of the original st
// before you change it
vec2 st0=st;

vec2 indices;

// create our grid
st=createGrid(st,vec2(10.,10.),indices);

vec3 color=vec3(0.);

// a float to control animation speed
float speed=.5;

float circle1=drawCircle(st,vec2(1.,1.),.5);
float circle2=drawCircle(st,vec2(0.,0.),.5);

// animations
// float circle1=drawCircle(st,vec2(0.,map(cos(u_time*speed),-1.,1.,0.,1.)),.5);
// float circle2=drawCircle(st,vec2(1.,map(cos(u_time*speed),-1.,1.,1.,0.)),.5);
// float circle1=drawCircle(st,vec2(map(sin(u_time*speed),-1.,1.,0.,1.),map(cos(u_time*speed),-1.,1.,0.,1.)),.5);
// float circle2=drawCircle(st,vec2(map(cos(u_time*speed),-1.,1.,0.,1.),map(sin(u_time*speed),-1.,1.,0.,1.)),.5);

// color = vec3(st.t.y,abs(sin(u_time)));
vec2 size=vec2(.25,.25);
vec2 pos=vec2(.5,.5);

// color = mix( color, vec3(pct2)*(atan(u_time)+1.)*0.03, circle2);

// background gradient
float rect=drawRectangle(st,vec2(.5),vec2(1.));

// various gradients based on different distances
float pct=distance(st,vec2(.5));
float pct2=distance(st,vec2(1.,1.));
float pct3=distance(st,vec2(0.,0.))*2.;
float pct4=distance(st,vec2(0.,0.));
float pct5=distance(st,vec2(map(sin(u_time*speed),-1.,1.,0.,1.),map(cos(u_time*speed),-1.,1.,0.,1.)));

// use the mix function to draw multiple shapes
color=mix(color,vec3(pct2),rect);
color=mix(color,vec3(pct5),circle1);
color=mix(color,vec3(pct),circle2);

gl_FragColor=vec4(color,1.);
}

My First Shader

Using the mix function in an HSB space, I animate through the color wheel using u_time.

Originally, I made a circular and smooth transition through all the hues, which was brightest in the center.

By adding the exp() and sin() shaping functions, the animation becomes psychedelic and more complex over time.

I struggled most with the fact that I can’t yet predict what the code will do. I’m coming from a place where I can write code and know what it will do before running it… GLSL is like a black box to me right now. Hoping to get a better grasp on it over the next week.

#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 u_resolution;
uniform float u_time;
// Function from IƱigo Quiles
// https://www.shadertoy.com/view/MsS3Wc
vec3 hsb2rgb(in vec3 c){
vec3 rgb=clamp(abs(mod(c.x*6.+vec3(0.,4.,2.),6.)-3.)-1.,0.,1.);
rgb=rgb*rgb*(3.-2.*rgb);
returnc.z*mix(vec3(1.),rgb,c.y);
}
void main(){
vec2 st=gl_FragCoord.xy/u_resolution;
vec3 color=vec3(0.);
vec2 toCenter=vec2(.5)-st*exp(sin(u_time*st.x));
float angle=max(toCenter.y,toCenter.x);
float radius=length(toCenter)*0.5;
color=hsb2rgb(vec3((angle/6.)+u_time*0.15,radius,1.));
gl_FragColor=vec4(color,1.);
}

screen-shot-2021-01-21-at-2-50-14-pm

screen-shot-2021-01-21-at-2-50-18-pm

screen-shot-2021-01-21-at-2-50-41-pm