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