Final

For my final project, I incorporated my knowledge of shaders gained during this class into one of my past game projects. The project I plan to use is a 2D Unity platformer, for comparison the original game can be played here: https://bakaretsu.itch.io/shanghai-scramble
I made 2 major changes to the project, I added floating particles that hover around the player that indicate their combo score, and I added a dissolve shader that dissolves the player’s sprite when they get hurt. GIFs of the shaders are shown below. There is a post-processing effect applied to the player as well, that results in the bloom that occurs during the dissolve.

particles

dissolve2

 

A playable build of the game for Windows can be downloaded here: https://drive.google.com/drive/folders/1brWm4flKaUf9cZ8z0X9QRmDXeSvDgU8o?usp=sharing

Week 10 HW

For this week, I created a holographic shader using the shader graph and post-processing effects. I modified the alpha and emission in the shader graph to achieve the line effect, and used a global volume post processing effect to add a bloom effect.

hologram

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 3 HW

For this week, I expanded upon my week 2 shader by adding noise and distorting it.

ripple

I first started by adding noise to the colour of my circles, and I experimented with the effects using different values would give me. I also applied noise to the entire canvas by using st.x, distorting the entire sketch.

 


#ifdef GL_ES
precision mediump float;
#endif

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

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 drawCircle (vec2 st, vec2 pos, float size){
float result = distance (st, pos);
result=1.-step(size,result);


return result;
}

float random (vec2 st) {
return fract(sin(dot(st.xy,
vec2(12.9898,78.233)))*
43758.5453123);
}
vec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }

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() {

vec2 st = gl_FragCoord.xy/u_resolution.xy;
st.x *= u_resolution.x/u_resolution.y;

st.x += snoise(st*0.4);
// good practice to take a copy of the original st
// before you change it
vec2 st0 = st;

vec2 indices;

// This divides the result of the sin function, changing the final size of the circle
float size = 3.;

// This changes the period of the sin function, changing the speed at which the circles animate
float speed = 3.;

vec3 color;

color.r = snoise(st*2. + vec2(0., u_time*.5)) * 0.5+0.5;
color.g = snoise(st*2. + vec2(100., u_time*.5)) * 0.5+0.5;
color.b = snoise(st*2. + vec2(200., u_time*.5)) * 0.5+0.5;
// Create grid for circles
st = createGrid( st, vec2(5., 5.), indices);

// Set bg colour
// Change the colour and sin function of each column
if(indices.x == 0.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);

}else if(indices.x == 1.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+1.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 2.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+2.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 3.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+3.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}
else if(indices.x == 4.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+4.)/size);
vec3 circleC;

circleC.r = snoise(st*2. + vec2(0., u_time*2.)) * 0.5+0.5;
circleC.g = snoise(st*2. + vec2(100., u_time*2.)) * 0.5+0.5;
circleC.b = snoise(st*2. + vec2(200., u_time*2.)) * 0.5+0.5;
color = mix( color, circleC, r);
}

gl_FragColor = vec4(color,1.0);
}

Week 2 HW

My favourite shader made this week was this neat ripple effect created using techniques learned in the patterns video, shaping functions video, as well as my own explorations into the sin function.

ripple

I first began by modifying the code from the grid example, and created a series of if else statements targeting each column individually.

In each of these conditions, I drew circles with the size being based off a sin function using u_time, which created an effect where the circle grew and shrunk over time.

I modified the speed of the effect by multiplying  u_time, effectively changing the period of the function, which resulted in a shorter cycle and animation. This can be seen below in my experiments in graphtoy, the orange wave is sin(x) while the shorter yellow wave is sin(x*2).

screenshot-2021-02-16-203402

In order to offset the animation of each circle to create the ripple effect, I added a varying horizontal shift to each function, so that the cycles would occur quickly in succession. Once again, this was verified using graphtoy.

Overall, making this shader refreshed a lot of what I learned about sin functions and their modifiers, and it was especially interesting using sin functions with u_time to create an animated shader.

 

#ifdef GL_ES
precision mediump float;
#endif

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

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 drawCircle (vec2 st, vec2 pos, float size){
float result = distance (st, pos);
result=1.-step(size,result);


return result;
}

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;

// This divides the result of the sin function, changing the final size of the circle
float size = 4.;

// This changes the period of the sin function, changing the speed at which the circles animate
float speed = 5.;

// Create grid for circles
st = createGrid( st, vec2(5., 5.), indices);

// Set bg colour
vec3 color = vec3(0.995,0.764,0.451);
// Change the colour and sin function of each column
if(indices.x == 0.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed)/size);
color = mix( color, vec3(0.683,0.289,1.000), r);
}else if(indices.x == 1.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+1.)/size);
color = mix( color, vec3(1.000,0.243,0.831), r);
}
else if(indices.x == 2.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+2.)/size);
color = mix( color, vec3(1.000,0.118,0.380), r);
}
else if(indices.x == 3.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+3.)/size);
color = mix( color, vec3(1.000,0.188,0.236), r);
}
else if(indices.x == 4.){
float r = drawCircle(st, vec2(0.5), sin(u_time*speed+4.)/size);
color = mix( color, vec3(1.000,0.237,0.122), r);
}

gl_FragColor = vec4(color,1.0);
}

Week 1 HW

For week 1’s homework, I experimented with shaping functions as well as u_time to create a neat moving gradient effect.

hw

I was pretty interested in using the sin function in conjunction with u_time to create a repeating pattern of colours. I first began by generating a moving pattern using the sin function, and editing the numbers to see what effects I could achieve.

After some experimentation, I took the shader one step further by not only changing the G value over time with sin, but also the B value. This created 2 patterns that moved out of sync with each other. Funnily enough this reminded me of looking out the window of a train, and seeing how scenery closer to you would speed by faster than scenery farther away.


#ifdef GL_ES
precision mediump float;
#endif

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

#define TWO_PI 6.283185307

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

float amt = st.x;
float amt2 = st.x;

amt = sin( u_time * 2. + st.x * TWO_PI * 1.7 ) * 0.5 + 0.620;
amt2 = sin( u_time * 15. + st.x * TWO_PI * 1.5 ) * 0.700 + 0.6;

// combine amt together
vec3 color = vec3( 0.9, amt, amt2);

gl_FragColor = vec4(color,1.0);
}