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

Leave a Reply