├── README.md ├── alien-strands └── index.html ├── assets ├── Clouds.png ├── Multi-Area-Light.jpg ├── cloud.png ├── clouds.jpg ├── gioconda.jpg ├── gioconda.png ├── gioconda32.jpg ├── gradient1.jpg ├── map-color.jpg ├── map-composite.jpg ├── matcap.jpg ├── matcap2.jpg ├── matcap3.jpg ├── milkmaid.jpg ├── milkmaid.png ├── milkmaid32.jpg ├── noise.png ├── pearl.jpg ├── pearl.png ├── pearl32.jpg ├── pumice │ ├── diffuse.png │ ├── height.png │ ├── normal.jpg │ ├── normal.png │ ├── specular.jpg │ └── specular.png ├── stroke.png ├── vincent.jpg ├── vincent.png └── white-construction-paper-texture.jpg ├── base └── index.html ├── bonkey-balls └── index.html ├── chromeography └── index.html ├── css └── styles.css ├── curl-scribbles └── index.html ├── digital-analog-color-display ├── index copy.html ├── index-shadow.html └── index.html ├── dotty-earth └── index.html ├── gi └── index.html ├── glow-worms ├── index.html └── mrf.html ├── holomap └── index.html ├── index.html ├── js ├── Backdrop.js ├── Bloom.js ├── CCapture.all.min.js ├── Common.js ├── CubemapToEquirectangular.js ├── EquirectangularToCubemap.js ├── ImprovedNoise.js ├── Maf.js ├── MeshCustomMaterial.js ├── OBJLoader.js ├── Odeo.js ├── OrbitControls.js ├── THREE.FBOHelper.js ├── THREE.MeshLine.js ├── THREE.PingPongTexture.js ├── THREE.ShaderTexture.js ├── dat.gui.min.js ├── isMobile.min.js ├── oimo.js ├── oimo.min.js ├── perlin.js ├── three.js └── three.min.js ├── plasma-waves ├── index copy.html └── index.html ├── rainbow-spikeball └── index.html ├── sdf-physics └── index.html ├── shredder-redux └── index.html ├── sound-waves └── index.html ├── sphere-carving └── index.html ├── supershape ├── index.html └── pervertex.html ├── terrain └── index.html ├── the-wrung-music └── index.html └── whirly-bonfire ├── index copy.html └── index.html /README.md: -------------------------------------------------------------------------------- 1 | # codevember-2017 2 | 3 | Experiments for Codevember 2017 4 | 5 | See also: [Codevember 2016](https://github.com/spite/codevember-2016) 6 | 7 | # License 8 | 9 | [Attribution CC BY](https://creativecommons.org/licenses/by/4.0/) 10 | 11 | This license lets others distribute, remix, tweak, and build upon your work, even commercially, as long as they credit you for the original creation. 12 | -------------------------------------------------------------------------------- /assets/Clouds.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/Clouds.png -------------------------------------------------------------------------------- /assets/Multi-Area-Light.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/Multi-Area-Light.jpg -------------------------------------------------------------------------------- /assets/cloud.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/cloud.png -------------------------------------------------------------------------------- /assets/clouds.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/clouds.jpg -------------------------------------------------------------------------------- /assets/gioconda.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/gioconda.jpg -------------------------------------------------------------------------------- /assets/gioconda.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/gioconda.png -------------------------------------------------------------------------------- /assets/gioconda32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/gioconda32.jpg -------------------------------------------------------------------------------- /assets/gradient1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/gradient1.jpg -------------------------------------------------------------------------------- /assets/map-color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/map-color.jpg -------------------------------------------------------------------------------- /assets/map-composite.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/map-composite.jpg -------------------------------------------------------------------------------- /assets/matcap.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/matcap.jpg -------------------------------------------------------------------------------- /assets/matcap2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/matcap2.jpg -------------------------------------------------------------------------------- /assets/matcap3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/matcap3.jpg -------------------------------------------------------------------------------- /assets/milkmaid.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/milkmaid.jpg -------------------------------------------------------------------------------- /assets/milkmaid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/milkmaid.png -------------------------------------------------------------------------------- /assets/milkmaid32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/milkmaid32.jpg -------------------------------------------------------------------------------- /assets/noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/noise.png -------------------------------------------------------------------------------- /assets/pearl.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pearl.jpg -------------------------------------------------------------------------------- /assets/pearl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pearl.png -------------------------------------------------------------------------------- /assets/pearl32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pearl32.jpg -------------------------------------------------------------------------------- /assets/pumice/diffuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/diffuse.png -------------------------------------------------------------------------------- /assets/pumice/height.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/height.png -------------------------------------------------------------------------------- /assets/pumice/normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/normal.jpg -------------------------------------------------------------------------------- /assets/pumice/normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/normal.png -------------------------------------------------------------------------------- /assets/pumice/specular.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/specular.jpg -------------------------------------------------------------------------------- /assets/pumice/specular.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/pumice/specular.png -------------------------------------------------------------------------------- /assets/stroke.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/stroke.png -------------------------------------------------------------------------------- /assets/vincent.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/vincent.jpg -------------------------------------------------------------------------------- /assets/vincent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/vincent.png -------------------------------------------------------------------------------- /assets/white-construction-paper-texture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spite/codevember-2017/cef2633db672d16e89c0a447607554b4d91afe07/assets/white-construction-paper-texture.jpg -------------------------------------------------------------------------------- /base/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 104 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /chromeography/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | chromeography - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 38 | 39 | 40 | 41 |
42 |
43 |
Loading
44 |
45 |
46 |

Previous | Next

47 |

7. chromeography

48 |

Fading one image into another and making those colors dance!

49 |

Select any of the four images at the bottom to fade into it.

50 |

Click or tap and drag to move the camera, scroll or zoom with two fingers to zoom in and out.

51 |

More details...

52 |
53 | 64 | 65 | 66 | 67 | 68 | 69 | 122 | 123 | 132 | 133 | 371 | 372 | 373 | 374 | -------------------------------------------------------------------------------- /css/styles.css: -------------------------------------------------------------------------------- 1 | *{ 2 | box-sizing: border-box; 3 | margin :0; 4 | padding: 0; 5 | } 6 | html { 7 | height: 100%; 8 | -moz-user-select: none; 9 | -khtml-user-select: none; 10 | -webkit-user-select: none; 11 | -ms-user-select: none; 12 | user-select: none; 13 | } 14 | body { 15 | margin: 0; 16 | padding: 0; 17 | background-color: #202020; 18 | color: #ffffff; 19 | line-height: 1.4em; 20 | height: 100%; 21 | overflow: hidden; 22 | font-family: 'Lato', sans-serif; 23 | font-size: 13px; 24 | font-weight: 100; 25 | text-shadow: 0 1px 0 rgba(0,0,0,1); 26 | } 27 | #container { 28 | position: absolute; 29 | left: 0; 30 | top: 0; 31 | right: 0; 32 | bottom: 0; 33 | width: 100%; 34 | height: 100%; 35 | } 36 | #info{ 37 | position: absolute; 38 | left: 20px; 39 | top: 20px; 40 | max-width: 400px; 41 | overflow: auto; 42 | pointer-events: none; 43 | } 44 | #info h1, #details h1{ 45 | font-family: 'Playfair Display', sans-serif; 46 | font-weight: 700; 47 | font-size: 16px; 48 | margin-bottom: 1em; 49 | text-transform: uppercase; 50 | } 51 | #info p, #details p{ 52 | margin-bottom: 1em; 53 | hyphens: auto; 54 | } 55 | #info a, .action, #details a{ 56 | color: inherit; 57 | cursor: pointer; 58 | text-decoration: none; 59 | opacity: .7; 60 | transition: opacity 100ms ease-out; 61 | font-weight: 700; 62 | border-bottom: 1px solid rgba(255,255,255,.2); 63 | pointer-events: auto; 64 | } 65 | #moreDetails{ 66 | pointer-events: auto 67 | } 68 | #info a:hover, .action:hover, #details a:hover{ 69 | opacity: 1 70 | border-bottom: 1px solid rgba(255,255,255,.5); 71 | } 72 | b{ 73 | font-weight: 700; 74 | } 75 | #details{ 76 | position: absolute; 77 | right: 0; 78 | width: 400px; 79 | max-width: 100%; 80 | height: 100%; 81 | background-color: black; 82 | transition: transform 150ms ease-out; 83 | z-index: 100; 84 | } 85 | #details.hidden{ 86 | transform: translate3d( 100%,0,0); 87 | } 88 | #details.hidden *{ 89 | pointer-events: none; 90 | } 91 | #details ul{ 92 | margin-left: 20px; margin-bottom: 1em; 93 | } 94 | #details .content{ 95 | padding: 20px; 96 | position: absolute; 97 | left: 0; top: 0; right: 0; bottom: 60px; 98 | overflow: auto; 99 | } 100 | 101 | .hub{ 102 | position: absolute; bottom: 20px; right: 85px; color: white; 103 | text-align: right; line-height: 24px; 104 | height: 28px; 105 | z-index: 1000; 106 | } 107 | .hub a{ 108 | color: inherit; 109 | } 110 | 111 | body > .button{ 112 | position: absolute; border: 1px solid white; z-index: 1000; width: 28px; height: 28px; cursor: pointer; text-align: center; line-height: 24px; cursor:pointer; 113 | } 114 | 115 | .fullscreen-button{ 116 | right: 20px; bottom: 20px; 117 | } 118 | .info-button{ 119 | right: 50px; bottom: 20px; 120 | } 121 | .code{ 122 | font-family: "courier new", courier; color: green; padding: 5px; 123 | } 124 | -------------------------------------------------------------------------------- /digital-analog-color-display/index copy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 82 | 83 | 94 | 95 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /digital-analog-color-display/index-shadow.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 107 | 108 | 168 | 169 | 364 | 365 | 366 | 367 | -------------------------------------------------------------------------------- /digital-analog-color-display/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Digital Analog Color Display - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

14. Digital Analog Color Display

18 |

A display that renders colors by orienting Red, Green and Blue blocks towards a light source.

19 |

Click or tap and drag to move the camera, scroll or zoom with two fingers to zoom in and out.

20 |

Zoom in to see the individual pixels and sublocks. It´s like getting really close to an old TV!

21 |

More details...

22 |
23 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 96 | 97 | 107 | 108 | 260 | 261 | 262 | 263 | -------------------------------------------------------------------------------- /gi/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 53 | 54 | 67 | 68 | 94 | 95 | 136 | 137 | 155 | 156 | 167 | 168 | 462 | 463 | 464 | 465 | -------------------------------------------------------------------------------- /glow-worms/mrf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 282 | 283 | 284 | 285 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Codevember 2017

17 | 34 |
35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /js/Backdrop.js: -------------------------------------------------------------------------------- 1 | function Backdrop( lightPosition, top, bottom ) { 2 | 3 | this.backGeometry = new THREE.IcosahedronBufferGeometry(1,4); 4 | this.backMaterial = new THREE.RawShaderMaterial({ 5 | uniforms: { 6 | top: { type: 'c', value: new THREE.Color(top) }, 7 | bottom: { type: 'c', value: new THREE.Color(bottom) }, 8 | lightPosition: { type: 'v3', value: lightPosition } 9 | }, 10 | vertexShader: document.getElementById( 'backdrop-vs' ).textContent, 11 | fragmentShader: document.getElementById( 'backdrop-fs' ).textContent, 12 | side: THREE.BackSide, 13 | depthWrite: false 14 | }); 15 | return new THREE.Mesh( this.backGeometry, this.backMaterial ); 16 | 17 | } 18 | -------------------------------------------------------------------------------- /js/Bloom.js: -------------------------------------------------------------------------------- 1 | function Bloom( levels ) { 2 | 3 | this.levels = levels !== undefined ? levels : 5; 4 | this.fbos = []; 5 | 6 | this.fbos.push( this.createFBO() ); 7 | helper.attach( this.fbos[0], 'highlight' ); 8 | 9 | for( var j = 0; j < this.levels; j++ ) { 10 | var fbo = this.createFBO(); 11 | this.fbos.push( fbo ); 12 | helper.attach( fbo, 'blur.' + j + '.h' ); 13 | var fbo = this.createFBO(); 14 | this.fbos.push( fbo ); 15 | helper.attach( fbo, 'blur.' + j + '.v' ); 16 | } 17 | this.fbos.push( this.createFBO() ); 18 | 19 | this.highlightShader = new THREE.RawShaderMaterial({ 20 | uniforms: { 21 | source: { type: 't', value: null }, 22 | threshold: { type: 'f', value: 1. } 23 | }, 24 | vertexShader: document.getElementById('ortho-vs').textContent, 25 | fragmentShader: document.getElementById('highlight-fs').textContent, 26 | }); 27 | 28 | this.blurShader = new THREE.RawShaderMaterial({ 29 | uniforms: { 30 | source: { type: 't', value: null }, 31 | resolution: { type: 'v2', value: new THREE.Vector2(1,1) }, 32 | delta: { type: 'v2', value: new THREE.Vector2( 0, 1 )} 33 | }, 34 | vertexShader: document.getElementById('ortho-vs').textContent, 35 | fragmentShader: document.getElementById('blur-fs').textContent, 36 | }); 37 | 38 | this.bloomShader = new THREE.RawShaderMaterial({ 39 | uniforms: { 40 | levels: { type: 'f', value: this.levels }, 41 | base: { type: 't', value: baseFBO.texture }, 42 | level0: { type: 't', value: this.levels>0?this.fbos[2].texture:null }, 43 | level1: { type: 't', value: this.levels>1?this.fbos[4].texture:null }, 44 | level2: { type: 't', value: this.levels>2?this.fbos[6].texture:null }, 45 | level3: { type: 't', value: this.levels>3?this.fbos[8].texture:null }, 46 | level4: { type: 't', value: this.levels>4?this.fbos[10].texture:null }, 47 | resolution: { type: 'v2', value: new THREE.Vector2(1,1) }, 48 | boost: { type: 'f', value: 1.1 }, 49 | reduction: { type: 'f', value: 1.1 }, 50 | amount: { type: 'f', value: 0 }, 51 | time: { type: 'f', value: 0 } 52 | }, 53 | vertexShader: document.getElementById('ortho-vs').textContent, 54 | fragmentShader: document.getElementById('bloom-fs').textContent, 55 | }); 56 | 57 | this.orthoScene = new THREE.Scene(); 58 | this.orthoCamera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, .00001, 1000 ); 59 | this.orthoQuad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 1, 1 ), this.highlightShader ); 60 | this.orthoScene.add( this.orthoQuad ); 61 | 62 | } 63 | 64 | Bloom.prototype.createFBO = function() { 65 | 66 | var fbo = new THREE.WebGLRenderTarget( 1, 1, { 67 | wrapS: THREE.ClampToEdgeWrapping, 68 | wrapT: THREE.ClampToEdgeWrapping, 69 | format: THREE.RGBAFormat, 70 | type: THREE.UnsignedByteType, 71 | minFilter: THREE.LinearFilter, 72 | magFilter: THREE.LinearFilter, 73 | stencilBuffer: false, 74 | depthBuffer: false 75 | }); 76 | 77 | fbo.texture.generateMipMaps = false; 78 | 79 | return fbo; 80 | } 81 | 82 | Bloom.prototype.setSize = function(w, h) { 83 | 84 | this.width = w; 85 | this.height = h; 86 | 87 | var tw = w; 88 | var th = h; 89 | 90 | this.fbos[ 0 ].setSize( tw, th ); 91 | helper.refreshFBO( this.fbos[0] ); 92 | 93 | tw /= 2; th /= 2; 94 | tw = Math.round( tw ); 95 | th = Math.round( th ); 96 | 97 | for( var j = 1; j < this.levels * 2; j+= 2) { 98 | this.fbos[ j ].setSize( tw, th ); 99 | helper.refreshFBO( this.fbos[j] ); 100 | this.fbos[ j + 1 ].setSize( tw, th ); 101 | helper.refreshFBO( this.fbos[j+1] ); 102 | tw /= 2; th /= 2; 103 | tw = Math.round( tw ); 104 | th = Math.round( th ); 105 | } 106 | 107 | } 108 | 109 | Bloom.prototype.setRenderSize = function(width, height) { 110 | 111 | this.orthoQuad.scale.set( width, height, 1. ); 112 | 113 | this.orthoCamera.left = - width / 2; 114 | this.orthoCamera.right = width / 2; 115 | this.orthoCamera.top = height / 2; 116 | this.orthoCamera.bottom = - height / 2; 117 | this.orthoCamera.updateProjectionMatrix(); 118 | 119 | } 120 | 121 | Bloom.prototype.render = function() { 122 | 123 | this.highlightShader.uniforms.source.value = baseFBO.texture; 124 | var w = this.fbos[ 0 ].width; 125 | var h = this.fbos[ 0 ].height; 126 | this.orthoQuad.material = this.highlightShader; 127 | this.setRenderSize(w, h); 128 | renderer.render(this.orthoScene,this.orthoCamera, this.fbos[ 0 ] ); 129 | 130 | var v = 1; 131 | 132 | for( var j = 1; j < this.levels * 2; j+= 2 ){ 133 | 134 | this.orthoQuad.material = this.blurShader; 135 | this.orthoQuad.material.uniforms.delta.value.set( v,0 ); 136 | this.orthoQuad.material.uniforms.source.value = this.fbos[ j - 1 ].texture; 137 | this.orthoQuad.material.uniforms.resolution.value.set( this.fbos[j].width, this.fbos[j].height ); 138 | this.setRenderSize( this.fbos[ j ].width, this.fbos[ j ].height ); 139 | renderer.render(this.orthoScene,this.orthoCamera, this.fbos[ j ] ); 140 | 141 | this.orthoQuad.material = this.blurShader; 142 | this.orthoQuad.material.uniforms.delta.value.set( 0,v ); 143 | this.orthoQuad.material.uniforms.source.value = this.fbos[ j ].texture; 144 | this.orthoQuad.material.uniforms.resolution.value.set( this.fbos[j+1].width, this.fbos[j+1].height ); 145 | this.setRenderSize( this.fbos[ j + 1 ].width, this.fbos[ j + 1 ].height ); 146 | renderer.render(this.orthoScene,this.orthoCamera, this.fbos[ j + 1 ] ); 147 | 148 | } 149 | 150 | this.orthoQuad.material = this.bloomShader; 151 | this.orthoQuad.material.uniforms.amount.value = .01; 152 | this.orthoQuad.material.uniforms.time.value = .001 * performance.now(); 153 | this.orthoQuad.material.uniforms.resolution.value.set( this.width, this.height ); 154 | this.setRenderSize( this.width, this.height ); 155 | renderer.render(this.orthoScene,this.orthoCamera ); 156 | 157 | } 158 | -------------------------------------------------------------------------------- /js/Common.js: -------------------------------------------------------------------------------- 1 | function addCommonUI( element, callback ) { 2 | 3 | element = element || document.body; 4 | callback = callback || function() {} 5 | 6 | function goFS() { 7 | 8 | if(element.requestFullscreen) { 9 | element.requestFullscreen(); 10 | } else if(element.mozRequestFullScreen) { 11 | element.mozRequestFullScreen(); 12 | } else if(element.webkitRequestFullscreen) { 13 | element.webkitRequestFullscreen(); 14 | } else if(element.msRequestFullscreen) { 15 | element.msRequestFullscreen(); 16 | } 17 | callback(); 18 | 19 | } 20 | 21 | function toggleDetails() { 22 | document.getElementById('details').classList.toggle('hidden'); 23 | } 24 | 25 | window.addEventListener( 'keydown', function( e ) { 26 | if( e.keyCode === 70 ) { 27 | goFS(); 28 | } 29 | } ) 30 | 31 | var btn = document.createElement( 'div' ); 32 | btn.textContent = '↗'; 33 | btn.className = 'fullscreen-button button' 34 | document.body.appendChild( btn ); 35 | btn.addEventListener( 'click', goFS ); 36 | 37 | var info = document.createElement( 'div' ); 38 | info.textContent = 'i'; 39 | info.className = 'info-button button' 40 | document.body.appendChild( info ); 41 | info.addEventListener( 'click', toggleDetails ); 42 | 43 | document.body.querySelector( '#moreDetails' ).addEventListener( 'click', toggleDetails ); 44 | document.body.querySelector( '#close-details' ).addEventListener( 'click', toggleDetails ); 45 | 46 | var hub = document.createElement( 'p' ); 47 | hub.className = 'hub'; 48 | hub.innerHTML = 'See other experiments for Codevember 2017'; 49 | document.body.appendChild( hub ); 50 | 51 | } 52 | -------------------------------------------------------------------------------- /js/CubemapToEquirectangular.js: -------------------------------------------------------------------------------- 1 | var vertexShader = ` 2 | attribute vec3 position; 3 | attribute vec2 uv; 4 | 5 | uniform mat4 projectionMatrix; 6 | uniform mat4 modelViewMatrix; 7 | 8 | varying vec2 vUv; 9 | 10 | void main() { 11 | 12 | vUv = vec2( 1.- uv.x, uv.y ); 13 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 14 | 15 | } 16 | `; 17 | 18 | var fragmentShader = ` 19 | precision mediump float; 20 | 21 | uniform samplerCube map; 22 | 23 | varying vec2 vUv; 24 | 25 | #define M_PI 3.1415926535897932384626433832795 26 | 27 | void main() { 28 | 29 | vec2 uv = vUv; 30 | 31 | float longitude = uv.x * 2. * M_PI - M_PI + M_PI / 2.; 32 | float latitude = uv.y * M_PI; 33 | 34 | vec3 dir = vec3( 35 | - sin( longitude ) * sin( latitude ), 36 | cos( latitude ), 37 | - cos( longitude ) * sin( latitude ) 38 | ); 39 | normalize( dir ); 40 | 41 | gl_FragColor = textureCube( map, dir ); 42 | 43 | } 44 | `; 45 | 46 | function CubemapToEquirectangular( renderer, provideCubeCamera ) { 47 | 48 | this.width = 1; 49 | this.height = 1; 50 | 51 | this.renderer = renderer; 52 | 53 | this.material = new THREE.RawShaderMaterial( { 54 | uniforms: { 55 | map: { type: 't', value: null } 56 | }, 57 | vertexShader: vertexShader, 58 | fragmentShader: fragmentShader, 59 | side: THREE.DoubleSide, 60 | transparent: true 61 | } ); 62 | 63 | this.scene = new THREE.Scene(); 64 | this.quad = new THREE.Mesh( 65 | new THREE.PlaneBufferGeometry( 1, 1 ), 66 | this.material 67 | ); 68 | this.scene.add( this.quad ); 69 | this.camera = new THREE.OrthographicCamera( 1 / - 2, 1 / 2, 1 / 2, 1 / - 2, -10000, 10000 ); 70 | 71 | this.canvas = document.createElement( 'canvas' ); 72 | this.ctx = this.canvas.getContext( '2d' ); 73 | 74 | this.cubeCamera = null; 75 | this.attachedCamera = null; 76 | 77 | this.setSize( 4096, 2048 ); 78 | 79 | var gl = this.renderer.getContext(); 80 | this.cubeMapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ) 81 | 82 | if( provideCubeCamera ) { 83 | this.getCubeCamera( 2048 ) 84 | } 85 | 86 | } 87 | 88 | CubemapToEquirectangular.prototype.setSize = function( width, height ) { 89 | 90 | this.width = width; 91 | this.height = height; 92 | 93 | this.quad.scale.set( this.width, this.height, 1 ); 94 | 95 | this.camera.left = this.width / - 2; 96 | this.camera.right = this.width / 2; 97 | this.camera.top = this.height / 2; 98 | this.camera.bottom = this.height / - 2; 99 | 100 | this.camera.updateProjectionMatrix(); 101 | 102 | this.output = new THREE.WebGLRenderTarget( this.width, this.height, { 103 | minFilter: THREE.LinearFilter, 104 | magFilter: THREE.LinearFilter, 105 | wrapS: THREE.ClampToEdgeWrapping, 106 | wrapT: THREE.ClampToEdgeWrapping, 107 | format: THREE.RGBAFormat, 108 | type: THREE.UnsignedByteType 109 | }); 110 | 111 | this.canvas.width = this.width; 112 | this.canvas.height = this.height; 113 | 114 | } 115 | 116 | CubemapToEquirectangular.prototype.getCubeCamera = function( size ) { 117 | 118 | var cubeMapSize = Math.min( this.cubeMapSize, size ); 119 | this.cubeCamera = new THREE.CubeCamera( .1, 1000, cubeMapSize ); 120 | 121 | var options = { format: THREE.RGBAFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter }; 122 | this.cubeCamera.renderTarget = new THREE.WebGLRenderTargetCube( cubeMapSize, cubeMapSize, options ); 123 | 124 | return this.cubeCamera; 125 | 126 | } 127 | 128 | CubemapToEquirectangular.prototype.attachCubeCamera = function( camera ) { 129 | 130 | this.getCubeCamera(); 131 | this.attachedCamera = camera; 132 | 133 | } 134 | 135 | CubemapToEquirectangular.prototype.convert = function( cubeCamera, download ) { 136 | 137 | this.quad.material.uniforms.map.value = cubeCamera.renderTarget.texture; 138 | this.renderer.render( this.scene, this.camera, this.output, true ); 139 | 140 | /*var pixels = new Uint8Array( 4 * this.width * this.height ); 141 | this.renderer.readRenderTargetPixels( this.output, 0, 0, this.width, this.height, pixels ); 142 | 143 | var imageData = new ImageData( new Uint8ClampedArray( pixels ), this.width, this.height ); 144 | 145 | if( download !== false ) { 146 | this.download( imageData ); 147 | } 148 | 149 | return imageData*/ 150 | 151 | }; 152 | 153 | CubemapToEquirectangular.prototype.download = function( imageData ) { 154 | 155 | this.ctx.putImageData( imageData, 0, 0 ); 156 | 157 | this.canvas.toBlob( function( blob ) { 158 | 159 | var url = URL.createObjectURL(blob); 160 | var fileName = 'pano-' + document.title + '-' + Date.now() + '.png'; 161 | var anchor = document.createElement( 'a' ); 162 | anchor.href = url; 163 | anchor.setAttribute("download", fileName); 164 | anchor.className = "download-js-link"; 165 | anchor.innerHTML = "downloading..."; 166 | anchor.style.display = "none"; 167 | document.body.appendChild(anchor); 168 | setTimeout(function() { 169 | anchor.click(); 170 | document.body.removeChild(anchor); 171 | }, 1 ); 172 | 173 | }, 'image/png' ); 174 | 175 | }; 176 | 177 | CubemapToEquirectangular.prototype.update = function( camera, scene ) { 178 | 179 | var autoClear = this.renderer.autoClear; 180 | this.renderer.autoClear = true; 181 | this.cubeCamera.position.copy( camera.position ); 182 | this.cubeCamera.updateCubeMap( this.renderer, scene ); 183 | this.renderer.autoClear = autoClear; 184 | 185 | this.convert( this.cubeCamera ); 186 | 187 | } 188 | -------------------------------------------------------------------------------- /js/EquirectangularToCubemap.js: -------------------------------------------------------------------------------- 1 | ;(function() { 2 | 3 | "use strict"; 4 | 5 | var root = this 6 | 7 | var has_require = typeof require !== 'undefined' 8 | 9 | var THREE = root.THREE || has_require && require('three') 10 | if( !THREE ) 11 | throw new Error( 'EquirectangularToCubemap requires three.js' ) 12 | 13 | function EquirectangularToCubemap( renderer ) { 14 | 15 | this.renderer = renderer; 16 | this.scene = new THREE.Scene(); 17 | 18 | var gl = this.renderer.getContext(); 19 | this.maxSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE ) 20 | 21 | this.camera = new THREE.CubeCamera( 1, 100000, 1 ); 22 | 23 | this.material = new THREE.MeshBasicMaterial( { 24 | map: null, 25 | side: THREE.BackSide 26 | } ); 27 | 28 | this.mesh = new THREE.Mesh( 29 | new THREE.IcosahedronGeometry( 100, 4 ), 30 | this.material 31 | ); 32 | this.scene.add( this.mesh ); 33 | 34 | } 35 | 36 | EquirectangularToCubemap.prototype.convert = function( source, size ) { 37 | 38 | var mapSize = Math.min( size, this.maxSize ); 39 | this.camera = new THREE.CubeCamera( 1, 100000, mapSize ); 40 | this.material.map = source; 41 | 42 | this.camera.update( this.renderer, this.scene ); 43 | 44 | return this.camera.renderTarget.texture; 45 | 46 | } 47 | 48 | if( typeof exports !== 'undefined' ) { 49 | if( typeof module !== 'undefined' && module.exports ) { 50 | exports = module.exports = EquirectangularToCubemap 51 | } 52 | exports.EquirectangularToCubemap = EquirectangularToCubemap 53 | } 54 | else { 55 | root.EquirectangularToCubemap = EquirectangularToCubemap 56 | } 57 | 58 | }).call(this); 59 | -------------------------------------------------------------------------------- /js/ImprovedNoise.js: -------------------------------------------------------------------------------- 1 | // http://mrl.nyu.edu/~perlin/noise/ 2 | 3 | var ImprovedNoise = function () { 4 | 5 | var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10, 6 | 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87, 7 | 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211, 8 | 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208, 9 | 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5, 10 | 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119, 11 | 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232, 12 | 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249, 13 | 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205, 14 | 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180]; 15 | 16 | for (var i=0; i < 256 ; i++) { 17 | 18 | p[256+i] = p[i]; 19 | 20 | } 21 | 22 | function fade(t) { 23 | 24 | return t * t * t * (t * (t * 6 - 15) + 10); 25 | 26 | } 27 | 28 | function lerp(t, a, b) { 29 | 30 | return a + t * (b - a); 31 | 32 | } 33 | 34 | function grad(hash, x, y, z) { 35 | 36 | var h = hash & 15; 37 | var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z; 38 | return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); 39 | 40 | } 41 | 42 | return { 43 | 44 | noise: function (x, y, z) { 45 | 46 | var floorX = Math.floor(x), floorY = Math.floor(y), floorZ = Math.floor(z); 47 | 48 | var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255; 49 | 50 | x -= floorX; 51 | y -= floorY; 52 | z -= floorZ; 53 | 54 | var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1; 55 | 56 | var u = fade(x), v = fade(y), w = fade(z); 57 | 58 | var A = p[X]+Y, AA = p[A]+Z, AB = p[A+1]+Z, B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; 59 | 60 | return lerp(w, lerp(v, lerp(u, grad(p[AA], x, y, z), 61 | grad(p[BA], xMinus1, y, z)), 62 | lerp(u, grad(p[AB], x, yMinus1, z), 63 | grad(p[BB], xMinus1, yMinus1, z))), 64 | lerp(v, lerp(u, grad(p[AA+1], x, y, zMinus1), 65 | grad(p[BA+1], xMinus1, y, z-1)), 66 | lerp(u, grad(p[AB+1], x, yMinus1, zMinus1), 67 | grad(p[BB+1], xMinus1, yMinus1, zMinus1)))); 68 | 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /js/Maf.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 3 | // Module code from underscore.js 4 | 5 | // Establish the root object, `window` (`self`) in the browser, `global` 6 | // on the server, or `this` in some virtual machines. We use `self` 7 | // instead of `window` for `WebWorker` support. 8 | var root = typeof self == 'object' && self.self === self && self || 9 | typeof global == 'object' && global.global === global && global || 10 | this; 11 | 12 | var Maf = function(obj) { 13 | if (obj instanceof Maf ) return obj; 14 | if (!(this instanceof Maf )) return new Maf(obj); 15 | this._wrapped = obj; 16 | }; 17 | 18 | // Export the Underscore object for **Node.js**, with 19 | // backwards-compatibility for their old module API. If we're in 20 | // the browser, add `Maf` as a global object. 21 | // (`nodeType` is checked to ensure that `module` 22 | // and `exports` are not HTML elements.) 23 | if (typeof exports != 'undefined' && !exports.nodeType) { 24 | if (typeof module != 'undefined' && !module.nodeType && module.exports) { 25 | exports = module.exports = Maf; 26 | } 27 | exports.Maf = Maf; 28 | } else { 29 | root.Maf = Maf; 30 | } 31 | 32 | // Current version. 33 | Maf.VERSION = '1.0.0'; 34 | 35 | Maf.PI = Math.PI; 36 | 37 | // https://www.opengl.org/sdk/docs/man/html/clamp.xhtml 38 | 39 | Maf.clamp = function( v, minVal, maxVal ) { 40 | return Math.min( maxVal, Math.max( minVal, v ) ); 41 | }; 42 | 43 | // https://www.opengl.org/sdk/docs/man/html/step.xhtml 44 | 45 | Maf.step = function( edge, v ) { 46 | return ( v < edge ) ? 0 : 1; 47 | } 48 | 49 | // https://www.opengl.org/sdk/docs/man/html/smoothstep.xhtml 50 | 51 | Maf.smoothStep = function ( edge0, edge1, v ) { 52 | var t = Maf.clamp( ( v - edge0 ) / ( edge1 - edge0 ), 0.0, 1.0 ); 53 | return t * t * ( 3.0 - 2.0 * t ); 54 | }; 55 | 56 | // http://docs.unity3d.com/ScriptReference/Mathf.html 57 | // http://www.shaderific.com/glsl-functions/ 58 | // https://www.opengl.org/sdk/docs/man4/html/ 59 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85).aspx 60 | // http://moutjs.com/docs/v0.11/math.html#map 61 | // https://code.google.com/p/kuda/source/browse/public/js/hemi/utils/mathUtils.js?r=8d581c02651077c4ac3f5fc4725323210b6b13cc 62 | 63 | // Converts from degrees to radians. 64 | Maf.deg2Rad = function( degrees ) { 65 |   return degrees * Math.PI / 180; 66 | }; 67 | 68 | Maf.toRadians = Maf.deg2Rad; 69 | 70 | // Converts from radians to degrees. 71 | Maf.rad2Deg = function(radians) { 72 |   return radians * 180 / Math.PI; 73 | }; 74 | 75 | Maf.toDegrees = Maf.rad2Deg; 76 | 77 | Maf.clamp01 = function( v ) { 78 | return Maf.clamp( v, 0, 1 ); 79 | }; 80 | 81 | // https://www.opengl.org/sdk/docs/man/html/mix.xhtml 82 | 83 | Maf.mix = function( x, y, a ) { 84 | if( a <= 0 ) return x; 85 | if( a >= 1 ) return y; 86 | return x + a * (y - x) 87 | }; 88 | 89 | Maf.lerp = Maf.mix; 90 | 91 | Maf.inverseMix = function( a, b, v ) { 92 | return ( v - a ) / ( b - a ); 93 | }; 94 | 95 | Maf.inverseLerp = Maf.inverseMix; 96 | 97 | Maf.mixUnclamped = function( x, y, a ) { 98 | if( a <= 0 ) return x; 99 | if( a >= 1 ) return y; 100 | return x + a * (y - x) 101 | }; 102 | 103 | Maf.lerpUnclamped = Maf.mixUnclamped; 104 | 105 | // https://www.opengl.org/sdk/docs/man/html/fract.xhtml 106 | 107 | Maf.fract = function( v ) { 108 | return v - Math.floor( v ); 109 | }; 110 | 111 | Maf.frac = Maf.fract; 112 | 113 | // http://stackoverflow.com/questions/4965301/finding-if-a-number-is-a-power-of-2 114 | 115 | Maf.isPowerOfTwo = function( v ) { 116 | return ( ( ( v - 1) & v ) == 0 ); 117 | }; 118 | 119 | // https://bocoup.com/weblog/find-the-closest-power-of-2-with-javascript 120 | 121 | Maf.closestPowerOfTwo = function( v ) { 122 | return Math.pow( 2, Math.round( Math.log( v ) / Math.log( 2 ) ) ); 123 | }; 124 | 125 | Maf.nextPowerOfTwo = function( v ) { 126 | return Math.pow( 2, Math.ceil( Math.log( v ) / Math.log( 2 ) ) ); 127 | } 128 | 129 | // http://stackoverflow.com/questions/1878907/the-smallest-difference-between-2-angles 130 | 131 | //function mod(a, n) { return a - Math.floor(a/n) * n; } 132 | Maf.mod = function(a, n) { return (a % n + n) % n; } 133 | 134 | Maf.deltaAngle = function( a, b ) { 135 | var d = Maf.mod( b - a, 360 ); 136 | if( d > 180 ) d = Math.abs( d - 360 ); 137 | return d; 138 | }; 139 | 140 | Maf.deltaAngleDeg = Maf.deltaAngle; 141 | 142 | Maf.deltaAngleRad = function( a, b ) { 143 | return Maf.toRadians( Maf.deltaAngle( Maf.toDegrees( a ), Maf.toDegrees( b ) ) ); 144 | }; 145 | 146 | Maf.lerpAngle = function( a, b, t ) { 147 | var angle = Maf.deltaAngle( a, b ); 148 | return Maf.mod( a + Maf.lerp( 0, angle, t ), 360 ); 149 | }; 150 | 151 | Maf.lerpAngleDeg = Maf.lerpAngle; 152 | 153 | Maf.lerpAngleRad = function( a, b, t ) { 154 | return Maf.toRadians( Maf.lerpAngleDeg( Maf.toDegrees( a ), Maf.toDegrees( b ), t ) ); 155 | }; 156 | 157 | // http://gamedev.stackexchange.com/questions/74324/gamma-space-and-linear-space-with-shader 158 | 159 | Maf.gammaToLinearSpace = function( v ) { 160 | return Math.pow( v, 2.2 ); 161 | }; 162 | 163 | Maf.linearToGammaSpace = function( v ) { 164 | return Math.pow( v, 1 / 2.2 ); 165 | }; 166 | 167 | Maf.map = function( from1, to1, from2, to2, v ) { 168 | return from2 + ( v - from1 ) * ( to2 - from2 ) / ( to1 - from1 ); 169 | } 170 | 171 | Maf.scale = Maf.map; 172 | 173 | // http://www.iquilezles.org/www/articles/functions/functions.htm 174 | 175 | Maf.almostIdentity = function( x, m, n ) { 176 | 177 | if( x > m ) return x; 178 | 179 | var a = 2 * n - m; 180 | var b = 2 * m - 3 * n; 181 | var t = x / m; 182 | 183 | return ( a * t + b) * t * t + n; 184 | } 185 | 186 | Maf.impulse = function( k, x ) { 187 | var h = k * x; 188 | return h * Math.exp( 1 - h ); 189 | }; 190 | 191 | Maf.cubicPulse = function( c, w, x ) { 192 | x = Math.abs( x - c ); 193 | if( x > w ) return 0; 194 | x /= w; 195 | return 1 - x * x * ( 3 - 2 * x ); 196 | } 197 | 198 | Maf.expStep = function( x, k, n ) { 199 | return Math.exp( -k * Math.pow( x, n ) ); 200 | } 201 | 202 | Maf.parabola = function( x, k ) { 203 | return Math.pow( 4 * x * ( 1 - x ), k ); 204 | } 205 | 206 | Maf.powerCurve = function( x, a, b ) { 207 | var k = Math.pow( a + b, a + b ) / ( Math.pow( a, a ) * Math.pow( b, b ) ); 208 | return k * Math.pow( x, a ) * Math.pow( 1 - x, b ); 209 | } 210 | 211 | // http://iquilezles.org/www/articles/smin/smin.htm ? 212 | 213 | Maf.latLonToCartesian = function( lat, lon ) { 214 | 215 | lon += 180; 216 | lat = Maf.clamp( lat, -85, 85 ); 217 | var phi = Maf.toRadians( 90 - lat ); 218 | var theta = Maf.toRadians( 180 - lon ); 219 | var x = Math.sin( phi ) * Math.cos( theta ); 220 | var y = Math.cos( phi ); 221 | var z = Math.sin( phi ) * Math.sin( theta ); 222 | 223 | return { x: x, y: y, z: z } 224 | 225 | } 226 | 227 | Maf.cartesianToLatLon = function( x, y, z ) { 228 | var n = Math.sqrt( x * x + y * y + z * z ); 229 | return{ lat: Math.asin( z / n ), lon: Math.atan2( y, x ) }; 230 | } 231 | 232 | Maf.randomInRange = function( min, max ) { 233 | return min + Math.random() * ( max - min ); 234 | } 235 | 236 | Maf.norm = function( v, minVal, maxVal ) { 237 | return ( v - minVal ) / ( maxVal - minVal ); 238 | } 239 | 240 | Maf.hash = function( n ) { 241 | return Maf.fract( (1.0 + Math.cos(n)) * 415.92653); 242 | } 243 | 244 | Maf.noise2d = function( x, y ) { 245 | var xhash = Maf.hash( x * 37.0 ); 246 | var yhash = Maf.hash( y * 57.0 ); 247 | return Maf.fract( xhash + yhash ); 248 | } 249 | 250 | // http://iquilezles.org/www/articles/smin/smin.htm 251 | 252 | Maf.smoothMin = function( a, b, k ) { 253 | var res = Math.exp( -k*a ) + Math.exp( -k*b ); 254 | return - Math.log( res )/k; 255 | } 256 | 257 | Maf.smoothMax = function( a, b, k ){ 258 | return Math.log( Math.exp(a) + Math.exp(b) )/k; 259 | } 260 | 261 | Maf.almost = function( a, b ) { 262 | return ( Math.abs( a - b ) < .0001 ); 263 | } 264 | 265 | }()); -------------------------------------------------------------------------------- /js/MeshCustomMaterial.js: -------------------------------------------------------------------------------- 1 | function MeshCustomMaterial (parameters) { 2 | THREE.MeshStandardMaterial.call( this ); 3 | this.uniforms = THREE.UniformsUtils.merge([ 4 | THREE.UniformsLib.common, 5 | THREE.UniformsLib.aomap, 6 | THREE.UniformsLib.lightmap, 7 | THREE.UniformsLib.emissivemap, 8 | THREE.UniformsLib.bumpmap, 9 | THREE.UniformsLib.normalmap, 10 | THREE.UniformsLib.displacementmap, 11 | THREE.UniformsLib.roughnessmap, 12 | THREE.UniformsLib.metalnessmap, 13 | THREE.UniformsLib.fog, 14 | THREE.UniformsLib.lights, 15 | parameters.u 16 | ]); 17 | 18 | this.vertexShader = parameters.vertexShader; 19 | this.fragmentShader = parameters.fragmentShader; 20 | this.type = 'MeshCustomMaterial'; 21 | 22 | this.setValues(parameters); 23 | } 24 | 25 | MeshCustomMaterial.prototype = Object.create( THREE.MeshStandardMaterial.prototype ); 26 | MeshCustomMaterial.prototype.constructor = MeshCustomMaterial; 27 | MeshCustomMaterial.prototype.isMeshStandardMaterial = true; 28 | 29 | MeshCustomMaterial.prototype.copy = function ( source ) { 30 | THREE.MeshStandardMaterial.prototype.copy.call( this, source ); 31 | this.uniforms = THREE.UniformsUtils.clone(source.uniforms); 32 | setFlags(this); 33 | return this; 34 | }; 35 | -------------------------------------------------------------------------------- /js/Odeo.js: -------------------------------------------------------------------------------- 1 | // /ˈôdēˌō/ 2 | 3 | ( function() { 4 | 5 | var AudioContext = window.AudioContext || window.webkitAudioContext; 6 | 7 | function OdeoSoundCloudPlayer( id, odeo ) { 8 | 9 | this.id = id; 10 | this.odeo = odeo; 11 | 12 | SC.initialize({ 13 | client_id: this.id 14 | }); 15 | 16 | this.audio = document.createElement( 'audio' ); 17 | this.audio.loop = true; 18 | this.audio.autoplay = true; 19 | this.audio.crossOrigin = ''; 20 | 21 | this.songSource = this.odeo.context.createMediaElementSource( this.audio ); 22 | this.songSource.connect( this.odeo.analyser ); 23 | this.songSource.connect( this.odeo.context.destination ); 24 | 25 | } 26 | 27 | OdeoSoundCloudPlayer.prototype.getSong = function( songURL ) { 28 | 29 | this.audio.play(); 30 | 31 | SC.resolve( songURL ).then( function( song ){ 32 | 33 | console.log( song ); 34 | //songInfo.innerHTML = '

' + song.title + ' PAUSE
' + song.user.username + '

' 35 | 36 | this.audio.src = song.stream_url + "?client_id=" + this.id; 37 | 38 | this.songSource.connect( this.odeo.analyser ); 39 | this.songSource.connect( this.odeo.context.destination ); 40 | 41 | }.bind( this ) ); 42 | 43 | } 44 | 45 | OdeoSoundCloudPlayer.prototype.stop = function() { 46 | 47 | this.audio.pause(); 48 | 49 | } 50 | 51 | function OdeoMediaPlayer() { 52 | 53 | thia.audioElement = document.createElement( 'audio' ); 54 | 55 | } 56 | 57 | OdeoMediaPlayer.prototype.play = function( src ) { 58 | 59 | this.audioElement.src = src; 60 | this.audioElement.play(); 61 | 62 | this.audioSource = this.context.createMediaElementSource( this.audioElement ); 63 | this.audioSource.connect( this.odeo.analyser ); 64 | this.audioSource.connect( this.odeo.context.destination ); 65 | 66 | } 67 | 68 | function OdeoMicrophone( odeo ) { 69 | 70 | this.microphone = null; 71 | this.odeo = odeo; 72 | 73 | } 74 | 75 | OdeoMicrophone.prototype.play = function() { 76 | 77 | if( navigator.getUserMedia ) { 78 | 79 | navigator.getUserMedia( { audio: true }, function( stream ) { 80 | 81 | this.microphone = this.odeo.context.createMediaStreamSource( stream ); 82 | this.microphone.connect( this.odeo.analyser ); 83 | 84 | }.bind( this ), 85 | function() { 86 | 87 | } ); 88 | 89 | } else if( navigator.mediaDevices ) { 90 | 91 | navigator.mediaDevices.getUserMedia( { audio: true } ).then(function( stream ) { 92 | 93 | this.microphone = this.odeo.context.createMediaStreamSource( stream ); 94 | this.microphone.connect( this.odeo.analyser ); 95 | 96 | }.bind( this ) ).catch(function(err) { 97 | }); 98 | } 99 | 100 | } 101 | 102 | OdeoMicrophone.prototype.stop = function() { 103 | 104 | if( this.microphone ) { 105 | this.microphone.disconnect( this.odeo.analyser ); 106 | } 107 | this.microphone = null; 108 | 109 | } 110 | 111 | function Odeo( opts ){ 112 | 113 | this.options = opts || {}; 114 | 115 | this.context = new AudioContext(); 116 | this.analyser = this.context.createAnalyser(); 117 | this.analyser.fftSize = this.options.fftSize || 256; 118 | this.frequencyData = new Uint8Array( this.analyser.frequencyBinCount ); 119 | this.timeData = new Uint8Array( this.analyser.frequencyBinCount ); 120 | this.waveData = []; 121 | this.levelsData = []; 122 | this.levelsCount = 16 123 | this.beatCutOff = 0; 124 | this.beatTime = 0; 125 | this.bpmStart = 0; 126 | this.volume = 0; 127 | 128 | this.spectrumTexture = null; 129 | 130 | this.soundCloudPlayer = null; 131 | this.microphone = null; 132 | 133 | } 134 | 135 | Odeo.prototype.playMedia = function() { 136 | 137 | } 138 | 139 | Odeo.prototype.useMicrophone = function() { 140 | 141 | if( !this.microphone ) this.microphone = new OdeoMicrophone( this ); 142 | this.microphone.play(); 143 | 144 | } 145 | 146 | Odeo.prototype.stopUsingMicrophone = function() { 147 | 148 | if( !this.microphone ) return; 149 | this.microphone.stop(); 150 | 151 | } 152 | 153 | Odeo.prototype.playSoundCloud = function( url ) { 154 | 155 | if( !this.soundCloudPlayer ) this.soundCloudPlayer = new OdeoSoundCloudPlayer( this.options.soundCloudId, this ); 156 | this.soundCloudPlayer.getSong( url ); 157 | 158 | } 159 | 160 | Odeo.prototype.stopSoundCloud = function( url ) { 161 | 162 | if( !this.soundCloudPlayer ) return; 163 | this.soundCloudPlayer.stop(); 164 | 165 | } 166 | 167 | Odeo.prototype.getSpectrumTexture = function() { 168 | 169 | this.spectrumTexture = new THREE.DataTexture( this.frequencyData, 1 * this.frequencyData.length, 1, THREE.LuminanceFormat ); 170 | //this.spectrumTexture = new THREE.DataTexture( this.timeData, 1 * this.timeData.length, 1, THREE.LuminanceFormat ); 171 | this.spectrumTexture.minFilter = THREE.NearestFilter; 172 | this.spectrumTexture.magFilter = THREE.NearestFilter; 173 | this.spectrumTexture.needsUpdate = true; 174 | 175 | return this.spectrumTexture; 176 | 177 | } 178 | 179 | Odeo.prototype.update = function() { 180 | 181 | var volSens = 1; 182 | 183 | this.analyser.getByteFrequencyData( this.frequencyData ); 184 | if( this.spectrumTexture ) this.spectrumTexture.needsUpdate = true; 185 | //kick.onUpdate(); 186 | 187 | 188 | this.analyser.getByteTimeDomainData(this.timeData); // <-- waveform 189 | 190 | for(var i = 0; i < this.analyser.frequencyBinCount; i++) { 191 | this.waveData[i] = ((this.timeData[i] - 128) /128 ) * volSens; 192 | } 193 | 194 | var levelBins = Math.floor(this.analyser.frequencyBinCount / this.levelsCount); 195 | 196 | for(var i = 0; i < this.levelsCount; i++) { 197 | var sum = 0; 198 | for(var j = 0; j < levelBins; j++) { 199 | sum += this.frequencyData[(i * levelBins) + j]; 200 | } 201 | this.levelsData[i] = sum / levelBins/256 * volSens; 202 | } 203 | 204 | var sum = 0; 205 | for(var j = 0; j < this.levelsCount; j++) { 206 | sum += this.levelsData[j]; 207 | } 208 | 209 | this.volume = sum / this.levelsCount; 210 | 211 | var BEAT_HOLD_TIME = 40; 212 | var BEAT_DECAY_RATE = 0.98; 213 | var BEAT_MIN = 0.15; 214 | 215 | if (this.volume > this.beatCutOff && this.volume > BEAT_MIN){ 216 | if( this.onBeat ) this.onBeat(); 217 | this.bpmStart = performance.now(); 218 | 219 | this.beatCutOff = this.volume *1.1; 220 | this.beatTime = 0; 221 | }else{ 222 | if (this.beatTime <= BEAT_HOLD_TIME){ 223 | this.beatTime ++; 224 | }else{ 225 | this.beatCutOff *= BEAT_DECAY_RATE; 226 | this.beatCutOff = Math.max(this.beatCutOff,BEAT_MIN); 227 | } 228 | } 229 | 230 | this.bpmTime = (performance.now() - this.bpmStart)/633; 231 | 232 | } 233 | 234 | // [ mic ] [ url ] [ play / pause ] 235 | 236 | Odeo.prototype.getUI = function() { 237 | 238 | this.div = document.createElement('div'); 239 | var code = ''; 240 | code += ''; 241 | code += ''; 242 | code += ''; 243 | code += ''; 244 | code += '
Mic
URL
'; 245 | this.div.innerHTML = code; 246 | 247 | var odeo = this; 248 | var div = this.div; 249 | var useMic = this.div.querySelector('.odeo-mic'); 250 | var useURL = this.div.querySelector('.odeo-url'); 251 | 252 | useMic.addEventListener('click', function(){ 253 | useURL.classList.remove('odeo-active'); 254 | useMic.classList.add('odeo-active'); 255 | odeo.stopSoundCloud(); 256 | odeo.useMicrophone(); 257 | }); 258 | 259 | useURL.addEventListener('click', function(){ 260 | useMic.classList.remove('odeo-active'); 261 | useURL.classList.add('odeo-active'); 262 | var url = div.querySelector('.odeo-input').value; 263 | odeo.stopUsingMicrophone(); 264 | odeo.playSoundCloud(url); 265 | }); 266 | 267 | return this.div; 268 | } 269 | 270 | window.Odeo = Odeo; 271 | 272 | } )(); 273 | -------------------------------------------------------------------------------- /js/THREE.FBOHelper.js: -------------------------------------------------------------------------------- 1 | ;(function() { 2 | 3 | "use strict"; 4 | 5 | var root = this 6 | 7 | var has_require = typeof require !== 'undefined' 8 | 9 | var THREE = root.THREE || has_require && require('three') 10 | if( !THREE ) 11 | throw new Error( 'FBOHelper requires three.js' ) 12 | 13 | "use strict"; 14 | 15 | var layerCSS = ` 16 | #fboh-fbos-list{ 17 | all: unset; 18 | position: fixed; 19 | left: 0; 20 | top: 0; 21 | z-index: 1000000; 22 | width: 150px; 23 | } 24 | #fboh-fbos-list, #fboh-fbos-list *, #fboh-hotspot, #fboh-label, #fboh-info{ 25 | box-sizing: border-box; 26 | font-family: 'Roboto Mono', 'courier new', courier, monospace; 27 | font-size: 11px; 28 | line-height: 1.4em; 29 | } 30 | #fboh-fbos-list li{ 31 | cursor: pointer; 32 | color: white; 33 | width: 100%; 34 | padding: 4px 0; 35 | border-top: 1px solid #888; 36 | border-bottom: 1px solid black; 37 | background-color: #444; 38 | text-align: center; 39 | text-shadow: 0 -1px black; 40 | } 41 | #fboh-fbos-list li:hover{ 42 | background-color: rgba( 158, 253, 56, .5 ); 43 | } 44 | #fboh-fbos-list li.active{ 45 | background-color: rgba( 158, 253, 56, .5 ); 46 | color: white; 47 | text-shadow: 0 1px black; 48 | } 49 | #fboh-hotspot{ 50 | position: absolute; 51 | left: 0; 52 | top: 0; 53 | background-color: rgba( 158, 253, 56,.5); 54 | pointer-events: none; 55 | } 56 | #fboh-label{ 57 | position: absolute; 58 | left: 0; 59 | bottom: 0; 60 | transform-origin: bottom left; 61 | pointer-events: none; 62 | } 63 | #fboh-info{ 64 | display: none; 65 | position: absolute; 66 | left: 160px; 67 | top: 10px; 68 | pointer-events: none; 69 | } 70 | .fboh-card{ 71 | display: block; 72 | white-space: nowrap; 73 | color: black; 74 | padding: 10px; 75 | background-color: white; 76 | border: 1px solid black; 77 | } 78 | `; 79 | 80 | let formats = {} 81 | formats[ THREE.AlphaFormat ] = 'THREE.AlphaFormat'; 82 | formats[ THREE.RGBFormat ] = 'THREE.RGBFormat'; 83 | formats[ THREE.RGBAFormat ] = 'THREE.RGBAFormat'; 84 | formats[ THREE.LuminanceFormat ] = 'THREE.LuminanceFormat'; 85 | formats[ THREE.LuminanceAlphaFormat ] = 'THREE.LuminanceAlphaFormat'; 86 | //formats[ THREE.RGBEFormat ] = 'THREE.RGBEFormat'; 87 | 88 | let types = {} 89 | types[ THREE.UnsignedByteType ] = 'THREE.UnsignedByteType'; 90 | types[ THREE.ByteType ] = 'THREE.ByteType'; 91 | types[ THREE.ShortType ] = 'THREE.ShortType'; 92 | types[ THREE.UnsignedShortType ] = 'THREE.UnsignedShortType'; 93 | types[ THREE.IntType ] = 'THREE.IntType'; 94 | types[ THREE.UnsignedIntType ] = 'THREE.UnsignedIntType'; 95 | types[ THREE.FloatType ] = 'THREE.FloatType'; 96 | types[ THREE.HalfFloatType ] = 'THREE.HalfFloatType'; 97 | types[ THREE.UnsignedShort4444Type ] = 'THREE.UnsignedShort4444Type'; 98 | types[ THREE.UnsignedShort5551Type ] = 'THREE.UnsignedShort5551Type'; 99 | types[ THREE.UnsignedShort565Type ] = 'THREE.UnsignedShort565Type'; 100 | 101 | class FBOHelper { 102 | 103 | constructor( renderer ) { 104 | 105 | this.renderer = renderer; 106 | this.autoUpdate = false; 107 | this.fbos = [] 108 | this.list = document.createElement( 'ul' ); 109 | this.list.setAttribute( 'id', 'fboh-fbos-list' ); 110 | document.body.appendChild( this.list ); 111 | 112 | this.scene = new THREE.Scene(); 113 | this.camera = new THREE.OrthographicCamera( -1, 1, 1, -1, .000001, 1000 ); 114 | 115 | this.raycaster = new THREE.Raycaster(); 116 | this.mouse = new THREE.Vector2(); 117 | 118 | this.grid = document.createElement( 'div' ); 119 | this.grid.setAttribute( 'style', 'position: fixed; left: 50%; top: 50%; border: 1px solid #000000; transform: translate3d(-50%, -50%, 0 ); box-shadow: 0 0 50px black; display: none' ); 120 | this.grid.setAttribute( 'id', 'bfoh-grid' ); 121 | document.body.appendChild( this.grid ); 122 | 123 | this.hotspot = document.createElement( 'div' ); 124 | this.hotspot.setAttribute( 'id', 'fboh-hotspot' ); 125 | this.grid.appendChild( this.hotspot ); 126 | 127 | this.label = document.createElement( 'div' ); 128 | this.label.setAttribute( 'id', 'fboh-label' ); 129 | this.label.className = 'fboh-card'; 130 | this.hotspot.appendChild( this.label ); 131 | 132 | this.info = document.createElement( 'div' ); 133 | this.info.setAttribute( 'id', 'fboh-info' ); 134 | this.info.className = 'fboh-card'; 135 | document.body.appendChild( this.info ); 136 | 137 | this.currentObj = null; 138 | this.currentU = 0; 139 | this.currentV = 0; 140 | 141 | this.fboMap = new Map(); 142 | 143 | this.offsetX = 0; 144 | this.offsetY = 0; 145 | 146 | this.grid.appendChild( this.hotspot ); 147 | 148 | const head = window.document.head || window.document.getElementsByTagName('head')[0]; 149 | const style = window.document.createElement('style'); 150 | 151 | style.type = 'text/css'; 152 | if (style.styleSheet){ 153 | style.styleSheet.cssText = layerCSS; 154 | } else { 155 | style.appendChild(document.createTextNode(layerCSS)); 156 | } 157 | 158 | head.appendChild(style); 159 | 160 | const ss = document.createElement( 'link' ); 161 | ss.type = 'text/css'; 162 | ss.rel = 'stylesheet'; 163 | ss.href = 'https://fonts.googleapis.com/css?family=Roboto+Mono'; 164 | 165 | head.appendChild( ss ); 166 | 167 | this.grid.addEventListener( 'wheel', e => { 168 | 169 | var direction = ( e.deltaY < 0 ) ? 1 : -1; 170 | 171 | this.camera.zoom += direction / 50; 172 | this.camera.updateProjectionMatrix(); 173 | this.grid.style.transform = `translate3d(-50%, -50%, 0 ) scale(${this.camera.zoom},${this.camera.zoom}) translate3d(${this.offsetX}px,${this.offsetY}px,0) `; 174 | this.label.style.transform = `scale(${1/this.camera.zoom},${1/this.camera.zoom})`; 175 | this.hotspot.style.transform = `scale(${1/this.camera.zoom},${1/this.camera.zoom})`; 176 | this.hotspot.style.borderWidth = `${1/this.camera.zoom}px`; 177 | this.readPixel( this.currentObj, this.currentU, this.currentV ); 178 | 179 | } ); 180 | 181 | let dragging = false; 182 | let mouseStart = { x: 0, y: 0 }; 183 | let offsetStart = { x: 0, y: 0 }; 184 | 185 | this.grid.addEventListener( 'mousedown', e => { 186 | 187 | dragging = true; 188 | mouseStart.x = e.clientX; 189 | mouseStart.y = e.clientY; 190 | offsetStart.x = this.offsetX; 191 | offsetStart.y = this.offsetY; 192 | 193 | } ); 194 | 195 | this.grid.addEventListener( 'mouseup', e => { 196 | 197 | dragging = false; 198 | 199 | } ); 200 | 201 | this.grid.addEventListener( 'mouseout', e => { 202 | 203 | this.label.style.display = 'none'; 204 | dragging = false; 205 | 206 | } ); 207 | 208 | this.grid.addEventListener( 'mouseover', e => { 209 | 210 | this.label.style.display = 'block'; 211 | 212 | } ); 213 | 214 | this.grid.addEventListener( 'mousemove', e => { 215 | 216 | if( dragging ) { 217 | 218 | this.offsetX = offsetStart.x + ( e.clientX - mouseStart.x ) / this.camera.zoom; 219 | this.offsetY = offsetStart.y + ( e.clientY - mouseStart.y ) / this.camera.zoom; 220 | this.camera.position.x = -this.offsetX; 221 | this.camera.position.y = this.offsetY; 222 | 223 | this.grid.style.transform = `translate3d(-50%, -50%, 0 ) scale(${this.camera.zoom},${this.camera.zoom}) translate3d(${this.offsetX}px,${this.offsetY}px,0)`; 224 | 225 | } else { 226 | 227 | this.mouse.x = ( e.clientX / renderer.domElement.clientWidth ) * 2 - 1; 228 | this.mouse.y = - ( e.clientY / renderer.domElement.clientHeight ) * 2 + 1; 229 | this.raycaster.setFromCamera( this.mouse, this.camera ); 230 | 231 | const intersects = this.raycaster.intersectObject( this.currentObj.quad, true ); 232 | 233 | if ( intersects.length > 0 ) { 234 | 235 | this.readPixel( this.fboMap.get( intersects[ 0 ].object ), intersects[ 0 ].uv.x, intersects[ 0 ].uv.y ); 236 | this.label.style.display = 'block'; 237 | 238 | } else { 239 | 240 | this.label.style.display = 'none'; 241 | 242 | } 243 | 244 | } 245 | 246 | } ); 247 | 248 | window.addEventListener( 'keydown', e => { 249 | if( e.keyCode === 27 ) { 250 | this.hide(); 251 | } 252 | } ); 253 | 254 | this.grid.addEventListener( 'keydown', e => { 255 | if( e.keyCode === 27 ) { 256 | this.hide(); 257 | } 258 | } ); 259 | 260 | } 261 | 262 | hide() { 263 | 264 | this.hideAll(); 265 | this.info.style.display = 'none'; 266 | this.grid.style.display = 'none'; 267 | this.currentObj = null; 268 | 269 | } 270 | 271 | attach( fbo, name, formatter ) { 272 | 273 | var li = document.createElement( 'li' ); 274 | 275 | li.textContent = name; 276 | 277 | if( fbo.image ) { 278 | fbo.width = fbo.image.width; 279 | fbo.height = fbo.image.height; 280 | } 281 | 282 | const width = 600; 283 | const height = fbo.height * width / fbo.width; 284 | 285 | const material = new THREE.MeshBasicMaterial( { map: fbo, side: THREE.DoubleSide } ); 286 | const quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 1, 1 ), material ); 287 | if( !fbo.flipY ) quad.rotation.x = Math.PI; 288 | quad.visible = false; 289 | quad.width = width; 290 | quad.height = height; 291 | quad.scale.set( width, height, 1. ); 292 | this.scene.add( quad ); 293 | 294 | var fboData = { 295 | width: width, 296 | height: height, 297 | name: name, 298 | fbo: fbo, 299 | flipY: fbo.flipY, 300 | li: li, 301 | visible: false, 302 | quad: quad, 303 | material: material, 304 | formatter: formatter 305 | }; 306 | this.fbos.push( fboData ); 307 | this.fboMap.set( quad, fboData ); 308 | 309 | li.addEventListener( 'click', e => { 310 | quad.visible = !quad.visible; 311 | if( quad.visible ) { 312 | this.hideAll(); 313 | quad.visible = true; 314 | li.classList.add( 'active' ); 315 | this.info.style.display = 'block'; 316 | this.grid.style.display = 'block'; 317 | this.grid.style.width = ( fboData.width + 2 ) + 'px'; 318 | this.grid.style.height = ( fboData.height + 2 ) + 'px'; 319 | this.currentObj = fboData; 320 | this.info.innerHTML = `Width: ${fbo.width} Height: ${fbo.height}
Format: ${formats[fbo.texture?fbo.texture.format:fbo.format]} Type: ${types[fbo.texture?fbo.texture.type:fbo.type]}`; 321 | } else { 322 | this.info.style.display = 'none'; 323 | li.classList.remove( 'active' ); 324 | this.grid.style.display = 'none'; 325 | this.currentObj = null; 326 | } 327 | } ); 328 | 329 | this.buildList(); 330 | 331 | } 332 | 333 | detach( f ) { 334 | 335 | var p = 0; 336 | for( var fbo of this.fbos ) { 337 | if( fbo.fbo === f ) { 338 | this.fbos.splice( p, 1 ) 339 | } 340 | p++; 341 | } 342 | 343 | this.buildList(); 344 | 345 | } 346 | 347 | refreshFBO( f ) { 348 | 349 | for( var fbo of this.fbos ) { 350 | if( fbo.fbo === f ) { 351 | const width = 600; 352 | const height = f.height * width / f.width; 353 | fbo.width = width; 354 | fbo.height = height; 355 | fbo.quad.width = width; 356 | fbo.quad.height = height; 357 | fbo.quad.scale.set( width, height, 1. ); 358 | } 359 | } 360 | 361 | } 362 | 363 | hideAll() { 364 | 365 | this.fbos.forEach( fbo => { 366 | fbo.quad.visible = false; 367 | fbo.li.classList.remove( 'active' ); 368 | } ); 369 | 370 | } 371 | 372 | buildList() { 373 | 374 | while( this.list.firstChild ) this.list.removeChild( this.list.firstChild ); 375 | 376 | for( var fbo of this.fbos ) { 377 | this.list.appendChild( fbo.li ); 378 | } 379 | 380 | } 381 | 382 | setSize( w, h ) { 383 | 384 | this.camera.left = w / - 2; 385 | this.camera.right = w / 2; 386 | this.camera.top = h / 2; 387 | this.camera.bottom = h / - 2; 388 | 389 | this.camera.updateProjectionMatrix(); 390 | 391 | } 392 | 393 | readPixel( obj, u, v ) { 394 | 395 | this.currentU = u; 396 | this.currentV = v; 397 | 398 | if( this.currentObj === null ) return; 399 | 400 | const fbo = obj.fbo; 401 | 402 | const x = ~~( fbo.width * u ); 403 | const y = ~~( fbo.height * v ); 404 | 405 | let types = {} 406 | types[ THREE.UnsignedByteType ] = Uint8Array; 407 | types[ THREE.ByteType ] = Int8Array; 408 | types[ THREE.ShortType ] = Int16Array; 409 | types[ THREE.UnsignedShortType ] = Uint16Array; 410 | types[ THREE.IntType ] = Int32Array; 411 | types[ THREE.UnsignedIntType ] = Uint32Array; 412 | types[ THREE.FloatType ] = Float32Array; 413 | types[ THREE.HalfFloatType ] = null; 414 | types[ THREE.UnsignedShort4444Type ] = Uint16Array; 415 | types[ THREE.UnsignedShort5551Type ] = Uint16Array; 416 | types[ THREE.UnsignedShort565Type ] = Uint16Array; 417 | 418 | var type = types[ fbo.texture ? fbo.texture.type : fbo.type ]; 419 | if( type === null ) { 420 | console.warning( fbo.texture ? fbo.texture.type : fbo.type + ' not supported' ); 421 | return; 422 | } 423 | 424 | const pixelBuffer = new ( type )( 4 ); 425 | 426 | this.renderer.readRenderTargetPixels( fbo, x, y, 1, 1, pixelBuffer ); 427 | const posTxt = `X : ${x} Y: ${y} u: ${u} v: ${v}`; 428 | const dataTxt = obj.formatter ? 429 | obj.formatter( { 430 | x: x, 431 | y: y, 432 | u: u, 433 | v: v, 434 | r: pixelBuffer[ 0 ], 435 | g: pixelBuffer[ 1 ], 436 | b: pixelBuffer[ 2 ], 437 | a: pixelBuffer[ 3 ] 438 | } ) 439 | : 440 | `R: ${pixelBuffer[ 0 ]} G: ${pixelBuffer[ 1 ]} B: ${pixelBuffer[ 2 ]} A: ${pixelBuffer[ 3 ]}`; 441 | this.label.innerHTML = `${posTxt}
${dataTxt}`; 442 | 443 | const ox = ~~( u * fbo.width ) * obj.quad.width / fbo.width; 444 | const oy = ~~( obj.flipY ? ( 1 - v ) * fbo.height : v * fbo.height ) * obj.quad.height / fbo.height; 445 | this.hotspot.style.width = `${obj.quad.width / fbo.width}px`; 446 | this.hotspot.style.height = `${obj.quad.height / fbo.height}px`; 447 | this.hotspot.style.transform = `translate3d(${ox}px,${oy}px,0)`; 448 | this.label.style.bottom = ( obj.quad.height / fbo.height ) + 'px'; 449 | 450 | } 451 | 452 | 453 | show( state ) { 454 | 455 | this.list.style.display = state ? 'block' : 'none'; 456 | 457 | } 458 | 459 | update() { 460 | 461 | this.renderer.autoClear = false; 462 | this.renderer.render( this.scene, this.camera ); 463 | this.renderer.autoClear = true; 464 | if( this.autoUpdate ) this.readPixel( this.currentObj, this.currentU, this.currentV ); 465 | 466 | } 467 | 468 | } 469 | 470 | if( typeof exports !== 'undefined' ) { 471 | if( typeof module !== 'undefined' && module.exports ) { 472 | exports = module.exports = FBOHelper 473 | } 474 | exports.FBOHelper = FBOHelper 475 | } 476 | else { 477 | root.FBOHelper = FBOHelper 478 | } 479 | 480 | }).call(this); 481 | 482 | -------------------------------------------------------------------------------- /js/THREE.MeshLine.js: -------------------------------------------------------------------------------- 1 | ;(function() { 2 | 3 | "use strict"; 4 | 5 | var root = this 6 | 7 | var has_require = typeof require !== 'undefined' 8 | 9 | var THREE = root.THREE || has_require && require('three') 10 | if( !THREE ) 11 | throw new Error( 'MeshLine requires three.js' ) 12 | 13 | function MeshLine() { 14 | 15 | this.positions = []; 16 | 17 | this.previous = []; 18 | this.next = []; 19 | this.side = []; 20 | this.width = []; 21 | this.indices_array = []; 22 | this.uvs = []; 23 | this.counters = []; 24 | this.geometry = new THREE.BufferGeometry(); 25 | 26 | this.widthCallback = null; 27 | 28 | } 29 | 30 | MeshLine.prototype.setGeometry = function( g, c ) { 31 | 32 | this.widthCallback = c; 33 | 34 | this.positions = []; 35 | this.counters = []; 36 | 37 | if( g instanceof THREE.Geometry ) { 38 | for( var j = 0; j < g.vertices.length; j++ ) { 39 | var v = g.vertices[ j ]; 40 | var c = j/g.vertices.length; 41 | this.positions.push( v.x, v.y, v.z ); 42 | this.positions.push( v.x, v.y, v.z ); 43 | this.counters.push(c); 44 | this.counters.push(c); 45 | } 46 | } 47 | 48 | if( g instanceof THREE.BufferGeometry ) { 49 | // read attribute positions ? 50 | } 51 | 52 | if( g instanceof Float32Array || g instanceof Array ) { 53 | for( var j = 0; j < g.length; j += 3 ) { 54 | var c = j/g.length; 55 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); 56 | this.positions.push( g[ j ], g[ j + 1 ], g[ j + 2 ] ); 57 | this.counters.push(c); 58 | this.counters.push(c); 59 | } 60 | } 61 | 62 | this.process(); 63 | 64 | } 65 | 66 | MeshLine.prototype.compareV3 = function( a, b ) { 67 | 68 | var aa = a * 6; 69 | var ab = b * 6; 70 | return ( this.positions[ aa ] === this.positions[ ab ] ) && ( this.positions[ aa + 1 ] === this.positions[ ab + 1 ] ) && ( this.positions[ aa + 2 ] === this.positions[ ab + 2 ] ); 71 | 72 | } 73 | 74 | MeshLine.prototype.copyV3 = function( a ) { 75 | 76 | var aa = a * 6; 77 | return [ this.positions[ aa ], this.positions[ aa + 1 ], this.positions[ aa + 2 ] ]; 78 | 79 | } 80 | 81 | MeshLine.prototype.process = function() { 82 | 83 | var l = this.positions.length / 6; 84 | 85 | this.previous = []; 86 | this.next = []; 87 | this.side = []; 88 | this.width = []; 89 | this.indices_array = []; 90 | this.uvs = []; 91 | 92 | for( var j = 0; j < l; j++ ) { 93 | this.side.push( 1 ); 94 | this.side.push( -1 ); 95 | } 96 | 97 | var w; 98 | for( var j = 0; j < l; j++ ) { 99 | if( this.widthCallback ) w = this.widthCallback( j / ( l -1 ) ); 100 | else w = 1; 101 | this.width.push( w ); 102 | this.width.push( w ); 103 | } 104 | 105 | for( var j = 0; j < l; j++ ) { 106 | this.uvs.push( j / ( l - 1 ), 0 ); 107 | this.uvs.push( j / ( l - 1 ), 1 ); 108 | } 109 | 110 | var v; 111 | 112 | if( this.compareV3( 0, l - 1 ) ){ 113 | v = this.copyV3( l - 2 ); 114 | } else { 115 | v = this.copyV3( 0 ); 116 | } 117 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 118 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 119 | for( var j = 0; j < l - 1; j++ ) { 120 | v = this.copyV3( j ); 121 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 122 | this.previous.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 123 | } 124 | 125 | for( var j = 1; j < l; j++ ) { 126 | v = this.copyV3( j ); 127 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 128 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 129 | } 130 | 131 | if( this.compareV3( l - 1, 0 ) ){ 132 | v = this.copyV3( 1 ); 133 | } else { 134 | v = this.copyV3( l - 1 ); 135 | } 136 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 137 | this.next.push( v[ 0 ], v[ 1 ], v[ 2 ] ); 138 | 139 | for( var j = 0; j < l - 1; j++ ) { 140 | var n = j * 2; 141 | this.indices_array.push( n, n + 1, n + 2 ); 142 | this.indices_array.push( n + 2, n + 1, n + 3 ); 143 | } 144 | 145 | if (!this.attributes) { 146 | this.attributes = { 147 | position: new THREE.BufferAttribute( new Float32Array( this.positions ), 3 ), 148 | previous: new THREE.BufferAttribute( new Float32Array( this.previous ), 3 ), 149 | next: new THREE.BufferAttribute( new Float32Array( this.next ), 3 ), 150 | side: new THREE.BufferAttribute( new Float32Array( this.side ), 1 ), 151 | width: new THREE.BufferAttribute( new Float32Array( this.width ), 1 ), 152 | uv: new THREE.BufferAttribute( new Float32Array( this.uvs ), 2 ), 153 | index: new THREE.BufferAttribute( new Uint16Array( this.indices_array ), 1 ), 154 | counters: new THREE.BufferAttribute( new Float32Array( this.counters ), 1 ) 155 | } 156 | } else { 157 | this.attributes.position.copyArray(new Float32Array(this.positions)); 158 | this.attributes.position.needsUpdate = true; 159 | this.attributes.previous.copyArray(new Float32Array(this.previous)); 160 | this.attributes.previous.needsUpdate = true; 161 | this.attributes.next.copyArray(new Float32Array(this.next)); 162 | this.attributes.next.needsUpdate = true; 163 | this.attributes.side.copyArray(new Float32Array(this.side)); 164 | this.attributes.side.needsUpdate = true; 165 | this.attributes.width.copyArray(new Float32Array(this.width)); 166 | this.attributes.width.needsUpdate = true; 167 | this.attributes.uv.copyArray(new Float32Array(this.uvs)); 168 | this.attributes.uv.needsUpdate = true; 169 | this.attributes.index.copyArray(new Uint16Array(this.indices_array)); 170 | this.attributes.index.needsUpdate = true; 171 | } 172 | 173 | this.geometry.addAttribute( 'position', this.attributes.position ); 174 | this.geometry.addAttribute( 'previous', this.attributes.previous ); 175 | this.geometry.addAttribute( 'next', this.attributes.next ); 176 | this.geometry.addAttribute( 'side', this.attributes.side ); 177 | this.geometry.addAttribute( 'width', this.attributes.width ); 178 | this.geometry.addAttribute( 'uv', this.attributes.uv ); 179 | this.geometry.addAttribute( 'counters', this.attributes.counters ); 180 | 181 | this.geometry.setIndex( this.attributes.index ); 182 | 183 | } 184 | 185 | function memcpy (src, srcOffset, dst, dstOffset, length) { 186 | var i 187 | 188 | src = src.subarray || src.slice ? src : src.buffer 189 | dst = dst.subarray || dst.slice ? dst : dst.buffer 190 | 191 | src = srcOffset ? src.subarray ? 192 | src.subarray(srcOffset, length && srcOffset + length) : 193 | src.slice(srcOffset, length && srcOffset + length) : src 194 | 195 | if (dst.set) { 196 | dst.set(src, dstOffset) 197 | } else { 198 | for (i=0; i 0 && seed < 1) { 57 | // Scale the seed out 58 | seed *= 65536; 59 | } 60 | 61 | seed = Math.floor(seed); 62 | if(seed < 256) { 63 | seed |= seed << 8; 64 | } 65 | 66 | for(var i = 0; i < 256; i++) { 67 | var v; 68 | if (i & 1) { 69 | v = p[i] ^ (seed & 255); 70 | } else { 71 | v = p[i] ^ ((seed>>8) & 255); 72 | } 73 | 74 | perm[i] = perm[i + 256] = v; 75 | gradP[i] = gradP[i + 256] = grad3[v % 12]; 76 | } 77 | }; 78 | 79 | module.seed(0); 80 | 81 | /* 82 | for(var i=0; i<256; i++) { 83 | perm[i] = perm[i + 256] = p[i]; 84 | gradP[i] = gradP[i + 256] = grad3[perm[i] % 12]; 85 | }*/ 86 | 87 | // Skewing and unskewing factors for 2, 3, and 4 dimensions 88 | var F2 = 0.5*(Math.sqrt(3)-1); 89 | var G2 = (3-Math.sqrt(3))/6; 90 | 91 | var F3 = 1/3; 92 | var G3 = 1/6; 93 | 94 | // 2D simplex noise 95 | module.simplex2 = function(xin, yin) { 96 | var n0, n1, n2; // Noise contributions from the three corners 97 | // Skew the input space to determine which simplex cell we're in 98 | var s = (xin+yin)*F2; // Hairy factor for 2D 99 | var i = Math.floor(xin+s); 100 | var j = Math.floor(yin+s); 101 | var t = (i+j)*G2; 102 | var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed. 103 | var y0 = yin-j+t; 104 | // For the 2D case, the simplex shape is an equilateral triangle. 105 | // Determine which simplex we are in. 106 | var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords 107 | if(x0>y0) { // lower triangle, XY order: (0,0)->(1,0)->(1,1) 108 | i1=1; j1=0; 109 | } else { // upper triangle, YX order: (0,0)->(0,1)->(1,1) 110 | i1=0; j1=1; 111 | } 112 | // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and 113 | // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where 114 | // c = (3-sqrt(3))/6 115 | var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords 116 | var y1 = y0 - j1 + G2; 117 | var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords 118 | var y2 = y0 - 1 + 2 * G2; 119 | // Work out the hashed gradient indices of the three simplex corners 120 | i &= 255; 121 | j &= 255; 122 | var gi0 = gradP[i+perm[j]]; 123 | var gi1 = gradP[i+i1+perm[j+j1]]; 124 | var gi2 = gradP[i+1+perm[j+1]]; 125 | // Calculate the contribution from the three corners 126 | var t0 = 0.5 - x0*x0-y0*y0; 127 | if(t0<0) { 128 | n0 = 0; 129 | } else { 130 | t0 *= t0; 131 | n0 = t0 * t0 * gi0.dot2(x0, y0); // (x,y) of grad3 used for 2D gradient 132 | } 133 | var t1 = 0.5 - x1*x1-y1*y1; 134 | if(t1<0) { 135 | n1 = 0; 136 | } else { 137 | t1 *= t1; 138 | n1 = t1 * t1 * gi1.dot2(x1, y1); 139 | } 140 | var t2 = 0.5 - x2*x2-y2*y2; 141 | if(t2<0) { 142 | n2 = 0; 143 | } else { 144 | t2 *= t2; 145 | n2 = t2 * t2 * gi2.dot2(x2, y2); 146 | } 147 | // Add contributions from each corner to get the final noise value. 148 | // The result is scaled to return values in the interval [-1,1]. 149 | return 70 * (n0 + n1 + n2); 150 | }; 151 | 152 | // 3D simplex noise 153 | module.simplex3 = function(xin, yin, zin) { 154 | var n0, n1, n2, n3; // Noise contributions from the four corners 155 | 156 | // Skew the input space to determine which simplex cell we're in 157 | var s = (xin+yin+zin)*F3; // Hairy factor for 2D 158 | var i = Math.floor(xin+s); 159 | var j = Math.floor(yin+s); 160 | var k = Math.floor(zin+s); 161 | 162 | var t = (i+j+k)*G3; 163 | var x0 = xin-i+t; // The x,y distances from the cell origin, unskewed. 164 | var y0 = yin-j+t; 165 | var z0 = zin-k+t; 166 | 167 | // For the 3D case, the simplex shape is a slightly irregular tetrahedron. 168 | // Determine which simplex we are in. 169 | var i1, j1, k1; // Offsets for second corner of simplex in (i,j,k) coords 170 | var i2, j2, k2; // Offsets for third corner of simplex in (i,j,k) coords 171 | if(x0 >= y0) { 172 | if(y0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=1; k2=0; } 173 | else if(x0 >= z0) { i1=1; j1=0; k1=0; i2=1; j2=0; k2=1; } 174 | else { i1=0; j1=0; k1=1; i2=1; j2=0; k2=1; } 175 | } else { 176 | if(y0 < z0) { i1=0; j1=0; k1=1; i2=0; j2=1; k2=1; } 177 | else if(x0 < z0) { i1=0; j1=1; k1=0; i2=0; j2=1; k2=1; } 178 | else { i1=0; j1=1; k1=0; i2=1; j2=1; k2=0; } 179 | } 180 | // A step of (1,0,0) in (i,j,k) means a step of (1-c,-c,-c) in (x,y,z), 181 | // a step of (0,1,0) in (i,j,k) means a step of (-c,1-c,-c) in (x,y,z), and 182 | // a step of (0,0,1) in (i,j,k) means a step of (-c,-c,1-c) in (x,y,z), where 183 | // c = 1/6. 184 | var x1 = x0 - i1 + G3; // Offsets for second corner 185 | var y1 = y0 - j1 + G3; 186 | var z1 = z0 - k1 + G3; 187 | 188 | var x2 = x0 - i2 + 2 * G3; // Offsets for third corner 189 | var y2 = y0 - j2 + 2 * G3; 190 | var z2 = z0 - k2 + 2 * G3; 191 | 192 | var x3 = x0 - 1 + 3 * G3; // Offsets for fourth corner 193 | var y3 = y0 - 1 + 3 * G3; 194 | var z3 = z0 - 1 + 3 * G3; 195 | 196 | // Work out the hashed gradient indices of the four simplex corners 197 | i &= 255; 198 | j &= 255; 199 | k &= 255; 200 | var gi0 = gradP[i+ perm[j+ perm[k ]]]; 201 | var gi1 = gradP[i+i1+perm[j+j1+perm[k+k1]]]; 202 | var gi2 = gradP[i+i2+perm[j+j2+perm[k+k2]]]; 203 | var gi3 = gradP[i+ 1+perm[j+ 1+perm[k+ 1]]]; 204 | 205 | // Calculate the contribution from the four corners 206 | var t0 = 0.6 - x0*x0 - y0*y0 - z0*z0; 207 | if(t0<0) { 208 | n0 = 0; 209 | } else { 210 | t0 *= t0; 211 | n0 = t0 * t0 * gi0.dot3(x0, y0, z0); // (x,y) of grad3 used for 2D gradient 212 | } 213 | var t1 = 0.6 - x1*x1 - y1*y1 - z1*z1; 214 | if(t1<0) { 215 | n1 = 0; 216 | } else { 217 | t1 *= t1; 218 | n1 = t1 * t1 * gi1.dot3(x1, y1, z1); 219 | } 220 | var t2 = 0.6 - x2*x2 - y2*y2 - z2*z2; 221 | if(t2<0) { 222 | n2 = 0; 223 | } else { 224 | t2 *= t2; 225 | n2 = t2 * t2 * gi2.dot3(x2, y2, z2); 226 | } 227 | var t3 = 0.6 - x3*x3 - y3*y3 - z3*z3; 228 | if(t3<0) { 229 | n3 = 0; 230 | } else { 231 | t3 *= t3; 232 | n3 = t3 * t3 * gi3.dot3(x3, y3, z3); 233 | } 234 | // Add contributions from each corner to get the final noise value. 235 | // The result is scaled to return values in the interval [-1,1]. 236 | return 32 * (n0 + n1 + n2 + n3); 237 | 238 | }; 239 | 240 | // ##### Perlin noise stuff 241 | 242 | function fade(t) { 243 | return t*t*t*(t*(t*6-15)+10); 244 | } 245 | 246 | function lerp(a, b, t) { 247 | return (1-t)*a + t*b; 248 | } 249 | 250 | // 2D Perlin Noise 251 | module.perlin2 = function(x, y) { 252 | // Find unit grid cell containing point 253 | var X = Math.floor(x), Y = Math.floor(y); 254 | // Get relative xy coordinates of point within that cell 255 | x = x - X; y = y - Y; 256 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 257 | X = X & 255; Y = Y & 255; 258 | 259 | // Calculate noise contributions from each of the four corners 260 | var n00 = gradP[X+perm[Y]].dot2(x, y); 261 | var n01 = gradP[X+perm[Y+1]].dot2(x, y-1); 262 | var n10 = gradP[X+1+perm[Y]].dot2(x-1, y); 263 | var n11 = gradP[X+1+perm[Y+1]].dot2(x-1, y-1); 264 | 265 | // Compute the fade curve value for x 266 | var u = fade(x); 267 | 268 | // Interpolate the four results 269 | return lerp( 270 | lerp(n00, n10, u), 271 | lerp(n01, n11, u), 272 | fade(y)); 273 | }; 274 | 275 | // 3D Perlin Noise 276 | module.perlin3 = function(x, y, z) { 277 | // Find unit grid cell containing point 278 | var X = Math.floor(x), Y = Math.floor(y), Z = Math.floor(z); 279 | // Get relative xyz coordinates of point within that cell 280 | x = x - X; y = y - Y; z = z - Z; 281 | // Wrap the integer cells at 255 (smaller integer period can be introduced here) 282 | X = X & 255; Y = Y & 255; Z = Z & 255; 283 | 284 | // Calculate noise contributions from each of the eight corners 285 | var n000 = gradP[X+ perm[Y+ perm[Z ]]].dot3(x, y, z); 286 | var n001 = gradP[X+ perm[Y+ perm[Z+1]]].dot3(x, y, z-1); 287 | var n010 = gradP[X+ perm[Y+1+perm[Z ]]].dot3(x, y-1, z); 288 | var n011 = gradP[X+ perm[Y+1+perm[Z+1]]].dot3(x, y-1, z-1); 289 | var n100 = gradP[X+1+perm[Y+ perm[Z ]]].dot3(x-1, y, z); 290 | var n101 = gradP[X+1+perm[Y+ perm[Z+1]]].dot3(x-1, y, z-1); 291 | var n110 = gradP[X+1+perm[Y+1+perm[Z ]]].dot3(x-1, y-1, z); 292 | var n111 = gradP[X+1+perm[Y+1+perm[Z+1]]].dot3(x-1, y-1, z-1); 293 | 294 | // Compute the fade curve value for x, y, z 295 | var u = fade(x); 296 | var v = fade(y); 297 | var w = fade(z); 298 | 299 | // Interpolate 300 | return lerp( 301 | lerp( 302 | lerp(n000, n100, u), 303 | lerp(n001, n101, u), w), 304 | lerp( 305 | lerp(n010, n110, u), 306 | lerp(n011, n111, u), w), 307 | v); 308 | }; 309 | 310 | })(this); 311 | -------------------------------------------------------------------------------- /plasma-waves/index copy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 82 | 83 | 101 | 102 | 398 | 399 | 400 | 401 | -------------------------------------------------------------------------------- /plasma-waves/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Plasma Waves - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

6. Plasma Waves

18 |

Experiment with sorting particles, set up with curl noise, and disturbed with another curl noise.

19 |

Click here to generate a new one

20 |

Click or tap and drag to move the camera, scroll or zoom with two fingers to zoom in and out.

More details...

21 |
22 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 53 | 54 | 55 | 72 | 73 | 120 | 121 | 142 | 143 | 491 | 492 | 493 | 494 | -------------------------------------------------------------------------------- /sdf-physics/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 52 | 53 | 76 | 77 | 237 | 238 | 281 | 282 | 292 | 293 | 584 | 585 | 586 | 587 | -------------------------------------------------------------------------------- /terrain/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /whirly-bonfire/index copy.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | TITLE - Codevember 2017 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Previous | Next

17 |

#. TITLE

18 |

Lorem ipsum

19 |

More details...

20 |
21 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 111 | 112 | 129 | 130 | 344 | 345 | 346 | 347 | --------------------------------------------------------------------------------