diff --git a/README.md b/README.md index 08c69b7..fc6a617 100644 --- a/README.md +++ b/README.md @@ -1,123 +1,18 @@ # Project 5: Shaders -## Project Instructions +Shaders Implemented: -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 +- Pointillism + - Computed a noise value based on position and drew a black pixel if the noise was above a certain threshold. - 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 + - Used a sine function to create a hatching texture. Used a noise function to add in some speckles as well. +- Monochromatic Shading + - I shaded the geometry similarly to the toon shader, but I mapped values to a monochromatic pallate. +- Geometric Shading + - I used multioctave noise to offset the UV coordinates in an interesting way. The result was not what I expected, but it looks pretty cool. +- Screen Print Shader + - Used a noise function that has a lot of repeated patterns to create a texture that looks like a screen print. + +![Alt text](references/monochrome.png?raw=true) +*Mario obj with monochromatic toon shader and hatching effect* diff --git a/references/flat.png b/references/flat.png new file mode 100644 index 0000000..6824f63 Binary files /dev/null and b/references/flat.png differ diff --git a/references/geometric.png b/references/geometric.png new file mode 100644 index 0000000..f165aca Binary files /dev/null and b/references/geometric.png differ diff --git a/references/hatching.png b/references/hatching.png new file mode 100644 index 0000000..6458ac5 Binary files /dev/null and b/references/hatching.png differ diff --git a/references/monochrome.png b/references/monochrome.png new file mode 100644 index 0000000..e3233f0 Binary files /dev/null and b/references/monochrome.png differ diff --git a/references/pointillism.png b/references/pointillism.png new file mode 100644 index 0000000..ffb481d Binary files /dev/null and b/references/pointillism.png differ diff --git a/references/screen.png b/references/screen.png new file mode 100644 index 0000000..0381f23 Binary files /dev/null and b/references/screen.png differ diff --git a/src/glsl/hatch-frag.glsl b/src/glsl/hatch-frag.glsl new file mode 100644 index 0000000..5768e00 --- /dev/null +++ b/src/glsl/hatch-frag.glsl @@ -0,0 +1,36 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; +varying vec3 fPos; + +float noise(float x, float y){ + float value1 = fract(sin(dot(vec2(x, y) ,vec2(1027.9898, 29381.233))) * 333019.5453); + + return dot(value1, 14958832.22); +} + +float hatch(float x, float y) { + return sin(300.0 * (x+y) ); +} + +void main() { + float noiseValue = noise(fPos.x , fPos.y); + float hatching = hatch(fPos.x, fPos.y); + + if (noiseValue < 0.5) { + gl_FragColor = vec4(0.0,0.0,0.0,1.0); + } else if (hatching > 0.7) { + gl_FragColor = vec4(0.294, 0.290, 0.282,1.0); + } else { + vec4 col = texture2D(tDiffuse, f_uv); + col.rgb = vec3(0.811, 0.666, 0.466) * (0.2) + col.rgb * (1.0 - 0.2); + gl_FragColor = col; + } + // vec4 col = texture2D(tDiffuse, f_uv); + // float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + + // col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + // gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/inclass-frag.glsl b/src/glsl/inclass-frag.glsl new file mode 100644 index 0000000..5ab6949 --- /dev/null +++ b/src/glsl/inclass-frag.glsl @@ -0,0 +1,18 @@ + +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 gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + + col.rgb = vec3(gray ,0.5,0.5) * u_amount + col.rgb * (1.0 - u_amount); + + // col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + gl_FragColor = col; +} \ No newline at end of file diff --git a/src/glsl/noise-frag.glsl b/src/glsl/noise-frag.glsl new file mode 100644 index 0000000..1d3ff97 --- /dev/null +++ b/src/glsl/noise-frag.glsl @@ -0,0 +1,25 @@ + +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; + +void main() { + vec4 color = vec4(u_albedo, 1.0); + + if (u_useTexture == 1) { + color = texture2D(texture, f_uv); + } + + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0); + + gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); + // gl_FragColor = vec4(0.5, 0.5, 0.0, 1.0); +} \ No newline at end of file diff --git a/src/glsl/noise-vert.glsl b/src/glsl/noise-vert.glsl new file mode 100644 index 0000000..9b5d015 --- /dev/null +++ b/src/glsl/noise-vert.glsl @@ -0,0 +1,191 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; +varying float vNoiseValue; + +uniform float u_time; + + +// Noise functions: +//------------------------------ +float noise_1(float x, float y, float z){ + float value1 = fract(sin(dot(vec2(z, y) ,vec2(81920.03934, 141414.233))) * 1992847.5453); + float value2 = fract(sin(x) * 102945.5453); + + return dot(value1, value2); +} + +float noise_2(float x, float y, float z) { + float value1 = fract(sin(dot(vec2(x, y) ,vec2(15.39481, 2394.233))) * 43758.141); + float value2 = fract(sin(z) * 1039555.54227873); + + return dot(value1, value2); +} + +float noise_3(float x, float y, float z) { + float n = x * 10100.101 ; + float m = y * 10000101101.0001; + n = fract(cos(dot(vec2(n,z), vec2(29984.294485, 40201845.9383))) * 3033077.117); + n = fract(tan(dot(n, m))); + return n; +} + +float noise_4(float x, float y, float z){ + float value1 = fract(sin(dot(vec2(x, y) ,vec2(3427.926341, 9847.91982))) * 18473.5453); + float value2 = fract(cos(z) * 39857201.5453); + + return fract(dot(value1, value2)); +} + +// Linear Interpolation +float lerp(float a, float b, float t) { + return a * (1.0 - t) + b * t; +} + +// Cosine Interpolation +float cos_interp(float a, float b, float t) { + float cos_t = (1.0 - cos(t * 3.14159265358979)) * 0.5; + return lerp(a , b , cos_t); +} + +//---------------------------- +// Interpolate Noise function +// Given a position, use surrounding lattice points to interpolate and find influence +// takes in (x,y,z) position, and the current octave level +float interpolateNoise(float x, float y, float z, int i) { + // define the lattice points surrounding the input position + float x0 = floor(x); + float x1 = x0 + 1.0; + float y0 = floor(y); + float y1 = y0 + 1.0; + float z0 = floor(z); + float z1 = z0 + 1.0; + + // VALUE BASED NOISE + vec3 p0 = vec3(x0, y0, z0); vec3 p1 = vec3(x0, y0, z1); + vec3 p2 = vec3(x0, y1, z0); vec3 p3 = vec3(x0, y1, z1); + vec3 p4 = vec3(x1, y0, z0); vec3 p5 = vec3(x1, y0, z1); + vec3 p6 = vec3(x1, y1, z0); vec3 p7 = vec3(x1, y1, z1); + + // use noise function to generate random value + // depending on the current octave, sample noise using a different function + float v0, v1, v2, v3, v4, v5, v6, v7; + if (i == 0) { + v0 = noise_2(p0.x, p0.y, p0.z); v1 = noise_2(p1.x, p1.y, p1.z); + v2 = noise_2(p2.x, p2.y, p2.z); v3 = noise_2(p3.x, p3.y, p3.z); + v4 = noise_2(p4.x, p4.y, p4.z); v5 = noise_2(p5.x, p5.y, p5.z); + v6 = noise_2(p6.x, p6.y, p6.z); v7 = noise_2(p7.x, p7.y, p7.z); + } else if (i == 1) { + v0 = noise_3(p0.x, p0.y, p0.z); v1 = noise_3(p1.x, p1.y, p1.z); + v2 = noise_3(p2.x, p2.y, p2.z); v3 = noise_3(p3.x, p3.y, p3.z); + v4 = noise_3(p4.x, p4.y, p4.z); v5 = noise_3(p5.x, p5.y, p5.z); + v6 = noise_3(p6.x, p6.y, p6.z); v7 = noise_3(p7.x, p7.y, p7.z); + } else if (i == 2) { + v0 = noise_1(p0.x, p0.y, p0.z); v1 = noise_1(p1.x, p1.y, p1.z); + v2 = noise_1(p2.x, p2.y, p2.z); v3 = noise_1(p3.x, p3.y, p3.z); + v4 = noise_1(p4.x, p4.y, p4.z); v5 = noise_1(p5.x, p5.y, p5.z); + v6 = noise_1(p6.x, p6.y, p6.z); v7 = noise_1(p7.x, p7.y, p7.z); + } else { + v0 = noise_4(p0.x, p0.y, p0.z); v1 = noise_4(p1.x, p1.y, p1.z); + v2 = noise_4(p2.x, p2.y, p2.z); v3 = noise_4(p3.x, p3.y, p3.z); + v4 = noise_4(p4.x, p4.y, p4.z); v5 = noise_4(p5.x, p5.y, p5.z); + v6 = noise_4(p6.x, p6.y, p6.z); v7 = noise_4(p7.x, p7.y, p7.z); + } + + // trilinear interpolation of all 8 values + // coordinates in the unit cube: + float unitX = x - x0; + float unitY = y - y0; + float unitZ = z - z0; + + float xCos1 = cos_interp(v0, v4, unitX); + float xCos2 = cos_interp(v1, v5, unitX); + float xCos3 = cos_interp(v2, v6, unitX); + float xCos4 = cos_interp(v3, v7, unitX); + + float yCos1 = cos_interp(xCos1, xCos3, unitY); + float yCos2 = cos_interp(xCos2, xCos4, unitY); + + float average = cos_interp(yCos1, yCos2, unitZ); + + return average; +} + +// multioctave noise generation +float fbm(float x, float y, float z) { + float total = 0.0; + const int OCTAVES = 4; + // float u_persistance = 4.0; + + // loop for some number of octaves + for(int i = 0; i < OCTAVES; i++) { + float i_float = float(i); + float frequency = pow(2.0, i_float); + float amplitude = pow(4.0, i_float); + + // use interpolate noise function to find noise value + float sampleNoise = interpolateNoise(x * frequency , y * frequency , z * frequency, 4 - i); + total += sampleNoise * amplitude; + } + + return total; +} + +float fbm2(float x, float y, float z) { + float total = 0.0; + const int OCTAVES = 4; + // float u_persistance = 4.0; + + // loop for some number of octaves + for(int i = 0; i < OCTAVES; i++) { + float i_float = float(i); + float frequency = pow(2.0, i_float); + float amplitude = pow(4.0, i_float); + + // use interpolate noise function to find noise value + float sampleNoise = interpolateNoise(x * frequency , y * frequency , z * frequency, i); + total += sampleNoise * amplitude; + } + + return total; +} + + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + // f_uv = uv; + f_normal = normal; + f_position = position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); + + // alter positions based on noise function + // add in the animation later meybe + // float timeMod = u_time / 300.0; + float noiseHeight = fbm( + float(uv.x) , + float(uv.y) , + float(position.z) ); + + vec3 noisyPosition = vec3( + uv.x + noiseHeight / 100.0, + uv.y + noiseHeight / 100.0 , + position.z ); + + float noiseHeight2 = fbm2( + uv.x + noisyPosition.x, + uv.y + noisyPosition.y, + position.z + noisyPosition.z); + + vec3 noisyPosition2 = (vec3( + noisyPosition.x + noiseHeight2 , + noisyPosition.y + noiseHeight2 , + position.z )); + + f_uv = vec2(noisyPosition2.x, noisyPosition2.y); + + // vNoiseValue = noiseHeight2; + + // gl_Position = projectionMatrix * modelViewMatrix * vec4(noisyPosition2, 1.0 ); + +} \ No newline at end of file diff --git a/src/glsl/pass-vert.glsl b/src/glsl/pass-vert.glsl index 2166f7a..befabd7 100644 --- a/src/glsl/pass-vert.glsl +++ b/src/glsl/pass-vert.glsl @@ -1,8 +1,10 @@ // we use this vertex shader for the post process steps. All we do is copy the uv value and set position appropriately +varying vec3 fPos; varying vec2 f_uv; void main() { f_uv = uv; + fPos = position; gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); } \ No newline at end of file diff --git a/src/glsl/pcolor-frag.glsl b/src/glsl/pcolor-frag.glsl new file mode 100644 index 0000000..a259fda --- /dev/null +++ b/src/glsl/pcolor-frag.glsl @@ -0,0 +1,43 @@ +uniform sampler2D texture; +uniform int u_useTexture; +uniform vec3 u_albedo; +uniform vec3 u_ambient; +uniform vec3 u_lightPos; +uniform vec3 u_lightCol; +uniform float u_lightIntensity; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + +// put into buckets +float findDiscreteValue() { + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0) * 3.0; + if (d <= 1.0) { + return 0.0; + } else if (d <= 2.0) { + return 1.0; + } else { + return 2.0; + } +} + +void main() { + vec3 cameraLook = f_position - cameraPosition; + + vec4 color = vec4(255.0/255.0, 177.0/255.0, 163.0/255.0,1.0); + + float toonValue = findDiscreteValue() / 3.0; + if (toonValue <= 1.0) { + // blue + color = vec4(108.0/255.0, 133.0/255.0, 232.0/255.0,1.0); + } else if (toonValue <= 2.0) { + // light blue + color = vec4(158.0/255.0 + 2.0, 177.0/215.0 - 2.0, 255.0/255.0,1.0); + } + + gl_FragColor = vec4(toonValue * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); + + // } + +} \ No newline at end of file diff --git a/src/glsl/pcolor-vert.glsl b/src/glsl/pcolor-vert.glsl new file mode 100644 index 0000000..86e2661 --- /dev/null +++ b/src/glsl/pcolor-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..9ca0c25 --- /dev/null +++ b/src/glsl/point-frag.glsl @@ -0,0 +1,43 @@ + +uniform sampler2D texture; +uniform int u_useTexture; +uniform vec3 u_albedo; +uniform vec3 u_ambient; +uniform vec3 u_lightPos; +uniform vec3 u_lightCol; +uniform float u_lightIntensity; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + +float noise(vec2 co){ + return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +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); + + float totalNoise = noise(vec2(f_position.x / 5.0, f_position.y / 5.0)); + + if (totalNoise > 0.5) { + gl_FragColor = vec4(0.0,0.0,0.0,1.0); + // gl_FragColor = vec4(0.294, 0.290, 0.282,1.0); + } else { + vec4 col = texture2D(texture, f_uv); + float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + + // col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + gl_FragColor = col; + } + + // gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); + // gl_FragColor = vec4(0.5, 0.5, 0.0, 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/screen-frag.glsl b/src/glsl/screen-frag.glsl new file mode 100644 index 0000000..02efcb9 --- /dev/null +++ b/src/glsl/screen-frag.glsl @@ -0,0 +1,57 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +varying vec2 f_uv; +varying vec3 fPos; + +float noise(float x, float y){ + float value1 = fract(sin(dot(vec2(x, y) ,vec2(1027.9898, 29381.233))) * 333019.5453); + + return dot(value1, 14958832.22); +} + +float noise_3(float x, float y, float z) { + float n = x * 109277.101 ; + float m = y * 101010010.0001; + n = fract(cos(dot(vec2(n,z), vec2(19469.294485, 128282.9383))) * 1094877.1293); + n = fract(tan(dot(n, m))); + return n; +} + +float noise_4(float x, float y, float z){ + float value1 = fract(sin(dot(vec2(x, y) ,vec2(3427.9898, 9847.233))) * 202.5453); + float value2 = fract(cos(z) * 20247.5453); + + return fract(dot(value1, value2)); +} + +float noise_1(float x, float y, float z){ + float value1 = fract(sin(dot(vec2(z, y) ,vec2(1027.9898, 29381.233))) * 333019.5453); + float value2 = fract(sin(x) * 43758.5453); + + return dot(value1, value2); +} + +void main() { + float noiseValue = noise_3(fPos.x / 200.0, fPos.y / 200.0, fPos.z / 200.0); + // float noiseValue1 = noise_1(fPos.x/ 100.0, fPos.y / 100.0, fPos.z / 100.0); + float totalNoise = 1.0 * noiseValue; // + 0.1 * noiseValue1; + // float totalNoise = noise(fPos.x, fPos.y); + if (totalNoise > 0.5) { + // gl_FragColor = vec4(0.0,0.0,0.0,1.0); + gl_FragColor = vec4(0.294, 0.290, 0.282,1.0); + } else { + vec4 col = texture2D(tDiffuse, f_uv); + float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + + col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + gl_FragColor = col; + } + // vec4 col = texture2D(tDiffuse, f_uv); + // float gray = dot(col.rgb, vec3(0.299, 0.587, 0.114)); + + // col.rgb = vec3(gray, gray, gray) * (u_amount) + col.rgb * (1.0 - u_amount); + + // gl_FragColor = col; +} \ 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..4142773 --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,51 @@ + +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; + +// put into buckets +float findDiscreteValue() { + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0) * 5.0; + if (d <= 1.0) { + return 0.0; + } else if (d <= 2.0) { + return 1.0; + } else if (d <= 3.0) { + return 2.0; + } else if (d <= 4.0) { + return 3.0; + } else { + return 4.0; + } +} + +void main() { + vec3 cameraLook = f_position - cameraPosition; + if (dot(cameraLook, f_normal) <= 0.5 && dot(cameraLook, f_normal) >= -0.5) { + gl_FragColor = vec4(1.0,1.0,1.0,1.0); + } + else { + 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); + + float toonValue = findDiscreteValue() / 5.0; + // take dot, multiplly by 10, then mod it by 10, then use that value to + + gl_FragColor = vec4(toonValue * color.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/post/grayscale.js b/src/post/grayscale.js index 728df40..80acbd3 100644 --- a/src/post/grayscale.js +++ b/src/post/grayscale.js @@ -5,6 +5,8 @@ var options = { amount: 1 } +// all postprocess shaders MUST have uniform called tDiffuse +// tDiffuse is texture which it renders the frame to. var GrayscaleShader = new EffectComposer.ShaderPass({ uniforms: { tDiffuse: { @@ -13,6 +15,8 @@ var GrayscaleShader = new EffectComposer.ShaderPass({ }, u_amount: { type: 'f', + // this is the amount of gray that I want to apply. when you want to modify the + // value, you need to say GrayscaleShader.material.uniforms.u_amount.value value: options.amount } }, @@ -20,6 +24,8 @@ var GrayscaleShader = new EffectComposer.ShaderPass({ fragmentShader: require('../glsl/grayscale-frag.glsl') }); +// using the three effect composer. ok. +// all shaders get initialized to renderer, scene, camera. i.e. for toon shading you need camera export default function Grayscale(renderer, scene, camera) { // this is the THREE.js object for doing post-process effects diff --git a/src/post/hatch.js b/src/post/hatch.js new file mode 100644 index 0000000..561e963 --- /dev/null +++ b/src/post/hatch.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +// all postprocess shaders MUST have uniform called tDiffuse +// tDiffuse is texture which it renders the frame to. +var GrayscaleShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + // this is the amount of gray that I want to apply. when you want to modify the + // value, you need to say GrayscaleShader.material.uniforms.u_amount.value + value: options.amount + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/hatch-frag.glsl') +}); + +// using the three effect composer. ok. +// all shaders get initialized to renderer, scene, camera. i.e. for toon shading you need camera +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/inclass.js b/src/post/inclass.js new file mode 100644 index 0000000..8df5688 --- /dev/null +++ b/src/post/inclass.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +// all postprocess shaders MUST have uniform called tDiffuse +// tDiffuse is texture which it renders the frame to. +var GrayscaleShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + // this is the amount of gray that I want to apply. when you want to modify the + // value, you need to say GrayscaleShader.material.uniforms.u_amount.value + value: options.amount + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/inclass-frag.glsl') +}); + +// using the three effect composer. ok. +// all shaders get initialized to renderer, scene, camera. i.e. for toon shading you need camera +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/index.js b/src/post/index.js index 9c0d763..ae47507 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 InClass} from './inclass' + +export {default as Screen} from './screen' + +export {default as Hatching} from './hatch' \ No newline at end of file diff --git a/src/post/screen.js b/src/post/screen.js new file mode 100644 index 0000000..1c3ef1b --- /dev/null +++ b/src/post/screen.js @@ -0,0 +1,54 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +var options = { + amount: 1 +} + +// all postprocess shaders MUST have uniform called tDiffuse +// tDiffuse is texture which it renders the frame to. +var GrayscaleShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + // this is the amount of gray that I want to apply. when you want to modify the + // value, you need to say GrayscaleShader.material.uniforms.u_amount.value + value: options.amount + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/screen-frag.glsl') +}); + +// using the three effect composer. ok. +// all shaders get initialized to renderer, scene, camera. i.e. for toon shading you need camera +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/shaders/index.js b/src/shaders/index.js index e5b85c1..55ce6b2 100644 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,12 @@ // 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 Geometric} from './noise' + +export {default as Pointillism} from './point' + +export {default as Monochrome} from './pcolor' \ No newline at end of file diff --git a/src/shaders/lambert.js b/src/shaders/lambert.js index 3e7abd1..4b62f8c 100644 --- a/src/shaders/lambert.js +++ b/src/shaders/lambert.js @@ -32,6 +32,9 @@ export default function(renderer, scene, camera) { }); }, + // all worlspace shaders should have a material + // this is the shader material used in project 1 + // all uniform values are used. material: new THREE.ShaderMaterial({ uniforms: { texture: { diff --git a/src/shaders/noise.js b/src/shaders/noise.js new file mode 100644 index 0000000..1a1e879 --- /dev/null +++ b/src/shaders/noise.js @@ -0,0 +1,80 @@ + +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; + }); + }, + + // all worlspace shaders should have a material + // this is the shader material used in project 1 + // all uniform values are used. + 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/noise-vert.glsl'), + fragmentShader: require('../glsl/noise-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/pcolor.js b/src/shaders/pcolor.js new file mode 100644 index 0000000..27d74f3 --- /dev/null +++ b/src/shaders/pcolor.js @@ -0,0 +1,82 @@ + +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 vector = new THREE.Vector3(); + // var lookVec = camera.getWorldDirection( vector ); + + 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; + }); + }, + + // all worlspace shaders should have a material + // this is the shader material used in project 1 + // all uniform values are used. + 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/pcolor-vert.glsl'), + fragmentShader: require('../glsl/pcolor-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..4957cdd --- /dev/null +++ b/src/shaders/point.js @@ -0,0 +1,80 @@ + +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; + }); + }, + + // all worlspace shaders should have a material + // this is the shader material used in project 1 + // all uniform values are used. + 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/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..7864913 --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,82 @@ + +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 vector = new THREE.Vector3(); + // var lookVec = camera.getWorldDirection( vector ); + + 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; + }); + }, + + // all worlspace shaders should have a material + // this is the shader material used in project 1 + // all uniform values are used. + 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