├── .gitignore
├── LICENSE
├── README.md
├── images
├── LitSphere_test_02.jpg
├── ghost_strip.gif
├── matball01.jpg
├── poi_icons_32.png
├── skylight.jpg
├── sunset.jpg
└── wheel.png
├── index.html
├── lib
├── dat.gui.min.js
└── leaflet-hash.js
├── main.js
├── scene.yaml
├── shaders
├── color_bleed.glsl
├── dots.glsl
├── elevator.glsl
├── glsl-noise-periodic-3d.glsl
├── noise.glsl
├── spotlight.glsl
└── wood.glsl
└── styles
├── breathe.yaml
├── dots.yaml
├── halftone.yaml
├── popup.yaml
└── windows.yaml
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/tangram/*
2 | !node_modules/tangram/dist/
3 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Mapzen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # shaders-demo
2 |
3 | A demo showing some ways to use GLSL shaders to draw maps with the [Tangram](http://github.com/tangrams/tangram) library.
4 |
5 | Live demo: http://tangrams.github.io/shaders-demo
6 |
7 | 
8 |
9 | ### To run locally:
10 |
11 | Download this repo, then start a web server in its directory:
12 |
13 | python -m SimpleHTTPServer 8000
14 |
15 | If that doesn't work, try:
16 |
17 | python -m http.server 8000
18 |
19 | Then navigate to: [http://localhost:8000](http://localhost:8000)
20 |
--------------------------------------------------------------------------------
/images/LitSphere_test_02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/LitSphere_test_02.jpg
--------------------------------------------------------------------------------
/images/ghost_strip.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/ghost_strip.gif
--------------------------------------------------------------------------------
/images/matball01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/matball01.jpg
--------------------------------------------------------------------------------
/images/poi_icons_32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/poi_icons_32.png
--------------------------------------------------------------------------------
/images/skylight.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/skylight.jpg
--------------------------------------------------------------------------------
/images/sunset.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/sunset.jpg
--------------------------------------------------------------------------------
/images/wheel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tangrams/shaders-demo/6857e4671bbad391d2c059c1c26436ae01e7d780/images/wheel.png
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
11 |
12 |
13 | Shaders demo - Tangram
14 |
15 |
16 |
17 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/lib/dat.gui.min.js:
--------------------------------------------------------------------------------
1 | var dat=dat||{};dat.gui=dat.gui||{};dat.utils=dat.utils||{};dat.controllers=dat.controllers||{};dat.dom=dat.dom||{};dat.color=dat.color||{};dat.utils.css=function(){return{load:function(e,a){a=a||document;var b=a.createElement("link");b.type="text/css";b.rel="stylesheet";b.href=e;a.getElementsByTagName("head")[0].appendChild(b)},inject:function(e,a){a=a||document;var b=document.createElement("style");b.type="text/css";b.innerHTML=e;a.getElementsByTagName("head")[0].appendChild(b)}}}();
2 | dat.utils.common=function(){var e=Array.prototype.forEach,a=Array.prototype.slice;return{BREAK:{},extend:function(b){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(a[f])||(b[f]=a[f])},this);return b},defaults:function(b){this.each(a.call(arguments,1),function(a){for(var f in a)this.isUndefined(b[f])&&(b[f]=a[f])},this);return b},compose:function(){var b=a.call(arguments);return function(){for(var d=a.call(arguments),f=b.length-1;0<=f;f--)d=[b[f].apply(this,d)];return d[0]}},
3 | each:function(a,d,f){if(e&&a.forEach===e)a.forEach(d,f);else if(a.length===a.length+0)for(var c=0,p=a.length;cthis.__max&&(a=this.__max);void 0!==this.__step&&0!=a%this.__step&&(a=Math.round(a/this.__step)*this.__step);return b.superclass.prototype.setValue.call(this,a)},min:function(a){this.__min=a;return this},max:function(a){this.__max=a;return this},step:function(a){this.__step=a;return this}});return b}(dat.controllers.Controller,dat.utils.common);
17 | dat.controllers.NumberControllerBox=function(e,a,b){var d=function(f,c,e){function k(){var a=parseFloat(n.__input.value);b.isNaN(a)||n.setValue(a)}function l(a){var c=r-a.clientY;n.setValue(n.getValue()+c*n.__impliedStep);r=a.clientY}function q(){a.unbind(window,"mousemove",l);a.unbind(window,"mouseup",q)}this.__truncationSuspended=!1;d.superclass.call(this,f,c,e);var n=this,r;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"change",k);a.bind(this.__input,
18 | "blur",function(){k();n.__onFinishChange&&n.__onFinishChange.call(n,n.getValue())});a.bind(this.__input,"mousedown",function(c){a.bind(window,"mousemove",l);a.bind(window,"mouseup",q);r=c.clientY});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&(n.__truncationSuspended=!0,this.blur(),n.__truncationSuspended=!1)});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;b.extend(d.prototype,e.prototype,{updateDisplay:function(){var a=this.__input,c;if(this.__truncationSuspended)c=
19 | this.getValue();else{c=this.getValue();var b=Math.pow(10,this.__precision);c=Math.round(c*b)/b}a.value=c;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.NumberController,dat.dom.dom,dat.utils.common);
20 | dat.controllers.NumberControllerSlider=function(e,a,b,d,f){function c(a,c,d,b,f){return b+(a-c)/(d-c)*(f-b)}var p=function(d,b,f,e,r){function y(d){d.preventDefault();var b=a.getOffset(h.__background),f=a.getWidth(h.__background);h.setValue(c(d.clientX,b.left,b.left+f,h.__min,h.__max));return!1}function g(){a.unbind(window,"mousemove",y);a.unbind(window,"mouseup",g);h.__onFinishChange&&h.__onFinishChange.call(h,h.getValue())}p.superclass.call(this,d,b,{min:f,max:e,step:r});var h=this;this.__background=
21 | document.createElement("div");this.__foreground=document.createElement("div");a.bind(this.__background,"mousedown",function(c){a.bind(window,"mousemove",y);a.bind(window,"mouseup",g);y(c)});a.addClass(this.__background,"slider");a.addClass(this.__foreground,"slider-fg");this.updateDisplay();this.__background.appendChild(this.__foreground);this.domElement.appendChild(this.__background)};p.superclass=e;p.useDefaultStyles=function(){b.inject(f)};d.extend(p.prototype,e.prototype,{updateDisplay:function(){var a=
22 | (this.getValue()-this.__min)/(this.__max-this.__min);this.__foreground.style.width=100*a+"%";return p.superclass.prototype.updateDisplay.call(this)}});return p}(dat.controllers.NumberController,dat.dom.dom,dat.utils.css,dat.utils.common,"/**\n * dat-gui JavaScript Controller Library\n * http://code.google.com/p/dat-gui\n *\n * Copyright 2011 Data Arts Team, Google Creative Lab\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n */\n\n.slider {\n box-shadow: inset 0 2px 4px rgba(0,0,0,0.15);\n height: 1em;\n border-radius: 1em;\n background-color: #eee;\n padding: 0 0.5em;\n overflow: hidden;\n}\n\n.slider-fg {\n padding: 1px 0 2px 0;\n background-color: #aaa;\n height: 1em;\n margin-left: -0.5em;\n padding-right: 0.5em;\n border-radius: 1em 0 0 1em;\n}\n\n.slider-fg:after {\n display: inline-block;\n border-radius: 1em;\n background-color: #fff;\n border: 1px solid #aaa;\n content: '';\n float: right;\n margin-right: -1em;\n margin-top: -1px;\n height: 0.9em;\n width: 0.9em;\n}");
23 | dat.controllers.FunctionController=function(e,a,b){var d=function(b,c,e){d.superclass.call(this,b,c);var k=this;this.__button=document.createElement("div");this.__button.innerHTML=void 0===e?"Fire":e;a.bind(this.__button,"click",function(a){a.preventDefault();k.fire();return!1});a.addClass(this.__button,"button");this.domElement.appendChild(this.__button)};d.superclass=e;b.extend(d.prototype,e.prototype,{fire:function(){this.__onChange&&this.__onChange.call(this);this.__onFinishChange&&this.__onFinishChange.call(this,
24 | this.getValue());this.getValue().call(this.object)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
25 | dat.controllers.BooleanController=function(e,a,b){var d=function(b,c){d.superclass.call(this,b,c);var e=this;this.__prev=this.getValue();this.__checkbox=document.createElement("input");this.__checkbox.setAttribute("type","checkbox");a.bind(this.__checkbox,"change",function(){e.setValue(!e.__prev)},!1);this.domElement.appendChild(this.__checkbox);this.updateDisplay()};d.superclass=e;b.extend(d.prototype,e.prototype,{setValue:function(a){a=d.superclass.prototype.setValue.call(this,a);this.__onFinishChange&&
26 | this.__onFinishChange.call(this,this.getValue());this.__prev=this.getValue();return a},updateDisplay:function(){!0===this.getValue()?(this.__checkbox.setAttribute("checked","checked"),this.__checkbox.checked=!0):this.__checkbox.checked=!1;return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common);
27 | dat.color.toString=function(e){return function(a){if(1==a.a||e.isUndefined(a.a)){for(a=a.hex.toString(16);6>a.length;)a="0"+a;return"#"+a}return"rgba("+Math.round(a.r)+","+Math.round(a.g)+","+Math.round(a.b)+","+a.a+")"}}(dat.utils.common);
28 | dat.color.interpret=function(e,a){var b,d,f=[{litmus:a.isString,conversions:{THREE_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9])([A-F0-9])([A-F0-9])$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString()+a[1].toString()+a[2].toString()+a[2].toString()+a[3].toString()+a[3].toString())}},write:e},SIX_CHAR_HEX:{read:function(a){a=a.match(/^#([A-F0-9]{6})$/i);return null===a?!1:{space:"HEX",hex:parseInt("0x"+a[1].toString())}},write:e},CSS_RGB:{read:function(a){a=a.match(/^rgb\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\)/);
29 | return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3])}},write:e},CSS_RGBA:{read:function(a){a=a.match(/^rgba\(\s*(.+)\s*,\s*(.+)\s*,\s*(.+)\s*\,\s*(.+)\s*\)/);return null===a?!1:{space:"RGB",r:parseFloat(a[1]),g:parseFloat(a[2]),b:parseFloat(a[3]),a:parseFloat(a[4])}},write:e}}},{litmus:a.isNumber,conversions:{HEX:{read:function(a){return{space:"HEX",hex:a,conversionName:"HEX"}},write:function(a){return a.hex}}}},{litmus:a.isArray,conversions:{RGB_ARRAY:{read:function(a){return 3!=
30 | a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2]}},write:function(a){return[a.r,a.g,a.b]}},RGBA_ARRAY:{read:function(a){return 4!=a.length?!1:{space:"RGB",r:a[0],g:a[1],b:a[2],a:a[3]}},write:function(a){return[a.r,a.g,a.b,a.a]}}}},{litmus:a.isObject,conversions:{RGBA_OBJ:{read:function(c){return a.isNumber(c.r)&&a.isNumber(c.g)&&a.isNumber(c.b)&&a.isNumber(c.a)?{space:"RGB",r:c.r,g:c.g,b:c.b,a:c.a}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b,a:a.a}}},RGB_OBJ:{read:function(c){return a.isNumber(c.r)&&
31 | a.isNumber(c.g)&&a.isNumber(c.b)?{space:"RGB",r:c.r,g:c.g,b:c.b}:!1},write:function(a){return{r:a.r,g:a.g,b:a.b}}},HSVA_OBJ:{read:function(c){return a.isNumber(c.h)&&a.isNumber(c.s)&&a.isNumber(c.v)&&a.isNumber(c.a)?{space:"HSV",h:c.h,s:c.s,v:c.v,a:c.a}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v,a:a.a}}},HSV_OBJ:{read:function(d){return a.isNumber(d.h)&&a.isNumber(d.s)&&a.isNumber(d.v)?{space:"HSV",h:d.h,s:d.s,v:d.v}:!1},write:function(a){return{h:a.h,s:a.s,v:a.v}}}}}];return function(){d=!1;
32 | var c=1\n\n Here\'s the new load parameter for your GUI
\'s constructor:\n\n \n\n \n\n
Automatically save\n values to
localStorage
on exit.\n\n
The values saved to localStorage
will\n override those passed to dat.GUI
\'s constructor. This makes it\n easier to work incrementally, but localStorage
is fragile,\n and your friends may not see the same values you do.\n \n
\n \n
\n\n',
59 | ".dg {\n /** Clear list styles */\n /* Auto-place container */\n /* Auto-placed GUI's */\n /* Line items that don't contain folders. */\n /** Folder names */\n /** Hides closed items */\n /** Controller row */\n /** Name-half (left) */\n /** Controller-half (right) */\n /** Controller placement */\n /** Shorter number boxes when slider is present. */\n /** Ensure the entire boolean and function row shows a hand */ }\n .dg ul {\n list-style: none;\n margin: 0;\n padding: 0;\n width: 100%;\n clear: both; }\n .dg.ac {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n height: 0;\n z-index: 0; }\n .dg:not(.ac) .main {\n /** Exclude mains in ac so that we don't hide close button */\n overflow: hidden; }\n .dg.main {\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear; }\n .dg.main.taller-than-window {\n overflow-y: auto; }\n .dg.main.taller-than-window .close-button {\n opacity: 1;\n /* TODO, these are style notes */\n margin-top: -1px;\n border-top: 1px solid #2c2c2c; }\n .dg.main ul.closed .close-button {\n opacity: 1 !important; }\n .dg.main:hover .close-button,\n .dg.main .close-button.drag {\n opacity: 1; }\n .dg.main .close-button {\n /*opacity: 0;*/\n -webkit-transition: opacity 0.1s linear;\n -o-transition: opacity 0.1s linear;\n -moz-transition: opacity 0.1s linear;\n transition: opacity 0.1s linear;\n border: 0;\n position: absolute;\n line-height: 19px;\n height: 20px;\n /* TODO, these are style notes */\n cursor: pointer;\n text-align: center;\n background-color: #000; }\n .dg.main .close-button:hover {\n background-color: #111; }\n .dg.a {\n float: right;\n margin-right: 15px;\n overflow-x: hidden; }\n .dg.a.has-save > ul {\n margin-top: 27px; }\n .dg.a.has-save > ul.closed {\n margin-top: 0; }\n .dg.a .save-row {\n position: fixed;\n top: 0;\n z-index: 1002; }\n .dg li {\n -webkit-transition: height 0.1s ease-out;\n -o-transition: height 0.1s ease-out;\n -moz-transition: height 0.1s ease-out;\n transition: height 0.1s ease-out; }\n .dg li:not(.folder) {\n cursor: auto;\n height: 27px;\n line-height: 27px;\n overflow: hidden;\n padding: 0 4px 0 5px; }\n .dg li.folder {\n padding: 0;\n border-left: 4px solid rgba(0, 0, 0, 0); }\n .dg li.title {\n cursor: pointer;\n margin-left: -4px; }\n .dg .closed li:not(.title),\n .dg .closed ul li,\n .dg .closed ul li > * {\n height: 0;\n overflow: hidden;\n border: 0; }\n .dg .cr {\n clear: both;\n padding-left: 3px;\n height: 27px; }\n .dg .property-name {\n cursor: default;\n float: left;\n clear: left;\n width: 40%;\n overflow: hidden;\n text-overflow: ellipsis; }\n .dg .c {\n float: left;\n width: 60%; }\n .dg .c input[type=text] {\n border: 0;\n margin-top: 4px;\n padding: 3px;\n width: 100%;\n float: right; }\n .dg .has-slider input[type=text] {\n width: 30%;\n /*display: none;*/\n margin-left: 0; }\n .dg .slider {\n float: left;\n width: 66%;\n margin-left: -5px;\n margin-right: 0;\n height: 19px;\n margin-top: 4px; }\n .dg .slider-fg {\n height: 100%; }\n .dg .c input[type=checkbox] {\n margin-top: 9px; }\n .dg .c select {\n margin-top: 5px; }\n .dg .cr.function,\n .dg .cr.function .property-name,\n .dg .cr.function *,\n .dg .cr.boolean,\n .dg .cr.boolean * {\n cursor: pointer; }\n .dg .selector {\n display: none;\n position: absolute;\n margin-left: -9px;\n margin-top: 23px;\n z-index: 10; }\n .dg .c:hover .selector,\n .dg .selector.drag {\n display: block; }\n .dg li.save-row {\n padding: 0; }\n .dg li.save-row .button {\n display: inline-block;\n padding: 0px 6px; }\n .dg.dialogue {\n background-color: #222;\n width: 460px;\n padding: 15px;\n font-size: 13px;\n line-height: 15px; }\n\n/* TODO Separate style and structure */\n#dg-new-constructor {\n padding: 10px;\n color: #222;\n font-family: Monaco, monospace;\n font-size: 10px;\n border: 0;\n resize: none;\n box-shadow: inset 1px 1px 1px #888;\n word-wrap: break-word;\n margin: 12px 0;\n display: block;\n width: 440px;\n overflow-y: scroll;\n height: 100px;\n position: relative; }\n\n#dg-local-explain {\n display: none;\n font-size: 11px;\n line-height: 17px;\n border-radius: 3px;\n background-color: #333;\n padding: 8px;\n margin-top: 10px; }\n #dg-local-explain code {\n font-size: 10px; }\n\n#dat-gui-save-locally {\n display: none; }\n\n/** Main type */\n.dg {\n color: #eee;\n font: 11px 'Lucida Grande', sans-serif;\n text-shadow: 0 -1px 0 #111;\n /** Auto place */\n /* Controller row, */\n /** Controllers */ }\n .dg.main {\n /** Scrollbar */ }\n .dg.main::-webkit-scrollbar {\n width: 5px;\n background: #1a1a1a; }\n .dg.main::-webkit-scrollbar-corner {\n height: 0;\n display: none; }\n .dg.main::-webkit-scrollbar-thumb {\n border-radius: 5px;\n background: #676767; }\n .dg li:not(.folder) {\n background: #1a1a1a;\n border-bottom: 1px solid #2c2c2c; }\n .dg li.save-row {\n line-height: 25px;\n background: #dad5cb;\n border: 0; }\n .dg li.save-row select {\n margin-left: 5px;\n width: 108px; }\n .dg li.save-row .button {\n margin-left: 5px;\n margin-top: 1px;\n border-radius: 2px;\n font-size: 9px;\n line-height: 7px;\n padding: 4px 4px 5px 4px;\n background: #c5bdad;\n color: #fff;\n text-shadow: 0 1px 0 #b0a58f;\n box-shadow: 0 -1px 0 #b0a58f;\n cursor: pointer; }\n .dg li.save-row .button.gears {\n 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;\n height: 7px;\n width: 8px; }\n .dg li.save-row .button:hover {\n background-color: #bab19e;\n box-shadow: 0 -1px 0 #b0a58f; }\n .dg li.folder {\n border-bottom: 0; }\n .dg li.title {\n padding-left: 16px;\n background: black url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;\n cursor: pointer;\n border-bottom: 1px solid rgba(255, 255, 255, 0.2); }\n .dg .closed li.title {\n background-image: url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==); }\n .dg .cr.boolean {\n border-left: 3px solid #806787; }\n .dg .cr.function {\n border-left: 3px solid #e61d5f; }\n .dg .cr.number {\n border-left: 3px solid #2fa1d6; }\n .dg .cr.number input[type=text] {\n color: #2fa1d6; }\n .dg .cr.string {\n border-left: 3px solid #1ed36f; }\n .dg .cr.string input[type=text] {\n color: #1ed36f; }\n .dg .cr.function:hover, .dg .cr.boolean:hover {\n background: #111; }\n .dg .c input[type=text] {\n background: #303030;\n outline: none; }\n .dg .c input[type=text]:hover {\n background: #3c3c3c; }\n .dg .c input[type=text]:focus {\n background: #494949;\n color: #fff; }\n .dg .c .slider {\n background: #303030;\n cursor: ew-resize; }\n .dg .c .slider-fg {\n background: #2fa1d6; }\n .dg .c .slider:hover {\n background: #3c3c3c; }\n .dg .c .slider:hover .slider-fg {\n background: #44abda; }\n",
60 | dat.controllers.factory=function(e,a,b,d,f,c,p){return function(k,l,q,n){var r=k[l];if(p.isArray(q)||p.isObject(q))return new e(k,l,q);if(p.isNumber(r))return p.isNumber(q)&&p.isNumber(n)?new b(k,l,q,n):new a(k,l,{min:q,max:n});if(p.isString(r))return new d(k,l);if(p.isFunction(r))return new f(k,l,"");if(p.isBoolean(r))return new c(k,l)}}(dat.controllers.OptionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.StringController=function(e,a,b){var d=
61 | function(b,c){function e(){k.setValue(k.__input.value)}d.superclass.call(this,b,c);var k=this;this.__input=document.createElement("input");this.__input.setAttribute("type","text");a.bind(this.__input,"keyup",e);a.bind(this.__input,"change",e);a.bind(this.__input,"blur",function(){k.__onFinishChange&&k.__onFinishChange.call(k,k.getValue())});a.bind(this.__input,"keydown",function(a){13===a.keyCode&&this.blur()});this.updateDisplay();this.domElement.appendChild(this.__input)};d.superclass=e;b.extend(d.prototype,
62 | e.prototype,{updateDisplay:function(){a.isActive(this.__input)||(this.__input.value=this.getValue());return d.superclass.prototype.updateDisplay.call(this)}});return d}(dat.controllers.Controller,dat.dom.dom,dat.utils.common),dat.controllers.FunctionController,dat.controllers.BooleanController,dat.utils.common),dat.controllers.Controller,dat.controllers.BooleanController,dat.controllers.FunctionController,dat.controllers.NumberControllerBox,dat.controllers.NumberControllerSlider,dat.controllers.OptionController,
63 | dat.controllers.ColorController=function(e,a,b,d,f){function c(a,b,d,c){a.style.background="";f.each(l,function(e){a.style.cssText+="background: "+e+"linear-gradient("+b+", "+d+" 0%, "+c+" 100%); "})}function p(a){a.style.background="";a.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);";a.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";
64 | a.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);";a.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var k=function(e,n){function r(b){t(b);a.bind(window,"mousemove",t);a.bind(window,
65 | "mouseup",l)}function l(){a.unbind(window,"mousemove",t);a.unbind(window,"mouseup",l)}function g(){var a=d(this.value);!1!==a?(s.__color.__state=a,s.setValue(s.__color.toOriginal())):this.value=s.__color.toString()}function h(){a.unbind(window,"mousemove",u);a.unbind(window,"mouseup",h)}function t(b){b.preventDefault();var d=a.getWidth(s.__saturation_field),c=a.getOffset(s.__saturation_field),e=(b.clientX-c.left+document.body.scrollLeft)/d;b=1-(b.clientY-c.top+document.body.scrollTop)/d;1
66 | b&&(b=0);1e&&(e=0);s.__color.v=b;s.__color.s=e;s.setValue(s.__color.toOriginal());return!1}function u(b){b.preventDefault();var d=a.getHeight(s.__hue_field),c=a.getOffset(s.__hue_field);b=1-(b.clientY-c.top+document.body.scrollTop)/d;1b&&(b=0);s.__color.h=360*b;s.setValue(s.__color.toOriginal());return!1}k.superclass.call(this,e,n);this.__color=new b(this.getValue());this.__temp=new b(0);var s=this;this.domElement=document.createElement("div");a.makeSelectable(this.domElement,!1);
67 | this.__selector=document.createElement("div");this.__selector.className="selector";this.__saturation_field=document.createElement("div");this.__saturation_field.className="saturation-field";this.__field_knob=document.createElement("div");this.__field_knob.className="field-knob";this.__field_knob_border="2px solid ";this.__hue_knob=document.createElement("div");this.__hue_knob.className="hue-knob";this.__hue_field=document.createElement("div");this.__hue_field.className="hue-field";this.__input=document.createElement("input");
68 | this.__input.type="text";this.__input_textShadow="0 1px 1px ";a.bind(this.__input,"keydown",function(a){13===a.keyCode&&g.call(this)});a.bind(this.__input,"blur",g);a.bind(this.__selector,"mousedown",function(b){a.addClass(this,"drag").bind(window,"mouseup",function(b){a.removeClass(s.__selector,"drag")})});var v=document.createElement("div");f.extend(this.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"});f.extend(this.__field_knob.style,
69 | {position:"absolute",width:"12px",height:"12px",border:this.__field_knob_border+(0.5>this.__color.v?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1});f.extend(this.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1});f.extend(this.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"});f.extend(v.style,{width:"100%",height:"100%",
70 | background:"none"});c(v,"top","rgba(0,0,0,0)","#000");f.extend(this.__hue_field.style,{width:"15px",height:"100px",display:"inline-block",border:"1px solid #555",cursor:"ns-resize"});p(this.__hue_field);f.extend(this.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:this.__input_textShadow+"rgba(0,0,0,0.7)"});a.bind(this.__saturation_field,"mousedown",r);a.bind(this.__field_knob,"mousedown",r);a.bind(this.__hue_field,"mousedown",function(b){u(b);a.bind(window,
71 | "mousemove",u);a.bind(window,"mouseup",h)});this.__saturation_field.appendChild(v);this.__selector.appendChild(this.__field_knob);this.__selector.appendChild(this.__saturation_field);this.__selector.appendChild(this.__hue_field);this.__hue_field.appendChild(this.__hue_knob);this.domElement.appendChild(this.__input);this.domElement.appendChild(this.__selector);this.updateDisplay()};k.superclass=e;f.extend(k.prototype,e.prototype,{updateDisplay:function(){var a=d(this.getValue());if(!1!==a){var e=!1;
72 | f.each(b.COMPONENTS,function(b){if(!f.isUndefined(a[b])&&!f.isUndefined(this.__color.__state[b])&&a[b]!==this.__color.__state[b])return e=!0,{}},this);e&&f.extend(this.__color.__state,a)}f.extend(this.__temp.__state,this.__color.__state);this.__temp.a=1;var k=0.5>this.__color.v||0.5a&&(a+=1);return{h:360*a,s:e/c,v:c/255}},rgb_to_hex:function(a,b,d){a=this.hex_with_component(0,2,a);a=this.hex_with_component(a,1,b);return a=this.hex_with_component(a,0,d)},component_from_hex:function(a,b){return a>>8*b&255},hex_with_component:function(a,b,d){return d<<(e=8*b)|a&~(255<Tangram | © OSM contributors | Mapzen '
30 | });
31 |
32 | window.layer = layer;
33 | var scene = layer.scene;
34 | window.scene = scene;
35 | // setView expects format ([lat, long], zoom)
36 | map.setView(map_start_location.slice(0, 3), map_start_location[2]);
37 |
38 | var hash = new L.Hash(map);
39 |
40 |
41 | // GUI options for rendering modes/effects
42 | var style_controls = {
43 | 'Default' : function() {
44 | this.setstyle(Object.keys(scene.config.layers), undefined);
45 | },
46 | 'Elevator' : function() {
47 | this.setstyle(['buildings'], 'elevator');
48 | },
49 | 'Popup' : function() {
50 | this.setstyle(['buildings'], 'popup');
51 | },
52 | 'radius': 300,
53 | 'height': 3,
54 | 'Rainbow' : function() {
55 | this.setstyle(['buildings','landuse'], 'rainbow');
56 | },
57 | 'Dots' : function() {
58 | this.setstyle(['buildings','landuse'], 'dots');
59 | },
60 | 'Halftone' : function() {
61 | this.setstyle(Object.keys(scene.config.layers), 'halftone');
62 | },
63 | 'dot_frequency' : 100,
64 | 'dot_scale' : 1.5,
65 | 'Colorhalftone' : function() {
66 | this.setstyle(Object.keys(scene.config.layers), 'colorhalftone');
67 | },
68 | 'color_dot_frequency' : 50,
69 | 'color_dot_scale' : 1.5,
70 | 'Windows' : function() {
71 | this.setstyle(['buildings'], 'windows', 'isometric');
72 | },
73 | setstyle: function (layers, newstyle, camera) {
74 | // Restore initial state
75 | for (var i in scene.config.layers) {
76 | try {
77 | scene.config.layers[i].draw.polygons.style = undefined;
78 | }
79 | catch(e) {
80 | scene.config.layers[i].draw.lines.style = undefined;
81 | }
82 | };
83 | // Apply new style
84 | for (var j=0; j < layers.length; j++) {
85 | try {
86 | scene.config.layers[layers[j]].draw.polygons.style = newstyle;
87 | }
88 | catch(e) {
89 | scene.config.layers[layers[j]].draw.lines.style = newstyle;
90 | }
91 | }
92 | // Set camera
93 | if (camera) {
94 | scene.setActiveCamera(camera);
95 | } else {
96 | scene.setActiveCamera("perspective");
97 | }
98 | // Recompile/rebuild
99 | scene.rebuild();
100 | }
101 | };
102 |
103 | // Create dat GUI
104 | var gui = new dat.GUI({ autoPlace: true });
105 | function addGUI () {
106 | gui.domElement.parentNode.style.zIndex = 500;
107 | window.gui = gui;
108 | var folder = gui.addFolder("Click a style:");
109 | folder.open(); // this just points the arrow downward
110 | // Styles
111 | gui.add(style_controls, 'Default');
112 | gui.add(style_controls, 'Elevator');
113 | gui.add(style_controls, 'Popup');
114 | gui.add(style_controls, 'radius', 0, 500).name(" radius").onChange(function(value) {
115 | scene.styles.popup.shaders.uniforms.u_popup_radius = value;
116 | scene.requestRedraw();
117 | });
118 | gui.add(style_controls, 'height', 0, 5).name(" amount").onChange(function(value) {
119 | scene.styles.popup.shaders.uniforms.u_popup_height = value;
120 | scene.requestRedraw();
121 | });
122 | gui.add(style_controls, 'Rainbow');
123 |
124 | gui.add(style_controls, 'Halftone');
125 | gui.add(style_controls, 'dot_frequency', 1, 200).name(" frequency").onChange(function(value) {
126 | scene.styles.halftone.shaders.uniforms.dot_frequency = value;
127 | scene.requestRedraw();
128 | });
129 | gui.add(style_controls, 'dot_scale', 0, 10).name(" scale").onChange(function(value) {
130 | scene.styles.halftone.shaders.uniforms.dot_scale = value;
131 | scene.requestRedraw();
132 | });
133 |
134 | gui.add(style_controls, 'Colorhalftone');
135 | gui.add(style_controls, 'color_dot_frequency', 0, 100).name(" frequency").onChange(function(value) {
136 | scene.styles.colorhalftone.shaders.uniforms.dot_frequency = value;
137 | scene.requestRedraw();
138 | });
139 | gui.add(style_controls, 'color_dot_scale', 0, 3).name(" scale").onChange(function(value) {
140 | scene.styles.colorhalftone.shaders.uniforms.dot_scale = value;
141 | scene.requestRedraw();
142 | });
143 |
144 | gui.add(style_controls, 'Windows');
145 | }
146 |
147 |
148 |
149 | /***** Render loop *****/
150 | window.addEventListener('load', function () {
151 | // Scene initialized
152 | layer.on('init', function() {
153 | addGUI();
154 | });
155 | layer.addTo(map);
156 |
157 | });
158 |
159 | return map;
160 |
161 |
162 | }());
163 |
--------------------------------------------------------------------------------
/scene.yaml:
--------------------------------------------------------------------------------
1 | import:
2 | - styles/popup.yaml
3 | - styles/breathe.yaml
4 | - styles/dots.yaml
5 | - styles/halftone.yaml
6 | - styles/halftone.yaml
7 | - styles/windows.yaml
8 |
9 | sources:
10 | mapzen:
11 | type: MVT
12 | url: https://tile.nextzen.org/tilezen/vector/v1/512/all/{z}/{x}/{y}.mvt
13 | url_params:
14 | api_key: NaqqS33fTUmyQcvbuIUCKA
15 | tile_size: 512
16 | max_zoom: 16
17 |
18 | cameras:
19 | perspective:
20 | type: perspective
21 | # focal_length: 1
22 | focal_length: [[16, 2], [17, 2.5], [18, 3], [19, 4], [20, 6]] # pairs of [zoom, focal len]
23 | vanishing_point: [-250, -250] # relative to center of screen, in pixels
24 | isometric:
25 | type: isometric
26 | axis: [0,1]
27 |
28 | lights:
29 | key:
30 | type: directional
31 | direction: [-.2, 1, -1]
32 | diffuse: 1
33 | ambient: .6
34 |
35 | styles:
36 | rainbow:
37 | base: polygons
38 | animated: true
39 | shaders:
40 | blocks:
41 | global: |
42 | // hue-saturation-value to RGB color space converter, to allow hue cycling
43 | vec3 hsv2rgb(vec3 c) {
44 | vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
45 | vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
46 | return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
47 | }
48 | color: |
49 | // set an hsv value with hue varied by z-position (aka height) and by time
50 | // then convert to rgb and set pixel color
51 | vec3 c = vec3(worldPosition().z * .003 + u_time / 10., 1.0, 1.0);
52 | color.rgb = hsv2rgb(c);
53 |
54 | elevator:
55 | base: polygons
56 | animated: true
57 | shaders:
58 | blocks:
59 | position: |
60 | // Elevator buildings
61 | if (position.z > 0.01) {
62 | position.z *= (sin(position.z + u_time) + 1.0);
63 | }
64 |
65 | layers:
66 | earth:
67 | data:
68 | source: mapzen
69 | layer: earth
70 | draw:
71 | polygons:
72 | order: function() { return feature.sort_rank; }
73 | color: [0.175, 0.175, 0.175]
74 |
75 | landuse:
76 | data:
77 | source: mapzen
78 | layer: landuse
79 | draw:
80 | polygons:
81 | order: function() { return feature.sort_rank; }
82 | color: [0.5, 0.875, 0.5]
83 | pitch:
84 | filter:
85 | kind: ['pitch', 'garden', 'playground']
86 | draw:
87 | polygons:
88 | color: [0.3, 0.675, 0.3]
89 |
90 | water:
91 | data:
92 | source: mapzen
93 | layer: water
94 | draw:
95 | polygons:
96 | order: function() { return feature.sort_rank; }
97 | color: [0.5, 0.5, 0.875]
98 | outline:
99 | # don't draw outlines on ocean or riverbank features
100 | filter: {not: {kind: [ocean, river, riverbank]}}
101 | draw:
102 | lines:
103 | color: [0.6, 0.6, 0.975]
104 | order: function() { return feature.sort_rank; }
105 | width: function () {
106 | return (
107 | $zoom >= 16 && (2.5 * Math.log($zoom))
108 | );
109 | }
110 |
111 | roads:
112 | data:
113 | source: mapzen
114 | layer: roads
115 | draw:
116 | lines:
117 | order: function () { return feature.sort_rank; }
118 | outline:
119 | color: [0.7, 0.7, 0.7]
120 | width: 1
121 | highway:
122 | filter: { kind: highway }
123 | draw:
124 | lines:
125 | color: [1.0, 1.0, 1.0]
126 | width: 9
127 | tunnel:
128 | filter: { is_tunnel: yes }
129 | draw:
130 | lines:
131 | color: '#333'
132 | width: 6
133 | outline:
134 | order: 352 # magic number
135 | color: white
136 | width: 1
137 | major_road:
138 | filter: { kind: major_road }
139 | draw:
140 | lines:
141 | color: [0.5, 0.5, 0.5]
142 | width: 5
143 | minor_road:
144 | filter: { kind: minor_road }
145 | draw:
146 | lines:
147 | color: [0.65, 0.65, 0.65]
148 | width: 4
149 | path:
150 | filter:
151 | kind: path
152 | draw:
153 | lines:
154 | color: [0.8, 0.8, 0.8]
155 | width: 3
156 | rail:
157 | filter:
158 | kind: rail
159 | not: { is_tunnel: yes }
160 | draw:
161 | lines:
162 | color: [0.5, 0.0, 0.0]
163 | width: 3
164 | outline:
165 | order: 352 # magic number
166 | width: .5
167 |
168 | buildings:
169 | data:
170 | source: mapzen
171 | layer: buildings
172 | filter: { $geometry: polygon } # filter out address points in buildings layer
173 | draw:
174 | polygons:
175 | order: function() { return feature.sort_rank; }
176 | color: [.6, .6, .6]
177 | # at z15, only extrude buildings over 20 m; at z16 and higher, extrude all buildings
178 | extrude: function () { return (($zoom >= 15 && feature.height > 20) || $zoom >= 16) }
179 | # buildings with a name only
180 | namedBuildings:
181 | filter: { name: true }
182 | draw:
183 | polygons:
184 | color: [.6, .2, .2]
185 | # buildings with a name and a kind
186 | namedKindBuildings:
187 | filter: { kind: true }
188 | draw:
189 | polygons:
190 | color: [.6, .2, .6]
191 | # buildings with a kind only
192 | kindBuildings:
193 | filter: { name: false, kind: true }
194 | draw:
195 | polygons:
196 | color: [.2, .2, .6]
197 |
--------------------------------------------------------------------------------
/shaders/color_bleed.glsl:
--------------------------------------------------------------------------------
1 | color += lighting * vec3(gl_FragCoord.x / u_resolution.x, 0.0, gl_FragCoord.y / u_resolution.y);
2 | #if defined(EFFECT_COLOR_BLEED_ANIMATED)
3 | color.r += lighting.r * sin(u_time / 3.0);
4 | #endif
5 |
--------------------------------------------------------------------------------
/shaders/dots.glsl:
--------------------------------------------------------------------------------
1 | // 3d dots
2 |
3 | uniform float u_dot_grid_scale; // = .1;
4 | uniform float u_dot_scale; // = .07;
5 | uniform vec3 u_dot_background_color; // vec3(.5, .2, .2)
6 | uniform vec3 u_dot_color; // vec3(1.)
7 |
8 | vec3 dots (vec3 pos) {
9 | vec3 color = u_dot_background_color;
10 |
11 | const float dot_fuzz = .15; // antialias range as % of dot radius
12 |
13 | // Rotate to get better dot coverage across 3d geometry
14 | float dot_angle = radians(45.);
15 | // float dot_angle = u_time / 100000.;
16 | mat4 dot_rotate;
17 |
18 | dot_rotate = mat4(
19 | // rotate z
20 | vec4(cos(dot_angle), sin(dot_angle), 0., 0.),
21 | vec4(-sin(dot_angle), cos(dot_angle), 0., 0.),
22 | vec4(0., 0., 1., 0.),
23 | vec4(0., 0., 0., 1.)
24 | );
25 |
26 | dot_rotate *= mat4(
27 | // rotate x
28 | vec4(1., 0., 0., 0.),
29 | vec4(0., cos(dot_angle), sin(dot_angle), 0.),
30 | vec4(0., -sin(dot_angle), cos(dot_angle), 0.),
31 | vec4(0., 0., 0., 1.)
32 | );
33 |
34 | // dot_rotate *= mat4(
35 | // // rotate y
36 | // vec4(cos(dot_angle), 0., sin(dot_angle), 0.),
37 | // vec4(0., 1., 0., 0.),
38 | // vec4(-sin(dot_angle), 0., cos(dot_angle), 0.),
39 | // vec4(0., 0., 0., 1.)
40 | // );
41 |
42 | pos = (dot_rotate * vec4(pos, 1.)).xyz;
43 |
44 | // offset experiments
45 | // pos += vec3(u_time * 10., u_time * 10., 0.);
46 | // pos += vec3(0., 0., u_time * 10.);
47 | // pos += vec3(u_time * 10., u_time * 10., u_time * 10.);
48 |
49 | vec3 scaledXYZ = pos * u_dot_grid_scale;
50 | vec3 cell = floor(scaledXYZ);
51 | vec3 offset = scaledXYZ - cell;
52 | vec3 currentOffset;
53 |
54 | float priority = -1.0;
55 | for (float i = -1.0; i <= 0.0; i++) {
56 | for (float j = -1.0; j <= 0.0; j++) {
57 | for (float k = -1.0; k <= 0.0; k++) {
58 | vec3 currentCell = cell + vec3(i, j, k);
59 | vec3 cellOffset = offset - vec3(i, j, k);
60 | vec2 randomXY = currentCell.xy + currentCell.z * 0.003;
61 | currentOffset = cellOffset - (vec3(0.5, 0.5, 0.5));
62 |
63 | float radius = dot(currentOffset, currentOffset);
64 | if (radius < u_dot_scale) {
65 | color = u_dot_color;
66 | }
67 | else if (radius < u_dot_scale * (1. + dot_fuzz)) {
68 | color = mix(u_dot_background_color, u_dot_color, ((u_dot_scale * (1. + dot_fuzz)) - radius) / (u_dot_scale * dot_fuzz));
69 | }
70 | }
71 | }
72 | }
73 |
74 | return color;
75 | }
76 |
77 | #pragma glslify: export(dots)
78 |
--------------------------------------------------------------------------------
/shaders/elevator.glsl:
--------------------------------------------------------------------------------
1 | if (position.z > 0.) {
2 | position.z *= max((sin(position.z + u_time) + 1.0) / 2.0, 0.05); // elevator buildings
3 | }
4 |
--------------------------------------------------------------------------------
/shaders/glsl-noise-periodic-3d.glsl:
--------------------------------------------------------------------------------
1 | //
2 | // GLSL textureless classic 3D noise "cnoise",
3 | // with an RSL-style periodic variant "pnoise".
4 | // Author: Stefan Gustavson (stefan.gustavson@liu.se)
5 | // Version: 2011-10-11
6 | //
7 | // Many thanks to Ian McEwan of Ashima Arts for the
8 | // ideas for permutation and gradient selection.
9 | //
10 | // Copyright (c) 2011 Stefan Gustavson. All rights reserved.
11 | // Distributed under the MIT license. See LICENSE file.
12 | // https://github.com/ashima/webgl-noise
13 | //
14 |
15 | vec3 mod289(vec3 x)
16 | {
17 | return x - floor(x * (1.0 / 289.0)) * 289.0;
18 | }
19 |
20 | vec4 mod289(vec4 x)
21 | {
22 | return x - floor(x * (1.0 / 289.0)) * 289.0;
23 | }
24 |
25 | vec4 permute(vec4 x)
26 | {
27 | return mod289(((x*34.0)+1.0)*x);
28 | }
29 |
30 | vec4 taylorInvSqrt(vec4 r)
31 | {
32 | return 1.79284291400159 - 0.85373472095314 * r;
33 | }
34 |
35 | vec3 fade(vec3 t) {
36 | return t*t*t*(t*(t*6.0-15.0)+10.0);
37 | }
38 |
39 | // Classic Perlin noise, periodic variant
40 | float pnoise(vec3 P, vec3 rep)
41 | {
42 | vec3 Pi0 = mod(floor(P), rep); // Integer part, modulo period
43 | vec3 Pi1 = mod(Pi0 + vec3(1.0), rep); // Integer part + 1, mod period
44 | Pi0 = mod289(Pi0);
45 | Pi1 = mod289(Pi1);
46 | vec3 Pf0 = fract(P); // Fractional part for interpolation
47 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
48 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
49 | vec4 iy = vec4(Pi0.yy, Pi1.yy);
50 | vec4 iz0 = Pi0.zzzz;
51 | vec4 iz1 = Pi1.zzzz;
52 |
53 | vec4 ixy = permute(permute(ix) + iy);
54 | vec4 ixy0 = permute(ixy + iz0);
55 | vec4 ixy1 = permute(ixy + iz1);
56 |
57 | vec4 gx0 = ixy0 * (1.0 / 7.0);
58 | vec4 gy0 = fract(floor(gx0) * (1.0 / 7.0)) - 0.5;
59 | gx0 = fract(gx0);
60 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
61 | vec4 sz0 = step(gz0, vec4(0.0));
62 | gx0 -= sz0 * (step(0.0, gx0) - 0.5);
63 | gy0 -= sz0 * (step(0.0, gy0) - 0.5);
64 |
65 | vec4 gx1 = ixy1 * (1.0 / 7.0);
66 | vec4 gy1 = fract(floor(gx1) * (1.0 / 7.0)) - 0.5;
67 | gx1 = fract(gx1);
68 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
69 | vec4 sz1 = step(gz1, vec4(0.0));
70 | gx1 -= sz1 * (step(0.0, gx1) - 0.5);
71 | gy1 -= sz1 * (step(0.0, gy1) - 0.5);
72 |
73 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
74 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
75 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
76 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
77 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
78 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
79 | vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
80 | vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);
81 |
82 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
83 | g000 *= norm0.x;
84 | g010 *= norm0.y;
85 | g100 *= norm0.z;
86 | g110 *= norm0.w;
87 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
88 | g001 *= norm1.x;
89 | g011 *= norm1.y;
90 | g101 *= norm1.z;
91 | g111 *= norm1.w;
92 |
93 | float n000 = dot(g000, Pf0);
94 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
95 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
96 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
97 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
98 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
99 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
100 | float n111 = dot(g111, Pf1);
101 |
102 | vec3 fade_xyz = fade(Pf0);
103 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
104 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
105 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
106 | return 2.2 * n_xyz;
107 | }
108 |
109 | #pragma glslify: export(pnoise)
110 |
--------------------------------------------------------------------------------
/shaders/noise.glsl:
--------------------------------------------------------------------------------
1 | // Default wrap space for noise if not specified
2 | #if defined(WORLD_POSITION_WRAP)
3 | #define NOISE_WRAP WORLD_POSITION_WRAP
4 | #else
5 | #define NOISE_WRAP 100000.
6 | #endif
7 |
8 | #if defined(EFFECT_NOISE_ANIMATED)
9 | color *= (abs(pnoise((v_world_position.xyz + vec3(u_time * 5., u_time * 7.5, u_time * 10.)) / 10.0, vec3(NOISE_WRAP / 10.0))) / 4.0) + 0.75;
10 | #else
11 | color *= (abs(pnoise(v_world_position.xyz / 10.0, vec3(NOISE_WRAP / 10.0))) / 4.0) + 0.75;
12 | #endif
13 |
--------------------------------------------------------------------------------
/shaders/spotlight.glsl:
--------------------------------------------------------------------------------
1 | // Spotlight effect
2 | vec2 pixel_position = gl_FragCoord.xy / u_resolution.xy; // scale coords to [0.0, 1.0]
3 | pixel_position = pixel_position * 2.0 - 1.0; // scale coords to [-1.0, 1.0]
4 | pixel_position *= u_aspect; // correct aspect ratio
5 |
6 | color *= max(1.0 - distance(pixel_position, vec2(0.0, 0.0)), 0.2);
7 |
--------------------------------------------------------------------------------
/shaders/wood.glsl:
--------------------------------------------------------------------------------
1 | uniform vec3 u_wood_color1; // = .1;
2 | uniform vec3 u_wood_color2; // = .1;
3 | uniform float u_wood_eccentricity; // = .07;
4 | uniform float u_wood_twist; // = .07;
5 | uniform float u_wood_scale; // = .07;
6 | uniform float u_wood_spacing; // = .07;
7 |
8 | vec3 wood( vec3 pos ) {
9 |
10 | float r = length(pos.xy);
11 | float phi = atan(pos.y, pos.x);
12 |
13 | phi += u_wood_twist * pos.z;
14 | // phi += u_test * pos.z;
15 |
16 | r *= 1.0 + u_wood_eccentricity * cos(phi);
17 | // r *= 1.0 + u_test3 * cos(phi);
18 |
19 | float k = u_wood_spacing / u_wood_scale;
20 | // float k = TAU / u_test2;
21 |
22 | float density = 1. + sin(k * r);
23 |
24 | return vec3(mix(
25 | u_wood_color1,
26 | u_wood_color2,
27 | density)
28 | );
29 | }
30 |
31 | #pragma glslify: export(wood)
--------------------------------------------------------------------------------
/styles/breathe.yaml:
--------------------------------------------------------------------------------
1 | styles:
2 | breathe:
3 | base: polygons
4 | animated: true
5 | shaders:
6 | uniforms:
7 | u_breathe_scale: 10
8 | u_breathe_speed: 1
9 | blocks:
10 | position: |
11 | position.xy += a_normal.xy * u_breathe_scale * smoothstep(0.25, 1., abs(sin(u_time * u_breathe_speed)));
12 |
13 |
--------------------------------------------------------------------------------
/styles/dots.yaml:
--------------------------------------------------------------------------------
1 | styles:
2 | # 3d dots
3 | dots:
4 | base: polygons
5 | shaders:
6 | uniforms:
7 | u_dot_grid_scale: 0.02
8 | u_dot_scale: 0.07
9 | u_dot_background_color: [.5, .2, .2]
10 | u_dot_color: [1, 1, 1]
11 | blocks:
12 | global: |
13 |
14 | vec3 dots (vec3 pos) {
15 | vec3 color = u_dot_background_color;
16 |
17 | const float dot_fuzz = .15; // antialias range as % of dot radius
18 |
19 | // Rotate to get better dot coverage across 3d geometry
20 | float dot_angle = radians(45.);
21 | // float dot_angle = u_time / 100000.;
22 | mat4 dot_rotate;
23 |
24 | dot_rotate = mat4(
25 | // rotate z
26 | vec4(cos(dot_angle), sin(dot_angle), 0., 0.),
27 | vec4(-sin(dot_angle), cos(dot_angle), 0., 0.),
28 | vec4(0., 0., 1., 0.),
29 | vec4(0., 0., 0., 1.)
30 | );
31 |
32 | dot_rotate *= mat4(
33 | // rotate x
34 | vec4(1., 0., 0., 0.),
35 | vec4(0., cos(dot_angle), sin(dot_angle), 0.),
36 | vec4(0., -sin(dot_angle), cos(dot_angle), 0.),
37 | vec4(0., 0., 0., 1.)
38 | );
39 |
40 | // dot_rotate *= mat4(
41 | // // rotate y
42 | // vec4(cos(dot_angle), 0., sin(dot_angle), 0.),
43 | // vec4(0., 1., 0., 0.),
44 | // vec4(-sin(dot_angle), 0., cos(dot_angle), 0.),
45 | // vec4(0., 0., 0., 1.)
46 | // );
47 |
48 | pos = (dot_rotate * vec4(pos, 1.)).xyz;
49 |
50 | // offset experiments
51 | // pos += vec3(u_time * 10., u_time * 10., 0.);
52 | // pos += vec3(0., 0., u_time * 10.);
53 | // pos += vec3(u_time * 10., u_time * 10., u_time * 10.);
54 |
55 | vec3 scaledXYZ = pos * u_dot_grid_scale;
56 | vec3 cell = floor(scaledXYZ);
57 | vec3 offset = scaledXYZ - cell;
58 | vec3 currentOffset;
59 |
60 | float priority = -1.0;
61 | for (float i = -1.0; i <= 0.0; i++) {
62 | for (float j = -1.0; j <= 0.0; j++) {
63 | for (float k = -1.0; k <= 0.0; k++) {
64 | vec3 currentCell = cell + vec3(i, j, k);
65 | vec3 cellOffset = offset - vec3(i, j, k);
66 | vec2 randomXY = currentCell.xy + currentCell.z * 0.003;
67 | currentOffset = cellOffset - (vec3(0.5, 0.5, 0.5));
68 |
69 | float radius = dot(currentOffset, currentOffset);
70 | if (radius < u_dot_scale) {
71 | color = u_dot_color;
72 | }
73 | else if (radius < u_dot_scale * (1. + dot_fuzz)) {
74 | color = mix(u_dot_background_color, u_dot_color, ((u_dot_scale * (1. + dot_fuzz)) - radius) / (u_dot_scale * dot_fuzz));
75 | }
76 | }
77 | }
78 | }
79 |
80 | return color;
81 | }
82 |
83 | color: color.rgb *= dots(worldPosition().xyz);
84 | # fragment: color *= dots(worldPosition().xyz + vec3(0., 0., u_time * 25.)); // animated dots
85 | # fragment: vec3 n = abs(v_normal); if (n.z > n.x && n.z > n.y) { color *= dots(worldPosition().xyz); } // apply only to up-facing surfaces
86 |
--------------------------------------------------------------------------------
/styles/halftone.yaml:
--------------------------------------------------------------------------------
1 | styles:
2 | # Halftone shaders adapted from: http://webstaff.itn.liu.se/~stegu/webglshadertutorial/shadertutorial.html
3 | halftone:
4 | base: polygons
5 | shaders:
6 | uniforms:
7 | dot_frequency: 100.4748637184972
8 | dot_scale: 2
9 | blocks:
10 | global: |
11 | // Antialiasing
12 | float aastep(float threshold, const float freq, float value) {
13 | const float scale = 2.;
14 | const float y_rot = 0.;
15 | float afwidth = freq * (1.0/200.0) / scale / cos(y_rot);
16 | return smoothstep(threshold-afwidth, threshold+afwidth, value);
17 | }
18 |
19 | filter: |
20 | // Distance to nearest point in a grid of
21 | // (frequency x frequency) points over the unit square
22 | // Scale dot size for a subset of zoom
23 | const float max_scale_zoom = 19.;
24 | const float min_scale_zoom = 17.;
25 | const float scale_zoom_factor = .25;
26 | float zoom_frequency = dot_frequency / u_device_pixel_ratio;
27 | zoom_frequency *= 1. + ((max_scale_zoom - clamp(u_map_position.z, min_scale_zoom, max_scale_zoom)) * scale_zoom_factor);
28 |
29 | float meter_pixels = u_meters_per_pixel / u_device_pixel_ratio;
30 |
31 | // Sample based on screenspace
32 | const float pixel_scale = 695.; // arbitrary pixel_scale based on playing w/values
33 | vec2 st = gl_FragCoord.xy / pixel_scale;
34 |
35 | // But peg to map center so dots on ground plane stay in place as we move
36 | // (there's what looks like some floating point precision crawl, but it's not too bad)
37 | const float dot_wrap = 1000.;
38 | st += mod(u_map_position.xy / meter_pixels, dot_wrap) / pixel_scale;
39 |
40 | // Rotate dot & find nearest dot distance
41 | vec2 st2 = mat2(0.707, -0.707, 0.707, 0.707) * st;
42 | vec2 nearest = dot_scale * fract(zoom_frequency * st2) - 1.0;
43 | float dist = length(nearest);
44 |
45 | // Modulate the size of the dots
46 | float radius = clamp(sqrt(1.0 - color.g), 0.001, 1.); // use green channel, clamp to avoid giant dot
47 |
48 | // Color mix
49 | const vec3 white = vec3(1.0, 1.0, 1.0);
50 | const vec3 black = vec3(0.0, 0.0, 0.0);
51 | // color = mix(black + (color * float(halftone_colored)), white, aastep(radius, zoom_frequency, dist));
52 | color.rgb = mix(black, white, aastep(radius, zoom_frequency, dist));
53 |
54 | # Color version simulating CMYK printing process
55 | colorhalftone:
56 | base: polygons
57 | shaders:
58 | uniforms:
59 | dot_frequency: 100.
60 | dot_scale: 1.5
61 | true_color: false
62 |
63 | blocks:
64 | global: |
65 |
66 | // Antialiasing
67 | float aastep(float threshold, const float freq, float value) {
68 | const float scale = 2.;
69 | const float y_rot = 0.;
70 | float afwidth = freq * (1.0/200.0) / scale / cos(y_rot);
71 | return smoothstep(threshold-afwidth, threshold+afwidth, value);
72 | }
73 |
74 | filter: |
75 | // Distance to nearest point in a grid of
76 | // (frequency x frequency) points over the unit square
77 | // Scale dot size for a subset of zoom
78 | const float max_scale_zoom = 19.;
79 | const float min_scale_zoom = 17.;
80 | const float scale_zoom_factor = .25;
81 | float zoom_frequency = dot_frequency / u_device_pixel_ratio;
82 | zoom_frequency *= 1. + ((max_scale_zoom - clamp(u_map_position.z, min_scale_zoom, max_scale_zoom)) * scale_zoom_factor);
83 |
84 | float meter_pixels = u_meters_per_pixel / u_device_pixel_ratio;
85 |
86 | // Sample based on screenspace
87 | const float pixel_scale = 695.; // arbitrary pixel_scale based on playing w/values
88 | vec2 st = gl_FragCoord.xy / pixel_scale;
89 |
90 | // But peg to map center so dots on ground plane stay in place as we move
91 | // (there's what looks like some floating point precision crawl, but it's not too bad)
92 | const float dot_wrap = 1000.;
93 | st += mod(u_map_position.xy / meter_pixels, dot_wrap) / pixel_scale;
94 |
95 | vec3 white = vec3(0.97);
96 | vec3 black = vec3(0.1);
97 |
98 | // Perform a rough RGB-to-CMYK conversion
99 | vec4 cmyk;
100 | cmyk.xyz = 1.0 - color.rgb;
101 | cmyk.w = min(cmyk.x, min(cmyk.y, cmyk.z)); // Create K
102 | if (!true_color) {cmyk.xyz -= cmyk.w;} // Subtract K equivalent from CMY
103 |
104 | // Distance to nearest point in a grid of
105 | // (frequency x frequency) points over the unit square
106 | vec2 Kst = zoom_frequency*mat2(0.707, -0.707, 0.707, 0.707)*st;
107 | vec2 Kuv = dot_scale*fract(Kst)-(dot_scale/2.);
108 | float k = aastep(0.0, zoom_frequency, sqrt(cmyk.w)-length(Kuv));
109 | vec2 Cst = zoom_frequency*mat2(0.966, -0.259, 0.259, 0.966)*st;
110 | vec2 Cuv = dot_scale*fract(Cst)-(dot_scale/2.);
111 | float c = aastep(0.0, zoom_frequency, sqrt(cmyk.x)-length(Cuv));
112 | vec2 Mst = zoom_frequency*mat2(0.966, 0.259, -0.259, 0.966)*st;
113 | vec2 Muv = dot_scale*fract(Mst)-(dot_scale/2.);
114 | float m = aastep(0.0, zoom_frequency, sqrt(cmyk.y)-length(Muv));
115 | vec2 Yst = zoom_frequency*st; // 0 deg
116 | vec2 Yuv = dot_scale*fract(Yst)-(dot_scale/2.);
117 | float y = aastep(0.0, zoom_frequency, sqrt(cmyk.z)-length(Yuv));
118 |
119 | vec3 rgbscreen = 1.0 - 0.9*vec3(c,m,y); // most saturated color = .9
120 | rgbscreen = mix(rgbscreen, black, 0.85*k); // darkest black = .85
121 |
122 | // Modulate the size of the dots
123 | //float luminance = (0.299 * color.r + 0.587 * color.g + 0.114 * color.b); // HSP color model
124 | //float radius = clamp(sqrt(1.0 - luminance), 0.001, 1.); // use luminance, clamp to avoid giant dot
125 |
126 | color.rgb = rgbscreen;
127 |
128 |
--------------------------------------------------------------------------------
/styles/popup.yaml:
--------------------------------------------------------------------------------
1 | styles:
2 | popup:
3 | base: polygons
4 | shaders:
5 | uniforms:
6 | u_popup_radius: 330
7 | u_popup_height: 5
8 | blocks:
9 | global: |
10 | // Pop-up effect - 3d in center of viewport, fading to 2d at edges
11 | vec4 popup (vec4 position, const vec2 center, const float radius) {
12 | if (position.z > 0.) {
13 | float cd = distance(position.xy, center);
14 | float popup_fade_inner = radius * 2. / 3.; // 0.5
15 | float popup_fade_outer = radius; // 0.75
16 | if (cd > popup_fade_inner) {
17 | position.z *= 1.0 - smoothstep(popup_fade_inner, popup_fade_outer, cd);
18 | }
19 | }
20 | return position;
21 | }
22 |
23 | position: |
24 | position.z *= u_popup_height; // boost height for exaggerated visual effect
25 | position = popup(position, vec2(0., 0.), u_popup_radius * u_meters_per_pixel);
26 |
--------------------------------------------------------------------------------
/styles/windows.yaml:
--------------------------------------------------------------------------------
1 | styles:
2 | windows:
3 | base: polygons
4 | animated: true
5 |
6 | shaders:
7 | uniforms:
8 | u_frequency: 10.
9 | u_windowColor: [1., 1., .9]
10 | u_buildingColor: [.8, .8, .7]
11 | u_roofColor: [.5, .4, .5]
12 | blocks:
13 | global: |
14 |
15 | // 3d noise
16 | vec4 v_mod289(vec4 x){return x - floor(x * (1.0 / 289.0)) * 289.0;}
17 | vec4 perm(vec4 x){return v_mod289(((x * 34.0) + 1.0) * x);}
18 | float noise(vec3 p){
19 | vec3 a = floor(p);
20 | vec3 d = p - a;
21 | d = d * d * (3.0 - 2.0 * d);
22 |
23 | vec4 b = a.xxyy + vec4(0.0, 1.0, 0.0, 1.0);
24 | vec4 k1 = perm(b.xyxy);
25 | vec4 k2 = perm(k1.xyxy + b.zzww);
26 |
27 | vec4 c = k2 + a.zzzz;
28 | vec4 k3 = perm(c);
29 | vec4 k4 = perm(c + 1.0);
30 |
31 | vec4 o1 = fract(k3 * (1.0 / 41.0));
32 | vec4 o2 = fract(k4 * (1.0 / 41.0));
33 |
34 | vec4 o3 = o2 * d.z + o1 * (1.0 - d.z);
35 | vec2 o4 = o3.yw * d.x + o3.xz * (1.0 - d.x);
36 |
37 | return o4.y * d.y + o4.x * (1.0 - d.y);
38 | }
39 | color: |
40 | vec3 vPos = worldPosition().xyz / u_frequency;
41 | vec3 mask = mix(vec3(0.0), vec3(1.0), step(fract(mod(vPos, .9)), vec3(.4, .4, .6)));
42 |
43 | if (mask.x + mask.y + mask.z > .5) {
44 | color.rgb = u_buildingColor;
45 | color.rgb -= vec3(vPos.z * .1); // height factor
46 | } else {
47 | float noiseColor = 2. * noise(worldPosition().xyz * 0.1 + (floor(u_time * 5.) / 10.));
48 | color.rgb = u_windowColor * noiseColor;
49 | }
50 |
51 | if (v_normal.z > .6 || v_normal.z < -.6) {
52 | color.rgb = u_roofColor;
53 | color.rgb -= vec3(vPos.z * .01); // height factor
54 | }
55 |
56 |
--------------------------------------------------------------------------------