├── .eslintignore
├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── dist
├── favicon.ico
├── index.html
└── static
│ ├── css
│ └── app.90f1cf61.css
│ ├── img
│ ├── back.1c4c0640.jpg
│ ├── bottom.f3c15dcc.jpg
│ ├── front.71cb831c.jpg
│ ├── left.ce4064e2.jpg
│ ├── right.8ff40888.jpg
│ └── top.4b15e8e9.jpg
│ ├── js
│ ├── app.48b07d0a.js
│ └── chunk-vendors.35a2dcb6.js
│ └── media
│ └── audio.2040dda6.mp3
├── example.png
├── example1.png
├── package-lock.json
├── package.json
├── public
├── favicon.ico
└── index.html
├── src
├── App.vue
├── assets
│ ├── bg2.jpg
│ └── skybox
│ │ ├── back.jpg
│ │ ├── bottom.jpg
│ │ ├── front.jpg
│ │ ├── left.jpg
│ │ ├── right.jpg
│ │ └── top.jpg
├── components
│ ├── Triangle.js
│ ├── node.js
│ ├── randomRange.js
│ └── range.js
├── lib
│ ├── CopyShader.js
│ ├── EffectComposer.js
│ ├── LuminosityHighPassShader.js
│ ├── MaskPass.js
│ ├── OBJLoader.js
│ ├── OrbitControls.js
│ ├── Pass.js
│ ├── RenderPass.js
│ ├── ShaderPass.js
│ ├── UnrealBloomPass.js
│ ├── dat.gui.module.js
│ ├── stats.module.js
│ └── three.module.js
├── main.js
└── router
│ └── index.js
├── static
└── audio.mp3
└── vue.config.js
/.eslintignore:
--------------------------------------------------------------------------------
1 | /src/lib
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 |
4 |
5 | # local env files
6 | .env.local
7 | .env.*.local
8 |
9 | # Log files
10 | npm-debug.log*
11 | yarn-debug.log*
12 | yarn-error.log*
13 | pnpm-debug.log*
14 |
15 | # Editor directories and files
16 | .idea
17 | .vscode
18 | *.suo
19 | *.ntvs*
20 | *.njsproj
21 | *.sln
22 | *.sw?
23 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Hocoa
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, 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,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # AudioPlayer
2 |
3 | ### 初始加载github上的音乐文件可能较慢,推荐选择本地的音乐文件
4 |
5 | [Demo](https://hocoa.github.io/AudioPlayer/dist/index.html)
6 |
7 |
8 | 
9 | 
10 | ## Project setup
11 | ```
12 | npm install
13 | ```
14 |
15 | ### Compiles and hot-reloads for development
16 | ```
17 | npm run serve
18 | ```
19 |
20 | ### Compiles and minifies for production
21 | ```
22 | npm run build
23 | ```
24 |
25 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ["@vue/cli-plugin-babel/preset"]
3 | };
4 |
--------------------------------------------------------------------------------
/dist/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/favicon.ico
--------------------------------------------------------------------------------
/dist/index.html:
--------------------------------------------------------------------------------
1 |
audioplayer We're sorry but audioplayer doesn't work properly without JavaScript enabled. Please enable it to continue.
--------------------------------------------------------------------------------
/dist/static/css/app.90f1cf61.css:
--------------------------------------------------------------------------------
1 | body{margin:0;padding:0;overflow:hidden;height:100%}.file-select-btn{position:fixed;bottom:0;left:0;width:70px;height:26px;box-shadow:inset 0 0 10px #c500e5;line-height:26px;color:#c500e5;font-size:12px;text-align:center;cursor:pointer}.file-select-btn .file-input{display:none}
--------------------------------------------------------------------------------
/dist/static/img/back.1c4c0640.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/back.1c4c0640.jpg
--------------------------------------------------------------------------------
/dist/static/img/bottom.f3c15dcc.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/bottom.f3c15dcc.jpg
--------------------------------------------------------------------------------
/dist/static/img/front.71cb831c.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/front.71cb831c.jpg
--------------------------------------------------------------------------------
/dist/static/img/left.ce4064e2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/left.ce4064e2.jpg
--------------------------------------------------------------------------------
/dist/static/img/right.8ff40888.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/right.8ff40888.jpg
--------------------------------------------------------------------------------
/dist/static/img/top.4b15e8e9.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/dist/static/img/top.4b15e8e9.jpg
--------------------------------------------------------------------------------
/dist/static/js/app.48b07d0a.js:
--------------------------------------------------------------------------------
1 | (function(e){function t(t){for(var i,a,s=t[0],l=t[1],c=t[2],u=0,h=[];uc||8*(1-_.dot(n.object.quaternion))>c)&&(n.dispatchEvent(i),m.copy(n.object.position),_.copy(n.object.quaternion),p=!1,!0)}}(),this.dispose=function(){n.domElement.removeEventListener("contextmenu",se,!1),n.domElement.removeEventListener("mousedown",$,!1),n.domElement.removeEventListener("wheel",ne,!1),n.domElement.removeEventListener("touchstart",oe,!1),n.domElement.removeEventListener("touchend",ae,!1),n.domElement.removeEventListener("touchmove",re,!1),document.removeEventListener("mousemove",ee,!1),document.removeEventListener("mouseup",te,!1),n.domElement.removeEventListener("keydown",ie,!1)};var n=this,i={type:"change"},o={type:"start"},r={type:"end"},s={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_PAN:4,TOUCH_DOLLY_PAN:5,TOUCH_DOLLY_ROTATE:6},l=s.NONE,c=1e-6,d=new a["F"],u=new a["F"],h=1,f=new a["J"],p=!1,m=new a["I"],_=new a["I"],g=new a["I"],b=new a["I"],v=new a["I"],y=new a["I"],w=new a["I"],x=new a["I"],E=new a["I"];function C(){return 2*Math.PI/60/60*n.autoRotateSpeed}function S(){return Math.pow(.95,n.zoomSpeed)}function T(e){u.theta-=e}function A(e){u.phi-=e}var O=function(){var e=new a["J"];return function(t,n){e.setFromMatrixColumn(n,0),e.multiplyScalar(-t),f.add(e)}}(),k=function(){var e=new a["J"];return function(t,i){!0===n.screenSpacePanning?e.setFromMatrixColumn(i,1):(e.setFromMatrixColumn(i,0),e.crossVectors(n.object.up,e)),e.multiplyScalar(t),f.add(e)}}(),R=function(){var e=new a["J"];return function(t,i){var o=n.domElement;if(n.object.isPerspectiveCamera){var r=n.object.position;e.copy(r).sub(n.target);var a=e.length();a*=Math.tan(n.object.fov/2*Math.PI/180),O(2*t*a/o.clientHeight,n.object.matrix),k(2*i*a/o.clientHeight,n.object.matrix)}else n.object.isOrthographicCamera?(O(t*(n.object.right-n.object.left)/n.object.zoom/o.clientWidth,n.object.matrix),k(i*(n.object.top-n.object.bottom)/n.object.zoom/o.clientHeight,n.object.matrix)):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."),n.enablePan=!1)}}();function P(e){n.object.isPerspectiveCamera?h/=e:n.object.isOrthographicCamera?(n.object.zoom=Math.max(n.minZoom,Math.min(n.maxZoom,n.object.zoom*e)),n.object.updateProjectionMatrix(),p=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function M(e){n.object.isPerspectiveCamera?h*=e:n.object.isOrthographicCamera?(n.object.zoom=Math.max(n.minZoom,Math.min(n.maxZoom,n.object.zoom/e)),n.object.updateProjectionMatrix(),p=!0):(console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."),n.enableZoom=!1)}function L(e){m.set(e.clientX,e.clientY)}function j(e){w.set(e.clientX,e.clientY)}function B(e){b.set(e.clientX,e.clientY)}function D(e){_.set(e.clientX,e.clientY),g.subVectors(_,m).multiplyScalar(n.rotateSpeed);var t=n.domElement;T(2*Math.PI*g.x/t.clientHeight),A(2*Math.PI*g.y/t.clientHeight),m.copy(_),n.update()}function N(e){x.set(e.clientX,e.clientY),E.subVectors(x,w),E.y>0?P(S()):E.y<0&&M(S()),w.copy(x),n.update()}function H(e){v.set(e.clientX,e.clientY),y.subVectors(v,b).multiplyScalar(n.panSpeed),R(y.x,y.y),b.copy(v),n.update()}function F(){}function I(e){e.deltaY<0?M(S()):e.deltaY>0&&P(S()),n.update()}function z(e){var t=!1;switch(e.keyCode){case n.keys.UP:R(0,n.keyPanSpeed),t=!0;break;case n.keys.BOTTOM:R(0,-n.keyPanSpeed),t=!0;break;case n.keys.LEFT:R(n.keyPanSpeed,0),t=!0;break;case n.keys.RIGHT:R(-n.keyPanSpeed,0),t=!0;break}t&&(e.preventDefault(),n.update())}function U(e){if(1==e.touches.length)m.set(e.touches[0].pageX,e.touches[0].pageY);else{var t=.5*(e.touches[0].pageX+e.touches[1].pageX),n=.5*(e.touches[0].pageY+e.touches[1].pageY);m.set(t,n)}}function V(e){if(1==e.touches.length)b.set(e.touches[0].pageX,e.touches[0].pageY);else{var t=.5*(e.touches[0].pageX+e.touches[1].pageX),n=.5*(e.touches[0].pageY+e.touches[1].pageY);b.set(t,n)}}function G(e){var t=e.touches[0].pageX-e.touches[1].pageX,n=e.touches[0].pageY-e.touches[1].pageY,i=Math.sqrt(t*t+n*n);w.set(0,i)}function Y(e){n.enableZoom&&G(e),n.enablePan&&V(e)}function X(e){n.enableZoom&&G(e),n.enableRotate&&U(e)}function Q(e){if(1==e.touches.length)_.set(e.touches[0].pageX,e.touches[0].pageY);else{var t=.5*(e.touches[0].pageX+e.touches[1].pageX),i=.5*(e.touches[0].pageY+e.touches[1].pageY);_.set(t,i)}g.subVectors(_,m).multiplyScalar(n.rotateSpeed);var o=n.domElement;T(2*Math.PI*g.x/o.clientHeight),A(2*Math.PI*g.y/o.clientHeight),m.copy(_)}function J(e){if(1==e.touches.length)v.set(e.touches[0].pageX,e.touches[0].pageY);else{var t=.5*(e.touches[0].pageX+e.touches[1].pageX),i=.5*(e.touches[0].pageY+e.touches[1].pageY);v.set(t,i)}y.subVectors(v,b).multiplyScalar(n.panSpeed),R(y.x,y.y),b.copy(v)}function W(e){var t=e.touches[0].pageX-e.touches[1].pageX,i=e.touches[0].pageY-e.touches[1].pageY,o=Math.sqrt(t*t+i*i);x.set(0,o),E.set(0,Math.pow(x.y/w.y,n.zoomSpeed)),P(E.y),w.copy(x)}function K(e){n.enableZoom&&W(e),n.enablePan&&J(e)}function Z(e){n.enableZoom&&W(e),n.enableRotate&&Q(e)}function q(){}function $(e){if(!1!==n.enabled){var t;switch(e.preventDefault(),n.domElement.focus?n.domElement.focus():window.focus(),e.button){case 0:t=n.mouseButtons.LEFT;break;case 1:t=n.mouseButtons.MIDDLE;break;case 2:t=n.mouseButtons.RIGHT;break;default:t=-1}switch(t){case a["t"].DOLLY:if(!1===n.enableZoom)return;j(e),l=s.DOLLY;break;case a["t"].ROTATE:if(e.ctrlKey||e.metaKey||e.shiftKey){if(!1===n.enablePan)return;B(e),l=s.PAN}else{if(!1===n.enableRotate)return;L(e),l=s.ROTATE}break;case a["t"].PAN:if(e.ctrlKey||e.metaKey||e.shiftKey){if(!1===n.enableRotate)return;L(e),l=s.ROTATE}else{if(!1===n.enablePan)return;B(e),l=s.PAN}break;default:l=s.NONE}l!==s.NONE&&(document.addEventListener("mousemove",ee,!1),document.addEventListener("mouseup",te,!1),n.dispatchEvent(o))}}function ee(e){if(!1!==n.enabled)switch(e.preventDefault(),l){case s.ROTATE:if(!1===n.enableRotate)return;D(e);break;case s.DOLLY:if(!1===n.enableZoom)return;N(e);break;case s.PAN:if(!1===n.enablePan)return;H(e);break}}function te(e){!1!==n.enabled&&(F(e),document.removeEventListener("mousemove",ee,!1),document.removeEventListener("mouseup",te,!1),n.dispatchEvent(r),l=s.NONE)}function ne(e){!1===n.enabled||!1===n.enableZoom||l!==s.NONE&&l!==s.ROTATE||(e.preventDefault(),e.stopPropagation(),n.dispatchEvent(o),I(e),n.dispatchEvent(r))}function ie(e){!1!==n.enabled&&!1!==n.enableKeys&&!1!==n.enablePan&&z(e)}function oe(e){if(!1!==n.enabled){switch(e.preventDefault(),e.touches.length){case 1:switch(n.touches.ONE){case a["G"].ROTATE:if(!1===n.enableRotate)return;U(e),l=s.TOUCH_ROTATE;break;case a["G"].PAN:if(!1===n.enablePan)return;V(e),l=s.TOUCH_PAN;break;default:l=s.NONE}break;case 2:switch(n.touches.TWO){case a["G"].DOLLY_PAN:if(!1===n.enableZoom&&!1===n.enablePan)return;Y(e),l=s.TOUCH_DOLLY_PAN;break;case a["G"].DOLLY_ROTATE:if(!1===n.enableZoom&&!1===n.enableRotate)return;X(e),l=s.TOUCH_DOLLY_ROTATE;break;default:l=s.NONE}break;default:l=s.NONE}l!==s.NONE&&n.dispatchEvent(o)}}function re(e){if(!1!==n.enabled)switch(e.preventDefault(),e.stopPropagation(),l){case s.TOUCH_ROTATE:if(!1===n.enableRotate)return;Q(e),n.update();break;case s.TOUCH_PAN:if(!1===n.enablePan)return;J(e),n.update();break;case s.TOUCH_DOLLY_PAN:if(!1===n.enableZoom&&!1===n.enablePan)return;K(e),n.update();break;case s.TOUCH_DOLLY_ROTATE:if(!1===n.enableZoom&&!1===n.enableRotate)return;Z(e),n.update();break;default:l=s.NONE}}function ae(e){!1!==n.enabled&&(q(e),n.dispatchEvent(r),l=s.NONE)}function se(e){!1!==n.enabled&&e.preventDefault()}n.domElement.addEventListener("contextmenu",se,!1),n.domElement.addEventListener("mousedown",$,!1),n.domElement.addEventListener("wheel",ne,!1),n.domElement.addEventListener("touchstart",oe,!1),n.domElement.addEventListener("touchend",ae,!1),n.domElement.addEventListener("touchmove",re,!1),n.domElement.addEventListener("keydown",ie,!1),-1===n.domElement.tabIndex&&(n.domElement.tabIndex=0),this.update()});s.prototype=Object.create(a["m"].prototype),s.prototype.constructor=s;var l=function(e,t){s.call(this,e,t),this.mouseButtons.LEFT=a["t"].PAN,this.mouseButtons.RIGHT=a["t"].ROTATE,this.touches.ONE=a["G"].PAN,this.touches.TWO=a["G"].DOLLY_ROTATE};l.prototype=Object.create(a["m"].prototype),l.prototype.constructor=l;n("a4d3"),n("e01a"),n("d28b"),n("c975"),n("a15b"),n("fb6a"),n("a434"),n("b0c0"),n("b680"),n("e439"),n("3410"),n("b64b"),n("4d63"),n("ac1f"),n("25f0"),n("3ca3"),n("466d"),n("5319"),n("1276");var c=n("53ca");function d(e){if(e&&"undefined"!==typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}function u(e,t){var n=e.__state.conversionName.toString(),i=Math.round(e.r),o=Math.round(e.g),r=Math.round(e.b),a=e.a,s=Math.round(e.h),l=e.s.toFixed(1),c=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){var d=e.hex.toString(16);while(d.length<6)d="0"+d;return"#"+d}return"CSS_RGB"===n?"rgb("+i+","+o+","+r+")":"CSS_RGBA"===n?"rgba("+i+","+o+","+r+","+a+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+i+","+o+","+r+"]":"RGBA_ARRAY"===n?"["+i+","+o+","+r+","+a+"]":"RGB_OBJ"===n?"{r:"+i+",g:"+o+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+i+",g:"+o+",b:"+r+",a:"+a+"}":"HSV_OBJ"===n?"{h:"+s+",s:"+l+",v:"+c+"}":"HSVA_OBJ"===n?"{h:"+s+",s:"+l+",v:"+c+",a:"+a+"}":"unknown format"}var h=Array.prototype.forEach,f=Array.prototype.slice,p={BREAK:{},extend:function(e){return this.each(f.call(arguments,1),(function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(t[n])||(e[n]=t[n])}.bind(this))}),this),e},defaults:function(e){return this.each(f.call(arguments,1),(function(t){var n=this.isObject(t)?Object.keys(t):[];n.forEach(function(n){this.isUndefined(e[n])&&(e[n]=t[n])}.bind(this))}),this),e},compose:function(){var e=f.call(arguments);return function(){for(var t=f.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(h&&e.forEach&&e.forEach===h)e.forEach(t,n);else if(e.length===e.length+0){var i=void 0,o=void 0;for(i=0,o=e.length;i1?p.toArray(arguments):arguments[0];return p.each(m,(function(t){if(t.litmus(e))return p.each(t.conversions,(function(t,n){if(_=t.read(e),!1===g&&!1!==_)return g=_,_.conversionName=n,_.conversion=t,p.BREAK})),p.BREAK})),g},v=void 0,y={hsv_to_rgb:function(e,t,n){var i=Math.floor(e/60)%6,o=e/60-Math.floor(e/60),r=n*(1-t),a=n*(1-o*t),s=n*(1-(1-o)*t),l=[[n,s,r],[a,n,r],[r,n,s],[r,a,n],[s,r,n],[n,r,a]][i];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var i=Math.min(e,t,n),o=Math.max(e,t,n),r=o-i,a=void 0,s=void 0;return 0===o?{h:NaN,s:0,v:0}:(s=r/o,a=e===o?(t-n)/r:t===o?2+(n-e)/r:4+(e-t)/r,a/=6,a<0&&(a+=1),{h:360*a,s:s,v:o/255})},rgb_to_hex:function(e,t,n){var i=this.hex_with_component(0,2,e);return i=this.hex_with_component(i,1,t),i=this.hex_with_component(i,0,n),i},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(v=8*t)|e&~(255<-1?t.length-t.indexOf(".")-1:0}var I=function(e){function t(e,n,i){x(this,t);var o=T(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i||{};return o.__min=r.min,o.__max=r.max,o.__step=r.step,p.isUndefined(o.__step)?0===o.initialValue?o.__impliedStep=1:o.__impliedStep=Math.pow(10,Math.floor(Math.log(Math.abs(o.initialValue))/Math.LN10))/10:o.__impliedStep=o.__step,o.__precision=F(o.__impliedStep),o}return S(t,e),E(t,[{key:"setValue",value:function(e){var n=e;return void 0!==this.__min&&nthis.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!==0&&(n=Math.round(n/this.__step)*this.__step),C(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=F(e),this}}]),t}(R);function z(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}var U=function(e){function t(e,n,i){x(this,t);var o=T(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,i));o.__truncationSuspended=!1;var r=o,a=void 0;function s(){var e=parseFloat(r.__input.value);p.isNaN(e)||r.setValue(e)}function l(){r.__onFinishChange&&r.__onFinishChange.call(r,r.getValue())}function c(){l()}function d(e){var t=a-e.clientY;r.setValue(r.getValue()+t*r.__impliedStep),a=e.clientY}function u(){B.unbind(window,"mousemove",d),B.unbind(window,"mouseup",u),l()}function h(e){B.bind(window,"mousemove",d),B.bind(window,"mouseup",u),a=e.clientY}return o.__input=document.createElement("input"),o.__input.setAttribute("type","text"),B.bind(o.__input,"change",s),B.bind(o.__input,"blur",c),B.bind(o.__input,"mousedown",h),B.bind(o.__input,"keydown",(function(e){13===e.keyCode&&(r.__truncationSuspended=!0,this.blur(),r.__truncationSuspended=!1,l())})),o.updateDisplay(),o.domElement.appendChild(o.__input),o}return S(t,e),E(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():z(this.getValue(),this.__precision),C(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(I);function V(e,t,n,i,o){return i+(e-t)/(n-t)*(o-i)}var G=function(e){function t(e,n,i,o,r){x(this,t);var a=T(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:i,max:o,step:r})),s=a;function l(e){document.activeElement.blur(),B.bind(window,"mousemove",c),B.bind(window,"mouseup",d),c(e)}function c(e){e.preventDefault();var t=s.__background.getBoundingClientRect();return s.setValue(V(e.clientX,t.left,t.right,s.__min,s.__max)),!1}function d(){B.unbind(window,"mousemove",c),B.unbind(window,"mouseup",d),s.__onFinishChange&&s.__onFinishChange.call(s,s.getValue())}function u(e){1===e.touches.length&&(B.bind(window,"touchmove",h),B.bind(window,"touchend",f),h(e))}function h(e){var t=e.touches[0].clientX,n=s.__background.getBoundingClientRect();s.setValue(V(t,n.left,n.right,s.__min,s.__max))}function f(){B.unbind(window,"touchmove",h),B.unbind(window,"touchend",f),s.__onFinishChange&&s.__onFinishChange.call(s,s.getValue())}return a.__background=document.createElement("div"),a.__foreground=document.createElement("div"),B.bind(a.__background,"mousedown",l),B.bind(a.__background,"touchstart",u),B.addClass(a.__background,"slider"),B.addClass(a.__foreground,"slider-fg"),a.updateDisplay(),a.__background.appendChild(a.__foreground),a.domElement.appendChild(a.__background),a}return S(t,e),E(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",C(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(I),Y=function(e){function t(e,n,i){x(this,t);var o=T(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=o;return o.__button=document.createElement("div"),o.__button.innerHTML=void 0===i?"Fire":i,B.bind(o.__button,"click",(function(e){return e.preventDefault(),r.fire(),!1})),B.addClass(o.__button,"button"),o.domElement.appendChild(o.__button),o}return S(t,e),E(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(R),X=function(e){function t(e,n){x(this,t);var i=T(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));i.__color=new A(i.getValue()),i.__temp=new A(0);var o=i;i.domElement=document.createElement("div"),B.makeSelectable(i.domElement,!1),i.__selector=document.createElement("div"),i.__selector.className="selector",i.__saturation_field=document.createElement("div"),i.__saturation_field.className="saturation-field",i.__field_knob=document.createElement("div"),i.__field_knob.className="field-knob",i.__field_knob_border="2px solid ",i.__hue_knob=document.createElement("div"),i.__hue_knob.className="hue-knob",i.__hue_field=document.createElement("div"),i.__hue_field.className="hue-field",i.__input=document.createElement("input"),i.__input.type="text",i.__input_textShadow="0 1px 1px ",B.bind(i.__input,"keydown",(function(e){13===e.keyCode&&d.call(this)})),B.bind(i.__input,"blur",d),B.bind(i.__selector,"mousedown",(function(){B.addClass(this,"drag").bind(window,"mouseup",(function(){B.removeClass(o.__selector,"drag")}))})),B.bind(i.__selector,"touchstart",(function(){B.addClass(this,"drag").bind(window,"touchend",(function(){B.removeClass(o.__selector,"drag")}))}));var r=document.createElement("div");function a(e){h(e),B.bind(window,"mousemove",h),B.bind(window,"touchmove",h),B.bind(window,"mouseup",l),B.bind(window,"touchend",l)}function s(e){f(e),B.bind(window,"mousemove",f),B.bind(window,"touchmove",f),B.bind(window,"mouseup",c),B.bind(window,"touchend",c)}function l(){B.unbind(window,"mousemove",h),B.unbind(window,"touchmove",h),B.unbind(window,"mouseup",l),B.unbind(window,"touchend",l),u()}function c(){B.unbind(window,"mousemove",f),B.unbind(window,"touchmove",f),B.unbind(window,"mouseup",c),B.unbind(window,"touchend",c),u()}function d(){var e=b(this.value);!1!==e?(o.__color.__state=e,o.setValue(o.__color.toOriginal())):this.value=o.__color.toString()}function u(){o.__onFinishChange&&o.__onFinishChange.call(o,o.__color.toOriginal())}function h(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=o.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,i=n.clientX,r=n.clientY,a=(i-t.left)/(t.right-t.left),s=1-(r-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),a>1?a=1:a<0&&(a=0),o.__color.v=s,o.__color.s=a,o.setValue(o.__color.toOriginal()),!1}function f(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=o.__hue_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,i=n.clientY,r=1-(i-t.top)/(t.bottom-t.top);return r>1?r=1:r<0&&(r=0),o.__color.h=360*r,o.setValue(o.__color.toOriginal()),!1}return p.extend(i.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),p.extend(i.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:i.__field_knob_border+(i.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),p.extend(i.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),p.extend(i.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),p.extend(r.style,{width:"100%",height:"100%",background:"none"}),J(r,"top","rgba(0,0,0,0)","#000"),p.extend(i.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),W(i.__hue_field),p.extend(i.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:i.__input_textShadow+"rgba(0,0,0,0.7)"}),B.bind(i.__saturation_field,"mousedown",a),B.bind(i.__saturation_field,"touchstart",a),B.bind(i.__field_knob,"mousedown",a),B.bind(i.__field_knob,"touchstart",a),B.bind(i.__hue_field,"mousedown",s),B.bind(i.__hue_field,"touchstart",s),i.__saturation_field.appendChild(r),i.__selector.appendChild(i.__field_knob),i.__selector.appendChild(i.__saturation_field),i.__selector.appendChild(i.__hue_field),i.__hue_field.appendChild(i.__hue_knob),i.domElement.appendChild(i.__input),i.domElement.appendChild(i.__selector),i.updateDisplay(),i}return S(t,e),E(t,[{key:"updateDisplay",value:function(){var e=b(this.getValue());if(!1!==e){var t=!1;p.each(A.COMPONENTS,(function(n){if(!p.isUndefined(e[n])&&!p.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}}),this),t&&p.extend(this.__color.__state,e)}p.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,i=255-n;p.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,J(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),p.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+i+","+i+","+i+",.7)"})}}]),t}(R),Q=["-moz-","-o-","-webkit-","-ms-",""];function J(e,t,n,i){e.style.background="",p.each(Q,(function(o){e.style.cssText+="background: "+o+"linear-gradient("+t+", "+n+" 0%, "+i+" 100%); "}))}function W(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}var K={load:function(e,t){var n=t||document,i=n.createElement("link");i.type="text/css",i.rel="stylesheet",i.href=e,n.getElementsByTagName("head")[0].appendChild(i)},inject:function(e,t){var n=t||document,i=document.createElement("style");i.type="text/css",i.innerHTML=e;var o=n.getElementsByTagName("head")[0];try{o.appendChild(i)}catch(r){}}},Z='\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
',q=function(e,t){var n=e[t];return p.isArray(arguments[2])||p.isObject(arguments[2])?new N(e,t,arguments[2]):p.isNumber(n)?p.isNumber(arguments[2])&&p.isNumber(arguments[3])?p.isNumber(arguments[4])?new G(e,t,arguments[2],arguments[3],arguments[4]):new G(e,t,arguments[2],arguments[3]):p.isNumber(arguments[4])?new U(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new U(e,t,{min:arguments[2],max:arguments[3]}):p.isString(n)?new H(e,t):p.isFunction(n)?new Y(e,t,""):p.isBoolean(n)?new D(e,t):null};function $(e){setTimeout(e,1e3/60)}var ee=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||$,te=function(){function e(){x(this,e),this.backgroundElement=document.createElement("div"),p.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),B.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),p.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;B.bind(this.backgroundElement,"click",(function(){t.hide()}))}return E(e,[{key:"show",value:function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),p.defer((function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"}))}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",B.unbind(e.domElement,"webkitTransitionEnd",t),B.unbind(e.domElement,"transitionend",t),B.unbind(e.domElement,"oTransitionEnd",t)};B.bind(this.domElement,"webkitTransitionEnd",t),B.bind(this.domElement,"transitionend",t),B.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-B.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-B.getHeight(this.domElement)/2+"px"}}]),e}(),ne=d(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");K.inject(ne);var ie="dg",oe=72,re=20,ae="Default",se=function(){try{return!!window.localStorage}catch(e){return!1}}(),le=void 0,ce=!0,de=void 0,ue=!1,he=[],fe=function e(t){var n=this,i=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),B.addClass(this.domElement,ie),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],i=p.defaults(i,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),i=p.defaults(i,{resizable:i.autoPlace,hideable:i.autoPlace}),p.isUndefined(i.load)?i.load={preset:ae}:i.preset&&(i.load.preset=i.preset),p.isUndefined(i.parent)&&i.hideable&&he.push(this),i.resizable=p.isUndefined(i.parent)&&i.resizable,i.autoPlace&&p.isUndefined(i.scrollable)&&(i.scrollable=!0);var o=se&&"true"===localStorage.getItem(ye(this,"isLocal")),r=void 0,a=void 0;if(Object.defineProperties(this,{parent:{get:function(){return i.parent}},scrollable:{get:function(){return i.scrollable}},autoPlace:{get:function(){return i.autoPlace}},closeOnTop:{get:function(){return i.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:i.load.preset},set:function(e){n.parent?n.getRoot().preset=e:i.load.preset=e,Ae(this),n.revert()}},width:{get:function(){return i.width},set:function(e){i.width=e,Se(n,e)}},name:{get:function(){return i.name},set:function(e){i.name=e,a&&(a.innerHTML=i.name)}},closed:{get:function(){return i.closed},set:function(t){i.closed=t,i.closed?B.addClass(n.__ul,e.CLASS_CLOSED):B.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return i.load}},useLocalStorage:{get:function(){return o},set:function(e){se&&(o=e,e?B.bind(window,"unload",r):B.unbind(window,"unload",r),localStorage.setItem(ye(n,"isLocal"),e))}}}),p.isUndefined(i.parent)){if(this.closed=i.closed||!1,B.addClass(this.domElement,e.CLASS_MAIN),B.makeSelectable(this.domElement,!1),se&&o){n.useLocalStorage=!0;var s=localStorage.getItem(ye(this,"gui"));s&&(i.load=JSON.parse(s))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,B.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),i.closeOnTop?(B.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(B.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),B.bind(this.__closeButton,"click",(function(){n.closed=!n.closed}))}else{void 0===i.closed&&(i.closed=!0);var l=document.createTextNode(i.name);B.addClass(l,"controller-name"),a=pe(n,l);var c=function(e){return e.preventDefault(),n.closed=!n.closed,!1};B.addClass(this.__ul,e.CLASS_CLOSED),B.addClass(a,"title"),B.bind(a,"click",c),i.closed||(this.closed=!1)}function d(){var e=n.getRoot();e.width+=1,p.defer((function(){e.width-=1}))}i.autoPlace&&(p.isUndefined(i.parent)&&(ce&&(de=document.createElement("div"),B.addClass(de,ie),B.addClass(de,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(de),ce=!1),de.appendChild(this.domElement),B.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||Se(n,i.width)),this.__resizeHandler=function(){n.onResizeDebounced()},B.bind(window,"resize",this.__resizeHandler),B.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),B.bind(this.__ul,"transitionend",this.__resizeHandler),B.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),i.resizable&&Ce(this),r=function(){se&&"true"===localStorage.getItem(ye(n,"isLocal"))&&localStorage.setItem(ye(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,i.parent||d()};function pe(e,t,n){var i=document.createElement("li");return t&&i.appendChild(t),n?e.__ul.insertBefore(i,n):e.__ul.appendChild(i),e.onResize(),i}function me(e){B.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&B.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function _e(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function ge(e,t,n){if(n.__li=t,n.__gui=e,p.extend(n,{options:function(t){if(arguments.length>1){var i=n.__li.nextElementSibling;return n.remove(),ve(e,n.object,n.property,{before:i,factoryArgs:[p.toArray(arguments)]})}if(p.isArray(t)||p.isObject(t)){var o=n.__li.nextElementSibling;return n.remove(),ve(e,n.object,n.property,{before:o,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof G){var i=new U(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});p.each(["updateDisplay","onChange","onFinishChange","step","min","max"],(function(e){var t=n[e],o=i[e];n[e]=i[e]=function(){var e=Array.prototype.slice.call(arguments);return o.apply(i,e),t.apply(n,e)}})),B.addClass(t,"has-slider"),n.domElement.insertBefore(i.domElement,n.domElement.firstElementChild)}else if(n instanceof U){var o=function(t){if(p.isNumber(n.__min)&&p.isNumber(n.__max)){var i=n.__li.firstElementChild.firstElementChild.innerHTML,o=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=ve(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(i),o&&r.listen(),r}return t};n.min=p.compose(o,n.min),n.max=p.compose(o,n.max)}else n instanceof D?(B.bind(t,"click",(function(){B.fakeEvent(n.__checkbox,"click")})),B.bind(n.__checkbox,"click",(function(e){e.stopPropagation()}))):n instanceof Y?(B.bind(t,"click",(function(){B.fakeEvent(n.__button,"click")})),B.bind(t,"mouseover",(function(){B.addClass(n.__button,"hover")})),B.bind(t,"mouseout",(function(){B.removeClass(n.__button,"hover")}))):n instanceof X&&(B.addClass(t,"color"),n.updateDisplay=p.compose((function(e){return t.style.borderLeftColor=n.__color.toString(),e}),n.updateDisplay),n.updateDisplay());n.setValue=p.compose((function(t){return e.getRoot().__preset_select&&n.isModified()&&_e(e.getRoot(),!0),t}),n.setValue)}function be(e,t){var n=e.getRoot(),i=n.__rememberedObjects.indexOf(t.object);if(-1!==i){var o=n.__rememberedObjectIndecesToControllers[i];if(void 0===o&&(o={},n.__rememberedObjectIndecesToControllers[i]=o),o[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,a=void 0;if(r[e.preset])a=r[e.preset];else{if(!r[ae])return;a=r[ae]}if(a[i]&&void 0!==a[i][t.property]){var s=a[i][t.property];t.initialValue=s,t.setValue(s)}}}}function ve(e,t,n,i){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var o=void 0;if(i.color)o=new X(t,n);else{var r=[t,n].concat(i.factoryArgs);o=q.apply(e,r)}i.before instanceof R&&(i.before=i.before.__li),be(e,o),B.addClass(o.domElement,"c");var a=document.createElement("span");B.addClass(a,"property-name"),a.innerHTML=o.property;var s=document.createElement("div");s.appendChild(a),s.appendChild(o.domElement);var l=pe(e,s,i.before);return B.addClass(l,fe.CLASS_CONTROLLER_ROW),o instanceof X?B.addClass(l,"color"):B.addClass(l,w(o.getValue())),ge(e,l,o),e.__controllers.push(o),o}function ye(e,t){return document.location.href+"."+t}function we(e,t,n){var i=document.createElement("option");i.innerHTML=t,i.value=t,e.__preset_select.appendChild(i),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function xe(e,t){t.style.display=e.useLocalStorage?"block":"none"}function Ee(e){var t=e.__save_row=document.createElement("li");B.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),B.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",B.addClass(n,"button gears");var i=document.createElement("span");i.innerHTML="Save",B.addClass(i,"button"),B.addClass(i,"save");var o=document.createElement("span");o.innerHTML="New",B.addClass(o,"button"),B.addClass(o,"save-as");var r=document.createElement("span");r.innerHTML="Revert",B.addClass(r,"button"),B.addClass(r,"revert");var a=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?p.each(e.load.remembered,(function(t,n){we(e,n,n===e.preset)})):we(e,ae,!1),B.bind(a,"change",(function(){for(var t=0;t0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=Te(this)),e.folders={},p.each(this.__folders,(function(t,n){e.folders[n]=t.getSaveObject()})),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=Te(this),_e(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[ae]=Te(this,!0)),this.load.remembered[e]=Te(this),this.preset=e,we(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){p.each(this.__controllers,(function(t){this.getRoot().load.remembered?be(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())}),this),p.each(this.__folders,(function(e){e.revert(e)})),e||_e(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&Oe(this.__listening)},updateDisplay:function(){p.each(this.__controllers,(function(e){e.updateDisplay()})),p.each(this.__folders,(function(e){e.updateDisplay()}))}});var ke=fe,Re={uniforms:{tDiffuse:{value:null},opacity:{value:1}},vertexShader:["varying vec2 vUv;","void main() {","\tvUv = uv;","\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );","}"].join("\n"),fragmentShader:["uniform float opacity;","uniform sampler2D tDiffuse;","varying vec2 vUv;","void main() {","\tvec4 texel = texture2D( tDiffuse, vUv );","\tgl_FragColor = opacity * texel;","}"].join("\n")};function Pe(){this.enabled=!0,this.needsSwap=!0,this.clear=!1,this.renderToScreen=!1}Object.assign(Pe.prototype,{setSize:function(){},render:function(){console.error("THREE.Pass: .render() must be implemented in derived pass.")}}),Pe.FullScreenQuad=function(){var e=new a["x"](-1,1,1,-1,0,1),t=new a["z"](2,2),n=function(e){this._mesh=new a["u"](t,e)};return Object.defineProperty(n.prototype,"material",{get:function(){return this._mesh.material},set:function(e){this._mesh.material=e}}),Object.assign(n.prototype,{render:function(t){t.render(this._mesh,e)}}),n}();var Me=function(e,t){Pe.call(this),this.textureID=void 0!==t?t:"tDiffuse",e instanceof a["E"]?(this.uniforms=e.uniforms,this.material=e):e&&(this.uniforms=a["H"].clone(e.uniforms),this.material=new a["E"]({defines:Object.assign({},e.defines),uniforms:this.uniforms,vertexShader:e.vertexShader,fragmentShader:e.fragmentShader})),this.fsQuad=new Pe.FullScreenQuad(this.material)};Me.prototype=Object.assign(Object.create(Pe.prototype),{constructor:Me,render:function(e,t,n){this.uniforms[this.textureID]&&(this.uniforms[this.textureID].value=n.texture),this.fsQuad.material=this.material,this.renderToScreen?(e.setRenderTarget(null),this.fsQuad.render(e)):(e.setRenderTarget(t),this.clear&&e.clear(e.autoClearColor,e.autoClearDepth,e.autoClearStencil),this.fsQuad.render(e))}});var Le=function(e,t){Pe.call(this),this.scene=e,this.camera=t,this.clear=!0,this.needsSwap=!1,this.inverse=!1};Le.prototype=Object.assign(Object.create(Pe.prototype),{constructor:Le,render:function(e,t,n){var i,o,r=e.getContext(),a=e.state;a.buffers.color.setMask(!1),a.buffers.depth.setMask(!1),a.buffers.color.setLocked(!0),a.buffers.depth.setLocked(!0),this.inverse?(i=0,o=1):(i=1,o=0),a.buffers.stencil.setTest(!0),a.buffers.stencil.setOp(r.REPLACE,r.REPLACE,r.REPLACE),a.buffers.stencil.setFunc(r.ALWAYS,i,4294967295),a.buffers.stencil.setClear(o),a.buffers.stencil.setLocked(!0),e.setRenderTarget(n),this.clear&&e.clear(),e.render(this.scene,this.camera),e.setRenderTarget(t),this.clear&&e.clear(),e.render(this.scene,this.camera),a.buffers.color.setLocked(!1),a.buffers.depth.setLocked(!1),a.buffers.stencil.setLocked(!1),a.buffers.stencil.setFunc(r.EQUAL,1,4294967295),a.buffers.stencil.setOp(r.KEEP,r.KEEP,r.KEEP),a.buffers.stencil.setLocked(!0)}});var je=function(){Pe.call(this),this.needsSwap=!1};je.prototype=Object.create(Pe.prototype),Object.assign(je.prototype,{render:function(e){e.state.buffers.stencil.setLocked(!1),e.state.buffers.stencil.setTest(!1)}});var Be=function(e,t){if(this.renderer=e,void 0===t){var n={minFilter:a["s"],magFilter:a["s"],format:a["C"],stencilBuffer:!1},i=e.getSize(new a["I"]);this._pixelRatio=e.getPixelRatio(),this._width=i.width,this._height=i.height,t=new a["K"](this._width*this._pixelRatio,this._height*this._pixelRatio,n),t.texture.name="EffectComposer.rt1"}else this._pixelRatio=1,this._width=t.width,this._height=t.height;this.renderTarget1=t,this.renderTarget2=t.clone(),this.renderTarget2.texture.name="EffectComposer.rt2",this.writeBuffer=this.renderTarget1,this.readBuffer=this.renderTarget2,this.renderToScreen=!0,this.passes=[],void 0===Re&&console.error("THREE.EffectComposer relies on CopyShader"),void 0===Me&&console.error("THREE.EffectComposer relies on ShaderPass"),this.copyPass=new Me(Re),this.clock=new a["j"]};Object.assign(Be.prototype,{swapBuffers:function(){var e=this.readBuffer;this.readBuffer=this.writeBuffer,this.writeBuffer=e},addPass:function(e){this.passes.push(e),e.setSize(this._width*this._pixelRatio,this._height*this._pixelRatio)},insertPass:function(e,t){this.passes.splice(t,0,e)},isLastEnabledPass:function(e){for(var t=e+1;t\t\t\t\tvarying vec2 vUv;\n\t\t\t\tuniform sampler2D colorTexture;\n\t\t\t\tuniform vec2 texSize;\t\t\t\tuniform vec2 direction;\t\t\t\t\t\t\t\tfloat gaussianPdf(in float x, in float sigma) {\t\t\t\t\treturn 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\t\t\t\t}\t\t\t\tvoid main() {\n\t\t\t\t\tvec2 invSize = 1.0 / texSize;\t\t\t\t\tfloat fSigma = float(SIGMA);\t\t\t\t\tfloat weightSum = gaussianPdf(0.0, fSigma);\t\t\t\t\tvec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\t\t\t\t\tfor( int i = 1; i < KERNEL_RADIUS; i ++ ) {\t\t\t\t\t\tfloat x = float(i);\t\t\t\t\t\tfloat w = gaussianPdf(x, fSigma);\t\t\t\t\t\tvec2 uvOffset = direction * invSize * x;\t\t\t\t\t\tvec3 sample1 = texture2D( colorTexture, vUv + uvOffset).rgb;\t\t\t\t\t\tvec3 sample2 = texture2D( colorTexture, vUv - uvOffset).rgb;\t\t\t\t\t\tdiffuseSum += (sample1 + sample2) * w;\t\t\t\t\t\tweightSum += 2.0 * w;\t\t\t\t\t}\t\t\t\t\tgl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\t\t\t\t}"})},getCompositeMaterial:function(e){return new a["E"]({defines:{NUM_MIPS:e},uniforms:{blurTexture1:{value:null},blurTexture2:{value:null},blurTexture3:{value:null},blurTexture4:{value:null},blurTexture5:{value:null},dirtTexture:{value:null},bloomStrength:{value:1},bloomFactors:{value:null},bloomTintColors:{value:null},bloomRadius:{value:0}},vertexShader:"varying vec2 vUv;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\t\t}",fragmentShader:"varying vec2 vUv;\t\t\t\tuniform sampler2D blurTexture1;\t\t\t\tuniform sampler2D blurTexture2;\t\t\t\tuniform sampler2D blurTexture3;\t\t\t\tuniform sampler2D blurTexture4;\t\t\t\tuniform sampler2D blurTexture5;\t\t\t\tuniform sampler2D dirtTexture;\t\t\t\tuniform float bloomStrength;\t\t\t\tuniform float bloomRadius;\t\t\t\tuniform float bloomFactors[NUM_MIPS];\t\t\t\tuniform vec3 bloomTintColors[NUM_MIPS];\t\t\t\t\t\t\t\tfloat lerpBloomFactor(const in float factor) { \t\t\t\t\tfloat mirrorFactor = 1.2 - factor;\t\t\t\t\treturn mix(factor, mirrorFactor, bloomRadius);\t\t\t\t}\t\t\t\t\t\t\t\tvoid main() {\t\t\t\t\tgl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + \t\t\t\t\t\t\t\t\t\t\t\t\t lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + \t\t\t\t\t\t\t\t\t\t\t\t\t lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + \t\t\t\t\t\t\t\t\t\t\t\t\t lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + \t\t\t\t\t\t\t\t\t\t\t\t\t lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\t\t\t\t}"})}}),Fe.BlurDirectionX=new a["I"](1,0),Fe.BlurDirectionY=new a["I"](0,1);var Ie=function e(){var t=0,n=document.createElement("div");function i(e){return n.appendChild(e.dom),e}function o(e){for(var i=0;i=a+1e3&&(l.update(1e3*s/(e-a),100),a=e,s=0,d)){var t=performance.memory;d.update(t.usedJSHeapSize/1048576,t.jsHeapSizeLimit/1048576)}return e},update:function(){r=this.end()},domElement:n,setMode:o}};Ie.Panel=function(e,t,n){var i=1/0,o=0,r=Math.round,a=r(window.devicePixelRatio||1),s=80*a,l=48*a,c=3*a,d=2*a,u=3*a,h=15*a,f=74*a,p=30*a,m=document.createElement("canvas");m.width=s,m.height=l,m.style.cssText="width:80px;height:48px";var _=m.getContext("2d");return _.font="bold "+9*a+"px Helvetica,Arial,sans-serif",_.textBaseline="top",_.fillStyle=n,_.fillRect(0,0,s,l),_.fillStyle=t,_.fillText(e,c,d),_.fillRect(u,h,f,p),_.fillStyle=n,_.globalAlpha=.9,_.fillRect(u,h,f,p),{dom:m,update:function(l,g){i=Math.min(i,l),o=Math.max(o,l),_.fillStyle=n,_.globalAlpha=1,_.fillRect(0,0,s,h),_.fillStyle=t,_.fillText(r(l)+" "+e+" ("+r(i)+"-"+r(o)+")",c,d),_.drawImage(m,u+a,h,f-a,p,u,h,f-a,p),_.fillRect(u+f-a,h,a,p),_.fillStyle=n,_.globalAlpha=.9,_.fillRect(u+f-a,h,a,r((1-l/g)*p))}}};var ze=Ie;function Ue(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1,i=arguments.length>3&&void 0!==arguments[3]&&arguments[3],o=-1,r=Math.max(Math.ceil((t-e)/n),0),a=Array(r);while(r--)a[i?r:++o]=e,e+=n;return a}var Ve=n("d4ec"),Ge=n("bee2"),Ye=n("ade3"),Xe=function(){function e(t,n,i){Object(Ve["a"])(this,e),Object(Ye["a"])(this,"lastStrength",0),Object(Ye["a"])(this,"theStrength",0),Object(Ye["a"])(this,"targetRange",0),Object(Ye["a"])(this,"_range",0),this.baseRange=t,this.angle=n,this.center=i}return Object(Ge["a"])(e,[{key:"positionA",value:function(){var e=this._range+this.baseRange,t=Math.cos(this.angle*Math.PI/180)*e,n=Math.sin(this.angle*Math.PI/180)*e;return new a["I"](this.center.x+t,this.center.y+n)}},{key:"positionB",value:function(){var e=-1*this._range+this.baseRange,t=Math.cos(this.angle*Math.PI/180)*e,n=Math.sin(this.angle*Math.PI/180)*e;return new a["I"](this.center.x+t,this.center.y+n)}},{key:"strength",value:function(e){this.lastStrength=this.theStrength,this.theStrength=e,this.targetRange=Math.max(this.theStrength-this.lastStrength,0),this.targetRange>this._range&&(this._range=this.targetRange)}},{key:"transition",value:function(e){this._range=Math.max(this._range-e*this._range*5,0)}}]),e}();function Qe(e,t){return e+(Math.random()-.5)*t}var Je,We,Ke,Ze,qe,$e,et,tt,nt,it,ot,rt,at,st,lt=function(){function e(t,n,i,o,r,s,l,c,d){var u,h;Object(Ve["a"])(this,e),Object(Ye["a"])(this,"rotate",360*Math.random()),Object(Ye["a"])(this,"id",Math.random()),Object(Ye["a"])(this,"distance",void 0),Object(Ye["a"])(this,"rotateSpeed",void 0),Object(Ye["a"])(this,"angle",void 0),Object(Ye["a"])(this,"speed",void 0),Object(Ye["a"])(this,"center",void 0),Object(Ye["a"])(this,"mesh",void 0),Object(Ye["a"])(this,"showDistance",void 0),Object(Ye["a"])(this,"panelMaterial",void 0),Object(Ye["a"])(this,"lineMaterial",void 0),Object(Ye["a"])(this,"panelOpacity",.1),Object(Ye["a"])(this,"line",void 0),Object(Ye["a"])(this,"group",void 0),Object(Ye["a"])(this,"onDelete",void 0),this.rotateSpeed=r,this.angle=i,this.speed=o,this.center=n,this.onDelete=d,this.distance=c.startShow,this.showDistance=c,this.panelMaterial=(new a["v"]).copy(s),this.panelMaterial.transparent=!0,this.lineMaterial=(new a["r"]).copy(l),this.lineMaterial.transparent=!0;var f=new a["o"],p=new a["o"],m=[new a["J"](Qe(t,t/2),Qe(t,t/2),Qe(t,t/2)),new a["J"](-1*Qe(t,t/2),Qe(t,t/2),Qe(t,t/2)-1),new a["J"](-1*Qe(t,t/2),-1*Qe(t,t/2),Qe(t,t/2)-1)];(u=f.vertices).push.apply(u,m),(h=p.vertices).push.apply(h,[].concat(m,[m[0]])),f.faces.push(new a["n"](0,1,2)),f.computeFaceNormals(),f.computeVertexNormals(),this.line=new a["q"](p,this.lineMaterial),this.mesh=new a["u"](f,this.panelMaterial),this.group=new a["p"],this.translateOnAxis(this.translate(this.distance),1),this.group.add(this.line),this.group.add(this.mesh),this.rotateZ(this.rotate),this.updatePosition(0)}return Object(Ge["a"])(e,[{key:"rotateZ",value:function(e){this.mesh.geometry.rotateZ(e),this.line.geometry.rotateZ(e)}},{key:"translate",value:function(e){var t=Math.cos(this.angle*Math.PI/180)*e,n=Math.sin(this.angle*Math.PI/180)*e,i=Math.cos(this.angle*Math.PI/360)*e*this.angle/180;return new a["J"](t,n,i)}},{key:"translateOnAxis",value:function(e,t){this.group.translateOnAxis(e,t)}},{key:"updatePosition",value:function(e){this.translateOnAxis(this.translate(e*this.speed),1),this.distance+=e*this.speed,this.rotateZ(this.rotateSpeed*e),this.panelMaterial.opacity=this.opacity(this.distance,this.showDistance)*this.panelOpacity,this.lineMaterial.opacity=this.opacity(this.distance,this.showDistance),this.distance>this.showDistance.endHide&&this.delete()}},{key:"delete",value:function(){this.onDelete(this),this.mesh.geometry.dispose(),this.line.geometry.dispose()}},{key:"opacity",value:function(e,t){return this.distancet.startHide?(t.endHide-this.distance)/(t.endHide-t.startHide):1}},{key:"transition",value:function(e){this.updatePosition(e)}}]),e}(),ct={R:20,G:90,B:225,TrianglesBgColor:240116,TrianglesLineColor:240116,lineColor:65535,rotate:!1},dt=[],ut=[],ht={name:"App",data:function(){return{positionZ:80,N:256,clock:new a["j"],scale:1}},methods:{init:function(){Je=new a["L"]({antialias:!0,alpha:!0}),Je.setClearAlpha(0),Je.setSize(window.innerWidth,window.innerHeight),document.body.appendChild(Je.domElement),We=new a["D"],We.background=(new a["l"]).load([n("9ac2"),n("1dc2"),n("6f4f"),n("f254"),n("a7f3"),n("dbe6")]),Ke=new a["y"](75,window.innerWidth/window.innerHeight,1,1e4),Ke.position.z=this.positionZ,window.addEventListener("resize",this.onWindowResize,!1),this.audioLines(20,this.N),this.audioBars(25,this.N/2),st=new a["p"],setInterval(this.addTriangle.bind(this),500),We.add(st);var e=new a["e"];et=new a["c"](e);var t=n("5e76");this.audioLoad(t),this.initLight(),this.initControls(),this.initGui(),this.initBloomPass(),this.initStats(),this.animate()},renderGeometries:function(e){var t=[];return e=e.concat(e[0]),e.forEach((function(e){t.push(e.x,e.y,0)})),new a["h"](new Float32Array(t),3)},updateCircle:function(){if(rt){nt.scale.set(this.scale,this.scale,this.scale);var e=it.geometry,t=e.getAttribute("position"),n=ot.geometry,i=n.getAttribute("position"),o=rt.map((function(e){return[e.positionA(),e.positionB()]}));o.forEach((function(e,n){t.set([e[0].x,e[0].y],3*n),i.set([e[1].x,e[1].y],3*n);var o=dt[n].geometry,r=o.getAttribute("position");r.set([e[0].x,e[0].y,0,e[1].x,e[1].y,0],0),r.needsUpdate=!0})),t.set([t.array[0],t.array[1]],3*o.length),i.set([i.array[0],i.array[1]],3*o.length),t.needsUpdate=!0,i.needsUpdate=!0}},audioLines:function(e,t){var n=this;rt=Ue(0,t).map((function(n){return new Xe(e,(n/t*360+45)%360,new a["I"](0,0))}));var i=new a["r"]({color:ct.lineColor});dt=Ue(0,t).map((function(e){return new a["q"]((new a["i"]).setAttribute("position",n.renderGeometries([rt[e].positionA(),rt[e].positionB()])),i)})),it=new a["q"]((new a["i"]).setAttribute("position",this.renderGeometries(rt.map((function(e){return e.positionA()})))),i),ot=new a["q"]((new a["i"]).setAttribute("position",this.renderGeometries(rt.map((function(e){return e.positionB()})))),i),nt=new a["p"],nt.add(it),nt.add(ot),dt.forEach((function(e){return nt.add(e)})),We.add(nt)},addTriangle:function(){var e=new a["v"]({color:ct.TrianglesBgColor}),t=new a["r"]({color:ct.TrianglesLineColor}),n=this.makeTriangle(e,t,(function(e){ut=ut.filter((function(t){return t!==e})),st.remove(e.group)}));st.add(n.group),ut.push(n)},makeTriangle:function(e,t,n){var i=new lt(2,new a["J"](0,0,0),360*Math.random(),Qe(5,1),Qe(.1,.05),e,t,{startShow:15,endShow:30,startHide:60,endHide:70},n);return i},audioBars:function(e,t){at=new a["p"];for(var n=e,i=t,o=0;o 1%",
47 | "last 2 versions",
48 | "not dead"
49 | ]
50 | }
51 |
--------------------------------------------------------------------------------
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/public/favicon.ico
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= htmlWebpackPlugin.options.title %>
9 |
10 |
11 |
12 | We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
10 |
457 |
458 |
485 |
--------------------------------------------------------------------------------
/src/assets/bg2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/bg2.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/back.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/back.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/bottom.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/bottom.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/front.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/front.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/left.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/left.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/right.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/right.jpg
--------------------------------------------------------------------------------
/src/assets/skybox/top.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/src/assets/skybox/top.jpg
--------------------------------------------------------------------------------
/src/components/Triangle.js:
--------------------------------------------------------------------------------
1 | // import * as THREE from '../lib/three.module.js';
2 | import * as THREE from "three";
3 | import { randomRange } from "./randomRange.js";
4 |
5 | export class ILineDistanceOption {
6 | startShow;
7 | endShow;
8 | startHide;
9 | endHide;
10 | }
11 |
12 | export class Triangle {
13 | rotate = Math.random() * 360;
14 | id = Math.random();
15 | distance;
16 | rotateSpeed;
17 | angle;
18 | // public pointA: THREE.Vector3;
19 | // public pointB: THREE.Vector3;
20 | // public pointC: THREE.Vector3;
21 | speed;
22 | center;
23 | mesh;
24 | showDistance;
25 | panelMaterial;
26 | lineMaterial;
27 | panelOpacity = 0.1;
28 | line;
29 | group;
30 | onDelete;
31 | constructor(
32 | size,
33 | center,
34 | angle,
35 | speed,
36 | rotateSpeed,
37 | material,
38 | lineMaterial,
39 | lineDistance,
40 | cb
41 | ) {
42 | this.rotateSpeed = rotateSpeed;
43 | this.angle = angle;
44 | this.speed = speed;
45 | this.center = center;
46 | this.onDelete = cb;
47 | this.distance = lineDistance.startShow;
48 | this.showDistance = lineDistance;
49 | this.panelMaterial = new THREE.MeshBasicMaterial().copy(material);
50 | this.panelMaterial.transparent = true;
51 | this.lineMaterial = new THREE.LineBasicMaterial().copy(lineMaterial);
52 | this.lineMaterial.transparent = true;
53 | const panelGeometry = new THREE.Geometry();
54 | const lineGeometry = new THREE.Geometry();
55 |
56 | const vertices = [
57 | new THREE.Vector3(
58 | randomRange(size, size / 2),
59 | randomRange(size, size / 2),
60 | randomRange(size, size / 2)
61 | ),
62 | new THREE.Vector3(
63 | randomRange(size, size / 2) * -1,
64 | randomRange(size, size / 2),
65 | randomRange(size, size / 2) - 1
66 | ),
67 | new THREE.Vector3(
68 | randomRange(size, size / 2) * -1,
69 | randomRange(size, size / 2) * -1,
70 | randomRange(size, size / 2) - 1
71 | )
72 | ];
73 |
74 | panelGeometry.vertices.push(...vertices);
75 |
76 | lineGeometry.vertices.push(...[...vertices, vertices[0]]);
77 |
78 | panelGeometry.faces.push(new THREE.Face3(0, 1, 2));
79 | panelGeometry.computeFaceNormals();
80 | panelGeometry.computeVertexNormals();
81 |
82 | this.line = new THREE.Line(lineGeometry, this.lineMaterial);
83 | this.mesh = new THREE.Mesh(panelGeometry, this.panelMaterial);
84 | this.group = new THREE.Group();
85 | this.translateOnAxis(this.translate(this.distance), 1);
86 | this.group.add(this.line);
87 | this.group.add(this.mesh);
88 | this.rotateZ(this.rotate);
89 | this.updatePosition(0);
90 | }
91 |
92 | rotateZ(angle) {
93 | this.mesh.geometry.rotateZ(angle);
94 | this.line.geometry.rotateZ(angle);
95 | }
96 |
97 | translate(distance) {
98 | const x = Math.cos((this.angle * Math.PI) / 180) * distance;
99 | const y = Math.sin((this.angle * Math.PI) / 180) * distance;
100 | const z =
101 | (Math.cos((this.angle * Math.PI) / 360) * distance * this.angle) / 180;
102 | return new THREE.Vector3(x, y, z);
103 | }
104 |
105 | translateOnAxis(axis, distance) {
106 | this.group.translateOnAxis(axis, distance);
107 | }
108 |
109 | updatePosition(delay) {
110 | this.translateOnAxis(this.translate(delay * this.speed), 1);
111 | this.distance += delay * this.speed;
112 | this.rotateZ(this.rotateSpeed * delay);
113 | this.panelMaterial.opacity =
114 | this.opacity(this.distance, this.showDistance) * this.panelOpacity;
115 | this.lineMaterial.opacity = this.opacity(this.distance, this.showDistance);
116 | if (this.distance > this.showDistance.endHide) {
117 | this.delete();
118 | }
119 | }
120 |
121 | delete() {
122 | this.onDelete(this);
123 | this.mesh.geometry.dispose();
124 | this.line.geometry.dispose();
125 | }
126 |
127 | opacity(distance, showDistance) {
128 | if (this.distance < showDistance.endShow) {
129 | return (
130 | (this.distance - showDistance.startShow) /
131 | (showDistance.endShow - showDistance.startShow)
132 | );
133 | } else if (this.distance > showDistance.startHide) {
134 | return (
135 | (showDistance.endHide - this.distance) /
136 | (showDistance.endHide - showDistance.startHide)
137 | );
138 | } else {
139 | return 1;
140 | }
141 | }
142 |
143 | transition(delay) {
144 | this.updatePosition(delay);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/src/components/node.js:
--------------------------------------------------------------------------------
1 | // import {Vector2} from '../lib/three.module.js';
2 | import {Vector2} from 'three';
3 |
4 | export class node {
5 | lastStrength = 0;
6 | theStrength = 0;
7 | targetRange = 0;
8 | _range = 0;
9 | constructor(baseRange, angle, center) {
10 | this.baseRange = baseRange;
11 | this.angle = angle;
12 | this.center = center;
13 | }
14 | positionA() {
15 |
16 | const range = this._range + this.baseRange;
17 | const x = Math.cos(this.angle * Math.PI / 180) * range;
18 | const y = Math.sin(this.angle * Math.PI / 180) * range;
19 | return new Vector2(this.center.x + x, this.center.y + y);
20 | }
21 | positionB() {
22 | const range = this._range * -1 + this.baseRange;
23 | const x = Math.cos(this.angle * Math.PI / 180) * range;
24 | const y = Math.sin(this.angle * Math.PI / 180) * range;
25 | return new Vector2(this.center.x + x, this.center.y + y);
26 | }
27 | strength(newStrength) {
28 | this.lastStrength = this.theStrength;
29 | this.theStrength = newStrength;
30 | this.targetRange = Math.max(this.theStrength - this.lastStrength, 0);
31 | if (this.targetRange > this._range) this._range = this.targetRange;
32 | }
33 | transition(delay) {
34 | this._range = Math.max(this._range - delay * this._range * 5, 0);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/components/randomRange.js:
--------------------------------------------------------------------------------
1 | export function randomRange(a, range) {
2 | return a + (Math.random() - 0.5) * range;
3 | }
4 |
--------------------------------------------------------------------------------
/src/components/range.js:
--------------------------------------------------------------------------------
1 | export function range(start, end, step = 1, fromRight = false) {
2 | let index = -1,
3 | length = Math.max(Math.ceil((end - start) / step), 0),
4 | result = Array(length);
5 |
6 | while (length--) {
7 | result[fromRight ? length : ++index] = start;
8 | start += step;
9 | }
10 | return result;
11 | }
12 |
--------------------------------------------------------------------------------
/src/lib/CopyShader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Full-screen textured quad shader
3 | */
4 |
5 | var CopyShader = {
6 |
7 | uniforms: {
8 |
9 | 'tDiffuse': { value: null },
10 | 'opacity': { value: 1.0 }
11 |
12 | },
13 |
14 | vertexShader: [
15 |
16 | 'varying vec2 vUv;',
17 |
18 | 'void main() {',
19 |
20 | ' vUv = uv;',
21 | ' gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );',
22 |
23 | '}'
24 |
25 | ].join( '\n' ),
26 |
27 | fragmentShader: [
28 |
29 | 'uniform float opacity;',
30 |
31 | 'uniform sampler2D tDiffuse;',
32 |
33 | 'varying vec2 vUv;',
34 |
35 | 'void main() {',
36 |
37 | ' vec4 texel = texture2D( tDiffuse, vUv );',
38 | ' gl_FragColor = opacity * texel;',
39 |
40 | '}'
41 |
42 | ].join( '\n' )
43 |
44 | };
45 |
46 | export { CopyShader };
47 |
--------------------------------------------------------------------------------
/src/lib/EffectComposer.js:
--------------------------------------------------------------------------------
1 | import {
2 | BufferGeometry,
3 | Clock,
4 | Float32BufferAttribute,
5 | LinearFilter,
6 | Mesh,
7 | OrthographicCamera,
8 | RGBAFormat,
9 | Vector2,
10 | WebGLRenderTarget
11 | } from "./three.module.js";
12 | import { CopyShader } from './CopyShader.js';
13 | import { ShaderPass } from './ShaderPass.js';
14 | import { MaskPass } from './MaskPass.js';
15 | import { ClearMaskPass } from './MaskPass.js';
16 |
17 | var EffectComposer = function ( renderer, renderTarget ) {
18 |
19 | this.renderer = renderer;
20 |
21 | if ( renderTarget === undefined ) {
22 |
23 | var parameters = {
24 | minFilter: LinearFilter,
25 | magFilter: LinearFilter,
26 | format: RGBAFormat
27 | };
28 |
29 | var size = renderer.getSize( new Vector2() );
30 | this._pixelRatio = renderer.getPixelRatio();
31 | this._width = size.width;
32 | this._height = size.height;
33 |
34 | renderTarget = new WebGLRenderTarget( this._width * this._pixelRatio, this._height * this._pixelRatio, parameters );
35 | renderTarget.texture.name = 'EffectComposer.rt1';
36 |
37 | } else {
38 |
39 | this._pixelRatio = 1;
40 | this._width = renderTarget.width;
41 | this._height = renderTarget.height;
42 |
43 | }
44 |
45 | this.renderTarget1 = renderTarget;
46 | this.renderTarget2 = renderTarget.clone();
47 | this.renderTarget2.texture.name = 'EffectComposer.rt2';
48 |
49 | this.writeBuffer = this.renderTarget1;
50 | this.readBuffer = this.renderTarget2;
51 |
52 | this.renderToScreen = true;
53 |
54 | this.passes = [];
55 |
56 | // dependencies
57 |
58 | if ( CopyShader === undefined ) {
59 |
60 | console.error( 'THREE.EffectComposer relies on CopyShader' );
61 |
62 | }
63 |
64 | if ( ShaderPass === undefined ) {
65 |
66 | console.error( 'THREE.EffectComposer relies on ShaderPass' );
67 |
68 | }
69 |
70 | this.copyPass = new ShaderPass( CopyShader );
71 |
72 | this.clock = new Clock();
73 |
74 | };
75 |
76 | Object.assign( EffectComposer.prototype, {
77 |
78 | swapBuffers: function () {
79 |
80 | var tmp = this.readBuffer;
81 | this.readBuffer = this.writeBuffer;
82 | this.writeBuffer = tmp;
83 |
84 | },
85 |
86 | addPass: function ( pass ) {
87 |
88 | this.passes.push( pass );
89 | pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
90 |
91 | },
92 |
93 | insertPass: function ( pass, index ) {
94 |
95 | this.passes.splice( index, 0, pass );
96 | pass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
97 |
98 | },
99 |
100 | removePass: function ( pass ) {
101 |
102 | const index = this.passes.indexOf( pass );
103 |
104 | if ( index !== - 1 ) {
105 |
106 | this.passes.splice( index, 1 );
107 |
108 | }
109 |
110 | },
111 |
112 | isLastEnabledPass: function ( passIndex ) {
113 |
114 | for ( var i = passIndex + 1; i < this.passes.length; i ++ ) {
115 |
116 | if ( this.passes[ i ].enabled ) {
117 |
118 | return false;
119 |
120 | }
121 |
122 | }
123 |
124 | return true;
125 |
126 | },
127 |
128 | render: function ( deltaTime ) {
129 |
130 | // deltaTime value is in seconds
131 |
132 | if ( deltaTime === undefined ) {
133 |
134 | deltaTime = this.clock.getDelta();
135 |
136 | }
137 |
138 | var currentRenderTarget = this.renderer.getRenderTarget();
139 |
140 | var maskActive = false;
141 |
142 | var pass, i, il = this.passes.length;
143 |
144 | for ( i = 0; i < il; i ++ ) {
145 |
146 | pass = this.passes[ i ];
147 |
148 | if ( pass.enabled === false ) continue;
149 |
150 | pass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );
151 | pass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );
152 |
153 | if ( pass.needsSwap ) {
154 |
155 | if ( maskActive ) {
156 |
157 | var context = this.renderer.getContext();
158 | var stencil = this.renderer.state.buffers.stencil;
159 |
160 | //context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
161 | stencil.setFunc( context.NOTEQUAL, 1, 0xffffffff );
162 |
163 | this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );
164 |
165 | //context.stencilFunc( context.EQUAL, 1, 0xffffffff );
166 | stencil.setFunc( context.EQUAL, 1, 0xffffffff );
167 |
168 | }
169 |
170 | this.swapBuffers();
171 |
172 | }
173 |
174 | if ( MaskPass !== undefined ) {
175 |
176 | if ( pass instanceof MaskPass ) {
177 |
178 | maskActive = true;
179 |
180 | } else if ( pass instanceof ClearMaskPass ) {
181 |
182 | maskActive = false;
183 |
184 | }
185 |
186 | }
187 |
188 | }
189 |
190 | this.renderer.setRenderTarget( currentRenderTarget );
191 |
192 | },
193 |
194 | reset: function ( renderTarget ) {
195 |
196 | if ( renderTarget === undefined ) {
197 |
198 | var size = this.renderer.getSize( new Vector2() );
199 | this._pixelRatio = this.renderer.getPixelRatio();
200 | this._width = size.width;
201 | this._height = size.height;
202 |
203 | renderTarget = this.renderTarget1.clone();
204 | renderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );
205 |
206 | }
207 |
208 | this.renderTarget1.dispose();
209 | this.renderTarget2.dispose();
210 | this.renderTarget1 = renderTarget;
211 | this.renderTarget2 = renderTarget.clone();
212 |
213 | this.writeBuffer = this.renderTarget1;
214 | this.readBuffer = this.renderTarget2;
215 |
216 | },
217 |
218 | setSize: function ( width, height ) {
219 |
220 | this._width = width;
221 | this._height = height;
222 |
223 | var effectiveWidth = this._width * this._pixelRatio;
224 | var effectiveHeight = this._height * this._pixelRatio;
225 |
226 | this.renderTarget1.setSize( effectiveWidth, effectiveHeight );
227 | this.renderTarget2.setSize( effectiveWidth, effectiveHeight );
228 |
229 | for ( var i = 0; i < this.passes.length; i ++ ) {
230 |
231 | this.passes[ i ].setSize( effectiveWidth, effectiveHeight );
232 |
233 | }
234 |
235 | },
236 |
237 | setPixelRatio: function ( pixelRatio ) {
238 |
239 | this._pixelRatio = pixelRatio;
240 |
241 | this.setSize( this._width, this._height );
242 |
243 | }
244 |
245 | } );
246 |
247 |
248 | var Pass = function () {
249 |
250 | // if set to true, the pass is processed by the composer
251 | this.enabled = true;
252 |
253 | // if set to true, the pass indicates to swap read and write buffer after rendering
254 | this.needsSwap = true;
255 |
256 | // if set to true, the pass clears its buffer before rendering
257 | this.clear = false;
258 |
259 | // if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.
260 | this.renderToScreen = false;
261 |
262 | };
263 |
264 | Object.assign( Pass.prototype, {
265 |
266 | setSize: function ( /* width, height */ ) {},
267 |
268 | render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
269 |
270 | console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
271 |
272 | }
273 |
274 | } );
275 |
276 | // Helper for passes that need to fill the viewport with a single quad.
277 | Pass.FullScreenQuad = ( function () {
278 |
279 | var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
280 |
281 | // https://github.com/mrdoob/three.js/pull/21358
282 |
283 | var geometry = new BufferGeometry();
284 | geometry.setAttribute( 'position', new Float32BufferAttribute( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) );
285 | geometry.setAttribute( 'uv', new Float32BufferAttribute( [ 0, 2, 0, 0, 2, 0 ], 2 ) );
286 |
287 | var FullScreenQuad = function ( material ) {
288 |
289 | this._mesh = new Mesh( geometry, material );
290 |
291 | };
292 |
293 | Object.defineProperty( FullScreenQuad.prototype, 'material', {
294 |
295 | get: function () {
296 |
297 | return this._mesh.material;
298 |
299 | },
300 |
301 | set: function ( value ) {
302 |
303 | this._mesh.material = value;
304 |
305 | }
306 |
307 | } );
308 |
309 | Object.assign( FullScreenQuad.prototype, {
310 |
311 | dispose: function () {
312 |
313 | this._mesh.geometry.dispose();
314 |
315 | },
316 |
317 | render: function ( renderer ) {
318 |
319 | renderer.render( this._mesh, camera );
320 |
321 | }
322 |
323 | } );
324 |
325 | return FullScreenQuad;
326 |
327 | } )();
328 |
329 | export { EffectComposer, Pass };
330 |
--------------------------------------------------------------------------------
/src/lib/LuminosityHighPassShader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author bhouston / http://clara.io/
3 | *
4 | * Luminosity
5 | * http://en.wikipedia.org/wiki/Luminosity
6 | */
7 |
8 | // import { Color } from "./three.module.js";
9 | import { Color } from "three";
10 |
11 | var LuminosityHighPassShader = {
12 | shaderID: "luminosityHighPass",
13 |
14 | uniforms: {
15 | tDiffuse: { value: null },
16 | luminosityThreshold: { value: 1.0 },
17 | smoothWidth: { value: 1.0 },
18 | defaultColor: { value: new Color(0x000000) },
19 | defaultOpacity: { value: 0.0 },
20 | },
21 |
22 | vertexShader: [
23 | "varying vec2 vUv;",
24 |
25 | "void main() {",
26 |
27 | " vUv = uv;",
28 |
29 | " gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );",
30 |
31 | "}",
32 | ].join("\n"),
33 |
34 | fragmentShader: [
35 | "uniform sampler2D tDiffuse;",
36 | "uniform vec3 defaultColor;",
37 | "uniform float defaultOpacity;",
38 | "uniform float luminosityThreshold;",
39 | "uniform float smoothWidth;",
40 |
41 | "varying vec2 vUv;",
42 |
43 | "void main() {",
44 |
45 | " vec4 texel = texture2D( tDiffuse, vUv );",
46 |
47 | " vec3 luma = vec3( 0.299, 0.587, 0.114 );",
48 |
49 | " float v = dot( texel.xyz, luma );",
50 |
51 | " vec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );",
52 |
53 | " float alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );",
54 |
55 | " gl_FragColor = mix( outputColor, texel, alpha );",
56 |
57 | "}",
58 | ].join("\n"),
59 | };
60 |
61 | export { LuminosityHighPassShader };
62 |
--------------------------------------------------------------------------------
/src/lib/MaskPass.js:
--------------------------------------------------------------------------------
1 | import { Pass } from './Pass';
2 |
3 | var MaskPass = function ( scene, camera ) {
4 |
5 | Pass.call( this );
6 |
7 | this.scene = scene;
8 | this.camera = camera;
9 |
10 | this.clear = true;
11 | this.needsSwap = false;
12 |
13 | this.inverse = false;
14 |
15 | };
16 |
17 | MaskPass.prototype = Object.assign( Object.create( Pass.prototype ), {
18 |
19 | constructor: MaskPass,
20 |
21 | render: function ( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {
22 |
23 | var context = renderer.getContext();
24 | var state = renderer.state;
25 |
26 | // don't update color or depth
27 |
28 | state.buffers.color.setMask( false );
29 | state.buffers.depth.setMask( false );
30 |
31 | // lock buffers
32 |
33 | state.buffers.color.setLocked( true );
34 | state.buffers.depth.setLocked( true );
35 |
36 | // set up stencil
37 |
38 | var writeValue, clearValue;
39 |
40 | if ( this.inverse ) {
41 |
42 | writeValue = 0;
43 | clearValue = 1;
44 |
45 | } else {
46 |
47 | writeValue = 1;
48 | clearValue = 0;
49 |
50 | }
51 |
52 | state.buffers.stencil.setTest( true );
53 | state.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );
54 | state.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );
55 | state.buffers.stencil.setClear( clearValue );
56 | state.buffers.stencil.setLocked( true );
57 |
58 | // draw into the stencil buffer
59 |
60 | renderer.setRenderTarget( readBuffer );
61 | if ( this.clear ) renderer.clear();
62 | renderer.render( this.scene, this.camera );
63 |
64 | renderer.setRenderTarget( writeBuffer );
65 | if ( this.clear ) renderer.clear();
66 | renderer.render( this.scene, this.camera );
67 |
68 | // unlock color and depth buffer for subsequent rendering
69 |
70 | state.buffers.color.setLocked( false );
71 | state.buffers.depth.setLocked( false );
72 |
73 | // only render where stencil is set to 1
74 |
75 | state.buffers.stencil.setLocked( false );
76 | state.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1
77 | state.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );
78 | state.buffers.stencil.setLocked( true );
79 |
80 | }
81 |
82 | } );
83 |
84 |
85 | var ClearMaskPass = function () {
86 |
87 | Pass.call( this );
88 |
89 | this.needsSwap = false;
90 |
91 | };
92 |
93 | ClearMaskPass.prototype = Object.create( Pass.prototype );
94 |
95 | Object.assign( ClearMaskPass.prototype, {
96 |
97 | render: function ( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
98 |
99 | renderer.state.buffers.stencil.setLocked( false );
100 | renderer.state.buffers.stencil.setTest( false );
101 |
102 | }
103 |
104 | } );
105 |
106 | export { MaskPass, ClearMaskPass };
107 |
--------------------------------------------------------------------------------
/src/lib/OBJLoader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | // import {
6 | // BufferGeometry,
7 | // FileLoader,
8 | // Float32BufferAttribute,
9 | // Group,
10 | // LineBasicMaterial,
11 | // LineSegments,
12 | // Loader,
13 | // Material,
14 | // Mesh,
15 | // MeshPhongMaterial,
16 | // NoColors,
17 | // Points,
18 | // PointsMaterial,
19 | // VertexColors,
20 | // } from "./three.module.js";
21 | import {
22 | BufferGeometry,
23 | FileLoader,
24 | Float32BufferAttribute,
25 | Group,
26 | LineBasicMaterial,
27 | LineSegments,
28 | Loader,
29 | Material,
30 | Mesh,
31 | MeshPhongMaterial,
32 | NoColors,
33 | Points,
34 | PointsMaterial,
35 | VertexColors,
36 | } from "three";
37 |
38 | var OBJLoader = (function () {
39 | // o object_name | g group_name
40 | var object_pattern = /^[og]\s*(.+)?/;
41 | // mtllib file_reference
42 | var material_library_pattern = /^mtllib /;
43 | // usemtl material_name
44 | var material_use_pattern = /^usemtl /;
45 | // usemap map_name
46 | var map_use_pattern = /^usemap /;
47 |
48 | function ParserState() {
49 | var state = {
50 | objects: [],
51 | object: {},
52 |
53 | vertices: [],
54 | normals: [],
55 | colors: [],
56 | uvs: [],
57 |
58 | materialLibraries: [],
59 |
60 | startObject: function (name, fromDeclaration) {
61 | // If the current object (initial from reset) is not from a g/o declaration in the parsed
62 | // file. We need to use it for the first parsed g/o to keep things in sync.
63 | if (this.object && this.object.fromDeclaration === false) {
64 | this.object.name = name;
65 | this.object.fromDeclaration = fromDeclaration !== false;
66 | return;
67 | }
68 |
69 | var previousMaterial =
70 | this.object && typeof this.object.currentMaterial === "function"
71 | ? this.object.currentMaterial()
72 | : undefined;
73 |
74 | if (this.object && typeof this.object._finalize === "function") {
75 | this.object._finalize(true);
76 | }
77 |
78 | this.object = {
79 | name: name || "",
80 | fromDeclaration: fromDeclaration !== false,
81 |
82 | geometry: {
83 | vertices: [],
84 | normals: [],
85 | colors: [],
86 | uvs: [],
87 | },
88 | materials: [],
89 | smooth: true,
90 |
91 | startMaterial: function (name, libraries) {
92 | var previous = this._finalize(false);
93 |
94 | // New usemtl declaration overwrites an inherited material, except if faces were declared
95 | // after the material, then it must be preserved for proper MultiMaterial continuation.
96 | if (previous && (previous.inherited || previous.groupCount <= 0)) {
97 | this.materials.splice(previous.index, 1);
98 | }
99 |
100 | var material = {
101 | index: this.materials.length,
102 | name: name || "",
103 | mtllib:
104 | Array.isArray(libraries) && libraries.length > 0
105 | ? libraries[libraries.length - 1]
106 | : "",
107 | smooth: previous !== undefined ? previous.smooth : this.smooth,
108 | groupStart: previous !== undefined ? previous.groupEnd : 0,
109 | groupEnd: -1,
110 | groupCount: -1,
111 | inherited: false,
112 |
113 | clone: function (index) {
114 | var cloned = {
115 | index: typeof index === "number" ? index : this.index,
116 | name: this.name,
117 | mtllib: this.mtllib,
118 | smooth: this.smooth,
119 | groupStart: 0,
120 | groupEnd: -1,
121 | groupCount: -1,
122 | inherited: false,
123 | };
124 | cloned.clone = this.clone.bind(cloned);
125 | return cloned;
126 | },
127 | };
128 |
129 | this.materials.push(material);
130 |
131 | return material;
132 | },
133 |
134 | currentMaterial: function () {
135 | if (this.materials.length > 0) {
136 | return this.materials[this.materials.length - 1];
137 | }
138 |
139 | return undefined;
140 | },
141 |
142 | _finalize: function (end) {
143 | var lastMultiMaterial = this.currentMaterial();
144 | if (lastMultiMaterial && lastMultiMaterial.groupEnd === -1) {
145 | lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3;
146 | lastMultiMaterial.groupCount =
147 | lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart;
148 | lastMultiMaterial.inherited = false;
149 | }
150 |
151 | // Ignore objects tail materials if no face declarations followed them before a new o/g started.
152 | if (end && this.materials.length > 1) {
153 | for (var mi = this.materials.length - 1; mi >= 0; mi--) {
154 | if (this.materials[mi].groupCount <= 0) {
155 | this.materials.splice(mi, 1);
156 | }
157 | }
158 | }
159 |
160 | // Guarantee at least one empty material, this makes the creation later more straight forward.
161 | if (end && this.materials.length === 0) {
162 | this.materials.push({
163 | name: "",
164 | smooth: this.smooth,
165 | });
166 | }
167 |
168 | return lastMultiMaterial;
169 | },
170 | };
171 |
172 | // Inherit previous objects material.
173 | // Spec tells us that a declared material must be set to all objects until a new material is declared.
174 | // If a usemtl declaration is encountered while this new object is being parsed, it will
175 | // overwrite the inherited material. Exception being that there was already face declarations
176 | // to the inherited material, then it will be preserved for proper MultiMaterial continuation.
177 |
178 | if (
179 | previousMaterial &&
180 | previousMaterial.name &&
181 | typeof previousMaterial.clone === "function"
182 | ) {
183 | var declared = previousMaterial.clone(0);
184 | declared.inherited = true;
185 | this.object.materials.push(declared);
186 | }
187 |
188 | this.objects.push(this.object);
189 | },
190 |
191 | finalize: function () {
192 | if (this.object && typeof this.object._finalize === "function") {
193 | this.object._finalize(true);
194 | }
195 | },
196 |
197 | parseVertexIndex: function (value, len) {
198 | var index = parseInt(value, 10);
199 | return (index >= 0 ? index - 1 : index + len / 3) * 3;
200 | },
201 |
202 | parseNormalIndex: function (value, len) {
203 | var index = parseInt(value, 10);
204 | return (index >= 0 ? index - 1 : index + len / 3) * 3;
205 | },
206 |
207 | parseUVIndex: function (value, len) {
208 | var index = parseInt(value, 10);
209 | return (index >= 0 ? index - 1 : index + len / 2) * 2;
210 | },
211 |
212 | addVertex: function (a, b, c) {
213 | var src = this.vertices;
214 | var dst = this.object.geometry.vertices;
215 |
216 | dst.push(src[a + 0], src[a + 1], src[a + 2]);
217 | dst.push(src[b + 0], src[b + 1], src[b + 2]);
218 | dst.push(src[c + 0], src[c + 1], src[c + 2]);
219 | },
220 |
221 | addVertexPoint: function (a) {
222 | var src = this.vertices;
223 | var dst = this.object.geometry.vertices;
224 |
225 | dst.push(src[a + 0], src[a + 1], src[a + 2]);
226 | },
227 |
228 | addVertexLine: function (a) {
229 | var src = this.vertices;
230 | var dst = this.object.geometry.vertices;
231 |
232 | dst.push(src[a + 0], src[a + 1], src[a + 2]);
233 | },
234 |
235 | addNormal: function (a, b, c) {
236 | var src = this.normals;
237 | var dst = this.object.geometry.normals;
238 |
239 | dst.push(src[a + 0], src[a + 1], src[a + 2]);
240 | dst.push(src[b + 0], src[b + 1], src[b + 2]);
241 | dst.push(src[c + 0], src[c + 1], src[c + 2]);
242 | },
243 |
244 | addColor: function (a, b, c) {
245 | var src = this.colors;
246 | var dst = this.object.geometry.colors;
247 |
248 | dst.push(src[a + 0], src[a + 1], src[a + 2]);
249 | dst.push(src[b + 0], src[b + 1], src[b + 2]);
250 | dst.push(src[c + 0], src[c + 1], src[c + 2]);
251 | },
252 |
253 | addUV: function (a, b, c) {
254 | var src = this.uvs;
255 | var dst = this.object.geometry.uvs;
256 |
257 | dst.push(src[a + 0], src[a + 1]);
258 | dst.push(src[b + 0], src[b + 1]);
259 | dst.push(src[c + 0], src[c + 1]);
260 | },
261 |
262 | addUVLine: function (a) {
263 | var src = this.uvs;
264 | var dst = this.object.geometry.uvs;
265 |
266 | dst.push(src[a + 0], src[a + 1]);
267 | },
268 |
269 | addFace: function (a, b, c, ua, ub, uc, na, nb, nc) {
270 | var vLen = this.vertices.length;
271 |
272 | var ia = this.parseVertexIndex(a, vLen);
273 | var ib = this.parseVertexIndex(b, vLen);
274 | var ic = this.parseVertexIndex(c, vLen);
275 |
276 | this.addVertex(ia, ib, ic);
277 |
278 | if (this.colors.length > 0) {
279 | this.addColor(ia, ib, ic);
280 | }
281 |
282 | if (ua !== undefined && ua !== "") {
283 | var uvLen = this.uvs.length;
284 | ia = this.parseUVIndex(ua, uvLen);
285 | ib = this.parseUVIndex(ub, uvLen);
286 | ic = this.parseUVIndex(uc, uvLen);
287 | this.addUV(ia, ib, ic);
288 | }
289 |
290 | if (na !== undefined && na !== "") {
291 | // Normals are many times the same. If so, skip function call and parseInt.
292 | var nLen = this.normals.length;
293 | ia = this.parseNormalIndex(na, nLen);
294 |
295 | ib = na === nb ? ia : this.parseNormalIndex(nb, nLen);
296 | ic = na === nc ? ia : this.parseNormalIndex(nc, nLen);
297 |
298 | this.addNormal(ia, ib, ic);
299 | }
300 | },
301 |
302 | addPointGeometry: function (vertices) {
303 | this.object.geometry.type = "Points";
304 |
305 | var vLen = this.vertices.length;
306 |
307 | for (var vi = 0, l = vertices.length; vi < l; vi++) {
308 | this.addVertexPoint(this.parseVertexIndex(vertices[vi], vLen));
309 | }
310 | },
311 |
312 | addLineGeometry: function (vertices, uvs) {
313 | this.object.geometry.type = "Line";
314 |
315 | var vLen = this.vertices.length;
316 | var uvLen = this.uvs.length;
317 |
318 | for (var vi = 0, l = vertices.length; vi < l; vi++) {
319 | this.addVertexLine(this.parseVertexIndex(vertices[vi], vLen));
320 | }
321 |
322 | for (var uvi = 0, l = uvs.length; uvi < l; uvi++) {
323 | this.addUVLine(this.parseUVIndex(uvs[uvi], uvLen));
324 | }
325 | },
326 | };
327 |
328 | state.startObject("", false);
329 |
330 | return state;
331 | }
332 |
333 | //
334 |
335 | function OBJLoader(manager) {
336 | Loader.call(this, manager);
337 |
338 | this.materials = null;
339 | }
340 |
341 | OBJLoader.prototype = Object.assign(Object.create(Loader.prototype), {
342 | constructor: OBJLoader,
343 |
344 | load: function (url, onLoad, onProgress, onError) {
345 | var scope = this;
346 |
347 | var loader = new FileLoader(scope.manager);
348 | loader.setPath(this.path);
349 | loader.load(
350 | url,
351 | function (text) {
352 | onLoad(scope.parse(text));
353 | },
354 | onProgress,
355 | onError
356 | );
357 | },
358 |
359 | setMaterials: function (materials) {
360 | this.materials = materials;
361 |
362 | return this;
363 | },
364 |
365 | parse: function (text) {
366 | console.time("OBJLoader");
367 |
368 | var state = new ParserState();
369 |
370 | if (text.indexOf("\r\n") !== -1) {
371 | // This is faster than String.split with regex that splits on both
372 | text = text.replace(/\r\n/g, "\n");
373 | }
374 |
375 | if (text.indexOf("\\\n") !== -1) {
376 | // join lines separated by a line continuation character (\)
377 | text = text.replace(/\\\n/g, "");
378 | }
379 |
380 | var lines = text.split("\n");
381 | var line = "",
382 | lineFirstChar = "";
383 | var lineLength = 0;
384 | var result = [];
385 |
386 | // Faster to just trim left side of the line. Use if available.
387 | var trimLeft = typeof "".trimLeft === "function";
388 |
389 | for (var i = 0, l = lines.length; i < l; i++) {
390 | line = lines[i];
391 |
392 | line = trimLeft ? line.trimLeft() : line.trim();
393 |
394 | lineLength = line.length;
395 |
396 | if (lineLength === 0) continue;
397 |
398 | lineFirstChar = line.charAt(0);
399 |
400 | // @todo invoke passed in handler if any
401 | if (lineFirstChar === "#") continue;
402 |
403 | if (lineFirstChar === "v") {
404 | var data = line.split(/\s+/);
405 |
406 | switch (data[0]) {
407 | case "v":
408 | state.vertices.push(
409 | parseFloat(data[1]),
410 | parseFloat(data[2]),
411 | parseFloat(data[3])
412 | );
413 | if (data.length >= 7) {
414 | state.colors.push(
415 | parseFloat(data[4]),
416 | parseFloat(data[5]),
417 | parseFloat(data[6])
418 | );
419 | }
420 | break;
421 | case "vn":
422 | state.normals.push(
423 | parseFloat(data[1]),
424 | parseFloat(data[2]),
425 | parseFloat(data[3])
426 | );
427 | break;
428 | case "vt":
429 | state.uvs.push(parseFloat(data[1]), parseFloat(data[2]));
430 | break;
431 | }
432 | } else if (lineFirstChar === "f") {
433 | var lineData = line.substr(1).trim();
434 | var vertexData = lineData.split(/\s+/);
435 | var faceVertices = [];
436 |
437 | // Parse the face vertex data into an easy to work with format
438 |
439 | for (var j = 0, jl = vertexData.length; j < jl; j++) {
440 | var vertex = vertexData[j];
441 |
442 | if (vertex.length > 0) {
443 | var vertexParts = vertex.split("/");
444 | faceVertices.push(vertexParts);
445 | }
446 | }
447 |
448 | // Draw an edge between the first vertex and all subsequent vertices to form an n-gon
449 |
450 | var v1 = faceVertices[0];
451 |
452 | for (var j = 1, jl = faceVertices.length - 1; j < jl; j++) {
453 | var v2 = faceVertices[j];
454 | var v3 = faceVertices[j + 1];
455 |
456 | state.addFace(
457 | v1[0],
458 | v2[0],
459 | v3[0],
460 | v1[1],
461 | v2[1],
462 | v3[1],
463 | v1[2],
464 | v2[2],
465 | v3[2]
466 | );
467 | }
468 | } else if (lineFirstChar === "l") {
469 | var lineParts = line.substring(1).trim().split(" ");
470 | var lineVertices = [],
471 | lineUVs = [];
472 |
473 | if (line.indexOf("/") === -1) {
474 | lineVertices = lineParts;
475 | } else {
476 | for (var li = 0, llen = lineParts.length; li < llen; li++) {
477 | var parts = lineParts[li].split("/");
478 |
479 | if (parts[0] !== "") lineVertices.push(parts[0]);
480 | if (parts[1] !== "") lineUVs.push(parts[1]);
481 | }
482 | }
483 | state.addLineGeometry(lineVertices, lineUVs);
484 | } else if (lineFirstChar === "p") {
485 | var lineData = line.substr(1).trim();
486 | var pointData = lineData.split(" ");
487 |
488 | state.addPointGeometry(pointData);
489 | } else if ((result = object_pattern.exec(line)) !== null) {
490 | // o object_name
491 | // or
492 | // g group_name
493 |
494 | // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869
495 | // var name = result[ 0 ].substr( 1 ).trim();
496 | var name = (" " + result[0].substr(1).trim()).substr(1);
497 |
498 | state.startObject(name);
499 | } else if (material_use_pattern.test(line)) {
500 | // material
501 |
502 | state.object.startMaterial(
503 | line.substring(7).trim(),
504 | state.materialLibraries
505 | );
506 | } else if (material_library_pattern.test(line)) {
507 | // mtl file
508 |
509 | state.materialLibraries.push(line.substring(7).trim());
510 | } else if (map_use_pattern.test(line)) {
511 | // the line is parsed but ignored since the loader assumes textures are defined MTL files
512 | // (according to https://www.okino.com/conv/imp_wave.htm, 'usemap' is the old-style Wavefront texture reference method)
513 |
514 | console.warn(
515 | 'THREE.OBJLoader: Rendering identifier "usemap" not supported. Textures must be defined in MTL files.'
516 | );
517 | } else if (lineFirstChar === "s") {
518 | result = line.split(" ");
519 |
520 | // smooth shading
521 |
522 | // @todo Handle files that have varying smooth values for a set of faces inside one geometry,
523 | // but does not define a usemtl for each face set.
524 | // This should be detected and a dummy material created (later MultiMaterial and geometry groups).
525 | // This requires some care to not create extra material on each smooth value for "normal" obj files.
526 | // where explicit usemtl defines geometry groups.
527 | // Example asset: examples/models/obj/cerberus/Cerberus.obj
528 |
529 | /*
530 | * http://paulbourke.net/dataformats/obj/
531 | * or
532 | * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf
533 | *
534 | * From chapter "Grouping" Syntax explanation "s group_number":
535 | * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off.
536 | * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form
537 | * surfaces, smoothing groups are either turned on or off; there is no difference between values greater
538 | * than 0."
539 | */
540 | if (result.length > 1) {
541 | var value = result[1].trim().toLowerCase();
542 | state.object.smooth = value !== "0" && value !== "off";
543 | } else {
544 | // ZBrush can produce "s" lines #11707
545 | state.object.smooth = true;
546 | }
547 | var material = state.object.currentMaterial();
548 | if (material) material.smooth = state.object.smooth;
549 | } else {
550 | // Handle null terminated files without exception
551 | if (line === "\0") continue;
552 |
553 | throw new Error('THREE.OBJLoader: Unexpected line: "' + line + '"');
554 | }
555 | }
556 |
557 | state.finalize();
558 |
559 | var container = new Group();
560 | container.materialLibraries = [].concat(state.materialLibraries);
561 |
562 | for (var i = 0, l = state.objects.length; i < l; i++) {
563 | var object = state.objects[i];
564 | var geometry = object.geometry;
565 | var materials = object.materials;
566 | var isLine = geometry.type === "Line";
567 | var isPoints = geometry.type === "Points";
568 | var hasVertexColors = false;
569 |
570 | // Skip o/g line declarations that did not follow with any faces
571 | if (geometry.vertices.length === 0) continue;
572 |
573 | var buffergeometry = new BufferGeometry();
574 |
575 | buffergeometry.setAttribute(
576 | "position",
577 | new Float32BufferAttribute(geometry.vertices, 3)
578 | );
579 |
580 | if (geometry.normals.length > 0) {
581 | buffergeometry.setAttribute(
582 | "normal",
583 | new Float32BufferAttribute(geometry.normals, 3)
584 | );
585 | } else {
586 | buffergeometry.computeVertexNormals();
587 | }
588 |
589 | if (geometry.colors.length > 0) {
590 | hasVertexColors = true;
591 | buffergeometry.setAttribute(
592 | "color",
593 | new Float32BufferAttribute(geometry.colors, 3)
594 | );
595 | }
596 |
597 | if (geometry.uvs.length > 0) {
598 | buffergeometry.setAttribute(
599 | "uv",
600 | new Float32BufferAttribute(geometry.uvs, 2)
601 | );
602 | }
603 |
604 | // Create materials
605 |
606 | var createdMaterials = [];
607 |
608 | for (var mi = 0, miLen = materials.length; mi < miLen; mi++) {
609 | var sourceMaterial = materials[mi];
610 | var material = undefined;
611 |
612 | if (this.materials !== null) {
613 | material = this.materials.create(sourceMaterial.name);
614 |
615 | // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material.
616 | if (
617 | isLine &&
618 | material &&
619 | !(material instanceof LineBasicMaterial)
620 | ) {
621 | var materialLine = new LineBasicMaterial();
622 | Material.prototype.copy.call(materialLine, material);
623 | materialLine.color.copy(material.color);
624 | material = materialLine;
625 | } else if (
626 | isPoints &&
627 | material &&
628 | !(material instanceof PointsMaterial)
629 | ) {
630 | var materialPoints = new PointsMaterial({
631 | size: 10,
632 | sizeAttenuation: false,
633 | });
634 | Material.prototype.copy.call(materialPoints, material);
635 | materialPoints.color.copy(material.color);
636 | materialPoints.map = material.map;
637 | material = materialPoints;
638 | }
639 | }
640 |
641 | if (!material) {
642 | if (isLine) {
643 | material = new LineBasicMaterial();
644 | } else if (isPoints) {
645 | material = new PointsMaterial({
646 | size: 1,
647 | sizeAttenuation: false,
648 | });
649 | } else {
650 | material = new MeshPhongMaterial();
651 | }
652 |
653 | material.name = sourceMaterial.name;
654 | }
655 |
656 | material.flatShading = sourceMaterial.smooth ? false : true;
657 | material.vertexColors = hasVertexColors ? VertexColors : NoColors;
658 |
659 | createdMaterials.push(material);
660 | }
661 |
662 | // Create mesh
663 |
664 | var mesh;
665 |
666 | if (createdMaterials.length > 1) {
667 | for (var mi = 0, miLen = materials.length; mi < miLen; mi++) {
668 | var sourceMaterial = materials[mi];
669 | buffergeometry.addGroup(
670 | sourceMaterial.groupStart,
671 | sourceMaterial.groupCount,
672 | mi
673 | );
674 | }
675 |
676 | if (isLine) {
677 | mesh = new LineSegments(buffergeometry, createdMaterials);
678 | } else if (isPoints) {
679 | mesh = new Points(buffergeometry, createdMaterials);
680 | } else {
681 | mesh = new Mesh(buffergeometry, createdMaterials);
682 | }
683 | } else {
684 | if (isLine) {
685 | mesh = new LineSegments(buffergeometry, createdMaterials[0]);
686 | } else if (isPoints) {
687 | mesh = new Points(buffergeometry, createdMaterials[0]);
688 | } else {
689 | mesh = new Mesh(buffergeometry, createdMaterials[0]);
690 | }
691 | }
692 |
693 | mesh.name = object.name;
694 |
695 | container.add(mesh);
696 | }
697 |
698 | console.timeEnd("OBJLoader");
699 |
700 | return container;
701 | },
702 | });
703 |
704 | return OBJLoader;
705 | })();
706 |
707 | export { OBJLoader };
708 |
--------------------------------------------------------------------------------
/src/lib/OrbitControls.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | * @author ScieCode / http://github.com/sciecode
8 | */
9 |
10 | // import {
11 | // EventDispatcher,
12 | // MOUSE,
13 | // Quaternion,
14 | // Spherical,
15 | // TOUCH,
16 | // Vector2,
17 | // Vector3,
18 | // } from "./three.module.js";
19 | import {
20 | EventDispatcher,
21 | MOUSE,
22 | Quaternion,
23 | Spherical,
24 | TOUCH,
25 | Vector2,
26 | Vector3,
27 | } from "three";
28 |
29 | // This set of controls performs orbiting, dollying (zooming), and panning.
30 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
31 | //
32 | // Orbit - left mouse / touch: one-finger move
33 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
34 | // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
35 |
36 | var OrbitControls = function (object, domElement) {
37 | if (domElement === undefined)
38 | console.warn(
39 | 'THREE.OrbitControls: The second parameter "domElement" is now mandatory.'
40 | );
41 | if (domElement === document)
42 | console.error(
43 | 'THREE.OrbitControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.'
44 | );
45 |
46 | this.object = object;
47 | this.domElement = domElement;
48 |
49 | // Set to false to disable this control
50 | this.enabled = true;
51 |
52 | // "target" sets the location of focus, where the object orbits around
53 | this.target = new Vector3();
54 |
55 | // How far you can dolly in and out ( PerspectiveCamera only )
56 | this.minDistance = 0;
57 | this.maxDistance = Infinity;
58 |
59 | // How far you can zoom in and out ( OrthographicCamera only )
60 | this.minZoom = 0;
61 | this.maxZoom = Infinity;
62 |
63 | // How far you can orbit vertically, upper and lower limits.
64 | // Range is 0 to Math.PI radians.
65 | this.minPolarAngle = 0; // radians
66 | this.maxPolarAngle = Math.PI; // radians
67 |
68 | // How far you can orbit horizontally, upper and lower limits.
69 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
70 | this.minAzimuthAngle = -Infinity; // radians
71 | this.maxAzimuthAngle = Infinity; // radians
72 |
73 | // Set to true to enable damping (inertia)
74 | // If damping is enabled, you must call controls.update() in your animation loop
75 | this.enableDamping = false;
76 | this.dampingFactor = 0.05;
77 |
78 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
79 | // Set to false to disable zooming
80 | this.enableZoom = true;
81 | this.zoomSpeed = 1.0;
82 |
83 | // Set to false to disable rotating
84 | this.enableRotate = true;
85 | this.rotateSpeed = 1.0;
86 |
87 | // Set to false to disable panning
88 | this.enablePan = true;
89 | this.panSpeed = 1.0;
90 | this.screenSpacePanning = false; // if true, pan in screen-space
91 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
92 |
93 | // Set to true to automatically rotate around the target
94 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
95 | this.autoRotate = false;
96 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
97 |
98 | // Set to false to disable use of the keys
99 | this.enableKeys = true;
100 |
101 | // The four arrow keys
102 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
103 |
104 | // Mouse buttons
105 | this.mouseButtons = {
106 | LEFT: MOUSE.ROTATE,
107 | MIDDLE: MOUSE.DOLLY,
108 | RIGHT: MOUSE.PAN,
109 | };
110 |
111 | // Touch fingers
112 | this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN };
113 |
114 | // for reset
115 | this.target0 = this.target.clone();
116 | this.position0 = this.object.position.clone();
117 | this.zoom0 = this.object.zoom;
118 |
119 | //
120 | // public methods
121 | //
122 |
123 | this.getPolarAngle = function () {
124 | return spherical.phi;
125 | };
126 |
127 | this.getAzimuthalAngle = function () {
128 | return spherical.theta;
129 | };
130 |
131 | this.saveState = function () {
132 | scope.target0.copy(scope.target);
133 | scope.position0.copy(scope.object.position);
134 | scope.zoom0 = scope.object.zoom;
135 | };
136 |
137 | this.reset = function () {
138 | scope.target.copy(scope.target0);
139 | scope.object.position.copy(scope.position0);
140 | scope.object.zoom = scope.zoom0;
141 |
142 | scope.object.updateProjectionMatrix();
143 | scope.dispatchEvent(changeEvent);
144 |
145 | scope.update();
146 |
147 | state = STATE.NONE;
148 | };
149 |
150 | // this method is exposed, but perhaps it would be better if we can make it private...
151 | this.update = (function () {
152 | var offset = new Vector3();
153 |
154 | // so camera.up is the orbit axis
155 | var quat = new Quaternion().setFromUnitVectors(
156 | object.up,
157 | new Vector3(0, 1, 0)
158 | );
159 | var quatInverse = quat.clone().inverse();
160 |
161 | var lastPosition = new Vector3();
162 | var lastQuaternion = new Quaternion();
163 |
164 | return function update() {
165 | var position = scope.object.position;
166 |
167 | offset.copy(position).sub(scope.target);
168 |
169 | // rotate offset to "y-axis-is-up" space
170 | offset.applyQuaternion(quat);
171 |
172 | // angle from z-axis around y-axis
173 | spherical.setFromVector3(offset);
174 |
175 | if (scope.autoRotate && state === STATE.NONE) {
176 | rotateLeft(getAutoRotationAngle());
177 | }
178 |
179 | if (scope.enableDamping) {
180 | spherical.theta += sphericalDelta.theta * scope.dampingFactor;
181 | spherical.phi += sphericalDelta.phi * scope.dampingFactor;
182 | } else {
183 | spherical.theta += sphericalDelta.theta;
184 | spherical.phi += sphericalDelta.phi;
185 | }
186 |
187 | // restrict theta to be between desired limits
188 | spherical.theta = Math.max(
189 | scope.minAzimuthAngle,
190 | Math.min(scope.maxAzimuthAngle, spherical.theta)
191 | );
192 |
193 | // restrict phi to be between desired limits
194 | spherical.phi = Math.max(
195 | scope.minPolarAngle,
196 | Math.min(scope.maxPolarAngle, spherical.phi)
197 | );
198 |
199 | spherical.makeSafe();
200 |
201 | spherical.radius *= scale;
202 |
203 | // restrict radius to be between desired limits
204 | spherical.radius = Math.max(
205 | scope.minDistance,
206 | Math.min(scope.maxDistance, spherical.radius)
207 | );
208 |
209 | // move target to panned location
210 |
211 | if (scope.enableDamping === true) {
212 | scope.target.addScaledVector(panOffset, scope.dampingFactor);
213 | } else {
214 | scope.target.add(panOffset);
215 | }
216 |
217 | offset.setFromSpherical(spherical);
218 |
219 | // rotate offset back to "camera-up-vector-is-up" space
220 | offset.applyQuaternion(quatInverse);
221 |
222 | position.copy(scope.target).add(offset);
223 |
224 | scope.object.lookAt(scope.target);
225 |
226 | if (scope.enableDamping === true) {
227 | sphericalDelta.theta *= 1 - scope.dampingFactor;
228 | sphericalDelta.phi *= 1 - scope.dampingFactor;
229 |
230 | panOffset.multiplyScalar(1 - scope.dampingFactor);
231 | } else {
232 | sphericalDelta.set(0, 0, 0);
233 |
234 | panOffset.set(0, 0, 0);
235 | }
236 |
237 | scale = 1;
238 |
239 | // update condition is:
240 | // min(camera displacement, camera rotation in radians)^2 > EPS
241 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
242 |
243 | if (
244 | zoomChanged ||
245 | lastPosition.distanceToSquared(scope.object.position) > EPS ||
246 | 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS
247 | ) {
248 | scope.dispatchEvent(changeEvent);
249 |
250 | lastPosition.copy(scope.object.position);
251 | lastQuaternion.copy(scope.object.quaternion);
252 | zoomChanged = false;
253 |
254 | return true;
255 | }
256 |
257 | return false;
258 | };
259 | })();
260 |
261 | this.dispose = function () {
262 | scope.domElement.removeEventListener("contextmenu", onContextMenu, false);
263 | scope.domElement.removeEventListener("mousedown", onMouseDown, false);
264 | scope.domElement.removeEventListener("wheel", onMouseWheel, false);
265 |
266 | scope.domElement.removeEventListener("touchstart", onTouchStart, false);
267 | scope.domElement.removeEventListener("touchend", onTouchEnd, false);
268 | scope.domElement.removeEventListener("touchmove", onTouchMove, false);
269 |
270 | document.removeEventListener("mousemove", onMouseMove, false);
271 | document.removeEventListener("mouseup", onMouseUp, false);
272 |
273 | scope.domElement.removeEventListener("keydown", onKeyDown, false);
274 |
275 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
276 | };
277 |
278 | //
279 | // internals
280 | //
281 |
282 | var scope = this;
283 |
284 | var changeEvent = { type: "change" };
285 | var startEvent = { type: "start" };
286 | var endEvent = { type: "end" };
287 |
288 | var STATE = {
289 | NONE: -1,
290 | ROTATE: 0,
291 | DOLLY: 1,
292 | PAN: 2,
293 | TOUCH_ROTATE: 3,
294 | TOUCH_PAN: 4,
295 | TOUCH_DOLLY_PAN: 5,
296 | TOUCH_DOLLY_ROTATE: 6,
297 | };
298 |
299 | var state = STATE.NONE;
300 |
301 | var EPS = 0.000001;
302 |
303 | // current position in spherical coordinates
304 | var spherical = new Spherical();
305 | var sphericalDelta = new Spherical();
306 |
307 | var scale = 1;
308 | var panOffset = new Vector3();
309 | var zoomChanged = false;
310 |
311 | var rotateStart = new Vector2();
312 | var rotateEnd = new Vector2();
313 | var rotateDelta = new Vector2();
314 |
315 | var panStart = new Vector2();
316 | var panEnd = new Vector2();
317 | var panDelta = new Vector2();
318 |
319 | var dollyStart = new Vector2();
320 | var dollyEnd = new Vector2();
321 | var dollyDelta = new Vector2();
322 |
323 | function getAutoRotationAngle() {
324 | return ((2 * Math.PI) / 60 / 60) * scope.autoRotateSpeed;
325 | }
326 |
327 | function getZoomScale() {
328 | return Math.pow(0.95, scope.zoomSpeed);
329 | }
330 |
331 | function rotateLeft(angle) {
332 | sphericalDelta.theta -= angle;
333 | }
334 |
335 | function rotateUp(angle) {
336 | sphericalDelta.phi -= angle;
337 | }
338 |
339 | var panLeft = (function () {
340 | var v = new Vector3();
341 |
342 | return function panLeft(distance, objectMatrix) {
343 | v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
344 | v.multiplyScalar(-distance);
345 |
346 | panOffset.add(v);
347 | };
348 | })();
349 |
350 | var panUp = (function () {
351 | var v = new Vector3();
352 |
353 | return function panUp(distance, objectMatrix) {
354 | if (scope.screenSpacePanning === true) {
355 | v.setFromMatrixColumn(objectMatrix, 1);
356 | } else {
357 | v.setFromMatrixColumn(objectMatrix, 0);
358 | v.crossVectors(scope.object.up, v);
359 | }
360 |
361 | v.multiplyScalar(distance);
362 |
363 | panOffset.add(v);
364 | };
365 | })();
366 |
367 | // deltaX and deltaY are in pixels; right and down are positive
368 | var pan = (function () {
369 | var offset = new Vector3();
370 |
371 | return function pan(deltaX, deltaY) {
372 | var element = scope.domElement;
373 |
374 | if (scope.object.isPerspectiveCamera) {
375 | // perspective
376 | var position = scope.object.position;
377 | offset.copy(position).sub(scope.target);
378 | var targetDistance = offset.length();
379 |
380 | // half of the fov is center to top of screen
381 | targetDistance *= Math.tan(((scope.object.fov / 2) * Math.PI) / 180.0);
382 |
383 | // we use only clientHeight here so aspect ratio does not distort speed
384 | panLeft(
385 | (2 * deltaX * targetDistance) / element.clientHeight,
386 | scope.object.matrix
387 | );
388 | panUp(
389 | (2 * deltaY * targetDistance) / element.clientHeight,
390 | scope.object.matrix
391 | );
392 | } else if (scope.object.isOrthographicCamera) {
393 | // orthographic
394 | panLeft(
395 | (deltaX * (scope.object.right - scope.object.left)) /
396 | scope.object.zoom /
397 | element.clientWidth,
398 | scope.object.matrix
399 | );
400 | panUp(
401 | (deltaY * (scope.object.top - scope.object.bottom)) /
402 | scope.object.zoom /
403 | element.clientHeight,
404 | scope.object.matrix
405 | );
406 | } else {
407 | // camera neither orthographic nor perspective
408 | console.warn(
409 | "WARNING: OrbitControls.js encountered an unknown camera type - pan disabled."
410 | );
411 | scope.enablePan = false;
412 | }
413 | };
414 | })();
415 |
416 | function dollyOut(dollyScale) {
417 | if (scope.object.isPerspectiveCamera) {
418 | scale /= dollyScale;
419 | } else if (scope.object.isOrthographicCamera) {
420 | scope.object.zoom = Math.max(
421 | scope.minZoom,
422 | Math.min(scope.maxZoom, scope.object.zoom * dollyScale)
423 | );
424 | scope.object.updateProjectionMatrix();
425 | zoomChanged = true;
426 | } else {
427 | console.warn(
428 | "WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."
429 | );
430 | scope.enableZoom = false;
431 | }
432 | }
433 |
434 | function dollyIn(dollyScale) {
435 | if (scope.object.isPerspectiveCamera) {
436 | scale *= dollyScale;
437 | } else if (scope.object.isOrthographicCamera) {
438 | scope.object.zoom = Math.max(
439 | scope.minZoom,
440 | Math.min(scope.maxZoom, scope.object.zoom / dollyScale)
441 | );
442 | scope.object.updateProjectionMatrix();
443 | zoomChanged = true;
444 | } else {
445 | console.warn(
446 | "WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled."
447 | );
448 | scope.enableZoom = false;
449 | }
450 | }
451 |
452 | //
453 | // event callbacks - update the object state
454 | //
455 |
456 | function handleMouseDownRotate(event) {
457 | rotateStart.set(event.clientX, event.clientY);
458 | }
459 |
460 | function handleMouseDownDolly(event) {
461 | dollyStart.set(event.clientX, event.clientY);
462 | }
463 |
464 | function handleMouseDownPan(event) {
465 | panStart.set(event.clientX, event.clientY);
466 | }
467 |
468 | function handleMouseMoveRotate(event) {
469 | rotateEnd.set(event.clientX, event.clientY);
470 |
471 | rotateDelta
472 | .subVectors(rotateEnd, rotateStart)
473 | .multiplyScalar(scope.rotateSpeed);
474 |
475 | var element = scope.domElement;
476 |
477 | rotateLeft((2 * Math.PI * rotateDelta.x) / element.clientHeight); // yes, height
478 |
479 | rotateUp((2 * Math.PI * rotateDelta.y) / element.clientHeight);
480 |
481 | rotateStart.copy(rotateEnd);
482 |
483 | scope.update();
484 | }
485 |
486 | function handleMouseMoveDolly(event) {
487 | dollyEnd.set(event.clientX, event.clientY);
488 |
489 | dollyDelta.subVectors(dollyEnd, dollyStart);
490 |
491 | if (dollyDelta.y > 0) {
492 | dollyOut(getZoomScale());
493 | } else if (dollyDelta.y < 0) {
494 | dollyIn(getZoomScale());
495 | }
496 |
497 | dollyStart.copy(dollyEnd);
498 |
499 | scope.update();
500 | }
501 |
502 | function handleMouseMovePan(event) {
503 | panEnd.set(event.clientX, event.clientY);
504 |
505 | panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
506 |
507 | pan(panDelta.x, panDelta.y);
508 |
509 | panStart.copy(panEnd);
510 |
511 | scope.update();
512 | }
513 |
514 | function handleMouseUp(/*event*/) {
515 | // no-op
516 | }
517 |
518 | function handleMouseWheel(event) {
519 | if (event.deltaY < 0) {
520 | dollyIn(getZoomScale());
521 | } else if (event.deltaY > 0) {
522 | dollyOut(getZoomScale());
523 | }
524 |
525 | scope.update();
526 | }
527 |
528 | function handleKeyDown(event) {
529 | var needsUpdate = false;
530 |
531 | switch (event.keyCode) {
532 | case scope.keys.UP:
533 | pan(0, scope.keyPanSpeed);
534 | needsUpdate = true;
535 | break;
536 |
537 | case scope.keys.BOTTOM:
538 | pan(0, -scope.keyPanSpeed);
539 | needsUpdate = true;
540 | break;
541 |
542 | case scope.keys.LEFT:
543 | pan(scope.keyPanSpeed, 0);
544 | needsUpdate = true;
545 | break;
546 |
547 | case scope.keys.RIGHT:
548 | pan(-scope.keyPanSpeed, 0);
549 | needsUpdate = true;
550 | break;
551 | }
552 |
553 | if (needsUpdate) {
554 | // prevent the browser from scrolling on cursor keys
555 | event.preventDefault();
556 |
557 | scope.update();
558 | }
559 | }
560 |
561 | function handleTouchStartRotate(event) {
562 | if (event.touches.length == 1) {
563 | rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
564 | } else {
565 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
566 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
567 |
568 | rotateStart.set(x, y);
569 | }
570 | }
571 |
572 | function handleTouchStartPan(event) {
573 | if (event.touches.length == 1) {
574 | panStart.set(event.touches[0].pageX, event.touches[0].pageY);
575 | } else {
576 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
577 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
578 |
579 | panStart.set(x, y);
580 | }
581 | }
582 |
583 | function handleTouchStartDolly(event) {
584 | var dx = event.touches[0].pageX - event.touches[1].pageX;
585 | var dy = event.touches[0].pageY - event.touches[1].pageY;
586 |
587 | var distance = Math.sqrt(dx * dx + dy * dy);
588 |
589 | dollyStart.set(0, distance);
590 | }
591 |
592 | function handleTouchStartDollyPan(event) {
593 | if (scope.enableZoom) handleTouchStartDolly(event);
594 |
595 | if (scope.enablePan) handleTouchStartPan(event);
596 | }
597 |
598 | function handleTouchStartDollyRotate(event) {
599 | if (scope.enableZoom) handleTouchStartDolly(event);
600 |
601 | if (scope.enableRotate) handleTouchStartRotate(event);
602 | }
603 |
604 | function handleTouchMoveRotate(event) {
605 | if (event.touches.length == 1) {
606 | rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
607 | } else {
608 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
609 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
610 |
611 | rotateEnd.set(x, y);
612 | }
613 |
614 | rotateDelta
615 | .subVectors(rotateEnd, rotateStart)
616 | .multiplyScalar(scope.rotateSpeed);
617 |
618 | var element = scope.domElement;
619 |
620 | rotateLeft((2 * Math.PI * rotateDelta.x) / element.clientHeight); // yes, height
621 |
622 | rotateUp((2 * Math.PI * rotateDelta.y) / element.clientHeight);
623 |
624 | rotateStart.copy(rotateEnd);
625 | }
626 |
627 | function handleTouchMovePan(event) {
628 | if (event.touches.length == 1) {
629 | panEnd.set(event.touches[0].pageX, event.touches[0].pageY);
630 | } else {
631 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
632 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
633 |
634 | panEnd.set(x, y);
635 | }
636 |
637 | panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
638 |
639 | pan(panDelta.x, panDelta.y);
640 |
641 | panStart.copy(panEnd);
642 | }
643 |
644 | function handleTouchMoveDolly(event) {
645 | var dx = event.touches[0].pageX - event.touches[1].pageX;
646 | var dy = event.touches[0].pageY - event.touches[1].pageY;
647 |
648 | var distance = Math.sqrt(dx * dx + dy * dy);
649 |
650 | dollyEnd.set(0, distance);
651 |
652 | dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
653 |
654 | dollyOut(dollyDelta.y);
655 |
656 | dollyStart.copy(dollyEnd);
657 | }
658 |
659 | function handleTouchMoveDollyPan(event) {
660 | if (scope.enableZoom) handleTouchMoveDolly(event);
661 |
662 | if (scope.enablePan) handleTouchMovePan(event);
663 | }
664 |
665 | function handleTouchMoveDollyRotate(event) {
666 | if (scope.enableZoom) handleTouchMoveDolly(event);
667 |
668 | if (scope.enableRotate) handleTouchMoveRotate(event);
669 | }
670 |
671 | function handleTouchEnd(/*event*/) {
672 | // no-op
673 | }
674 |
675 | //
676 | // event handlers - FSM: listen for events and reset state
677 | //
678 |
679 | function onMouseDown(event) {
680 | if (scope.enabled === false) return;
681 |
682 | // Prevent the browser from scrolling.
683 | event.preventDefault();
684 |
685 | // Manually set the focus since calling preventDefault above
686 | // prevents the browser from setting it automatically.
687 |
688 | scope.domElement.focus ? scope.domElement.focus() : window.focus();
689 |
690 | var mouseAction;
691 |
692 | switch (event.button) {
693 | case 0:
694 | mouseAction = scope.mouseButtons.LEFT;
695 | break;
696 |
697 | case 1:
698 | mouseAction = scope.mouseButtons.MIDDLE;
699 | break;
700 |
701 | case 2:
702 | mouseAction = scope.mouseButtons.RIGHT;
703 | break;
704 |
705 | default:
706 | mouseAction = -1;
707 | }
708 |
709 | switch (mouseAction) {
710 | case MOUSE.DOLLY:
711 | if (scope.enableZoom === false) return;
712 |
713 | handleMouseDownDolly(event);
714 |
715 | state = STATE.DOLLY;
716 |
717 | break;
718 |
719 | case MOUSE.ROTATE:
720 | if (event.ctrlKey || event.metaKey || event.shiftKey) {
721 | if (scope.enablePan === false) return;
722 |
723 | handleMouseDownPan(event);
724 |
725 | state = STATE.PAN;
726 | } else {
727 | if (scope.enableRotate === false) return;
728 |
729 | handleMouseDownRotate(event);
730 |
731 | state = STATE.ROTATE;
732 | }
733 |
734 | break;
735 |
736 | case MOUSE.PAN:
737 | if (event.ctrlKey || event.metaKey || event.shiftKey) {
738 | if (scope.enableRotate === false) return;
739 |
740 | handleMouseDownRotate(event);
741 |
742 | state = STATE.ROTATE;
743 | } else {
744 | if (scope.enablePan === false) return;
745 |
746 | handleMouseDownPan(event);
747 |
748 | state = STATE.PAN;
749 | }
750 |
751 | break;
752 |
753 | default:
754 | state = STATE.NONE;
755 | }
756 |
757 | if (state !== STATE.NONE) {
758 | document.addEventListener("mousemove", onMouseMove, false);
759 | document.addEventListener("mouseup", onMouseUp, false);
760 |
761 | scope.dispatchEvent(startEvent);
762 | }
763 | }
764 |
765 | function onMouseMove(event) {
766 | if (scope.enabled === false) return;
767 |
768 | event.preventDefault();
769 |
770 | switch (state) {
771 | case STATE.ROTATE:
772 | if (scope.enableRotate === false) return;
773 |
774 | handleMouseMoveRotate(event);
775 |
776 | break;
777 |
778 | case STATE.DOLLY:
779 | if (scope.enableZoom === false) return;
780 |
781 | handleMouseMoveDolly(event);
782 |
783 | break;
784 |
785 | case STATE.PAN:
786 | if (scope.enablePan === false) return;
787 |
788 | handleMouseMovePan(event);
789 |
790 | break;
791 | }
792 | }
793 |
794 | function onMouseUp(event) {
795 | if (scope.enabled === false) return;
796 |
797 | handleMouseUp(event);
798 |
799 | document.removeEventListener("mousemove", onMouseMove, false);
800 | document.removeEventListener("mouseup", onMouseUp, false);
801 |
802 | scope.dispatchEvent(endEvent);
803 |
804 | state = STATE.NONE;
805 | }
806 |
807 | function onMouseWheel(event) {
808 | if (
809 | scope.enabled === false ||
810 | scope.enableZoom === false ||
811 | (state !== STATE.NONE && state !== STATE.ROTATE)
812 | )
813 | return;
814 |
815 | event.preventDefault();
816 | event.stopPropagation();
817 |
818 | scope.dispatchEvent(startEvent);
819 |
820 | handleMouseWheel(event);
821 |
822 | scope.dispatchEvent(endEvent);
823 | }
824 |
825 | function onKeyDown(event) {
826 | if (
827 | scope.enabled === false ||
828 | scope.enableKeys === false ||
829 | scope.enablePan === false
830 | )
831 | return;
832 |
833 | handleKeyDown(event);
834 | }
835 |
836 | function onTouchStart(event) {
837 | if (scope.enabled === false) return;
838 |
839 | event.preventDefault(); // prevent scrolling
840 |
841 | switch (event.touches.length) {
842 | case 1:
843 | switch (scope.touches.ONE) {
844 | case TOUCH.ROTATE:
845 | if (scope.enableRotate === false) return;
846 |
847 | handleTouchStartRotate(event);
848 |
849 | state = STATE.TOUCH_ROTATE;
850 |
851 | break;
852 |
853 | case TOUCH.PAN:
854 | if (scope.enablePan === false) return;
855 |
856 | handleTouchStartPan(event);
857 |
858 | state = STATE.TOUCH_PAN;
859 |
860 | break;
861 |
862 | default:
863 | state = STATE.NONE;
864 | }
865 |
866 | break;
867 |
868 | case 2:
869 | switch (scope.touches.TWO) {
870 | case TOUCH.DOLLY_PAN:
871 | if (scope.enableZoom === false && scope.enablePan === false) return;
872 |
873 | handleTouchStartDollyPan(event);
874 |
875 | state = STATE.TOUCH_DOLLY_PAN;
876 |
877 | break;
878 |
879 | case TOUCH.DOLLY_ROTATE:
880 | if (scope.enableZoom === false && scope.enableRotate === false)
881 | return;
882 |
883 | handleTouchStartDollyRotate(event);
884 |
885 | state = STATE.TOUCH_DOLLY_ROTATE;
886 |
887 | break;
888 |
889 | default:
890 | state = STATE.NONE;
891 | }
892 |
893 | break;
894 |
895 | default:
896 | state = STATE.NONE;
897 | }
898 |
899 | if (state !== STATE.NONE) {
900 | scope.dispatchEvent(startEvent);
901 | }
902 | }
903 |
904 | function onTouchMove(event) {
905 | if (scope.enabled === false) return;
906 |
907 | event.preventDefault(); // prevent scrolling
908 | event.stopPropagation();
909 |
910 | switch (state) {
911 | case STATE.TOUCH_ROTATE:
912 | if (scope.enableRotate === false) return;
913 |
914 | handleTouchMoveRotate(event);
915 |
916 | scope.update();
917 |
918 | break;
919 |
920 | case STATE.TOUCH_PAN:
921 | if (scope.enablePan === false) return;
922 |
923 | handleTouchMovePan(event);
924 |
925 | scope.update();
926 |
927 | break;
928 |
929 | case STATE.TOUCH_DOLLY_PAN:
930 | if (scope.enableZoom === false && scope.enablePan === false) return;
931 |
932 | handleTouchMoveDollyPan(event);
933 |
934 | scope.update();
935 |
936 | break;
937 |
938 | case STATE.TOUCH_DOLLY_ROTATE:
939 | if (scope.enableZoom === false && scope.enableRotate === false) return;
940 |
941 | handleTouchMoveDollyRotate(event);
942 |
943 | scope.update();
944 |
945 | break;
946 |
947 | default:
948 | state = STATE.NONE;
949 | }
950 | }
951 |
952 | function onTouchEnd(event) {
953 | if (scope.enabled === false) return;
954 |
955 | handleTouchEnd(event);
956 |
957 | scope.dispatchEvent(endEvent);
958 |
959 | state = STATE.NONE;
960 | }
961 |
962 | function onContextMenu(event) {
963 | if (scope.enabled === false) return;
964 |
965 | event.preventDefault();
966 | }
967 |
968 | //
969 |
970 | scope.domElement.addEventListener("contextmenu", onContextMenu, false);
971 |
972 | scope.domElement.addEventListener("mousedown", onMouseDown, false);
973 | scope.domElement.addEventListener("wheel", onMouseWheel, false);
974 |
975 | scope.domElement.addEventListener("touchstart", onTouchStart, false);
976 | scope.domElement.addEventListener("touchend", onTouchEnd, false);
977 | scope.domElement.addEventListener("touchmove", onTouchMove, false);
978 |
979 | scope.domElement.addEventListener("keydown", onKeyDown, false);
980 |
981 | // make sure element can receive keys.
982 |
983 | if (scope.domElement.tabIndex === -1) {
984 | scope.domElement.tabIndex = 0;
985 | }
986 |
987 | // force an update at start
988 |
989 | this.update();
990 | };
991 |
992 | OrbitControls.prototype = Object.create(EventDispatcher.prototype);
993 | OrbitControls.prototype.constructor = OrbitControls;
994 |
995 | // This set of controls performs orbiting, dollying (zooming), and panning.
996 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
997 | // This is very similar to OrbitControls, another set of touch behavior
998 | //
999 | // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
1000 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
1001 | // Pan - left mouse, or arrow keys / touch: one-finger move
1002 |
1003 | var MapControls = function (object, domElement) {
1004 | OrbitControls.call(this, object, domElement);
1005 |
1006 | this.mouseButtons.LEFT = MOUSE.PAN;
1007 | this.mouseButtons.RIGHT = MOUSE.ROTATE;
1008 |
1009 | this.touches.ONE = TOUCH.PAN;
1010 | this.touches.TWO = TOUCH.DOLLY_ROTATE;
1011 | };
1012 |
1013 | MapControls.prototype = Object.create(EventDispatcher.prototype);
1014 | MapControls.prototype.constructor = MapControls;
1015 |
1016 | export { OrbitControls, MapControls };
1017 |
--------------------------------------------------------------------------------
/src/lib/Pass.js:
--------------------------------------------------------------------------------
1 | import {
2 | OrthographicCamera,
3 | PlaneGeometry,
4 | Mesh
5 | } from "./three.module.js";
6 |
7 | function Pass() {
8 |
9 | // if set to true, the pass is processed by the composer
10 | this.enabled = true;
11 |
12 | // if set to true, the pass indicates to swap read and write buffer after rendering
13 | this.needsSwap = true;
14 |
15 | // if set to true, the pass clears its buffer before rendering
16 | this.clear = false;
17 |
18 | // if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.
19 | this.renderToScreen = false;
20 |
21 | }
22 |
23 | Object.assign( Pass.prototype, {
24 |
25 | setSize: function ( /* width, height */ ) {},
26 |
27 | render: function ( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {
28 |
29 | console.error( 'THREE.Pass: .render() must be implemented in derived pass.' );
30 |
31 | }
32 |
33 | } );
34 |
35 | // Helper for passes that need to fill the viewport with a single quad.
36 |
37 | // Important: It's actually a hack to put FullScreenQuad into the Pass namespace. This is only
38 | // done to make examples/js code work. Normally, FullScreenQuad should be exported
39 | // from this module like Pass.
40 |
41 | Pass.FullScreenQuad = ( function () {
42 |
43 | var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0, 1 );
44 | var geometry = new PlaneGeometry( 2, 2 );
45 |
46 | var FullScreenQuad = function ( material ) {
47 |
48 | this._mesh = new Mesh( geometry, material );
49 |
50 | };
51 |
52 | Object.defineProperty( FullScreenQuad.prototype, 'material', {
53 |
54 | get: function () {
55 |
56 | return this._mesh.material;
57 |
58 | },
59 |
60 | set: function ( value ) {
61 |
62 | this._mesh.material = value;
63 |
64 | }
65 |
66 | } );
67 |
68 | Object.assign( FullScreenQuad.prototype, {
69 |
70 | dispose: function () {
71 |
72 | this._mesh.geometry.dispose();
73 |
74 | },
75 |
76 | render: function ( renderer ) {
77 |
78 | renderer.render( this._mesh, camera );
79 |
80 | }
81 |
82 | } );
83 |
84 | return FullScreenQuad;
85 |
86 | } )();
87 |
88 | export { Pass };
89 |
--------------------------------------------------------------------------------
/src/lib/RenderPass.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | */
4 |
5 | import { Pass } from "./Pass.js";
6 |
7 | var RenderPass = function (
8 | scene,
9 | camera,
10 | overrideMaterial,
11 | clearColor,
12 | clearAlpha
13 | ) {
14 | Pass.call(this);
15 |
16 | this.scene = scene;
17 | this.camera = camera;
18 |
19 | this.overrideMaterial = overrideMaterial;
20 |
21 | this.clearColor = clearColor;
22 | this.clearAlpha = clearAlpha !== undefined ? clearAlpha : 0;
23 |
24 | this.clear = true;
25 | this.clearDepth = false;
26 | this.needsSwap = false;
27 | };
28 |
29 | RenderPass.prototype = Object.assign(Object.create(Pass.prototype), {
30 | constructor: RenderPass,
31 |
32 | render: function (
33 | renderer,
34 | writeBuffer,
35 | readBuffer /*, deltaTime, maskActive */
36 | ) {
37 | var oldAutoClear = renderer.autoClear;
38 | renderer.autoClear = false;
39 |
40 | this.scene.overrideMaterial = this.overrideMaterial;
41 |
42 | var oldClearColor, oldClearAlpha;
43 |
44 | if (this.clearColor) {
45 | oldClearColor = renderer.getClearColor().getHex();
46 | oldClearAlpha = renderer.getClearAlpha();
47 | renderer.setClearColor(this.clearColor, this.clearAlpha);
48 | }
49 |
50 | if (this.clearDepth) {
51 | renderer.clearDepth();
52 | }
53 |
54 |
55 | renderer.setRenderTarget(this.renderToScreen ? null : readBuffer);
56 |
57 | // TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
58 | if (this.clear)
59 | renderer.clear(
60 | renderer.autoClearColor,
61 | renderer.autoClearDepth,
62 | renderer.autoClearStencil
63 | );
64 | renderer.render(this.scene, this.camera);
65 |
66 | if (this.clearColor) {
67 | renderer.setClearColor(oldClearColor, oldClearAlpha);
68 | }
69 |
70 | this.scene.overrideMaterial = null;
71 | renderer.autoClear = oldAutoClear;
72 | },
73 | });
74 |
75 | export { RenderPass };
76 |
--------------------------------------------------------------------------------
/src/lib/ShaderPass.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author alteredq / http://alteredqualia.com/
3 | */
4 |
5 | // import { ShaderMaterial, UniformsUtils } from "./three.module.js";
6 | import { ShaderMaterial, UniformsUtils } from "three";
7 | import { Pass } from "./Pass.js";
8 |
9 | var ShaderPass = function (shader, textureID) {
10 | Pass.call(this);
11 |
12 | this.textureID = textureID !== undefined ? textureID : "tDiffuse";
13 |
14 | if (shader instanceof ShaderMaterial) {
15 | this.uniforms = shader.uniforms;
16 |
17 | this.material = shader;
18 | } else if (shader) {
19 | this.uniforms = UniformsUtils.clone(shader.uniforms);
20 |
21 | this.material = new ShaderMaterial({
22 | defines: Object.assign({}, shader.defines),
23 | uniforms: this.uniforms,
24 | vertexShader: shader.vertexShader,
25 | fragmentShader: shader.fragmentShader,
26 | });
27 | }
28 |
29 | this.fsQuad = new Pass.FullScreenQuad(this.material);
30 | };
31 |
32 | ShaderPass.prototype = Object.assign(Object.create(Pass.prototype), {
33 | constructor: ShaderPass,
34 |
35 | render: function (
36 | renderer,
37 | writeBuffer,
38 | readBuffer /*, deltaTime, maskActive */
39 | ) {
40 | if (this.uniforms[this.textureID]) {
41 | this.uniforms[this.textureID].value = readBuffer.texture;
42 | }
43 |
44 | this.fsQuad.material = this.material;
45 |
46 | if (this.renderToScreen) {
47 | renderer.setRenderTarget(null);
48 | this.fsQuad.render(renderer);
49 | } else {
50 | renderer.setRenderTarget(writeBuffer);
51 | // TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600
52 | if (this.clear)
53 | renderer.clear(
54 | renderer.autoClearColor,
55 | renderer.autoClearDepth,
56 | renderer.autoClearStencil
57 | );
58 | this.fsQuad.render(renderer);
59 | }
60 | },
61 | });
62 |
63 | export { ShaderPass };
64 |
--------------------------------------------------------------------------------
/src/lib/UnrealBloomPass.js:
--------------------------------------------------------------------------------
1 | import {
2 | AdditiveBlending,
3 | Color,
4 | LinearFilter,
5 | MeshBasicMaterial,
6 | RGBAFormat,
7 | ShaderMaterial,
8 | UniformsUtils,
9 | Vector2,
10 | Vector3,
11 | WebGLRenderTarget
12 | } from "./three.module.js";
13 | import { Pass } from './Pass.js';
14 | import { CopyShader } from './CopyShader.js';
15 | import { LuminosityHighPassShader } from './LuminosityHighPassShader.js';
16 |
17 | /**
18 | * UnrealBloomPass is inspired by the bloom pass of Unreal Engine. It creates a
19 | * mip map chain of bloom textures and blurs them with different radii. Because
20 | * of the weighted combination of mips, and because larger blurs are done on
21 | * higher mips, this effect provides good quality and performance.
22 | *
23 | * Reference:
24 | * - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/
25 | */
26 | var UnrealBloomPass = function (resolution, strength, radius, threshold) {
27 |
28 | Pass.call(this);
29 |
30 | this.strength = (strength !== undefined) ? strength : 1;
31 | this.radius = radius;
32 | this.threshold = threshold;
33 | this.resolution = (resolution !== undefined) ? new Vector2(resolution.x, resolution.y) : new Vector2(256, 256);
34 |
35 | // create color only once here, reuse it later inside the render function
36 | this.clearColor = new Color(0, 0, 0);
37 |
38 | // render targets
39 | var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBAFormat };
40 | this.renderTargetsHorizontal = [];
41 | this.renderTargetsVertical = [];
42 | this.nMips = 5;
43 | var resx = Math.round(this.resolution.x / 2);
44 | var resy = Math.round(this.resolution.y / 2);
45 |
46 | this.renderTargetBright = new WebGLRenderTarget(resx, resy, pars);
47 | this.renderTargetBright.texture.name = "UnrealBloomPass.bright";
48 | this.renderTargetBright.texture.generateMipmaps = false;
49 |
50 | for (var i = 0; i < this.nMips; i++) {
51 |
52 | var renderTargetHorizonal = new WebGLRenderTarget(resx, resy, pars);
53 |
54 | renderTargetHorizonal.texture.name = "UnrealBloomPass.h" + i;
55 | renderTargetHorizonal.texture.generateMipmaps = false;
56 |
57 | this.renderTargetsHorizontal.push(renderTargetHorizonal);
58 |
59 | var renderTargetVertical = new WebGLRenderTarget(resx, resy, pars);
60 |
61 | renderTargetVertical.texture.name = "UnrealBloomPass.v" + i;
62 | renderTargetVertical.texture.generateMipmaps = false;
63 |
64 | this.renderTargetsVertical.push(renderTargetVertical);
65 |
66 | resx = Math.round(resx / 2);
67 |
68 | resy = Math.round(resy / 2);
69 |
70 | }
71 |
72 | // luminosity high pass material
73 |
74 | if (LuminosityHighPassShader === undefined)
75 | console.error("UnrealBloomPass relies on LuminosityHighPassShader");
76 |
77 | var highPassShader = LuminosityHighPassShader;
78 | this.highPassUniforms = UniformsUtils.clone(highPassShader.uniforms);
79 |
80 | this.highPassUniforms["luminosityThreshold"].value = threshold;
81 | this.highPassUniforms["smoothWidth"].value = 0.01;
82 |
83 | this.materialHighPassFilter = new ShaderMaterial({
84 | uniforms: this.highPassUniforms,
85 | vertexShader: highPassShader.vertexShader,
86 | fragmentShader: highPassShader.fragmentShader,
87 | defines: {}
88 | });
89 |
90 | // Gaussian Blur Materials
91 | this.separableBlurMaterials = [];
92 | var kernelSizeArray = [3, 5, 7, 9, 11];
93 | var resx = Math.round(this.resolution.x / 2);
94 | var resy = Math.round(this.resolution.y / 2);
95 |
96 | for (var i = 0; i < this.nMips; i++) {
97 |
98 | this.separableBlurMaterials.push(this.getSeperableBlurMaterial(kernelSizeArray[i]));
99 |
100 | this.separableBlurMaterials[i].uniforms["texSize"].value = new Vector2(resx, resy);
101 |
102 | resx = Math.round(resx / 2);
103 |
104 | resy = Math.round(resy / 2);
105 |
106 | }
107 |
108 | // Composite material
109 | this.compositeMaterial = this.getCompositeMaterial(this.nMips);
110 | this.compositeMaterial.uniforms["blurTexture1"].value = this.renderTargetsVertical[0].texture;
111 | this.compositeMaterial.uniforms["blurTexture2"].value = this.renderTargetsVertical[1].texture;
112 | this.compositeMaterial.uniforms["blurTexture3"].value = this.renderTargetsVertical[2].texture;
113 | this.compositeMaterial.uniforms["blurTexture4"].value = this.renderTargetsVertical[3].texture;
114 | this.compositeMaterial.uniforms["blurTexture5"].value = this.renderTargetsVertical[4].texture;
115 | this.compositeMaterial.uniforms["bloomStrength"].value = strength;
116 | this.compositeMaterial.uniforms["bloomRadius"].value = 0.1;
117 | this.compositeMaterial.needsUpdate = true;
118 |
119 | var bloomFactors = [1.0, 0.8, 0.6, 0.4, 0.2];
120 | this.compositeMaterial.uniforms["bloomFactors"].value = bloomFactors;
121 | this.bloomTintColors = [new Vector3(1, 1, 1), new Vector3(1, 1, 1), new Vector3(1, 1, 1),
122 | new Vector3(1, 1, 1), new Vector3(1, 1, 1)];
123 | this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
124 |
125 | // copy material
126 | if (CopyShader === undefined) {
127 |
128 | console.error("UnrealBloomPass relies on CopyShader");
129 |
130 | }
131 |
132 | var copyShader = CopyShader;
133 |
134 | this.copyUniforms = UniformsUtils.clone(copyShader.uniforms);
135 | this.copyUniforms["opacity"].value = 1.0;
136 |
137 | this.materialCopy = new ShaderMaterial({
138 | uniforms: this.copyUniforms,
139 | vertexShader: copyShader.vertexShader,
140 | fragmentShader: copyShader.fragmentShader,
141 | blending: AdditiveBlending,
142 | depthTest: false,
143 | depthWrite: false,
144 | transparent: true
145 | });
146 |
147 | this.enabled = true;
148 | this.needsSwap = false;
149 |
150 | this.oldClearColor = new Color();
151 | this.oldClearAlpha = 1;
152 |
153 | this.basic = new MeshBasicMaterial();
154 |
155 | this.fsQuad = new Pass.FullScreenQuad(null);
156 |
157 | };
158 |
159 | UnrealBloomPass.prototype = Object.assign(Object.create(Pass.prototype), {
160 |
161 | constructor: UnrealBloomPass,
162 |
163 | dispose: function () {
164 |
165 | for (var i = 0; i < this.renderTargetsHorizontal.length; i++) {
166 |
167 | this.renderTargetsHorizontal[i].dispose();
168 |
169 | }
170 |
171 | for (var i = 0; i < this.renderTargetsVertical.length; i++) {
172 |
173 | this.renderTargetsVertical[i].dispose();
174 |
175 | }
176 |
177 | this.renderTargetBright.dispose();
178 |
179 | },
180 |
181 | setSize: function (width, height) {
182 |
183 | var resx = Math.round(width / 2);
184 | var resy = Math.round(height / 2);
185 |
186 | this.renderTargetBright.setSize(resx, resy);
187 |
188 | for (var i = 0; i < this.nMips; i++) {
189 |
190 | this.renderTargetsHorizontal[i].setSize(resx, resy);
191 | this.renderTargetsVertical[i].setSize(resx, resy);
192 |
193 | this.separableBlurMaterials[i].uniforms["texSize"].value = new Vector2(resx, resy);
194 |
195 | resx = Math.round(resx / 2);
196 | resy = Math.round(resy / 2);
197 |
198 | }
199 |
200 | },
201 |
202 | render: function (renderer, writeBuffer, readBuffer, deltaTime, maskActive) {
203 |
204 | this.oldClearColor.copy(renderer.getClearColor());
205 | this.oldClearAlpha = renderer.getClearAlpha();
206 | var oldAutoClear = renderer.autoClear;
207 | renderer.autoClear = false;
208 |
209 | renderer.setClearColor(this.clearColor, 0);
210 |
211 | if (maskActive) renderer.state.buffers.stencil.setTest(false);
212 |
213 | // Render input to screen
214 |
215 | if (this.renderToScreen) {
216 |
217 | this.fsQuad.material = this.basic;
218 | this.basic.map = readBuffer.texture;
219 |
220 | renderer.setRenderTarget(null);
221 | renderer.clear();
222 | this.fsQuad.render(renderer);
223 |
224 | }
225 |
226 | // 1. Extract Bright Areas
227 |
228 | this.highPassUniforms["tDiffuse"].value = readBuffer.texture;
229 | this.highPassUniforms["luminosityThreshold"].value = this.threshold;
230 | this.fsQuad.material = this.materialHighPassFilter;
231 |
232 | renderer.setRenderTarget(this.renderTargetBright);
233 | renderer.clear();
234 | this.fsQuad.render(renderer);
235 |
236 | // 2. Blur All the mips progressively
237 |
238 | var inputRenderTarget = this.renderTargetBright;
239 |
240 | for (var i = 0; i < this.nMips; i++) {
241 |
242 | this.fsQuad.material = this.separableBlurMaterials[i];
243 |
244 | this.separableBlurMaterials[i].uniforms["colorTexture"].value = inputRenderTarget.texture;
245 | this.separableBlurMaterials[i].uniforms["direction"].value = UnrealBloomPass.BlurDirectionX;
246 | renderer.setRenderTarget(this.renderTargetsHorizontal[i]);
247 | renderer.clear();
248 | this.fsQuad.render(renderer);
249 |
250 | this.separableBlurMaterials[i].uniforms["colorTexture"].value = this.renderTargetsHorizontal[i].texture;
251 | this.separableBlurMaterials[i].uniforms["direction"].value = UnrealBloomPass.BlurDirectionY;
252 | renderer.setRenderTarget(this.renderTargetsVertical[i]);
253 | renderer.clear();
254 | this.fsQuad.render(renderer);
255 |
256 | inputRenderTarget = this.renderTargetsVertical[i];
257 |
258 | }
259 |
260 | // Composite All the mips
261 |
262 | this.fsQuad.material = this.compositeMaterial;
263 | this.compositeMaterial.uniforms["bloomStrength"].value = this.strength;
264 | this.compositeMaterial.uniforms["bloomRadius"].value = this.radius;
265 | this.compositeMaterial.uniforms["bloomTintColors"].value = this.bloomTintColors;
266 |
267 | renderer.setRenderTarget(this.renderTargetsHorizontal[0]);
268 | renderer.clear();
269 | this.fsQuad.render(renderer);
270 |
271 | // Blend it additively over the input texture
272 |
273 | this.fsQuad.material = this.materialCopy;
274 | this.copyUniforms["tDiffuse"].value = this.renderTargetsHorizontal[0].texture;
275 |
276 | if (maskActive) renderer.state.buffers.stencil.setTest(true);
277 |
278 | if (this.renderToScreen) {
279 |
280 | renderer.setRenderTarget(null);
281 | this.fsQuad.render(renderer);
282 |
283 | } else {
284 |
285 | renderer.setRenderTarget(readBuffer);
286 | this.fsQuad.render(renderer);
287 |
288 | }
289 |
290 | // Restore renderer settings
291 |
292 | renderer.setClearColor(this.oldClearColor, this.oldClearAlpha);
293 | renderer.autoClear = oldAutoClear;
294 |
295 | },
296 |
297 | getSeperableBlurMaterial: function (kernelRadius) {
298 |
299 | return new ShaderMaterial({
300 |
301 | defines: {
302 | "KERNEL_RADIUS": kernelRadius,
303 | "SIGMA": kernelRadius
304 | },
305 |
306 | uniforms: {
307 | "colorTexture": { value: null },
308 | "texSize": { value: new Vector2(0.5, 0.5) },
309 | "direction": { value: new Vector2(0.5, 0.5) }
310 | },
311 |
312 | vertexShader:
313 | "varying vec2 vUv;\n\
314 | void main() {\n\
315 | vUv = uv;\n\
316 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
317 | }",
318 |
319 | fragmentShader:
320 | "#include \
321 | varying vec2 vUv;\n\
322 | uniform sampler2D colorTexture;\n\
323 | uniform vec2 texSize;\
324 | uniform vec2 direction;\
325 | \
326 | float gaussianPdf(in float x, in float sigma) {\
327 | return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma;\
328 | }\
329 | void main() {\n\
330 | vec2 invSize = 1.0 / texSize;\
331 | float fSigma = float(SIGMA);\
332 | float weightSum = gaussianPdf(0.0, fSigma);\
333 | float alphaSum = 0.0;\
334 | vec3 diffuseSum = texture2D( colorTexture, vUv).rgb * weightSum;\
335 | for( int i = 1; i < KERNEL_RADIUS; i ++ ) {\
336 | float x = float(i);\
337 | float w = gaussianPdf(x, fSigma);\
338 | vec2 uvOffset = direction * invSize * x;\
339 | vec4 sample1 = texture2D( colorTexture, vUv + uvOffset);\
340 | vec4 sample2 = texture2D( colorTexture, vUv - uvOffset);\
341 | diffuseSum += (sample1.rgb + sample2.rgb) * w;\
342 | alphaSum += (sample1.a + sample2.a) * w;\
343 | weightSum += 2.0 * w;\
344 | }\
345 | gl_FragColor = vec4(diffuseSum/weightSum, alphaSum/weightSum);\n\
346 | }"
347 | });
348 |
349 | },
350 |
351 | getCompositeMaterial: function (nMips) {
352 |
353 | return new ShaderMaterial({
354 |
355 | defines: {
356 | "NUM_MIPS": nMips
357 | },
358 |
359 | uniforms: {
360 | "blurTexture1": { value: null },
361 | "blurTexture2": { value: null },
362 | "blurTexture3": { value: null },
363 | "blurTexture4": { value: null },
364 | "blurTexture5": { value: null },
365 | "dirtTexture": { value: null },
366 | "bloomStrength": { value: 1.0 },
367 | "bloomFactors": { value: null },
368 | "bloomTintColors": { value: null },
369 | "bloomRadius": { value: 0.0 }
370 | },
371 |
372 | vertexShader:
373 | "varying vec2 vUv;\n\
374 | void main() {\n\
375 | vUv = uv;\n\
376 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\
377 | }",
378 |
379 | fragmentShader:
380 | "varying vec2 vUv;\
381 | uniform sampler2D blurTexture1;\
382 | uniform sampler2D blurTexture2;\
383 | uniform sampler2D blurTexture3;\
384 | uniform sampler2D blurTexture4;\
385 | uniform sampler2D blurTexture5;\
386 | uniform sampler2D dirtTexture;\
387 | uniform float bloomStrength;\
388 | uniform float bloomRadius;\
389 | uniform float bloomFactors[NUM_MIPS];\
390 | uniform vec3 bloomTintColors[NUM_MIPS];\
391 | \
392 | float lerpBloomFactor(const in float factor) { \
393 | float mirrorFactor = 1.2 - factor;\
394 | return mix(factor, mirrorFactor, bloomRadius);\
395 | }\
396 | \
397 | void main() {\
398 | gl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) + \
399 | lerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) + \
400 | lerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) + \
401 | lerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) + \
402 | lerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\
403 | }"
404 | });
405 |
406 | }
407 |
408 | });
409 |
410 | UnrealBloomPass.BlurDirectionX = new Vector2(1.0, 0.0);
411 | UnrealBloomPass.BlurDirectionY = new Vector2(0.0, 1.0);
412 |
413 | export { UnrealBloomPass };
414 |
--------------------------------------------------------------------------------
/src/lib/stats.module.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | var Stats = function () {
6 |
7 | var mode = 0;
8 |
9 | var container = document.createElement( 'div' );
10 | container.style.cssText = 'position:fixed;top:0;left:0;cursor:pointer;opacity:0.9;z-index:10000';
11 | container.addEventListener( 'click', function ( event ) {
12 |
13 | event.preventDefault();
14 | showPanel( ++ mode % container.children.length );
15 |
16 | }, false );
17 |
18 | //
19 |
20 | function addPanel( panel ) {
21 |
22 | container.appendChild( panel.dom );
23 | return panel;
24 |
25 | }
26 |
27 | function showPanel( id ) {
28 |
29 | for ( var i = 0; i < container.children.length; i ++ ) {
30 |
31 | container.children[ i ].style.display = i === id ? 'block' : 'none';
32 |
33 | }
34 |
35 | mode = id;
36 |
37 | }
38 |
39 | //
40 |
41 | var beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0;
42 |
43 | var fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) );
44 | var msPanel = addPanel( new Stats.Panel( 'MS', '#0f0', '#020' ) );
45 |
46 | if ( self.performance && self.performance.memory ) {
47 |
48 | var memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) );
49 |
50 | }
51 |
52 | showPanel( 0 );
53 |
54 | return {
55 |
56 | REVISION: 16,
57 |
58 | dom: container,
59 |
60 | addPanel: addPanel,
61 | showPanel: showPanel,
62 |
63 | begin: function () {
64 |
65 | beginTime = ( performance || Date ).now();
66 |
67 | },
68 |
69 | end: function () {
70 |
71 | frames ++;
72 |
73 | var time = ( performance || Date ).now();
74 |
75 | msPanel.update( time - beginTime, 200 );
76 |
77 | if ( time >= prevTime + 1000 ) {
78 |
79 | fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 );
80 |
81 | prevTime = time;
82 | frames = 0;
83 |
84 | if ( memPanel ) {
85 |
86 | var memory = performance.memory;
87 | memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 );
88 |
89 | }
90 |
91 | }
92 |
93 | return time;
94 |
95 | },
96 |
97 | update: function () {
98 |
99 | beginTime = this.end();
100 |
101 | },
102 |
103 | // Backwards Compatibility
104 |
105 | domElement: container,
106 | setMode: showPanel
107 |
108 | };
109 |
110 | };
111 |
112 | Stats.Panel = function ( name, fg, bg ) {
113 |
114 | var min = Infinity, max = 0, round = Math.round;
115 | var PR = round( window.devicePixelRatio || 1 );
116 |
117 | var WIDTH = 80 * PR, HEIGHT = 48 * PR,
118 | TEXT_X = 3 * PR, TEXT_Y = 2 * PR,
119 | GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR,
120 | GRAPH_WIDTH = 74 * PR, GRAPH_HEIGHT = 30 * PR;
121 |
122 | var canvas = document.createElement( 'canvas' );
123 | canvas.width = WIDTH;
124 | canvas.height = HEIGHT;
125 | canvas.style.cssText = 'width:80px;height:48px';
126 |
127 | var context = canvas.getContext( '2d' );
128 | context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif';
129 | context.textBaseline = 'top';
130 |
131 | context.fillStyle = bg;
132 | context.fillRect( 0, 0, WIDTH, HEIGHT );
133 |
134 | context.fillStyle = fg;
135 | context.fillText( name, TEXT_X, TEXT_Y );
136 | context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
137 |
138 | context.fillStyle = bg;
139 | context.globalAlpha = 0.9;
140 | context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT );
141 |
142 | return {
143 |
144 | dom: canvas,
145 |
146 | update: function ( value, maxValue ) {
147 |
148 | min = Math.min( min, value );
149 | max = Math.max( max, value );
150 |
151 | context.fillStyle = bg;
152 | context.globalAlpha = 1;
153 | context.fillRect( 0, 0, WIDTH, GRAPH_Y );
154 | context.fillStyle = fg;
155 | context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y );
156 |
157 | context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT );
158 |
159 | context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT );
160 |
161 | context.fillStyle = bg;
162 | context.globalAlpha = 0.9;
163 | context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) );
164 |
165 | }
166 |
167 | };
168 |
169 | };
170 |
171 | export default Stats;
172 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import App from "./App.vue";
3 | import router from "./router";
4 |
5 | Vue.config.productionTip = false;
6 |
7 | new Vue({
8 | router,
9 | render: h => h(App)
10 | }).$mount("#app");
11 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from "vue";
2 | import VueRouter from "vue-router";
3 | // import Home from "../views/Home.vue";
4 |
5 | Vue.use(VueRouter);
6 |
7 | const routes = [
8 | // {
9 | // path: "/",
10 | // name: "Home",
11 | // component: Home
12 | // },
13 | // {
14 | // path: "/about",
15 | // name: "About",
16 | // // route level code-splitting
17 | // // this generates a separate chunk (about.[hash].js) for this route
18 | // // which is lazy-loaded when the route is visited.
19 | // component: () =>
20 | // import(/* webpackChunkName: "about" */ "../views/About.vue")
21 | // }
22 | ];
23 |
24 | const router = new VueRouter({
25 | mode: "history",
26 | base: process.env.BASE_URL,
27 | routes
28 | });
29 |
30 | export default router;
31 |
--------------------------------------------------------------------------------
/static/audio.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Hocoa/AudioPlayer/97baf14994f6423ada381249c3b2682ba7827c71/static/audio.mp3
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 |
3 | module.exports = {
4 | // 部署生产环境和开发环境下的URL。
5 | // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
6 | // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
7 | publicPath: "./",
8 | // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
9 | outputDir: "dist",
10 | // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
11 | assetsDir: "static",
12 | // 是否开启eslint保存检测,有效值:ture | false | 'error'
13 | lintOnSave: process.env.NODE_ENV === "development",
14 | // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
15 | productionSourceMap: false
16 | };
17 |
--------------------------------------------------------------------------------