diff --git a/README.md b/README.md index a2754de..1fa2098 100644 --- a/README.md +++ b/README.md @@ -1,124 +1,20 @@ # Project 5: Shaders -## Project Instructions +https://nnewberg.github.io/Project5-Shaders/ -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. +## Project Overview -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! +I have implemented a lit-sphere, pointilism and gaussian blur shader.
+I have also designed a 'Toon Hatch' shader, which was inspired by a shader created by 3 dreams of black: +https://www.chromeexperiments.com/experiment/hatching-glow-shader
-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. +## Pics -Examples: [https://cis700-procedural-graphics.github.io/Project5-Shaders/](https://cis700-procedural-graphics.github.io/Project5-Shaders/) +![img](https://github.com/nnewberg/Project5-Shaders/blob/master/screenshots/red.png?raw=true) -### 15 points each: Instagram-like filters +![img](https://github.com/nnewberg/Project5-Shaders/blob/master/screenshots/toonhatch.png?raw=true) -- Tone mapping: - - Linear (5 points) - - Reinhard (5 points) - - Filmic (5 points) -- Gaussian blur (no double counting with Bloom) -- Iridescence -- Pointilism -- Vignette -- Fish-eye bulge +![img](https://github.com/nnewberg/Project5-Shaders/blob/master/screenshots/blur.png?raw=true) -### 25 points each: -- Bloom -- Noise Warp -- Hatching -- Edge detection with Sobel filtering -- Lit Sphere ([paper](http://www.ppsloan.org/publications/LitSphere.pdf)) -- 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: (5 points total) - - Controlling Exposure - - Side by side comparison between linear, Reinhard, filmic, and Uncharted2 . - -### 37.5 points each: -- K-means color compression (unless you are extremely clever, the k-means clusterer has to be CPU side) -- Dithering - - -### 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 diff --git a/package.json b/package.json index a91b2a1..0f9800a 100644 --- a/package.json +++ b/package.json @@ -15,8 +15,8 @@ "three-effectcomposer": "0.0.1", "three-obj-loader": "^1.0.2", "three-orbit-controls": "^82.1.0", - "webpack": "^2.2.1", - "webpack-dev-server": "^2.3.0", + "webpack": "^1.13.1", + "webpack-dev-server": "^1.16.2", "webpack-glsl-loader": "^1.0.1" } } diff --git a/screenshots/blur.png b/screenshots/blur.png new file mode 100644 index 0000000..69d2fad Binary files /dev/null and b/screenshots/blur.png differ diff --git a/screenshots/chrome.png b/screenshots/chrome.png new file mode 100644 index 0000000..fd8a544 Binary files /dev/null and b/screenshots/chrome.png differ diff --git a/screenshots/red.png b/screenshots/red.png new file mode 100644 index 0000000..1a206eb Binary files /dev/null and b/screenshots/red.png differ diff --git a/screenshots/toonhatch.png b/screenshots/toonhatch.png new file mode 100644 index 0000000..957a185 Binary files /dev/null and b/screenshots/toonhatch.png differ diff --git a/src/assets/sphere-textures/bluegreen.jpg b/src/assets/sphere-textures/bluegreen.jpg new file mode 100644 index 0000000..4f2b643 Binary files /dev/null and b/src/assets/sphere-textures/bluegreen.jpg differ diff --git a/src/assets/sphere-textures/bronze.jpg b/src/assets/sphere-textures/bronze.jpg new file mode 100644 index 0000000..4af0390 Binary files /dev/null and b/src/assets/sphere-textures/bronze.jpg differ diff --git a/src/assets/sphere-textures/chrome.jpg b/src/assets/sphere-textures/chrome.jpg new file mode 100644 index 0000000..2e2cd68 Binary files /dev/null and b/src/assets/sphere-textures/chrome.jpg differ diff --git a/src/assets/sphere-textures/colorwheel.png b/src/assets/sphere-textures/colorwheel.png new file mode 100644 index 0000000..2d07967 Binary files /dev/null and b/src/assets/sphere-textures/colorwheel.png differ diff --git a/src/assets/sphere-textures/red.jpg b/src/assets/sphere-textures/red.jpg new file mode 100644 index 0000000..fd1499b Binary files /dev/null and b/src/assets/sphere-textures/red.jpg differ diff --git a/src/assets/sphere-textures/slime.jpg b/src/assets/sphere-textures/slime.jpg new file mode 100644 index 0000000..dc27ef4 Binary files /dev/null and b/src/assets/sphere-textures/slime.jpg differ diff --git a/src/glsl/colorfilter-frag.glsl b/src/glsl/colorfilter-frag.glsl new file mode 100644 index 0000000..6b1efc4 --- /dev/null +++ b/src/glsl/colorfilter-frag.glsl @@ -0,0 +1,15 @@ + +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 col = texture2D(tDiffuse, f_uv); + //float red = dot(col.rgb, vec3(0.500, 0.0, 0.0)); + + col.rgb = (col.rgb - vec3(1.0, 0.0, 0.0)) * (u_amount) + col.rgb * (1.0 - u_amount); + + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/dot-frag.glsl b/src/glsl/dot-frag.glsl new file mode 100644 index 0000000..029de61 --- /dev/null +++ b/src/glsl/dot-frag.glsl @@ -0,0 +1,152 @@ +uniform vec3 uLightDir; +varying vec3 vNormal; +varying vec3 vPos; +#define M_PI 3.1415926535897932384626433832795 +#define N_OCTAVES 5 + + +float noise(vec3 seed){ + return fract(sin(dot(seed ,vec3(12.9898,78.233, 157.179))) * 43758.5453); +} + +float TotalNoise(vec3 seed, float frequency, float amplitude){ //inside frequency outside amplit + float n1 = noise(seed * frequency) * amplitude; + return n1; +} + +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 * M_PI)) * 0.5; + return lerp(a, b, cos_t); +} + + +float trilinearInterpolation(vec3 pos, float frequency, float amplitude){ + + vec3 pd = pos * frequency; + + //8 adjacent vec3 positions on lattice + vec3 v000 = vec3(floor(pd.x),floor(pd.y),floor(pd.z)); + vec3 v100 = vec3(ceil(pd.x),floor(pd.y),floor(pd.z)); + vec3 v010 = vec3(floor(pd.x), ceil(pd.y), floor(pd.z)); + vec3 v001 = vec3(floor(pd.x), floor(pd.y), ceil(pd.z)); + vec3 v101 = vec3(ceil(pd.x), floor(pd.y), ceil(pd.z)); + vec3 v110 = vec3(ceil(pd.x), ceil(pd.y), floor(pd.z)); + vec3 v011 = vec3(floor(pd.x), ceil(pd.y), ceil(pd.z)); + vec3 v111 = vec3(ceil(pd.x), ceil(pd.y), ceil(pd.z)); + + //noise of cooresponding positions on lattice + float n000 = TotalNoise(v000, frequency, amplitude); + float n100 = TotalNoise(v100, frequency, amplitude); + float n010 = TotalNoise(v010, frequency, amplitude); + float n001 = TotalNoise(v001, frequency, amplitude); + float n101 = TotalNoise(v101, frequency, amplitude); + float n110 = TotalNoise(v110, frequency, amplitude); + float n011 = TotalNoise(v011, frequency, amplitude); + float n111 = TotalNoise(v111, frequency, amplitude); + + //time val for interpolation + float tX = pd.x - floor(pd.x); + float tY = pd.y - floor(pd.y); + float tZ = pd.z - floor(pd.z); + + float n00 = cosine_interpolate(n000, n100, tX); + float n10 = cosine_interpolate(n001, n101, tX); + float n11 = cosine_interpolate(n011, n111, tX); + float n01 = cosine_interpolate(n010, n110, tX); + float n0 = cosine_interpolate(n00, n10, tZ); + float n1 = cosine_interpolate(n01, n11, tZ); + float n = cosine_interpolate(n0, n1, tY); + + return n; +} + + +float PerlinNoise3D(vec3 pos, float freqControl){ + float total = 0.0; + float persistance = 1.0 / 2.0; + + for (int i = 0 ; i < N_OCTAVES; i++){ + + float frequency = pow(2.0, float(i)) * freqControl; + float amplitude = pow(persistance, float(i)); + total += trilinearInterpolation(pos, frequency, amplitude); + + } + + return total; + +} + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main() +{ + float intensity; + float r; //random number between 0,1; + float partitions = 3.0; + + vec4 white = vec4(1.0,1.0,1.0,1.0); + vec4 black = vec4(0.0,0.0,0.0,1.0); + vec4 color = white; + + + intensity = dot(uLightDir,vNormal); + r = noise(vPos); + + // intensity = intensity * partitions; + // intensity = floor(intensity)/partitions; + + // float frequency = ((intensity)); + + //if (intensity > 0.95) + // frequency = 1.0; + // else if (intensity > 0.5) + // frequency = 2.0; + // else if (intensity > 0.25) + // frequency = 3.0; + // else + // frequency = 4.0; + + // float amplitude = 1.0/frequency; + // float perlin = PerlinNoise3D(vPos, frequency); + // vec3 noise_col = vec3(perlin,perlin,perlin); + + // vec3 hsvColor = rgb2hsv(color.rgb); + // float h = hsvColor.r; + + // hsvColor = hsvColor * 5.0; + // hsvColor = floor(hsvColor)/5.0; + // hsvColor.r = h; + + // vec3 rgbColor = hsv2rgb(hsvColor); + // color = vec4(rgbColor.x,rgbColor.y,rgbColor.z, 1.0); + + if (r > intensity){ + color = black; + } + + //color = vec4(noise_col.rgb,1.0); + + gl_FragColor = color; + +} \ No newline at end of file diff --git a/src/glsl/dot-vert.glsl b/src/glsl/dot-vert.glsl new file mode 100644 index 0000000..e085aa7 --- /dev/null +++ b/src/glsl/dot-vert.glsl @@ -0,0 +1,16 @@ +varying vec3 vNormal; +varying vec3 vPos; + +void main(){ + + vec4 vertPos = vec4(position, 1.0); + + vec3 eye = normalize(vec3(modelViewMatrix * vertPos)); + vec3 n = normalize(normalMatrix * normal); + + vNormal = n; + vPos = position; + + gl_Position = projectionMatrix * modelViewMatrix * vertPos; + +} \ No newline at end of file diff --git a/src/glsl/gaussian-frag.glsl b/src/glsl/gaussian-frag.glsl new file mode 100644 index 0000000..5abc4f1 --- /dev/null +++ b/src/glsl/gaussian-frag.glsl @@ -0,0 +1,32 @@ + +uniform sampler2D tDiffuse; +varying vec2 f_uv; + +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to + +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + float uvIncr = 0.002; + + vec2 uv01 = f_uv + vec2(0.0,uvIncr); + vec2 uv0n1 = f_uv + vec2(0.0, -uvIncr); + + vec2 uv10 = f_uv + vec2(uvIncr, 0.0); + vec2 uvn10 = f_uv + vec2(-uvIncr, 0.0); + + vec4 col1 = texture2D(tDiffuse, uv01); + vec4 col2 = texture2D(tDiffuse, uv0n1); + vec4 col3 = texture2D(tDiffuse, uv10); + vec4 col4 = texture2D(tDiffuse, uvn10); + + col = (col1 + col2 + col3 + col4)/4.0; + col[3] = 1.0; + + // vec2 uv11 = f_uv + vec2(1.0, 0.0); + // vec2 uvn11 = f_uv + vec2(-1.0, 0.0); + // vec2 uv1n1 = f_uv + vec2(-1.0, 0.0); + + + + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/hatch-frag.glsl b/src/glsl/hatch-frag.glsl new file mode 100644 index 0000000..2588987 --- /dev/null +++ b/src/glsl/hatch-frag.glsl @@ -0,0 +1,50 @@ + +uniform sampler2D tDiffuse; +varying vec2 f_uv; + +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to + +float rand(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +bool nearlyEqual(vec3 a, vec3 b){ + return distance(a,b) < 0.01; +} + +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + vec3 background = vec3(153.0,153.0,153.0)/255.0; + vec3 white = vec3(1.0,1.0,1.0); + vec3 black = vec3(0.0,0.0,0.0); + float hatchVal = 1.0; + float lightness = length(col.rgb); + float jitter = rand(f_uv); + vec4 red = vec4(1.0,0.5,0.5,1.0); + + float hatchA = sin((f_uv.x + f_uv.y) * 800.0) ; + float hatchB = sin((f_uv.x - f_uv.y) * 800.0) ; + + if (col.rgb == background || col.rgb == white){ //don't change background or white colors + gl_FragColor = col; + return; + }else if (hatchA > 0.6){ //if it's not in the hatch, make it white + + hatchVal = lightness/1.5; + col = vec4(hatchVal,0.0,0.0,1.0); + gl_FragColor = col; + // return; + }else if(hatchB > 0.9){ + + hatchVal = lightness/1.0; + col = vec4(hatchVal,0.0,0.0,1.0); + gl_FragColor = col; + // return; + } + else{ //if it is in the hatch + gl_FragColor = vec4(white,1.0); + + } + + //gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/lit-sphere-frag.glsl b/src/glsl/lit-sphere-frag.glsl new file mode 100644 index 0000000..7e89078 --- /dev/null +++ b/src/glsl/lit-sphere-frag.glsl @@ -0,0 +1,10 @@ +uniform sampler2D uSphereTexture; + +varying vec2 vNormal; + +void main() { + + vec3 textureColor = texture2D( uSphereTexture, vNormal ).rgb; + gl_FragColor = vec4( textureColor, 1. ); + +} \ No newline at end of file diff --git a/src/glsl/lit-sphere-vert.glsl b/src/glsl/lit-sphere-vert.glsl new file mode 100644 index 0000000..d52558b --- /dev/null +++ b/src/glsl/lit-sphere-vert.glsl @@ -0,0 +1,20 @@ +varying vec2 vNormal; + +void main(){ + + vec4 vertPos = vec4(position, 1.0); + + vec3 eye = normalize(vec3(modelViewMatrix * vertPos)); + vec3 screenNormal = normalize(normalMatrix * normal); + + vec3 reflected= reflect(eye, screenNormal); + float m = 2.0 * sqrt( + pow( reflected.x, 2.0 ) + + pow( reflected.y, 2.0 ) + + pow( reflected.z + 1.0, 2.0 ) + ); + vNormal = reflected.xy/m + 0.50; + + gl_Position = projectionMatrix * modelViewMatrix * vertPos; + +} \ 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..8a66350 --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,56 @@ + +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; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +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); + d = d * 5.0; + d = floor(d)/5.0; + + vec3 hsvColor = rgb2hsv(color.rgb); + float h = hsvColor.r; + + hsvColor = hsvColor * 5.0; + hsvColor = floor(hsvColor)/5.0; + hsvColor.r = h; + + + vec3 rgbColor = hsv2rgb(hsvColor); + color = vec4(rgbColor.x,rgbColor.y,rgbColor.z, 1.0); + + gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} \ No newline at end of file diff --git a/src/glsl/toon-hatch-frag.glsl b/src/glsl/toon-hatch-frag.glsl new file mode 100644 index 0000000..2ab0811 --- /dev/null +++ b/src/glsl/toon-hatch-frag.glsl @@ -0,0 +1,182 @@ +uniform vec3 uLightPos; +varying vec3 vNormal; +varying vec3 vPos; +#define M_PI 3.1415926535897932384626433832795 +#define N_OCTAVES 5 + + +float noise(vec3 seed){ + return fract(sin(dot(seed ,vec3(12.9898,78.233, 157.179))) * 43758.5453); +} + +float TotalNoise(vec3 seed, float frequency, float amplitude){ //inside frequency outside amplit + float n1 = noise(seed * frequency) * amplitude; + return n1; +} + +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 * M_PI)) * 0.5; + return lerp(a, b, cos_t); +} + + +float trilinearInterpolation(vec3 pos, float frequency, float amplitude){ + + vec3 pd = pos * frequency; + + //8 adjacent vec3 positions on lattice + vec3 v000 = vec3(floor(pd.x),floor(pd.y),floor(pd.z)); + vec3 v100 = vec3(ceil(pd.x),floor(pd.y),floor(pd.z)); + vec3 v010 = vec3(floor(pd.x), ceil(pd.y), floor(pd.z)); + vec3 v001 = vec3(floor(pd.x), floor(pd.y), ceil(pd.z)); + vec3 v101 = vec3(ceil(pd.x), floor(pd.y), ceil(pd.z)); + vec3 v110 = vec3(ceil(pd.x), ceil(pd.y), floor(pd.z)); + vec3 v011 = vec3(floor(pd.x), ceil(pd.y), ceil(pd.z)); + vec3 v111 = vec3(ceil(pd.x), ceil(pd.y), ceil(pd.z)); + + //noise of cooresponding positions on lattice + float n000 = TotalNoise(v000, frequency, amplitude); + float n100 = TotalNoise(v100, frequency, amplitude); + float n010 = TotalNoise(v010, frequency, amplitude); + float n001 = TotalNoise(v001, frequency, amplitude); + float n101 = TotalNoise(v101, frequency, amplitude); + float n110 = TotalNoise(v110, frequency, amplitude); + float n011 = TotalNoise(v011, frequency, amplitude); + float n111 = TotalNoise(v111, frequency, amplitude); + + //time val for interpolation + float tX = pd.x - floor(pd.x); + float tY = pd.y - floor(pd.y); + float tZ = pd.z - floor(pd.z); + + float n00 = cosine_interpolate(n000, n100, tX); + float n10 = cosine_interpolate(n001, n101, tX); + float n11 = cosine_interpolate(n011, n111, tX); + float n01 = cosine_interpolate(n010, n110, tX); + float n0 = cosine_interpolate(n00, n10, tZ); + float n1 = cosine_interpolate(n01, n11, tZ); + float n = cosine_interpolate(n0, n1, tY); + + return n; +} + + +float PerlinNoise3D(vec3 pos, float freqControl){ + float total = 0.0; + float persistance = 1.0 / 2.0; + + for (int i = 0 ; i < N_OCTAVES; i++){ + + float frequency = pow(2.0, float(i)) * freqControl; + float amplitude = pow(persistance, float(i)); + total += trilinearInterpolation(pos, frequency, amplitude); + + } + + return total; + +} + +vec3 rgb2hsv(vec3 c) +{ + vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); + vec4 p = mix(vec4(c.bg, K.wz), vec4(c.gb, K.xy), step(c.b, c.g)); + vec4 q = mix(vec4(p.xyw, c.r), vec4(c.r, p.yzx), step(p.x, c.r)); + + float d = q.x - min(q.w, q.y); + float e = 1.0e-10; + return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + e)), d / (q.x + e), q.x); +} + +vec3 hsv2rgb(vec3 c) +{ + vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); + vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www); + return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y); +} + +void main() +{ + float intensity; + + vec4 white = vec4(1.0,1.0,1.0,1.0); + vec4 black = vec4(0.0,0.0,0.0,1.0); + vec4 color = black; + + // float perlinFreq = 2.0; + // float perlinAmp = 1.0; + // float perlin = clamp(PerlinNoise3D(vPos, perlinFreq) * perlinAmp, 0.80, 1.0); + float perlin = 1.0; + + vec4 highColor = vec4(1.0,215.0/255.0,0.0,1.0) * perlin; + vec4 medColor = vec4(1.0,0.0,0.0,1.0) * perlin; + vec4 lowColor = vec4(127.0/255.0,0.0,0.0,1.0) * perlin; + // vec3 noise_col = vec3(perlin,perlin,perlin); + + float hiFreqHatchA = sin(((vPos.x + vPos.y) + 10.0) * 50.0); + bool hiFreqHatchAon = hiFreqHatchA > 0.99; + + float hatchA = sin((vPos.x + vPos.y) * 50.0); + bool hatchAon = hatchA > 0.99; + + float hatchB = sin((vPos.x - vPos.y) * 50.0); + bool hatchBon = hatchB > 0.99; + + + //float hatchB = sin((f_uv.x - f_uv.y) * 800.0) ; + + intensity = clamp(dot(vNormal, normalize(uLightPos - vPos)), 0.0, 1.0); + + + if (intensity > 0.65){ //high intensity + + color = black; + + // if (hiFreqHatchAon){ + // color = highColor; + // }else if (hatchAon || hatchBon){ + // color = medColor; + // } + + + }else if (intensity > 0.55){ //medium intensity + + if(hatchAon) + color = medColor; + + // if (hatchAon || hatchBon){ + // color = medColor; + // } + + }else if (intensity > 0.15){ //low intensity + + if (hatchAon || hatchBon){ + color = medColor; + } + // color = medColor; + }else { + + if (hiFreqHatchAon){ + color = highColor; + }else if (hatchAon || hatchBon){ + color = medColor; + } + + // }else if (hatchAon || hatchBon){ + // color = medColor; + // } + //color = black; + + } + + //color = vec4(hatchA, hatchA,hatchA, 1.0); + + + + gl_FragColor = color; + +} \ No newline at end of file diff --git a/src/glsl/toon-hatch-vert.glsl b/src/glsl/toon-hatch-vert.glsl new file mode 100644 index 0000000..7a968fd --- /dev/null +++ b/src/glsl/toon-hatch-vert.glsl @@ -0,0 +1,17 @@ +varying vec3 vNormal; +varying vec3 vPos; + +void main(){ + + vec4 vertPos = vec4(position, 1.0); + + vec3 eye = normalize(vec3(modelViewMatrix * vertPos)); + vec3 n = normalize(normalMatrix * normal); + + vNormal = n; + vPos = position; + + + gl_Position = projectionMatrix * modelViewMatrix * vertPos; + +} \ 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/main.js b/src/main.js index d7c08ae..31a7a17 100644 --- a/src/main.js +++ b/src/main.js @@ -20,7 +20,7 @@ window.addEventListener('load', function() { var renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); - renderer.setClearColor(0x999999, 1.0); + renderer.setClearColor(0x000000, 1.0); var controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; @@ -37,7 +37,7 @@ window.addEventListener('load', function() { renderer.setSize(window.innerWidth, window.innerHeight); }); - var mesh, shader, post; + var mesh, shader, post, elapsedFrames; // this gets called when we set the shader function shaderSet(Shader, gui) { // create the shader and initialize its gui @@ -67,6 +67,9 @@ window.addEventListener('load', function() { const center = geo.boundingSphere.center; camera.lookAt(center); controls.target.set(center.x, center.y, center.z); + + //start the clock + elapsedFrames = 0.0; }); (function tick() { @@ -76,6 +79,12 @@ window.addEventListener('load', function() { if (post && post.update) post.update(); // perform any necessary updates if (post) post.render(); // render the scene stats.end(); + + //rotate mesh + elapsedFrames ++; + if(mesh) + mesh.rotation.y = elapsedFrames/5.0 * Math.PI/180.0; + requestAnimationFrame(tick); })(); }); \ No newline at end of file diff --git a/src/post/colorfilter.js b/src/post/colorfilter.js new file mode 100644 index 0000000..8dd6b9e --- /dev/null +++ b/src/post/colorfilter.js @@ -0,0 +1,48 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +var ColorfilterShader = 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/colorfilter-frag.glsl') +}); + +export default function Colorfilter(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(ColorfilterShader); + + // set this to true on the shader for your last pass to write to the screen + ColorfilterShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + ColorfilterShader.material.uniforms.u_amount.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/gaussian.js b/src/post/gaussian.js new file mode 100644 index 0000000..ea7dd43 --- /dev/null +++ b/src/post/gaussian.js @@ -0,0 +1,45 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +var GaussianShader = 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/gaussian-frag.glsl') +}); + +export default function Gaussian(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(GaussianShader); + + // set this to true on the shader for your last pass to write to the screen + GaussianShader.renderToScreen = true; + + return { + initGUI: function(gui) { + }, + + render: function() {; + composer.render(); + } + } +} \ No newline at end of file diff --git a/src/post/hatch.js b/src/post/hatch.js new file mode 100644 index 0000000..796c92c --- /dev/null +++ b/src/post/hatch.js @@ -0,0 +1,46 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) +var cameraPos; + +var options = { + amount: 1 +} + +var ColorfilterShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + uCameraPos: {value: cameraPos} + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/hatch-frag.glsl') +}); + +export default function Hatch(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(ColorfilterShader); + + // set this to true on the shader for your last pass to write to the screen + ColorfilterShader.renderToScreen = true; + + return { + initGUI: function(gui) { + // gui.add(options, 'amount', 0, 1).onChange(function(val) { + // ColorfilterShader.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..fe68cb9 100644 --- a/src/post/index.js +++ b/src/post/index.js @@ -15,4 +15,8 @@ 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 Colorfilter} from './colorfilter' +export {default as Gaussian} from './gaussian' + +// export {default as Hatch} from './hatch' \ No newline at end of file diff --git a/src/shaders/dot.js b/src/shaders/dot.js new file mode 100644 index 0000000..eb860fe --- /dev/null +++ b/src/shaders/dot.js @@ -0,0 +1,33 @@ + +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) { + + var lightDir = new THREE.Vector3(1.0,1.0,1.0); + + const Shader = { + initGUI: function(gui) { + + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + uLightDir: {value: lightDir} + }, + vertexShader: require('../glsl/dot-vert.glsl'), + fragmentShader: require('../glsl/dot-frag.glsl') + }) + } + + return Shader; +} \ No newline at end of file diff --git a/src/shaders/index.js b/src/shaders/index.js index e5b85c1..a8cea2b 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,10 @@ // 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 LitSphere} from './lit-sphere' +export {default as Dot} from './dot' +export {default as ToonHatch} from './toon-hatch' + + diff --git a/src/shaders/lit-sphere.js b/src/shaders/lit-sphere.js new file mode 100644 index 0000000..7bc7666 --- /dev/null +++ b/src/shaders/lit-sphere.js @@ -0,0 +1,61 @@ + +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) { + + + var bluegreen = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/bluegreen.jpg'); + var colorwheel = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/colorwheel.png'); + var bronze = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/bronze.jpg'); + var chrome = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/chrome.jpg'); + var red = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/red.jpg'); + var slime = THREE.ImageUtils.loadTexture('src/assets/sphere-textures/slime.jpg'); + + + + var selectedTexture = { + texture: 'bluegreen' + }; + + var textureMap = { + 'bluegreen' : bluegreen, + 'colorwheel' : colorwheel, + 'bronze': bronze, + 'chrome': chrome, + 'red': red, + 'slime': slime + }; + + var sphereTexture = bluegreen; + + + const Shader = { + initGUI: function(gui) { + gui.add(selectedTexture, 'texture', ['bluegreen','slime', 'bronze', 'colorwheel', 'chrome', 'red'] ).onChange(function(val){ + Shader.material.uniforms.uSphereTexture.value = textureMap[val]; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + uSphereTexture: { + type: "t", + value: sphereTexture }, + }, + vertexShader: require('../glsl/lit-sphere-vert.glsl'), + fragmentShader: require('../glsl/lit-sphere-frag.glsl') + }) + } + + return Shader; +} \ No newline at end of file diff --git a/src/shaders/toon-hatch.js b/src/shaders/toon-hatch.js new file mode 100644 index 0000000..d2f9064 --- /dev/null +++ b/src/shaders/toon-hatch.js @@ -0,0 +1,28 @@ + +const THREE = require('three'); +import {textureLoaded} from '../mario' + +// options for lambert shader +var options = { + rotation: 0.0 +}; + +export default function(renderer, scene, camera) { + + var lightPos = new THREE.Vector3(30, 50, 40); + + const Shader = { + initGUI: function(gui) { + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + uLightPos: {value: lightPos} + }, + vertexShader: require('../glsl/toon-hatch-vert.glsl'), + fragmentShader: require('../glsl/toon-hatch-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..36032fa --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,77 @@ + +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 + } + }, + 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