diff --git a/README.md b/README.md index 08c69b7..a3349d4 100644 --- a/README.md +++ b/README.md @@ -1,123 +1,44 @@ # 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. - -`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. - -`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. - -At the bottom, I have the following snippet of code. All it does is bind the Mario texture once it's loaded. - -```javascript -textureLoaded.then(function(texture) { - Shader.material.uniforms.texture.value = texture; -}); -``` - -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. - -**post/grayscale.js** - -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;` - -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);`. - -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') -}); -``` - -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. - -## Deploy - -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` \ No newline at end of file +## Pointillism +This is what the pointillism shader looks like for different threshold and light intensity values. +
+ + +
+ +## Iridescence +This is what the iridescence shader looks like for different light color and light intensity values. +
+ + +
+ +## Fish-Eye Bulge +This is what the fish-eye bulge shader looks like for different amount values. +
+ + +
+ +## Vignette +This is what the vignette shader looks like for different offset and darkness values. +
+ + +
+ +## Comic Book +This is what the comic book shader looks like for different amount values. For this shader, I tried to mimic the effect Apple's Photobooth application has. This post- shader creates diamonds on the screen and colors them based on the base color's darkness. If the base color is darker than a certin value, the diamond that covers it is colored a lighter color. If the base color is brighter than a certin value, the diamond that covers it is colored a darker color. If the base color is too dark or too bright, the diamond remains the same color. This effect, in my opinion, goes well over the toon shader. +
+ + +
+ +## Edge detection with Sobel filtering +This is what the sobel filter shader looks like for different amount values. +
+ + +
\ No newline at end of file diff --git a/cm1.png b/cm1.png new file mode 100644 index 0000000..2f64c9c Binary files /dev/null and b/cm1.png differ diff --git a/cm2.png b/cm2.png new file mode 100644 index 0000000..b979572 Binary files /dev/null and b/cm2.png differ diff --git a/f1.png b/f1.png new file mode 100644 index 0000000..6fb0914 Binary files /dev/null and b/f1.png differ diff --git a/f2.png b/f2.png new file mode 100644 index 0000000..2e8142a Binary files /dev/null and b/f2.png differ diff --git a/iri1.png b/iri1.png new file mode 100644 index 0000000..81fd569 Binary files /dev/null and b/iri1.png differ diff --git a/iri2.png b/iri2.png new file mode 100644 index 0000000..a484ac4 Binary files /dev/null and b/iri2.png differ diff --git a/package.json b/package.json index a91b2a1..e14393e 100644 --- a/package.json +++ b/package.json @@ -18,5 +18,9 @@ "webpack": "^2.2.1", "webpack-dev-server": "^2.3.0", "webpack-glsl-loader": "^1.0.1" + }, + "devDependencies": { + "file-loader": "^0.10.0", + "image-webpack-loader": "^3.2.0" } } diff --git a/pt1.png b/pt1.png new file mode 100644 index 0000000..5390683 Binary files /dev/null and b/pt1.png differ diff --git a/pt2.png b/pt2.png new file mode 100644 index 0000000..5d61aca Binary files /dev/null and b/pt2.png differ diff --git a/s1.png b/s1.png new file mode 100644 index 0000000..70f790e Binary files /dev/null and b/s1.png differ diff --git a/s2.png b/s2.png new file mode 100644 index 0000000..70d7119 Binary files /dev/null and b/s2.png differ diff --git a/src/glsl/comic-frag.glsl b/src/glsl/comic-frag.glsl new file mode 100644 index 0000000..5a97d6a --- /dev/null +++ b/src/glsl/comic-frag.glsl @@ -0,0 +1,38 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; + +//from http://www.nbdtech.com/Blog/archive/2008/04/27/Calculating-the-Perceived-Brightness-of-a-Color.aspx +float darkness(vec4 c) +{ + return sqrt( + c.r * c.r * .241 + + c.g * c.g * .691 + + c.b * c.b * .068); +} + + +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + + if (col.rgb == vec3(0.6, 0.6, 0.6)) + { + gl_FragColor = col; + } + + else + + { + float sn = sin(f_uv.x * 800.0 - f_uv.y * 800.0); + float sp = sin(f_uv.x * 800.0 + f_uv.y * 800.0); + float d = darkness(col); + + if (sn < 0.3 && sp < 0.3) + { + col += (vec4(0.1, 0.1, 0.1, 1.0) * sin(2.0 * d * 3.14) * u_amount); + } + + gl_FragColor = col; + } +} \ No newline at end of file diff --git a/src/glsl/fish-frag.glsl b/src/glsl/fish-frag.glsl new file mode 100644 index 0000000..36b8768 --- /dev/null +++ b/src/glsl/fish-frag.glsl @@ -0,0 +1,26 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; + +float M_PI = 3.1415926535; + +void main() { + +// referred to http://www.geeks3d.com/20140213/glsl-shader-library-fish-eye-and-dome-and-barrel-distortion-post-processing-filters/ + + vec2 uv = f_uv.xy; + + vec2 xy = 2.0 * f_uv.xy - 1.0; + float d = length(xy); + float z = sqrt(1.0 - d * d); + float r = (1.0 - u_amount) * atan(d, z) / M_PI; + float t = atan(xy.y, xy.x); + + uv.x = r * cos(t) + 0.5; + uv.y = r * sin(t) + 0.5; + + + vec4 c = texture2D(tDiffuse, uv); + gl_FragColor = c; +} \ No newline at end of file diff --git a/src/glsl/iridescence-frag.glsl b/src/glsl/iridescence-frag.glsl new file mode 100644 index 0000000..ab20f9c --- /dev/null +++ b/src/glsl/iridescence-frag.glsl @@ -0,0 +1,35 @@ + +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; + +//from lecture slides +vec3 getNewColor(float t) +{ + vec3 col1 = vec3(0.5, 0.5, 0.5); + vec3 col2 = vec3(0.5, 0.5, 0.5); + vec3 col3 = vec3(1.0, 1.0, 0.5); + vec3 col4 = vec3(0.8, 0.9, 0.3); + + return col1 + col2 * cos(6.28318 * (col3 * t + col4)); +} + +void main() { + + float t = clamp(dot(normalize(u_cameraPos - f_position), f_normal), 0.0, 0.9); + + vec3 iriCol = getNewColor(t); + + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0); + + gl_FragColor = vec4(d * iriCol * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/iridescence-vert.glsl b/src/glsl/iridescence-vert.glsl new file mode 100644 index 0000000..86e2661 --- /dev/null +++ b/src/glsl/iridescence-vert.glsl @@ -0,0 +1,12 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/glsl/point-frag.glsl b/src/glsl/point-frag.glsl new file mode 100644 index 0000000..5c685cd --- /dev/null +++ b/src/glsl/point-frag.glsl @@ -0,0 +1,36 @@ + +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 float u_threshold; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + +float noise_gen(vec3 pos) +{ + return fract(sin(dot(pos, vec3(12.9898, 78.233, 39.73))) * 43758.545); +} + +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); + + + if (noise_gen(f_position) * d < u_threshold) + { + color = vec4(0.0, 0.0, 0.0, 1.0); + } + + gl_FragColor = vec4(color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/point-vert.glsl b/src/glsl/point-vert.glsl new file mode 100644 index 0000000..86e2661 --- /dev/null +++ b/src/glsl/point-vert.glsl @@ -0,0 +1,12 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/glsl/sobel-frag.glsl b/src/glsl/sobel-frag.glsl new file mode 100644 index 0000000..02cbf1d --- /dev/null +++ b/src/glsl/sobel-frag.glsl @@ -0,0 +1,42 @@ + +uniform sampler2D tDiffuse; +varying vec2 f_uv; + +uniform float u_amount; +vec4 amount[8]; + +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + + if (col.rgb == vec3(0.6, 0.6, 0.6)) + { + gl_FragColor = col; + return; + } + + else + { + amount[0] = vec4(1, -1, 1, -1); + amount[1] = vec4(1, 1, 1, 1); + amount[2] = vec4(-1, -1, -1, -1); + amount[3] = vec4(-1, 1, -1, 1); + amount[4] = vec4(0, 1, 0, 2); + amount[5] = vec4(0, -1, 0, -2); + amount[6] = vec4(1, 0, 2, 0); + amount[7] = vec4(-1, 0, -2, 0); + + vec4 h = vec4(0.0, 0.0, 0.0, 0.0); + vec4 v = vec4(0.0, 0.0, 0.0, 0.0); + + for (int i = 0; i < 4; i++) + { + amount[i].x *= u_amount * 0.002; + amount[i].y *= u_amount * 0.002; + + h += amount[i].z * texture2D(tDiffuse, vec2(f_uv[0] + amount[i].x, f_uv[1] + amount[i].y)); + v += amount[i].w * texture2D(tDiffuse, vec2(f_uv[0] + amount[i].x, f_uv[1] + amount[i].y)); + } + + gl_FragColor = sqrt(h * h + v * v); + } +} \ No newline at end of file diff --git a/src/glsl/toon-frag.glsl b/src/glsl/toon-frag.glsl new file mode 100644 index 0000000..00a4030 --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,36 @@ + +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; +uniform float u_numShades; + +varying vec3 f_position; +varying vec3 f_normal; +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); + + vec4 toonCol = (d + 0.5) * color; + float n = pow(u_numShades, 1.0 / 3.0); + toonCol.r = floor(toonCol.r * n) / n; + toonCol.g = floor(toonCol.g * n) / n; + toonCol.b = floor(toonCol.b * n) / n; + + if (dot(f_normal, normalize(u_cameraPos - f_position)) < 0.4) { + toonCol = vec4(0, 0, 0, toonCol.a); + } + + gl_FragColor = vec4(toonCol.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/toon-vert.glsl b/src/glsl/toon-vert.glsl new file mode 100644 index 0000000..86e2661 --- /dev/null +++ b/src/glsl/toon-vert.glsl @@ -0,0 +1,12 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} \ No newline at end of file diff --git a/src/glsl/vignette-frag.glsl b/src/glsl/vignette-frag.glsl new file mode 100644 index 0000000..9f9435b --- /dev/null +++ b/src/glsl/vignette-frag.glsl @@ -0,0 +1,13 @@ + +uniform sampler2D tDiffuse; +uniform float u_offset; +uniform float u_darkness; +varying vec2 f_uv; + +void main() { + + vec4 col = texture2D(tDiffuse, f_uv); + col.rgb *= smoothstep(0.8, u_offset / 2.0, + distance(f_uv, vec2(0.5)) * (u_darkness + u_offset)); + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/post/comic.js b/src/post/comic.js new file mode 100644 index 0000000..2ddd53b --- /dev/null +++ b/src/post/comic.js @@ -0,0 +1,48 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +var ComicShader = 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/comic-frag.glsl') +}); + +export default function Comic(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the ComicShader + composer.addPass(ComicShader); + + // set this to true on the shader for your last pass to write to the screen + ComicShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + ComicShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/fish.js b/src/post/fish.js new file mode 100644 index 0000000..fc54f14 --- /dev/null +++ b/src/post/fish.js @@ -0,0 +1,48 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 0.3 +} + +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/fish-frag.glsl') +}); + +export default function grayscale(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the grayscaleShader + composer.addPass(grayscaleShader); + + // set this to true on the shader for your last pass to write to the screen + grayscaleShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 0.5).onChange(function(val) { + grayscaleShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/index.js b/src/post/index.js index 9c0d763..f528cbd 100644 --- a/src/post/index.js +++ b/src/post/index.js @@ -15,4 +15,7 @@ export function None(renderer, scene, camera) { } // follow this syntax to make your shaders available to the GUI -export {default as Grayscale} from './grayscale' \ No newline at end of file +export {default as Comic_Book} from './comic' +export {default as Sobel_Filter} from './sobel' +export {default as Fish_Eye_Bulge} from './fish' +export {default as Vignette} from './vignette' \ No newline at end of file diff --git a/src/post/sobel.js b/src/post/sobel.js new file mode 100644 index 0000000..3743016 --- /dev/null +++ b/src/post/sobel.js @@ -0,0 +1,68 @@ + +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +var SobelShader = 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/sobel-frag.glsl') +}); + +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') +}); + +export default function Grayscale(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // apply the grayscale shader to the rendered result + composer.addPass(GrayscaleShader); + GrayscaleShader.renderToScreen = false; + + // then apply the SobelShader + composer.addPass(SobelShader); + + // set this to true on the shader for your last pass to write to the screen + SobelShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + SobelShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/vignette.js b/src/post/vignette.js new file mode 100644 index 0000000..0afc929 --- /dev/null +++ b/src/post/vignette.js @@ -0,0 +1,56 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + offset: 0.5, + darkness: 0.5 +} + +var VignetteShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_offset: { + type: 'f', + value: options.offset + }, + u_darkness: { + type: 'f', + value: options.darkness + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/vignette-frag.glsl') +}); + +export default function Vignette(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + + // first render the scene normally and add that as the first pass + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + + // then take the rendered result and apply the VignetteShader + composer.addPass(VignetteShader); + + // set this to true on the shader for your last pass to write to the screen + VignetteShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'offset', 0, 1).onChange(function(val) { + VignetteShader.material.uniforms.u_offset.value = val; + }); + gui.add(options, 'darkness', 0, 1).onChange(function(val) { + VignetteShader.material.uniforms.u_darkness.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/shaders/index.js b/src/shaders/index.js index e5b85c1..a9a5a55 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,7 @@ // This file exports available shaders to the GUI. // follow this syntax to make your shaders available to the GUI -export {default as Lambert} from './lambert' \ No newline at end of file +export {default as Lambert} from './lambert' +export {default as Pointillism} from './point' +export {default as Iridescence} from './iridescence' +export {default as Toon} from './toon' \ No newline at end of file diff --git a/src/shaders/iridescence.js b/src/shaders/iridescence.js new file mode 100644 index 0000000..4f367d7 --- /dev/null +++ b/src/shaders/iridescence.js @@ -0,0 +1,75 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for iridescence shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true +} + +export default function(renderer, scene, camera) { + + const Shader = { + initGUI: function(gui) { + gui.addColor(options, 'lightColor').onChange(function(val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function(val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'ambient').onChange(function(val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_cameraPos: { + type: 'v3', + value: camera.position + } + }, + vertexShader: require('../glsl/iridescence-vert.glsl'), + fragmentShader: require('../glsl/iridescence-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file diff --git a/src/shaders/point.js b/src/shaders/point.js new file mode 100644 index 0000000..883905b --- /dev/null +++ b/src/shaders/point.js @@ -0,0 +1,85 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for pointillism shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true, + threshold: 0.5 +} + +export default function(renderer, scene, camera) { + + const Shader = { + initGUI: function(gui) { + gui.addColor(options, 'lightColor').onChange(function(val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function(val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function(val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function(val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function(val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + gui.add(options, 'threshold', 0, 1).onChange(function(val) { + Shader.material.uniforms.u_threshold.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_threshold: { + type: 'f', + value: options.threshold + } + }, + vertexShader: require('../glsl/point-vert.glsl'), + fragmentShader: require('../glsl/point-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file diff --git a/src/shaders/toon.js b/src/shaders/toon.js new file mode 100644 index 0000000..f1b2327 --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,89 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for toon shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true, + numShades: 125 +} + +export default function(renderer, scene, camera) { + + const Shader = { + initGUI: function(gui) { + gui.addColor(options, 'lightColor').onChange(function(val) { + Shader.material.uniforms.u_lightCol.value = new THREE.Color(val); + }); + gui.add(options, 'lightIntensity').onChange(function(val) { + Shader.material.uniforms.u_lightIntensity.value = val; + }); + gui.addColor(options, 'albedo').onChange(function(val) { + Shader.material.uniforms.u_albedo.value = new THREE.Color(val); + }); + gui.addColor(options, 'ambient').onChange(function(val) { + Shader.material.uniforms.u_ambient.value = new THREE.Color(val); + }); + gui.add(options, 'useTexture').onChange(function(val) { + Shader.material.uniforms.u_useTexture.value = val; + }); + gui.add(options, 'numShades', 2, 216).onChange(function(val) { + Shader.material.uniforms.u_numShades.value = val; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + u_useTexture: { + type: 'i', + value: options.useTexture + }, + u_albedo: { + type: 'v3', + value: new THREE.Color(options.albedo) + }, + u_ambient: { + type: 'v3', + value: new THREE.Color(options.ambient) + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_lightCol: { + type: 'v3', + value: new THREE.Color(options.lightColor) + }, + u_lightIntensity: { + type: 'f', + value: options.lightIntensity + }, + u_cameraPos: { + type: 'v3', + value: camera.position + }, + u_numShades: { + type: 'f', + value: options.numShades + } + }, + vertexShader: require('../glsl/toon-vert.glsl'), + fragmentShader: require('../glsl/toon-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file diff --git a/v1.png b/v1.png new file mode 100644 index 0000000..702ca76 Binary files /dev/null and b/v1.png differ diff --git a/v2.png b/v2.png new file mode 100644 index 0000000..252bc8c Binary files /dev/null and b/v2.png differ