Week 5 Homework

For this week’s assignment I worked with Joshua Linton, and we decided to both port a shader from previous weeks as well as choose one of the remaining options.  While porting the shader, Joshua was having trouble with getting his shader to work, and we discovered the only issue was the fact that while loading the shader, the vert had to come before the frag.

Ported Shader from Last Week:
https://editor.p5js.org/ryanmackboyd/sketches/q2fBsppHg

Afterwards, Joshua chose to create a displacement shader using an image of text that turned out to be something really interesting.  I chose to play with a live video shader, iterating on the Video Paint example through the use of its wobbled offset but instead creating a grid that grew its cells based on the mouse’s y axis and pixelated based on the mouse’s x axis.  The result was a very cool experiment that I call Mirror of Fragments.

Mirror of Fragments:
https://editor.p5js.org/ryanmackboyd/sketches/beBWXEB4b

week5

week52

week53

Through this process I learned the importance of keeping variables consistent between fragment shaders and javascript, so that you can pass information along through the setUniform command.  I also learned that you could map the mouse separately on two axis by creating 2 floats in the fragment shader and then attaching them to the mapped mouseX and mouseY respectively.  Overall this was an enjoyable collaboration between Joshua and I.

 

Week 5 – Dysmorphic Mosaic

screen-shot-2021-03-17-at-12-35-43-am screen-shot-2021-03-17-at-12-36-23-am


#ifdef GL_ES
precision mediump float;
#endif

uniform sampler2D tex0;
uniform vec2 uResolution;
uniform float uTime;
uniform float uDisplacement;
uniform vec2 uMousePosition;

varying vec2 vTexCoord;

float amt = -0.05; // the amount of displacement
float squares = 40.0; // the number of squares to render vertically

void main() {

float aspect = uResolution.x / uResolution.y;
float offset = amt * 0.5;

vec2 uv = vTexCoord;

// the texture is loaded upside down and backwards by default so lets flip it
uv.y = 1.0 - uv.y;

// copy of the texture coords
vec2 tc = uv;

// move into a range of -0.5 - 0.5
uv -= 0.5;

// correct for window aspect to make squares
uv.x *= aspect;

// tile will be used to offset the texture coordinates
vec2 tile = fract(uv * squares + 0.5) * (tan(amt));

// sample the texture using our computed tile
// offset will remove some texcoord edge artifacting
vec4 tex = texture2D(tex0, vec2(fract(tc*uDisplacement) + fract(tile*uDisplacement-uTime*0.1) - offset));

// render the output
gl_FragColor = tex;

}

Week 5 – Image Distortion

screen-shot-2021-03-17-at-2-16-54-am-min screen-shot-2021-03-17-at-2-10-40-am-min screen-shot-2021-03-17-at-2-01-04-am-min

Image Distortion (Noise)


#ifdef GL_ES
precision mediump float;
#endif
 
uniform vec2 uMousePosition;
uniform vec2 uResolution;

uniform sampler2D uTexture0; // image
uniform sampler2D uTexture1; // image2
uniform bool uMousePressed;
uniform float uTime;
uniform float uDisplacement;
 
varying vec2 vTexCoord;

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

// 2D Noise based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
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;
}

// calulate luminosity/brightness of pixel from rgb
float rgb_to_luma( vec3 color ){
 return 0.2126*color.r + 0.7152*color.g + 0.0722*color.b;
}

// map range (just like processing/p5)
float map(float value, float min1, float max1, float min2, float max2) {
 
 return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
}

void main() {
 
 vec4 color = vec4(0.0, 0.0, 0.0, 1.0);
 
 float br = rgb_to_luma(texture2D(uTexture0, vec2(vTexCoord.x, 1.0-vTexCoord.y)).rgb);
 
 vec2 uv = vec2(vTexCoord.x, 1.0-vTexCoord.y);
 color = texture2D(uTexture0, fract(uv));

// Use the noise function
 float n = noise(uv);
 
 float mode = 4.0;
 mode = floor(mode);
 
 if( mode==4.0){

vec4 color1 = texture2D(uTexture0, vec2(vTexCoord.x, fract(1.0-vTexCoord.y)));
 
 // get brightness
 // map from 0, 1 => -1, 1
 float br = rgb_to_luma(color1.rgb);
 br = map(br, 0.0, 1., -1., 1.);
 
 // add brigness to current pixel lookup
 // use fract to repeat values
 color = texture2D(uTexture1, vec2(fract(vTexCoord.x+ br*uDisplacement), fract(1.0-vTexCoord.y+ br*uDisplacement)));
 } 
 
 
 gl_FragColor = vec4(color);
}

 

Week 5 HW

For this week’s homework, I worked with Shannen to explore shaders in p5.js. After porting one of my previous shaders to p5.js, I decided to create a shader that distorts an image using shaping functions.

The code for this sketch can be found here: https://editor.p5js.org/Bakaretsu/sketches/zxuKhPC0z

The images I distorted are of Morshu from the Legend of Zelda games. I was inspired by a recent hyper detailed render of him that was posted on the internet, and decided to have these 2 images morph into each other in some way. bts3dho3e7f61tx4xftkd67j2y5zd

I followed the example in the displacement video, and created an offset that changed based on the sin value of time. I multiplied the sin wave to make the warping effect more intense in the x and y directions.

To blend between the 2 images, I used the mix function and passed in time as the value to use to interpolate. This resulted in the 2 images blending between each other over time.

I combined that effect with the displacement shader to create the end result.

Week 5

I worked with Nicole Vella for this week’s homework.

This one which resembles a diffractive glass wall (or kind of like tiny glass brick) is achieved by creating a large grid (with tiny units) where each grid unit has its webcam image shifted slightly to focus on the part where it lies in the greater grid. A brownian noise was added on top by Nicole and then I also added an interactive “clear” spot that can be moved by the mouse. View on p5 here

screenshot-2021-02-22-054756

precision mediump float;

// lets grab texcoords just for fun
varying vec2 vTexCoord;

// our texture coming from p5
uniform sampler2D tex0;
uniform float time;
uniform vec2 uMousePos;

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 drawCircle( vec2 st, vec2 pos, float size ){

float result = distance( st, pos);
result = smoothstep( result, result + 0.1 * (sin(time* 2.) * 0.5 + 0.5), 0.15);

return result;
}

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

st *= grid;

indices = floor(st);
st = fract(st);

return st;
}

void main() {

vec2 uv = vTexCoord;
// the texture is loaded upside down and backwards by default so lets flip it
uv = 1.0 - uv;
vec2 st = uv;
vec2 test = uv;
vec2 indices;
st = createGrid(st, vec2(100.), indices);

float n=snoise(vTexCoord+time*0.3)*.5+.5;

// add the distortion to our texture coordinates
vec4 tex = texture2D(tex0, uv + st / 9. * n);
float c = drawCircle(test, uMousePos, 0.05);

vec2 toCenter = vec2(0.5)-st;
float angle = atan(toCenter.y,toCenter.x);
float radius = length(toCenter)*2.0;
float z = radius * 10.*sin(time/1.+ atan(st.y, st.x));

vec4 originalTex = texture2D(tex0, test);
tex = mix(tex, originalTex, c);

gl_FragColor = tex;
}

The second randomly samples a gridded colour palette to create multiple moving shapes which are then mixed using brownian motion.
The grid size of the palette needs to be specified, and it will generate a different result every time. View on p5 here

screenshot-2021-02-17-220830
palette

screenshot-2021-02-22-055437

precision mediump float;

// lets grab texcoords just for fun
varying vec2 vTexCoord;

// our texture coming from p5
uniform sampler2D u_tex0;
uniform float u_time;
uniform vec2 u_mouse;
uniform vec2 u_resolution;
uniform vec2 randCoord1;
uniform vec2 randCoord2;
uniform vec2 randCoord3;
uniform vec2 randCoord4;
uniform vec2 randCoord5;
uniform vec2 randCoord6;
uniform vec2 randCoord7;
uniform float gridSize;

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

// Based on Morgan McGuire @morgan3d
// https://www.shadertoy.com/view/4dS3Wd
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));

vec2 u = f * f * (3.0 - 2.0 * f);

return mix(a, b, u.x) +
(c - a)* u.y * (1.0 - u.x) +
(d - b) * u.x * u.y;
}

#define OCTAVES 6
float fbm (in vec2 st) {
// Initial values
float value = 0.0;
float amplitude = .5;
float frequency = 0.;
//
// Loop of octaves
for (int i = 0; i < OCTAVES; i++) {
value += amplitude * noise(st);
st *= 2.;
amplitude *= .5;
}
return value;
}

float drawCircle(in vec2 st, in float radius, vec2 pos){
vec2 dist = st-vec2(pos);
return 1.-smoothstep(radius-(radius*0.01),
radius+(radius*0.01),
dot(dist,dist)*4.0);
}

float drawBlurryCircle(in vec2 st, in float radius, vec2 pos){
vec2 dist = st-vec2(pos);
return 1.-smoothstep(radius-(radius*0.3),
radius+(radius*0.1),
dot(dist,dist)*4.0);
}

vec4 sampleRandomColour(vec2 randCoord, vec2 uv) {
// set up uv fields to sample colours from the image grid. divide by the cells per side so that it 'zooms' up on one colour
vec2 colourField = uv / gridSize;
// the coords provided need to be normalized
// to shift the canvas the right amount
// to focus on a single random colour
colourField += randCoord / gridSize;
// sample the colour from the image texture
return texture2D(u_tex0, colourField);
}

void main() {

vec2 uv = vTexCoord;

// flip because it's backwards
uv.y = 1.0 - uv.y;

vec4 colour;

vec4 colour1 = sampleRandomColour(randCoord1, uv);
vec4 colour2 = sampleRandomColour(randCoord2, uv);
vec4 colour3 = sampleRandomColour(randCoord3, uv);
vec4 colour4 = sampleRandomColour(randCoord4, uv);
vec4 colour5 = sampleRandomColour(randCoord5, uv);
vec4 colour6 = sampleRandomColour(randCoord6, uv);
vec4 colour7 = sampleRandomColour(randCoord7, uv);

uv += fbm(uv * 3.0);
uv -= 0.3;
uv /= 2.;

vec2 circleField = uv;
circleField.y += sin(sin(u_time) * uv.x * 20.) * 0.1;

float c = drawBlurryCircle(circleField, 0.3, vec2(0.3 + (sin(u_time) *0.5 + 0.5) * 0.2, 0.4));

vec2 circleField2 = uv;
circleField2.x *= 2.0;
circleField2.x += cos(sin(u_time / 4.) * uv.x * 100.) * 0.1;
float c2 = drawBlurryCircle(circleField2, 0.3, vec2(0.5 + (sin(u_time) *0.5 + 0.5) * 0.2, 0.6));

vec2 circleField3 = uv;
circleField3.x *= 3.0;
circleField3.y += sin(sin(u_time / 6.) * uv.x * 50.) * 0.1;
float c3 = drawBlurryCircle(circleField3, 0.7, vec2(0.1 + (sin(u_time) *0.5 + 0.5), 0.8 - (sin(u_time)*0.5 + 0.5)));

vec2 circleField4 = uv;
circleField4.y *= 5.0;
circleField4.x += sin(cos(u_time / 6.) * uv.x * 50.) * 0.1;
float c4 = drawBlurryCircle(circleField4, 0.2, vec2(0.3 + (sin(u_time) *0.5 + 0.5), 0.7 + (sin(u_time)*0.5 + 0.5)));

vec2 circleField5 = uv;
circleField5.y *= 5.0;
circleField5.x += sin(cos(u_time / 3.) * uv.x * 50.) * 0.1;
float c5 = drawCircle(circleField5, 0.4, u_mouse + vec2(0.0, 1.0));

colour = mix(colour1, colour2, dot(uv.x * 2., uv.y * 2.));
colour = mix(colour, colour3, c3);
colour = mix(colour, colour4, c);
colour = mix(colour, colour5, c2);
colour = mix(colour, colour6, c4);
colour = mix(colour, colour7, c5);

gl_FragColor = colour;
}

Shaders week 5

wolfshaderwolf1

For this first shader I took inspiration from the webcam displacement example and instead used two images together. I took a picture of a wolf’s head and a picture of water from the internet and added the sin() function to create a murky, watery effect. I used millis() in x position for the set.Uniform statement (myShader.setUniform(“uDisplacement”, map(millis()/50, 0, width, 0, 5));) to produce a u_time effect like in GLSL. In a way, the water image is being animated to displace the wolf image.


#ifdef GL_ES
precision mediump float;
#endif

uniform vec2 uMousePosition;
uniform vec2 uResolution;

uniform sampler2D uTexture0; //wolf
uniform sampler2D uTexture1; //water
uniform float uTime;
uniform float uDisplacement;

varying vec2 vTexCoord;

//takes rbg of a pixel and calculates luminosity
float rgb_to_luma( vec3 color ){
return 0.2126*color.r + 0.7152*color.g + 0.0722*color.b;
}

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

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


void main() {

vec4 color = vec4(0.0, 1.0, 1.0, 0.0);

vec2 offset = vec2(0.0, 0.0);

offset = texture2D(uTexture0, vec2(vTexCoord.x, 1.0-vTexCoord.y)).gb;
offset *= 1.0;

//colours to luminosity
float c = rgb_to_luma(texture2D(uTexture0, vec2(vTexCoord.x, 1.0-vTexCoord.y)).rgb);

offset = vec2(c, c) + uDisplacement;

vec2 uv = vec2(vTexCoord.x, 1.0-vTexCoord.y) + offset;
//vec2 uv = vec2(uTime(vTexCoord.x), 1.0-vTexCoord.y) + offset;
//using sin() to distort the image
color = texture2D(uTexture1, sin(uv) * 0.5);

gl_FragColor = vec4(color);
}

Week 5 Shader Explorations

download-31download-26download-24download-34download-36download-35

For WEEK 5, I worked with Mahnoor. I was tasked with the initial porting of our Week 3 shaders into p5.js and creating an image distortion shader.

For the image distortion shader, I created a distorter that affects the texture UV coordinates of the image, based on Simple Texture Distort by mikiex on Shader Toy. Instead of using a noise texture as mikiex did, I replaced it with generated simplex noise from the Book of Shaders. To create an inverted colour filter for the image, I divided the initial image that I added the distortion value to the UV with a mix of the distorted initial image texture with an altered second version of the image that instead subtracted the distortion from the UV. Mixing the two versions of the distorted image, one that follows the original colour scheme and another that is inverted distorts them in opposite directions. This results in a swipe effect where the value of distortion would become zero in both directions (looped using sin) and will form the original non-distorted image of the flowers for a split second.

The distorted colours and rounded shapes that the noise forms the image into reminds me of the psychedelic closeups of the surface of a soap bubble (caused by a two-beam interference of light).

Overall, I enjoyed the Shader exercises this week and had fun seeing how my partner, Mahnoor, approached shader art. It was also great to have immediate feedback during the process and to support each other and help when we got stuck.

There is not much to say about porting our Week 3 shaders into p5.js, other than every line of setup code counts. It was more complicated than I thought it would be, although fairly straightforward to execute once you are used to the process. I did have fun applying the shaders as textures to some simple (default) shapes (a sphere and box). I added simple interaction to the p5.js sketch to switch between 3D shapes and shaders on mouse click as well allow the viewer to rotate the shapes using mouse coordinates.


//Author: Madelaine Fischer-Bernhut
//Title: Image Distortion

#ifdef GL_ES
precision mediump float;
#endif

//get texture coordinates from vert shader
varying vec2 vTexCoord;
 
uniform vec2 u_resolution;
uniform vec2 u_mouse;
uniform float u_time;

//texture coming from p5.js
uniform sampler2D imgtext;

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

void main() {
 
 // position of the pixel divided by resolution, to get normalized positions on the canvas
 vec2 st = gl_FragCoord.xy/u_resolution.xy; 
 
 vec2 uv = vTexCoord;
 
 //texture is loaded upside down and backwards by default, so flip it
 uv.y = 1.0 - uv.y;
 
 //create a distorter (based off Simple Texture Distort by mikiex, instead of another texture it uses snoise)
 vec2 pos = vec2(st.x*10.0 - (u_time*0.2), st.y*10.0 + (u_time*0.2));
 
 vec3 dist = vec3(snoise(pos)*0.5+0.5);
 
 vec2 distorter = vec2(dist.rg) * vec2(0.1-sin(u_time*0.2));
 
 //zoom in and out of image by multiplying the "UV" value, use fract to tile zoomed out images 
 vec4 imgText = texture2D(imgtext, fract(uv)+distorter);
 vec4 imgText2 = texture2D(imgtext, fract(uv)-distorter);


 float grey = (imgText.r + imgText.g + imgText.b)/3.0;
 
 vec3 color = vec3(0); 
 
 //grey filter
 // color = vec3(grey); 
 
 //default (full) color
 color = vec3(imgText.r,imgText.g, imgText.b); 
 
 //blend in an "inverted" color filter version of the image
 // color /= mix(color, vec3(1.0), vec3(imgText2.r,imgText2.g, imgText2.b));

 color /= mix(color, vec3((sin(u_time*0.1))), vec3(imgText2.r,imgText2.g, imgText2.b));
 
 //direct image color
 // gl_FragColor = vec4(imgText);
 
 //filtered camera feed
 gl_FragColor = vec4(color, 1.0);
}