├── .babelrc ├── .gitignore ├── README.md ├── src ├── fragapp │ ├── vert.glsl │ ├── frag.glsl │ └── index.js ├── 003 │ ├── vert.glsl │ ├── frag.glsl │ └── index.js ├── 001 │ ├── vert.glsl │ ├── compute-position.glsl │ ├── frag.glsl │ ├── compute-velocity.glsl │ └── index.js ├── templates │ └── index.hbs ├── ThreeApp.js ├── 002 │ └── index.js └── lib │ └── GPUComputationRenderer.js ├── public ├── 001 │ ├── particle.png │ └── index.html ├── now.json ├── index.html ├── scripts │ ├── ga.js │ ├── tween.min.js │ └── dat.gui.min.js ├── 002 │ ├── index.html │ └── bundle.js ├── 003 │ ├── index.html │ └── bundle.js └── styles │ └── experiments.css ├── experiments.json ├── LICENSE ├── package.json └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["latest"] 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | **/*.sw* 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # experiments 2 | 3 | audio/VR/AR/GL experiments for the web. 4 | -------------------------------------------------------------------------------- /src/fragapp/vert.glsl: -------------------------------------------------------------------------------- 1 | void main() { 2 | gl_Position = vec4(position, 1.0); 3 | } 4 | -------------------------------------------------------------------------------- /public/001/particle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsantell/experiments/HEAD/public/001/particle.png -------------------------------------------------------------------------------- /public/now.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "experiments-jsantell", 3 | "alias": "experiments.jsantell.com", 4 | "type": "static" 5 | } 6 | -------------------------------------------------------------------------------- /src/003/vert.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() { 4 | vUv = uv; 5 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 6 | } 7 | -------------------------------------------------------------------------------- /src/001/vert.glsl: -------------------------------------------------------------------------------- 1 | uniform float size; 2 | uniform sampler2D tPosition; 3 | uniform sampler2D tVelocity; 4 | varying vec3 vPosition; 5 | 6 | void main() { 7 | vec3 pos = texture2D(tPosition, uv).xyz; 8 | vPosition = pos; 9 | gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0); 10 | gl_PointSize = size; 11 | } 12 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Experiments 6 | 7 | 8 | 9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/001/compute-position.glsl: -------------------------------------------------------------------------------- 1 | uniform float delta; 2 | 3 | #pragma glslify: when_lt = require(glsl-conditionals/when_lt) 4 | 5 | void main() { 6 | vec2 uv = gl_FragCoord.xy / resolution.xy; 7 | vec3 pos = texture2D(tPosition, uv).xyz; 8 | vec4 tmpVel = texture2D(tVelocity, uv); 9 | vec3 vel = tmpVel.xyz; 10 | float mass = tmpVel.w; 11 | 12 | pos += vel * delta * mass; 13 | 14 | pos *= when_lt(length(pos), 2.5); 15 | 16 | gl_FragColor = vec4(pos, 1.0); 17 | } 18 | -------------------------------------------------------------------------------- /src/001/frag.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | uniform sampler2D sprite; 3 | 4 | varying vec3 vPosition; 5 | 6 | #pragma glslify: map = require(glsl-map) 7 | #pragma glslify: hsl2rgb = require(glsl-hsl2rgb) 8 | 9 | void main() { 10 | vec4 tex = texture2D(sprite, gl_PointCoord); 11 | float l = length(vPosition); 12 | float t = clamp(-1.0, 1.0, sin(time * 0.0005)); 13 | vec3 hsl = hsl2rgb(map(t+l, -1.0, 3.0, 0.3, 0.7), 0.8, 0.5); 14 | gl_FragColor = vec4(hsl, tex.a*0.1); 15 | } 16 | -------------------------------------------------------------------------------- /src/fragapp/frag.glsl: -------------------------------------------------------------------------------- 1 | uniform float uTime; 2 | uniform float uDelta; 3 | uniform vec2 uResolution; 4 | 5 | #pragma glslify: hsl2rgb = require(glsl-hsl2rgb) 6 | 7 | void main() { 8 | vec2 st = gl_FragCoord.xy / uResolution.xy; 9 | float hue = cos(st.y) + sin(uTime * 0.0001); 10 | vec3 rgb = vec3( 11 | (sin((uTime * 0.001) + 0.1) + 1.0) / 2.0, 12 | (sin((uTime * 0.001) + 0.2) + 1.0) / 2.0, 13 | (sin((uTime * 0.001) + 0.8) + 1.0) / 2.0 14 | ); 15 | gl_FragColor = vec4(rgb, 1.0); 16 | } 17 | -------------------------------------------------------------------------------- /public/scripts/ga.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | if (!/jsantell.com/.test(window.location.host)) { 3 | return; 4 | } 5 | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 6 | (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 7 | m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 8 | })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 9 | 10 | ga('create', 'UA-23782413-1', 'auto'); 11 | ga('send', 'pageview'); 12 | })(); 13 | -------------------------------------------------------------------------------- /src/003/frag.glsl: -------------------------------------------------------------------------------- 1 | uniform vec3 fgColor; 2 | uniform vec3 bgColor; 3 | 4 | varying vec2 vUv; 5 | 6 | #pragma glslify: when_gt = require(glsl-conditionals/when_gt) 7 | 8 | void main() { 9 | float limit = 0.1; 10 | vec3 color = fgColor; 11 | 12 | float isTiled = 0.0; 13 | isTiled += when_gt(limit, vUv.x); 14 | isTiled += when_gt(limit, vUv.y); 15 | isTiled += when_gt(vUv.x, 1.0 - limit); 16 | isTiled += when_gt(vUv.y, 1.0 - limit); 17 | 18 | color = (step(1.0, isTiled) * bgColor) + ((1.0 - step(1.0, isTiled)) * fgColor); 19 | gl_FragColor = vec4(color, 1.0); 20 | } 21 | -------------------------------------------------------------------------------- /experiments.json: -------------------------------------------------------------------------------- 1 | { 2 | "experiments": { 3 | "001": { 4 | "title": "Energy", 5 | "subtitle": "1 Million Particles", 6 | "dependencies": [ 7 | { "name": "three" } 8 | ] 9 | }, 10 | "002": { 11 | "title": "Slinky", 12 | "subtitle": "Exploration of splines", 13 | "dependencies": [ 14 | { "name": "three" } 15 | ] 16 | }, 17 | "003": { 18 | "title": "rubix", 19 | "subtitle": "three degrees of freedom", 20 | "dependencies": [ 21 | { "name": "three" }, 22 | { "name": "tween" } 23 | ] 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /public/001/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Experiment 001: Energy 6 | 7 | 8 | 9 | 10 | 11 |
12 | Experiment 001 13 | Energy 14 | 1 Million Particles 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /public/002/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Experiment 002: Slinky 6 | 7 | 8 | 9 | 10 | 11 |
12 | Experiment 002 13 | Slinky 14 | Exploration of splines 15 |
16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/001/compute-velocity.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | 3 | #pragma glslify: snoise3 = require(glsl-noise/simplex/3d) 4 | #pragma glslify: when_gt = require(glsl-conditionals/when_gt) 5 | 6 | const float max = 1.5; 7 | 8 | void main() { 9 | vec2 uv = gl_FragCoord.xy / resolution.xy; 10 | vec3 pos = texture2D(tPosition, uv).xyz; 11 | vec4 tmpVel = texture2D(tVelocity, uv); 12 | vec3 vel = tmpVel.xyz; 13 | float mass = tmpVel.w; 14 | 15 | // decay 16 | vel *= 0.9; 17 | 18 | float mod = sin(time * 0.0001); 19 | vel += -pos * 15.0 * snoise3(pos*mod+5.0); 20 | 21 | float outOfBounds = when_gt(length(pos), max); 22 | vel = (outOfBounds * -pos * 0.15) + ((1.0 - outOfBounds) * vel); 23 | 24 | gl_FragColor = vec4(vel, mass); 25 | } 26 | -------------------------------------------------------------------------------- /public/003/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Experiment 003: rubix 6 | 7 | 8 | 9 | 10 | 11 |
12 | Experiment 003 13 | rubix 14 | three degrees of freedom 15 |
16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /public/styles/experiments.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | padding: 0; 4 | font-family: 'Roboto', sans-serif; 5 | color: white; 6 | padding: fixed; 7 | } 8 | 9 | #info { 10 | padding: 10px; 11 | background-color: rgba(0, 0, 0, 0.4); 12 | position: fixed; 13 | left: 0; 14 | bottom: 0; 15 | font-size: 120%; 16 | } 17 | 18 | .experiment-number { 19 | font-weight: 800; 20 | text-transform: uppercase; 21 | } 22 | 23 | .experiment-number:after { 24 | content: ':'; 25 | } 26 | 27 | .experiment-title { 28 | font-weight: 300; 29 | text-transform: uppercase; 30 | } 31 | 32 | .experiment-subtitle { 33 | margin-top: 3px; 34 | text-transform: lowercase; 35 | font-weight: 300; 36 | font-size: 70%; 37 | color: #ccc; 38 | display: block; 39 | } 40 | 41 | .experiment-subtitle:before { 42 | content: '>'; 43 | } 44 | -------------------------------------------------------------------------------- /src/templates/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Experiment {{htmlWebpackPlugin.options.id}}: {{htmlWebpackPlugin.options.title}} 6 | 7 | 8 | 9 | 10 | 11 |
12 | Experiment {{htmlWebpackPlugin.options.id}} 13 | {{htmlWebpackPlugin.options.title}} 14 | {{htmlWebpackPlugin.options.subtitle}} 15 |
16 | {{#each htmlWebpackPlugin.options.dependencies}} 17 | 18 | {{/each}} 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 Jordan Santell 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/fragapp/index.js: -------------------------------------------------------------------------------- 1 | import { PlaneGeometry, Mesh, ShaderMaterial } from 'three'; 2 | import ThreeApp from '../ThreeApp'; 3 | import vertexShader from './vert.glsl'; 4 | import fragmentShader from './frag.glsl'; 5 | 6 | class Experiment002 extends ThreeApp { 7 | init() { 8 | this.material = new ShaderMaterial({ 9 | uniforms: { 10 | uTime: { value: performance.now() }, 11 | uResolution: { value: [window.innerWidth, window.innerHeight] }, 12 | uDelta: { value: 0 }, 13 | }, 14 | fragmentShader, 15 | vertexShader, 16 | }); 17 | this.geometry = new PlaneGeometry(2, 2); 18 | this.mesh = new Mesh(this.geometry, this.material); 19 | this.scene.add(this.mesh); 20 | 21 | this.camera.position.set(0, 0, 1); 22 | } 23 | 24 | update(t, delta) { 25 | this.material.uniforms.uTime.value = t; 26 | this.material.uniforms.uDelta.value = delta; 27 | } 28 | 29 | render() { 30 | this.renderer.render(this.scene, this.camera); 31 | } 32 | 33 | onResize() { 34 | super.onResize(); 35 | this.material.uniforms.uResolution.value = [window.innerWidth, window.innerHeight]; 36 | } 37 | } 38 | 39 | export default new Experiment002(); 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@jsantell/experiments", 3 | "version": "1.0.0", 4 | "private": true, 5 | "description": "audio/VR/AR/GL experiments for the web.", 6 | "main": "index.js", 7 | "scripts": { 8 | "build": "webpack", 9 | "watch": "webpack-dev-server" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/jsantell/experiments.git" 14 | }, 15 | "author": "Jordan Santell", 16 | "license": "MIT", 17 | "bugs": { 18 | "url": "https://github.com/jsantell/experiments/issues" 19 | }, 20 | "homepage": "https://github.com/jsantell/experiments#readme", 21 | "devDependencies": { 22 | "babel-core": "^6.26.0", 23 | "babel-loader": "^7.1.2", 24 | "babel-preset-latest": "^6.24.1", 25 | "glsl-conditionals": "^1.0.0", 26 | "glsl-hsl2rgb": "^1.1.0", 27 | "glsl-hsv2rgb": "^1.0.0", 28 | "glsl-map": "^1.0.1", 29 | "glsl-noise": "0.0.0", 30 | "glsl-raytrace": "^1.0.0", 31 | "glsl-sdf-box": "^1.0.0", 32 | "glsl-sdf-normal": "^1.0.0", 33 | "glsl-turntable-camera": "^1.0.0", 34 | "glslify-loader": "^1.0.2", 35 | "handlebars": "^4.0.11", 36 | "handlebars-loader": "^1.6.0", 37 | "html-webpack-plugin": "^2.30.1", 38 | "raw-loader": "^0.5.1", 39 | "webpack": "^3.7.1", 40 | "webpack-dev-server": "^2.9.1" 41 | }, 42 | "dependencies": { 43 | "@alex_toudic/wagner": "^0.1.20", 44 | "stats.js": "^0.17.0" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const path = require('path'); 3 | const webpack = require('webpack'); 4 | const html = require('html-webpack-plugin'); 5 | const experiments = require('./experiments.json').experiments; 6 | 7 | const data = { 8 | entries: {}, 9 | html: [], 10 | }; 11 | Object.keys(experiments).map(id => { 12 | data.entries[id] = `./src/${id}/index.js`; 13 | 14 | const meta = experiments[id]; 15 | const config = Object.assign({ 16 | title: 'untitled', 17 | subtitle: '', 18 | template: './src/templates/index.hbs', 19 | id: id, 20 | filename: `${id}/index.html`, 21 | inject: false, 22 | }, meta); 23 | 24 | data.html.push(new html(config)); 25 | }); 26 | 27 | module.exports = { 28 | entry: data.entries, 29 | output: { 30 | path: path.join(__dirname, 'public'), 31 | publicPath: '', 32 | libraryTarget: 'umd', 33 | library: 'app', 34 | filename: '[name]/bundle.js' 35 | }, 36 | module: { 37 | rules: [ 38 | { test: /\.js/, exclude: /node_modules/, use: ['babel-loader'] }, 39 | { test: /\.hbs/, exclude: /node_modules/, use: ['handlebars-loader'] }, 40 | { 41 | test: /\.(glsl|frag|vert)$/, 42 | // exclude: /node_modules/, 43 | use: ['raw-loader', 'glslify-loader'] 44 | }, 45 | ] 46 | }, 47 | externals: { 48 | three: { 49 | commonjs: 'three', 50 | commonjs2: 'three', 51 | amd: 'three', 52 | root: 'THREE', 53 | }, 54 | tween: { 55 | commonjs: 'tween', 56 | commonjs2: 'tween', 57 | amd: 'tween', 58 | root: 'TWEEN', 59 | }, 60 | 'dat.gui': 'dat', 61 | }, 62 | resolve: { 63 | extensions: ['.js'] 64 | }, 65 | devServer: { 66 | contentBase: [path.resolve(path.join(__dirname, 'public'))], 67 | host: '0.0.0.0', 68 | disableHostCheck: true 69 | }, 70 | plugins: [ 71 | ...data.html 72 | ] 73 | }; 74 | -------------------------------------------------------------------------------- /src/ThreeApp.js: -------------------------------------------------------------------------------- 1 | import { WebGLRenderer, PerspectiveCamera, Scene } from 'three'; 2 | import Stats from 'stats.js'; 3 | 4 | export default class App { 5 | constructor() { 6 | 7 | if (window.location.search) { 8 | const params = window.location.search.substr(1).split('&'); 9 | for (let param of params) { 10 | let [prop, value] = param.split('='); 11 | if (prop === 'debug') { 12 | this.stats = new Stats(); 13 | this.stats.showPanel(0); 14 | document.body.appendChild(this.stats.dom); 15 | } 16 | } 17 | } 18 | this.renderer = new WebGLRenderer(); 19 | this.renderer.setPixelRatio(window.devicePixelRatio); 20 | this.renderer.setSize(window.innerWidth, window.innerHeight); 21 | this.renderer.autoClear = false; 22 | document.body.appendChild(this.renderer.domElement); 23 | 24 | this.scene = new Scene(); 25 | 26 | this.camera = new PerspectiveCamera(60, this.getAspect(), 0.1, 100); 27 | 28 | this.onResize = this.onResize.bind(this); 29 | window.addEventListener('resize', this.onResize); 30 | 31 | this.init(); 32 | 33 | this.lastTick = 0; 34 | this.onTick = this.onTick.bind(this); 35 | requestAnimationFrame(this.onTick); 36 | } 37 | 38 | onTick() { 39 | const t = performance.now(); 40 | const delta = performance.now() - this.lastTick; 41 | if (this.stats) { 42 | this.stats.begin(); 43 | } 44 | this.update(t, delta); 45 | this.render(t, delta); 46 | if (this.stats) { 47 | this.stats.end(); 48 | } 49 | this.lastTick = t; 50 | requestAnimationFrame(this.onTick); 51 | } 52 | 53 | getAspect() { 54 | return window.innerWidth / window.innerHeight; 55 | } 56 | 57 | onResize() { 58 | this.camera.aspect = this.getAspect(); 59 | this.camera.updateProjectionMatrix(); 60 | this.renderer.setSize(window.innerWidth, window.innerHeight); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/002/index.js: -------------------------------------------------------------------------------- 1 | import { EllipseCurve, SplineCurve, Color, LineBasicMaterial, Line, Path, AdditiveBlending, Object3D } from 'three'; 2 | import ThreeApp from '../ThreeApp'; 3 | import WAGNER from '@alex_toudic/wagner'; 4 | import BloomPass from '@alex_toudic/wagner/src/passes/bloom/MultiPassBloomPass'; 5 | 6 | const count = 400; 7 | const points = 100; 8 | class Experiment extends ThreeApp { 9 | init() { 10 | this.renderer.setClearColor(0x111111); 11 | this.curves = []; 12 | 13 | for (let i = 0; i < count; i++) { 14 | const curve = new EllipseCurve(0, 0, 2, 2, 0, 2 * Math.PI, false, 0); 15 | const path = new Path(curve.getPoints(points)); 16 | const geo = path.createPointsGeometry(points); 17 | const c = (i / count) * 360 / 1.9; 18 | const mat = new LineBasicMaterial({ 19 | color: new Color(`hsl(${c}, 100%, 50%)`), 20 | transparent: true, 21 | depthWrite: false, 22 | blending: AdditiveBlending, 23 | opacity: 0.4, 24 | }); 25 | const line = new Line(geo, mat); 26 | this.curves.push(line); 27 | this.scene.add(line); 28 | } 29 | 30 | this.camera.position.set(0, 0, 5); 31 | 32 | this.pivot = new Object3D(); 33 | this.pivot.add(this.camera); 34 | this.scene.add(this.pivot); 35 | 36 | this.composer = new WAGNER.Composer(this.renderer); 37 | this.pass = new BloomPass({ 38 | zoomBlurStrength: 0.05, 39 | applyZoomBlur: true, 40 | blurAmount: 0.2, 41 | }); 42 | } 43 | 44 | update(t, delta) { 45 | for (let i = 0; i < count; i++) { 46 | const curve = this.curves[i]; 47 | const pct = i / count; 48 | const scale = ((Math.sin(t * 0.0001 + (pct*Math.PI*2)) + 1) / 2); 49 | curve.scale.set(scale, scale, scale); 50 | curve.rotation.z = t * 0.00001 + (pct*2); 51 | curve.rotation.y = t * 0.001 + (pct*Math.PI*2); 52 | curve.rotation.x = (t * 0.001 + (pct*Math.PI*2)) + Math.PI/2; 53 | } 54 | this.pivot.rotation.y = -t * 0.001; 55 | } 56 | 57 | render() { 58 | this.renderer.clearColor(); 59 | this.composer.reset(); 60 | this.composer.render(this.scene, this.camera); 61 | this.composer.pass(this.pass); 62 | this.composer.toScreen(); 63 | } 64 | } 65 | 66 | export default new Experiment(); 67 | -------------------------------------------------------------------------------- /public/scripts/tween.min.js: -------------------------------------------------------------------------------- 1 | var TWEEN=TWEEN||function(){var n=[];return{getAll:function(){return n},removeAll:function(){n=[]},add:function(t){n.push(t)},remove:function(t){var r=n.indexOf(t);-1!==r&&n.splice(r,1)},update:function(t,r){if(0===n.length)return!1;var i=0;for(t=void 0!==t?t:TWEEN.now();in;n++)p[n].stop()},this.delay=function(n){return s=n,this},this.repeat=function(n){return e=n,this},this.yoyo=function(n){return a=n,this},this.easing=function(n){return l=n,this},this.interpolation=function(n){return E=n,this},this.chain=function(){return p=arguments,this},this.onStart=function(n){return d=n,this},this.onUpdate=function(n){return w=n,this},this.onComplete=function(n){return I=n,this},this.onStop=function(n){return M=n,this},this.update=function(n){var f,M,T;if(h>n)return!0;v===!1&&(null!==d&&d.call(t),v=!0),M=(n-h)/u,M=M>1?1:M,T=l(M);for(f in i)if(void 0!==r[f]){var N=r[f]||0,W=i[f];W instanceof Array?t[f]=E(W,T):("string"==typeof W&&(W="+"===W.charAt(0)||"-"===W.charAt(0)?N+parseFloat(W,10):parseFloat(W,10)),"number"==typeof W&&(t[f]=N+(W-N)*T))}if(null!==w&&w.call(t,T),1===M){if(e>0){isFinite(e)&&e--;for(f in o){if("string"==typeof i[f]&&(o[f]=o[f]+parseFloat(i[f],10)),a){var O=o[f];o[f]=i[f],i[f]=O}r[f]=o[f]}return a&&(c=!c),h=n+s,!0}null!==I&&I.call(t);for(var m=0,g=p.length;g>m;m++)p[m].start(h+u);return!1}return!0}},TWEEN.Easing={Linear:{None:function(n){return n}},Quadratic:{In:function(n){return n*n},Out:function(n){return n*(2-n)},InOut:function(n){return(n*=2)<1?.5*n*n:-.5*(--n*(n-2)-1)}},Cubic:{In:function(n){return n*n*n},Out:function(n){return--n*n*n+1},InOut:function(n){return(n*=2)<1?.5*n*n*n:.5*((n-=2)*n*n+2)}},Quartic:{In:function(n){return n*n*n*n},Out:function(n){return 1- --n*n*n*n},InOut:function(n){return(n*=2)<1?.5*n*n*n*n:-.5*((n-=2)*n*n*n-2)}},Quintic:{In:function(n){return n*n*n*n*n},Out:function(n){return--n*n*n*n*n+1},InOut:function(n){return(n*=2)<1?.5*n*n*n*n*n:.5*((n-=2)*n*n*n*n+2)}},Sinusoidal:{In:function(n){return 1-Math.cos(n*Math.PI/2)},Out:function(n){return Math.sin(n*Math.PI/2)},InOut:function(n){return.5*(1-Math.cos(Math.PI*n))}},Exponential:{In:function(n){return 0===n?0:Math.pow(1024,n-1)},Out:function(n){return 1===n?1:1-Math.pow(2,-10*n)},InOut:function(n){return 0===n?0:1===n?1:(n*=2)<1?.5*Math.pow(1024,n-1):.5*(-Math.pow(2,-10*(n-1))+2)}},Circular:{In:function(n){return 1-Math.sqrt(1-n*n)},Out:function(n){return Math.sqrt(1- --n*n)},InOut:function(n){return(n*=2)<1?-.5*(Math.sqrt(1-n*n)-1):.5*(Math.sqrt(1-(n-=2)*n)+1)}},Elastic:{In:function(n){return 0===n?0:1===n?1:-Math.pow(2,10*(n-1))*Math.sin(5*(n-1.1)*Math.PI)},Out:function(n){return 0===n?0:1===n?1:Math.pow(2,-10*n)*Math.sin(5*(n-.1)*Math.PI)+1},InOut:function(n){return 0===n?0:1===n?1:(n*=2,1>n?-.5*Math.pow(2,10*(n-1))*Math.sin(5*(n-1.1)*Math.PI):.5*Math.pow(2,-10*(n-1))*Math.sin(5*(n-1.1)*Math.PI)+1)}},Back:{In:function(n){var t=1.70158;return n*n*((t+1)*n-t)},Out:function(n){var t=1.70158;return--n*n*((t+1)*n+t)+1},InOut:function(n){var t=2.5949095;return(n*=2)<1?.5*(n*n*((t+1)*n-t)):.5*((n-=2)*n*((t+1)*n+t)+2)}},Bounce:{In:function(n){return 1-TWEEN.Easing.Bounce.Out(1-n)},Out:function(n){return 1/2.75>n?7.5625*n*n:2/2.75>n?7.5625*(n-=1.5/2.75)*n+.75:2.5/2.75>n?7.5625*(n-=2.25/2.75)*n+.9375:7.5625*(n-=2.625/2.75)*n+.984375},InOut:function(n){return.5>n?.5*TWEEN.Easing.Bounce.In(2*n):.5*TWEEN.Easing.Bounce.Out(2*n-1)+.5}}},TWEEN.Interpolation={Linear:function(n,t){var r=n.length-1,i=r*t,o=Math.floor(i),u=TWEEN.Interpolation.Utils.Linear;return 0>t?u(n[0],n[1],i):t>1?u(n[r],n[r-1],r-i):u(n[o],n[o+1>r?r:o+1],i-o)},Bezier:function(n,t){for(var r=0,i=n.length-1,o=Math.pow,u=TWEEN.Interpolation.Utils.Bernstein,e=0;i>=e;e++)r+=o(1-t,i-e)*o(t,e)*n[e]*u(i,e);return r},CatmullRom:function(n,t){var r=n.length-1,i=r*t,o=Math.floor(i),u=TWEEN.Interpolation.Utils.CatmullRom;return n[0]===n[r]?(0>t&&(o=Math.floor(i=r*(1+t))),u(n[(o-1+r)%r],n[o],n[(o+1)%r],n[(o+2)%r],i-o)):0>t?n[0]-(u(n[0],n[0],n[1],n[1],-i)-n[0]):t>1?n[r]-(u(n[r],n[r],n[r-1],n[r-1],i-r)-n[r]):u(n[o?o-1:0],n[o],n[o+1>r?r:o+1],n[o+2>r?r:o+2],i-o)},Utils:{Linear:function(n,t,r){return(t-n)*r+n},Bernstein:function(n,t){var r=TWEEN.Interpolation.Utils.Factorial;return r(n)/r(t)/r(n-t)},Factorial:function(){var n=[1];return function(t){var r=1;if(n[t])return n[t];for(var i=t;i>1;i--)r*=i;return n[t]=r,r}}(),CatmullRom:function(n,t,r,i,o){var u=.5*(r-n),e=.5*(i-t),a=o*o,f=o*a;return(2*t-2*r+u+e)*f+(-3*t+3*r-2*u-e)*a+u*o+t}}},function(n){"function"==typeof define&&define.amd?define([],function(){return TWEEN}):"undefined"!=typeof module&&"object"==typeof exports?module.exports=TWEEN:void 0!==n&&(n.TWEEN=TWEEN)}(this); 2 | //# sourceMappingURL=Tween.min.js.map -------------------------------------------------------------------------------- /src/003/index.js: -------------------------------------------------------------------------------- 1 | import { Vector3, Color, Mesh, ShaderMaterial, MeshBasicMaterial, BoxGeometry, AdditiveBlending, Object3D } from 'three'; 2 | import { Tween, Easing, update as tweenUpdate } from 'tween'; 3 | import ThreeApp from '../ThreeApp'; 4 | import fragmentShader from './frag.glsl'; 5 | import vertexShader from './vert.glsl'; 6 | import WAGNER from '@alex_toudic/wagner'; 7 | import VignettePass from '@alex_toudic/wagner/src/passes/vignette/VignettePass'; 8 | 9 | const ROTATION_DELAY = 100; 10 | const ROTATION_SPEED = 800; 11 | const DIMENSIONS = 3; 12 | const CUBE_SCALE = 1.0; 13 | const CUBE_DISTANCE_SCALE = 1.0; 14 | const EASING = Easing.Back.Out; 15 | const BG_COLOR = 0x333333; 16 | 17 | // Randomly return val1 or val2 18 | const or = (val1, val2) => Math.random() > 0.5 ? val1 : val2; 19 | // Pass in an axis ('x', 'y', 'z') and return a different axis 20 | const getDifferentAxis = axis => axis === 'x' ? or('y', 'z') : 21 | axis === 'y' ? or('x', 'z') : or('y', 'x'); 22 | const getRandomAxis = () => ['x', 'y', 'z'][Math.floor(Math.random() * 3)]; 23 | 24 | class Experiment extends ThreeApp { 25 | init() { 26 | this.renderer.setClearColor(BG_COLOR); 27 | this.curves = []; 28 | 29 | this.cubeGroup = new Object3D(); 30 | this.rotationHelper = new Object3D(); 31 | this.cubeGroup.add(this.rotationHelper); 32 | this.scene.add(this.cubeGroup); 33 | this.material = new ShaderMaterial({ 34 | vertexShader, 35 | fragmentShader, 36 | uniforms: { 37 | fgColor: { value: new Color(0xffffff) }, 38 | bgColor: { value: new Color(BG_COLOR) }, 39 | }, 40 | }); 41 | 42 | this.createCubes(); 43 | 44 | this.pivot = new Object3D(); 45 | this.scene.add(this.pivot); 46 | this.camera.lookAt(new Vector3()); 47 | this.pivot.add(this.camera); 48 | this.camera.position.set(4, 4, 4); 49 | 50 | this.lastRotation = 0; 51 | this.composer = new WAGNER.Composer(this.renderer); 52 | this.pass = new VignettePass(0.9, 1.0); 53 | } 54 | 55 | createCubes() { 56 | this.cubes = []; 57 | 58 | /** 59 | * Store cubes in plane, row, columns, below 60 | * is a face 61 | * 62 | * z,y,x 63 | * 64 | * 0,0,0 0,0,1 0,0,2 65 | * 0,1,0 0,1,1 0,1,2 66 | * 0,2,0 0,2,1 0,2,2 67 | * 68 | */ 69 | const solid = this.material; 70 | const transparent = new MeshBasicMaterial({ opacity: 0, transparent: true }); 71 | const last = DIMENSIONS - 1; 72 | for (let z = 0; z < DIMENSIONS; z++) { 73 | const plane = this.cubes[z] = []; 74 | for (let y = 0; y < DIMENSIONS; y++) { 75 | const row = plane[y] = []; 76 | for (let x = 0; x < DIMENSIONS; x++) { 77 | let cube = new Mesh(new BoxGeometry(CUBE_SCALE, CUBE_SCALE, CUBE_SCALE), [ 78 | x === last ? solid : transparent, // bot right 79 | x === 0 ? solid : transparent, // back left 80 | y === last ? solid : transparent, // top 81 | y === 0 ? solid : transparent, // bottom 82 | z === last ? solid : transparent, // bot left 83 | z === 0 ? solid : transparent, // back right 84 | ]); 85 | row[x] = cube; 86 | this.cubeGroup.add(cube); 87 | 88 | const half = DIMENSIONS % 2 === 0 ? (DIMENSIONS / 2) -0.5 : Math.floor(DIMENSIONS / 2); 89 | cube.position.set( 90 | ((x ) - half) * CUBE_DISTANCE_SCALE, 91 | ((y ) - half) * CUBE_DISTANCE_SCALE, 92 | ((z ) - half) * CUBE_DISTANCE_SCALE 93 | ); 94 | } 95 | } 96 | } 97 | } 98 | 99 | getCubesBySlice(axis, index) { 100 | // I'm sure there's a better way for this 101 | const cubes = []; 102 | for (let z = 0; z < DIMENSIONS; z++) { 103 | for (let y = 0; y < DIMENSIONS; y++) { 104 | for (let x = 0; x < DIMENSIONS; x++) { 105 | const r = axis === 'z' ? z : 106 | axis === 'y' ? y : x; 107 | if (r === index) { 108 | const cube = this.cubes[z][y][x]; 109 | cubes.push(cube); 110 | } 111 | } 112 | } 113 | } 114 | return cubes; 115 | } 116 | 117 | rotateCubes(axis, index, dir) { 118 | const cubes = this.getCubesBySlice(axis, index); 119 | for (let cube of cubes) { 120 | this.cubeGroup.remove(cube); 121 | this.rotationHelper.add(cube); 122 | } 123 | 124 | this.cubeTween = this.rotate(this.rotationHelper, axis, dir); 125 | this.cubeTween.onComplete(() => { 126 | cubes.forEach(c => { 127 | this.cubeGroup.add(c); 128 | this.rotationHelper.remove(c); 129 | }); 130 | this.rotationHelper.rotation.set(0, 0, 0); 131 | this.cubeTween = null; 132 | }); 133 | } 134 | 135 | rotate(object, axis, dir, easing) { 136 | const startRotation = object.rotation[axis]; 137 | 138 | return new Tween({ x: 0 }) 139 | .to({ x: 1 }, ROTATION_SPEED) 140 | .onUpdate(value => { 141 | object.rotation[axis] = startRotation + (value * Math.PI / 2 * dir); 142 | }) 143 | .easing(easing || EASING) 144 | .start(); 145 | } 146 | 147 | update(t, delta) { 148 | if (this.lastRotation + ROTATION_SPEED + ROTATION_DELAY < t && 149 | !this.camTween && !this.cubeTween) { 150 | const index = Math.floor(Math.random() * 3); 151 | const axis = getRandomAxis(); 152 | const dir = or(-1, 1); 153 | // Rotate a slice of cubes on `axis` at `index` 154 | this.rotateCubes(axis, index, dir); 155 | // Also rotate the camera randomly on a different access 156 | this.camTween = this.rotate(this.pivot, getRandomAxis(), dir * -1, Easing.Cubic.Out); 157 | this.camTween.onComplete(() => this.camTween = null); 158 | 159 | this.lastRotation = t; 160 | } 161 | this.camera.lookAt(new Vector3()); 162 | this.camera.updateMatrixWorld(); 163 | 164 | tweenUpdate(); 165 | } 166 | 167 | render() { 168 | this.renderer.clearColor(); 169 | this.composer.reset(); 170 | this.composer.render(this.scene, this.camera); 171 | this.composer.pass(this.pass); 172 | this.composer.toScreen(); 173 | } 174 | } 175 | 176 | export default new Experiment(); 177 | -------------------------------------------------------------------------------- /src/001/index.js: -------------------------------------------------------------------------------- 1 | import { SphereBufferGeometry, TextureLoader, AdditiveBlending, BufferAttribute, Points, Mesh, Object3D, ShaderMaterial, BoxBufferGeometry } from 'three'; 2 | import ThreeApp from '../ThreeApp'; 3 | import GPUComputationRenderer from '../lib/GPUComputationRenderer'; 4 | import vertexShader from './vert.glsl'; 5 | import fragmentShader from './frag.glsl'; 6 | import computePositionShader from './compute-position.glsl'; 7 | import computeVelocityShader from './compute-velocity.glsl'; 8 | import WAGNER from '@alex_toudic/wagner'; 9 | import BloomPass from '@alex_toudic/wagner/src/passes/bloom/MultiPassBloomPass'; 10 | 11 | const scale = 1000; 12 | const size = 1; 13 | class Experiment extends ThreeApp { 14 | init() { 15 | this.renderer.setClearColor(0x111111); 16 | this.material = new ShaderMaterial({ 17 | uniforms: { 18 | size: { value: size }, 19 | time: { value: 0.0 }, 20 | tPosition: { value: null }, 21 | tVelocity: { value: null }, 22 | sprite: { value: null }, 23 | }, 24 | fragmentShader, 25 | vertexShader, 26 | transparent: true, 27 | depthWrite: false, 28 | }); 29 | this.material.blending = AdditiveBlending; 30 | this.textureLoader = new TextureLoader(); 31 | this.textureLoader.load('particle.png', texture => { 32 | this.material.uniforms.sprite.value = texture; 33 | }); 34 | 35 | this.setupGeometry(); 36 | 37 | this.mesh = new Points(this.geometry, this.material); 38 | this.mesh.position.set(0, 0, 0); 39 | 40 | this.setupGPURenderer(); 41 | 42 | this.pivot = new Object3D(); 43 | this.pivot.add(this.camera); 44 | this.scene.add(this.mesh); 45 | this.scene.add(this.pivot); 46 | this.camera.position.set(0, 0, 4); 47 | 48 | this.composer = new WAGNER.Composer(this.renderer); 49 | this.pass = new BloomPass({ 50 | zoomBlurStrength: 0.5, 51 | applyZoomBlur: true, 52 | blurAmount: 5, 53 | }); 54 | } 55 | 56 | getTextureSize() { 57 | const count = this.geometry.getAttribute('position').count; 58 | 59 | let size = 2; 60 | while (size < Math.sqrt(count)) { 61 | size *= 2; 62 | } 63 | 64 | return size; 65 | } 66 | 67 | setupGeometry() { 68 | this.geometry = new SphereBufferGeometry(3,scale, scale); 69 | 70 | const verticesCount = this.geometry.getAttribute('position').count; 71 | console.log('Particle count: ', verticesCount); 72 | const width = this.getTextureSize(); 73 | const uvs = new Float32Array(verticesCount * 2); 74 | let count = 0; 75 | 76 | for (let i = 0; i < width; i++) { 77 | for (let j = 0; j < width; j++) { 78 | uvs[count++] = i / (width - 1); 79 | uvs[count++] = j / (width - 1); 80 | 81 | if (count === verticesCount * 2) { 82 | break; 83 | } 84 | } 85 | if (count === verticesCount * 2) { 86 | break; 87 | } 88 | } 89 | this.geometry.addAttribute('uv', new BufferAttribute(uvs, 2)); 90 | } 91 | 92 | setupGPURenderer() { 93 | const textureSize = this.getTextureSize(); 94 | this.gpu = new GPUComputationRenderer(textureSize, textureSize, this.renderer); 95 | 96 | this.velTexture = this.gpu.createTexture(); 97 | this.posTexture = this.gpu.createTexture(); 98 | 99 | this.seedTextures(); 100 | 101 | this.velVar = this.gpu.addVariable('tVelocity', computeVelocityShader, this.velTexture); 102 | this.posVar = this.gpu.addVariable('tPosition', computePositionShader, this.posTexture); 103 | this.gpu.setVariableDependencies(this.velVar, [this.velVar, this.posVar]); 104 | this.gpu.setVariableDependencies(this.posVar, [this.velVar, this.posVar]); 105 | this.velVar.material.uniforms.time = { value: 0.0 }; 106 | this.posVar.material.uniforms.delta = { value: 0.0 }; 107 | 108 | const error = this.gpu.init(); 109 | if (error) { 110 | throw new Error(error); 111 | } 112 | } 113 | 114 | seedTextures() { 115 | const positionData = this.posTexture.image.data; 116 | const velocityData = this.velTexture.image.data; 117 | 118 | // Use BoxBufferGeometry's position to start in 119 | // the texture 120 | let posCount = 0; 121 | let geoPos = this.geometry.getAttribute('position'); 122 | 123 | for (let i = 0; i < positionData.length; i += 4) { 124 | if (i / 4 >= geoPos.count) { 125 | positionData[i] = positionData[i + 1] = positionData[i + 2] = positionData[i + 3] = 0; 126 | velocityData[i] = velocityData[i + 1] = velocityData[i + 2] = velocityData[i + 3] = 0; 127 | } else { 128 | /* 129 | // Initial position from buffer geometry 130 | positionData[i] = geoPos.array[posCount++]; 131 | positionData[i + 1] = geoPos.array[posCount++]; 132 | positionData[i + 2] = geoPos.array[posCount++]; 133 | positionData[i + 3] = 1; 134 | */ 135 | 136 | let theta = Math.random() * Math.PI * 2; 137 | let phi = (Math.random() * Math.PI) - (Math.PI/2); 138 | let r = Math.random() * 1.5; 139 | positionData[i] = r * Math.cos(theta) * Math.cos(phi); 140 | positionData[i + 1] = r * Math.sin(phi); 141 | positionData[i + 2] = r * Math.sin(theta) * Math.cos(phi); 142 | positionData[i + 3] = 1; 143 | 144 | velocityData[i] = Math.random()*2 - 1; 145 | velocityData[i + 1] = Math.random()*2 - 1; 146 | velocityData[i + 2] = Math.random()*2-1; 147 | velocityData[i + 3] = 1; 148 | } 149 | } 150 | } 151 | 152 | update(t, delta) { 153 | this.pivot.rotation.y = t * 0.0001; 154 | this.material.uniforms.time.value = t; 155 | this.velVar.material.uniforms.time.value = t; 156 | this.posVar.material.uniforms.delta.value = delta / 1000; 157 | } 158 | 159 | render() { 160 | this.renderer.clearColor(); 161 | this.gpu.compute(); 162 | this.material.uniforms.tPosition.value = this.gpu.getCurrentRenderTarget(this.posVar).texture; 163 | this.material.uniforms.tVelocity.value = this.gpu.getCurrentRenderTarget(this.velVar).texture; 164 | this.composer.reset(); 165 | this.composer.render(this.scene, this.camera); 166 | this.composer.pass(this.pass); 167 | this.composer.toScreen(); 168 | // this.renderer.render(this.scene, this.camera); 169 | } 170 | } 171 | 172 | export default new Experiment(); 173 | -------------------------------------------------------------------------------- /src/lib/GPUComputationRenderer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author yomboprime https://github.com/yomboprime 3 | * 4 | * GPUComputationRenderer, based on SimulationRenderer by zz85 5 | * 6 | * The GPUComputationRenderer uses the concept of variables. These variables are RGBA float textures that hold 4 floats 7 | * for each compute element (texel) 8 | * 9 | * Each variable has a fragment shader that defines the computation made to obtain the variable in question. 10 | * You can use as many variables you need, and make dependencies so you can use textures of other variables in the shader 11 | * (the sampler uniforms are added automatically) Most of the variables will need themselves as dependency. 12 | * 13 | * The renderer has actually two render targets per variable, to make ping-pong. Textures from the current frame are used 14 | * as inputs to render the textures of the next frame. 15 | * 16 | * The render targets of the variables can be used as input textures for your visualization shaders. 17 | * 18 | * Variable names should be valid identifiers and should not collide with THREE GLSL used identifiers. 19 | * a common approach could be to use 'texture' prefixing the variable name; i.e texturePosition, textureVelocity... 20 | * 21 | * The size of the computation (sizeX * sizeY) is defined as 'resolution' automatically in the shader. For example: 22 | * #DEFINE resolution vec2( 1024.0, 1024.0 ) 23 | * 24 | * ------------- 25 | * 26 | * Basic use: 27 | * 28 | * // Initialization... 29 | * 30 | * // Create computation renderer 31 | * var gpuCompute = new GPUComputationRenderer( 1024, 1024, renderer ); 32 | * 33 | * // Create initial state float textures 34 | * var pos0 = gpuCompute.createTexture(); 35 | * var vel0 = gpuCompute.createTexture(); 36 | * // and fill in here the texture data... 37 | * 38 | * // Add texture variables 39 | * var velVar = gpuCompute.addVariable( "textureVelocity", fragmentShaderVel, pos0 ); 40 | * var posVar = gpuCompute.addVariable( "texturePosition", fragmentShaderPos, vel0 ); 41 | * 42 | * // Add variable dependencies 43 | * gpuCompute.setVariableDependencies( velVar, [ velVar, posVar ] ); 44 | * gpuCompute.setVariableDependencies( posVar, [ velVar, posVar ] ); 45 | * 46 | * // Add custom uniforms 47 | * velVar.material.uniforms.time = { value: 0.0 }; 48 | * 49 | * // Check for completeness 50 | * var error = gpuCompute.init(); 51 | * if ( error !== null ) { 52 | * console.error( error ); 53 | * } 54 | * 55 | * 56 | * // In each frame... 57 | * 58 | * // Compute! 59 | * gpuCompute.compute(); 60 | * 61 | * // Update texture uniforms in your visualization materials with the gpu renderer output 62 | * myMaterial.uniforms.myTexture.value = gpuCompute.getCurrentRenderTarget( posVar ).texture; 63 | * 64 | * // Do your rendering 65 | * renderer.render( myScene, myCamera ); 66 | * 67 | * ------------- 68 | * 69 | * Also, you can use utility functions to create ShaderMaterial and perform computations (rendering between textures) 70 | * Note that the shaders can have multiple input textures. 71 | * 72 | * var myFilter1 = gpuCompute.createShaderMaterial( myFilterFragmentShader1, { theTexture: { value: null } } ); 73 | * var myFilter2 = gpuCompute.createShaderMaterial( myFilterFragmentShader2, { theTexture: { value: null } } ); 74 | * 75 | * var inputTexture = gpuCompute.createTexture(); 76 | * 77 | * // Fill in here inputTexture... 78 | * 79 | * myFilter1.uniforms.theTexture.value = inputTexture; 80 | * 81 | * var myRenderTarget = gpuCompute.createRenderTarget(); 82 | * myFilter2.uniforms.theTexture.value = myRenderTarget.texture; 83 | * 84 | * var outputRenderTarget = gpuCompute.createRenderTarget(); 85 | * 86 | * // Now use the output texture where you want: 87 | * myMaterial.uniforms.map.value = outputRenderTarget.texture; 88 | * 89 | * // And compute each frame, before rendering to screen: 90 | * gpuCompute.doRenderTarget( myFilter1, myRenderTarget ); 91 | * gpuCompute.doRenderTarget( myFilter2, outputRenderTarget ); 92 | * 93 | * 94 | * 95 | * @param {int} sizeX Computation problem size is always 2d: sizeX * sizeY elements. 96 | * @param {int} sizeY Computation problem size is always 2d: sizeX * sizeY elements. 97 | * @param {WebGLRenderer} renderer The renderer 98 | */ 99 | 100 | export default function GPUComputationRenderer( sizeX, sizeY, renderer ) { 101 | 102 | this.variables = []; 103 | 104 | this.currentTextureIndex = 0; 105 | 106 | var scene = new THREE.Scene(); 107 | 108 | var camera = new THREE.Camera(); 109 | camera.position.z = 1; 110 | 111 | var passThruUniforms = { 112 | texture: { value: null } 113 | }; 114 | 115 | var passThruShader = createShaderMaterial( getPassThroughFragmentShader(), passThruUniforms ); 116 | 117 | var mesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), passThruShader ); 118 | scene.add( mesh ); 119 | 120 | 121 | this.addVariable = function( variableName, computeFragmentShader, initialValueTexture ) { 122 | 123 | var material = this.createShaderMaterial( computeFragmentShader ); 124 | 125 | var variable = { 126 | name: variableName, 127 | initialValueTexture: initialValueTexture, 128 | material: material, 129 | dependencies: null, 130 | renderTargets: [], 131 | wrapS: null, 132 | wrapT: null, 133 | minFilter: THREE.NearestFilter, 134 | magFilter: THREE.NearestFilter 135 | }; 136 | 137 | this.variables.push( variable ); 138 | 139 | return variable; 140 | 141 | }; 142 | 143 | this.setVariableDependencies = function( variable, dependencies ) { 144 | 145 | variable.dependencies = dependencies; 146 | 147 | }; 148 | 149 | this.init = function() { 150 | 151 | if ( ! renderer.extensions.get( "OES_texture_float" ) ) { 152 | 153 | return "No OES_texture_float support for float textures."; 154 | 155 | } 156 | 157 | if ( renderer.capabilities.maxVertexTextures === 0 ) { 158 | 159 | return "No support for vertex shader textures."; 160 | 161 | } 162 | 163 | for ( var i = 0; i < this.variables.length; i++ ) { 164 | 165 | var variable = this.variables[ i ]; 166 | 167 | // Creates rendertargets and initialize them with input texture 168 | variable.renderTargets[ 0 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter ); 169 | variable.renderTargets[ 1 ] = this.createRenderTarget( sizeX, sizeY, variable.wrapS, variable.wrapT, variable.minFilter, variable.magFilter ); 170 | this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 0 ] ); 171 | this.renderTexture( variable.initialValueTexture, variable.renderTargets[ 1 ] ); 172 | 173 | // Adds dependencies uniforms to the ShaderMaterial 174 | var material = variable.material; 175 | var uniforms = material.uniforms; 176 | if ( variable.dependencies !== null ) { 177 | 178 | for ( var d = 0; d < variable.dependencies.length; d++ ) { 179 | 180 | var depVar = variable.dependencies[ d ]; 181 | 182 | if ( depVar.name !== variable.name ) { 183 | 184 | // Checks if variable exists 185 | var found = false; 186 | for ( var j = 0; j < this.variables.length; j++ ) { 187 | 188 | if ( depVar.name === this.variables[ j ].name ) { 189 | found = true; 190 | break; 191 | } 192 | 193 | } 194 | if ( ! found ) { 195 | return "Variable dependency not found. Variable=" + variable.name + ", dependency=" + depVar.name; 196 | } 197 | 198 | } 199 | 200 | uniforms[ depVar.name ] = { value: null }; 201 | 202 | material.fragmentShader = "\nuniform sampler2D " + depVar.name + ";\n" + material.fragmentShader; 203 | 204 | } 205 | } 206 | } 207 | 208 | this.currentTextureIndex = 0; 209 | 210 | return null; 211 | 212 | }; 213 | 214 | this.compute = function() { 215 | 216 | var currentTextureIndex = this.currentTextureIndex; 217 | var nextTextureIndex = this.currentTextureIndex === 0 ? 1 : 0; 218 | 219 | for ( var i = 0, il = this.variables.length; i < il; i++ ) { 220 | 221 | var variable = this.variables[ i ]; 222 | 223 | // Sets texture dependencies uniforms 224 | if ( variable.dependencies !== null ) { 225 | 226 | var uniforms = variable.material.uniforms; 227 | for ( var d = 0, dl = variable.dependencies.length; d < dl; d++ ) { 228 | 229 | var depVar = variable.dependencies[ d ]; 230 | 231 | uniforms[ depVar.name ].value = depVar.renderTargets[ currentTextureIndex ].texture; 232 | 233 | } 234 | 235 | } 236 | 237 | // Performs the computation for this variable 238 | this.doRenderTarget( variable.material, variable.renderTargets[ nextTextureIndex ] ); 239 | 240 | } 241 | 242 | this.currentTextureIndex = nextTextureIndex; 243 | }; 244 | 245 | this.getCurrentRenderTarget = function( variable ) { 246 | 247 | return variable.renderTargets[ this.currentTextureIndex ]; 248 | 249 | }; 250 | 251 | this.getAlternateRenderTarget = function( variable ) { 252 | 253 | return variable.renderTargets[ this.currentTextureIndex === 0 ? 1 : 0 ]; 254 | 255 | }; 256 | 257 | function addResolutionDefine( materialShader ) { 258 | 259 | materialShader.defines.resolution = 'vec2( ' + sizeX.toFixed( 1 ) + ', ' + sizeY.toFixed( 1 ) + " )"; 260 | 261 | } 262 | this.addResolutionDefine = addResolutionDefine; 263 | 264 | 265 | // The following functions can be used to compute things manually 266 | 267 | function createShaderMaterial( computeFragmentShader, uniforms ) { 268 | 269 | uniforms = uniforms || {}; 270 | 271 | var material = new THREE.ShaderMaterial( { 272 | uniforms: uniforms, 273 | vertexShader: getPassThroughVertexShader(), 274 | fragmentShader: computeFragmentShader 275 | } ); 276 | 277 | addResolutionDefine( material ); 278 | 279 | return material; 280 | } 281 | this.createShaderMaterial = createShaderMaterial; 282 | 283 | this.createRenderTarget = function( sizeXTexture, sizeYTexture, wrapS, wrapT, minFilter, magFilter ) { 284 | 285 | sizeXTexture = sizeXTexture || sizeX; 286 | sizeYTexture = sizeYTexture || sizeY; 287 | 288 | wrapS = wrapS || THREE.ClampToEdgeWrapping; 289 | wrapT = wrapT || THREE.ClampToEdgeWrapping; 290 | 291 | minFilter = minFilter || THREE.NearestFilter; 292 | magFilter = magFilter || THREE.NearestFilter; 293 | 294 | var renderTarget = new THREE.WebGLRenderTarget( sizeXTexture, sizeYTexture, { 295 | wrapS: wrapS, 296 | wrapT: wrapT, 297 | minFilter: minFilter, 298 | magFilter: magFilter, 299 | format: THREE.RGBAFormat, 300 | type: ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) ? THREE.HalfFloatType : THREE.FloatType, 301 | stencilBuffer: false 302 | } ); 303 | 304 | return renderTarget; 305 | 306 | }; 307 | 308 | this.createTexture = function( sizeXTexture, sizeYTexture ) { 309 | 310 | sizeXTexture = sizeXTexture || sizeX; 311 | sizeYTexture = sizeYTexture || sizeY; 312 | 313 | var a = new Float32Array( sizeXTexture * sizeYTexture * 4 ); 314 | var texture = new THREE.DataTexture( a, sizeX, sizeY, THREE.RGBAFormat, THREE.FloatType ); 315 | texture.needsUpdate = true; 316 | 317 | return texture; 318 | 319 | }; 320 | 321 | 322 | this.renderTexture = function( input, output ) { 323 | 324 | // Takes a texture, and render out in rendertarget 325 | // input = Texture 326 | // output = RenderTarget 327 | 328 | passThruUniforms.texture.value = input; 329 | 330 | this.doRenderTarget( passThruShader, output); 331 | 332 | passThruUniforms.texture.value = null; 333 | 334 | }; 335 | 336 | this.doRenderTarget = function( material, output ) { 337 | 338 | mesh.material = material; 339 | renderer.render( scene, camera, output ); 340 | mesh.material = passThruShader; 341 | 342 | }; 343 | 344 | // Shaders 345 | 346 | function getPassThroughVertexShader() { 347 | 348 | return "void main() {\n" + 349 | "\n" + 350 | " gl_Position = vec4( position, 1.0 );\n" + 351 | "\n" + 352 | "}\n"; 353 | 354 | } 355 | 356 | function getPassThroughFragmentShader() { 357 | 358 | return "uniform sampler2D texture;\n" + 359 | "\n" + 360 | "void main() {\n" + 361 | "\n" + 362 | " vec2 uv = gl_FragCoord.xy / resolution.xy;\n" + 363 | "\n" + 364 | " gl_FragColor = texture2D( texture, uv );\n" + 365 | "\n" + 366 | "}\n"; 367 | 368 | } 369 | 370 | } 371 | -------------------------------------------------------------------------------- /public/003/bundle.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("three"), require("tween")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["three", "tween"], factory); 6 | else if(typeof exports === 'object') 7 | exports["app"] = factory(require("three"), require("tween")); 8 | else 9 | root["app"] = factory(root["THREE"], root["TWEEN"]); 10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_0__, __WEBPACK_EXTERNAL_MODULE_29__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 28); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, exports) { 79 | 80 | module.exports = __WEBPACK_EXTERNAL_MODULE_0__; 81 | 82 | /***/ }), 83 | /* 1 */ 84 | /***/ (function(module, exports, __webpack_require__) { 85 | 86 | "use strict"; 87 | 88 | 89 | var THREE = __webpack_require__(0); 90 | var processShader = __webpack_require__(8); 91 | 92 | function Pass() { 93 | this.shader = null; 94 | this.loaded = null; 95 | this.params = {}; 96 | this.isSim = false; 97 | } 98 | 99 | module.exports = Pass; 100 | 101 | Pass.prototype.setShader = function(vs, fs) { 102 | this.shader = processShader(vs, fs); 103 | }; 104 | 105 | Pass.prototype.run = function(composer) { 106 | composer.pass(this.shader); 107 | }; 108 | 109 | Pass.prototype.getOfflineTexture = function(w, h, useRGBA) { 110 | return new THREE.WebGLRenderTarget(w, h, { 111 | minFilter: THREE.LinearFilter, 112 | magFilter: THREE.LinearFilter, 113 | format: useRGBA ? THREE.RGBAFormat : THREE.RGBFormat 114 | }); 115 | }; 116 | 117 | 118 | /***/ }), 119 | /* 2 */ 120 | /***/ (function(module, exports) { 121 | 122 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\n\nvoid main() {\n\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n}" 123 | 124 | /***/ }), 125 | /* 3 */ 126 | /***/ (function(module, exports, __webpack_require__) { 127 | 128 | "use strict"; 129 | 130 | 131 | var Pass = __webpack_require__(1); 132 | var vertex = __webpack_require__(2); 133 | var fragment = __webpack_require__(9); 134 | 135 | function CopyPass() { 136 | Pass.call(this); 137 | this.setShader(vertex, fragment); 138 | } 139 | 140 | module.exports = CopyPass; 141 | 142 | CopyPass.prototype = Object.create(Pass.prototype); 143 | CopyPass.prototype.constructor = CopyPass; 144 | 145 | 146 | /***/ }), 147 | /* 4 */ 148 | /***/ (function(module, exports, __webpack_require__) { 149 | 150 | "use strict"; 151 | 152 | 153 | module.exports.Composer = __webpack_require__(5); 154 | module.exports.CopyPass = __webpack_require__(3); 155 | module.exports.BlendMode = { 156 | Normal: 1, 157 | Dissolve: 2, // UNAVAILABLE 158 | Darken: 3, 159 | Multiply: 4, 160 | ColorBurn: 5, 161 | LinearBurn: 6, 162 | DarkerColor: 7, // UNAVAILABLE 163 | Lighten: 8, 164 | Screen: 9, 165 | ColorDodge: 10, 166 | LinearDodge: 11, 167 | LighterColor: 12, // UNAVAILABLE 168 | Overlay: 13, 169 | SoftLight: 14, 170 | HardLight: 15, 171 | VividLight: 16, // UNAVAILABLE 172 | LinearLight: 17, 173 | PinLight: 18, // UNAVAILABLE 174 | HardMix: 19, // UNAVAILABLE 175 | Difference: 20, 176 | Exclusion: 21, 177 | Substract: 22, // UNAVAILABLE 178 | Divide: 23 // UNAVAILABLE 179 | }; 180 | 181 | 182 | /***/ }), 183 | /* 5 */ 184 | /***/ (function(module, exports, __webpack_require__) { 185 | 186 | "use strict"; 187 | 188 | 189 | var THREE = __webpack_require__(0); 190 | var CopyPass = __webpack_require__(3); 191 | var Stack = __webpack_require__(10); 192 | var Pass = __webpack_require__(1); 193 | 194 | function Composer(renderer, settings) { 195 | var pixelRatio = renderer.getPixelRatio(); 196 | 197 | this.width = Math.floor(renderer.context.canvas.width / pixelRatio) || 1; 198 | this.height = Math.floor(renderer.context.canvas.height / pixelRatio) || 1; 199 | 200 | this.output = null; 201 | this.input = null; 202 | this.read = null; 203 | this.write = null; 204 | 205 | this.settings = settings || {}; 206 | this.useRGBA = this.settings.useRGBA || false; 207 | 208 | this.renderer = renderer; 209 | this.copyPass = new CopyPass(this.settings); 210 | 211 | this.defaultMaterial = new THREE.MeshBasicMaterial({color: 0x00FF00, wireframe: false}); 212 | this.scene = new THREE.Scene(); 213 | this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1), this.defaultMaterial); 214 | this.scene.add(this.quad); 215 | this.camera = new THREE.OrthographicCamera(1, 1, 1, 1, -10000, 10000); 216 | 217 | this.front = new THREE.WebGLRenderTarget(1, 1, { 218 | minFilter: this.settings.minFilter !== undefined ? this.settings.minFilter : THREE.LinearFilter, 219 | magFilter: this.settings.magFilter !== undefined ? this.settings.magFilter : THREE.LinearFilter, 220 | wrapS: this.settings.wrapS !== undefined ? this.settings.wrapS : THREE.ClampToEdgeWrapping, 221 | wrapT: this.settings.wrapT !== undefined ? this.settings.wrapT : THREE.ClampToEdgeWrapping, 222 | format: this.useRGBA ? THREE.RGBAFormat : THREE.RGBFormat, 223 | type: this.settings.type !== undefined ? this.settings.type : THREE.UnsignedByteType, 224 | stencilBuffer: this.settings.stencilBuffer !== undefined ? this.settings.stencilBuffer : true 225 | }); 226 | 227 | this.back = this.front.clone(); 228 | this.startTime = Date.now(); 229 | this.passes = {}; 230 | 231 | this.setSize(this.width, this.height); 232 | } 233 | 234 | module.exports = Composer; 235 | 236 | Composer.prototype.swapBuffers = function() { 237 | this.output = this.write; 238 | this.input = this.read; 239 | 240 | var t = this.write; 241 | this.write = this.read; 242 | this.read = t; 243 | }; 244 | 245 | Composer.prototype.render = function(scene, camera, keep, output) { 246 | if (keep) this.swapBuffers(); 247 | this.renderer.render(scene, camera, output ? output : this.write, true); 248 | if (!output) this.swapBuffers(); 249 | }; 250 | 251 | Composer.prototype.toScreen = function() { 252 | this.quad.material = this.copyPass.shader; 253 | this.quad.material.uniforms.tInput.value = this.read; 254 | this.quad.material.uniforms.resolution.value.set(this.width, this.height); 255 | this.renderer.render(this.scene, this.camera); 256 | }; 257 | 258 | Composer.prototype.toTexture = function(t) { 259 | this.quad.material = this.copyPass.shader; 260 | this.quad.material.uniforms.tInput.value = this.read; 261 | this.renderer.render(this.scene, this.camera, t, false); 262 | }; 263 | 264 | Composer.prototype.pass = function(pass) { 265 | if (pass instanceof Stack) { 266 | this.passStack(pass); 267 | } 268 | else { 269 | if (pass instanceof THREE.ShaderMaterial) { 270 | this.quad.material = pass; 271 | } 272 | if (pass instanceof Pass) { 273 | pass.run(this); 274 | return; 275 | } 276 | 277 | if (!pass.isSim) { 278 | this.quad.material.uniforms.tInput.value = this.read; 279 | } 280 | 281 | this.quad.material.uniforms.resolution.value.set(this.width, this.height); 282 | this.quad.material.uniforms.time.value = 0.001 * (Date.now() - this.startTime); 283 | this.renderer.render(this.scene, this.camera, this.write, false); 284 | this.swapBuffers(); 285 | } 286 | }; 287 | 288 | Composer.prototype.passStack = function(stack) { 289 | stack.getPasses().forEach(function(pass) { 290 | this.pass(pass); 291 | }.bind(this)); 292 | }; 293 | 294 | Composer.prototype.reset = function() { 295 | this.read = this.front; 296 | this.write = this.back; 297 | this.output = this.write; 298 | this.input = this.read; 299 | }; 300 | 301 | Composer.prototype.setSource = function(src) { 302 | this.quad.material = this.copyPass.shader; 303 | this.quad.material.uniforms.tInput.value = src; 304 | this.renderer.render(this.scene, this.camera, this.write, true); 305 | this.swapBuffers(); 306 | }; 307 | 308 | Composer.prototype.setSize = function(w, h) { 309 | this.width = w; 310 | this.height = h; 311 | 312 | this.camera.projectionMatrix.makeOrthographic( w / - 2, w / 2, h / 2, h / - 2, this.camera.near, this.camera.far ); 313 | this.quad.scale.set( w, h, 1 ); 314 | 315 | this.front.setSize( w, h ); 316 | this.back.setSize( w, h ); 317 | }; 318 | 319 | 320 | 321 | /***/ }), 322 | /* 6 */ 323 | /***/ (function(module, exports, __webpack_require__) { 324 | 325 | "use strict"; 326 | 327 | 328 | Object.defineProperty(exports, "__esModule", { 329 | value: true 330 | }); 331 | 332 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 333 | 334 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 335 | 336 | var _three = __webpack_require__(0); 337 | 338 | var _stats = __webpack_require__(7); 339 | 340 | var _stats2 = _interopRequireDefault(_stats); 341 | 342 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 343 | 344 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 345 | 346 | var App = function () { 347 | function App() { 348 | _classCallCheck(this, App); 349 | 350 | if (window.location.search) { 351 | var params = window.location.search.substr(1).split('&'); 352 | var _iteratorNormalCompletion = true; 353 | var _didIteratorError = false; 354 | var _iteratorError = undefined; 355 | 356 | try { 357 | for (var _iterator = params[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 358 | var param = _step.value; 359 | 360 | var _param$split = param.split('='), 361 | _param$split2 = _slicedToArray(_param$split, 2), 362 | prop = _param$split2[0], 363 | value = _param$split2[1]; 364 | 365 | if (prop === 'debug') { 366 | this.stats = new _stats2.default(); 367 | this.stats.showPanel(0); 368 | document.body.appendChild(this.stats.dom); 369 | } 370 | } 371 | } catch (err) { 372 | _didIteratorError = true; 373 | _iteratorError = err; 374 | } finally { 375 | try { 376 | if (!_iteratorNormalCompletion && _iterator.return) { 377 | _iterator.return(); 378 | } 379 | } finally { 380 | if (_didIteratorError) { 381 | throw _iteratorError; 382 | } 383 | } 384 | } 385 | } 386 | this.renderer = new _three.WebGLRenderer(); 387 | this.renderer.setPixelRatio(window.devicePixelRatio); 388 | this.renderer.setSize(window.innerWidth, window.innerHeight); 389 | this.renderer.autoClear = false; 390 | document.body.appendChild(this.renderer.domElement); 391 | 392 | this.scene = new _three.Scene(); 393 | 394 | this.camera = new _three.PerspectiveCamera(60, this.getAspect(), 0.1, 100); 395 | 396 | this.onResize = this.onResize.bind(this); 397 | window.addEventListener('resize', this.onResize); 398 | 399 | this.init(); 400 | 401 | this.lastTick = 0; 402 | this.onTick = this.onTick.bind(this); 403 | requestAnimationFrame(this.onTick); 404 | } 405 | 406 | _createClass(App, [{ 407 | key: 'onTick', 408 | value: function onTick() { 409 | var t = performance.now(); 410 | var delta = performance.now() - this.lastTick; 411 | if (this.stats) { 412 | this.stats.begin(); 413 | } 414 | this.update(t, delta); 415 | this.render(t, delta); 416 | if (this.stats) { 417 | this.stats.end(); 418 | } 419 | this.lastTick = t; 420 | requestAnimationFrame(this.onTick); 421 | } 422 | }, { 423 | key: 'getAspect', 424 | value: function getAspect() { 425 | return window.innerWidth / window.innerHeight; 426 | } 427 | }, { 428 | key: 'onResize', 429 | value: function onResize() { 430 | this.camera.aspect = this.getAspect(); 431 | this.camera.updateProjectionMatrix(); 432 | this.renderer.setSize(window.innerWidth, window.innerHeight); 433 | } 434 | }]); 435 | 436 | return App; 437 | }(); 438 | 439 | exports.default = App; 440 | 441 | /***/ }), 442 | /* 7 */ 443 | /***/ (function(module, exports, __webpack_require__) { 444 | 445 | // stats.js - http://github.com/mrdoob/stats.js 446 | (function(f,e){ true?module.exports=e():"function"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;dg+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/ 448 | 1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=h;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v); 449 | b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+" "+e+" ("+g(c)+"-"+g(k)+")",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f}); 450 | 451 | 452 | /***/ }), 453 | /* 8 */ 454 | /***/ (function(module, exports, __webpack_require__) { 455 | 456 | "use strict"; 457 | 458 | 459 | var THREE = __webpack_require__(0); 460 | 461 | module.exports = function processShader(vertexShaderCode, fragmentShaderCode) { 462 | 463 | var regExp = /uniform\s+([^\s]+)\s+([^\s]+)\s*;/gi; 464 | var regExp2 = /uniform\s+([^\s]+)\s+([^\s]+)\s*\[\s*(\w+)\s*\]*\s*;/gi; 465 | 466 | var typesMap = { 467 | sampler2D: { type: 't', value: function() { return new THREE.Texture(); } }, 468 | samplerCube: { type: 't', value: function() {} }, 469 | 470 | bool: { type: 'b', value: function() { return 0; } }, 471 | int: { type: 'i', value: function() { return 0; } }, 472 | float: { type: 'f', value: function() { return 0; } }, 473 | 474 | vec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 475 | vec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 476 | vec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 477 | 478 | bvec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 479 | bvec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 480 | bvec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 481 | 482 | ivec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 483 | ivec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 484 | ivec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 485 | 486 | mat2: { type: 'v2', value: function() { return new THREE.Matrix2(); } }, 487 | mat3: { type: 'v3', value: function() { return new THREE.Matrix3(); } }, 488 | mat4: { type: 'v4', value: function() { return new THREE.Matrix4(); } } 489 | }; 490 | 491 | var arrayTypesMap = { 492 | float: { type: 'fv', value: function() { return []; } }, 493 | vec3: { type: 'v3v', value: function() { return []; } } 494 | }; 495 | 496 | var matches; 497 | var uniforms = { 498 | resolution: { type: 'v2', value: new THREE.Vector2( 1, 1 ), default: true }, 499 | time: { type: 'f', value: Date.now(), default: true }, 500 | tInput: { type: 't', value: new THREE.Texture(), default: true } 501 | }; 502 | 503 | var uniformType, uniformName, arraySize; 504 | 505 | while ((matches = regExp.exec(fragmentShaderCode)) !== null) { 506 | if (matches.index === regExp.lastIndex) { 507 | regExp.lastIndex++; 508 | } 509 | uniformType = matches[1]; 510 | uniformName = matches[2]; 511 | 512 | uniforms[uniformName] = { 513 | type: typesMap[uniformType].type, 514 | value: typesMap[uniformType].value() 515 | }; 516 | } 517 | 518 | while ((matches = regExp2.exec(fragmentShaderCode)) !== null) { 519 | if (matches.index === regExp.lastIndex) { 520 | regExp.lastIndex++; 521 | } 522 | uniformType = matches[1]; 523 | uniformName = matches[2]; 524 | arraySize = matches[3]; 525 | 526 | uniforms[uniformName] = { 527 | type: arrayTypesMap[uniformType].type, 528 | value: arrayTypesMap[uniformType].value() 529 | }; 530 | } 531 | 532 | var shader = new THREE.ShaderMaterial({ 533 | uniforms: uniforms, 534 | vertexShader: vertexShaderCode, 535 | fragmentShader: fragmentShaderCode, 536 | shading: THREE.FlatShading, 537 | depthWrite: false, 538 | depthTest: false, 539 | transparent: true 540 | }); 541 | 542 | return shader; 543 | }; 544 | 545 | /***/ }), 546 | /* 9 */ 547 | /***/ (function(module, exports) { 548 | 549 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\nuniform sampler2D tInput;\n\nvoid main() {\n gl_FragColor = texture2D( tInput, vUv );\n\n}" 550 | 551 | /***/ }), 552 | /* 10 */ 553 | /***/ (function(module, exports, __webpack_require__) { 554 | 555 | "use strict"; 556 | 557 | 558 | function Stack(shadersPool) { 559 | this.passItems = []; 560 | this.shadersPool = shadersPool; 561 | this.passes = []; 562 | } 563 | 564 | module.exports = Stack; 565 | 566 | Stack.prototype.addPass = function(shaderName, enabled, params, index) { 567 | var length = 0; 568 | var passItem = { 569 | shaderName: shaderName, 570 | enabled: enabled || false 571 | }; 572 | 573 | // TODO use and store params values 574 | 575 | this.passItems.push(passItem); 576 | length = this.passItems.length; 577 | 578 | this.updatePasses(); 579 | 580 | if (index) { 581 | return this.movePassToIndex(this.passItems[length], index); 582 | } 583 | else { 584 | return length - 1; 585 | } 586 | }; 587 | 588 | Stack.prototype.removePass = function(index) { 589 | this.passItems.splice(index, 1); 590 | this.updatePasses(); 591 | }; 592 | 593 | Stack.prototype.enablePass = function(index) { 594 | this.passItems[index].enabled = true; 595 | this.updatePasses(); 596 | }; 597 | 598 | Stack.prototype.disablePass = function(index) { 599 | this.passItems[index].enabled = false; 600 | this.updatePasses(); 601 | }; 602 | 603 | Stack.prototype.isPassEnabled = function(index) { 604 | return this.passItems[index].enabled; 605 | }; 606 | 607 | Stack.prototype.movePassToIndex = function(index, destIndex) { 608 | this.passItems.splice(destIndex, 0, this.passItems.splice(index, 1)[0]); 609 | this.updatePasses(); 610 | 611 | // TODO check if destIndex is final index 612 | return destIndex; 613 | }; 614 | 615 | Stack.prototype.reverse = function() { 616 | this.passItems.reverse(); 617 | this.updatePasses(); 618 | }; 619 | 620 | Stack.prototype.updatePasses = function() { 621 | this.passes = this.shadersPool.getPasses(this.passItems); 622 | 623 | // init default params for new passItems 624 | this.passItems.forEach(function(passItem, index) { 625 | if (passItem.params === undefined) { 626 | passItem.params = JSON.parse(JSON.stringify(this.passes[index].params)); // clone params without reference to the real shader instance params 627 | } 628 | }.bind(this)); 629 | }; 630 | 631 | Stack.prototype.getPasses = function() { 632 | return this.passes; 633 | }; 634 | 635 | 636 | /***/ }), 637 | /* 11 */, 638 | /* 12 */, 639 | /* 13 */, 640 | /* 14 */, 641 | /* 15 */, 642 | /* 16 */, 643 | /* 17 */, 644 | /* 18 */, 645 | /* 19 */, 646 | /* 20 */, 647 | /* 21 */, 648 | /* 22 */, 649 | /* 23 */, 650 | /* 24 */, 651 | /* 25 */, 652 | /* 26 */, 653 | /* 27 */, 654 | /* 28 */ 655 | /***/ (function(module, exports, __webpack_require__) { 656 | 657 | "use strict"; 658 | 659 | 660 | Object.defineProperty(exports, "__esModule", { 661 | value: true 662 | }); 663 | 664 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 665 | 666 | var _three = __webpack_require__(0); 667 | 668 | var _tween = __webpack_require__(29); 669 | 670 | var _ThreeApp2 = __webpack_require__(6); 671 | 672 | var _ThreeApp3 = _interopRequireDefault(_ThreeApp2); 673 | 674 | var _frag = __webpack_require__(30); 675 | 676 | var _frag2 = _interopRequireDefault(_frag); 677 | 678 | var _vert = __webpack_require__(31); 679 | 680 | var _vert2 = _interopRequireDefault(_vert); 681 | 682 | var _wagner = __webpack_require__(4); 683 | 684 | var _wagner2 = _interopRequireDefault(_wagner); 685 | 686 | var _VignettePass = __webpack_require__(32); 687 | 688 | var _VignettePass2 = _interopRequireDefault(_VignettePass); 689 | 690 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 691 | 692 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 693 | 694 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 695 | 696 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 697 | 698 | var ROTATION_DELAY = 100; 699 | var ROTATION_SPEED = 800; 700 | var DIMENSIONS = 3; 701 | var CUBE_SCALE = 1.0; 702 | var CUBE_DISTANCE_SCALE = 1.0; 703 | var EASING = _tween.Easing.Back.Out; 704 | var BG_COLOR = 0x333333; 705 | 706 | // Randomly return val1 or val2 707 | var or = function or(val1, val2) { 708 | return Math.random() > 0.5 ? val1 : val2; 709 | }; 710 | // Pass in an axis ('x', 'y', 'z') and return a different axis 711 | var getDifferentAxis = function getDifferentAxis(axis) { 712 | return axis === 'x' ? or('y', 'z') : axis === 'y' ? or('x', 'z') : or('y', 'x'); 713 | }; 714 | var getRandomAxis = function getRandomAxis() { 715 | return ['x', 'y', 'z'][Math.floor(Math.random() * 3)]; 716 | }; 717 | 718 | var Experiment = function (_ThreeApp) { 719 | _inherits(Experiment, _ThreeApp); 720 | 721 | function Experiment() { 722 | _classCallCheck(this, Experiment); 723 | 724 | return _possibleConstructorReturn(this, (Experiment.__proto__ || Object.getPrototypeOf(Experiment)).apply(this, arguments)); 725 | } 726 | 727 | _createClass(Experiment, [{ 728 | key: 'init', 729 | value: function init() { 730 | this.renderer.setClearColor(BG_COLOR); 731 | this.curves = []; 732 | 733 | this.cubeGroup = new _three.Object3D(); 734 | this.rotationHelper = new _three.Object3D(); 735 | this.cubeGroup.add(this.rotationHelper); 736 | this.scene.add(this.cubeGroup); 737 | this.material = new _three.ShaderMaterial({ 738 | vertexShader: _vert2.default, 739 | fragmentShader: _frag2.default, 740 | uniforms: { 741 | fgColor: { value: new _three.Color(0xffffff) }, 742 | bgColor: { value: new _three.Color(BG_COLOR) } 743 | } 744 | }); 745 | 746 | this.createCubes(); 747 | 748 | this.pivot = new _three.Object3D(); 749 | this.scene.add(this.pivot); 750 | this.camera.lookAt(new _three.Vector3()); 751 | this.pivot.add(this.camera); 752 | this.camera.position.set(4, 4, 4); 753 | 754 | this.lastRotation = 0; 755 | this.composer = new _wagner2.default.Composer(this.renderer); 756 | this.pass = new _VignettePass2.default(0.9, 1.0); 757 | } 758 | }, { 759 | key: 'createCubes', 760 | value: function createCubes() { 761 | this.cubes = []; 762 | 763 | /** 764 | * Store cubes in plane, row, columns, below 765 | * is a face 766 | * 767 | * z,y,x 768 | * 769 | * 0,0,0 0,0,1 0,0,2 770 | * 0,1,0 0,1,1 0,1,2 771 | * 0,2,0 0,2,1 0,2,2 772 | * 773 | */ 774 | var solid = this.material; 775 | var transparent = new _three.MeshBasicMaterial({ opacity: 0, transparent: true }); 776 | var last = DIMENSIONS - 1; 777 | for (var z = 0; z < DIMENSIONS; z++) { 778 | var plane = this.cubes[z] = []; 779 | for (var y = 0; y < DIMENSIONS; y++) { 780 | var row = plane[y] = []; 781 | for (var x = 0; x < DIMENSIONS; x++) { 782 | var cube = new _three.Mesh(new _three.BoxGeometry(CUBE_SCALE, CUBE_SCALE, CUBE_SCALE), [x === last ? solid : transparent, // bot right 783 | x === 0 ? solid : transparent, // back left 784 | y === last ? solid : transparent, // top 785 | y === 0 ? solid : transparent, // bottom 786 | z === last ? solid : transparent, // bot left 787 | z === 0 ? solid : transparent]); 788 | row[x] = cube; 789 | this.cubeGroup.add(cube); 790 | 791 | var half = DIMENSIONS % 2 === 0 ? DIMENSIONS / 2 - 0.5 : Math.floor(DIMENSIONS / 2); 792 | cube.position.set((x - half) * CUBE_DISTANCE_SCALE, (y - half) * CUBE_DISTANCE_SCALE, (z - half) * CUBE_DISTANCE_SCALE); 793 | } 794 | } 795 | } 796 | } 797 | }, { 798 | key: 'getCubesBySlice', 799 | value: function getCubesBySlice(axis, index) { 800 | // I'm sure there's a better way for this 801 | var cubes = []; 802 | for (var z = 0; z < DIMENSIONS; z++) { 803 | for (var y = 0; y < DIMENSIONS; y++) { 804 | for (var x = 0; x < DIMENSIONS; x++) { 805 | var r = axis === 'z' ? z : axis === 'y' ? y : x; 806 | if (r === index) { 807 | var cube = this.cubes[z][y][x]; 808 | cubes.push(cube); 809 | } 810 | } 811 | } 812 | } 813 | return cubes; 814 | } 815 | }, { 816 | key: 'rotateCubes', 817 | value: function rotateCubes(axis, index, dir) { 818 | var _this2 = this; 819 | 820 | var cubes = this.getCubesBySlice(axis, index); 821 | var _iteratorNormalCompletion = true; 822 | var _didIteratorError = false; 823 | var _iteratorError = undefined; 824 | 825 | try { 826 | for (var _iterator = cubes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 827 | var cube = _step.value; 828 | 829 | this.cubeGroup.remove(cube); 830 | this.rotationHelper.add(cube); 831 | } 832 | } catch (err) { 833 | _didIteratorError = true; 834 | _iteratorError = err; 835 | } finally { 836 | try { 837 | if (!_iteratorNormalCompletion && _iterator.return) { 838 | _iterator.return(); 839 | } 840 | } finally { 841 | if (_didIteratorError) { 842 | throw _iteratorError; 843 | } 844 | } 845 | } 846 | 847 | this.cubeTween = this.rotate(this.rotationHelper, axis, dir); 848 | this.cubeTween.onComplete(function () { 849 | cubes.forEach(function (c) { 850 | _this2.cubeGroup.add(c); 851 | _this2.rotationHelper.remove(c); 852 | }); 853 | _this2.rotationHelper.rotation.set(0, 0, 0); 854 | _this2.cubeTween = null; 855 | }); 856 | } 857 | }, { 858 | key: 'rotate', 859 | value: function rotate(object, axis, dir, easing) { 860 | var startRotation = object.rotation[axis]; 861 | 862 | return new _tween.Tween({ x: 0 }).to({ x: 1 }, ROTATION_SPEED).onUpdate(function (value) { 863 | object.rotation[axis] = startRotation + value * Math.PI / 2 * dir; 864 | }).easing(easing || EASING).start(); 865 | } 866 | }, { 867 | key: 'update', 868 | value: function update(t, delta) { 869 | var _this3 = this; 870 | 871 | if (this.lastRotation + ROTATION_SPEED + ROTATION_DELAY < t && !this.camTween && !this.cubeTween) { 872 | var index = Math.floor(Math.random() * 3); 873 | var axis = getRandomAxis(); 874 | var dir = or(-1, 1); 875 | // Rotate a slice of cubes on `axis` at `index` 876 | this.rotateCubes(axis, index, dir); 877 | // Also rotate the camera randomly on a different access 878 | this.camTween = this.rotate(this.pivot, getRandomAxis(), dir * -1, _tween.Easing.Cubic.Out); 879 | this.camTween.onComplete(function () { 880 | return _this3.camTween = null; 881 | }); 882 | 883 | this.lastRotation = t; 884 | } 885 | this.camera.lookAt(new _three.Vector3()); 886 | this.camera.updateMatrixWorld(); 887 | 888 | (0, _tween.update)(); 889 | } 890 | }, { 891 | key: 'render', 892 | value: function render() { 893 | this.renderer.clearColor(); 894 | this.composer.reset(); 895 | this.composer.render(this.scene, this.camera); 896 | this.composer.pass(this.pass); 897 | this.composer.toScreen(); 898 | } 899 | }]); 900 | 901 | return Experiment; 902 | }(_ThreeApp3.default); 903 | 904 | exports.default = new Experiment(); 905 | 906 | /***/ }), 907 | /* 29 */ 908 | /***/ (function(module, exports) { 909 | 910 | module.exports = __WEBPACK_EXTERNAL_MODULE_29__; 911 | 912 | /***/ }), 913 | /* 30 */ 914 | /***/ (function(module, exports) { 915 | 916 | module.exports = "#define GLSLIFY 1\nuniform vec3 fgColor;\nuniform vec3 bgColor;\n\nvarying vec2 vUv;\n\nfloat when_gt_1_0(float x, float y) {\n return max(sign(x - y), 0.0);\n}\n\nvec2 when_gt_1_0(vec2 x, vec2 y) {\n return max(sign(x - y), 0.0);\n}\n\nvec3 when_gt_1_0(vec3 x, vec3 y) {\n return max(sign(x - y), 0.0);\n}\n\nvec4 when_gt_1_0(vec4 x, vec4 y) {\n return max(sign(x - y), 0.0);\n}\n\n\n\n\nvoid main() {\n float limit = 0.1;\n vec3 color = fgColor;\n\n float isTiled = 0.0;\n isTiled += when_gt_1_0(limit, vUv.x);\n isTiled += when_gt_1_0(limit, vUv.y);\n isTiled += when_gt_1_0(vUv.x, 1.0 - limit);\n isTiled += when_gt_1_0(vUv.y, 1.0 - limit);\n\n color = (step(1.0, isTiled) * bgColor) + ((1.0 - step(1.0, isTiled)) * fgColor);\n gl_FragColor = vec4(color, 1.0);\n}\n" 917 | 918 | /***/ }), 919 | /* 31 */ 920 | /***/ (function(module, exports) { 921 | 922 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\n\nvoid main() {\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n}\n" 923 | 924 | /***/ }), 925 | /* 32 */ 926 | /***/ (function(module, exports, __webpack_require__) { 927 | 928 | "use strict"; 929 | 930 | 931 | var Pass = __webpack_require__(1); 932 | var vertex = __webpack_require__(2); 933 | var fragment = __webpack_require__(33); 934 | 935 | function VignettePass(boost, reduction) { 936 | Pass.call(this); 937 | 938 | this.setShader(vertex, fragment); 939 | 940 | this.params.boost = boost || 2; 941 | this.params.reduction = reduction || 2; 942 | } 943 | 944 | module.exports = VignettePass; 945 | 946 | VignettePass.prototype = Object.create(Pass.prototype); 947 | VignettePass.prototype.constructor = VignettePass; 948 | 949 | VignettePass.prototype.run = function(composer) { 950 | this.shader.uniforms.boost.value = this.params.boost; 951 | this.shader.uniforms.reduction.value = this.params.reduction; 952 | composer.pass(this.shader); 953 | }; 954 | 955 | 956 | /***/ }), 957 | /* 33 */ 958 | /***/ (function(module, exports) { 959 | 960 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\nuniform sampler2D tInput;\nuniform vec2 resolution;\n\nuniform float reduction;\nuniform float boost;\n\nvoid main() {\n\n vec4 color = texture2D( tInput, vUv );\n\n vec2 center = resolution * 0.5;\n float vignette = distance( center, gl_FragCoord.xy ) / resolution.x;\n vignette = boost - vignette * reduction;\n\n color.rgb *= vignette;\n gl_FragColor = color;\n\n}" 961 | 962 | /***/ }) 963 | /******/ ]); 964 | }); -------------------------------------------------------------------------------- /public/002/bundle.js: -------------------------------------------------------------------------------- 1 | (function webpackUniversalModuleDefinition(root, factory) { 2 | if(typeof exports === 'object' && typeof module === 'object') 3 | module.exports = factory(require("three")); 4 | else if(typeof define === 'function' && define.amd) 5 | define(["three"], factory); 6 | else if(typeof exports === 'object') 7 | exports["app"] = factory(require("three")); 8 | else 9 | root["app"] = factory(root["THREE"]); 10 | })(this, function(__WEBPACK_EXTERNAL_MODULE_0__) { 11 | return /******/ (function(modules) { // webpackBootstrap 12 | /******/ // The module cache 13 | /******/ var installedModules = {}; 14 | /******/ 15 | /******/ // The require function 16 | /******/ function __webpack_require__(moduleId) { 17 | /******/ 18 | /******/ // Check if module is in cache 19 | /******/ if(installedModules[moduleId]) { 20 | /******/ return installedModules[moduleId].exports; 21 | /******/ } 22 | /******/ // Create a new module (and put it into the cache) 23 | /******/ var module = installedModules[moduleId] = { 24 | /******/ i: moduleId, 25 | /******/ l: false, 26 | /******/ exports: {} 27 | /******/ }; 28 | /******/ 29 | /******/ // Execute the module function 30 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 31 | /******/ 32 | /******/ // Flag the module as loaded 33 | /******/ module.l = true; 34 | /******/ 35 | /******/ // Return the exports of the module 36 | /******/ return module.exports; 37 | /******/ } 38 | /******/ 39 | /******/ 40 | /******/ // expose the modules object (__webpack_modules__) 41 | /******/ __webpack_require__.m = modules; 42 | /******/ 43 | /******/ // expose the module cache 44 | /******/ __webpack_require__.c = installedModules; 45 | /******/ 46 | /******/ // define getter function for harmony exports 47 | /******/ __webpack_require__.d = function(exports, name, getter) { 48 | /******/ if(!__webpack_require__.o(exports, name)) { 49 | /******/ Object.defineProperty(exports, name, { 50 | /******/ configurable: false, 51 | /******/ enumerable: true, 52 | /******/ get: getter 53 | /******/ }); 54 | /******/ } 55 | /******/ }; 56 | /******/ 57 | /******/ // getDefaultExport function for compatibility with non-harmony modules 58 | /******/ __webpack_require__.n = function(module) { 59 | /******/ var getter = module && module.__esModule ? 60 | /******/ function getDefault() { return module['default']; } : 61 | /******/ function getModuleExports() { return module; }; 62 | /******/ __webpack_require__.d(getter, 'a', getter); 63 | /******/ return getter; 64 | /******/ }; 65 | /******/ 66 | /******/ // Object.prototype.hasOwnProperty.call 67 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 68 | /******/ 69 | /******/ // __webpack_public_path__ 70 | /******/ __webpack_require__.p = ""; 71 | /******/ 72 | /******/ // Load entry module and return exports 73 | /******/ return __webpack_require__(__webpack_require__.s = 27); 74 | /******/ }) 75 | /************************************************************************/ 76 | /******/ ([ 77 | /* 0 */ 78 | /***/ (function(module, exports) { 79 | 80 | module.exports = __WEBPACK_EXTERNAL_MODULE_0__; 81 | 82 | /***/ }), 83 | /* 1 */ 84 | /***/ (function(module, exports, __webpack_require__) { 85 | 86 | "use strict"; 87 | 88 | 89 | var THREE = __webpack_require__(0); 90 | var processShader = __webpack_require__(8); 91 | 92 | function Pass() { 93 | this.shader = null; 94 | this.loaded = null; 95 | this.params = {}; 96 | this.isSim = false; 97 | } 98 | 99 | module.exports = Pass; 100 | 101 | Pass.prototype.setShader = function(vs, fs) { 102 | this.shader = processShader(vs, fs); 103 | }; 104 | 105 | Pass.prototype.run = function(composer) { 106 | composer.pass(this.shader); 107 | }; 108 | 109 | Pass.prototype.getOfflineTexture = function(w, h, useRGBA) { 110 | return new THREE.WebGLRenderTarget(w, h, { 111 | minFilter: THREE.LinearFilter, 112 | magFilter: THREE.LinearFilter, 113 | format: useRGBA ? THREE.RGBAFormat : THREE.RGBFormat 114 | }); 115 | }; 116 | 117 | 118 | /***/ }), 119 | /* 2 */ 120 | /***/ (function(module, exports) { 121 | 122 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\n\nvoid main() {\n\n vUv = uv;\n gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n}" 123 | 124 | /***/ }), 125 | /* 3 */ 126 | /***/ (function(module, exports, __webpack_require__) { 127 | 128 | "use strict"; 129 | 130 | 131 | var Pass = __webpack_require__(1); 132 | var vertex = __webpack_require__(2); 133 | var fragment = __webpack_require__(9); 134 | 135 | function CopyPass() { 136 | Pass.call(this); 137 | this.setShader(vertex, fragment); 138 | } 139 | 140 | module.exports = CopyPass; 141 | 142 | CopyPass.prototype = Object.create(Pass.prototype); 143 | CopyPass.prototype.constructor = CopyPass; 144 | 145 | 146 | /***/ }), 147 | /* 4 */ 148 | /***/ (function(module, exports, __webpack_require__) { 149 | 150 | "use strict"; 151 | 152 | 153 | module.exports.Composer = __webpack_require__(5); 154 | module.exports.CopyPass = __webpack_require__(3); 155 | module.exports.BlendMode = { 156 | Normal: 1, 157 | Dissolve: 2, // UNAVAILABLE 158 | Darken: 3, 159 | Multiply: 4, 160 | ColorBurn: 5, 161 | LinearBurn: 6, 162 | DarkerColor: 7, // UNAVAILABLE 163 | Lighten: 8, 164 | Screen: 9, 165 | ColorDodge: 10, 166 | LinearDodge: 11, 167 | LighterColor: 12, // UNAVAILABLE 168 | Overlay: 13, 169 | SoftLight: 14, 170 | HardLight: 15, 171 | VividLight: 16, // UNAVAILABLE 172 | LinearLight: 17, 173 | PinLight: 18, // UNAVAILABLE 174 | HardMix: 19, // UNAVAILABLE 175 | Difference: 20, 176 | Exclusion: 21, 177 | Substract: 22, // UNAVAILABLE 178 | Divide: 23 // UNAVAILABLE 179 | }; 180 | 181 | 182 | /***/ }), 183 | /* 5 */ 184 | /***/ (function(module, exports, __webpack_require__) { 185 | 186 | "use strict"; 187 | 188 | 189 | var THREE = __webpack_require__(0); 190 | var CopyPass = __webpack_require__(3); 191 | var Stack = __webpack_require__(10); 192 | var Pass = __webpack_require__(1); 193 | 194 | function Composer(renderer, settings) { 195 | var pixelRatio = renderer.getPixelRatio(); 196 | 197 | this.width = Math.floor(renderer.context.canvas.width / pixelRatio) || 1; 198 | this.height = Math.floor(renderer.context.canvas.height / pixelRatio) || 1; 199 | 200 | this.output = null; 201 | this.input = null; 202 | this.read = null; 203 | this.write = null; 204 | 205 | this.settings = settings || {}; 206 | this.useRGBA = this.settings.useRGBA || false; 207 | 208 | this.renderer = renderer; 209 | this.copyPass = new CopyPass(this.settings); 210 | 211 | this.defaultMaterial = new THREE.MeshBasicMaterial({color: 0x00FF00, wireframe: false}); 212 | this.scene = new THREE.Scene(); 213 | this.quad = new THREE.Mesh(new THREE.PlaneBufferGeometry(1, 1), this.defaultMaterial); 214 | this.scene.add(this.quad); 215 | this.camera = new THREE.OrthographicCamera(1, 1, 1, 1, -10000, 10000); 216 | 217 | this.front = new THREE.WebGLRenderTarget(1, 1, { 218 | minFilter: this.settings.minFilter !== undefined ? this.settings.minFilter : THREE.LinearFilter, 219 | magFilter: this.settings.magFilter !== undefined ? this.settings.magFilter : THREE.LinearFilter, 220 | wrapS: this.settings.wrapS !== undefined ? this.settings.wrapS : THREE.ClampToEdgeWrapping, 221 | wrapT: this.settings.wrapT !== undefined ? this.settings.wrapT : THREE.ClampToEdgeWrapping, 222 | format: this.useRGBA ? THREE.RGBAFormat : THREE.RGBFormat, 223 | type: this.settings.type !== undefined ? this.settings.type : THREE.UnsignedByteType, 224 | stencilBuffer: this.settings.stencilBuffer !== undefined ? this.settings.stencilBuffer : true 225 | }); 226 | 227 | this.back = this.front.clone(); 228 | this.startTime = Date.now(); 229 | this.passes = {}; 230 | 231 | this.setSize(this.width, this.height); 232 | } 233 | 234 | module.exports = Composer; 235 | 236 | Composer.prototype.swapBuffers = function() { 237 | this.output = this.write; 238 | this.input = this.read; 239 | 240 | var t = this.write; 241 | this.write = this.read; 242 | this.read = t; 243 | }; 244 | 245 | Composer.prototype.render = function(scene, camera, keep, output) { 246 | if (keep) this.swapBuffers(); 247 | this.renderer.render(scene, camera, output ? output : this.write, true); 248 | if (!output) this.swapBuffers(); 249 | }; 250 | 251 | Composer.prototype.toScreen = function() { 252 | this.quad.material = this.copyPass.shader; 253 | this.quad.material.uniforms.tInput.value = this.read; 254 | this.quad.material.uniforms.resolution.value.set(this.width, this.height); 255 | this.renderer.render(this.scene, this.camera); 256 | }; 257 | 258 | Composer.prototype.toTexture = function(t) { 259 | this.quad.material = this.copyPass.shader; 260 | this.quad.material.uniforms.tInput.value = this.read; 261 | this.renderer.render(this.scene, this.camera, t, false); 262 | }; 263 | 264 | Composer.prototype.pass = function(pass) { 265 | if (pass instanceof Stack) { 266 | this.passStack(pass); 267 | } 268 | else { 269 | if (pass instanceof THREE.ShaderMaterial) { 270 | this.quad.material = pass; 271 | } 272 | if (pass instanceof Pass) { 273 | pass.run(this); 274 | return; 275 | } 276 | 277 | if (!pass.isSim) { 278 | this.quad.material.uniforms.tInput.value = this.read; 279 | } 280 | 281 | this.quad.material.uniforms.resolution.value.set(this.width, this.height); 282 | this.quad.material.uniforms.time.value = 0.001 * (Date.now() - this.startTime); 283 | this.renderer.render(this.scene, this.camera, this.write, false); 284 | this.swapBuffers(); 285 | } 286 | }; 287 | 288 | Composer.prototype.passStack = function(stack) { 289 | stack.getPasses().forEach(function(pass) { 290 | this.pass(pass); 291 | }.bind(this)); 292 | }; 293 | 294 | Composer.prototype.reset = function() { 295 | this.read = this.front; 296 | this.write = this.back; 297 | this.output = this.write; 298 | this.input = this.read; 299 | }; 300 | 301 | Composer.prototype.setSource = function(src) { 302 | this.quad.material = this.copyPass.shader; 303 | this.quad.material.uniforms.tInput.value = src; 304 | this.renderer.render(this.scene, this.camera, this.write, true); 305 | this.swapBuffers(); 306 | }; 307 | 308 | Composer.prototype.setSize = function(w, h) { 309 | this.width = w; 310 | this.height = h; 311 | 312 | this.camera.projectionMatrix.makeOrthographic( w / - 2, w / 2, h / 2, h / - 2, this.camera.near, this.camera.far ); 313 | this.quad.scale.set( w, h, 1 ); 314 | 315 | this.front.setSize( w, h ); 316 | this.back.setSize( w, h ); 317 | }; 318 | 319 | 320 | 321 | /***/ }), 322 | /* 6 */ 323 | /***/ (function(module, exports, __webpack_require__) { 324 | 325 | "use strict"; 326 | 327 | 328 | Object.defineProperty(exports, "__esModule", { 329 | value: true 330 | }); 331 | 332 | var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); 333 | 334 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 335 | 336 | var _three = __webpack_require__(0); 337 | 338 | var _stats = __webpack_require__(7); 339 | 340 | var _stats2 = _interopRequireDefault(_stats); 341 | 342 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 343 | 344 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 345 | 346 | var App = function () { 347 | function App() { 348 | _classCallCheck(this, App); 349 | 350 | if (window.location.search) { 351 | var params = window.location.search.substr(1).split('&'); 352 | var _iteratorNormalCompletion = true; 353 | var _didIteratorError = false; 354 | var _iteratorError = undefined; 355 | 356 | try { 357 | for (var _iterator = params[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { 358 | var param = _step.value; 359 | 360 | var _param$split = param.split('='), 361 | _param$split2 = _slicedToArray(_param$split, 2), 362 | prop = _param$split2[0], 363 | value = _param$split2[1]; 364 | 365 | if (prop === 'debug') { 366 | this.stats = new _stats2.default(); 367 | this.stats.showPanel(0); 368 | document.body.appendChild(this.stats.dom); 369 | } 370 | } 371 | } catch (err) { 372 | _didIteratorError = true; 373 | _iteratorError = err; 374 | } finally { 375 | try { 376 | if (!_iteratorNormalCompletion && _iterator.return) { 377 | _iterator.return(); 378 | } 379 | } finally { 380 | if (_didIteratorError) { 381 | throw _iteratorError; 382 | } 383 | } 384 | } 385 | } 386 | this.renderer = new _three.WebGLRenderer(); 387 | this.renderer.setPixelRatio(window.devicePixelRatio); 388 | this.renderer.setSize(window.innerWidth, window.innerHeight); 389 | this.renderer.autoClear = false; 390 | document.body.appendChild(this.renderer.domElement); 391 | 392 | this.scene = new _three.Scene(); 393 | 394 | this.camera = new _three.PerspectiveCamera(60, this.getAspect(), 0.1, 100); 395 | 396 | this.onResize = this.onResize.bind(this); 397 | window.addEventListener('resize', this.onResize); 398 | 399 | this.init(); 400 | 401 | this.lastTick = 0; 402 | this.onTick = this.onTick.bind(this); 403 | requestAnimationFrame(this.onTick); 404 | } 405 | 406 | _createClass(App, [{ 407 | key: 'onTick', 408 | value: function onTick() { 409 | var t = performance.now(); 410 | var delta = performance.now() - this.lastTick; 411 | if (this.stats) { 412 | this.stats.begin(); 413 | } 414 | this.update(t, delta); 415 | this.render(t, delta); 416 | if (this.stats) { 417 | this.stats.end(); 418 | } 419 | this.lastTick = t; 420 | requestAnimationFrame(this.onTick); 421 | } 422 | }, { 423 | key: 'getAspect', 424 | value: function getAspect() { 425 | return window.innerWidth / window.innerHeight; 426 | } 427 | }, { 428 | key: 'onResize', 429 | value: function onResize() { 430 | this.camera.aspect = this.getAspect(); 431 | this.camera.updateProjectionMatrix(); 432 | this.renderer.setSize(window.innerWidth, window.innerHeight); 433 | } 434 | }]); 435 | 436 | return App; 437 | }(); 438 | 439 | exports.default = App; 440 | 441 | /***/ }), 442 | /* 7 */ 443 | /***/ (function(module, exports, __webpack_require__) { 444 | 445 | // stats.js - http://github.com/mrdoob/stats.js 446 | (function(f,e){ true?module.exports=e():"function"===typeof define&&define.amd?define(e):f.Stats=e()})(this,function(){var f=function(){function e(a){c.appendChild(a.dom);return a}function u(a){for(var d=0;dg+1E3&&(r.update(1E3*a/(c-g),100),g=c,a=0,t)){var d=performance.memory;t.update(d.usedJSHeapSize/ 448 | 1048576,d.jsHeapSizeLimit/1048576)}return c},update:function(){k=this.end()},domElement:c,setMode:u}};f.Panel=function(e,f,l){var c=Infinity,k=0,g=Math.round,a=g(window.devicePixelRatio||1),r=80*a,h=48*a,t=3*a,v=2*a,d=3*a,m=15*a,n=74*a,p=30*a,q=document.createElement("canvas");q.width=r;q.height=h;q.style.cssText="width:80px;height:48px";var b=q.getContext("2d");b.font="bold "+9*a+"px Helvetica,Arial,sans-serif";b.textBaseline="top";b.fillStyle=l;b.fillRect(0,0,r,h);b.fillStyle=f;b.fillText(e,t,v); 449 | b.fillRect(d,m,n,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d,m,n,p);return{dom:q,update:function(h,w){c=Math.min(c,h);k=Math.max(k,h);b.fillStyle=l;b.globalAlpha=1;b.fillRect(0,0,r,m);b.fillStyle=f;b.fillText(g(h)+" "+e+" ("+g(c)+"-"+g(k)+")",t,v);b.drawImage(q,d+a,m,n-a,p,d,m,n-a,p);b.fillRect(d+n-a,m,a,p);b.fillStyle=l;b.globalAlpha=.9;b.fillRect(d+n-a,m,a,g((1-h/w)*p))}}};return f}); 450 | 451 | 452 | /***/ }), 453 | /* 8 */ 454 | /***/ (function(module, exports, __webpack_require__) { 455 | 456 | "use strict"; 457 | 458 | 459 | var THREE = __webpack_require__(0); 460 | 461 | module.exports = function processShader(vertexShaderCode, fragmentShaderCode) { 462 | 463 | var regExp = /uniform\s+([^\s]+)\s+([^\s]+)\s*;/gi; 464 | var regExp2 = /uniform\s+([^\s]+)\s+([^\s]+)\s*\[\s*(\w+)\s*\]*\s*;/gi; 465 | 466 | var typesMap = { 467 | sampler2D: { type: 't', value: function() { return new THREE.Texture(); } }, 468 | samplerCube: { type: 't', value: function() {} }, 469 | 470 | bool: { type: 'b', value: function() { return 0; } }, 471 | int: { type: 'i', value: function() { return 0; } }, 472 | float: { type: 'f', value: function() { return 0; } }, 473 | 474 | vec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 475 | vec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 476 | vec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 477 | 478 | bvec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 479 | bvec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 480 | bvec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 481 | 482 | ivec2: { type: 'v2', value: function() { return new THREE.Vector2(); } }, 483 | ivec3: { type: 'v3', value: function() { return new THREE.Vector3(); } }, 484 | ivec4: { type: 'v4', value: function() { return new THREE.Vector4(); } }, 485 | 486 | mat2: { type: 'v2', value: function() { return new THREE.Matrix2(); } }, 487 | mat3: { type: 'v3', value: function() { return new THREE.Matrix3(); } }, 488 | mat4: { type: 'v4', value: function() { return new THREE.Matrix4(); } } 489 | }; 490 | 491 | var arrayTypesMap = { 492 | float: { type: 'fv', value: function() { return []; } }, 493 | vec3: { type: 'v3v', value: function() { return []; } } 494 | }; 495 | 496 | var matches; 497 | var uniforms = { 498 | resolution: { type: 'v2', value: new THREE.Vector2( 1, 1 ), default: true }, 499 | time: { type: 'f', value: Date.now(), default: true }, 500 | tInput: { type: 't', value: new THREE.Texture(), default: true } 501 | }; 502 | 503 | var uniformType, uniformName, arraySize; 504 | 505 | while ((matches = regExp.exec(fragmentShaderCode)) !== null) { 506 | if (matches.index === regExp.lastIndex) { 507 | regExp.lastIndex++; 508 | } 509 | uniformType = matches[1]; 510 | uniformName = matches[2]; 511 | 512 | uniforms[uniformName] = { 513 | type: typesMap[uniformType].type, 514 | value: typesMap[uniformType].value() 515 | }; 516 | } 517 | 518 | while ((matches = regExp2.exec(fragmentShaderCode)) !== null) { 519 | if (matches.index === regExp.lastIndex) { 520 | regExp.lastIndex++; 521 | } 522 | uniformType = matches[1]; 523 | uniformName = matches[2]; 524 | arraySize = matches[3]; 525 | 526 | uniforms[uniformName] = { 527 | type: arrayTypesMap[uniformType].type, 528 | value: arrayTypesMap[uniformType].value() 529 | }; 530 | } 531 | 532 | var shader = new THREE.ShaderMaterial({ 533 | uniforms: uniforms, 534 | vertexShader: vertexShaderCode, 535 | fragmentShader: fragmentShaderCode, 536 | shading: THREE.FlatShading, 537 | depthWrite: false, 538 | depthTest: false, 539 | transparent: true 540 | }); 541 | 542 | return shader; 543 | }; 544 | 545 | /***/ }), 546 | /* 9 */ 547 | /***/ (function(module, exports) { 548 | 549 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\nuniform sampler2D tInput;\n\nvoid main() {\n gl_FragColor = texture2D( tInput, vUv );\n\n}" 550 | 551 | /***/ }), 552 | /* 10 */ 553 | /***/ (function(module, exports, __webpack_require__) { 554 | 555 | "use strict"; 556 | 557 | 558 | function Stack(shadersPool) { 559 | this.passItems = []; 560 | this.shadersPool = shadersPool; 561 | this.passes = []; 562 | } 563 | 564 | module.exports = Stack; 565 | 566 | Stack.prototype.addPass = function(shaderName, enabled, params, index) { 567 | var length = 0; 568 | var passItem = { 569 | shaderName: shaderName, 570 | enabled: enabled || false 571 | }; 572 | 573 | // TODO use and store params values 574 | 575 | this.passItems.push(passItem); 576 | length = this.passItems.length; 577 | 578 | this.updatePasses(); 579 | 580 | if (index) { 581 | return this.movePassToIndex(this.passItems[length], index); 582 | } 583 | else { 584 | return length - 1; 585 | } 586 | }; 587 | 588 | Stack.prototype.removePass = function(index) { 589 | this.passItems.splice(index, 1); 590 | this.updatePasses(); 591 | }; 592 | 593 | Stack.prototype.enablePass = function(index) { 594 | this.passItems[index].enabled = true; 595 | this.updatePasses(); 596 | }; 597 | 598 | Stack.prototype.disablePass = function(index) { 599 | this.passItems[index].enabled = false; 600 | this.updatePasses(); 601 | }; 602 | 603 | Stack.prototype.isPassEnabled = function(index) { 604 | return this.passItems[index].enabled; 605 | }; 606 | 607 | Stack.prototype.movePassToIndex = function(index, destIndex) { 608 | this.passItems.splice(destIndex, 0, this.passItems.splice(index, 1)[0]); 609 | this.updatePasses(); 610 | 611 | // TODO check if destIndex is final index 612 | return destIndex; 613 | }; 614 | 615 | Stack.prototype.reverse = function() { 616 | this.passItems.reverse(); 617 | this.updatePasses(); 618 | }; 619 | 620 | Stack.prototype.updatePasses = function() { 621 | this.passes = this.shadersPool.getPasses(this.passItems); 622 | 623 | // init default params for new passItems 624 | this.passItems.forEach(function(passItem, index) { 625 | if (passItem.params === undefined) { 626 | passItem.params = JSON.parse(JSON.stringify(this.passes[index].params)); // clone params without reference to the real shader instance params 627 | } 628 | }.bind(this)); 629 | }; 630 | 631 | Stack.prototype.getPasses = function() { 632 | return this.passes; 633 | }; 634 | 635 | 636 | /***/ }), 637 | /* 11 */ 638 | /***/ (function(module, exports, __webpack_require__) { 639 | 640 | "use strict"; 641 | 642 | 643 | var THREE = __webpack_require__(0); 644 | var Pass = __webpack_require__(1); 645 | var Composer = __webpack_require__(5); 646 | var BlendMode = __webpack_require__(4).BlendMode; 647 | var FullBoxBlurPass = __webpack_require__(12); 648 | var BlendPass = __webpack_require__(15); 649 | var ZoomBlurPass = __webpack_require__(17); 650 | var BrightnessContrastPass = __webpack_require__(19); 651 | 652 | function MultiPassBloomPass(options) { 653 | Pass.call(this); 654 | 655 | options = options || {}; 656 | 657 | this.composer = null; 658 | 659 | this.tmpTexture = this.getOfflineTexture( options.width, options.height, true ); 660 | this.blurPass = new FullBoxBlurPass(2); 661 | this.blendPass = new BlendPass(); 662 | this.zoomBlur = new ZoomBlurPass(); 663 | this.brightnessContrastPass = new BrightnessContrastPass(); 664 | 665 | this.width = options.width || 512; 666 | this.height = options.height || 512; 667 | 668 | this.params.blurAmount = options.blurAmount || 2; 669 | this.params.applyZoomBlur = options.applyZoomBlur || false; 670 | this.params.zoomBlurStrength = options.zoomBlurStrength || 0.2; 671 | this.params.useTexture = options.useTexture || false; 672 | this.params.zoomBlurCenter = options.zoomBlurCenter || new THREE.Vector2(0.5, 0.5); 673 | this.params.blendMode = options.blendMode || BlendMode.Screen; 674 | this.params.glowTexture = null; 675 | } 676 | 677 | module.exports = MultiPassBloomPass; 678 | 679 | MultiPassBloomPass.prototype = Object.create(Pass.prototype); 680 | MultiPassBloomPass.prototype.constructor = MultiPassBloomPass; 681 | 682 | MultiPassBloomPass.prototype.run = function(composer) { 683 | if (!this.composer) { 684 | this.composer = new Composer(composer.renderer, {useRGBA: true}); 685 | this.composer.setSize(this.width, this.height); 686 | } 687 | 688 | this.composer.reset(); 689 | 690 | if (this.params.useTexture === true) { 691 | this.composer.setSource(this.params.glowTexture); 692 | } else { 693 | this.composer.setSource(composer.output); 694 | } 695 | 696 | this.blurPass.params.amount = this.params.blurAmount; 697 | this.composer.pass(this.blurPass); 698 | 699 | if (this.params.applyZoomBlur) { 700 | this.zoomBlur.params.center.set(0.5, 0.5); 701 | this.zoomBlur.params.strength = this.params.zoomBlurStrength; 702 | this.composer.pass(this.zoomBlur); 703 | } 704 | 705 | if (this.params.useTexture === true) { 706 | this.blendPass.params.mode = BlendMode.Screen; 707 | this.blendPass.params.tInput = this.params.glowTexture; 708 | composer.pass(this.blendPass); 709 | } 710 | 711 | this.blendPass.params.mode = this.params.blendMode; 712 | this.blendPass.params.tInput2 = this.composer.output; 713 | composer.pass(this.blendPass); 714 | }; 715 | 716 | 717 | /***/ }), 718 | /* 12 */ 719 | /***/ (function(module, exports, __webpack_require__) { 720 | 721 | "use strict"; 722 | 723 | 724 | var Pass = __webpack_require__(1); 725 | var BoxBlurPass = __webpack_require__(13); 726 | 727 | function FullBoxBlurPass(amount) { 728 | Pass.call(this); 729 | 730 | amount = amount || 2; 731 | 732 | this.boxPass = new BoxBlurPass(amount, amount); 733 | this.params.amount = amount; 734 | } 735 | 736 | module.exports = FullBoxBlurPass; 737 | 738 | FullBoxBlurPass.prototype = Object.create(Pass.prototype); 739 | FullBoxBlurPass.prototype.constructor = FullBoxBlurPass; 740 | 741 | FullBoxBlurPass.prototype.run = function(composer) { 742 | var s = this.params.amount; 743 | this.boxPass.params.delta.set( s, 0 ); 744 | composer.pass( this.boxPass ); 745 | this.boxPass.params.delta.set( 0, s ); 746 | composer.pass( this.boxPass ); 747 | }; 748 | 749 | 750 | /***/ }), 751 | /* 13 */ 752 | /***/ (function(module, exports, __webpack_require__) { 753 | 754 | "use strict"; 755 | 756 | 757 | var THREE = __webpack_require__(0); 758 | var Pass = __webpack_require__(1); 759 | var vertex = __webpack_require__(2); 760 | var fragment = __webpack_require__(14); 761 | 762 | function BoxBlurPass(deltaX, deltaY) { 763 | Pass.call(this); 764 | 765 | this.setShader(vertex, fragment); 766 | this.params.delta = new THREE.Vector2(deltaX || 0, deltaY || 0); 767 | } 768 | 769 | module.exports = BoxBlurPass; 770 | 771 | BoxBlurPass.prototype = Object.create(Pass.prototype); 772 | BoxBlurPass.prototype.constructor = BoxBlurPass; 773 | 774 | BoxBlurPass.prototype.run = function(composer) { 775 | this.shader.uniforms.delta.value.copy(this.params.delta); 776 | composer.pass(this.shader); 777 | 778 | }; 779 | 780 | 781 | /***/ }), 782 | /* 14 */ 783 | /***/ (function(module, exports) { 784 | 785 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\nuniform sampler2D tInput;\nuniform vec2 delta;\nuniform vec2 resolution;\n\nvoid main() {\n\n vec4 sum = vec4( 0. );\n vec2 inc = delta / resolution;\n\n sum += texture2D( tInput, ( vUv - inc * 4. ) ) * 0.051;\n sum += texture2D( tInput, ( vUv - inc * 3. ) ) * 0.0918;\n sum += texture2D( tInput, ( vUv - inc * 2. ) ) * 0.12245;\n sum += texture2D( tInput, ( vUv - inc * 1. ) ) * 0.1531;\n sum += texture2D( tInput, ( vUv + inc * 0. ) ) * 0.1633;\n sum += texture2D( tInput, ( vUv + inc * 1. ) ) * 0.1531;\n sum += texture2D( tInput, ( vUv + inc * 2. ) ) * 0.12245;\n sum += texture2D( tInput, ( vUv + inc * 3. ) ) * 0.0918;\n sum += texture2D( tInput, ( vUv + inc * 4. ) ) * 0.051;\n\n gl_FragColor = sum;\n\n}" 786 | 787 | /***/ }), 788 | /* 15 */ 789 | /***/ (function(module, exports, __webpack_require__) { 790 | 791 | "use strict"; 792 | 793 | 794 | var THREE = __webpack_require__(0); 795 | var Pass = __webpack_require__(1); 796 | var vertex = __webpack_require__(2); 797 | var fragment = __webpack_require__(16); 798 | 799 | function BlendPass(options) { 800 | Pass.call(this); 801 | 802 | options = options || {}; 803 | 804 | this.setShader(vertex, fragment); 805 | 806 | this.params.mode = options.mode || 1; 807 | this.params.opacity = options.opacity || 1; 808 | this.params.tInput2 = options.tInput2 || null; 809 | this.params.resolution2 = options.resolution2 || new THREE.Vector2(); 810 | this.params.sizeMode = options.sizeMode || 1; 811 | this.params.aspectRatio = options.aspectRatio || 1; 812 | this.params.aspectRatio2 = options.aspectRatio2 || 1; 813 | } 814 | 815 | module.exports = BlendPass; 816 | 817 | BlendPass.prototype = Object.create(Pass.prototype); 818 | BlendPass.prototype.constructor = BlendPass; 819 | 820 | BlendPass.prototype.run = function(composer) { 821 | this.shader.uniforms.mode.value = this.params.mode; 822 | this.shader.uniforms.opacity.value = this.params.opacity; 823 | this.shader.uniforms.tInput2.value = this.params.tInput2; 824 | this.shader.uniforms.sizeMode.value = this.params.sizeMode; 825 | this.shader.uniforms.aspectRatio.value = this.params.aspectRatio; 826 | this.shader.uniforms.aspectRatio2.value = this.params.aspectRatio2; 827 | composer.pass(this.shader); 828 | }; 829 | 830 | 831 | /***/ }), 832 | /* 16 */ 833 | /***/ (function(module, exports) { 834 | 835 | module.exports = "#define GLSLIFY 1\nvarying vec2 vUv;\nuniform sampler2D tInput;\nuniform sampler2D tInput2;\nuniform vec2 resolution;\nuniform vec2 resolution2;\nuniform float aspectRatio;\nuniform float aspectRatio2;\nuniform int mode;\nuniform int sizeMode;\nuniform float opacity;\n\nvec2 vUv2;\n\nfloat applyOverlayToChannel( float base, float blend ) {\n\n return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));\n\n}\n\nfloat applySoftLightToChannel( float base, float blend ) {\n\n return ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)));\n\n}\n\nfloat applyColorBurnToChannel( float base, float blend ) {\n\n return ((blend == 0.0) ? blend : max((1.0 - ((1.0 - base) / blend)), 0.0));\n\n}\n\nfloat applyColorDodgeToChannel( float base, float blend ) {\n\n return ((blend == 1.0) ? blend : min(base / (1.0 - blend), 1.0));\n\n}\n\nfloat applyLinearBurnToChannel( float base, float blend ) {\n\n return max(base + blend - 1., 0.0 );\n\n}\n\nfloat applyLinearDodgeToChannel( float base, float blend ) {\n\n return min( base + blend, 1. );\n\n}\n\nfloat applyLinearLightToChannel( float base, float blend ) {\n\n return ( blend < .5 ) ? applyLinearBurnToChannel( base, 2. * blend ) : applyLinearDodgeToChannel( base, 2. * ( blend - .5 ) );\n\n}\n\nvoid main() {\n\n vUv2 = vUv;\n \n if( sizeMode == 1 ) {\n \n if( aspectRatio2 > aspectRatio ) {\n vUv2.x = vUv.x * aspectRatio / aspectRatio2;\n vUv2.x += .5 * ( 1. - aspectRatio / aspectRatio2 ); \n vUv2.y = vUv.y;\n }\n\n if( aspectRatio2 < aspectRatio ) {\n vUv2.x = vUv.x;\n vUv2.y = vUv.y * aspectRatio2 / aspectRatio;\n vUv2.y += .5 * ( 1. - aspectRatio2 / aspectRatio );\n }\n\n }\n\n vec4 base = texture2D( tInput, vUv );\n vec4 blend = texture2D( tInput2, vUv2 );\n\n if( mode == 1 ) { // normal\n\n gl_FragColor = base;\n gl_FragColor.a *= opacity;\n return;\n\n }\n\n if( mode == 2 ) { // dissolve\n\n }\n\n if( mode == 3 ) { // darken\n\n gl_FragColor = min( base, blend );\n return;\n\n }\n\n if( mode == 4 ) { // multiply\n\n gl_FragColor = base * blend;\n return;\n\n }\n\n if( mode == 5 ) { // color burn\n\n gl_FragColor = vec4(\n applyColorBurnToChannel( base.r, blend.r ),\n applyColorBurnToChannel( base.g, blend.g ),\n applyColorBurnToChannel( base.b, blend.b ),\n applyColorBurnToChannel( base.a, blend.a )\n );\n return;\n\n }\n\n if( mode == 6 ) { // linear burn\n\n gl_FragColor = max(base + blend - 1.0, 0.0);\n return;\n\n }\n\n if( mode == 7 ) { // darker color\n\n }\n\n if( mode == 8 ) { // lighten\n\n gl_FragColor = max( base, blend );\n return;\n\n }\n\n if( mode == 9 ) { // screen\n\n gl_FragColor = (1.0 - ((1.0 - base) * (1.0 - blend)));\n gl_FragColor = gl_FragColor * opacity + base * ( 1. - opacity );\n return;\n\n }\n\n if( mode == 10 ) { // color dodge\n\n gl_FragColor = vec4(\n applyColorDodgeToChannel( base.r, blend.r ),\n applyColorDodgeToChannel( base.g, blend.g ),\n applyColorDodgeToChannel( base.b, blend.b ),\n applyColorDodgeToChannel( base.a, blend.a )\n );\n return;\n\n }\n\n if( mode == 11 ) { // linear dodge\n\n gl_FragColor = min(base + blend, 1.0);\n return;\n\n }\n\n if( mode == 12 ) { // lighter color\n\n }\n\n if( mode == 13 ) { // overlay\n\n gl_FragColor = gl_FragColor = vec4( \n applyOverlayToChannel( base.r, blend.r ),\n applyOverlayToChannel( base.g, blend.g ),\n applyOverlayToChannel( base.b, blend.b ),\n applyOverlayToChannel( base.a, blend.a )\n );\n gl_FragColor = gl_FragColor * opacity + base * ( 1. - opacity );\n \n return;\n\n }\n\n if( mode == 14 ) { // soft light\n\n gl_FragColor = vec4( \n applySoftLightToChannel( base.r, blend.r ),\n applySoftLightToChannel( base.g, blend.g ),\n applySoftLightToChannel( base.b, blend.b ),\n applySoftLightToChannel( base.a, blend.a )\n );\n return;\n\n }\n\n if( mode == 15 ) { // hard light\n\n gl_FragColor = vec4( \n applyOverlayToChannel( base.r, blend.r ),\n applyOverlayToChannel( base.g, blend.g ),\n applyOverlayToChannel( base.b, blend.b ),\n applyOverlayToChannel( base.a, blend.a )\n );\n gl_FragColor = gl_FragColor * opacity + base * ( 1. - opacity );\n return;\n\n }\n\n if( mode == 16 ) { // vivid light\n\n }\n\n if( mode == 17 ) { // linear light\n\n gl_FragColor = vec4( \n applyLinearLightToChannel( base.r, blend.r ),\n applyLinearLightToChannel( base.g, blend.g ),\n applyLinearLightToChannel( base.b, blend.b ),\n applyLinearLightToChannel( base.a, blend.a )\n );\n return;\n\n }\n\n if( mode == 18 ) { // pin light\n\n }\n\n if( mode == 19 ) { // hard mix\n\n }\n\n if( mode == 20 ) { // difference\n\n gl_FragColor = abs( base - blend );\n gl_FragColor.a = base.a + blend.b;\n return;\n\n }\n\n if( mode == 21 ) { // exclusion\n\n gl_FragColor = base + blend - 2. * base * blend;\n \n }\n\n if( mode == 22 ) { // substract\n\n }\n\n if( mode == 23 ) { // divide\n\n }\n\n gl_FragColor = vec4( 1., 0., 1., 1. );\n\n}" 836 | 837 | /***/ }), 838 | /* 17 */ 839 | /***/ (function(module, exports, __webpack_require__) { 840 | 841 | "use strict"; 842 | 843 | 844 | var THREE = __webpack_require__(0); 845 | var Pass = __webpack_require__(1); 846 | var vertex = __webpack_require__(2); 847 | var fragment = __webpack_require__(18); 848 | 849 | function ZoomBlurPass(options) { 850 | Pass.call(this); 851 | 852 | options = options || {}; 853 | 854 | this.setShader(vertex, fragment); 855 | 856 | this.params.center = new THREE.Vector2(options.centerX || 0.5, options.centerY || 0.5); 857 | this.params.strength = options.strength || 0.1; 858 | } 859 | 860 | module.exports = ZoomBlurPass; 861 | 862 | ZoomBlurPass.prototype = Object.create(Pass.prototype); 863 | ZoomBlurPass.prototype.constructor = ZoomBlurPass; 864 | 865 | ZoomBlurPass.prototype.run = function(composer) { 866 | this.shader.uniforms.center.value.set(composer.width * this.params.center.x, composer.height * this.params.center.y); 867 | this.shader.uniforms.strength.value = this.params.strength; 868 | composer.pass(this.shader); 869 | }; 870 | 871 | 872 | /***/ }), 873 | /* 18 */ 874 | /***/ (function(module, exports) { 875 | 876 | module.exports = "#define GLSLIFY 1\nuniform sampler2D tInput;\nuniform vec2 center;\nuniform float strength;\nuniform vec2 resolution;\nvarying vec2 vUv;\n\nfloat random(vec3 scale,float seed){return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);}\n\nvoid main(){\n vec4 color=vec4(0.0);\n float total=0.0;\n vec2 toCenter=center-vUv*resolution;\n float offset=random(vec3(12.9898,78.233,151.7182),0.0);\n for(float t=0.0;t<=40.0;t++){\n float percent=(t+offset)/40.0;\n float weight=4.0*(percent-percent*percent);\n vec4 sample=texture2D(tInput,vUv+toCenter*percent*strength/resolution);\n sample.rgb*=sample.a;\n color+=sample*weight;\n total+=weight;\n }\n gl_FragColor=color/total;\n gl_FragColor.rgb/=gl_FragColor.a+0.00001;\n}" 877 | 878 | /***/ }), 879 | /* 19 */ 880 | /***/ (function(module, exports, __webpack_require__) { 881 | 882 | "use strict"; 883 | 884 | 885 | var Pass = __webpack_require__(1); 886 | var vertex = __webpack_require__(2); 887 | var fragment = __webpack_require__(20); 888 | 889 | function BrightnessContrastPass(brightness, contrast) { 890 | Pass.call(this); 891 | 892 | this.setShader(vertex, fragment); 893 | 894 | this.params.brightness = brightness || 1; 895 | this.params.contrast = contrast || 1; 896 | } 897 | 898 | module.exports = BrightnessContrastPass; 899 | 900 | BrightnessContrastPass.prototype = Object.create(Pass.prototype); 901 | BrightnessContrastPass.prototype.constructor = BrightnessContrastPass; 902 | 903 | BrightnessContrastPass.prototype.run = function(composer) { 904 | this.shader.uniforms.brightness.value = this.params.brightness; 905 | this.shader.uniforms.contrast.value = this.params.contrast; 906 | composer.pass(this.shader); 907 | }; 908 | 909 | 910 | /***/ }), 911 | /* 20 */ 912 | /***/ (function(module, exports) { 913 | 914 | module.exports = "#define GLSLIFY 1\nuniform float brightness;\nuniform float contrast;\nuniform sampler2D tInput;\n\nvarying vec2 vUv;\n\nvoid main() {\n\n vec3 color = texture2D(tInput, vUv).rgb;\n vec3 colorContrasted = (color) * contrast;\n vec3 bright = colorContrasted + vec3(brightness,brightness,brightness);\n gl_FragColor.rgb = bright;\n gl_FragColor.a = 1.;\n\n}" 915 | 916 | /***/ }), 917 | /* 21 */, 918 | /* 22 */, 919 | /* 23 */, 920 | /* 24 */, 921 | /* 25 */, 922 | /* 26 */, 923 | /* 27 */ 924 | /***/ (function(module, exports, __webpack_require__) { 925 | 926 | "use strict"; 927 | 928 | 929 | Object.defineProperty(exports, "__esModule", { 930 | value: true 931 | }); 932 | 933 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 934 | 935 | var _three = __webpack_require__(0); 936 | 937 | var _ThreeApp2 = __webpack_require__(6); 938 | 939 | var _ThreeApp3 = _interopRequireDefault(_ThreeApp2); 940 | 941 | var _wagner = __webpack_require__(4); 942 | 943 | var _wagner2 = _interopRequireDefault(_wagner); 944 | 945 | var _MultiPassBloomPass = __webpack_require__(11); 946 | 947 | var _MultiPassBloomPass2 = _interopRequireDefault(_MultiPassBloomPass); 948 | 949 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 950 | 951 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 952 | 953 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 954 | 955 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 956 | 957 | var count = 400; 958 | var points = 100; 959 | 960 | var Experiment = function (_ThreeApp) { 961 | _inherits(Experiment, _ThreeApp); 962 | 963 | function Experiment() { 964 | _classCallCheck(this, Experiment); 965 | 966 | return _possibleConstructorReturn(this, (Experiment.__proto__ || Object.getPrototypeOf(Experiment)).apply(this, arguments)); 967 | } 968 | 969 | _createClass(Experiment, [{ 970 | key: 'init', 971 | value: function init() { 972 | this.renderer.setClearColor(0x111111); 973 | this.curves = []; 974 | 975 | for (var i = 0; i < count; i++) { 976 | var curve = new _three.EllipseCurve(0, 0, 2, 2, 0, 2 * Math.PI, false, 0); 977 | var path = new _three.Path(curve.getPoints(points)); 978 | var geo = path.createPointsGeometry(points); 979 | var c = i / count * 360 / 1.9; 980 | var mat = new _three.LineBasicMaterial({ 981 | color: new _three.Color('hsl(' + c + ', 100%, 50%)'), 982 | transparent: true, 983 | depthWrite: false, 984 | blending: _three.AdditiveBlending, 985 | opacity: 0.4 986 | }); 987 | var line = new _three.Line(geo, mat); 988 | this.curves.push(line); 989 | this.scene.add(line); 990 | } 991 | 992 | this.camera.position.set(0, 0, 5); 993 | 994 | this.pivot = new _three.Object3D(); 995 | this.pivot.add(this.camera); 996 | this.scene.add(this.pivot); 997 | 998 | this.composer = new _wagner2.default.Composer(this.renderer); 999 | this.pass = new _MultiPassBloomPass2.default({ 1000 | zoomBlurStrength: 0.05, 1001 | applyZoomBlur: true, 1002 | blurAmount: 0.2 1003 | }); 1004 | } 1005 | }, { 1006 | key: 'update', 1007 | value: function update(t, delta) { 1008 | for (var i = 0; i < count; i++) { 1009 | var curve = this.curves[i]; 1010 | var pct = i / count; 1011 | var scale = (Math.sin(t * 0.0001 + pct * Math.PI * 2) + 1) / 2; 1012 | curve.scale.set(scale, scale, scale); 1013 | curve.rotation.z = t * 0.00001 + pct * 2; 1014 | curve.rotation.y = t * 0.001 + pct * Math.PI * 2; 1015 | curve.rotation.x = t * 0.001 + pct * Math.PI * 2 + Math.PI / 2; 1016 | } 1017 | this.pivot.rotation.y = -t * 0.001; 1018 | } 1019 | }, { 1020 | key: 'render', 1021 | value: function render() { 1022 | this.renderer.clearColor(); 1023 | this.composer.reset(); 1024 | this.composer.render(this.scene, this.camera); 1025 | this.composer.pass(this.pass); 1026 | this.composer.toScreen(); 1027 | } 1028 | }]); 1029 | 1030 | return Experiment; 1031 | }(_ThreeApp3.default); 1032 | 1033 | exports.default = new Experiment(); 1034 | 1035 | /***/ }) 1036 | /******/ ]); 1037 | }); -------------------------------------------------------------------------------- /public/scripts/dat.gui.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.dat=t():e.dat=t()}(this,function(){return function(e){function t(o){if(n[o])return n[o].exports;var i=n[o]={exports:{},id:o,loaded:!1};return e[o].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(1),r=o(i);t.default=r.default,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(2),r=o(i),a=n(6),l=o(a),s=n(3),u=o(s),d=n(7),c=o(d),f=n(8),_=o(f),p=n(10),h=o(p),m=n(11),b=o(m),g=n(12),v=o(g),y=n(13),w=o(y),x=n(14),E=o(x),C=n(15),A=o(C),S=n(16),k=o(S),O=n(9),T=o(O),R=n(17),L=o(R);t.default={color:{Color:r.default,math:l.default,interpret:u.default},controllers:{Controller:c.default,BooleanController:_.default,OptionController:h.default,StringController:b.default,NumberController:v.default,NumberControllerBox:w.default,NumberControllerSlider:E.default,FunctionController:A.default,ColorController:k.default},dom:{dom:T.default},gui:{GUI:L.default},GUI:L.default},e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(h.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(h.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function a(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(h.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(h.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}t.__esModule=!0;var l=n(3),s=o(l),u=n(6),d=o(u),c=n(4),f=o(c),_=n(5),p=o(_),h=function(){function e(){if(i(this,e),this.__state=s.default.apply(this,arguments),this.__state===!1)throw new Error("Failed to interpret color arguments");this.__state.a=this.__state.a||1}return e.prototype.toString=function(){return(0,f.default)(this)},e.prototype.toHexString=function(){return(0,f.default)(this,!0)},e.prototype.toOriginal=function(){return this.__state.conversion.write(this)},e}();h.recalculateRGB=function(e,t,n){if("HEX"===e.__state.space)e.__state[t]=d.default.component_from_hex(e.__state.hex,n);else{if("HSV"!==e.__state.space)throw new Error("Corrupted color state");p.default.extend(e.__state,d.default.hsv_to_rgb(e.__state.h,e.__state.s,e.__state.v))}},h.recalculateHSV=function(e){var t=d.default.rgb_to_hsv(e.r,e.g,e.b);p.default.extend(e.__state,{s:t.s,v:t.v}),p.default.isNaN(t.h)?p.default.isUndefined(e.__state.h)&&(e.__state.h=0):e.__state.h=t.h},h.COMPONENTS=["r","g","b","h","s","v","hex","a"],r(h.prototype,"r",2),r(h.prototype,"g",1),r(h.prototype,"b",0),a(h.prototype,"h"),a(h.prototype,"s"),a(h.prototype,"v"),Object.defineProperty(h.prototype,"a",{get:function(){return this.__state.a},set:function(e){this.__state.a=e}}),Object.defineProperty(h.prototype,"hex",{get:function(){return"HEX"!==!this.__state.space&&(this.__state.hex=d.default.rgb_to_hex(this.r,this.g,this.b)),this.__state.hex},set:function(e){this.__state.space="HEX",this.__state.hex=e}}),t.default=h,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(4),r=o(i),a=n(5),l=o(a),s=[{litmus:l.default.isString,conversions:{THREE_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString()+t[1].toString()+t[2].toString()+t[2].toString()+t[3].toString()+t[3].toString(),0)}},write:r.default},SIX_CHAR_HEX:{read:function(e){var t=e.match(/^#([A-F0-9]{6})$/i);return null!==t&&{space:"HEX",hex:parseInt("0x"+t[1].toString(),0)}},write:r.default},CSS_RGB:{read:function(e){var t=e.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3])}},write:r.default},CSS_RGBA:{read:function(e){var t=e.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);return null!==t&&{space:"RGB",r:parseFloat(t[1]),g:parseFloat(t[2]),b:parseFloat(t[3]),a:parseFloat(t[4])}},write:r.default}}},{litmus:l.default.isNumber,conversions:{HEX:{read:function(e){return{space:"HEX",hex:e,conversionName:"HEX"}},write:function(e){return e.hex}}}},{litmus:l.default.isArray,conversions:{RGB_ARRAY:{read:function(e){return 3===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2]}},write:function(e){return[e.r,e.g,e.b]}},RGBA_ARRAY:{read:function(e){return 4===e.length&&{space:"RGB",r:e[0],g:e[1],b:e[2],a:e[3]}},write:function(e){return[e.r,e.g,e.b,e.a]}}}},{litmus:l.default.isObject,conversions:{RGBA_OBJ:{read:function(e){return!!(l.default.isNumber(e.r)&&l.default.isNumber(e.g)&&l.default.isNumber(e.b)&&l.default.isNumber(e.a))&&{space:"RGB",r:e.r,g:e.g,b:e.b,a:e.a}},write:function(e){return{r:e.r,g:e.g,b:e.b,a:e.a}}},RGB_OBJ:{read:function(e){return!!(l.default.isNumber(e.r)&&l.default.isNumber(e.g)&&l.default.isNumber(e.b))&&{space:"RGB",r:e.r,g:e.g,b:e.b}},write:function(e){return{r:e.r,g:e.g,b:e.b}}},HSVA_OBJ:{read:function(e){return!!(l.default.isNumber(e.h)&&l.default.isNumber(e.s)&&l.default.isNumber(e.v)&&l.default.isNumber(e.a))&&{space:"HSV",h:e.h,s:e.s,v:e.v,a:e.a}},write:function(e){return{h:e.h,s:e.s,v:e.v,a:e.a}}},HSV_OBJ:{read:function(e){return!!(l.default.isNumber(e.h)&&l.default.isNumber(e.s)&&l.default.isNumber(e.v))&&{space:"HSV",h:e.h,s:e.s,v:e.v}},write:function(e){return{h:e.h,s:e.s,v:e.v}}}}}],u=void 0,d=void 0,c=function(){d=!1;var e=arguments.length>1?l.default.toArray(arguments):arguments[0];return l.default.each(s,function(t){if(t.litmus(e))return l.default.each(t.conversions,function(t,n){if(u=t.read(e),d===!1&&u!==!1)return d=u,u.conversionName=n,u.conversion=t,l.default.BREAK}),l.default.BREAK}),d};t.default=c,e.exports=t.default},function(e,t){"use strict";t.__esModule=!0,t.default=function(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),a=e.a,l=Math.round(e.h),s=e.s.toFixed(1),u=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var d=e.hex.toString(16);d.length<6;)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+"}":"HSVA_OBJ"===n?"{h:"+l+",s:"+s+",v:"+u+",a:"+a+"}":"unknown format"},e.exports=t.default},function(e,t){"use strict";t.__esModule=!0;var n=Array.prototype.forEach,o=Array.prototype.slice,i={BREAK:{},extend:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))},this),e},defaults:function(e){return this.each(o.call(arguments,1),function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))},this),e},compose:function(){var e=o.call(arguments);return function(){for(var t=o.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,o){if(e)if(n&&e.forEach&&e.forEach===n)e.forEach(t,o);else if(e.length===e.length+0){var i=void 0,r=void 0;for(i=0,r=e.length;i>8*t&255},hex_with_component:function(e,t,o){return o<<(n=8*t)|e&~(255<-1?t.length-t.indexOf(".")-1:0}t.__esModule=!0;var s=n(7),u=o(s),d=n(5),c=o(d),f=function(e){function t(n,o,a){i(this,t);var s=r(this,e.call(this,n,o)),u=a||{};return s.__min=u.min,s.__max=u.max,s.__step=u.step,c.default.isUndefined(s.__step)?0===s.initialValue?s.__impliedStep=1:s.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(s.initialValue))/Math.LN10))/10:s.__impliedStep=s.__step,s.__precision=l(s.__impliedStep),s}return a(t,e),t.prototype.setValue=function(t){var n=t;return void 0!==this.__min&&nthis.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),e.prototype.setValue.call(this,n)},t.prototype.min=function(e){return this.__min=e,this},t.prototype.max=function(e){return this.__max=e,this},t.prototype.step=function(e){return this.__step=e,this.__impliedStep=e,this.__precision=l(e),this},t}(u.default);t.default=f,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=n(5),_=o(f),p=function(e){function t(n,o,a){function l(){var e=parseFloat(m.__input.value);_.default.isNaN(e)||m.setValue(e)}function s(){m.__onFinishChange&&m.__onFinishChange.call(m,m.getValue())}function u(){s()}function d(e){var t=b-e.clientY;m.setValue(m.getValue()+t*m.__impliedStep),b=e.clientY}function f(){c.default.unbind(window,"mousemove",d),c.default.unbind(window,"mouseup",f),s()}function p(e){c.default.bind(window,"mousemove",d),c.default.bind(window,"mouseup",f),b=e.clientY}i(this,t);var h=r(this,e.call(this,n,o,a));h.__truncationSuspended=!1;var m=h,b=void 0;return h.__input=document.createElement("input"),h.__input.setAttribute("type","text"),c.default.bind(h.__input,"change",l),c.default.bind(h.__input,"blur",u),c.default.bind(h.__input,"mousedown",p),c.default.bind(h.__input,"keydown",function(e){13===e.keyCode&&(m.__truncationSuspended=!0,this.blur(),m.__truncationSuspended=!1,s())}),h.updateDisplay(),h.domElement.appendChild(h.__input),h}return a(t,e),t.prototype.updateDisplay=function(){return this.__input.value=this.__truncationSuspended?this.getValue():l(this.getValue(),this.__precision),e.prototype.updateDisplay.call(this)},t}(u.default);t.default=p,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o,i){return o+(i-o)*((e-t)/(n-t))}t.__esModule=!0;var s=n(12),u=o(s),d=n(9),c=o(d),f=function(e){function t(n,o,a,s,u){function d(e){document.activeElement.blur(),c.default.bind(window,"mousemove",f),c.default.bind(window,"mouseup",_),f(e)}function f(e){e.preventDefault();var t=h.__background.getBoundingClientRect();return h.setValue(l(e.clientX,t.left,t.right,h.__min,h.__max)),!1}function _(){c.default.unbind(window,"mousemove",f),c.default.unbind(window,"mouseup",_),h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}i(this,t);var p=r(this,e.call(this,n,o,{min:a,max:s,step:u})),h=p;return p.__background=document.createElement("div"),p.__foreground=document.createElement("div"),c.default.bind(p.__background,"mousedown",d),c.default.addClass(p.__background,"slider"),c.default.addClass(p.__foreground,"slider-fg"),p.updateDisplay(),p.__background.appendChild(p.__foreground),p.domElement.appendChild(p.__background),p}return a(t,e),t.prototype.updateDisplay=function(){var t=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*t+"%",e.prototype.updateDisplay.call(this)},t}(u.default);t.default=f,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}t.__esModule=!0;var l=n(7),s=o(l),u=n(9),d=o(u),c=function(e){function t(n,o,a){i(this,t);var l=r(this,e.call(this,n,o)),s=l;return l.__button=document.createElement("div"),l.__button.innerHTML=void 0===a?"Fire":a,d.default.bind(l.__button,"click",function(e){return e.preventDefault(),s.fire(),!1}),d.default.addClass(l.__button,"button"),l.domElement.appendChild(l.__button),l}return a(t,e),t.prototype.fire=function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())},t}(s.default);t.default=c,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function r(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t,n,o){e.style.background="",g.default.each(y,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function s(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}t.__esModule=!0;var u=n(7),d=o(u),c=n(9),f=o(c),_=n(2),p=o(_),h=n(3),m=o(h),b=n(5),g=o(b),v=function(e){function t(n,o){function a(e){h(e),f.default.bind(window,"mousemove",h),f.default.bind(window,"mouseup",u)}function u(){f.default.unbind(window,"mousemove",h),f.default.unbind(window,"mouseup",u),_()}function d(){var e=(0,m.default)(this.value);e!==!1?(y.__color.__state=e,y.setValue(y.__color.toOriginal())):this.value=y.__color.toString()}function c(){f.default.unbind(window,"mousemove",b),f.default.unbind(window,"mouseup",c),_()}function _(){y.__onFinishChange&&y.__onFinishChange.call(y,y.__color.toOriginal())}function h(e){e.preventDefault();var t=y.__saturation_field.getBoundingClientRect(),n=(e.clientX-t.left)/(t.right-t.left),o=1-(e.clientY-t.top)/(t.bottom-t.top);return o>1?o=1:o<0&&(o=0),n>1?n=1:n<0&&(n=0),y.__color.v=o,y.__color.s=n,y.setValue(y.__color.toOriginal()),!1}function b(e){e.preventDefault();var t=y.__hue_field.getBoundingClientRect(),n=1-(e.clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),y.__color.h=360*n,y.setValue(y.__color.toOriginal()),!1}i(this,t);var v=r(this,e.call(this,n,o));v.__color=new p.default(v.getValue()),v.__temp=new p.default(0);var y=v;v.domElement=document.createElement("div"),f.default.makeSelectable(v.domElement,!1),v.__selector=document.createElement("div"),v.__selector.className="selector",v.__saturation_field=document.createElement("div"),v.__saturation_field.className="saturation-field",v.__field_knob=document.createElement("div"),v.__field_knob.className="field-knob",v.__field_knob_border="2px solid ",v.__hue_knob=document.createElement("div"),v.__hue_knob.className="hue-knob",v.__hue_field=document.createElement("div"),v.__hue_field.className="hue-field",v.__input=document.createElement("input"),v.__input.type="text",v.__input_textShadow="0 1px 1px ",f.default.bind(v.__input,"keydown",function(e){13===e.keyCode&&d.call(this)}),f.default.bind(v.__input,"blur",d),f.default.bind(v.__selector,"mousedown",function(){f.default.addClass(this,"drag").bind(window,"mouseup",function(){f.default.removeClass(y.__selector,"drag")})});var w=document.createElement("div");return g.default.extend(v.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),g.default.extend(v.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:v.__field_knob_border+(v.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),g.default.extend(v.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),g.default.extend(v.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),g.default.extend(w.style,{width:"100%",height:"100%",background:"none"}),l(w,"top","rgba(0,0,0,0)","#000"),g.default.extend(v.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),s(v.__hue_field),g.default.extend(v.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:v.__input_textShadow+"rgba(0,0,0,0.7)"}),f.default.bind(v.__saturation_field,"mousedown",a),f.default.bind(v.__field_knob,"mousedown",a),f.default.bind(v.__hue_field,"mousedown",function(e){b(e),f.default.bind(window,"mousemove",b),f.default.bind(window,"mouseup",c)}),v.__saturation_field.appendChild(w),v.__selector.appendChild(v.__field_knob),v.__selector.appendChild(v.__saturation_field),v.__selector.appendChild(v.__hue_field),v.__hue_field.appendChild(v.__hue_knob),v.domElement.appendChild(v.__input),v.domElement.appendChild(v.__selector),v.updateDisplay(),v}return a(t,e),t.prototype.updateDisplay=function(){var e=(0,m.default)(this.getValue());if(e!==!1){var t=!1;g.default.each(p.default.COMPONENTS,function(n){if(!g.default.isUndefined(e[n])&&!g.default.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&g.default.extend(this.__color.__state,e)}g.default.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;g.default.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),g.default.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})},t}(d.default),y=["-moz-","-o-","-webkit-","-ms-",""];t.default=v,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function r(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];t?n.innerHTML=n.value+"*":n.innerHTML=n.value}function a(e,t,n){if(n.__li=t,n.__gui=e,U.default.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:o,factoryArgs:[U.default.toArray(arguments)]})}if(U.default.isArray(t)||U.default.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),s(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof N.default){var o=new B.default(n.object,n.property,{ 2 | min:n.__min,max:n.__max,step:n.__step});U.default.each(["updateDisplay","onChange","onFinishChange","step"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),z.default.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof B.default){var i=function(t){if(U.default.isNumber(n.__min)&&U.default.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=s(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=U.default.compose(i,n.min),n.max=U.default.compose(i,n.max)}else n instanceof O.default?(z.default.bind(t,"click",function(){z.default.fakeEvent(n.__checkbox,"click")}),z.default.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof R.default?(z.default.bind(t,"click",function(){z.default.fakeEvent(n.__button,"click")}),z.default.bind(t,"mouseover",function(){z.default.addClass(n.__button,"hover")}),z.default.bind(t,"mouseout",function(){z.default.removeClass(n.__button,"hover")})):n instanceof j.default&&(z.default.addClass(t,"color"),n.updateDisplay=U.default.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=U.default.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&r(e.getRoot(),!0),t},n.setValue)}function l(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(o!==-1){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[Q])return;a=r[Q]}if(a[o]&&void 0!==a[o][t.property]){var l=a[o][t.property];t.initialValue=l,t.setValue(l)}}}}function s(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var r=void 0;if(o.color)r=new j.default(t,n);else{var s=[t,n].concat(o.factoryArgs);r=C.default.apply(e,s)}o.before instanceof S.default&&(o.before=o.before.__li),l(e,r),z.default.addClass(r.domElement,"c");var u=document.createElement("span");z.default.addClass(u,"property-name"),u.innerHTML=r.property;var d=document.createElement("div");d.appendChild(u),d.appendChild(r.domElement);var c=i(e,d,o.before);return z.default.addClass(c,oe.CLASS_CONTROLLER_ROW),r instanceof j.default?z.default.addClass(c,"color"):z.default.addClass(c,g(r.getValue())),a(e,c,r),e.__controllers.push(r),r}function u(e,t){return document.location.href+"."+t}function d(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function c(e,t){t.style.display=e.useLocalStorage?"block":"none"}function f(e){var t=e.__save_row=document.createElement("li");z.default.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),z.default.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",z.default.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",z.default.addClass(o,"button"),z.default.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",z.default.addClass(i,"button"),z.default.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",z.default.addClass(r,"button"),z.default.addClass(r,"revert");var a=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?U.default.each(e.load.remembered,function(t,n){d(e,n,n===e.preset)}):d(e,Q,!1),z.default.bind(a,"change",function(){for(var t=0;t0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=h(this)),e.folders={},U.default.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=h(this),r(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[Q]=h(this,!0)),this.load.remembered[e]=h(this),this.preset=e,d(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){U.default.each(this.__controllers,function(t){this.getRoot().load.remembered?l(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),U.default.each(this.__folders,function(e){e.revert(e)}),e||r(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&b(this.__listening)},updateDisplay:function(){U.default.each(this.__controllers,function(e){e.updateDisplay()}),U.default.each(this.__folders,function(e){e.updateDisplay()})}}),t.default=oe,e.exports=t.default},function(e,t){"use strict";e.exports={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}}},function(e,t){e.exports="
Here's the new load parameter for your GUI's constructor:
Automatically save values to localStorage on exit.
The values saved to localStorage will override those passed to dat.GUI's constructor. This makes it easier to work incrementally, but localStorage is fragile, and your friends may not see the same values you do.
"},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}t.__esModule=!0;var i=n(10),r=o(i),a=n(13),l=o(a),s=n(14),u=o(s),d=n(11),c=o(d),f=n(15),_=o(f),p=n(8),h=o(p),m=n(5),b=o(m),g=function(e,t){var n=e[t];return b.default.isArray(arguments[2])||b.default.isObject(arguments[2])?new r.default(e,t,arguments[2]):b.default.isNumber(n)?b.default.isNumber(arguments[2])&&b.default.isNumber(arguments[3])?b.default.isNumber(arguments[4])?new u.default(e,t,arguments[2],arguments[3],arguments[4]):new u.default(e,t,arguments[2],arguments[3]):b.default.isNumber(arguments[4])?new l.default(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new l.default(e,t,{min:arguments[2],max:arguments[3]}):b.default.isString(n)?new c.default(e,t):b.default.isFunction(n)?new _.default(e,t,""):b.default.isBoolean(n)?new h.default(e,t):null};t.default=g,e.exports=t.default},function(e,t){"use strict";function n(e){setTimeout(e,1e3/60)}t.__esModule=!0,t.default=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||n,e.exports=t.default},function(e,t,n){"use strict";function o(e){return e&&e.__esModule?e:{default:e}}function i(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}t.__esModule=!0;var r=n(9),a=o(r),l=n(5),s=o(l),u=function(){function e(){i(this,e),this.backgroundElement=document.createElement("div"),s.default.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),a.default.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),s.default.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;a.default.bind(this.backgroundElement,"click",function(){t.hide()})}return e.prototype.show=function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),s.default.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})},e.prototype.hide=function e(){var t=this,e=function e(){t.domElement.style.display="none",t.backgroundElement.style.display="none",a.default.unbind(t.domElement,"webkitTransitionEnd",e),a.default.unbind(t.domElement,"transitionend",e),a.default.unbind(t.domElement,"oTransitionEnd",e)};a.default.bind(this.domElement,"webkitTransitionEnd",e),a.default.bind(this.domElement,"transitionend",e),a.default.bind(this.domElement,"oTransitionEnd",e),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"},e.prototype.layout=function(){this.domElement.style.left=window.innerWidth/2-a.default.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-a.default.getHeight(this.domElement)/2+"px"},e}();t.default=u,e.exports=t.default},function(e,t,n){t=e.exports=n(24)(),t.push([e.id,".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1!important}.dg.main .close-button.drag,.dg.main:hover .close-button{opacity:1}.dg.main .close-button{transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{transition:height .1s ease-out;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid transparent}.dg li.title{margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.boolean,.dg .cr.boolean *,.dg .cr.function,.dg .cr.function *,.dg .cr.function .property-name{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco,monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px Lucida Grande,sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid hsla(0,0%,100%,.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2fa1d6}.dg .cr.number input[type=text]{color:#2fa1d6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.boolean:hover,.dg .cr.function:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2fa1d6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}",""])},function(e,t){e.exports=function(){var e=[];return e.toString=function(){for(var e=[],t=0;t