Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
133 changes: 26 additions & 107 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,123 +1,42 @@

# Project 5: Shaders

## Project Instructions

Implement at least 75 points worth of shaders from the following list. We reserve the right to grant only partial credit for shaders that do not meet our standards, as well as extra credit for shaders that we find to be particularly impressive.

Some of these shading effects were covered in lecture -- some were not. If you wish to implement the more complex effects, you will have to perform some extra research. Of course, we encourage such academic curiosity which is why we’ve included these advanced shaders in the first place!

Document each shader you implement in your README with at least a sentence or two of explanation. Well-commented code will earn you many brownie (and probably sanity) points.

If you use shadertoy or any materials as reference, please properly credit your sources in the README and on top of the shader file. Failing to do so will result in plagiarism and will significantly reduce your points.

Examples: [https://cis700-procedural-graphics.github.io/Project5-Shaders/](https://cis700-procedural-graphics.github.io/Project5-Shaders/)

### 15 points each: Instagram-like filters

- Tone mapping:
- Linear (+5 points)
- Reinhard (+5 points)
- Filmic (+5 points)
- Gaussian blur (no double counting with Bloom)
- Iridescence
- Pointilism
- Vignette
- Fish-eye bulge

### 25 points each:
- Bloom
- Noise Warp
- Hatching
- Lit Sphere ([paper](http://www.ppsloan.org/publications/LitSphere.pdf))

### 37.5 points each:
- K-means color compression (unless you are extremely clever, the k-means clusterer has to be CPU side)
- Dithering
- Edge detection with Sobel filtering
- Uncharted 2 customizable filmic curve, following John Hable’s presetantion.
- Without Linear, Reinhard, filmic (+10 points)
- With all of linear, Reinhard, filmic (+10 points)
- Customizable via GUI (+17.5 points)
- Controlling Exposure (4 points)
- Side by side comparison between linear, Reinhard, filmic, and Uncharted2 (13.5 points).

### 5 points - Interactivity
Implement a dropdown GUI to select different shader effects from your list.

### ??? points
Propose your own shading effects!

### For the overachievers:
Weave all your shading effects into one aesthetically-coherent scene, perhaps by incorporating some of your previous assignments!


## Getting Started

### main.js

`main.js` is responsible for setting up the scene with the Mario mesh, initializing GUI and camera, etc.

### Adding Shaders

To add a shader, you'll want to add a file to the `src/shaders` or `src/post` folder. As examples, we've provided two shaders `lambert.js` and `grayscale.js`. Here, I will give a brief overview of how these work and how everything hooks together.

**shaders/lambert.js**

IMPORTANT: I make my lambert shader available by exporting it in `shaders/index.js`.

```javascript
export {default as Lambert} from './Lambert'
```

Each shader should export a function that takes in the `renderer`, `scene`, and `camera`. That function should return a `Shader` Object.
[Demo](http://josephgao.me/Project5-Shaders)

`Shader.initGUI` is a function that will be called to initialize the GUI for that shader. in `lambert.js`, you can see that it's here that I set up all the parameters that will affect my shader.
* Author: Joseph Gao
* PennKey: gaoj

`Shader.material` should be a `THREE.ShaderMaterial`. This should be pretty similar to what you've seen in previous projects. `Shader.material.vertexShader` and `Shader.material.fragmentShader` are the vertex and fragment shaders used.
**Goal:** Create some cool shaders using WebGL.

At the bottom, I have the following snippet of code. All it does is bind the Mario texture once it's loaded.
* DISCLAIMER - I accidentally made Hatching a Shader rather than a Post Shader. I was too lazy to change it (also it's 6AM), but I understand that Cross Hatching is considered a Post rather than a render step.

```javascript
textureLoaded.then(function(texture) {
Shader.material.uniforms.texture.value = texture;
});
```
## 95 points worth of shaders implemented.

So when you change the Shader parameter in the GUI, `Shader.initGUI(gui)` will be called to initialize the GUI, and then the Mario mesh will have `Shader.material` applied to it.
## Render Time Shaders

**post/grayscale.js**
### Iridescence (15 pts)
![](./ss1.png)
- My iridescence implementation responds to the lightColor slider as well as the ambient light slider. The shading is done at render time, not in post. The iridescence itself is a default magenta/blue color. I added in a magenta outline as well (in the same way a toon outline is added) because I thought it would look nice!

GUI parameters here are initialized the same way they are for the other shaders.

Post process shaders should use the THREE.js `EffectComposer`. To set up the grayscale filter, I first create a new composer: `var composer = new EffectComposer(renderer);`. Then I add a a render pass as the first pass: `composer.addPass(new EffectComposer.RenderPass(scene, camera));`. This will set up the composer to render the scene as normal into a buffer. I add my filter to operate on that buffer: `composer.addPass(GrayscaleShader);`, and mark it as the final pass that will write to the screen `GrayscaleShader.renderToScreen = true;`
### Hatching (25 pts)
![](./ss2.png)
- As mentioned above, I accidentally implemented my Hatching shader as a render time shader rather than a post render shader. I understand the difference, but on the bright side, the albedo slider works nicely with my hatching shader. The ambient light and light color sliders simply re-adjust how many hatches will appear. The hatching algorithm was borrowed from a unity3D forum (I mixed in some fundamentals from our own slides and attempted to improve on the evenly distributed hatches produced by the method suggested in the class slides by incorporating ideas from the forum). The forum link can be found in the GLSL file!

GrayscaleShader is a `EffectComposer.ShaderPass` which basically takes the same arguments as `THREE.ShaderMaterial`. Note, that one uniform that will have to include is `tDiffuse`. This is the texture sampler which the EffectComposer will automatically bind the previously rendered pass to. If you look at `glsl/grayscale-frag.glsl`, this is the texture we read from to get the previous pixel color: `vec4 col = texture2D(tDiffuse, f_uv);`.
### Static (??? pts)
![](./ss3.png)
- This is my own proposed shader. I was attempting to perform iridescence and accidentally ran into this shader that is based largely on noise. The effect was really cool and reminded me of a antenna TV with no signal, receiving only static, hence the name. I decided this would be the shader we were to submit for the "your own shader" section.

IMPORTANT: You initially define your shader passes like so:

```javascript
var GrayscaleShader = new EffectComposer.ShaderPass({
uniforms: {
tDiffuse: {
type: 't',
value: null
},
u_amount: {
type: 'f',
value: options.amount
}
},
vertexShader: require('../glsl/pass-vert.glsl'),
fragmentShader: require('../glsl/grayscale-frag.glsl')
});
```
## Post Render Shaders

BUT, if you want to modify the uniforms, you need to do so like so: `GrayscaleShader.material.uniforms.u_amount.value = val;`. Note the extra `.material` property.
### Pointilism (15 pts)
![](./ss4.png)
- You are able to modify the amount of points used to draw Mario, as well as the color of the points for some pretty cool effects. The login behind my code is well documented in the GLSL file, and I used a glsl random function that everyone seems to be able to find on Stack Overflow.

## Deploy
### Vignette (15 pts)
![](./ss5.png)
- Like my Pointilism shader, you are able to modify both the color and the intensity of the vignette filter. While brighter colors may make the circle harder to see, I promise it is there.

1. Create a `gh-pages` branch on GitHub
2. Do `npm run build`
3. Commit and add all your changes.
4. Do `npm run deploy`
### NoiseWarp (25 pts)
![](./ss6.png)
- Okay, I know. It doesn't look as good as the one presented in the demo, and in fact just looks like Mario is vibrating on the X and Y axes indefinitely. The frequency slider does alter the intensity of his vibrations, though! In all seriousness, the most amount of work went into this shader. I first brought back concepts from Project 1 by calculating and interpolating a noise value for each fragment using techniques we have already studied (linear, cosine interpolation), and then I use these noise values to offset the UV coordinates in a way very similar to Mini Minecraft from my CIS 460 days.
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>Shader Demos</title>
<title>HW5: Shaders</title>
<style>
html, body {
margin: 0;
Expand Down
Binary file added src/.DS_Store
Binary file not shown.
13 changes: 13 additions & 0 deletions src/glsl/flux-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@

uniform sampler2D tDiffuse;
uniform float u_amount;
uniform vec3 u_color;
varying vec2 f_uv;

void main() {
vec4 col = texture2D(tDiffuse, f_uv);
col.rgb = u_color * (u_amount) + col.rgb * (1.0 - u_amount);
gl_FragColor = col;

}

2 changes: 1 addition & 1 deletion src/glsl/grayscale-frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ void main() {
col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount);

gl_FragColor = col;
}
}
56 changes: 56 additions & 0 deletions src/glsl/hatch-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// source - https://forum.unity3d.com/threads/ported-cross-hatching-shader-from-webgl.136100/

uniform vec3 u_albedo;
uniform vec3 u_ambient;
uniform vec3 u_lightPos;
uniform vec3 u_lightCol;
uniform float u_lightIntensity;
uniform vec3 u_cameraPos;

varying vec3 f_position;
varying vec3 f_normal;
varying vec2 f_uv;


void main() {
vec4 color = vec4(u_albedo, 1.0);
gl_FragColor = color;

vec3 light_direction = normalize(u_lightPos - f_position);
float light_direction_weight = max(dot(normalize(f_normal), light_direction), 0.0);
vec3 light_weight = u_ambient + u_lightCol * light_direction_weight;

// check for outline
vec3 camera_dir = normalize(u_cameraPos - f_position);
if (dot(f_normal, camera_dir) < 0.2) {
gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
}
else {
// originally i just have a simple sin function + noise, but it didn't look that great.
// vary the mod values from 10 to 40 for different line distances, and use the sin method shown in class.
if (length(light_weight) < 1.00) {
if (mod(gl_FragCoord.x + gl_FragCoord.y, 40.0) == 0.0) {
gl_FragColor = color * (sin(gl_FragCoord.x + gl_FragCoord.y));
}
}

if (length(light_weight) < 0.75) {
if (mod(gl_FragCoord.x - gl_FragCoord.y, 30.0) == 0.0) {
gl_FragColor = color * (sin(gl_FragCoord.x - gl_FragCoord.y));
}
}

if (length(light_weight) < 0.50) {
if (mod(gl_FragCoord.x + gl_FragCoord.y - 5.0, 16.0) == 0.0) {
gl_FragColor = color * (sin(gl_FragCoord.x + gl_FragCoord.y));
}
}

if (length(light_weight) < 0.3465) {
if (mod(gl_FragCoord.x - gl_FragCoord.y - 5.0, 10.0) == 0.0) {
gl_FragColor = color * (sin(gl_FragCoord.x - gl_FragCoord.y));
}
}
gl_FragColor = gl_FragColor * u_lightIntensity;
}
}
12 changes: 12 additions & 0 deletions src/glsl/hatch-vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

varying vec2 f_uv;
varying vec3 f_normal;
varying vec3 f_position;

void main() {
f_uv = uv;
f_normal = normal;
f_position = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

43 changes: 43 additions & 0 deletions src/glsl/iridescence-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@

uniform sampler2D texture;
uniform int u_useTexture;
uniform vec3 u_albedo;
uniform vec3 u_ambient;
uniform vec3 u_lightPos;
uniform vec3 u_lightCol;
uniform float u_lightIntensity;
uniform vec3 u_cameraPos;

varying vec3 f_position;
varying vec3 f_normal;
varying vec2 f_uv;

// this function is from SO
float rand(float x){
return fract(sin(dot(vec3(x, x, x), vec3(12.9898, 78.233, 78.233))) * 43758.5453);
}

void main() {
vec4 color = vec4(u_albedo, 1.0);

if (u_useTexture == 1) {
color = texture2D(texture, f_uv);
}

vec3 camera_dir = normalize(u_cameraPos - f_position);
float d = clamp(dot(f_normal, camera_dir), 0.0, 1.0);

// i like using outlines
if (d < 0.08) {
gl_FragColor = vec4(0.5, 0.0, 1.0, 0.5);
}
else {
float r = 0.1 + 0.25 * sin(1.34 * fract(d));
float g = 0.4 + 0.25 * sin(3.56 * fract(d) + 0.25);
float b = 0.6 + 0.25 * sin(2.53 * fract(d) + 0.5);

// randomize the resulting dot product
color = vec4(r, g, b, 1.0);
gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);
}
}
12 changes: 12 additions & 0 deletions src/glsl/iridescence-vert.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

varying vec2 f_uv;
varying vec3 f_normal;
varying vec3 f_position;

void main() {
f_uv = uv;
f_normal = normal;
f_position = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

4 changes: 2 additions & 2 deletions src/glsl/lambert-frag.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@ varying vec2 f_uv;

void main() {
vec4 color = vec4(u_albedo, 1.0);

if (u_useTexture == 1) {
color = texture2D(texture, f_uv);
}

float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0);

gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0);
}
}
2 changes: 1 addition & 1 deletion src/glsl/lambert-vert.glsl
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,4 @@ void main() {
f_normal = normal;
f_position = position;
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}
}
65 changes: 65 additions & 0 deletions src/glsl/noisewarp-frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// change the color of the points as well!

uniform sampler2D tDiffuse;
uniform float u_freq;
uniform vec3 u_color;
uniform float u_time;
uniform float u_amp;
varying vec2 f_uv;


// our favorite SO glsl random function!
float rand(float x, float y, float z){
return fract(sin(dot(vec3(x, y, z), vec3(12.9898, 12.9898, 78.233))) * 43758.5453);
}


// my noise functions
float lerp(float a, float b, float t) {
return a * (1.0 - t) + b * t;
}

float cosine_interpolate(float a, float b, float t) {
float cos_t = (1.0 - cos(t * 3.1459)) * 0.5;
return lerp(a, b, cos_t);
}

float interpolate_noise(float x, float y, float z) {
//pos
float pos_NE = rand(ceil(x), ceil(y), ceil(z));
float pos_NW = rand(floor(x), ceil(y), ceil(z));
float pos_SW = rand(floor(x), ceil(y), floor(z));
float pos_SE = rand(ceil(x), ceil(y), floor(z));

//neg
float neg_NE = rand(ceil(x), floor(y), ceil(z));
float neg_NW = rand(floor(x), floor(y), ceil(z));
float neg_SW = rand(floor(x), floor(y), floor(z));
float neg_SE = rand(ceil(x), floor(y), floor(z));

float x_t = ceil(x) - x;
float z_t = ceil(z) - z;
float y_t = ceil(y) - y;

float pos_north = cosine_interpolate(pos_NE, pos_NW, x_t);
float pos_south = cosine_interpolate(pos_SE, pos_SW, x_t);
float pos_ns = cosine_interpolate(pos_north, pos_south, z_t);

float neg_north = cosine_interpolate(neg_NE, neg_NW, x_t);
float neg_south = cosine_interpolate(neg_SE, neg_SW, x_t);
float neg_ns = cosine_interpolate(neg_north, neg_south, z_t);

float res_noise = cosine_interpolate(pos_ns, neg_ns, y_t);

// returned interpolated noise for a single point
return res_noise;
}


void main() {
float warp = interpolate_noise(f_uv.x, f_uv.y, u_amp * sin(u_time * 0.01));
vec2 new_uv = f_uv + vec2(-0.3 * sin(warp), 0.2 * sin(warp));
gl_FragColor = texture2D(tDiffuse, new_uv);

}

Loading