diff --git a/README.md b/README.md index 08c69b7..344f3f1 100644 --- a/README.md +++ b/README.md @@ -1,123 +1,7 @@ - -# 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 +Implemented: +- Iridescence shader using IQ's color palette and formula from slides (15) +- Pointilism filter using old noise functions from Project 1 and slides(15) +- Vignette filter (15) +- Fish-eye filter (15) +- Pixellate filter (proposing 15??) +- attempted hatching filter (???) \ No newline at end of file diff --git a/src/glsl/fisheye-frag.glsl b/src/glsl/fisheye-frag.glsl new file mode 100644 index 0000000..92b29e5 --- /dev/null +++ b/src/glsl/fisheye-frag.glsl @@ -0,0 +1,29 @@ +uniform sampler2D tDiffuse; +uniform float aperture; +varying vec2 f_uv; +const float PI = 3.1415926535; + +// uses the polar method from http://paulbourke.net/dome/fisheye/ +void main() { + float apertureHalf = 0.5 * aperture * (PI / 180.0); + float maxFactor = sin(apertureHalf); + + vec2 uv; + vec2 xy = 2.0 * f_uv.xy - 1.0; + float d = length(xy); + + if (d < (2.0 - maxFactor)) { + d = length(xy * maxFactor); + float z = sqrt(1.0 - d * d); + float r = atan(d, z) / PI; + float phi = atan(xy.y, xy.x); + + uv.x = r * cos(phi) + 0.5; + uv.y = r * sin(phi) + 0.5; + } else { + uv = f_uv.xy; + } + + vec4 c = texture2D(tDiffuse, uv); + gl_FragColor = c; +} \ No newline at end of file diff --git a/src/glsl/hatching-frag.glsl b/src/glsl/hatching-frag.glsl new file mode 100644 index 0000000..16a6415 --- /dev/null +++ b/src/glsl/hatching-frag.glsl @@ -0,0 +1,15 @@ +varying vec2 f_uv; +uniform sampler2D tDiffuse; + +void main() { + vec4 texel = texture2D(tDiffuse, f_uv); + vec3 col = texel.rgb; + + float darkness = (0.2126*col.r + 0.7152*col.g + 0.0722*col.b); + float sinValX = sin(f_uv.x * 1000.0); + float sinValY = sin(f_uv.y * 1000.0); + + float hatching = darkness * sinValX * sinValY; + + gl_FragColor = vec4(hatching); +} \ No newline at end of file diff --git a/src/glsl/iridescent-frag.glsl b/src/glsl/iridescent-frag.glsl new file mode 100644 index 0000000..94c2761 --- /dev/null +++ b/src/glsl/iridescent-frag.glsl @@ -0,0 +1,29 @@ + +uniform sampler2D texture; +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; + +// cosine based palette, 4 vec3 params from http://www.iquilezles.org/www/articles/palettes/palettes.htm +vec3 palette( in float t, in vec3 a, in vec3 b, in vec3 c, in vec3 d ) +{ + return a + b*cos( 6.28318*(c*t+d) ); +} + +void main() { + vec4 color = vec4(u_albedo, 1.0); + + vec3 look = normalize(u_cameraPos-f_position); + float d = dot(look, f_normal); + + vec3 paletteColor = palette(d, vec3(0.5, 0.5, 0.5), vec3(0.5, 0.5, 0.5), vec3(1.0, 1.0, 1.0), vec3(0.00, 0.33, 0.67)); + + gl_FragColor = vec4(paletteColor * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/pixellate-frag.glsl b/src/glsl/pixellate-frag.glsl new file mode 100644 index 0000000..2db2ea5 --- /dev/null +++ b/src/glsl/pixellate-frag.glsl @@ -0,0 +1,14 @@ +varying vec2 f_uv; +uniform sampler2D tDiffuse; +uniform float pixellateFactor; + +// https://www.airtightinteractive.com/2013/02/intro-to-pixel-shaders-in-three-js/ +void main() { + vec2 p = f_uv.xy; + + p.x -= mod(p.x, 1.0 / pixellateFactor); + p.y -= mod(p.y, 1.0 / pixellateFactor); + + vec3 col = texture2D(tDiffuse, p).rgb; + gl_FragColor = vec4(col, 1.0); +} \ No newline at end of file diff --git a/src/glsl/pointilism-frag.glsl b/src/glsl/pointilism-frag.glsl new file mode 100644 index 0000000..a323a18 --- /dev/null +++ b/src/glsl/pointilism-frag.glsl @@ -0,0 +1,20 @@ +varying vec2 f_uv; +uniform sampler2D tDiffuse; + +float generateNoise(float x, float y) { + return fract(sin(dot(vec2(x,y), vec2(12.9898, 78.23))) * 43758.5453); +} + +void main() { + vec4 texel = texture2D(tDiffuse, f_uv); + vec3 col = texel.rgb; + + float darkness = (0.2126*col.r + 0.7152*col.g + 0.0722*col.b); + float noiseValue = generateNoise(texel.x, texel.y); + + if (noiseValue > darkness) { + gl_FragColor = vec4(darkness); + } else { + gl_FragColor = vec4(1.0); + } +} \ No newline at end of file diff --git a/src/glsl/random-frag.glsl b/src/glsl/random-frag.glsl new file mode 100644 index 0000000..57ff1ef --- /dev/null +++ b/src/glsl/random-frag.glsl @@ -0,0 +1,20 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; + +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to + +void main() { + vec4 color = texture2D(tDiffuse, f_uv); + + color.x = 0.393 * (color.x * 255.0) + 0.769*(color.y*255.0) + 0.189*(color.z*255.0); + color.y = 0.349 * (color.x*255.0) + 0.686*(color.y*255.0) + 0.168*(color.z*255.0); + color.z = 0.272 * (color.x*255.0) + 0.534*(color.y*255.0) + 0.131*(color.z*255.0); + + color.x /= 255.0; + color.y /= 255.0; + color.z /= 255.0; + + gl_FragColor = color; +} \ 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..c5127fe --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,53 @@ + +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; + +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); + + vec3 look = normalize(f_position - u_cameraPos); + if (dot(f_normal, look) > -0.2 && dot(f_normal, look) < 0.2) { + gl_FragColor == vec4(0.0,0.0,0.0,1.0); + } else { + if (mod(color.x, 0.3) != 0.0) { + if (mod(color.x, 0.3) >= 0.05) { + color.x = color.x + (0.3 - mod(color.x, 0.3)); + } else if (mod(color.x, 0.3) < 0.05) { + color.x = color.x - (mod(color.x, 0.3)); + } + } + + if (mod(color.y, 0.3) != 0.0) { + if (mod(color.y, 0.3) >= 0.05) { + color.y = color.y + (0.3 - mod(color.y, 0.3)); + } else if (mod(color.y, 0.3) < 0.05) { + color.y = color.y - (mod(color.y, 0.3)); + } + } + + if (mod(color.z, 0.3) != 0.0) { + if (mod(color.z, 0.3) >= 0.05) { + color.z = color.z + (0.3 - mod(color.z, 0.3)); + } else if (mod(color.z, 0.3) < 0.05) { + color.z = color.z - (mod(color.z, 0.3)); + } + } + gl_FragColor = vec4(color.rgb * u_lightCol * u_lightIntensity + u_ambient, 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..1e45c6e --- /dev/null +++ b/src/glsl/vignette-frag.glsl @@ -0,0 +1,12 @@ + +uniform sampler2D tDiffuse; +uniform float u_offset; +uniform float u_darkness; +varying vec2 f_uv; + +// https://www.airtightinteractive.com/2013/02/intro-to-pixel-shaders-in-three-js/ +void main() { + vec4 texel = texture2D(tDiffuse, f_uv); + vec2 uv = (f_uv - vec2(0.5)) * vec2(u_offset); + gl_FragColor = vec4(mix(texel.rgb, vec3(1.0 - u_darkness), dot(uv, uv)), texel.a); +} \ No newline at end of file diff --git a/src/post/fisheye.js b/src/post/fisheye.js new file mode 100644 index 0000000..7afbd3f --- /dev/null +++ b/src/post/fisheye.js @@ -0,0 +1,45 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + aperture: 200.0 +} + +var FisheyeShader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + tDiffuse: { + type: 't', + value: null + }, + aperture: { + type: 'f', + value: options.aperture + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/fisheye-frag.glsl') +}); + +export default function Fisheye(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + composer.addPass(FisheyeShader); + + // set this to true on the shader for your last pass to write to the screen + FisheyeShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'aperture').onChange(function(val) { + FisheyeShader.material.uniforms.aperture.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/grayscale.js b/src/post/grayscale.js index 728df40..9344ee1 100644 --- a/src/post/grayscale.js +++ b/src/post/grayscale.js @@ -7,6 +7,7 @@ var options = { var GrayscaleShader = new EffectComposer.ShaderPass({ uniforms: { + // the texture the frame is rendered to before passing to the post processing shader tDiffuse: { type: 't', value: null diff --git a/src/post/hatching.js b/src/post/hatching.js new file mode 100644 index 0000000..929f036 --- /dev/null +++ b/src/post/hatching.js @@ -0,0 +1,34 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var Shader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + tDiffuse: { + type: 't', + value: null + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/hatching-frag.glsl') +}); + +export default function Fisheye(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + composer.addPass(Shader); + + // set this to true on the shader for your last pass to write to the screen + Shader.renderToScreen = true; + + return { + initGUI: function(gui) { + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/index.js b/src/post/index.js index 9c0d763..8f388b7 100644 --- a/src/post/index.js +++ b/src/post/index.js @@ -15,4 +15,10 @@ 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 Grayscale} from './grayscale' +export {default as Random} from './random' +export {default as Vignette} from './vignette' +export {default as Fisheye} from './fisheye' +export {default as Pixellate} from './pixellate' +export {default as Pointilism} from './pointilism' +export {default as Hatching} from './hatching' \ No newline at end of file diff --git a/src/post/pixellate.js b/src/post/pixellate.js new file mode 100644 index 0000000..106d312 --- /dev/null +++ b/src/post/pixellate.js @@ -0,0 +1,45 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + pixellateFactor: 100.0 +} + +var Shader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + tDiffuse: { + type: 't', + value: null + }, + pixellateFactor: { + type: 'f', + value: options.pixellateFactor + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/pixellate-frag.glsl') +}); + +export default function Fisheye(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + composer.addPass(Shader); + + // set this to true on the shader for your last pass to write to the screen + Shader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'pixellateFactor').onChange(function(val) { + Shader.material.uniforms.pixellateFactor.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/pointilism.js b/src/post/pointilism.js new file mode 100644 index 0000000..023b83c --- /dev/null +++ b/src/post/pointilism.js @@ -0,0 +1,34 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var Shader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + tDiffuse: { + type: 't', + value: null + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/pointilism-frag.glsl') +}); + +export default function Fisheye(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + var composer = new EffectComposer(renderer); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + composer.addPass(Shader); + + // set this to true on the shader for your last pass to write to the screen + Shader.renderToScreen = true; + + return { + initGUI: function(gui) { + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/random.js b/src/post/random.js new file mode 100644 index 0000000..d0f433e --- /dev/null +++ b/src/post/random.js @@ -0,0 +1,49 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +var GrayscaleShader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/random-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, 1).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/vignette.js b/src/post/vignette.js new file mode 100644 index 0000000..ed75faf --- /dev/null +++ b/src/post/vignette.js @@ -0,0 +1,53 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + offset: 1.0, + darkness: 1.0 +} + +var VignetteShader = new EffectComposer.ShaderPass({ + uniforms: { + // the texture the frame is rendered to before passing to the post processing shader + 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); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + 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..0987a37 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,6 @@ // 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 Toon} from './toon' +export {default as Iridescent} from './iridescent' \ No newline at end of file diff --git a/src/shaders/iridescent.js b/src/shaders/iridescent.js new file mode 100644 index 0000000..2f325c4 --- /dev/null +++ b/src/shaders/iridescent.js @@ -0,0 +1,67 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for lambert shader +var options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111' +} + +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); + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + texture: { + type: "t", + value: null + }, + 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/lambert-vert.glsl'), + fragmentShader: require('../glsl/iridescent-frag.glsl') + }) + } + 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..13777c6 --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,81 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for lambert 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, '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; + }); + }, + + 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/lambert-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