diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 08c69b7..1dbf183 --- a/README.md +++ b/README.md @@ -1,123 +1,34 @@ +# Shaders -# Project 5: Shaders +### Lambert +Standard lambert shading by default! -## Project Instructions +### Toon +In this Toon shader, we band color intensities together and set them to a floored value. We also take the vertex normal and color the fragment by the view direction if it exceeds a certain angle. This allows for a fun rainbowy outline of a character who seems to be shaded by a few colors only. -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. +### Lit Sphere +In this shader, we load MatCap spheres that were pre-generated. We then map the normal-space to UV-space using one easy trick that pipeline engineers don't want you to know! We extract the color from that texture using the corresponding UVs (mapped from normals) and set the vertex color. The end result is really cool materials that are applied to our model. This could have also been done as a fragment shader but I think it's a bit easier as a vertex shader and works well enough for our mesh which has high vertex density. -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! +# Post Processes -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. +### Grayscale +This is our Hello World, and is just a standard RGB -> Luminosity map. -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. +### Tint +We add a flat color to our fragment shaded values. -Examples: [https://cis700-procedural-graphics.github.io/Project5-Shaders/](https://cis700-procedural-graphics.github.io/Project5-Shaders/) +### Sobel +We take the two gradient Sobel kernels and apply a high pass to the image. We threshold the intensity values of both horizontal and vertical gradients and set the fragment colors to black beyond a certain point to highlight edges. -### 15 points each: Instagram-like filters +### Bloom +The pipeline is as follows: High pass, Blur, Additive Re-blending. The first step is a multi-target pass that generates a texture of only high intensity fragments and a texture of regular scene rendering. We then blur the high pass scene with a gaussian blur. The end result is additively recombined with the original. This yields a bloom effect. -- 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)) +### Oil/Watercolor paintings +For each pixel, we band intensities but this time we keep track of the sum of the R, G, and B values of that intensity as well as how often an intensity appears (the mode). We take the most frequent intensity band and then do a reverse lookup of the total R, G, and B values of that intensity band. We then divide by the mode of the intensity to obtain a flat color that we apply to pixels. Because the mode intensity doesn't change that often over pixels, we get the blotchiness that is characteristic of oil/watercolor paintings. -### 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). +### Dithering +Since the traditional serial Dithering algorithms aren't parallelizable in glsl, we resort to using other approximation methods. In particular, we perform Ordered Dithering using a generated Bayer matrix to "push" error around. We add the error to the pixel and round to either 1 or 0 (full color or none at all). The end result is pretty neat. -### 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 +### Pointilism +Really simple algorithm that goes as follows: take the intensity/luminosity of pixel, generate a random float, if the intensity/luminosity exceeds that random value, we make the pixel white, otherwise black. diff --git a/img/Thumbs.db b/img/Thumbs.db new file mode 100755 index 0000000..a1747da Binary files /dev/null and b/img/Thumbs.db differ diff --git a/img/mario1.png b/img/mario1.png new file mode 100755 index 0000000..ac003c3 Binary files /dev/null and b/img/mario1.png differ diff --git a/img/mario2.png b/img/mario2.png new file mode 100755 index 0000000..15f4ada Binary files /dev/null and b/img/mario2.png differ diff --git a/img/mario3.png b/img/mario3.png new file mode 100755 index 0000000..27ccf83 Binary files /dev/null and b/img/mario3.png differ diff --git a/img/mario4.png b/img/mario4.png new file mode 100755 index 0000000..a587520 Binary files /dev/null and b/img/mario4.png differ diff --git a/img/mario5.png b/img/mario5.png new file mode 100755 index 0000000..dff3f07 Binary files /dev/null and b/img/mario5.png differ diff --git a/index.html b/index.html old mode 100644 new mode 100755 diff --git a/mat/1.jpg b/mat/1.jpg new file mode 100755 index 0000000..2e2cd68 Binary files /dev/null and b/mat/1.jpg differ diff --git a/mat/2.jpg b/mat/2.jpg new file mode 100755 index 0000000..a91e84d Binary files /dev/null and b/mat/2.jpg differ diff --git a/mat/3.jpg b/mat/3.jpg new file mode 100755 index 0000000..42f7001 Binary files /dev/null and b/mat/3.jpg differ diff --git a/mat/4.jpg b/mat/4.jpg new file mode 100755 index 0000000..5564884 Binary files /dev/null and b/mat/4.jpg differ diff --git a/mat/5.jpg b/mat/5.jpg new file mode 100755 index 0000000..ed33ae8 Binary files /dev/null and b/mat/5.jpg differ diff --git a/mat/Thumbs.db b/mat/Thumbs.db new file mode 100755 index 0000000..fe7b0f3 Binary files /dev/null and b/mat/Thumbs.db differ diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/src/assets/0.bmp b/src/assets/0.bmp new file mode 100755 index 0000000..77ab3b5 Binary files /dev/null and b/src/assets/0.bmp differ diff --git a/src/assets/1.bmp b/src/assets/1.bmp new file mode 100755 index 0000000..d0fbc67 Binary files /dev/null and b/src/assets/1.bmp differ diff --git a/src/assets/2.bmp b/src/assets/2.bmp new file mode 100755 index 0000000..4a4cd05 Binary files /dev/null and b/src/assets/2.bmp differ diff --git a/src/assets/3.bmp b/src/assets/3.bmp new file mode 100755 index 0000000..323491e Binary files /dev/null and b/src/assets/3.bmp differ diff --git a/src/assets/4.bmp b/src/assets/4.bmp new file mode 100755 index 0000000..e79f25c Binary files /dev/null and b/src/assets/4.bmp differ diff --git a/src/assets/5.bmp b/src/assets/5.bmp new file mode 100755 index 0000000..2c5408b Binary files /dev/null and b/src/assets/5.bmp differ diff --git a/src/assets/6.bmp b/src/assets/6.bmp new file mode 100755 index 0000000..fc237e3 Binary files /dev/null and b/src/assets/6.bmp differ diff --git a/src/assets/Thumbs.db b/src/assets/Thumbs.db new file mode 100755 index 0000000..2693b16 Binary files /dev/null and b/src/assets/Thumbs.db differ diff --git a/src/assets/wahoo.bmp b/src/assets/wahoo.bmp old mode 100644 new mode 100755 diff --git a/src/assets/wahoo.obj b/src/assets/wahoo.obj old mode 100644 new mode 100755 diff --git a/src/glsl/bloom-frag.glsl b/src/glsl/bloom-frag.glsl new file mode 100755 index 0000000..f1f240b --- /dev/null +++ b/src/glsl/bloom-frag.glsl @@ -0,0 +1,15 @@ + +uniform sampler2D tDiffuse; +uniform sampler2D tBuffer; + +varying vec2 f_uv; + +float luminosity(vec4 color) { + return (0.2126*color.x + 0.7152*color.y + 0.0722*color.z); +} + +void main() { + vec4 regPass = texture2D(tDiffuse, f_uv); + vec4 highPass = texture2D(tBuffer, f_uv); + gl_FragColor = highPass + regPass; +} diff --git a/src/glsl/blur-frag.glsl b/src/glsl/blur-frag.glsl new file mode 100755 index 0000000..099e064 --- /dev/null +++ b/src/glsl/blur-frag.glsl @@ -0,0 +1,54 @@ +uniform sampler2D tDiffuse; +uniform vec2 u_scale; +uniform float u_std; +varying vec2 f_uv; + +#define PI 3.1415926535897932384626433 +#define E 2.7182818284590452353602874 +#define INV2PI 0.159154943 +#define SIZE 8 + +float luminosity(vec4 color) { + return (0.2126*color.x + 0.7152*color.y + 0.0722*color.z); +} + +float gaussian(float x, float y, float std) { + float invStdSqr = 1.0 / pow(std, 2.0); + float exponent = -(pow(x, 2.0) + pow(y, 2.0)) * invStdSqr / 2.0; + return INV2PI * invStdSqr * exp(exponent); +} + +void generateKernel(inout float kernel[SIZE * SIZE]) { + float total = 0.0; + float g = 0.0; + // Precompute gaussian kernel + for (int i = -SIZE / 2; i <= SIZE / 2; i++) { + for (int j = -SIZE / 2; j <= SIZE / 2; j++) { + g = gaussian(float(i), float(j), u_std); + kernel[(i + SIZE / 2) * SIZE + j] = g; + total += g; + } + } + // Normalize + for (int i = 0; i < SIZE * SIZE; i++) { + kernel[i] /= total; + } +} + +void applyKernel(inout vec4 color, float kernel[SIZE * SIZE]) { + for (int i = -SIZE / 2; i <= SIZE / 2; i++) { + for (int j = -SIZE / 2; j <= SIZE / 2; j++) { + color += texture2D(tDiffuse, f_uv + u_scale * vec2(i,j)) * kernel[(i + SIZE / 2) * SIZE + j]; + } + } +} + +void main() { + vec4 color = vec4(0.0, 0.0, 0.0, 1.0); + float kernel[SIZE * SIZE]; + + generateKernel(kernel); + applyKernel(color, kernel); + + gl_FragColor = color; +} diff --git a/src/glsl/dither-frag.glsl b/src/glsl/dither-frag.glsl new file mode 100755 index 0000000..ff98c15 --- /dev/null +++ b/src/glsl/dither-frag.glsl @@ -0,0 +1,45 @@ + +uniform sampler2D tDiffuse; +uniform float u_threshold; +uniform float u_kernel[9]; +uniform vec2 u_scale; +varying vec2 f_uv; + +#define MAX_LEVEL 16 +/* +Fast arbitrary bayer matrix generation algorithm borrowed from: +https://www.shadertoy.com/view/XtV3RG +*/ +float GetBayerFromCoordLevel(vec2 pixelpos) +{ + float finalBayer = 0.0; + float finalDivisor = 0.0; + float layerMult = 1.0; + + for(float bayerLevel = float(MAX_LEVEL); bayerLevel >= 1.0; bayerLevel--) { + vec2 bayercoord = mod(floor(pixelpos.xy / exp2(bayerLevel) * 2.0),2.0); + layerMult *= 4.0; + float line0202 = bayercoord.x * 2.0; + finalBayer += mix(line0202,3.0 - line0202,bayercoord.y) / 3.0 * layerMult; + finalDivisor += layerMult; + } + + return finalBayer / finalDivisor; +} + +vec4 closest(vec4 color) { + float r, g, b; + r = floor(color.r + u_threshold); + g = floor(color.g + u_threshold); + b = floor(color.b + u_threshold); + vec4 rounded = vec4(r, g, b, 1.0); + return rounded; +} + +void main() { + vec4 color = texture2D(tDiffuse, f_uv); + vec2 xy = f_uv / u_scale; + float bayer = GetBayerFromCoordLevel(xy) / 2.0; + color += vec4(bayer, bayer, bayer, 1.0); + gl_FragColor = closest(color); +} diff --git a/src/glsl/grayscale-frag.glsl b/src/glsl/grayscale-frag.glsl old mode 100644 new mode 100755 diff --git a/src/glsl/high-frag.glsl b/src/glsl/high-frag.glsl new file mode 100755 index 0000000..2da4075 --- /dev/null +++ b/src/glsl/high-frag.glsl @@ -0,0 +1,28 @@ + +uniform sampler2D tDiffuse; +uniform float u_threshold; +uniform vec2 u_scale; +uniform float u_std; +varying vec2 f_uv; + +#define PI 3.1415926535897932384626433 +#define E 2.7182818284590452353602874 +#define INV2PI 0.159154943 +#define SIZE 15 + +float intensity(vec4 color) { + return (color.x + color.y + color.z) / 3.0; +} + +float luminosity(vec4 color) { + return (0.2126*color.x + 0.7152*color.y + 0.0722*color.z); +} + +void main() { + vec4 texColor = texture2D(tDiffuse, f_uv); + if (luminosity(texColor) > u_threshold) { + gl_FragColor = texColor; + return; + } + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); +} diff --git a/src/glsl/intensity-frag.glsl b/src/glsl/intensity-frag.glsl new file mode 100755 index 0000000..aca162e --- /dev/null +++ b/src/glsl/intensity-frag.glsl @@ -0,0 +1,43 @@ +uniform sampler2D tDiffuse; +uniform int u_radius; +uniform float u_intensity; +uniform vec2 u_scale; +varying vec2 f_uv; + +const int MAXRAD = 10; + +float intensity(vec4 color) { + return (color.x + color.y + color.z) / 3.0; +} +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to + +void main() { + vec4 color = texture2D(tDiffuse, f_uv); + + + for (int i = -MAXRAD; i < MAXRAD; i++) { + if (i < -u_radius || i > u_radius) continue; + for (int j = -MAXRAD; j < MAXRAD; j++) { + if (j < -u_radius || j > u_radius) continue; + color = texture2D(tDiffuse, f_uv + u_scale * vec2(i,j)) * 255.0; + int curInt = int(intensity(color) * u_intensity / 255.0); + if (curInt > 255) curInt = 255; + intensities[curInt]++; + reds[curInt] += color.r; + greens[curInt] += color.g; + blues[curInt] += color.b; + } + } + + + int curMax = 0; + int maxIndex = 0; + for (int i = 0; i < 256; i++) { + if (intensities[i] > curMax) { + curMax = intensities[i]; + maxIndex = i; + } + } + vec3 rgb = vec3(reds[maxIndex], greens[maxIndex], blues[maxIndex]) / (255.0 * float(curMax)); + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/glsl/iridescent-frag.glsl b/src/glsl/iridescent-frag.glsl new file mode 100755 index 0000000..55b4cfd --- /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_viewPos; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; +varying float noise; + +// some standard noise function +float rand(vec2 coord){ + return fract(sin(dot(coord.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +void main() { + vec4 color = vec4(u_albedo, 1.0); + + float d = clamp(dot(f_normal, normalize(u_lightPos - f_position)), 0.0, 1.0); + + // color = texture2D(texture, vec2(f_uv.x - d * float(noise), f_uv.y - d * float(noise))); + color = texture2D(texture, f_uv); + + gl_FragColor = vec4(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient, 1.0); +} diff --git a/src/glsl/iridescent-vert.glsl b/src/glsl/iridescent-vert.glsl new file mode 100755 index 0000000..e88a907 --- /dev/null +++ b/src/glsl/iridescent-vert.glsl @@ -0,0 +1,74 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; +varying float noise; + +float PI = 3.14159265358979323; +float gen_noise(float x, float y, float z) { + return fract(sin(dot(vec3(x, y, z) ,vec3(12.9898,78.233,53.641))) * 43758.5453); +} + +float linear_interpolation(float a, float b, float t) { + return a * (1.0 - t) + b * t; +} + +float cosine_interpolation(float a, float b, float t) { + return linear_interpolation(a, b, (1.0 - cos(t * PI)) * 0.5); +} + +float noise_interpolation(float x, float y, float z) { + float x0 = floor(x), + x1 = floor(x) + 1.0, + y0 = floor(y), + y1 = floor(y) + 1.0, + z0 = floor(z), + z1 = floor(z) + 1.0; + + float i000 = gen_noise(x0, y0, z0), + i001 = gen_noise(x0, y0, z1), + i010 = gen_noise(x0, y1, z0), + i011 = gen_noise(x0, y1, z1), + i100 = gen_noise(x1, y0, z0), + i101 = gen_noise(x1, y0, z1), + i110 = gen_noise(x1, y1, z0), + i111 = gen_noise(x1, y1, z1); + + float dx = x - x0, + dy = y - y0, + dz = z - z0; + + float ix00 = cosine_interpolation(i000, i100, dx), + ix01 = cosine_interpolation(i001, i101, dx), + ix10 = cosine_interpolation(i010, i110, dx), + ix11 = cosine_interpolation(i011, i111, dx); + + float iy0 = cosine_interpolation(ix00, ix10, dy), + iy1 = cosine_interpolation(ix01, ix11, dy); + + float iz = cosine_interpolation(iy0, iy1, dz); + return iz; +} + +float multi_octave_noise(float x, float y, float z, float persistence) { + float total = 0.0; + for (int i = 0; i < 10; i++) { + // if (i >= octaves) { + // break; + // } + float freq = pow(2.0, float(i)); + float amp = pow(persistence, float(i)); + + total += noise_interpolation(freq * x, freq * y, freq * z) * amp; + } + + return total; +} +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + noise = multi_octave_noise(position.x, position.y, position.z, 0.5); + f_position = -.1 * noise * normal + position; + gl_Position = projectionMatrix * modelViewMatrix * vec4(f_position, 1.0); +} diff --git a/src/glsl/lambert-frag.glsl b/src/glsl/lambert-frag.glsl old mode 100644 new mode 100755 diff --git a/src/glsl/lambert-vert.glsl b/src/glsl/lambert-vert.glsl old mode 100644 new mode 100755 diff --git a/src/glsl/lit-frag.glsl b/src/glsl/lit-frag.glsl new file mode 100755 index 0000000..7c637f6 --- /dev/null +++ b/src/glsl/lit-frag.glsl @@ -0,0 +1,21 @@ + +uniform sampler2D texture; +uniform sampler2D matTexture; +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_viewPos; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; +varying vec2 v_n; + +void main() { + vec3 color = texture2D(matTexture, v_n).rgb; + gl_FragColor = vec4(color, 1.0); + +} diff --git a/src/glsl/lit-vert.glsl b/src/glsl/lit-vert.glsl new file mode 100755 index 0000000..3869cc8 --- /dev/null +++ b/src/glsl/lit-vert.glsl @@ -0,0 +1,17 @@ + +varying vec2 f_uv; +varying vec3 f_normal; +varying vec3 f_position; +varying vec2 v_n; + +// uv, position, projectionMatrix, modelViewMatrix, normal +void main() { + f_uv = uv; + f_normal = normal; + f_position = position; + // map normals to UVs + vec3 r = reflect(normalize(vec3(modelViewMatrix * vec4(position, 1.0))), normalize(normalMatrix * normal)); + float m = 2.0 * sqrt(pow(r.x, 2.0) + pow(r.y, 2.0) + pow(r.z + 1.0, 2.0)); + v_n = r.xy / m + 0.5; + gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); +} diff --git a/src/glsl/oil-frag.glsl b/src/glsl/oil-frag.glsl new file mode 100755 index 0000000..d859309 --- /dev/null +++ b/src/glsl/oil-frag.glsl @@ -0,0 +1,49 @@ +uniform sampler2D tDiffuse; +uniform int u_radius; +uniform float u_intensity; +uniform vec2 u_scale; +varying vec2 f_uv; + +#define MAXRAD 10 +#define INTENSITY 6 + +float intensity(vec4 color) { + return (color.x + color.y + color.z) / 3.0; +} +// tDiffuse is a special uniform sampler that THREE.js will bind the previously rendered frame to + +void main() { + vec4 col = texture2D(tDiffuse, f_uv); + vec4 color; + int intensities[INTENSITY]; + float reds[INTENSITY]; + float greens[INTENSITY]; + float blues[INTENSITY]; + for (int h = 0; h < INTENSITY; h++) { + for (int i = -MAXRAD; i < MAXRAD; i++) { + if (i < -u_radius || i > u_radius) continue; + for (int j = -MAXRAD; j < MAXRAD; j++) { + if (j < -u_radius || j > u_radius) continue; + color = texture2D(tDiffuse, f_uv + u_scale * vec2(i,j)); + int curInt = int(intensity(color) * float(INTENSITY - 1)); + if (h == curInt) { + intensities[h]++; + reds[h] += color.r; + greens[h] += color.g; + blues[h] += color.b; + } + } + } + } + + + int curMax = 0; + vec3 rgb; + for (int i = 0; i < INTENSITY; i++) { + if (intensities[i] > curMax) { + curMax = intensities[i]; + rgb = vec3(reds[i], greens[i], blues[i]) / float(curMax); + } + } + gl_FragColor = vec4(rgb, 1.0); +} diff --git a/src/glsl/pass-vert.glsl b/src/glsl/pass-vert.glsl old mode 100644 new mode 100755 diff --git a/src/glsl/point-frag.glsl b/src/glsl/point-frag.glsl new file mode 100755 index 0000000..85d97f6 --- /dev/null +++ b/src/glsl/point-frag.glsl @@ -0,0 +1,31 @@ + +uniform sampler2D tDiffuse; +uniform float u_threshold; +uniform float u_kernel[9]; +uniform vec2 u_scale; +varying vec2 f_uv; + +// some standard noise function +float rand(vec2 coord){ + return fract(sin(dot(coord.xy ,vec2(12.9898,78.233))) * 43758.5453); +} + +float luminosity(vec4 color) { + return (0.2126*color.x + 0.7152*color.y + 0.0722*color.z); +} + +vec4 threshold(vec4 color, vec2 loc) { + float lum = luminosity(color); + if (rand(loc) > lum) { + color = vec4(0.,0.,0.,1.); + } else { + color = vec4(1., 1., 1., 1.); + } + return color; +} + +void main() { + vec4 color = texture2D(tDiffuse, f_uv); + + gl_FragColor = threshold(color, f_uv); +} diff --git a/src/glsl/sobel-frag.glsl b/src/glsl/sobel-frag.glsl new file mode 100755 index 0000000..e6fe5df --- /dev/null +++ b/src/glsl/sobel-frag.glsl @@ -0,0 +1,44 @@ + +uniform sampler2D tDiffuse; +uniform float u_threshold; +uniform float u_kernel[9]; +uniform vec2 u_scale; +varying vec2 f_uv; + + +float intensity(vec4 color) { + return (color.x + color.y + color.z) / 3.0; +} + +void main() { + vec4 color = vec4(0.0, 0.0, 0.0, 1.0); + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, -1)) * 1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(0, -1)) * 2.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, -1)) * 1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, 0)) * 0.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, 0)) * 0.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, 1)) * -1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(0, 1)) * -2.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, 1)) * -1.0; + + if (intensity(color) > u_threshold) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + color = vec4(0.0, 0.0, 0.0, 1.0); + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, -1)) * -1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(0, -1)) * 0.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, -1)) * 1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, 0)) * -2.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, 0)) * 2.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(-1, 1)) * -1.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(0, 1)) * 0.0; + color += texture2D(tDiffuse, f_uv + u_scale * vec2(1, 1)) * 1.0; + + if (intensity(color) > u_threshold) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + return; + } + + gl_FragColor = texture2D(tDiffuse, f_uv); +} diff --git a/src/glsl/tint-frag.glsl b/src/glsl/tint-frag.glsl new file mode 100755 index 0000000..8e05fe2 --- /dev/null +++ b/src/glsl/tint-frag.glsl @@ -0,0 +1,14 @@ + +uniform sampler2D tDiffuse; +uniform float u_amount; +uniform vec3 u_tint; +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); + col.rgb = u_tint * u_amount + col.rgb * (1.0 - u_amount); + gl_FragColor = col; +} diff --git a/src/glsl/toon-frag.glsl b/src/glsl/toon-frag.glsl new file mode 100755 index 0000000..e7691b9 --- /dev/null +++ b/src/glsl/toon-frag.glsl @@ -0,0 +1,48 @@ + +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_viewPos; + +varying vec3 f_position; +varying vec3 f_normal; +varying vec2 f_uv; + + +float u_bands = 3.0; + +float band(float value) { + return floor(value * u_bands) / u_bands; +} + +float intensity(vec3 color) { + return (color.r + color.g + color.b) / 3.0; +} + +vec3 bandColor(vec3 color) { + float i = intensity(color); + float i_b = band(i); + return color * (i_b / i); +} + +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 u_viewDir = normalize(u_viewPos - f_position); + + if (dot(f_normal, u_viewDir) < 0.4) { + gl_FragColor = vec4(u_viewDir, 1.0); + } else { + gl_FragColor = vec4(bandColor(d * color.rgb * u_lightCol * u_lightIntensity + u_ambient), 1.0); + } +} diff --git a/src/glsl/toon-vert.glsl b/src/glsl/toon-vert.glsl new file mode 100755 index 0000000..7556051 --- /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); +} diff --git a/src/loader.js b/src/loader.js new file mode 100755 index 0000000..ed7fd78 --- /dev/null +++ b/src/loader.js @@ -0,0 +1,27 @@ + +// this file is just for convenience. it sets up loading the mario obj and texture +const THREE = require('three'); +const NUM_MATS = 7; +require('three-obj-loader')(THREE) + +export let textureLoaded = new Promise((resolve, reject) => { + (new THREE.TextureLoader()).load(require('./assets/wahoo.bmp'), function(texture) { + resolve(texture); + }); +}); + +export let objLoaded = new Promise((resolve, reject) => { + (new THREE.OBJLoader()).load(require('./assets/wahoo.obj'), function(obj) { + let geo = obj.children[0].geometry; + geo.computeBoundingSphere(); + resolve(geo); + }); +}); + +export let matLoaded = Promise.all([...Array(NUM_MATS).keys()].map(i => { + return new Promise((resolve, reject) => { + (new THREE.TextureLoader()).load(require(`./assets/${i}.bmp`), function(texture) { + resolve(texture); + }); + }); +})); diff --git a/src/main.js b/src/main.js old mode 100644 new mode 100755 index d7c08ae..e20e0f2 --- a/src/main.js +++ b/src/main.js @@ -4,25 +4,25 @@ const THREE = require('three'); const OrbitControls = require('three-orbit-controls')(THREE) import Stats from 'stats-js' -import {objLoaded} from './mario' +import {objLoaded} from './loader' import {setupGUI} from './setup' window.addEventListener('load', function() { - var stats = new Stats(); + let stats = new Stats(); stats.setMode(1); stats.domElement.style.position = 'absolute'; stats.domElement.style.left = '0px'; stats.domElement.style.top = '0px'; document.body.appendChild(stats.domElement); - var scene = new THREE.Scene(); - var camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); - var renderer = new THREE.WebGLRenderer( { antialias: true } ); + let scene = new THREE.Scene(); + let camera = new THREE.PerspectiveCamera( 75, window.innerWidth/window.innerHeight, 0.1, 1000 ); + let renderer = new THREE.WebGLRenderer( { antialias: true } ); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); renderer.setClearColor(0x999999, 1.0); - var controls = new OrbitControls(camera, renderer.domElement); + let controls = new OrbitControls(camera, renderer.domElement); controls.enableDamping = true; controls.enableZoom = true; controls.rotateSpeed = 0.3; @@ -36,8 +36,8 @@ window.addEventListener('load', function() { camera.updateProjectionMatrix(); renderer.setSize(window.innerWidth, window.innerHeight); }); - - var mesh, shader, post; + + let mesh, shader, post; // this gets called when we set the shader function shaderSet(Shader, gui) { // create the shader and initialize its gui @@ -78,4 +78,4 @@ window.addEventListener('load', function() { stats.end(); requestAnimationFrame(tick); })(); -}); \ No newline at end of file +}); diff --git a/src/mario.js b/src/mario.js deleted file mode 100644 index 38647ba..0000000 --- a/src/mario.js +++ /dev/null @@ -1,19 +0,0 @@ - -// this file is just for convenience. it sets up loading the mario obj and texture - -const THREE = require('three'); -require('three-obj-loader')(THREE) - -export var textureLoaded = new Promise((resolve, reject) => { - (new THREE.TextureLoader()).load(require('./assets/wahoo.bmp'), function(texture) { - resolve(texture); - }) -}) - -export var objLoaded = new Promise((resolve, reject) => { - (new THREE.OBJLoader()).load(require('./assets/wahoo.obj'), function(obj) { - var geo = obj.children[0].geometry; - geo.computeBoundingSphere(); - resolve(geo); - }); -}) \ No newline at end of file diff --git a/src/post/bloom.js b/src/post/bloom.js new file mode 100755 index 0000000..8cca041 --- /dev/null +++ b/src/post/bloom.js @@ -0,0 +1,95 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + threshold: 0.9, + color: '#000000', + std: 5 +}; + +let bufferTexture = THREE.WebGLRenderTarget(window.innerWidth, window.innerHeight); + +let HighPass = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_threshold: { + type: 'f', + value: options.threshold + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/high-frag.glsl') +}); + +let BlurPass = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_std: { + type: 'v3', + value: options.std + }, + u_scale: { + type: 'v3', + value: new THREE.Vector2(1.0 / window.innerWidth, 1.0 / window.innerHeight) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/blur-frag.glsl') +}); + +let BloomShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + tBuffer: { + type: 't', + value: null + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/bloom-frag.glsl') +}); + + +export default function Bloom(renderer, scene, camera) { + + renderer.render(scene, camera, bufferTexture); + + let composer = new EffectComposer(renderer); + composer.addPass(new EffectComposer.RenderPass(scene, camera)); + composer.addPass(HighPass); + composer.addPass(BlurPass); + composer.addPass(BlurPass); + composer.addPass(BlurPass); + + let final = new EffectComposer(renderer); + final.addPass(new EffectComposer.RenderPass(scene, camera)); + final.addPass(BloomShader); + BloomShader.material.uniforms.tBuffer.value = composer.renderTarget2.texture; + + BloomShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'threshold', 0, 1).onChange(function(val) { + HighPass.material.uniforms.u_threshold.value = val; + }); + gui.add(options, 'std', 0.01, 10).onChange(function(val) { + BlurPass.material.uniforms.u_std.value = val; + }); + }, + + render: function() { + composer.render(); + final.render(); + } + } +} diff --git a/src/post/dither.js b/src/post/dither.js new file mode 100755 index 0000000..83ce083 --- /dev/null +++ b/src/post/dither.js @@ -0,0 +1,52 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + threshold: 0.35, +}; + +let DitherShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_threshold: { + type: 'f', + value: options.threshold + }, + u_scale: { + type: 'v3', + value: new THREE.Vector2(1.0 / window.innerWidth, 1.0 / window.innerHeight) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/dither-frag.glsl') +}); + +export default function Dither(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + let 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 DitherShader + composer.addPass(DitherShader); + + // set this to true on the shader for your last pass to write to the screen + DitherShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'threshold', 0, 1).onChange(function(val) { + DitherShader.material.uniforms.u_threshold.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} diff --git a/src/post/grayscale.js b/src/post/grayscale.js old mode 100644 new mode 100755 index 728df40..c7b1ea9 --- a/src/post/grayscale.js +++ b/src/post/grayscale.js @@ -1,11 +1,11 @@ const THREE = require('three'); const EffectComposer = require('three-effectcomposer')(THREE) -var options = { +let options = { amount: 1 } -var GrayscaleShader = new EffectComposer.ShaderPass({ +let GrayscaleShader = new EffectComposer.ShaderPass({ uniforms: { tDiffuse: { type: 't', @@ -23,7 +23,7 @@ var GrayscaleShader = new EffectComposer.ShaderPass({ export default function Grayscale(renderer, scene, camera) { // this is the THREE.js object for doing post-process effects - var composer = new EffectComposer(renderer); + let composer = new EffectComposer(renderer); // first render the scene normally and add that as the first pass composer.addPass(new EffectComposer.RenderPass(scene, camera)); diff --git a/src/post/index.js b/src/post/index.js old mode 100644 new mode 100755 index 9c0d763..200efd1 --- 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 Tint} from './tint' +export {default as Sobel} from './sobel' +export {default as Bloom} from './bloom' +export {default as Oil} from './oil' +export {default as Dither} from './dither' +export {default as Point} from './point' diff --git a/src/post/oil.js b/src/post/oil.js new file mode 100755 index 0000000..98812df --- /dev/null +++ b/src/post/oil.js @@ -0,0 +1,62 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + intensity: 5, + color: '#000000', + radius: 5 +}; + +let OilShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_intensity: { + type: 'f', + value: options.intensity + }, + u_radius: { + type: 'v3', + value: options.radius + }, + u_scale: { + type: 'v3', + value: new THREE.Vector2(1.0 / window.innerWidth, 1.0 / window.innerHeight) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/oil-frag.glsl') +}); + + +export default function Oil(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + let 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 OilShader + composer.addPass(OilShader); + + // set this to true on the shader for your last pass to write to the screen + OilShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'intensity', 0, 50).onChange(function(val) { + OilShader.material.uniforms.u_intensity.value = val; + }); + gui.add(options, 'radius', 0, 10).step(1).onChange(function(val) { + OilShader.material.uniforms.u_radius.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} diff --git a/src/post/point.js b/src/post/point.js new file mode 100755 index 0000000..9cf5299 --- /dev/null +++ b/src/post/point.js @@ -0,0 +1,52 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + threshold: 0.35, +}; + +let PointShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_threshold: { + type: 'f', + value: options.threshold + }, + u_scale: { + type: 'v3', + value: new THREE.Vector2(1.0 / window.innerWidth, 1.0 / window.innerHeight) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/point-frag.glsl') +}); + +export default function Point(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + let 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 PointShader + composer.addPass(PointShader); + + // set this to true on the shader for your last pass to write to the screen + PointShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'threshold', 0, 1).onChange(function(val) { + PointShader.material.uniforms.u_threshold.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} diff --git a/src/post/sobel.js b/src/post/sobel.js new file mode 100755 index 0000000..dae532e --- /dev/null +++ b/src/post/sobel.js @@ -0,0 +1,53 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + threshold: 0.8, + color: '#000000' +}; + +let SobelShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_threshold: { + type: 'f', + value: options.threshold + }, + u_scale: { + type: 'v3', + value: new THREE.Vector2(1.0 / window.innerWidth, 1.0 / window.innerHeight) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/sobel-frag.glsl') +}); + +export default function Sobel(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + let 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 SobelShader + composer.addPass(SobelShader); + + // set this to true on the shader for your last pass to write to the screen + SobelShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'threshold', 0, 1).onChange(function(val) { + SobelShader.material.uniforms.u_threshold.value = val; + }); + }, + + render: function() {; + composer.render(); + } + } +} diff --git a/src/post/tint.js b/src/post/tint.js new file mode 100755 index 0000000..18a7c56 --- /dev/null +++ b/src/post/tint.js @@ -0,0 +1,56 @@ +const THREE = require('three'); +const EffectComposer = require('three-effectcomposer')(THREE) + +let options = { + amount:0.2, + color: '#000000' +}; + +let TintShader = new EffectComposer.ShaderPass({ + uniforms: { + tDiffuse: { + type: 't', + value: null + }, + u_amount: { + type: 'f', + value: options.amount + }, + u_tint: { + type: 'v3', + value: new THREE.Color(options.color) + } + }, + vertexShader: require('../glsl/pass-vert.glsl'), + fragmentShader: require('../glsl/tint-frag.glsl') +}); + +export default function Tint(renderer, scene, camera) { + + // this is the THREE.js object for doing post-process effects + let 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 TintShader + composer.addPass(TintShader); + + // set this to true on the shader for your last pass to write to the screen + TintShader.renderToScreen = true; + + return { + initGUI: function(gui) { + gui.add(options, 'amount', 0, 1).onChange(function(val) { + TintShader.material.uniforms.u_amount.value = val; + }); + gui.addColor(options, 'color').onChange(function(val) { + TintShader.material.uniforms.u_tint.value = new THREE.Color(val); + }); + }, + + render: function() {; + composer.render(); + } + } +} diff --git a/src/setup.js b/src/setup.js old mode 100644 new mode 100755 index 0414457..ba124bd --- a/src/setup.js +++ b/src/setup.js @@ -3,7 +3,7 @@ import * as Post from './post' import DAT from 'dat-gui' DAT.GUI.prototype.removeFolder = function(name) { - var folder = this.__folders[name]; + let folder = this.__folders[name]; if (!folder) { return; } @@ -14,7 +14,7 @@ DAT.GUI.prototype.removeFolder = function(name) { } DAT.GUI.prototype.emptyFolder = function(name) { - var folder = this.__folders[name]; + let folder = this.__folders[name]; if (!folder) { return; } @@ -26,19 +26,19 @@ DAT.GUI.prototype.emptyFolder = function(name) { } export function setupGUI(shaderSet, postProcessSet) { - var gui = new DAT.GUI(); - var opts = { shader: null, post: null } + let gui = new DAT.GUI(); + let opts = { shader: null, post: null } - var shaderControl = gui.add(opts, 'shader', Object.keys(Shaders)).onChange(name => { + let shaderControl = gui.add(opts, 'shader', Object.keys(Shaders)).onChange(name => { setShader(name); }); - var shaderFolder = gui.addFolder('Shader Settings'); + let shaderFolder = gui.addFolder('Shader Settings'); shaderFolder.open(); - var postControl = gui.add(opts, 'post', Object.keys(Post)).onChange(name => { + let postControl = gui.add(opts, 'post', Object.keys(Post)).onChange(name => { setPostProcess(name); }) - var postFolder = gui.addFolder('Post Process Settings'); + let postFolder = gui.addFolder('Post Process Settings'); postFolder.open(); function setShader(name) { diff --git a/src/shaders/index.js b/src/shaders/index.js old mode 100644 new mode 100755 index e5b85c1..c96a7e1 --- a/src/shaders/index.js +++ b/src/shaders/index.js @@ -1,4 +1,8 @@ // 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 Lit} from './lit' +// export {default as Iridescent} from './iridescent' diff --git a/src/shaders/iridescent.js b/src/shaders/iridescent.js new file mode 100755 index 0000000..c0cecee --- /dev/null +++ b/src/shaders/iridescent.js @@ -0,0 +1,75 @@ +const THREE = require('three'); +import { + textureLoaded +} from '../loader' + +// options for lambert shader +let 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); + }); + }, + + 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/iridescent-vert.glsl'), + fragmentShader: require('../glsl/iridescent-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} diff --git a/src/shaders/lambert.js b/src/shaders/lambert.js old mode 100644 new mode 100755 index 3e7abd1..842e914 --- a/src/shaders/lambert.js +++ b/src/shaders/lambert.js @@ -1,77 +1,78 @@ - -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/lambert-vert.glsl'), - fragmentShader: require('../glsl/lambert-frag.glsl') - }) - } - - // once the Mario texture loads, bind it to the material - textureLoaded.then(function(texture) { - Shader.material.uniforms.texture.value = texture; - }); - - return Shader; +const THREE = require('three'); +import { + textureLoaded +} from '../loader' + +// options for lambert shader +let 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/lambert-vert.glsl'), + fragmentShader: require('../glsl/lambert-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/lit.js b/src/shaders/lit.js new file mode 100755 index 0000000..ce27875 --- /dev/null +++ b/src/shaders/lit.js @@ -0,0 +1,59 @@ + +const THREE = require('three'); +import {textureLoaded, matLoaded} from '../loader' + +// options for ramp shader +let options = { + lightColor: '#ffffff', + lightIntensity: 2, + albedo: '#dddddd', + ambient: '#111111', + useTexture: true, + mat: 'Tarnished' +} + +let mat = {}; +let materials = ['Tarnished', 'Metal', 'Clay', 'Brass', 'Plastic', 'Marble', 'Shiny']; + +export default function(renderer, scene, camera) { + + const Shader = { + initGUI: function(gui) { + gui.add(options, 'mat', materials).onChange(function (val) { + Shader.material.uniforms.matTexture.value = mat[val]; + }); + }, + + material: new THREE.ShaderMaterial({ + uniforms: { + matTexture: { + type: "t", + value: null + }, + u_lightPos: { + type: 'v3', + value: new THREE.Vector3(30, 50, 40) + }, + u_viewPos: { + type: 'v3', + value: camera.position + } + }, + vertexShader: require('../glsl/lit-vert.glsl'), + fragmentShader: require('../glsl/lit-frag.glsl') + }) + } + + matLoaded.then(textures => { + textures.forEach((t, i) => { + mat[i] = t; + }); + // aliasing + materials.forEach((m, i) => { + mat[m] = mat[i] + }); + Shader.material.uniforms.matTexture.value = mat[options.mat]; + }); + + return Shader; +} diff --git a/src/shaders/toon.js b/src/shaders/toon.js new file mode 100755 index 0000000..cc56d97 --- /dev/null +++ b/src/shaders/toon.js @@ -0,0 +1,82 @@ +const THREE = require('three'); +import { + textureLoaded +} from '../loader' + +// options for ramp shader +let 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_viewPos: { + type: 'v3', + value: camera.position + } + }, + vertexShader: require('../glsl/toon-vert.glsl'), + fragmentShader: require('../glsl/toon-frag.glsl') + }) + } + + // once the Mario texture loads, bind it to the material + textureLoaded.then(function(texture) { + Shader.material.uniforms.texture.value = texture; + }); + + return Shader; +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js old mode 100644 new mode 100755