diff --git a/build/js/0.app.js b/build/js/0.app.js
index 09b954a..ebfd16f 100644
--- a/build/js/0.app.js
+++ b/build/js/0.app.js
@@ -1 +1 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[0],[,,,,function(e,t){e.exports=function(O){var e=O.MOUSE;function A(e){this.object=e,this.target=new O.Vector3,this.minDistance=0,this.maxDistance=1/0,this.minZoom=0,this.maxZoom=1/0,this.minPolarAngle=0,this.maxPolarAngle=Math.PI,this.minAzimuthAngle=-1/0,this.maxAzimuthAngle=1/0,this.enableDamping=!1,this.dampingFactor=.25;var n,o,a,i,r,s,l,c,h,d=this,u=1e-6,m=0,g=0,p=1,f=new O.Vector3,b=!1;this.getPolarAngle=function(){return o},this.getAzimuthalAngle=function(){return n},this.rotateLeft=function(e){g-=e},this.rotateUp=function(e){m-=e},this.panLeft=(a=new O.Vector3,function(e){var t=this.object.matrix.elements;a.set(t[0],t[1],t[2]),a.multiplyScalar(-e),f.add(a)}),this.panUp=(i=new O.Vector3,function(e){var t=this.object.matrix.elements;i.set(t[4],t[5],t[6]),i.multiplyScalar(e),f.add(i)}),this.pan=function(e,t,n,o){if(d.object instanceof O.PerspectiveCamera){var a=d.object.position.clone().sub(d.target).length();a*=Math.tan(d.object.fov/2*Math.PI/180),d.panLeft(2*e*a/o),d.panUp(2*t*a/o)}else d.object instanceof O.OrthographicCamera?(d.panLeft(e*(d.object.right-d.object.left)/n),d.panUp(t*(d.object.top-d.object.bottom)/o)):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.")},this.dollyIn=function(e){d.object instanceof O.PerspectiveCamera?p/=e:d.object instanceof O.OrthographicCamera?(d.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom*e)),d.object.updateProjectionMatrix(),b=!0):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")},this.dollyOut=function(e){d.object instanceof O.PerspectiveCamera?p*=e:d.object instanceof O.OrthographicCamera?(d.object.zoom=Math.max(this.minZoom,Math.min(this.maxZoom,this.object.zoom/e)),d.object.updateProjectionMatrix(),b=!0):console.warn("WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.")},this.update=(r=new O.Vector3,s=(new O.Quaternion).setFromUnitVectors(e.up,new O.Vector3(0,1,0)),l=s.clone().inverse(),c=new O.Vector3,h=new O.Quaternion,function(){var e=this.object.position;r.copy(e).sub(this.target),r.applyQuaternion(s),n=Math.atan2(r.x,r.z),o=Math.atan2(Math.sqrt(r.x*r.x+r.z*r.z),r.y),n+=g,o+=m,n=Math.max(this.minAzimuthAngle,Math.min(this.maxAzimuthAngle,n)),o=Math.max(this.minPolarAngle,Math.min(this.maxPolarAngle,o)),o=Math.max(u,Math.min(Math.PI-u,o));var t=r.length()*p;return t=Math.max(this.minDistance,Math.min(this.maxDistance,t)),this.target.add(f),r.x=t*Math.sin(o)*Math.sin(n),r.y=t*Math.cos(o),r.z=t*Math.sin(o)*Math.cos(n),r.applyQuaternion(l),e.copy(this.target).add(r),this.object.lookAt(this.target),!0===this.enableDamping?(g*=1-this.dampingFactor,m*=1-this.dampingFactor):m=g=0,p=1,f.set(0,0,0),!(!(b||c.distanceToSquared(this.object.position)>u||8*(1-h.dot(this.object.quaternion))>u)||(c.copy(this.object.position),h.copy(this.object.quaternion),b=!1))})}function t(e,t){var i=new A(e);this.domElement=void 0!==t?t:document,Object.defineProperty(this,"constraint",{get:function(){return i}}),this.getPolarAngle=function(){return i.getPolarAngle()},this.getAzimuthalAngle=function(){return i.getAzimuthalAngle()},this.enabled=!0,this.center=this.target,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.keyPanSpeed=7,this.autoRotate=!1,this.autoRotateSpeed=2,this.enableKeys=!0,this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40},this.mouseButtons={ORBIT:O.MOUSE.LEFT,ZOOM:O.MOUSE.MIDDLE,PAN:O.MOUSE.RIGHT};var r=this,s=new O.Vector2,l=new O.Vector2,c=new O.Vector2,h=new O.Vector2,d=new O.Vector2,u=new O.Vector2,m=new O.Vector2,g=new O.Vector2,p=new O.Vector2,f={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY:4,TOUCH_PAN:5},b=f.NONE;this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom;var n={type:"change"},a={type:"start"},o={type:"end"};function v(e,t){var n=r.domElement===document?r.domElement.body:r.domElement;i.pan(e,t,n.clientWidth,n.clientHeight)}function w(){return Math.pow(.95,r.zoomSpeed)}function y(e){if(!1!==r.enabled){if(e.preventDefault(),e.button===r.mouseButtons.ORBIT){if(!1===r.enableRotate)return;b=f.ROTATE,s.set(e.clientX,e.clientY)}else if(e.button===r.mouseButtons.ZOOM){if(!1===r.enableZoom)return;b=f.DOLLY,m.set(e.clientX,e.clientY)}else if(e.button===r.mouseButtons.PAN){if(!1===r.enablePan)return;b=f.PAN,h.set(e.clientX,e.clientY)}b!==f.NONE&&(document.addEventListener("mousemove",L,!1),document.addEventListener("mouseup",C,!1),r.dispatchEvent(a))}}function L(e){if(!1!==r.enabled){e.preventDefault();var t=r.domElement===document?r.domElement.body:r.domElement;if(b===f.ROTATE){if(!1===r.enableRotate)return;l.set(e.clientX,e.clientY),c.subVectors(l,s),i.rotateLeft(2*Math.PI*c.x/t.clientWidth*r.rotateSpeed),i.rotateUp(2*Math.PI*c.y/t.clientHeight*r.rotateSpeed),s.copy(l)}else if(b===f.DOLLY){if(!1===r.enableZoom)return;g.set(e.clientX,e.clientY),p.subVectors(g,m),0
WebGL.
','Find out how to get it here.'].join("\n"):['Your browser does not seem to support WebGL.
','Find out how to get it here.'].join("\n")),e},addGetWebGLMessage:function(e){var t,n,o;t=void 0!==(e=e||{}).parent?e.parent:document.body,n=void 0!==e.id?e.id:"oldie",(o=this.getWebGLErrorMessage()).id=n,t.appendChild(o)}},s=n(0);function r(e,t){for(var n=0;nu||8*(1-h.dot(this.object.quaternion))>u)||(c.copy(this.object.position),h.copy(this.object.quaternion),b=!1))})}function e(e,t){var i=new A(e);this.domElement=void 0!==t?t:document,Object.defineProperty(this,"constraint",{get:function(){return i}}),this.getPolarAngle=function(){return i.getPolarAngle()},this.getAzimuthalAngle=function(){return i.getAzimuthalAngle()},this.enabled=!0,this.center=this.target,this.enableZoom=!0,this.zoomSpeed=1,this.enableRotate=!0,this.rotateSpeed=1,this.enablePan=!0,this.keyPanSpeed=7,this.autoRotate=!1,this.autoRotateSpeed=2,this.enableKeys=!0,this.keys={LEFT:37,UP:38,RIGHT:39,BOTTOM:40},this.mouseButtons={ORBIT:O.MOUSE.LEFT,ZOOM:O.MOUSE.MIDDLE,PAN:O.MOUSE.RIGHT};var r=this,s=new O.Vector2,l=new O.Vector2,c=new O.Vector2,h=new O.Vector2,d=new O.Vector2,u=new O.Vector2,m=new O.Vector2,g=new O.Vector2,p=new O.Vector2,f={NONE:-1,ROTATE:0,DOLLY:1,PAN:2,TOUCH_ROTATE:3,TOUCH_DOLLY:4,TOUCH_PAN:5},b=f.NONE;this.target0=this.target.clone(),this.position0=this.object.position.clone(),this.zoom0=this.object.zoom;var n={type:"change"},a={type:"start"},o={type:"end"};function v(e,t){var n=r.domElement===document?r.domElement.body:r.domElement;i.pan(e,t,n.clientWidth,n.clientHeight)}function w(){return Math.pow(.95,r.zoomSpeed)}function y(e){if(!1!==r.enabled){if(e.preventDefault(),e.button===r.mouseButtons.ORBIT){if(!1===r.enableRotate)return;b=f.ROTATE,s.set(e.clientX,e.clientY)}else if(e.button===r.mouseButtons.ZOOM){if(!1===r.enableZoom)return;b=f.DOLLY,m.set(e.clientX,e.clientY)}else if(e.button===r.mouseButtons.PAN){if(!1===r.enablePan)return;b=f.PAN,h.set(e.clientX,e.clientY)}b!==f.NONE&&(document.addEventListener("mousemove",L,!1),document.addEventListener("mouseup",C,!1),r.dispatchEvent(a))}}function L(e){if(!1!==r.enabled){e.preventDefault();var t=r.domElement===document?r.domElement.body:r.domElement;if(b===f.ROTATE){if(!1===r.enableRotate)return;l.set(e.clientX,e.clientY),c.subVectors(l,s),i.rotateLeft(2*Math.PI*c.x/t.clientWidth*r.rotateSpeed),i.rotateUp(2*Math.PI*c.y/t.clientHeight*r.rotateSpeed),s.copy(l)}else if(b===f.DOLLY){if(!1===r.enableZoom)return;g.set(e.clientX,e.clientY),p.subVectors(g,m),0WebGL.
','Find out how to get it here.'].join("\n"):['Your browser does not seem to support WebGL.
','Find out how to get it here.'].join("\n")),e},addGetWebGLMessage:function(e){var t,n,o;t=void 0!==(e=e||{}).parent?e.parent:document.body,n=void 0!==e.id?e.id:"oldie",(o=this.getWebGLErrorMessage()).id=n,t.appendChild(o)}},r=n(0);function s(e,t){for(var n=0;n EPS\n // using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n if ( zoomChanged ||\n lastPosition.distanceToSquared( this.object.position ) > EPS ||\n 8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) {\n\n lastPosition.copy( this.object.position );\n lastQuaternion.copy( this.object.quaternion );\n zoomChanged = false;\n\n return true;\n\n }\n\n return false;\n\n };\n\n }();\n\n };\n\n\n // This set of controls performs orbiting, dollying (zooming), and panning. It maintains\n // the \"up\" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is\n // supported.\n //\n // Orbit - left mouse / touch: one finger move\n // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish\n // Pan - right mouse, or arrow keys / touch: three finter swipe\n\n function OrbitControls ( object, domElement ) {\n\n var constraint = new OrbitConstraint( object );\n\n this.domElement = ( domElement !== undefined ) ? domElement : document;\n\n // API\n\n Object.defineProperty( this, 'constraint', {\n\n get: function() {\n\n return constraint;\n\n }\n\n } );\n\n this.getPolarAngle = function () {\n\n return constraint.getPolarAngle();\n\n };\n\n this.getAzimuthalAngle = function () {\n\n return constraint.getAzimuthalAngle();\n\n };\n\n // Set to false to disable this control\n this.enabled = true;\n\n // center is old, deprecated; use \"target\" instead\n this.center = this.target;\n\n // This option actually enables dollying in and out; left as \"zoom\" for\n // backwards compatibility.\n // Set to false to disable zooming\n this.enableZoom = true;\n this.zoomSpeed = 1.0;\n\n // Set to false to disable rotating\n this.enableRotate = true;\n this.rotateSpeed = 1.0;\n\n // Set to false to disable panning\n this.enablePan = true;\n this.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\n // Set to true to automatically rotate around the target\n // If auto-rotate is enabled, you must call controls.update() in your animation loop\n this.autoRotate = false;\n this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60\n\n // Set to false to disable use of the keys\n this.enableKeys = true;\n\n // The four arrow keys\n this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };\n\n // Mouse buttons\n this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };\n\n ////////////\n // internals\n\n var scope = this;\n\n var rotateStart = new THREE.Vector2();\n var rotateEnd = new THREE.Vector2();\n var rotateDelta = new THREE.Vector2();\n\n var panStart = new THREE.Vector2();\n var panEnd = new THREE.Vector2();\n var panDelta = new THREE.Vector2();\n\n var dollyStart = new THREE.Vector2();\n var dollyEnd = new THREE.Vector2();\n var dollyDelta = new THREE.Vector2();\n\n var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };\n\n var state = STATE.NONE;\n\n // for reset\n\n this.target0 = this.target.clone();\n this.position0 = this.object.position.clone();\n this.zoom0 = this.object.zoom;\n\n // events\n\n var changeEvent = { type: 'change' };\n var startEvent = { type: 'start' };\n var endEvent = { type: 'end' };\n\n // pass in x,y of change desired in pixel space,\n // right and down are positive\n function pan( deltaX, deltaY ) {\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight );\n\n }\n\n this.update = function () {\n\n if ( this.autoRotate && state === STATE.NONE ) {\n\n constraint.rotateLeft( getAutoRotationAngle() );\n\n }\n\n if ( constraint.update() === true ) {\n\n this.dispatchEvent( changeEvent );\n\n }\n\n };\n\n this.reset = function () {\n\n state = STATE.NONE;\n\n this.target.copy( this.target0 );\n this.object.position.copy( this.position0 );\n this.object.zoom = this.zoom0;\n\n this.object.updateProjectionMatrix();\n this.dispatchEvent( changeEvent );\n\n this.update();\n\n };\n\n function getAutoRotationAngle() {\n\n return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n }\n\n function getZoomScale() {\n\n return Math.pow( 0.95, scope.zoomSpeed );\n\n }\n\n function onMouseDown( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n\n if ( event.button === scope.mouseButtons.ORBIT ) {\n\n if ( scope.enableRotate === false ) return;\n\n state = STATE.ROTATE;\n\n rotateStart.set( event.clientX, event.clientY );\n\n } else if ( event.button === scope.mouseButtons.ZOOM ) {\n\n if ( scope.enableZoom === false ) return;\n\n state = STATE.DOLLY;\n\n dollyStart.set( event.clientX, event.clientY );\n\n } else if ( event.button === scope.mouseButtons.PAN ) {\n\n if ( scope.enablePan === false ) return;\n\n state = STATE.PAN;\n\n panStart.set( event.clientX, event.clientY );\n\n }\n\n if ( state !== STATE.NONE ) {\n\n document.addEventListener( 'mousemove', onMouseMove, false );\n document.addEventListener( 'mouseup', onMouseUp, false );\n scope.dispatchEvent( startEvent );\n\n }\n\n }\n\n function onMouseMove( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n if ( state === STATE.ROTATE ) {\n\n if ( scope.enableRotate === false ) return;\n\n rotateEnd.set( event.clientX, event.clientY );\n rotateDelta.subVectors( rotateEnd, rotateStart );\n\n // rotating across whole screen goes 360 degrees around\n constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n // rotating up and down along whole screen attempts to go 360, but limited to 180\n constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n rotateStart.copy( rotateEnd );\n\n } else if ( state === STATE.DOLLY ) {\n\n if ( scope.enableZoom === false ) return;\n\n dollyEnd.set( event.clientX, event.clientY );\n dollyDelta.subVectors( dollyEnd, dollyStart );\n\n if ( dollyDelta.y > 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n } else if ( dollyDelta.y < 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n }\n\n dollyStart.copy( dollyEnd );\n\n } else if ( state === STATE.PAN ) {\n\n if ( scope.enablePan === false ) return;\n\n panEnd.set( event.clientX, event.clientY );\n panDelta.subVectors( panEnd, panStart );\n\n pan( panDelta.x, panDelta.y );\n\n panStart.copy( panEnd );\n\n }\n\n if ( state !== STATE.NONE ) scope.update();\n\n }\n\n function onMouseUp( /* event */ ) {\n\n if ( scope.enabled === false ) return;\n\n document.removeEventListener( 'mousemove', onMouseMove, false );\n document.removeEventListener( 'mouseup', onMouseUp, false );\n scope.dispatchEvent( endEvent );\n state = STATE.NONE;\n\n }\n\n function onMouseWheel( event ) {\n\n if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n var delta = 0;\n\n if ( event.wheelDelta !== undefined ) {\n\n // WebKit / Opera / Explorer 9\n\n delta = event.wheelDelta;\n\n } else if ( event.detail !== undefined ) {\n\n // Firefox\n\n delta = - event.detail;\n\n }\n\n if ( delta > 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n } else if ( delta < 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n }\n\n scope.update();\n scope.dispatchEvent( startEvent );\n scope.dispatchEvent( endEvent );\n\n }\n\n function onKeyDown( event ) {\n\n if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;\n\n switch ( event.keyCode ) {\n\n case scope.keys.UP:\n pan( 0, scope.keyPanSpeed );\n scope.update();\n break;\n\n case scope.keys.BOTTOM:\n pan( 0, - scope.keyPanSpeed );\n scope.update();\n break;\n\n case scope.keys.LEFT:\n pan( scope.keyPanSpeed, 0 );\n scope.update();\n break;\n\n case scope.keys.RIGHT:\n pan( - scope.keyPanSpeed, 0 );\n scope.update();\n break;\n\n }\n\n }\n\n function touchstart( event ) {\n\n if ( scope.enabled === false ) return;\n\n switch ( event.touches.length ) {\n\n case 1:\t// one-fingered touch: rotate\n\n if ( scope.enableRotate === false ) return;\n\n state = STATE.TOUCH_ROTATE;\n\n rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n break;\n\n case 2:\t// two-fingered touch: dolly\n\n if ( scope.enableZoom === false ) return;\n\n state = STATE.TOUCH_DOLLY;\n\n var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n var distance = Math.sqrt( dx * dx + dy * dy );\n dollyStart.set( 0, distance );\n break;\n\n case 3: // three-fingered touch: pan\n\n if ( scope.enablePan === false ) return;\n\n state = STATE.TOUCH_PAN;\n\n panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n break;\n\n default:\n\n state = STATE.NONE;\n\n }\n\n if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );\n\n }\n\n function touchmove( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n switch ( event.touches.length ) {\n\n case 1: // one-fingered touch: rotate\n\n if ( scope.enableRotate === false ) return;\n if ( state !== STATE.TOUCH_ROTATE ) return;\n\n rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n rotateDelta.subVectors( rotateEnd, rotateStart );\n\n // rotating across whole screen goes 360 degrees around\n constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n // rotating up and down along whole screen attempts to go 360, but limited to 180\n constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n rotateStart.copy( rotateEnd );\n\n scope.update();\n break;\n\n case 2: // two-fingered touch: dolly\n\n if ( scope.enableZoom === false ) return;\n if ( state !== STATE.TOUCH_DOLLY ) return;\n\n var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n var distance = Math.sqrt( dx * dx + dy * dy );\n\n dollyEnd.set( 0, distance );\n dollyDelta.subVectors( dollyEnd, dollyStart );\n\n if ( dollyDelta.y > 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n } else if ( dollyDelta.y < 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n }\n\n dollyStart.copy( dollyEnd );\n\n scope.update();\n break;\n\n case 3: // three-fingered touch: pan\n\n if ( scope.enablePan === false ) return;\n if ( state !== STATE.TOUCH_PAN ) return;\n\n panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n panDelta.subVectors( panEnd, panStart );\n\n pan( panDelta.x, panDelta.y );\n\n panStart.copy( panEnd );\n\n scope.update();\n break;\n\n default:\n\n state = STATE.NONE;\n\n }\n\n }\n\n function touchend( /* event */ ) {\n\n if ( scope.enabled === false ) return;\n\n scope.dispatchEvent( endEvent );\n state = STATE.NONE;\n\n }\n\n function contextmenu( event ) {\n\n event.preventDefault();\n\n }\n\n this.dispose = function() {\n\n this.domElement.removeEventListener( 'contextmenu', contextmenu, false );\n this.domElement.removeEventListener( 'mousedown', onMouseDown, false );\n this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );\n this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox\n\n this.domElement.removeEventListener( 'touchstart', touchstart, false );\n this.domElement.removeEventListener( 'touchend', touchend, false );\n this.domElement.removeEventListener( 'touchmove', touchmove, false );\n\n document.removeEventListener( 'mousemove', onMouseMove, false );\n document.removeEventListener( 'mouseup', onMouseUp, false );\n\n window.removeEventListener( 'keydown', onKeyDown, false );\n\n }\n\n this.domElement.addEventListener( 'contextmenu', contextmenu, false );\n\n this.domElement.addEventListener( 'mousedown', onMouseDown, false );\n this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );\n this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox\n\n this.domElement.addEventListener( 'touchstart', touchstart, false );\n this.domElement.addEventListener( 'touchend', touchend, false );\n this.domElement.addEventListener( 'touchmove', touchmove, false );\n\n window.addEventListener( 'keydown', onKeyDown, false );\n\n // force an update at start\n this.update();\n\n };\n\n OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );\n OrbitControls.prototype.constructor = OrbitControls;\n\n Object.defineProperties( OrbitControls.prototype, {\n\n object: {\n\n get: function () {\n\n return this.constraint.object;\n\n }\n\n },\n\n target: {\n\n get: function () {\n\n return this.constraint.target;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' );\n this.constraint.target.copy( value );\n\n }\n\n },\n\n minDistance : {\n\n get: function () {\n\n return this.constraint.minDistance;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minDistance = value;\n\n }\n\n },\n\n maxDistance : {\n\n get: function () {\n\n return this.constraint.maxDistance;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxDistance = value;\n\n }\n\n },\n\n minZoom : {\n\n get: function () {\n\n return this.constraint.minZoom;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minZoom = value;\n\n }\n\n },\n\n maxZoom : {\n\n get: function () {\n\n return this.constraint.maxZoom;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxZoom = value;\n\n }\n\n },\n\n minPolarAngle : {\n\n get: function () {\n\n return this.constraint.minPolarAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minPolarAngle = value;\n\n }\n\n },\n\n maxPolarAngle : {\n\n get: function () {\n\n return this.constraint.maxPolarAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxPolarAngle = value;\n\n }\n\n },\n\n minAzimuthAngle : {\n\n get: function () {\n\n return this.constraint.minAzimuthAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minAzimuthAngle = value;\n\n }\n\n },\n\n maxAzimuthAngle : {\n\n get: function () {\n\n return this.constraint.maxAzimuthAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxAzimuthAngle = value;\n\n }\n\n },\n\n enableDamping : {\n\n get: function () {\n\n return this.constraint.enableDamping;\n\n },\n\n set: function ( value ) {\n\n this.constraint.enableDamping = value;\n\n }\n\n },\n\n dampingFactor : {\n\n get: function () {\n\n return this.constraint.dampingFactor;\n\n },\n\n set: function ( value ) {\n\n this.constraint.dampingFactor = value;\n\n }\n\n },\n\n // backward compatibility\n\n noZoom: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n return ! this.enableZoom;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n this.enableZoom = ! value;\n\n }\n\n },\n\n noRotate: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n return ! this.enableRotate;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n this.enableRotate = ! value;\n\n }\n\n },\n\n noPan: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n return ! this.enablePan;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n this.enablePan = ! value;\n\n }\n\n },\n\n noKeys: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n return ! this.enableKeys;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n this.enableKeys = ! value;\n\n }\n\n },\n\n staticMoving : {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n return ! this.constraint.enableDamping;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n this.constraint.enableDamping = ! value;\n\n }\n\n },\n\n dynamicDampingFactor : {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n return this.constraint.dampingFactor;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n this.constraint.dampingFactor = value;\n\n }\n\n }\n\n } );\n\n return OrbitControls;\n}\n","import TWEEN from 'tween.js';\n\n// This object contains the state of the app\nexport default {\n isDev: false,\n isShowingStats: true,\n isLoaded: false,\n isTweening: false,\n isRotating: true,\n isMouseMoving: false,\n isMouseOver: false,\n maxAnisotropy: 1,\n dpr: 1,\n easing: TWEEN.Easing.Quadratic.InOut,\n duration: 500,\n model: {\n path: './assets/models/Teapot.json',\n scale: 20\n },\n texture: {\n path: './assets/textures/',\n imageFiles: [\n {name: 'UV', image: 'UV_Grid_Sm.jpg'}\n ]\n },\n mesh: {\n enableHelper: false,\n wireframe: false,\n translucent: false,\n material: {\n color: 0xffffff,\n emissive: 0xffffff\n }\n },\n fog: {\n color: 0xffffff,\n near: 0.0008\n },\n camera: {\n fov: 40,\n near: 2,\n far: 1000,\n aspect: 1,\n posX: 0,\n posY: 30,\n posZ: 40\n },\n controls: {\n autoRotate: true,\n autoRotateSpeed: -0.5,\n rotateSpeed: 0.5,\n zoomSpeed: 0.8,\n minDistance: 200,\n maxDistance: 600,\n minPolarAngle: Math.PI / 5,\n maxPolarAngle: Math.PI / 2,\n minAzimuthAngle: -Infinity,\n maxAzimuthAngle: Infinity,\n enableDamping: true,\n dampingFactor: 0.5,\n enableZoom: true,\n target: {\n x: 0,\n y: 0,\n z: 0\n }\n },\n ambientLight: {\n enabled: true,\n color: 0x141414\n },\n directionalLight: {\n enabled: true,\n color: 0xf0f0f0,\n intensity: 0.4,\n x: -75,\n y: 280,\n z: 150\n },\n shadow: {\n enabled: true,\n helperEnabled: true,\n bias: 0,\n mapWidth: 2048,\n mapHeight: 2048,\n near: 250,\n far: 400,\n top: 100,\n right: 100,\n bottom: -100,\n left: -100\n },\n pointLight: {\n enabled: true,\n color: 0xffffff,\n intensity: 0.34,\n distance: 115,\n x: 0,\n y: 0,\n z: 0\n },\n hemiLight: {\n enabled: true,\n color: 0xc8c8c8,\n groundColor: 0xffffff,\n intensity: 0.55,\n x: 0,\n y: 0,\n z: 0\n }\n};\n","/**\n * @author alteredq / http://alteredqualia.com/\n * @author mr.doob / http://mrdoob.com/\n */\n\nexport default {\n canvas: !!window.CanvasRenderingContext2D,\n webgl: (function() {\n try {\n var canvas = document.createElement('canvas');\n\n return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));\n } catch(e) {\n return false;\n }\n })(),\n\n workers: !!window.Worker,\n fileapi: window.File && window.FileReader && window.FileList && window.Blob,\n\n getWebGLErrorMessage: function() {\n var element = document.createElement('div');\n element.id = 'webgl-error-message';\n element.style.fontFamily = 'monospace';\n element.style.fontSize = '13px';\n element.style.fontWeight = 'normal';\n element.style.textAlign = 'center';\n element.style.background = '#fff';\n element.style.color = '#000';\n element.style.padding = '1.5em';\n element.style.width = '400px';\n element.style.margin = '5em auto 0';\n\n if(!this.webgl) {\n element.innerHTML = window.WebGLRenderingContext ? [\n 'Your graphics card does not seem to support WebGL.
',\n 'Find out how to get it here.'\n ].join('\\n') : [\n 'Your browser does not seem to support WebGL.
',\n 'Find out how to get it here.'\n ].join('\\n');\n }\n\n return element;\n },\n\n addGetWebGLMessage: function(parameters) {\n var parent, id, element;\n\n parameters = parameters || {};\n\n parent = parameters.parent !== undefined ? parameters.parent : document.body;\n id = parameters.id !== undefined ? parameters.id : 'oldie';\n\n element = this.getWebGLErrorMessage();\n element.id = id;\n\n parent.appendChild(element);\n }\n};\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// Main webGL renderer class\nexport default class Renderer {\n constructor(scene, container) {\n // Properties\n this.scene = scene;\n this.container = container;\n\n // Create WebGL renderer and set its antialias\n this.threeRenderer = new THREE.WebGLRenderer({antialias: true});\n\n // Set clear color to fog to enable fog or to hex color for no fog\n this.threeRenderer.setClearColor(scene.fog.color);\n this.threeRenderer.setPixelRatio(window.devicePixelRatio); // For retina\n\n // Appends canvas\n container.appendChild(this.threeRenderer.domElement);\n\n // Shadow map options\n this.threeRenderer.shadowMap.enabled = true;\n this.threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;\n\n // Get anisotropy for textures\n Config.maxAnisotropy = this.threeRenderer.getMaxAnisotropy();\n\n // Initial size update set to canvas container\n this.updateSize();\n\n // Listeners\n document.addEventListener('DOMContentLoaded', () => this.updateSize(), false);\n window.addEventListener('resize', () => this.updateSize(), false);\n }\n\n updateSize() {\n this.threeRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight);\n }\n\n render(scene, camera) {\n // Renders scene to canvas target\n this.threeRenderer.render(scene, camera);\n }\n}\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// Class that creates and updates the main camera\nexport default class Camera {\n constructor(renderer) {\n const width = renderer.domElement.width;\n const height = renderer.domElement.height;\n\n // Create and position a Perspective Camera\n this.threeCamera = new THREE.PerspectiveCamera(Config.camera.fov, width / height, Config.camera.near, Config.camera.far);\n this.threeCamera.position.set(Config.camera.posX, Config.camera.posY, Config.camera.posZ);\n\n // Initial sizing\n this.updateSize(renderer);\n \n // Listeners\n window.addEventListener('resize', () => this.updateSize(renderer), false);\n }\n\n updateSize(renderer) {\n // Update camera aspect ratio with window aspect ratio\n this.threeCamera.aspect = renderer.domElement.width / renderer.domElement.height;\n\n // Always call updateProjectionMatrix on camera change\n this.threeCamera.updateProjectionMatrix();\n }\n}\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// Sets up and places all lights in scene\nexport default class Light {\n constructor(scene) {\n this.scene = scene;\n\n this.init();\n }\n\n init() {\n // Ambient\n this.ambientLight = new THREE.AmbientLight(Config.ambientLight.color);\n this.ambientLight.visible = Config.ambientLight.enabled;\n\n // Point light\n this.pointLight = new THREE.PointLight(Config.pointLight.color, Config.pointLight.intensity, Config.pointLight.distance);\n this.pointLight.position.set(Config.pointLight.x, Config.pointLight.y, Config.pointLight.z);\n this.pointLight.visible = Config.pointLight.enabled;\n\n // Directional light\n this.directionalLight = new THREE.DirectionalLight(Config.directionalLight.color, Config.directionalLight.intensity);\n this.directionalLight.position.set(Config.directionalLight.x, Config.directionalLight.y, Config.directionalLight.z);\n this.directionalLight.visible = Config.directionalLight.enabled;\n\n // Shadow map\n this.directionalLight.castShadow = Config.shadow.enabled;\n this.directionalLight.shadow.bias = Config.shadow.bias;\n this.directionalLight.shadow.camera.near = Config.shadow.near;\n this.directionalLight.shadow.camera.far = Config.shadow.far;\n this.directionalLight.shadow.camera.left = Config.shadow.left;\n this.directionalLight.shadow.camera.right = Config.shadow.right;\n this.directionalLight.shadow.camera.top = Config.shadow.top;\n this.directionalLight.shadow.camera.bottom = Config.shadow.bottom;\n this.directionalLight.shadow.mapSize.width = Config.shadow.mapWidth;\n this.directionalLight.shadow.mapSize.height = Config.shadow.mapHeight;\n\n // Shadow camera helper\n this.directionalLightHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);\n this.directionalLightHelper.visible = Config.shadow.helperEnabled;\n\n // Hemisphere light\n this.hemiLight = new THREE.HemisphereLight(Config.hemiLight.color, Config.hemiLight.groundColor, Config.hemiLight.intensity);\n this.hemiLight.position.set(Config.hemiLight.x, Config.hemiLight.y, Config.hemiLight.z);\n this.hemiLight.visible = Config.hemiLight.enabled;\n }\n\n place(lightName) {\n switch(lightName) {\n case 'ambient':\n this.scene.add(this.ambientLight);\n break;\n\n case 'directional':\n this.scene.add(this.directionalLight);\n this.scene.add(this.directionalLightHelper);\n break;\n\n case 'point':\n this.scene.add(this.pointLight);\n break;\n\n case 'hemi':\n this.scene.add(this.hemiLight);\n break;\n }\n }\n}\n","import * as THREE from 'three';\n\nimport OrbitControls from '../../utils/orbitControls';\nimport Config from '../../data/config';\n\n// Controls based on orbit controls\nexport default class Controls {\n constructor(camera, container) {\n // Orbit controls first needs to pass in THREE to constructor\n const orbitControls = new OrbitControls(THREE);\n this.threeControls = new orbitControls(camera, container);\n\n this.init();\n }\n\n init() {\n this.threeControls.target.set(Config.controls.target.x, Config.controls.target.y, Config.controls.target.z);\n this.threeControls.autoRotate = Config.controls.autoRotate;\n this.threeControls.autoRotateSpeed = Config.controls.autoRotateSpeed;\n this.threeControls.rotateSpeed = Config.controls.rotateSpeed;\n this.threeControls.zoomSpeed = Config.controls.zoomSpeed;\n this.threeControls.minDistance = Config.controls.minDistance;\n this.threeControls.maxDistance = Config.controls.maxDistance;\n this.threeControls.minPolarAngle = Config.controls.minPolarAngle;\n this.threeControls.maxPolarAngle = Config.controls.maxPolarAngle;\n this.threeControls.enableDamping = Config.controls.enableDamping;\n this.threeControls.enableZoom = Config.controls.enableZoom;\n this.threeControls.dampingFactor = Config.controls.dampingFactor;\n }\n}\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// USe this class as a helper to set up some default materials\nexport default class Material {\n constructor(color) {\n this.basic = new THREE.MeshBasicMaterial({\n color,\n side: THREE.DoubleSide\n });\n\n this.standard = new THREE.MeshStandardMaterial({\n color,\n shading: THREE.FlatShading,\n roughness: 1,\n metalness: 0,\n side: THREE.DoubleSide\n });\n\n this.wire = new THREE.MeshBasicMaterial({wireframe: true});\n }\n}\n\n","// Local vars for rStats\nlet rS, bS, glS, tS;\n\nexport default class Stats {\n constructor(renderer) {\n this.renderer = renderer;\n }\n\n setUp() {\n bS = new BrowserStats();\n glS = new glStats();\n tS = new threeStats(this.renderer.threeRenderer);\n\n rS = new rStats({\n CSSPath: './css/',\n userTimingAPI: true,\n values: {\n frame: { caption: 'Total frame time (ms)', over: 16, average: true, avgMs: 100 },\n fps: { caption: 'Framerate (FPS)', below: 30 },\n calls: { caption: 'Calls (three.js)', over: 3000 },\n raf: { caption: 'Time since last rAF (ms)', average: true, avgMs: 100 },\n rstats: { caption: 'rStats update (ms)', average: true, avgMs: 100 },\n texture: { caption: 'GenTex', average: true, avgMs: 100 }\n },\n groups: [\n { caption: 'Framerate', values: ['fps', 'raf'] },\n { caption: 'Frame Budget', values: ['frame', 'texture', 'setup', 'render'] }\n ],\n fractions: [\n { base: 'frame', steps: ['texture', 'setup', 'render'] }\n ],\n plugins: [bS, tS, glS]\n });\n };\n\n static start() {\n rS('frame').start();\n glS.start();\n\n rS('rAF').tick();\n rS('FPS').frame();\n\n rS('render').start();\n };\n\n static end() {\n rS('render').end(); // render finished\n rS('frame').end(); // frame finished\n\n // Local rStats update\n rS('rStats').start();\n rS().update();\n rS('rStats').end();\n };\n}\n","import * as THREE from 'three';\n\nimport Material from './material';\n\nimport Config from '../../data/config';\n\n// This helper class can be used to create and then place geometry in the scene\nexport default class Geometry {\n constructor(scene) {\n this.scene = scene;\n this.geo = null;\n }\n\n make(type) {\n if(type === 'plane') {\n return (width, height, widthSegments = 1, heightSegments = 1) => {\n this.geo = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);\n };\n }\n\n if(type === 'sphere') {\n return (radius, widthSegments = 32, heightSegments = 32) => {\n this.geo = new THREE.SphereGeometry(radius, widthSegments, heightSegments);\n };\n }\n }\n\n place(position, rotation) {\n const material = new Material(0xeeeeee).standard;\n const mesh = new THREE.Mesh(this.geo, material);\n\n // Use ES6 spread to set position and rotation from passed in array\n mesh.position.set(...position);\n mesh.rotation.set(...rotation);\n\n if(Config.shadow.enabled) {\n mesh.receiveShadow = true;\n }\n\n this.scene.add(mesh);\n }\n}\n","// Provides simple static functions that are used multiple times in the app\nexport default class Helpers {\n static throttle(fn, threshhold, scope) {\n threshhold || (threshhold = 250);\n let last, deferTimer;\n\n return function() {\n const context = scope || this;\n\n const now = +new Date,\n args = arguments;\n\n if(last && now < last + threshhold) {\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function() {\n last = now;\n fn.apply(context, args);\n }, threshhold);\n }\n else {\n last = now;\n fn.apply(context, args);\n }\n };\n }\n\n static logProgress() {\n return function(xhr) {\n if(xhr.lengthComputable) {\n const percentComplete = xhr.loaded / xhr.total * 100;\n\n console.log(Math.round(percentComplete, 2) + '% downloaded');\n }\n }\n }\n\n static logError() {\n return function(xhr) {\n console.error(xhr);\n }\n }\n\n static handleColorChange(color) {\n return (value) => {\n if(typeof value === 'string') {\n value = value.replace('#', '0x');\n }\n\n color.setHex(value);\n };\n }\n\n static update(mesh) {\n this.needsUpdate(mesh.material, mesh.geometry);\n }\n\n static needsUpdate(material, geometry) {\n return function() {\n material.shading = +material.shading; //Ensure number\n material.vertexColors = +material.vertexColors; //Ensure number\n material.side = +material.side; //Ensure number\n material.needsUpdate = true;\n geometry.verticesNeedUpdate = true;\n geometry.normalsNeedUpdate = true;\n geometry.colorsNeedUpdate = true;\n };\n }\n\n static updateTexture(material, materialKey, textures) {\n return function(key) {\n material[materialKey] = textures[key];\n material.needsUpdate = true;\n };\n }\n}\n","import * as THREE from 'three';\n// Promise polyfill for IE\nimport { Promise } from 'es6-promise';\n\nimport Helpers from '../../utils/helpers';\nimport Config from '../../data/config';\n\n// This class preloads all textures in the imageFiles array in the Config via ES6 Promises.\n// Once all textures are done loading the model itself will be loaded after the Promise .then() callback.\n// Using promises to preload textures prevents issues when applying textures to materials\n// before the textures have loaded.\nexport default class Texture {\n constructor() {\n // Prop that will contain all loaded textures\n this.textures = {};\n }\n\n load() {\n const loader = new THREE.TextureLoader();\n const maxAnisotropy = Config.maxAnisotropy;\n const imageFiles = Config.texture.imageFiles;\n const promiseArray = [];\n\n loader.setPath(Config.texture.path);\n\n imageFiles.forEach(imageFile => {\n // Add an individual Promise for each image in array\n promiseArray.push(new Promise((resolve, reject) => {\n // Each Promise will attempt to load the image file\n loader.load(imageFile.image,\n // This gets called on load with the loaded texture\n texture => {\n texture.anisotropy = maxAnisotropy;\n\n // Resolve Promise with object of texture if it is instance of THREE.Texture\n const modelOBJ = {};\n modelOBJ[imageFile.name] = texture;\n if(modelOBJ[imageFile.name] instanceof THREE.Texture)\n resolve(modelOBJ);\n },\n Helpers.logProgress(),\n xhr => reject(new Error(xhr + 'An error occurred loading while loading ' + imageFile.image))\n )\n }));\n });\n\n // Iterate through all Promises in array and return another Promise when all have resolved or console log reason when any reject\n return Promise.all(promiseArray).then(textures => {\n // Set the textures prop object to have name be the resolved texture\n for(let i = 0; i < textures.length; i++) {\n this.textures[Object.keys(textures[i])[0]] = textures[i][Object.keys(textures[i])[0]];\n }\n }, reason => console.log(reason));\n }\n}\n","import * as THREE from 'three';\n\n// Simple mesh helper that shows edges, wireframes, and face and vertex normals\nexport default class MeshHelper {\n constructor(scene, mesh) {\n const wireframe = new THREE.WireframeGeometry(mesh.geometry);\n const wireLine = new THREE.LineSegments(wireframe);\n wireLine.material.depthTest = false;\n wireLine.material.opacity = 0.25;\n wireLine.material.transparent = true;\n mesh.add(wireLine);\n\n const edges = new THREE.EdgesGeometry(mesh.geometry);\n const edgesLine = new THREE.LineSegments(edges);\n edgesLine.material.depthTest = false;\n edgesLine.material.opacity = 0.25;\n edgesLine.material.transparent = true;\n mesh.add(edgesLine);\n\n scene.add(new THREE.BoxHelper(mesh));\n scene.add(new THREE.FaceNormalsHelper(mesh, 2));\n scene.add(new THREE.VertexNormalsHelper(mesh, 2));\n }\n}\n","import * as THREE from 'three';\n\nimport Material from '../helpers/material';\nimport MeshHelper from '../helpers/meshHelper';\nimport Helpers from '../../utils/helpers';\nimport Config from '../../data/config';\n\n// Loads in a single object from the config file\nexport default class Model {\n constructor(scene, manager, textures) {\n this.scene = scene;\n this.textures = textures;\n\n // Manager is passed in to loader to determine when loading done in main\n this.loader = new THREE.ObjectLoader(manager);\n this.obj = null;\n }\n\n load() {\n // Load model with ObjectLoader\n this.loader.load(\n Config.model.path,\n obj => {\n obj.traverse(child => {\n if(child instanceof THREE.Mesh) {\n // Create material for mesh and set its map to texture by name from preloaded textures\n const material = new Material(0xffffff).standard;\n material.map = this.textures.UV;\n child.material = material;\n\n // Set to cast and receive shadow if enabled\n if(Config.shadow.enabled) {\n child.receiveShadow = true;\n child.castShadow = true;\n }\n }\n });\n\n // Add mesh helper if Dev\n if(Config.isDev && Config.mesh.enableHelper) {\n new MeshHelper(this.scene, obj);\n }\n\n // Set prop to obj so it can be accessed from outside the class\n this.obj = obj;\n\n obj.scale.multiplyScalar(Config.model.scale);\n this.scene.add(obj);\n },\n Helpers.logProgress(),\n Helpers.logError()\n );\n }\n}\n","const ALIAS = {\n 'left'\t\t: 37,\n 'up'\t\t : 38,\n 'right'\t\t: 39,\n 'down'\t\t: 40,\n 'space'\t\t: 32,\n 'tab'\t\t : 9,\n 'escape'\t: 27\n};\n\nexport default class Keyboard {\n constructor(domElement) {\n this.domElement = domElement || document;\n this.keyCodes = {};\n\n // bind keyEvents\n this.domElement.addEventListener('keydown', (event) => this.onKeyChange(event), false);\n this.domElement.addEventListener('keyup', (event) => this.onKeyChange(event), false);\n\n // bind window blur\n window.addEventListener('blur', () => this.onBlur, false);\n }\n\n destroy() {\n this.domElement.removeEventListener('keydown', (event) => this.onKeyChange(event), false);\n this.domElement.removeEventListener('keyup', (event) => this.onKeyChange(event), false);\n\n // unbind window blur event\n window.removeEventListener('blur', () => this.onBlur, false);\n }\n\n onBlur() {\n for(const prop in this.keyCodes)\n this.keyCodes[prop] = false;\n }\n\n onKeyChange(event) {\n // log to debug\n //console.log('onKeyChange', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)\n\n // update this.keyCodes\n const keyCode = event.keyCode;\n this.keyCodes[keyCode] = event.type === 'keydown';\n }\n\n pressed(keyDesc) {\n const keys = keyDesc.split('+');\n for(let i = 0; i < keys.length; i++) {\n const key = keys[i];\n let pressed = false;\n if(Object.keys(ALIAS).indexOf(key) != -1) {\n pressed = this.keyCodes[ALIAS[key]];\n } else {\n pressed = this.keyCodes[key.toUpperCase().charCodeAt(0)];\n }\n if(!pressed)\n return false;\n }\n\n return true;\n }\n\n eventMatches(event, keyDesc) {\n const aliases = ALIAS;\n const aliasKeys = Object.keys(aliases);\n const keys = keyDesc.split('+');\n // log to debug\n // console.log('eventMatches', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)\n for(let i = 0; i < keys.length; i++) {\n const key = keys[i];\n let pressed = false;\n if(key === 'shift') {\n pressed = event.shiftKey ? true : false;\n } else if(key === 'ctrl') {\n pressed = event.ctrlKey ? true : false;\n } else if(key === 'alt') {\n pressed = event.altKey ? true : false;\n } else if(key === 'meta') {\n pressed = event.metaKey ? true : false;\n } else if(aliasKeys.indexOf(key) !== -1) {\n pressed = event.keyCode === aliases[key];\n } else if(event.keyCode === key.toUpperCase().charCodeAt(0)) {\n pressed = true;\n }\n if(!pressed)\n return false;\n }\n\n return true;\n }\n}\n","import Keyboard from '../../utils/keyboard';\nimport Helpers from '../../utils/helpers';\nimport Config from '../../data/config';\n\n// Manages all input interactions\nexport default class Interaction {\n constructor(renderer, scene, camera, controls) {\n // Properties\n this.renderer = renderer;\n this.scene = scene;\n this.camera = camera;\n this.controls = controls;\n\n this.timeout = null;\n\n // Instantiate keyboard helper\n this.keyboard = new Keyboard();\n\n // Listeners\n // Mouse events\n this.renderer.domElement.addEventListener('mousemove', (event) => Helpers.throttle(this.onMouseMove(event), 250), false);\n this.renderer.domElement.addEventListener('mouseleave', (event) => this.onMouseLeave(event), false);\n this.renderer.domElement.addEventListener('mouseover', (event) => this.onMouseOver(event), false);\n\n // Keyboard events\n this.keyboard.domElement.addEventListener('keydown', (event) => {\n // Only once\n if(event.repeat) {\n return;\n }\n\n if(this.keyboard.eventMatches(event, 'escape')) {\n console.log('Escape pressed');\n }\n });\n }\n\n onMouseOver(event) {\n event.preventDefault();\n\n Config.isMouseOver = true;\n }\n\n onMouseLeave(event) {\n event.preventDefault();\n\n Config.isMouseOver = false;\n }\n\n onMouseMove(event) {\n event.preventDefault();\n\n clearTimeout(this.timeout);\n\n this.timeout = setTimeout(function() {\n Config.isMouseMoving = false;\n }, 200);\n\n Config.isMouseMoving = true;\n }\n}\n","import Config from '../../data/config';\n\n// Manages all dat.GUI interactions\nexport default class DatGUI {\n constructor(main, mesh) {\n const gui = new dat.GUI();\n\n this.camera = main.camera.threeCamera;\n this.controls = main.controls.threeControls;\n this.light = main.light;\n\n /* Global */\n //gui.close();\n\n /* Camera */\n const cameraFolder = gui.addFolder('Camera');\n const cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV');\n cameraFOVGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.camera.fov = value;\n });\n cameraFOVGui.onFinishChange(() => {\n this.camera.updateProjectionMatrix();\n\n this.controls.enableRotate = true;\n });\n const cameraAspectGui = cameraFolder.add(Config.camera, 'aspect', 0, 4).name('Camera Aspect');\n cameraAspectGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.camera.aspect = value;\n });\n cameraAspectGui.onFinishChange(() => {\n this.camera.updateProjectionMatrix();\n\n this.controls.enableRotate = true;\n });\n const cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color');\n cameraFogColorGui.onChange((value) => {\n main.scene.fog.color.setHex(value);\n });\n const cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near');\n cameraFogNearGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n main.scene.fog.density = value;\n });\n cameraFogNearGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n /* Controls */\n const controlsFolder = gui.addFolder('Controls');\n controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => {\n this.controls.autoRotate = value;\n });\n const controlsAutoRotateSpeedGui = controlsFolder.add(Config.controls, 'autoRotateSpeed', -1, 1).name('Rotation Speed');\n controlsAutoRotateSpeedGui.onChange((value) => {\n this.controls.enableRotate = false;\n this.controls.autoRotateSpeed = value;\n });\n controlsAutoRotateSpeedGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n /* Mesh */\n const meshFolder = gui.addFolder('Mesh');\n meshFolder.add(Config.mesh, 'translucent', true).name('Translucent').onChange((value) => {\n if(value) {\n mesh.material.transparent = true;\n mesh.material.opacity = 0.5;\n } else {\n mesh.material.opacity = 1.0;\n }\n });\n meshFolder.add(Config.mesh, 'wireframe', true).name('Wireframe').onChange((value) => {\n mesh.material.wireframe = value;\n });\n\n\n /* Lights */\n // Ambient Light\n const ambientLightFolder = gui.addFolder('Ambient Light');\n ambientLightFolder.add(Config.ambientLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.ambientLight.visible = value;\n });\n ambientLightFolder.addColor(Config.ambientLight, 'color').name('Color').onChange((value) => {\n this.light.ambientLight.color.setHex(value);\n });\n\n\n // Directional Light\n const directionalLightFolder = gui.addFolder('Directional Light');\n directionalLightFolder.add(Config.directionalLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.directionalLight.visible = value;\n });\n directionalLightFolder.addColor(Config.directionalLight, 'color').name('Color').onChange((value) => {\n this.light.directionalLight.color.setHex(value);\n });\n const directionalLightIntensityGui = directionalLightFolder.add(Config.directionalLight, 'intensity', 0, 2).name('Intensity');\n directionalLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.intensity = value;\n });\n directionalLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionXGui = directionalLightFolder.add(Config.directionalLight, 'x', -1000, 1000).name('Position X');\n directionalLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.x = value;\n });\n directionalLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionYGui = directionalLightFolder.add(Config.directionalLight, 'y', -1000, 1000).name('Position Y');\n directionalLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.y = value;\n });\n directionalLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionZGui = directionalLightFolder.add(Config.directionalLight, 'z', -1000, 1000).name('Position Z');\n directionalLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.z = value;\n });\n directionalLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n // Shadow Map\n const shadowFolder = gui.addFolder('Shadow Map');\n shadowFolder.add(Config.shadow, 'enabled').name('Enabled').onChange((value) => {\n this.light.directionalLight.castShadow = value;\n });\n shadowFolder.add(Config.shadow, 'helperEnabled').name('Helper Enabled').onChange((value) => {\n this.light.directionalLightHelper.visible = value;\n });\n const shadowNearGui = shadowFolder.add(Config.shadow, 'near', 0, 400).name('Near');\n shadowNearGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.near = value;\n });\n shadowNearGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowFarGui = shadowFolder.add(Config.shadow, 'far', 0, 1200).name('Far');\n shadowFarGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.far = value;\n });\n shadowFarGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowTopGui = shadowFolder.add(Config.shadow, 'top', -400, 400).name('Top');\n shadowTopGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.top = value;\n });\n shadowTopGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowRightGui = shadowFolder.add(Config.shadow, 'right', -400, 400).name('Right');\n shadowRightGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.right = value;\n });\n shadowRightGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowBottomGui = shadowFolder.add(Config.shadow, 'bottom', -400, 400).name('Bottom');\n shadowBottomGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.bottom = value;\n });\n shadowBottomGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowLeftGui = shadowFolder.add(Config.shadow, 'left', -400, 400).name('Left');\n shadowLeftGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.left = value;\n });\n shadowLeftGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowBiasGui = shadowFolder.add(Config.shadow, 'bias', -0.000010, 1).name('Bias');\n shadowBiasGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.bias = value;\n });\n shadowBiasGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n\n\n // Point Light\n const pointLightFolder = gui.addFolder('Point Light');\n pointLightFolder.add(Config.pointLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.pointLight.visible = value;\n });\n pointLightFolder.addColor(Config.pointLight, 'color').name('Color').onChange((value) => {\n this.light.pointLight.color.setHex(value);\n });\n const pointLightIntensityGui = pointLightFolder.add(Config.pointLight, 'intensity', 0, 2).name('Intensity');\n pointLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.intensity = value;\n });\n pointLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightDistanceGui = pointLightFolder.add(Config.pointLight, 'distance', 0, 1000).name('Distance');\n pointLightDistanceGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.distance = value;\n });\n pointLightDistanceGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionXGui = pointLightFolder.add(Config.pointLight, 'x', -1000, 1000).name('Position X');\n pointLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.x = value;\n });\n pointLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionYGui = pointLightFolder.add(Config.pointLight, 'y', -1000, 1000).name('Position Y');\n pointLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.y = value;\n });\n pointLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionZGui = pointLightFolder.add(Config.pointLight, 'z', -1000, 1000).name('Position Z');\n pointLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.z = value;\n });\n pointLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n // Hemi Light\n const hemiLightFolder = gui.addFolder('Hemi Light');\n hemiLightFolder.add(Config.hemiLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.hemiLight.visible = value;\n });\n hemiLightFolder.addColor(Config.hemiLight, 'color').name('Color').onChange((value) => {\n this.light.hemiLight.color.setHex(value);\n });\n hemiLightFolder.addColor(Config.hemiLight, 'groundColor').name('ground Color').onChange((value) => {\n this.light.hemiLight.groundColor.setHex(value);\n });\n const hemiLightIntensityGui = hemiLightFolder.add(Config.hemiLight, 'intensity', 0, 2).name('Intensity');\n hemiLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.intensity = value;\n });\n hemiLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionXGui = hemiLightFolder.add(Config.hemiLight, 'x', -1000, 1000).name('Position X');\n hemiLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.x = value;\n });\n hemiLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionYGui = hemiLightFolder.add(Config.hemiLight, 'y', -500, 1000).name('Position Y');\n hemiLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.y = value;\n });\n hemiLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionZGui = hemiLightFolder.add(Config.hemiLight, 'z', -1000, 1000).name('Position Z');\n hemiLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.z = value;\n });\n hemiLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n }\n}\n","// Global imports -\nimport * as THREE from 'three';\nimport TWEEN from 'tween.js';\n\n// Local imports -\n// Components\nimport Renderer from './components/renderer';\nimport Camera from './components/camera';\nimport Light from './components/light';\nimport Controls from './components/controls';\n\n// Helpers\nimport Geometry from './helpers/geometry';\nimport Stats from './helpers/stats';\n\n// Model\nimport Texture from './model/texture';\nimport Model from './model/model';\n\n// Managers\nimport Interaction from './managers/interaction';\nimport DatGUI from './managers/datGUI';\n\n// data\nimport Config from './../data/config';\n// -- End of imports\n\n// This class instantiates and ties all of the components together, starts the loading process and renders the main loop\nexport default class Main {\n constructor(container) {\n // Set container property to container element\n this.container = container;\n\n // Start Three clock\n this.clock = new THREE.Clock();\n\n // Main scene creation\n this.scene = new THREE.Scene();\n this.scene.fog = new THREE.FogExp2(Config.fog.color, Config.fog.near);\n\n // Get Device Pixel Ratio first for retina\n if(window.devicePixelRatio) {\n Config.dpr = window.devicePixelRatio;\n }\n\n // Main renderer constructor\n this.renderer = new Renderer(this.scene, container);\n\n // Components instantiations\n this.camera = new Camera(this.renderer.threeRenderer);\n this.controls = new Controls(this.camera.threeCamera, container);\n this.light = new Light(this.scene);\n\n // Create and place lights in scene\n const lights = ['ambient', 'directional', 'point', 'hemi'];\n lights.forEach((light) => this.light.place(light));\n\n // Create and place geo in scene\n this.geometry = new Geometry(this.scene);\n this.geometry.make('plane')(150, 150, 10, 10);\n this.geometry.place([0, -20, 0], [Math.PI / 2, 0, 0]);\n\n // Set up rStats if dev environment\n if(Config.isDev && Config.isShowingStats) {\n this.stats = new Stats(this.renderer);\n this.stats.setUp();\n }\n\n // Instantiate texture class\n this.texture = new Texture();\n\n // Start loading the textures and then go on to load the model after the texture Promises have resolved\n this.texture.load().then(() => {\n this.manager = new THREE.LoadingManager();\n\n // Textures loaded, load model\n this.model = new Model(this.scene, this.manager, this.texture.textures);\n this.model.load();\n\n // onProgress callback\n this.manager.onProgress = (item, loaded, total) => {\n console.log(`${item}: ${loaded} ${total}`);\n };\n\n // All loaders done now\n this.manager.onLoad = () => {\n // Set up interaction manager with the app now that the model is finished loading\n new Interaction(this.renderer.threeRenderer, this.scene, this.camera.threeCamera, this.controls.threeControls);\n\n // Add dat.GUI controls if dev\n if(Config.isDev) {\n new DatGUI(this, this.model.obj);\n }\n\n // Everything is now fully loaded\n Config.isLoaded = true;\n this.container.querySelector('#loading').style.display = 'none';\n };\n });\n\n // Start render which does not wait for model fully loaded\n this.render();\n }\n\n render() {\n // Render rStats if Dev\n if(Config.isDev && Config.isShowingStats) {\n Stats.start();\n }\n\n // Call render function and pass in created scene and camera\n this.renderer.render(this.scene, this.camera.threeCamera);\n\n // rStats has finished determining render call now\n if(Config.isDev && Config.isShowingStats) {\n Stats.end();\n }\n\n // Delta time is sometimes needed for certain updates\n //const delta = this.clock.getDelta();\n\n // Call any vendor or module frame updates here\n TWEEN.update();\n this.controls.threeControls.update();\n\n // RAF\n requestAnimationFrame(this.render.bind(this)); // Bind the main class instead of window object\n }\n}\n","import Config from './data/config';\nimport Detector from './utils/detector';\nimport Main from './app/main';\n\n// Styles\nimport './../css/app.scss';\n\n// Check environment and set the Config helper\nif(__ENV__ === 'dev') {\n console.log('----- RUNNING IN DEV ENVIRONMENT! -----');\n\n Config.isDev = true;\n}\n\nfunction init() {\n // Check for webGL capabilities\n if(!Detector.webgl) {\n Detector.addGetWebGLMessage();\n } else {\n const container = document.getElementById('appContainer');\n new Main(container);\n }\n}\n\ninit();\n"],"sourceRoot":""}
\ No newline at end of file
+{"version":3,"sources":["webpack:///./src/js/utils/orbitControls.js","webpack:///./src/js/data/config.js","webpack:///./src/js/utils/detector.js","webpack:///./src/js/app/components/renderer.js","webpack:///./src/js/app/components/camera.js","webpack:///./src/js/app/components/light.js","webpack:///./src/js/app/components/controls.js","webpack:///./src/js/app/helpers/material.js","webpack:///./src/js/app/helpers/stats.js","webpack:///./src/js/app/helpers/geometry.js","webpack:///./src/js/utils/helpers.js","webpack:///./src/js/app/model/texture.js","webpack:///./src/js/app/helpers/meshHelper.js","webpack:///./src/js/app/model/model.js","webpack:///./src/js/utils/keyboard.js","webpack:///./src/js/app/managers/interaction.js","webpack:///./src/js/app/managers/datGUI.js","webpack:///./src/js/app/main.js","webpack:///./src/js/app.js"],"names":["module","exports","THREE","MOUSE","OrbitConstraint","object","this","target","Vector3","minDistance","maxDistance","Infinity","minZoom","maxZoom","minPolarAngle","maxPolarAngle","Math","PI","minAzimuthAngle","maxAzimuthAngle","enableDamping","dampingFactor","theta","phi","v","offset","quat","quatInverse","lastPosition","lastQuaternion","scope","EPS","phiDelta","thetaDelta","scale","panOffset","zoomChanged","getPolarAngle","getAzimuthalAngle","rotateLeft","angle","rotateUp","panLeft","distance","te","matrix","elements","set","multiplyScalar","add","panUp","pan","deltaX","deltaY","screenWidth","screenHeight","PerspectiveCamera","targetDistance","position","clone","sub","length","tan","fov","OrthographicCamera","right","left","top","bottom","console","warn","dollyIn","dollyScale","zoom","max","min","updateProjectionMatrix","dollyOut","update","Quaternion","setFromUnitVectors","up","inverse","copy","applyQuaternion","atan2","x","z","sqrt","y","radius","sin","cos","lookAt","distanceToSquared","dot","quaternion","OrbitControls","domElement","constraint","undefined","document","Object","defineProperty","get","enabled","center","enableZoom","zoomSpeed","enableRotate","rotateSpeed","enablePan","keyPanSpeed","autoRotate","autoRotateSpeed","enableKeys","keys","LEFT","UP","RIGHT","BOTTOM","mouseButtons","ORBIT","ZOOM","MIDDLE","PAN","rotateStart","Vector2","rotateEnd","rotateDelta","panStart","panEnd","panDelta","dollyStart","dollyEnd","dollyDelta","STATE","NONE","ROTATE","DOLLY","TOUCH_ROTATE","TOUCH_DOLLY","TOUCH_PAN","state","target0","position0","zoom0","changeEvent","type","startEvent","endEvent","element","body","clientWidth","clientHeight","getZoomScale","pow","onMouseDown","event","preventDefault","button","clientX","clientY","addEventListener","onMouseMove","onMouseUp","dispatchEvent","subVectors","removeEventListener","onMouseWheel","stopPropagation","delta","wheelDelta","detail","onKeyDown","keyCode","touchstart","touches","pageX","pageY","dx","dy","touchmove","touchend","contextmenu","reset","dispose","window","prototype","create","EventDispatcher","constructor","defineProperties","value","noZoom","noRotate","noPan","noKeys","staticMoving","dynamicDampingFactor","isDev","isShowingStats","isLoaded","isTweening","isRotating","isMouseMoving","isMouseOver","maxAnisotropy","dpr","easing","TWEEN","Easing","Quadratic","InOut","duration","model","path","texture","imageFiles","name","image","mesh","enableHelper","wireframe","translucent","material","color","emissive","fog","near","camera","far","aspect","posX","posY","posZ","controls","ambientLight","directionalLight","intensity","shadow","helperEnabled","bias","mapWidth","mapHeight","pointLight","hemiLight","groundColor","canvas","CanvasRenderingContext2D","webgl","createElement","WebGLRenderingContext","getContext","e","workers","Worker","fileapi","File","FileReader","FileList","Blob","getWebGLErrorMessage","id","style","fontFamily","fontSize","fontWeight","textAlign","background","padding","width","margin","innerHTML","join","addGetWebGLMessage","parameters","parent","appendChild","Renderer","scene","container","threeRenderer","antialias","setClearColor","setPixelRatio","devicePixelRatio","shadowMap","Config","getMaxAnisotropy","updateSize","setSize","offsetWidth","offsetHeight","render","Camera","renderer","height","threeCamera","Light","init","visible","castShadow","mapSize","directionalLightHelper","lightName","Controls","orbitControls","threeControls","Material","basic","side","standard","shading","roughness","metalness","wire","rS","bS","glS","tS","Geometry","geo","widthSegments","heightSegments","rotation","receiveShadow","Stats","start","tick","frame","end","BrowserStats","glStats","threeStats","rStats","CSSPath","userTimingAPI","values","caption","over","average","avgMs","fps","below","calls","raf","rstats","groups","fractions","base","steps","plugins","Helpers","fn","threshhold","last","deferTimer","context","now","Date","args","arguments","clearTimeout","setTimeout","apply","xhr","lengthComputable","percentComplete","loaded","total","log","round","error","replace","setHex","needsUpdate","geometry","vertexColors","verticesNeedUpdate","normalsNeedUpdate","colorsNeedUpdate","materialKey","textures","key","Texture","loader","promiseArray","setPath","forEach","imageFile","push","Promise","resolve","reject","load","anisotropy","modelOBJ","logProgress","Error","all","then","i","reason","MeshHelper","wireLine","depthTest","opacity","transparent","edges","edgesLine","Model","manager","obj","traverse","child","map","UV","logError","ALIAS","Keyboard","keyCodes","onKeyChange","onBlur","prop","keyDesc","split","pressed","indexOf","toUpperCase","charCodeAt","aliases","aliasKeys","shiftKey","ctrlKey","altKey","metaKey","Interaction","timeout","keyboard","throttle","onMouseLeave","onMouseOver","repeat","eventMatches","DatGUI","main","gui","dat","GUI","light","cameraFolder","addFolder","cameraFOVGui","onChange","onFinishChange","cameraAspectGui","addColor","cameraFogNearGui","density","controlsFolder","controlsAutoRotateSpeedGui","meshFolder","ambientLightFolder","directionalLightFolder","directionalLightIntensityGui","directionalLightPositionXGui","directionalLightPositionYGui","directionalLightPositionZGui","shadowFolder","shadowNearGui","shadowFarGui","shadowTopGui","shadowRightGui","shadowBottomGui","shadowLeftGui","shadowBiasGui","pointLightFolder","pointLightIntensityGui","pointLightDistanceGui","pointLightPositionXGui","pointLightPositionYGui","pointLightPositionZGui","hemiLightFolder","hemiLightIntensityGui","hemiLightPositionXGui","hemiLightPositionYGui","hemiLightPositionZGui","Main","clock","place","make","stats","setUp","onProgress","item","onLoad","querySelector","display","requestAnimationFrame","bind","Detector","getElementById"],"mappings":"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","file":"0.app.js","sourcesContent":["module.exports = function(THREE) {\n var MOUSE = THREE.MOUSE\n if (!MOUSE)\n MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2 };\n\n /**\n * @author qiao / https://github.com/qiao\n * @author mrdoob / http://mrdoob.com\n * @author alteredq / http://alteredqualia.com/\n * @author WestLangley / http://github.com/WestLangley\n * @author erich666 / http://erichaines.com\n */\n /*global THREE, console */\n\n function OrbitConstraint ( object ) {\n\n this.object = object;\n\n // \"target\" sets the location of focus, where the object orbits around\n // and where it pans with respect to.\n this.target = new THREE.Vector3();\n\n // Limits to how far you can dolly in and out ( PerspectiveCamera only )\n this.minDistance = 0;\n this.maxDistance = Infinity;\n\n // Limits to how far you can zoom in and out ( OrthographicCamera only )\n this.minZoom = 0;\n this.maxZoom = Infinity;\n\n // How far you can orbit vertically, upper and lower limits.\n // Range is 0 to Math.PI radians.\n this.minPolarAngle = 0; // radians\n this.maxPolarAngle = Math.PI; // radians\n\n // How far you can orbit horizontally, upper and lower limits.\n // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].\n this.minAzimuthAngle = - Infinity; // radians\n this.maxAzimuthAngle = Infinity; // radians\n\n // Set to true to enable damping (inertia)\n // If damping is enabled, you must call controls.update() in your animation loop\n this.enableDamping = false;\n this.dampingFactor = 0.25;\n\n ////////////\n // internals\n\n var scope = this;\n\n var EPS = 0.000001;\n\n // Current position in spherical coordinate system.\n var theta;\n var phi;\n\n // Pending changes\n var phiDelta = 0;\n var thetaDelta = 0;\n var scale = 1;\n var panOffset = new THREE.Vector3();\n var zoomChanged = false;\n\n // API\n\n this.getPolarAngle = function () {\n\n return phi;\n\n };\n\n this.getAzimuthalAngle = function () {\n\n return theta;\n\n };\n\n this.rotateLeft = function ( angle ) {\n\n thetaDelta -= angle;\n\n };\n\n this.rotateUp = function ( angle ) {\n\n phiDelta -= angle;\n\n };\n\n // pass in distance in world space to move left\n this.panLeft = function() {\n\n var v = new THREE.Vector3();\n\n return function panLeft ( distance ) {\n\n var te = this.object.matrix.elements;\n\n // get X column of matrix\n v.set( te[ 0 ], te[ 1 ], te[ 2 ] );\n v.multiplyScalar( - distance );\n\n panOffset.add( v );\n\n };\n\n }();\n\n // pass in distance in world space to move up\n this.panUp = function() {\n\n var v = new THREE.Vector3();\n\n return function panUp ( distance ) {\n\n var te = this.object.matrix.elements;\n\n // get Y column of matrix\n v.set( te[ 4 ], te[ 5 ], te[ 6 ] );\n v.multiplyScalar( distance );\n\n panOffset.add( v );\n\n };\n\n }();\n\n // pass in x,y of change desired in pixel space,\n // right and down are positive\n this.pan = function ( deltaX, deltaY, screenWidth, screenHeight ) {\n\n if ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n // perspective\n var position = scope.object.position;\n var offset = position.clone().sub( scope.target );\n var targetDistance = offset.length();\n\n // half of the fov is center to top of screen\n targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n // we actually don't use screenWidth, since perspective camera is fixed to screen height\n scope.panLeft( 2 * deltaX * targetDistance / screenHeight );\n scope.panUp( 2 * deltaY * targetDistance / screenHeight );\n\n } else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n // orthographic\n scope.panLeft( deltaX * ( scope.object.right - scope.object.left ) / screenWidth );\n scope.panUp( deltaY * ( scope.object.top - scope.object.bottom ) / screenHeight );\n\n } else {\n\n // camera neither orthographic or perspective\n console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\n }\n\n };\n\n this.dollyIn = function ( dollyScale ) {\n\n if ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n scale /= dollyScale;\n\n } else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );\n scope.object.updateProjectionMatrix();\n zoomChanged = true;\n\n } else {\n\n console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\n }\n\n };\n\n this.dollyOut = function ( dollyScale ) {\n\n if ( scope.object instanceof THREE.PerspectiveCamera ) {\n\n scale *= dollyScale;\n\n } else if ( scope.object instanceof THREE.OrthographicCamera ) {\n\n scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );\n scope.object.updateProjectionMatrix();\n zoomChanged = true;\n\n } else {\n\n console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\n }\n\n };\n\n this.update = function() {\n\n var offset = new THREE.Vector3();\n\n // so camera.up is the orbit axis\n var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );\n var quatInverse = quat.clone().inverse();\n\n var lastPosition = new THREE.Vector3();\n var lastQuaternion = new THREE.Quaternion();\n\n return function () {\n\n var position = this.object.position;\n\n offset.copy( position ).sub( this.target );\n\n // rotate offset to \"y-axis-is-up\" space\n offset.applyQuaternion( quat );\n\n // angle from z-axis around y-axis\n\n theta = Math.atan2( offset.x, offset.z );\n\n // angle from y-axis\n\n phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );\n\n theta += thetaDelta;\n phi += phiDelta;\n\n // restrict theta to be between desired limits\n theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );\n\n // restrict phi to be between desired limits\n phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );\n\n // restrict phi to be betwee EPS and PI-EPS\n phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );\n\n var radius = offset.length() * scale;\n\n // restrict radius to be between desired limits\n radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );\n\n // move target to panned location\n this.target.add( panOffset );\n\n offset.x = radius * Math.sin( phi ) * Math.sin( theta );\n offset.y = radius * Math.cos( phi );\n offset.z = radius * Math.sin( phi ) * Math.cos( theta );\n\n // rotate offset back to \"camera-up-vector-is-up\" space\n offset.applyQuaternion( quatInverse );\n\n position.copy( this.target ).add( offset );\n\n this.object.lookAt( this.target );\n\n if ( this.enableDamping === true ) {\n\n thetaDelta *= ( 1 - this.dampingFactor );\n phiDelta *= ( 1 - this.dampingFactor );\n\n } else {\n\n thetaDelta = 0;\n phiDelta = 0;\n\n }\n\n scale = 1;\n panOffset.set( 0, 0, 0 );\n\n // update condition is:\n // min(camera displacement, camera rotation in radians)^2 > EPS\n // using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n if ( zoomChanged ||\n lastPosition.distanceToSquared( this.object.position ) > EPS ||\n 8 * ( 1 - lastQuaternion.dot( this.object.quaternion ) ) > EPS ) {\n\n lastPosition.copy( this.object.position );\n lastQuaternion.copy( this.object.quaternion );\n zoomChanged = false;\n\n return true;\n\n }\n\n return false;\n\n };\n\n }();\n\n };\n\n\n // This set of controls performs orbiting, dollying (zooming), and panning. It maintains\n // the \"up\" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is\n // supported.\n //\n // Orbit - left mouse / touch: one finger move\n // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish\n // Pan - right mouse, or arrow keys / touch: three finter swipe\n\n function OrbitControls ( object, domElement ) {\n\n var constraint = new OrbitConstraint( object );\n\n this.domElement = ( domElement !== undefined ) ? domElement : document;\n\n // API\n\n Object.defineProperty( this, 'constraint', {\n\n get: function() {\n\n return constraint;\n\n }\n\n } );\n\n this.getPolarAngle = function () {\n\n return constraint.getPolarAngle();\n\n };\n\n this.getAzimuthalAngle = function () {\n\n return constraint.getAzimuthalAngle();\n\n };\n\n // Set to false to disable this control\n this.enabled = true;\n\n // center is old, deprecated; use \"target\" instead\n this.center = this.target;\n\n // This option actually enables dollying in and out; left as \"zoom\" for\n // backwards compatibility.\n // Set to false to disable zooming\n this.enableZoom = true;\n this.zoomSpeed = 1.0;\n\n // Set to false to disable rotating\n this.enableRotate = true;\n this.rotateSpeed = 1.0;\n\n // Set to false to disable panning\n this.enablePan = true;\n this.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\n // Set to true to automatically rotate around the target\n // If auto-rotate is enabled, you must call controls.update() in your animation loop\n this.autoRotate = false;\n this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60\n\n // Set to false to disable use of the keys\n this.enableKeys = true;\n\n // The four arrow keys\n this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };\n\n // Mouse buttons\n this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };\n\n ////////////\n // internals\n\n var scope = this;\n\n var rotateStart = new THREE.Vector2();\n var rotateEnd = new THREE.Vector2();\n var rotateDelta = new THREE.Vector2();\n\n var panStart = new THREE.Vector2();\n var panEnd = new THREE.Vector2();\n var panDelta = new THREE.Vector2();\n\n var dollyStart = new THREE.Vector2();\n var dollyEnd = new THREE.Vector2();\n var dollyDelta = new THREE.Vector2();\n\n var STATE = { NONE : - 1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };\n\n var state = STATE.NONE;\n\n // for reset\n\n this.target0 = this.target.clone();\n this.position0 = this.object.position.clone();\n this.zoom0 = this.object.zoom;\n\n // events\n\n var changeEvent = { type: 'change' };\n var startEvent = { type: 'start' };\n var endEvent = { type: 'end' };\n\n // pass in x,y of change desired in pixel space,\n // right and down are positive\n function pan( deltaX, deltaY ) {\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n constraint.pan( deltaX, deltaY, element.clientWidth, element.clientHeight );\n\n }\n\n this.update = function () {\n\n if ( this.autoRotate && state === STATE.NONE ) {\n\n constraint.rotateLeft( getAutoRotationAngle() );\n\n }\n\n if ( constraint.update() === true ) {\n\n this.dispatchEvent( changeEvent );\n\n }\n\n };\n\n this.reset = function () {\n\n state = STATE.NONE;\n\n this.target.copy( this.target0 );\n this.object.position.copy( this.position0 );\n this.object.zoom = this.zoom0;\n\n this.object.updateProjectionMatrix();\n this.dispatchEvent( changeEvent );\n\n this.update();\n\n };\n\n function getAutoRotationAngle() {\n\n return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n }\n\n function getZoomScale() {\n\n return Math.pow( 0.95, scope.zoomSpeed );\n\n }\n\n function onMouseDown( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n\n if ( event.button === scope.mouseButtons.ORBIT ) {\n\n if ( scope.enableRotate === false ) return;\n\n state = STATE.ROTATE;\n\n rotateStart.set( event.clientX, event.clientY );\n\n } else if ( event.button === scope.mouseButtons.ZOOM ) {\n\n if ( scope.enableZoom === false ) return;\n\n state = STATE.DOLLY;\n\n dollyStart.set( event.clientX, event.clientY );\n\n } else if ( event.button === scope.mouseButtons.PAN ) {\n\n if ( scope.enablePan === false ) return;\n\n state = STATE.PAN;\n\n panStart.set( event.clientX, event.clientY );\n\n }\n\n if ( state !== STATE.NONE ) {\n\n document.addEventListener( 'mousemove', onMouseMove, false );\n document.addEventListener( 'mouseup', onMouseUp, false );\n scope.dispatchEvent( startEvent );\n\n }\n\n }\n\n function onMouseMove( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n if ( state === STATE.ROTATE ) {\n\n if ( scope.enableRotate === false ) return;\n\n rotateEnd.set( event.clientX, event.clientY );\n rotateDelta.subVectors( rotateEnd, rotateStart );\n\n // rotating across whole screen goes 360 degrees around\n constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n\n // rotating up and down along whole screen attempts to go 360, but limited to 180\n constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n rotateStart.copy( rotateEnd );\n\n } else if ( state === STATE.DOLLY ) {\n\n if ( scope.enableZoom === false ) return;\n\n dollyEnd.set( event.clientX, event.clientY );\n dollyDelta.subVectors( dollyEnd, dollyStart );\n\n if ( dollyDelta.y > 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n } else if ( dollyDelta.y < 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n }\n\n dollyStart.copy( dollyEnd );\n\n } else if ( state === STATE.PAN ) {\n\n if ( scope.enablePan === false ) return;\n\n panEnd.set( event.clientX, event.clientY );\n panDelta.subVectors( panEnd, panStart );\n\n pan( panDelta.x, panDelta.y );\n\n panStart.copy( panEnd );\n\n }\n\n if ( state !== STATE.NONE ) scope.update();\n\n }\n\n function onMouseUp( /* event */ ) {\n\n if ( scope.enabled === false ) return;\n\n document.removeEventListener( 'mousemove', onMouseMove, false );\n document.removeEventListener( 'mouseup', onMouseUp, false );\n scope.dispatchEvent( endEvent );\n state = STATE.NONE;\n\n }\n\n function onMouseWheel( event ) {\n\n if ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n var delta = 0;\n\n if ( event.wheelDelta !== undefined ) {\n\n // WebKit / Opera / Explorer 9\n\n delta = event.wheelDelta;\n\n } else if ( event.detail !== undefined ) {\n\n // Firefox\n\n delta = - event.detail;\n\n }\n\n if ( delta > 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n } else if ( delta < 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n }\n\n scope.update();\n scope.dispatchEvent( startEvent );\n scope.dispatchEvent( endEvent );\n\n }\n\n function onKeyDown( event ) {\n\n if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;\n\n switch ( event.keyCode ) {\n\n case scope.keys.UP:\n pan( 0, scope.keyPanSpeed );\n scope.update();\n break;\n\n case scope.keys.BOTTOM:\n pan( 0, - scope.keyPanSpeed );\n scope.update();\n break;\n\n case scope.keys.LEFT:\n pan( scope.keyPanSpeed, 0 );\n scope.update();\n break;\n\n case scope.keys.RIGHT:\n pan( - scope.keyPanSpeed, 0 );\n scope.update();\n break;\n\n }\n\n }\n\n function touchstart( event ) {\n\n if ( scope.enabled === false ) return;\n\n switch ( event.touches.length ) {\n\n case 1:\t// one-fingered touch: rotate\n\n if ( scope.enableRotate === false ) return;\n\n state = STATE.TOUCH_ROTATE;\n\n rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n break;\n\n case 2:\t// two-fingered touch: dolly\n\n if ( scope.enableZoom === false ) return;\n\n state = STATE.TOUCH_DOLLY;\n\n var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n var distance = Math.sqrt( dx * dx + dy * dy );\n dollyStart.set( 0, distance );\n break;\n\n case 3: // three-fingered touch: pan\n\n if ( scope.enablePan === false ) return;\n\n state = STATE.TOUCH_PAN;\n\n panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n break;\n\n default:\n\n state = STATE.NONE;\n\n }\n\n if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );\n\n }\n\n function touchmove( event ) {\n\n if ( scope.enabled === false ) return;\n\n event.preventDefault();\n event.stopPropagation();\n\n var element = scope.domElement === document ? scope.domElement.body : scope.domElement;\n\n switch ( event.touches.length ) {\n\n case 1: // one-fingered touch: rotate\n\n if ( scope.enableRotate === false ) return;\n if ( state !== STATE.TOUCH_ROTATE ) return;\n\n rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n rotateDelta.subVectors( rotateEnd, rotateStart );\n\n // rotating across whole screen goes 360 degrees around\n constraint.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );\n // rotating up and down along whole screen attempts to go 360, but limited to 180\n constraint.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );\n\n rotateStart.copy( rotateEnd );\n\n scope.update();\n break;\n\n case 2: // two-fingered touch: dolly\n\n if ( scope.enableZoom === false ) return;\n if ( state !== STATE.TOUCH_DOLLY ) return;\n\n var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;\n var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;\n var distance = Math.sqrt( dx * dx + dy * dy );\n\n dollyEnd.set( 0, distance );\n dollyDelta.subVectors( dollyEnd, dollyStart );\n\n if ( dollyDelta.y > 0 ) {\n\n constraint.dollyOut( getZoomScale() );\n\n } else if ( dollyDelta.y < 0 ) {\n\n constraint.dollyIn( getZoomScale() );\n\n }\n\n dollyStart.copy( dollyEnd );\n\n scope.update();\n break;\n\n case 3: // three-fingered touch: pan\n\n if ( scope.enablePan === false ) return;\n if ( state !== STATE.TOUCH_PAN ) return;\n\n panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );\n panDelta.subVectors( panEnd, panStart );\n\n pan( panDelta.x, panDelta.y );\n\n panStart.copy( panEnd );\n\n scope.update();\n break;\n\n default:\n\n state = STATE.NONE;\n\n }\n\n }\n\n function touchend( /* event */ ) {\n\n if ( scope.enabled === false ) return;\n\n scope.dispatchEvent( endEvent );\n state = STATE.NONE;\n\n }\n\n function contextmenu( event ) {\n\n event.preventDefault();\n\n }\n\n this.dispose = function() {\n\n this.domElement.removeEventListener( 'contextmenu', contextmenu, false );\n this.domElement.removeEventListener( 'mousedown', onMouseDown, false );\n this.domElement.removeEventListener( 'mousewheel', onMouseWheel, false );\n this.domElement.removeEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox\n\n this.domElement.removeEventListener( 'touchstart', touchstart, false );\n this.domElement.removeEventListener( 'touchend', touchend, false );\n this.domElement.removeEventListener( 'touchmove', touchmove, false );\n\n document.removeEventListener( 'mousemove', onMouseMove, false );\n document.removeEventListener( 'mouseup', onMouseUp, false );\n\n window.removeEventListener( 'keydown', onKeyDown, false );\n\n }\n\n this.domElement.addEventListener( 'contextmenu', contextmenu, false );\n\n this.domElement.addEventListener( 'mousedown', onMouseDown, false );\n this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );\n this.domElement.addEventListener( 'MozMousePixelScroll', onMouseWheel, false ); // firefox\n\n this.domElement.addEventListener( 'touchstart', touchstart, false );\n this.domElement.addEventListener( 'touchend', touchend, false );\n this.domElement.addEventListener( 'touchmove', touchmove, false );\n\n window.addEventListener( 'keydown', onKeyDown, false );\n\n // force an update at start\n this.update();\n\n };\n\n OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );\n OrbitControls.prototype.constructor = OrbitControls;\n\n Object.defineProperties( OrbitControls.prototype, {\n\n object: {\n\n get: function () {\n\n return this.constraint.object;\n\n }\n\n },\n\n target: {\n\n get: function () {\n\n return this.constraint.target;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: target is now immutable. Use target.set() instead.' );\n this.constraint.target.copy( value );\n\n }\n\n },\n\n minDistance : {\n\n get: function () {\n\n return this.constraint.minDistance;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minDistance = value;\n\n }\n\n },\n\n maxDistance : {\n\n get: function () {\n\n return this.constraint.maxDistance;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxDistance = value;\n\n }\n\n },\n\n minZoom : {\n\n get: function () {\n\n return this.constraint.minZoom;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minZoom = value;\n\n }\n\n },\n\n maxZoom : {\n\n get: function () {\n\n return this.constraint.maxZoom;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxZoom = value;\n\n }\n\n },\n\n minPolarAngle : {\n\n get: function () {\n\n return this.constraint.minPolarAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minPolarAngle = value;\n\n }\n\n },\n\n maxPolarAngle : {\n\n get: function () {\n\n return this.constraint.maxPolarAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxPolarAngle = value;\n\n }\n\n },\n\n minAzimuthAngle : {\n\n get: function () {\n\n return this.constraint.minAzimuthAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.minAzimuthAngle = value;\n\n }\n\n },\n\n maxAzimuthAngle : {\n\n get: function () {\n\n return this.constraint.maxAzimuthAngle;\n\n },\n\n set: function ( value ) {\n\n this.constraint.maxAzimuthAngle = value;\n\n }\n\n },\n\n enableDamping : {\n\n get: function () {\n\n return this.constraint.enableDamping;\n\n },\n\n set: function ( value ) {\n\n this.constraint.enableDamping = value;\n\n }\n\n },\n\n dampingFactor : {\n\n get: function () {\n\n return this.constraint.dampingFactor;\n\n },\n\n set: function ( value ) {\n\n this.constraint.dampingFactor = value;\n\n }\n\n },\n\n // backward compatibility\n\n noZoom: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n return ! this.enableZoom;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.' );\n this.enableZoom = ! value;\n\n }\n\n },\n\n noRotate: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n return ! this.enableRotate;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.' );\n this.enableRotate = ! value;\n\n }\n\n },\n\n noPan: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n return ! this.enablePan;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noPan has been deprecated. Use .enablePan instead.' );\n this.enablePan = ! value;\n\n }\n\n },\n\n noKeys: {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n return ! this.enableKeys;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.' );\n this.enableKeys = ! value;\n\n }\n\n },\n\n staticMoving : {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n return ! this.constraint.enableDamping;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.' );\n this.constraint.enableDamping = ! value;\n\n }\n\n },\n\n dynamicDampingFactor : {\n\n get: function () {\n\n console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n return this.constraint.dampingFactor;\n\n },\n\n set: function ( value ) {\n\n console.warn( 'THREE.OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.' );\n this.constraint.dampingFactor = value;\n\n }\n\n }\n\n } );\n\n return OrbitControls;\n}\n","import TWEEN from 'tween.js';\r\n\r\n// This object contains the state of the app\r\nexport default {\r\n isDev: false,\r\n isShowingStats: true,\r\n isLoaded: false,\r\n isTweening: false,\r\n isRotating: true,\r\n isMouseMoving: false,\r\n isMouseOver: false,\r\n maxAnisotropy: 1,\r\n dpr: 1,\r\n easing: TWEEN.Easing.Quadratic.InOut,\r\n duration: 500,\r\n model: {\r\n path: './assets/models/Teapot.json',\r\n scale: 20\r\n },\r\n texture: {\r\n path: './assets/textures/',\r\n imageFiles: [\r\n {name: 'UV', image: 'UV_Grid_Sm.jpg'}\r\n ]\r\n },\r\n mesh: {\r\n enableHelper: false,\r\n wireframe: false,\r\n translucent: false,\r\n material: {\r\n color: 0xffffff,\r\n emissive: 0xffffff\r\n }\r\n },\r\n fog: {\r\n color: 0xffffff,\r\n near: 0.0008\r\n },\r\n camera: {\r\n fov: 40,\r\n near: 2,\r\n far: 1000,\r\n aspect: 1,\r\n posX: 0,\r\n posY: 30,\r\n posZ: 40\r\n },\r\n controls: {\r\n autoRotate: true,\r\n autoRotateSpeed: -0.5,\r\n rotateSpeed: 0.5,\r\n zoomSpeed: 0.8,\r\n minDistance: 200,\r\n maxDistance: 600,\r\n minPolarAngle: Math.PI / 5,\r\n maxPolarAngle: Math.PI / 2,\r\n minAzimuthAngle: -Infinity,\r\n maxAzimuthAngle: Infinity,\r\n enableDamping: true,\r\n dampingFactor: 0.5,\r\n enableZoom: true,\r\n target: {\r\n x: 0,\r\n y: 0,\r\n z: 0\r\n }\r\n },\r\n ambientLight: {\r\n enabled: true,\r\n color: 0x141414\r\n },\r\n directionalLight: {\r\n enabled: true,\r\n color: 0xf0f0f0,\r\n intensity: 0.4,\r\n x: -75,\r\n y: 280,\r\n z: 150\r\n },\r\n shadow: {\r\n enabled: true,\r\n helperEnabled: true,\r\n bias: 0,\r\n mapWidth: 2048,\r\n mapHeight: 2048,\r\n near: 250,\r\n far: 400,\r\n top: 100,\r\n right: 100,\r\n bottom: -100,\r\n left: -100\r\n },\r\n pointLight: {\r\n enabled: true,\r\n color: 0xffffff,\r\n intensity: 0.34,\r\n distance: 115,\r\n x: 0,\r\n y: 0,\r\n z: 0\r\n },\r\n hemiLight: {\r\n enabled: true,\r\n color: 0xc8c8c8,\r\n groundColor: 0xffffff,\r\n intensity: 0.55,\r\n x: 0,\r\n y: 0,\r\n z: 0\r\n }\r\n};\r\n","/**\r\n * @author alteredq / http://alteredqualia.com/\r\n * @author mr.doob / http://mrdoob.com/\r\n */\r\n\r\nexport default {\r\n canvas: !!window.CanvasRenderingContext2D,\r\n webgl: (function() {\r\n try {\r\n var canvas = document.createElement('canvas');\r\n\r\n return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));\r\n } catch(e) {\r\n return false;\r\n }\r\n })(),\r\n\r\n workers: !!window.Worker,\r\n fileapi: window.File && window.FileReader && window.FileList && window.Blob,\r\n\r\n getWebGLErrorMessage: function() {\r\n var element = document.createElement('div');\r\n element.id = 'webgl-error-message';\r\n element.style.fontFamily = 'monospace';\r\n element.style.fontSize = '13px';\r\n element.style.fontWeight = 'normal';\r\n element.style.textAlign = 'center';\r\n element.style.background = '#fff';\r\n element.style.color = '#000';\r\n element.style.padding = '1.5em';\r\n element.style.width = '400px';\r\n element.style.margin = '5em auto 0';\r\n\r\n if(!this.webgl) {\r\n element.innerHTML = window.WebGLRenderingContext ? [\r\n 'Your graphics card does not seem to support WebGL.
',\r\n 'Find out how to get it here.'\r\n ].join('\\n') : [\r\n 'Your browser does not seem to support WebGL.
',\r\n 'Find out how to get it here.'\r\n ].join('\\n');\r\n }\r\n\r\n return element;\r\n },\r\n\r\n addGetWebGLMessage: function(parameters) {\r\n var parent, id, element;\r\n\r\n parameters = parameters || {};\r\n\r\n parent = parameters.parent !== undefined ? parameters.parent : document.body;\r\n id = parameters.id !== undefined ? parameters.id : 'oldie';\r\n\r\n element = this.getWebGLErrorMessage();\r\n element.id = id;\r\n\r\n parent.appendChild(element);\r\n }\r\n};\r\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// Main webGL renderer class\nexport default class Renderer {\n constructor(scene, container) {\n // Properties\n this.scene = scene;\n this.container = container;\n\n // Create WebGL renderer and set its antialias\n this.threeRenderer = new THREE.WebGLRenderer({antialias: true});\n\n // Set clear color to fog to enable fog or to hex color for no fog\n this.threeRenderer.setClearColor(scene.fog.color);\n this.threeRenderer.setPixelRatio(window.devicePixelRatio); // For retina\n\n // Appends canvas\n container.appendChild(this.threeRenderer.domElement);\n\n // Shadow map options\n this.threeRenderer.shadowMap.enabled = true;\n this.threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;\n\n // Get anisotropy for textures\n Config.maxAnisotropy = this.threeRenderer.getMaxAnisotropy();\n\n // Initial size update set to canvas container\n this.updateSize();\n\n // Listeners\n document.addEventListener('DOMContentLoaded', () => this.updateSize(), false);\n window.addEventListener('resize', () => this.updateSize(), false);\n }\n\n updateSize() {\n this.threeRenderer.setSize(this.container.offsetWidth, this.container.offsetHeight);\n }\n\n render(scene, camera) {\n // Renders scene to canvas target\n this.threeRenderer.render(scene, camera);\n }\n}\n","import * as THREE from 'three';\r\n\r\nimport Config from '../../data/config';\r\n\r\n// Class that creates and updates the main camera\r\nexport default class Camera {\r\n constructor(renderer) {\r\n const width = renderer.domElement.width;\r\n const height = renderer.domElement.height;\r\n\r\n // Create and position a Perspective Camera\r\n this.threeCamera = new THREE.PerspectiveCamera(Config.camera.fov, width / height, Config.camera.near, Config.camera.far);\r\n this.threeCamera.position.set(Config.camera.posX, Config.camera.posY, Config.camera.posZ);\r\n\r\n // Initial sizing\r\n this.updateSize(renderer);\r\n \r\n // Listeners\r\n window.addEventListener('resize', () => this.updateSize(renderer), false);\r\n }\r\n\r\n updateSize(renderer) {\r\n // Update camera aspect ratio with window aspect ratio\r\n this.threeCamera.aspect = renderer.domElement.width / renderer.domElement.height;\r\n\r\n // Always call updateProjectionMatrix on camera change\r\n this.threeCamera.updateProjectionMatrix();\r\n }\r\n}\r\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// Sets up and places all lights in scene\nexport default class Light {\n constructor(scene) {\n this.scene = scene;\n\n this.init();\n }\n\n init() {\n // Ambient\n this.ambientLight = new THREE.AmbientLight(Config.ambientLight.color);\n this.ambientLight.visible = Config.ambientLight.enabled;\n\n // Point light\n this.pointLight = new THREE.PointLight(Config.pointLight.color, Config.pointLight.intensity, Config.pointLight.distance);\n this.pointLight.position.set(Config.pointLight.x, Config.pointLight.y, Config.pointLight.z);\n this.pointLight.visible = Config.pointLight.enabled;\n\n // Directional light\n this.directionalLight = new THREE.DirectionalLight(Config.directionalLight.color, Config.directionalLight.intensity);\n this.directionalLight.position.set(Config.directionalLight.x, Config.directionalLight.y, Config.directionalLight.z);\n this.directionalLight.visible = Config.directionalLight.enabled;\n\n // Shadow map\n this.directionalLight.castShadow = Config.shadow.enabled;\n this.directionalLight.shadow.bias = Config.shadow.bias;\n this.directionalLight.shadow.camera.near = Config.shadow.near;\n this.directionalLight.shadow.camera.far = Config.shadow.far;\n this.directionalLight.shadow.camera.left = Config.shadow.left;\n this.directionalLight.shadow.camera.right = Config.shadow.right;\n this.directionalLight.shadow.camera.top = Config.shadow.top;\n this.directionalLight.shadow.camera.bottom = Config.shadow.bottom;\n this.directionalLight.shadow.mapSize.width = Config.shadow.mapWidth;\n this.directionalLight.shadow.mapSize.height = Config.shadow.mapHeight;\n\n // Shadow camera helper\n this.directionalLightHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);\n this.directionalLightHelper.visible = Config.shadow.helperEnabled;\n\n // Hemisphere light\n this.hemiLight = new THREE.HemisphereLight(Config.hemiLight.color, Config.hemiLight.groundColor, Config.hemiLight.intensity);\n this.hemiLight.position.set(Config.hemiLight.x, Config.hemiLight.y, Config.hemiLight.z);\n this.hemiLight.visible = Config.hemiLight.enabled;\n }\n\n place(lightName) {\n switch(lightName) {\n case 'ambient':\n this.scene.add(this.ambientLight);\n break;\n\n case 'directional':\n this.scene.add(this.directionalLight);\n this.scene.add(this.directionalLightHelper);\n break;\n\n case 'point':\n this.scene.add(this.pointLight);\n break;\n\n case 'hemi':\n this.scene.add(this.hemiLight);\n break;\n }\n }\n}\n","import * as THREE from 'three';\n\nimport OrbitControls from '../../utils/orbitControls';\nimport Config from '../../data/config';\n\n// Controls based on orbit controls\nexport default class Controls {\n constructor(camera, container) {\n // Orbit controls first needs to pass in THREE to constructor\n const orbitControls = new OrbitControls(THREE);\n this.threeControls = new orbitControls(camera, container);\n\n this.init();\n }\n\n init() {\n this.threeControls.target.set(Config.controls.target.x, Config.controls.target.y, Config.controls.target.z);\n this.threeControls.autoRotate = Config.controls.autoRotate;\n this.threeControls.autoRotateSpeed = Config.controls.autoRotateSpeed;\n this.threeControls.rotateSpeed = Config.controls.rotateSpeed;\n this.threeControls.zoomSpeed = Config.controls.zoomSpeed;\n this.threeControls.minDistance = Config.controls.minDistance;\n this.threeControls.maxDistance = Config.controls.maxDistance;\n this.threeControls.minPolarAngle = Config.controls.minPolarAngle;\n this.threeControls.maxPolarAngle = Config.controls.maxPolarAngle;\n this.threeControls.enableDamping = Config.controls.enableDamping;\n this.threeControls.enableZoom = Config.controls.enableZoom;\n this.threeControls.dampingFactor = Config.controls.dampingFactor;\n }\n}\n","import * as THREE from 'three';\n\nimport Config from '../../data/config';\n\n// USe this class as a helper to set up some default materials\nexport default class Material {\n constructor(color) {\n this.basic = new THREE.MeshBasicMaterial({\n color,\n side: THREE.DoubleSide\n });\n\n this.standard = new THREE.MeshStandardMaterial({\n color,\n shading: THREE.FlatShading,\n roughness: 1,\n metalness: 0,\n side: THREE.DoubleSide\n });\n\n this.wire = new THREE.MeshBasicMaterial({wireframe: true});\n }\n}\n\n","// Local vars for rStats\r\nlet rS, bS, glS, tS;\r\n\r\nexport default class Stats {\r\n constructor(renderer) {\r\n this.renderer = renderer;\r\n }\r\n\r\n setUp() {\r\n bS = new BrowserStats();\r\n glS = new glStats();\r\n tS = new threeStats(this.renderer.threeRenderer);\r\n\r\n rS = new rStats({\r\n CSSPath: './css/',\r\n userTimingAPI: true,\r\n values: {\r\n frame: { caption: 'Total frame time (ms)', over: 16, average: true, avgMs: 100 },\r\n fps: { caption: 'Framerate (FPS)', below: 30 },\r\n calls: { caption: 'Calls (three.js)', over: 3000 },\r\n raf: { caption: 'Time since last rAF (ms)', average: true, avgMs: 100 },\r\n rstats: { caption: 'rStats update (ms)', average: true, avgMs: 100 },\r\n texture: { caption: 'GenTex', average: true, avgMs: 100 }\r\n },\r\n groups: [\r\n { caption: 'Framerate', values: ['fps', 'raf'] },\r\n { caption: 'Frame Budget', values: ['frame', 'texture', 'setup', 'render'] }\r\n ],\r\n fractions: [\r\n { base: 'frame', steps: ['texture', 'setup', 'render'] }\r\n ],\r\n plugins: [bS, tS, glS]\r\n });\r\n };\r\n\r\n static start() {\r\n rS('frame').start();\r\n glS.start();\r\n\r\n rS('rAF').tick();\r\n rS('FPS').frame();\r\n\r\n rS('render').start();\r\n };\r\n\r\n static end() {\r\n rS('render').end(); // render finished\r\n rS('frame').end(); // frame finished\r\n\r\n // Local rStats update\r\n rS('rStats').start();\r\n rS().update();\r\n rS('rStats').end();\r\n };\r\n}\r\n","import * as THREE from 'three';\n\nimport Material from './material';\n\nimport Config from '../../data/config';\n\n// This helper class can be used to create and then place geometry in the scene\nexport default class Geometry {\n constructor(scene) {\n this.scene = scene;\n this.geo = null;\n }\n\n make(type) {\n if(type === 'plane') {\n return (width, height, widthSegments = 1, heightSegments = 1) => {\n this.geo = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);\n };\n }\n\n if(type === 'sphere') {\n return (radius, widthSegments = 32, heightSegments = 32) => {\n this.geo = new THREE.SphereGeometry(radius, widthSegments, heightSegments);\n };\n }\n }\n\n place(position, rotation) {\n const material = new Material(0xeeeeee).standard;\n const mesh = new THREE.Mesh(this.geo, material);\n\n // Use ES6 spread to set position and rotation from passed in array\n mesh.position.set(...position);\n mesh.rotation.set(...rotation);\n\n if(Config.shadow.enabled) {\n mesh.receiveShadow = true;\n }\n\n this.scene.add(mesh);\n }\n}\n","// Provides simple static functions that are used multiple times in the app\nexport default class Helpers {\n static throttle(fn, threshhold, scope) {\n threshhold || (threshhold = 250);\n let last, deferTimer;\n\n return function() {\n const context = scope || this;\n\n const now = +new Date,\n args = arguments;\n\n if(last && now < last + threshhold) {\n clearTimeout(deferTimer);\n deferTimer = setTimeout(function() {\n last = now;\n fn.apply(context, args);\n }, threshhold);\n }\n else {\n last = now;\n fn.apply(context, args);\n }\n };\n }\n\n static logProgress() {\n return function(xhr) {\n if(xhr.lengthComputable) {\n const percentComplete = xhr.loaded / xhr.total * 100;\n\n console.log(Math.round(percentComplete, 2) + '% downloaded');\n }\n }\n }\n\n static logError() {\n return function(xhr) {\n console.error(xhr);\n }\n }\n\n static handleColorChange(color) {\n return (value) => {\n if(typeof value === 'string') {\n value = value.replace('#', '0x');\n }\n\n color.setHex(value);\n };\n }\n\n static update(mesh) {\n this.needsUpdate(mesh.material, mesh.geometry);\n }\n\n static needsUpdate(material, geometry) {\n return function() {\n material.shading = +material.shading; //Ensure number\n material.vertexColors = +material.vertexColors; //Ensure number\n material.side = +material.side; //Ensure number\n material.needsUpdate = true;\n geometry.verticesNeedUpdate = true;\n geometry.normalsNeedUpdate = true;\n geometry.colorsNeedUpdate = true;\n };\n }\n\n static updateTexture(material, materialKey, textures) {\n return function(key) {\n material[materialKey] = textures[key];\n material.needsUpdate = true;\n };\n }\n}\n","import * as THREE from 'three';\n// Promise polyfill for IE\nimport { Promise } from 'es6-promise';\n\nimport Helpers from '../../utils/helpers';\nimport Config from '../../data/config';\n\n// This class preloads all textures in the imageFiles array in the Config via ES6 Promises.\n// Once all textures are done loading the model itself will be loaded after the Promise .then() callback.\n// Using promises to preload textures prevents issues when applying textures to materials\n// before the textures have loaded.\nexport default class Texture {\n constructor() {\n // Prop that will contain all loaded textures\n this.textures = {};\n }\n\n load() {\n const loader = new THREE.TextureLoader();\n const maxAnisotropy = Config.maxAnisotropy;\n const imageFiles = Config.texture.imageFiles;\n const promiseArray = [];\n\n loader.setPath(Config.texture.path);\n\n imageFiles.forEach(imageFile => {\n // Add an individual Promise for each image in array\n promiseArray.push(new Promise((resolve, reject) => {\n // Each Promise will attempt to load the image file\n loader.load(imageFile.image,\n // This gets called on load with the loaded texture\n texture => {\n texture.anisotropy = maxAnisotropy;\n\n // Resolve Promise with object of texture if it is instance of THREE.Texture\n const modelOBJ = {};\n modelOBJ[imageFile.name] = texture;\n if(modelOBJ[imageFile.name] instanceof THREE.Texture)\n resolve(modelOBJ);\n },\n Helpers.logProgress(),\n xhr => reject(new Error(xhr + 'An error occurred loading while loading ' + imageFile.image))\n )\n }));\n });\n\n // Iterate through all Promises in array and return another Promise when all have resolved or console log reason when any reject\n return Promise.all(promiseArray).then(textures => {\n // Set the textures prop object to have name be the resolved texture\n for(let i = 0; i < textures.length; i++) {\n this.textures[Object.keys(textures[i])[0]] = textures[i][Object.keys(textures[i])[0]];\n }\n }, reason => console.log(reason));\n }\n}\n","import * as THREE from 'three';\n\n// Simple mesh helper that shows edges, wireframes, and face and vertex normals\nexport default class MeshHelper {\n constructor(scene, mesh) {\n const wireframe = new THREE.WireframeGeometry(mesh.geometry);\n const wireLine = new THREE.LineSegments(wireframe);\n wireLine.material.depthTest = false;\n wireLine.material.opacity = 0.25;\n wireLine.material.transparent = true;\n mesh.add(wireLine);\n\n const edges = new THREE.EdgesGeometry(mesh.geometry);\n const edgesLine = new THREE.LineSegments(edges);\n edgesLine.material.depthTest = false;\n edgesLine.material.opacity = 0.25;\n edgesLine.material.transparent = true;\n mesh.add(edgesLine);\n\n scene.add(new THREE.BoxHelper(mesh));\n scene.add(new THREE.FaceNormalsHelper(mesh, 2));\n scene.add(new THREE.VertexNormalsHelper(mesh, 2));\n }\n}\n","import * as THREE from 'three';\r\n\r\nimport Material from '../helpers/material';\r\nimport MeshHelper from '../helpers/meshHelper';\r\nimport Helpers from '../../utils/helpers';\r\nimport Config from '../../data/config';\r\n\r\n// Loads in a single object from the config file\r\nexport default class Model {\r\n constructor(scene, manager, textures) {\r\n this.scene = scene;\r\n this.textures = textures;\r\n\r\n // Manager is passed in to loader to determine when loading done in main\r\n this.loader = new THREE.ObjectLoader(manager);\r\n this.obj = null;\r\n }\r\n\r\n load() {\r\n // Load model with ObjectLoader\r\n this.loader.load(\r\n Config.model.path,\r\n obj => {\r\n obj.traverse(child => {\r\n if(child instanceof THREE.Mesh) {\r\n // Create material for mesh and set its map to texture by name from preloaded textures\r\n const material = new Material(0xffffff).standard;\r\n material.map = this.textures.UV;\r\n child.material = material;\r\n\r\n // Set to cast and receive shadow if enabled\r\n if(Config.shadow.enabled) {\r\n child.receiveShadow = true;\r\n child.castShadow = true;\r\n }\r\n }\r\n });\r\n\r\n // Add mesh helper if Dev\r\n if(Config.isDev && Config.mesh.enableHelper) {\r\n new MeshHelper(this.scene, obj);\r\n }\r\n\r\n // Set prop to obj so it can be accessed from outside the class\r\n this.obj = obj;\r\n\r\n obj.scale.multiplyScalar(Config.model.scale);\r\n this.scene.add(obj);\r\n },\r\n Helpers.logProgress(),\r\n Helpers.logError()\r\n );\r\n }\r\n}\r\n","const ALIAS = {\r\n 'left'\t\t: 37,\r\n 'up'\t\t : 38,\r\n 'right'\t\t: 39,\r\n 'down'\t\t: 40,\r\n 'space'\t\t: 32,\r\n 'tab'\t\t : 9,\r\n 'escape'\t: 27\r\n};\r\n\r\nexport default class Keyboard {\r\n constructor(domElement) {\r\n this.domElement = domElement || document;\r\n this.keyCodes = {};\r\n\r\n // bind keyEvents\r\n this.domElement.addEventListener('keydown', (event) => this.onKeyChange(event), false);\r\n this.domElement.addEventListener('keyup', (event) => this.onKeyChange(event), false);\r\n\r\n // bind window blur\r\n window.addEventListener('blur', () => this.onBlur, false);\r\n }\r\n\r\n destroy() {\r\n this.domElement.removeEventListener('keydown', (event) => this.onKeyChange(event), false);\r\n this.domElement.removeEventListener('keyup', (event) => this.onKeyChange(event), false);\r\n\r\n // unbind window blur event\r\n window.removeEventListener('blur', () => this.onBlur, false);\r\n }\r\n\r\n onBlur() {\r\n for(const prop in this.keyCodes)\r\n this.keyCodes[prop] = false;\r\n }\r\n\r\n onKeyChange(event) {\r\n // log to debug\r\n //console.log('onKeyChange', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)\r\n\r\n // update this.keyCodes\r\n const keyCode = event.keyCode;\r\n this.keyCodes[keyCode] = event.type === 'keydown';\r\n }\r\n\r\n pressed(keyDesc) {\r\n const keys = keyDesc.split('+');\r\n for(let i = 0; i < keys.length; i++) {\r\n const key = keys[i];\r\n let pressed = false;\r\n if(Object.keys(ALIAS).indexOf(key) != -1) {\r\n pressed = this.keyCodes[ALIAS[key]];\r\n } else {\r\n pressed = this.keyCodes[key.toUpperCase().charCodeAt(0)];\r\n }\r\n if(!pressed)\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n\r\n eventMatches(event, keyDesc) {\r\n const aliases = ALIAS;\r\n const aliasKeys = Object.keys(aliases);\r\n const keys = keyDesc.split('+');\r\n // log to debug\r\n // console.log('eventMatches', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)\r\n for(let i = 0; i < keys.length; i++) {\r\n const key = keys[i];\r\n let pressed = false;\r\n if(key === 'shift') {\r\n pressed = event.shiftKey ? true : false;\r\n } else if(key === 'ctrl') {\r\n pressed = event.ctrlKey ? true : false;\r\n } else if(key === 'alt') {\r\n pressed = event.altKey ? true : false;\r\n } else if(key === 'meta') {\r\n pressed = event.metaKey ? true : false;\r\n } else if(aliasKeys.indexOf(key) !== -1) {\r\n pressed = event.keyCode === aliases[key];\r\n } else if(event.keyCode === key.toUpperCase().charCodeAt(0)) {\r\n pressed = true;\r\n }\r\n if(!pressed)\r\n return false;\r\n }\r\n\r\n return true;\r\n }\r\n}\r\n","import Keyboard from '../../utils/keyboard';\nimport Helpers from '../../utils/helpers';\nimport Config from '../../data/config';\n\n// Manages all input interactions\nexport default class Interaction {\n constructor(renderer, scene, camera, controls) {\n // Properties\n this.renderer = renderer;\n this.scene = scene;\n this.camera = camera;\n this.controls = controls;\n\n this.timeout = null;\n\n // Instantiate keyboard helper\n this.keyboard = new Keyboard();\n\n // Listeners\n // Mouse events\n this.renderer.domElement.addEventListener('mousemove', (event) => Helpers.throttle(this.onMouseMove(event), 250), false);\n this.renderer.domElement.addEventListener('mouseleave', (event) => this.onMouseLeave(event), false);\n this.renderer.domElement.addEventListener('mouseover', (event) => this.onMouseOver(event), false);\n\n // Keyboard events\n this.keyboard.domElement.addEventListener('keydown', (event) => {\n // Only once\n if(event.repeat) {\n return;\n }\n\n if(this.keyboard.eventMatches(event, 'escape')) {\n console.log('Escape pressed');\n }\n });\n }\n\n onMouseOver(event) {\n event.preventDefault();\n\n Config.isMouseOver = true;\n }\n\n onMouseLeave(event) {\n event.preventDefault();\n\n Config.isMouseOver = false;\n }\n\n onMouseMove(event) {\n event.preventDefault();\n\n clearTimeout(this.timeout);\n\n this.timeout = setTimeout(function() {\n Config.isMouseMoving = false;\n }, 200);\n\n Config.isMouseMoving = true;\n }\n}\n","import Config from '../../data/config';\n\n// Manages all dat.GUI interactions\nexport default class DatGUI {\n constructor(main, mesh) {\n const gui = new dat.GUI();\n\n this.camera = main.camera.threeCamera;\n this.controls = main.controls.threeControls;\n this.light = main.light;\n\n /* Global */\n //gui.close();\n\n /* Camera */\n const cameraFolder = gui.addFolder('Camera');\n const cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV');\n cameraFOVGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.camera.fov = value;\n });\n cameraFOVGui.onFinishChange(() => {\n this.camera.updateProjectionMatrix();\n\n this.controls.enableRotate = true;\n });\n const cameraAspectGui = cameraFolder.add(Config.camera, 'aspect', 0, 4).name('Camera Aspect');\n cameraAspectGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.camera.aspect = value;\n });\n cameraAspectGui.onFinishChange(() => {\n this.camera.updateProjectionMatrix();\n\n this.controls.enableRotate = true;\n });\n const cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color');\n cameraFogColorGui.onChange((value) => {\n main.scene.fog.color.setHex(value);\n });\n const cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near');\n cameraFogNearGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n main.scene.fog.density = value;\n });\n cameraFogNearGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n /* Controls */\n const controlsFolder = gui.addFolder('Controls');\n controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => {\n this.controls.autoRotate = value;\n });\n const controlsAutoRotateSpeedGui = controlsFolder.add(Config.controls, 'autoRotateSpeed', -1, 1).name('Rotation Speed');\n controlsAutoRotateSpeedGui.onChange((value) => {\n this.controls.enableRotate = false;\n this.controls.autoRotateSpeed = value;\n });\n controlsAutoRotateSpeedGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n /* Mesh */\n const meshFolder = gui.addFolder('Mesh');\n meshFolder.add(Config.mesh, 'translucent', true).name('Translucent').onChange((value) => {\n if(value) {\n mesh.material.transparent = true;\n mesh.material.opacity = 0.5;\n } else {\n mesh.material.opacity = 1.0;\n }\n });\n meshFolder.add(Config.mesh, 'wireframe', true).name('Wireframe').onChange((value) => {\n mesh.material.wireframe = value;\n });\n\n\n /* Lights */\n // Ambient Light\n const ambientLightFolder = gui.addFolder('Ambient Light');\n ambientLightFolder.add(Config.ambientLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.ambientLight.visible = value;\n });\n ambientLightFolder.addColor(Config.ambientLight, 'color').name('Color').onChange((value) => {\n this.light.ambientLight.color.setHex(value);\n });\n\n\n // Directional Light\n const directionalLightFolder = gui.addFolder('Directional Light');\n directionalLightFolder.add(Config.directionalLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.directionalLight.visible = value;\n });\n directionalLightFolder.addColor(Config.directionalLight, 'color').name('Color').onChange((value) => {\n this.light.directionalLight.color.setHex(value);\n });\n const directionalLightIntensityGui = directionalLightFolder.add(Config.directionalLight, 'intensity', 0, 2).name('Intensity');\n directionalLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.intensity = value;\n });\n directionalLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionXGui = directionalLightFolder.add(Config.directionalLight, 'x', -1000, 1000).name('Position X');\n directionalLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.x = value;\n });\n directionalLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionYGui = directionalLightFolder.add(Config.directionalLight, 'y', -1000, 1000).name('Position Y');\n directionalLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.y = value;\n });\n directionalLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const directionalLightPositionZGui = directionalLightFolder.add(Config.directionalLight, 'z', -1000, 1000).name('Position Z');\n directionalLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.position.z = value;\n });\n directionalLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n // Shadow Map\n const shadowFolder = gui.addFolder('Shadow Map');\n shadowFolder.add(Config.shadow, 'enabled').name('Enabled').onChange((value) => {\n this.light.directionalLight.castShadow = value;\n });\n shadowFolder.add(Config.shadow, 'helperEnabled').name('Helper Enabled').onChange((value) => {\n this.light.directionalLightHelper.visible = value;\n });\n const shadowNearGui = shadowFolder.add(Config.shadow, 'near', 0, 400).name('Near');\n shadowNearGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.near = value;\n });\n shadowNearGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowFarGui = shadowFolder.add(Config.shadow, 'far', 0, 1200).name('Far');\n shadowFarGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.far = value;\n });\n shadowFarGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowTopGui = shadowFolder.add(Config.shadow, 'top', -400, 400).name('Top');\n shadowTopGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.top = value;\n });\n shadowTopGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowRightGui = shadowFolder.add(Config.shadow, 'right', -400, 400).name('Right');\n shadowRightGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.right = value;\n });\n shadowRightGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowBottomGui = shadowFolder.add(Config.shadow, 'bottom', -400, 400).name('Bottom');\n shadowBottomGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.bottom = value;\n });\n shadowBottomGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowLeftGui = shadowFolder.add(Config.shadow, 'left', -400, 400).name('Left');\n shadowLeftGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.camera.left = value;\n });\n shadowLeftGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n const shadowBiasGui = shadowFolder.add(Config.shadow, 'bias', -0.000010, 1).name('Bias');\n shadowBiasGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.directionalLight.shadow.bias = value;\n });\n shadowBiasGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n this.light.directionalLight.shadow.map.dispose();\n this.light.directionalLight.shadow.map = null;\n this.light.directionalLightHelper.update();\n });\n\n\n // Point Light\n const pointLightFolder = gui.addFolder('Point Light');\n pointLightFolder.add(Config.pointLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.pointLight.visible = value;\n });\n pointLightFolder.addColor(Config.pointLight, 'color').name('Color').onChange((value) => {\n this.light.pointLight.color.setHex(value);\n });\n const pointLightIntensityGui = pointLightFolder.add(Config.pointLight, 'intensity', 0, 2).name('Intensity');\n pointLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.intensity = value;\n });\n pointLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightDistanceGui = pointLightFolder.add(Config.pointLight, 'distance', 0, 1000).name('Distance');\n pointLightDistanceGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.distance = value;\n });\n pointLightDistanceGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionXGui = pointLightFolder.add(Config.pointLight, 'x', -1000, 1000).name('Position X');\n pointLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.x = value;\n });\n pointLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionYGui = pointLightFolder.add(Config.pointLight, 'y', -1000, 1000).name('Position Y');\n pointLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.y = value;\n });\n pointLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const pointLightPositionZGui = pointLightFolder.add(Config.pointLight, 'z', -1000, 1000).name('Position Z');\n pointLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.pointLight.position.z = value;\n });\n pointLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n\n\n // Hemi Light\n const hemiLightFolder = gui.addFolder('Hemi Light');\n hemiLightFolder.add(Config.hemiLight, 'enabled').name('Enabled').onChange((value) => {\n this.light.hemiLight.visible = value;\n });\n hemiLightFolder.addColor(Config.hemiLight, 'color').name('Color').onChange((value) => {\n this.light.hemiLight.color.setHex(value);\n });\n hemiLightFolder.addColor(Config.hemiLight, 'groundColor').name('ground Color').onChange((value) => {\n this.light.hemiLight.groundColor.setHex(value);\n });\n const hemiLightIntensityGui = hemiLightFolder.add(Config.hemiLight, 'intensity', 0, 2).name('Intensity');\n hemiLightIntensityGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.intensity = value;\n });\n hemiLightIntensityGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionXGui = hemiLightFolder.add(Config.hemiLight, 'x', -1000, 1000).name('Position X');\n hemiLightPositionXGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.x = value;\n });\n hemiLightPositionXGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionYGui = hemiLightFolder.add(Config.hemiLight, 'y', -500, 1000).name('Position Y');\n hemiLightPositionYGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.y = value;\n });\n hemiLightPositionYGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n const hemiLightPositionZGui = hemiLightFolder.add(Config.hemiLight, 'z', -1000, 1000).name('Position Z');\n hemiLightPositionZGui.onChange((value) => {\n this.controls.enableRotate = false;\n\n this.light.hemiLight.position.z = value;\n });\n hemiLightPositionZGui.onFinishChange(() => {\n this.controls.enableRotate = true;\n });\n }\n}\n","// Global imports -\nimport * as THREE from 'three';\nimport TWEEN from 'tween.js';\n\n// Local imports -\n// Components\nimport Renderer from './components/renderer';\nimport Camera from './components/camera';\nimport Light from './components/light';\nimport Controls from './components/controls';\n\n// Helpers\nimport Geometry from './helpers/geometry';\nimport Stats from './helpers/stats';\n\n// Model\nimport Texture from './model/texture';\nimport Model from './model/model';\n\n// Managers\nimport Interaction from './managers/interaction';\nimport DatGUI from './managers/datGUI';\n\n// data\nimport Config from './../data/config';\n// -- End of imports\n\n// This class instantiates and ties all of the components together, starts the loading process and renders the main loop\nexport default class Main {\n constructor(container) {\n // Set container property to container element\n this.container = container;\n\n // Start Three clock\n this.clock = new THREE.Clock();\n\n // Main scene creation\n this.scene = new THREE.Scene();\n this.scene.fog = new THREE.FogExp2(Config.fog.color, Config.fog.near);\n\n // Get Device Pixel Ratio first for retina\n if(window.devicePixelRatio) {\n Config.dpr = window.devicePixelRatio;\n }\n\n // Main renderer constructor\n this.renderer = new Renderer(this.scene, container);\n\n // Components instantiations\n this.camera = new Camera(this.renderer.threeRenderer);\n this.controls = new Controls(this.camera.threeCamera, container);\n this.light = new Light(this.scene);\n\n // Create and place lights in scene\n const lights = ['ambient', 'directional', 'point', 'hemi'];\n lights.forEach((light) => this.light.place(light));\n\n // Create and place geo in scene\n this.geometry = new Geometry(this.scene);\n this.geometry.make('plane')(150, 150, 10, 10);\n this.geometry.place([0, -20, 0], [Math.PI / 2, 0, 0]);\n\n // Set up rStats if dev environment\n if(Config.isDev && Config.isShowingStats) {\n this.stats = new Stats(this.renderer);\n this.stats.setUp();\n }\n\n // Instantiate texture class\n this.texture = new Texture();\n\n // Start loading the textures and then go on to load the model after the texture Promises have resolved\n this.texture.load().then(() => {\n this.manager = new THREE.LoadingManager();\n\n // Textures loaded, load model\n this.model = new Model(this.scene, this.manager, this.texture.textures);\n this.model.load();\n\n // onProgress callback\n this.manager.onProgress = (item, loaded, total) => {\n console.log(`${item}: ${loaded} ${total}`);\n };\n\n // All loaders done now\n this.manager.onLoad = () => {\n // Set up interaction manager with the app now that the model is finished loading\n new Interaction(this.renderer.threeRenderer, this.scene, this.camera.threeCamera, this.controls.threeControls);\n\n // Add dat.GUI controls if dev\n if(Config.isDev) {\n new DatGUI(this, this.model.obj);\n }\n\n // Everything is now fully loaded\n Config.isLoaded = true;\n this.container.querySelector('#loading').style.display = 'none';\n };\n });\n\n // Start render which does not wait for model fully loaded\n this.render();\n }\n\n render() {\n // Render rStats if Dev\n if(Config.isDev && Config.isShowingStats) {\n Stats.start();\n }\n\n // Call render function and pass in created scene and camera\n this.renderer.render(this.scene, this.camera.threeCamera);\n\n // rStats has finished determining render call now\n if(Config.isDev && Config.isShowingStats) {\n Stats.end();\n }\n\n // Delta time is sometimes needed for certain updates\n //const delta = this.clock.getDelta();\n\n // Call any vendor or module frame updates here\n TWEEN.update();\n this.controls.threeControls.update();\n\n // RAF\n requestAnimationFrame(this.render.bind(this)); // Bind the main class instead of window object\n }\n}\n","import Config from './data/config';\r\nimport Detector from './utils/detector';\r\nimport Main from './app/main';\r\n\r\n// Styles\r\nimport './../css/app.scss';\r\n\r\n// Check environment and set the Config helper\r\nif(__ENV__ === 'dev') {\r\n console.log('----- RUNNING IN DEV ENVIRONMENT! -----');\r\n\r\n Config.isDev = true;\r\n}\r\n\r\nfunction init() {\r\n // Check for webGL capabilities\r\n if(!Detector.webgl) {\r\n Detector.addGetWebGLMessage();\r\n } else {\r\n const container = document.getElementById('appContainer');\r\n new Main(container);\r\n }\r\n}\r\n\r\ninit();\r\n"],"sourceRoot":""}
\ No newline at end of file
diff --git a/build/js/2.app.js b/build/js/2.app.js
index 51eeaef..23a379f 100644
--- a/build/js/2.app.js
+++ b/build/js/2.app.js
@@ -1,13 +1,13 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[2],[function(t,e,n){"use strict";function r(){}n.r(e),n.d(e,"WebGLRenderTargetCube",function(){return Bn}),n.d(e,"WebGLRenderTarget",function(){return Dn}),n.d(e,"WebGLRenderer",function(){return ko}),n.d(e,"ShaderLib",function(){return $n}),n.d(e,"UniformsLib",function(){return Kn}),n.d(e,"UniformsUtils",function(){return Xn}),n.d(e,"ShaderChunk",function(){return Hn}),n.d(e,"FogExp2",function(){return Vo}),n.d(e,"Fog",function(){return jo}),n.d(e,"Scene",function(){return Wo}),n.d(e,"Sprite",function(){return Jo}),n.d(e,"LOD",function(){return Zo}),n.d(e,"SkinnedMesh",function(){return Qo}),n.d(e,"Skeleton",function(){return Ko}),n.d(e,"Bone",function(){return $o}),n.d(e,"Mesh",function(){return Gi}),n.d(e,"LineSegments",function(){return ns}),n.d(e,"LineLoop",function(){return rs}),n.d(e,"Line",function(){return es}),n.d(e,"Points",function(){return as}),n.d(e,"Group",function(){return vo}),n.d(e,"VideoTexture",function(){return os}),n.d(e,"DataTexture",function(){return Nn}),n.d(e,"DataTexture3D",function(){return Ki}),n.d(e,"CompressedTexture",function(){return ss}),n.d(e,"CubeTexture",function(){return Qi}),n.d(e,"CanvasTexture",function(){return cs}),n.d(e,"DepthTexture",function(){return us}),n.d(e,"Texture",function(){return On}),n.d(e,"AnimationLoader",function(){return $c}),n.d(e,"CompressedTextureLoader",function(){return tu}),n.d(e,"DataTextureLoader",function(){return eu}),n.d(e,"CubeTextureLoader",function(){return ru}),n.d(e,"TextureLoader",function(){return iu}),n.d(e,"ObjectLoader",function(){return Vu}),n.d(e,"MaterialLoader",function(){return Gu}),n.d(e,"BufferGeometryLoader",function(){return Hu}),n.d(e,"DefaultLoadingManager",function(){return Zc}),n.d(e,"LoadingManager",function(){return Jc}),n.d(e,"ImageLoader",function(){return nu}),n.d(e,"ImageBitmapLoader",function(){return Ku}),n.d(e,"FontLoader",function(){return nh}),n.d(e,"FileLoader",function(){return Kc}),n.d(e,"Loader",function(){return rh}),n.d(e,"LoaderUtils",function(){return Fu}),n.d(e,"Cache",function(){return Yc}),n.d(e,"AudioLoader",function(){return Eh}),n.d(e,"SpotLightShadow",function(){return Ru}),n.d(e,"SpotLight",function(){return Ou}),n.d(e,"PointLight",function(){return Iu}),n.d(e,"RectAreaLight",function(){return Uu}),n.d(e,"HemisphereLight",function(){return Pu}),n.d(e,"DirectionalLightShadow",function(){return Bu}),n.d(e,"DirectionalLight",function(){return Nu}),n.d(e,"AmbientLight",function(){return zu}),n.d(e,"LightShadow",function(){return Cu}),n.d(e,"Light",function(){return Lu}),n.d(e,"StereoCamera",function(){return Sh}),n.d(e,"PerspectiveCamera",function(){return xo}),n.d(e,"OrthographicCamera",function(){return Du}),n.d(e,"CubeCamera",function(){return Th}),n.d(e,"ArrayCamera",function(){return bo}),n.d(e,"Camera",function(){return yo}),n.d(e,"AudioListener",function(){return Lh}),n.d(e,"PositionalAudio",function(){return Ch}),n.d(e,"AudioContext",function(){return Mh}),n.d(e,"AudioAnalyser",function(){return Rh}),n.d(e,"Audio",function(){return Ph}),n.d(e,"VectorKeyframeTrack",function(){return Wc}),n.d(e,"StringKeyframeTrack",function(){return jc}),n.d(e,"QuaternionKeyframeTrack",function(){return Vc}),n.d(e,"NumberKeyframeTrack",function(){return Hc}),n.d(e,"ColorKeyframeTrack",function(){return Fc}),n.d(e,"BooleanKeyframeTrack",function(){return Gc}),n.d(e,"PropertyMixer",function(){return Oh}),n.d(e,"PropertyBinding",function(){return ml}),n.d(e,"KeyframeTrack",function(){return Uc}),n.d(e,"AnimationUtils",function(){return Ic}),n.d(e,"AnimationObjectGroup",function(){return gl}),n.d(e,"AnimationMixer",function(){return yl}),n.d(e,"AnimationClip",function(){return qc}),n.d(e,"Uniform",function(){return xl}),n.d(e,"InstancedBufferGeometry",function(){return bl}),n.d(e,"BufferGeometry",function(){return ri}),n.d(e,"Geometry",function(){return Ir}),n.d(e,"InterleavedBufferAttribute",function(){return Xo}),n.d(e,"InstancedInterleavedBuffer",function(){return wl}),n.d(e,"InterleavedBuffer",function(){return qo}),n.d(e,"InstancedBufferAttribute",function(){return _l}),n.d(e,"Face3",function(){return nr}),n.d(e,"Object3D",function(){return Er}),n.d(e,"Raycaster",function(){return Ml}),n.d(e,"Layers",function(){return ir}),n.d(e,"EventDispatcher",function(){return r}),n.d(e,"Clock",function(){return Ah}),n.d(e,"QuaternionLinearInterpolant",function(){return kc}),n.d(e,"LinearInterpolant",function(){return Nc}),n.d(e,"DiscreteInterpolant",function(){return zc}),n.d(e,"CubicInterpolant",function(){return Bc}),n.d(e,"Interpolant",function(){return Dc}),n.d(e,"Triangle",function(){return zi}),n.d(e,"Math",function(){return cn}),n.d(e,"Spherical",function(){return Tl}),n.d(e,"Cylindrical",function(){return Al}),n.d(e,"Plane",function(){return Gn}),n.d(e,"Frustum",function(){return Fn}),n.d(e,"Sphere",function(){return Un}),n.d(e,"Ray",function(){return Ni}),n.d(e,"Matrix4",function(){return hn}),n.d(e,"Matrix3",function(){return pn}),n.d(e,"Box3",function(){return zn}),n.d(e,"Box2",function(){return Ll}),n.d(e,"Line3",function(){return Pl}),n.d(e,"Euler",function(){return rr}),n.d(e,"Vector4",function(){return In}),n.d(e,"Vector3",function(){return dn}),n.d(e,"Vector2",function(){return un}),n.d(e,"Quaternion",function(){return ln}),n.d(e,"Color",function(){return Jn}),n.d(e,"ImmediateRenderObject",function(){return Cl}),n.d(e,"VertexNormalsHelper",function(){return Rl}),n.d(e,"SpotLightHelper",function(){return Ol}),n.d(e,"SkeletonHelper",function(){return Il}),n.d(e,"PointLightHelper",function(){return Dl}),n.d(e,"RectAreaLightHelper",function(){return Bl}),n.d(e,"HemisphereLightHelper",function(){return Nl}),n.d(e,"GridHelper",function(){return zl}),n.d(e,"PolarGridHelper",function(){return Ul}),n.d(e,"FaceNormalsHelper",function(){return Gl}),n.d(e,"DirectionalLightHelper",function(){return Fl}),n.d(e,"CameraHelper",function(){return Hl}),n.d(e,"BoxHelper",function(){return kl}),n.d(e,"Box3Helper",function(){return Vl}),n.d(e,"PlaneHelper",function(){return jl}),n.d(e,"ArrowHelper",function(){return Wl}),n.d(e,"AxesHelper",function(){return ql}),n.d(e,"Shape",function(){return Au}),n.d(e,"Path",function(){return Tu}),n.d(e,"ShapePath",function(){return $u}),n.d(e,"Font",function(){return th}),n.d(e,"CurvePath",function(){return Su}),n.d(e,"Curve",function(){return au}),n.d(e,"ImageUtils",function(){return Cn}),n.d(e,"ShapeUtils",function(){return Zs}),n.d(e,"WebGLUtils",function(){return go}),n.d(e,"WireframeGeometry",function(){return hs}),n.d(e,"ParametricGeometry",function(){return ls}),n.d(e,"ParametricBufferGeometry",function(){return ds}),n.d(e,"TetrahedronGeometry",function(){return ms}),n.d(e,"TetrahedronBufferGeometry",function(){return gs}),n.d(e,"OctahedronGeometry",function(){return vs}),n.d(e,"OctahedronBufferGeometry",function(){return ys}),n.d(e,"IcosahedronGeometry",function(){return xs}),n.d(e,"IcosahedronBufferGeometry",function(){return bs}),n.d(e,"DodecahedronGeometry",function(){return ws}),n.d(e,"DodecahedronBufferGeometry",function(){return _s}),n.d(e,"PolyhedronGeometry",function(){return ps}),n.d(e,"PolyhedronBufferGeometry",function(){return fs}),n.d(e,"TubeGeometry",function(){return Ms}),n.d(e,"TubeBufferGeometry",function(){return Es}),n.d(e,"TorusKnotGeometry",function(){return Ss}),n.d(e,"TorusKnotBufferGeometry",function(){return Ts}),n.d(e,"TorusGeometry",function(){return As}),n.d(e,"TorusBufferGeometry",function(){return Ls}),n.d(e,"TextGeometry",function(){return rc}),n.d(e,"TextBufferGeometry",function(){return ic}),n.d(e,"SphereGeometry",function(){return ac}),n.d(e,"SphereBufferGeometry",function(){return oc}),n.d(e,"RingGeometry",function(){return sc}),n.d(e,"RingBufferGeometry",function(){return cc}),n.d(e,"PlaneGeometry",function(){return oi}),n.d(e,"PlaneBufferGeometry",function(){return si}),n.d(e,"LatheGeometry",function(){return uc}),n.d(e,"LatheBufferGeometry",function(){return hc}),n.d(e,"ShapeGeometry",function(){return lc}),n.d(e,"ShapeBufferGeometry",function(){return dc}),n.d(e,"ExtrudeGeometry",function(){return $s}),n.d(e,"ExtrudeBufferGeometry",function(){return tc}),n.d(e,"EdgesGeometry",function(){return fc}),n.d(e,"ConeGeometry",function(){return vc}),n.d(e,"ConeBufferGeometry",function(){return yc}),n.d(e,"CylinderGeometry",function(){return mc}),n.d(e,"CylinderBufferGeometry",function(){return gc}),n.d(e,"CircleGeometry",function(){return xc}),n.d(e,"CircleBufferGeometry",function(){return bc}),n.d(e,"BoxGeometry",function(){return ii}),n.d(e,"BoxBufferGeometry",function(){return ai}),n.d(e,"ShadowMaterial",function(){return _c}),n.d(e,"SpriteMaterial",function(){return Yo}),n.d(e,"RawShaderMaterial",function(){return Mc}),n.d(e,"ShaderMaterial",function(){return Bi}),n.d(e,"PointsMaterial",function(){return is}),n.d(e,"MeshPhysicalMaterial",function(){return Sc}),n.d(e,"MeshStandardMaterial",function(){return Ec}),n.d(e,"MeshPhongMaterial",function(){return Tc}),n.d(e,"MeshToonMaterial",function(){return Ac}),n.d(e,"MeshNormalMaterial",function(){return Lc}),n.d(e,"MeshLambertMaterial",function(){return Pc}),n.d(e,"MeshDepthMaterial",function(){return ho}),n.d(e,"MeshDistanceMaterial",function(){return lo}),n.d(e,"MeshBasicMaterial",function(){return Ui}),n.d(e,"MeshMatcapMaterial",function(){return Cc}),n.d(e,"LineDashedMaterial",function(){return Rc}),n.d(e,"LineBasicMaterial",function(){return ts}),n.d(e,"Material",function(){return Di}),n.d(e,"Float64BufferAttribute",function(){return Vr}),n.d(e,"Float32BufferAttribute",function(){return kr}),n.d(e,"Uint32BufferAttribute",function(){return Hr}),n.d(e,"Int32BufferAttribute",function(){return Fr}),n.d(e,"Uint16BufferAttribute",function(){return Gr}),n.d(e,"Int16BufferAttribute",function(){return Ur}),n.d(e,"Uint8ClampedBufferAttribute",function(){return zr}),n.d(e,"Uint8BufferAttribute",function(){return Nr}),n.d(e,"Int8BufferAttribute",function(){return Br}),n.d(e,"BufferAttribute",function(){return Dr}),n.d(e,"ArcCurve",function(){return su}),n.d(e,"CatmullRomCurve3",function(){return pu}),n.d(e,"CubicBezierCurve",function(){return vu}),n.d(e,"CubicBezierCurve3",function(){return yu}),n.d(e,"EllipseCurve",function(){return ou}),n.d(e,"LineCurve",function(){return xu}),n.d(e,"LineCurve3",function(){return bu}),n.d(e,"QuadraticBezierCurve",function(){return wu}),n.d(e,"QuadraticBezierCurve3",function(){return _u}),n.d(e,"SplineCurve",function(){return Mu}),n.d(e,"REVISION",function(){return _t}),n.d(e,"MOUSE",function(){return T}),n.d(e,"CullFaceNone",function(){return q}),n.d(e,"CullFaceBack",function(){return X}),n.d(e,"CullFaceFront",function(){return Y}),n.d(e,"CullFaceFrontBack",function(){return A}),n.d(e,"FrontFaceDirectionCW",function(){return L}),n.d(e,"FrontFaceDirectionCCW",function(){return P}),n.d(e,"BasicShadowMap",function(){return C}),n.d(e,"PCFShadowMap",function(){return G}),n.d(e,"PCFSoftShadowMap",function(){return F}),n.d(e,"FrontSide",function(){return B}),n.d(e,"BackSide",function(){return Mt}),n.d(e,"DoubleSide",function(){return tt}),n.d(e,"FlatShading",function(){return R}),n.d(e,"SmoothShading",function(){return O}),n.d(e,"NoColors",function(){return I}),n.d(e,"FaceColors",function(){return D}),n.d(e,"VertexColors",function(){return N}),n.d(e,"NoBlending",function(){return J}),n.d(e,"NormalBlending",function(){return Z}),n.d(e,"AdditiveBlending",function(){return Q}),n.d(e,"SubtractiveBlending",function(){return K}),n.d(e,"MultiplyBlending",function(){return $}),n.d(e,"CustomBlending",function(){return et}),n.d(e,"AddEquation",function(){return nt}),n.d(e,"SubtractEquation",function(){return z}),n.d(e,"ReverseSubtractEquation",function(){return U}),n.d(e,"MinEquation",function(){return H}),n.d(e,"MaxEquation",function(){return k}),n.d(e,"ZeroFactor",function(){return V}),n.d(e,"OneFactor",function(){return j}),n.d(e,"SrcColorFactor",function(){return W}),n.d(e,"OneMinusSrcColorFactor",function(){return rt}),n.d(e,"SrcAlphaFactor",function(){return it}),n.d(e,"OneMinusSrcAlphaFactor",function(){return at}),n.d(e,"DstAlphaFactor",function(){return ot}),n.d(e,"OneMinusDstAlphaFactor",function(){return st}),n.d(e,"DstColorFactor",function(){return ct}),n.d(e,"OneMinusDstColorFactor",function(){return ut}),n.d(e,"SrcAlphaSaturateFactor",function(){return ht}),n.d(e,"NeverDepth",function(){return lt}),n.d(e,"AlwaysDepth",function(){return dt}),n.d(e,"LessDepth",function(){return pt}),n.d(e,"LessEqualDepth",function(){return ft}),n.d(e,"EqualDepth",function(){return mt}),n.d(e,"GreaterEqualDepth",function(){return gt}),n.d(e,"GreaterDepth",function(){return vt}),n.d(e,"NotEqualDepth",function(){return yt}),n.d(e,"MultiplyOperation",function(){return xt}),n.d(e,"MixOperation",function(){return bt}),n.d(e,"AddOperation",function(){return wt}),n.d(e,"NoToneMapping",function(){return Et}),n.d(e,"LinearToneMapping",function(){return St}),n.d(e,"ReinhardToneMapping",function(){return Tt}),n.d(e,"Uncharted2ToneMapping",function(){return At}),n.d(e,"CineonToneMapping",function(){return Lt}),n.d(e,"ACESFilmicToneMapping",function(){return Pt}),n.d(e,"UVMapping",function(){return Ct}),n.d(e,"CubeReflectionMapping",function(){return Rt}),n.d(e,"CubeRefractionMapping",function(){return Ot}),n.d(e,"EquirectangularReflectionMapping",function(){return It}),n.d(e,"EquirectangularRefractionMapping",function(){return Dt}),n.d(e,"SphericalReflectionMapping",function(){return Bt}),n.d(e,"CubeUVReflectionMapping",function(){return Nt}),n.d(e,"CubeUVRefractionMapping",function(){return zt}),n.d(e,"RepeatWrapping",function(){return Ut}),n.d(e,"ClampToEdgeWrapping",function(){return Gt}),n.d(e,"MirroredRepeatWrapping",function(){return Ft}),n.d(e,"NearestFilter",function(){return Ht}),n.d(e,"NearestMipMapNearestFilter",function(){return kt}),n.d(e,"NearestMipMapLinearFilter",function(){return Vt}),n.d(e,"LinearFilter",function(){return jt}),n.d(e,"LinearMipMapNearestFilter",function(){return Wt}),n.d(e,"LinearMipMapLinearFilter",function(){return qt}),n.d(e,"UnsignedByteType",function(){return Xt}),n.d(e,"ByteType",function(){return Yt}),n.d(e,"ShortType",function(){return Jt}),n.d(e,"UnsignedShortType",function(){return Zt}),n.d(e,"IntType",function(){return Qt}),n.d(e,"UnsignedIntType",function(){return Kt}),n.d(e,"FloatType",function(){return $t}),n.d(e,"HalfFloatType",function(){return te}),n.d(e,"UnsignedShort4444Type",function(){return ee}),n.d(e,"UnsignedShort5551Type",function(){return ne}),n.d(e,"UnsignedShort565Type",function(){return re}),n.d(e,"UnsignedInt248Type",function(){return ie}),n.d(e,"AlphaFormat",function(){return ae}),n.d(e,"RGBFormat",function(){return oe}),n.d(e,"RGBAFormat",function(){return se}),n.d(e,"LuminanceFormat",function(){return ce}),n.d(e,"LuminanceAlphaFormat",function(){return ue}),n.d(e,"RGBEFormat",function(){return he}),n.d(e,"DepthFormat",function(){return le}),n.d(e,"DepthStencilFormat",function(){return de}),n.d(e,"RedFormat",function(){return pe}),n.d(e,"RGB_S3TC_DXT1_Format",function(){return fe}),n.d(e,"RGBA_S3TC_DXT1_Format",function(){return me}),n.d(e,"RGBA_S3TC_DXT3_Format",function(){return ge}),n.d(e,"RGBA_S3TC_DXT5_Format",function(){return ve}),n.d(e,"RGB_PVRTC_4BPPV1_Format",function(){return ye}),n.d(e,"RGB_PVRTC_2BPPV1_Format",function(){return xe}),n.d(e,"RGBA_PVRTC_4BPPV1_Format",function(){return be}),n.d(e,"RGBA_PVRTC_2BPPV1_Format",function(){return we}),n.d(e,"RGB_ETC1_Format",function(){return _e}),n.d(e,"RGBA_ASTC_4x4_Format",function(){return Me}),n.d(e,"RGBA_ASTC_5x4_Format",function(){return Ee}),n.d(e,"RGBA_ASTC_5x5_Format",function(){return Se}),n.d(e,"RGBA_ASTC_6x5_Format",function(){return Te}),n.d(e,"RGBA_ASTC_6x6_Format",function(){return Ae}),n.d(e,"RGBA_ASTC_8x5_Format",function(){return Le}),n.d(e,"RGBA_ASTC_8x6_Format",function(){return Pe}),n.d(e,"RGBA_ASTC_8x8_Format",function(){return Ce}),n.d(e,"RGBA_ASTC_10x5_Format",function(){return Re}),n.d(e,"RGBA_ASTC_10x6_Format",function(){return Oe}),n.d(e,"RGBA_ASTC_10x8_Format",function(){return Ie}),n.d(e,"RGBA_ASTC_10x10_Format",function(){return De}),n.d(e,"RGBA_ASTC_12x10_Format",function(){return Be}),n.d(e,"RGBA_ASTC_12x12_Format",function(){return Ne}),n.d(e,"LoopOnce",function(){return ze}),n.d(e,"LoopRepeat",function(){return Ue}),n.d(e,"LoopPingPong",function(){return Ge}),n.d(e,"InterpolateDiscrete",function(){return Fe}),n.d(e,"InterpolateLinear",function(){return He}),n.d(e,"InterpolateSmooth",function(){return ke}),n.d(e,"ZeroCurvatureEnding",function(){return Ve}),n.d(e,"ZeroSlopeEnding",function(){return je}),n.d(e,"WrapAroundEnding",function(){return We}),n.d(e,"TrianglesDrawMode",function(){return qe}),n.d(e,"TriangleStripDrawMode",function(){return Xe}),n.d(e,"TriangleFanDrawMode",function(){return Ye}),n.d(e,"LinearEncoding",function(){return Je}),n.d(e,"sRGBEncoding",function(){return Ze}),n.d(e,"GammaEncoding",function(){return Qe}),n.d(e,"RGBEEncoding",function(){return Ke}),n.d(e,"LogLuvEncoding",function(){return $e}),n.d(e,"RGBM7Encoding",function(){return tn}),n.d(e,"RGBM16Encoding",function(){return en}),n.d(e,"RGBDEncoding",function(){return nn}),n.d(e,"BasicDepthPacking",function(){return rn}),n.d(e,"RGBADepthPacking",function(){return an}),n.d(e,"TangentSpaceNormalMap",function(){return on}),n.d(e,"ObjectSpaceNormalMap",function(){return sn}),n.d(e,"CubeGeometry",function(){return ii}),n.d(e,"Face4",function(){return Xl}),n.d(e,"LineStrip",function(){return Jl}),n.d(e,"LinePieces",function(){return Zl}),n.d(e,"MeshFaceMaterial",function(){return Ql}),n.d(e,"MultiMaterial",function(){return Kl}),n.d(e,"PointCloud",function(){return $l}),n.d(e,"Particle",function(){return td}),n.d(e,"ParticleSystem",function(){return ed}),n.d(e,"PointCloudMaterial",function(){return nd}),n.d(e,"ParticleBasicMaterial",function(){return rd}),n.d(e,"ParticleSystemMaterial",function(){return id}),n.d(e,"Vertex",function(){return ad}),n.d(e,"DynamicBufferAttribute",function(){return od}),n.d(e,"Int8Attribute",function(){return sd}),n.d(e,"Uint8Attribute",function(){return cd}),n.d(e,"Uint8ClampedAttribute",function(){return ud}),n.d(e,"Int16Attribute",function(){return hd}),n.d(e,"Uint16Attribute",function(){return ld}),n.d(e,"Int32Attribute",function(){return dd}),n.d(e,"Uint32Attribute",function(){return pd}),n.d(e,"Float32Attribute",function(){return fd}),n.d(e,"Float64Attribute",function(){return md}),n.d(e,"ClosedSplineCurve3",function(){return gd}),n.d(e,"SplineCurve3",function(){return vd}),n.d(e,"Spline",function(){return yd}),n.d(e,"AxisHelper",function(){return xd}),n.d(e,"BoundingBoxHelper",function(){return bd}),n.d(e,"EdgesHelper",function(){return wd}),n.d(e,"WireframeHelper",function(){return _d}),n.d(e,"XHRLoader",function(){return Md}),n.d(e,"BinaryTextureLoader",function(){return Ed}),n.d(e,"GeometryUtils",function(){return Sd}),n.d(e,"Projector",function(){return Td}),n.d(e,"CanvasRenderer",function(){return Ad}),n.d(e,"JSONLoader",function(){return Ld}),n.d(e,"SceneUtils",function(){return Pd}),n.d(e,"LensFlare",function(){return Cd}),void 0===Number.EPSILON&&(Number.EPSILON=Math.pow(2,-52)),void 0===Number.isInteger&&(Number.isInteger=function(t){return"number"==typeof t&&isFinite(t)&&Math.floor(t)===t}),void 0===Math.sign&&(Math.sign=function(t){return t<0?-1:0>8&255]+i[t>>16&255]+i[t>>24&255]+"-"+i[255&e]+i[e>>8&255]+"-"+i[e>>16&15|64]+i[e>>24&255]+"-"+i[63&n|128]+i[n>>8&255]+"-"+i[n>>16&255]+i[n>>24&255]+i[255&r]+i[r>>8&255]+i[r>>16&255]+i[r>>24&255]).toUpperCase()}}(),clamp:function(t,e,n){return Math.max(e,Math.min(n,t))},euclideanModulo:function(t,e){return(t%e+e)%e},mapLinear:function(t,e,n,r,i){return r+(t-e)*(i-r)/(n-e)},lerp:function(t,e,n){return(1-n)*t+n*e},smoothstep:function(t,e,n){return t<=e?0:n<=t?1:(t=(t-e)/(n-e))*t*(3-2*t)},smootherstep:function(t,e,n){return t<=e?0:n<=t?1:(t=(t-e)/(n-e))*t*t*(t*(6*t-15)+10)},randInt:function(t,e){return t+Math.floor(Math.random()*(e-t+1))},randFloat:function(t,e){return t+Math.random()*(e-t)},randFloatSpread:function(t){return t*(.5-Math.random())},degToRad:function(t){return t*cn.DEG2RAD},radToDeg:function(t){return t*cn.RAD2DEG},isPowerOfTwo:function(t){return 0==(t&t-1)&&0!==t},ceilPowerOfTwo:function(t){return Math.pow(2,Math.ceil(Math.log(t)/Math.LN2))},floorPowerOfTwo:function(t){return Math.pow(2,Math.floor(Math.log(t)/Math.LN2))}};function un(t,e){this.x=t||0,this.y=e||0}function hn(){this.elements=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],0Number.EPSILON){var x=Math.sqrt(y),b=Math.atan2(x,g*v);m=Math.sin(m*b)/x,o=Math.sin(o*b)/x}var w=o*v;if(s=s*m+l*w,c=c*m+d*w,u=u*m+p*w,h=h*m+f*w,m===1-o){var _=1/Math.sqrt(s*s+c*c+u*u+h*h);s*=_,c*=_,u*=_,h*=_}}t[e]=s,t[e+1]=c,t[e+2]=u,t[e+3]=h}}),Object.defineProperties(ln.prototype,{x:{get:function(){return this._x},set:function(t){this._x=t,this.onChangeCallback()}},y:{get:function(){return this._y},set:function(t){this._y=t,this.onChangeCallback()}},z:{get:function(){return this._z},set:function(t){this._z=t,this.onChangeCallback()}},w:{get:function(){return this._w},set:function(t){this._w=t,this.onChangeCallback()}}}),Object.assign(ln.prototype,{isQuaternion:!0,set:function(t,e,n,r){return this._x=t,this._y=e,this._z=n,this._w=r,this.onChangeCallback(),this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(t){return this._x=t.x,this._y=t.y,this._z=t.z,this._w=t.w,this.onChangeCallback(),this},setFromEuler:function(t,e){if(!t||!t.isEuler)throw new Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var n=t._x,r=t._y,i=t._z,a=t.order,o=Math.cos,s=Math.sin,c=o(n/2),u=o(r/2),h=o(i/2),l=s(n/2),d=s(r/2),p=s(i/2);return"XYZ"===a?(this._x=l*u*h+c*d*p,this._y=c*d*h-l*u*p,this._z=c*u*p+l*d*h,this._w=c*u*h-l*d*p):"YXZ"===a?(this._x=l*u*h+c*d*p,this._y=c*d*h-l*u*p,this._z=c*u*p-l*d*h,this._w=c*u*h+l*d*p):"ZXY"===a?(this._x=l*u*h-c*d*p,this._y=c*d*h+l*u*p,this._z=c*u*p+l*d*h,this._w=c*u*h-l*d*p):"ZYX"===a?(this._x=l*u*h-c*d*p,this._y=c*d*h+l*u*p,this._z=c*u*p-l*d*h,this._w=c*u*h+l*d*p):"YZX"===a?(this._x=l*u*h+c*d*p,this._y=c*d*h+l*u*p,this._z=c*u*p-l*d*h,this._w=c*u*h-l*d*p):"XZY"===a&&(this._x=l*u*h-c*d*p,this._y=c*d*h-l*u*p,this._z=c*u*p+l*d*h,this._w=c*u*h+l*d*p),!1!==e&&this.onChangeCallback(),this},setFromAxisAngle:function(t,e){var n=e/2,r=Math.sin(n);return this._x=t.x*r,this._y=t.y*r,this._z=t.z*r,this._w=Math.cos(n),this.onChangeCallback(),this},setFromRotationMatrix:function(t){var e,n=t.elements,r=n[0],i=n[4],a=n[8],o=n[1],s=n[5],c=n[9],u=n[2],h=n[6],l=n[10],d=r+s+l;return this._z=0Math.abs(t.z)?g.set(-t.y,t.x,0):g.set(0,-t.z,t.y)):g.crossVectors(t,e),this._x=g.x,this._y=g.y,this._z=g.z,this._w=m,this.normalize()}),angleTo:function(t){return 2*Math.acos(Math.abs(cn.clamp(this.dot(t),-1,1)))},rotateTowards:function(t,e){var n=this.angleTo(t);if(0===n)return this;var r=Math.min(1,e/n);return this.slerp(t,r),this},inverse:function(){return this.conjugate()},conjugate:function(){return this._x*=-1,this._y*=-1,this._z*=-1,this.onChangeCallback(),this},dot:function(t){return this._x*t._x+this._y*t._y+this._z*t._z+this._w*t._w},lengthSq:function(){return this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w},length:function(){return Math.sqrt(this._x*this._x+this._y*this._y+this._z*this._z+this._w*this._w)},normalize:function(){var t=this.length();return this._w=0===t?(this._x=0,this._y=0,this._z=0,1):(t=1/t,this._x=this._x*t,this._y=this._y*t,this._z=this._z*t,this._w*t),this.onChangeCallback(),this},multiply:function(t,e){return void 0!==e?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(t,e)):this.multiplyQuaternions(this,t)},premultiply:function(t){return this.multiplyQuaternions(t,this)},multiplyQuaternions:function(t,e){var n=t._x,r=t._y,i=t._z,a=t._w,o=e._x,s=e._y,c=e._z,u=e._w;return this._x=n*u+a*o+r*c-i*s,this._y=r*u+a*s+i*o-n*c,this._z=i*u+a*c+n*s-r*o,this._w=a*u-n*o-r*s-i*c,this.onChangeCallback(),this},slerp:function(t,e){if(0===e)return this;if(1===e)return this.copy(t);var n=this._x,r=this._y,i=this._z,a=this._w,o=a*t._w+n*t._x+r*t._y+i*t._z;if(o<0?(this._w=-t._w,this._x=-t._x,this._y=-t._y,this._z=-t._z,o=-o):this.copy(t),1<=o)return this._w=a,this._x=n,this._y=r,this._z=i,this;var s=1-o*o;if(s<=Number.EPSILON){var c=1-e;return this._w=c*a+e*this._w,this._x=c*n+e*this._x,this._y=c*r+e*this._y,this._z=c*i+e*this._z,this.normalize()}var u=Math.sqrt(s),h=Math.atan2(u,o),l=Math.sin((1-e)*h)/u,d=Math.sin(e*h)/u;return this._w=a*l+this._w*d,this._x=n*l+this._x*d,this._y=r*l+this._y*d,this._z=i*l+this._z*d,this.onChangeCallback(),this},equals:function(t){return t._x===this._x&&t._y===this._y&&t._z===this._z&&t._w===this._w},fromArray:function(t,e){return void 0===e&&(e=0),this._x=t[e],this._y=t[e+1],this._z=t[e+2],this._w=t[e+3],this.onChangeCallback(),this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this._x,t[e+1]=this._y,t[e+2]=this._z,t[e+3]=this._w,t},onChange:function(t){return this.onChangeCallback=t,this},onChangeCallback:function(){}}),Object.assign(dn.prototype,{isVector3:!0,set:function(t,e,n){return this.x=t,this.y=e,this.z=n,this},setScalar:function(t){return this.x=t,this.y=t,this.z=t,this},setX:function(t){return this.x=t,this},setY:function(t){return this.y=t,this},setZ:function(t){return this.z=t,this},setComponent:function(t,e){switch(t){case 0:this.x=e;break;case 1:this.y=e;break;case 2:this.z=e;break;default:throw new Error("index is out of range: "+t)}return this},getComponent:function(t){switch(t){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw new Error("index is out of range: "+t)}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(t){return this.x=t.x,this.y=t.y,this.z=t.z,this},add:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(t,e)):(this.x+=t.x,this.y+=t.y,this.z+=t.z,this)},addScalar:function(t){return this.x+=t,this.y+=t,this.z+=t,this},addVectors:function(t,e){return this.x=t.x+e.x,this.y=t.y+e.y,this.z=t.z+e.z,this},addScaledVector:function(t,e){return this.x+=t.x*e,this.y+=t.y*e,this.z+=t.z*e,this},sub:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(t,e)):(this.x-=t.x,this.y-=t.y,this.z-=t.z,this)},subScalar:function(t){return this.x-=t,this.y-=t,this.z-=t,this},subVectors:function(t,e){return this.x=t.x-e.x,this.y=t.y-e.y,this.z=t.z-e.z,this},multiply:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(t,e)):(this.x*=t.x,this.y*=t.y,this.z*=t.z,this)},multiplyScalar:function(t){return this.x*=t,this.y*=t,this.z*=t,this},multiplyVectors:function(t,e){return this.x=t.x*e.x,this.y=t.y*e.y,this.z=t.z*e.z,this},applyEuler:(M=new ln,function(t){return t&&t.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order."),this.applyQuaternion(M.setFromEuler(t))}),applyAxisAngle:(_=new ln,function(t,e){return this.applyQuaternion(_.setFromAxisAngle(t,e))}),applyMatrix3:function(t){var e=this.x,n=this.y,r=this.z,i=t.elements;return this.x=i[0]*e+i[3]*n+i[6]*r,this.y=i[1]*e+i[4]*n+i[7]*r,this.z=i[2]*e+i[5]*n+i[8]*r,this},applyMatrix4:function(t){var e=this.x,n=this.y,r=this.z,i=t.elements,a=1/(i[3]*e+i[7]*n+i[11]*r+i[15]);return this.x=(i[0]*e+i[4]*n+i[8]*r+i[12])*a,this.y=(i[1]*e+i[5]*n+i[9]*r+i[13])*a,this.z=(i[2]*e+i[6]*n+i[10]*r+i[14])*a,this},applyQuaternion:function(t){var e=this.x,n=this.y,r=this.z,i=t.x,a=t.y,o=t.z,s=t.w,c=s*e+a*r-o*n,u=s*n+o*e-i*r,h=s*r+i*n-a*e,l=-i*e-a*n-o*r;return this.x=c*s+l*-i+u*-o-h*-a,this.y=u*s+l*-a+h*-i-c*-o,this.z=h*s+l*-o+c*-a-u*-i,this},project:function(t){return this.applyMatrix4(t.matrixWorldInverse).applyMatrix4(t.projectionMatrix)},unproject:(w=new hn,function(t){return this.applyMatrix4(w.getInverse(t.projectionMatrix)).applyMatrix4(t.matrixWorld)}),transformDirection:function(t){var e=this.x,n=this.y,r=this.z,i=t.elements;return this.x=i[0]*e+i[4]*n+i[8]*r,this.y=i[1]*e+i[5]*n+i[9]*r,this.z=i[2]*e+i[6]*n+i[10]*r,this.normalize()},divide:function(t){return this.x/=t.x,this.y/=t.y,this.z/=t.z,this},divideScalar:function(t){return this.multiplyScalar(1/t)},min:function(t){return this.x=Math.min(this.x,t.x),this.y=Math.min(this.y,t.y),this.z=Math.min(this.z,t.z),this},max:function(t){return this.x=Math.max(this.x,t.x),this.y=Math.max(this.y,t.y),this.z=Math.max(this.z,t.z),this},clamp:function(t,e){return this.x=Math.max(t.x,Math.min(e.x,this.x)),this.y=Math.max(t.y,Math.min(e.y,this.y)),this.z=Math.max(t.z,Math.min(e.z,this.z)),this},clampScalar:(x=new dn,b=new dn,function(t,e){return x.set(t,t,t),b.set(e,e,e),this.clamp(x,b)}),clampLength:function(t,e){var n=this.length();return this.divideScalar(n||1).multiplyScalar(Math.max(t,Math.min(e,n)))},floor:function(){return this.x=Math.floor(this.x),this.y=Math.floor(this.y),this.z=Math.floor(this.z),this},ceil:function(){return this.x=Math.ceil(this.x),this.y=Math.ceil(this.y),this.z=Math.ceil(this.z),this},round:function(){return this.x=Math.round(this.x),this.y=Math.round(this.y),this.z=Math.round(this.z),this},roundToZero:function(){return this.x=this.x<0?Math.ceil(this.x):Math.floor(this.x),this.y=this.y<0?Math.ceil(this.y):Math.floor(this.y),this.z=this.z<0?Math.ceil(this.z):Math.floor(this.z),this},negate:function(){return this.x=-this.x,this.y=-this.y,this.z=-this.z,this},dot:function(t){return this.x*t.x+this.y*t.y+this.z*t.z},lengthSq:function(){return this.x*this.x+this.y*this.y+this.z*this.z},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y+this.z*this.z)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(t){return this.normalize().multiplyScalar(t)},lerp:function(t,e){return this.x+=(t.x-this.x)*e,this.y+=(t.y-this.y)*e,this.z+=(t.z-this.z)*e,this},lerpVectors:function(t,e,n){return this.subVectors(e,t).multiplyScalar(n).add(t)},cross:function(t,e){return void 0!==e?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(t,e)):this.crossVectors(this,t)},crossVectors:function(t,e){var n=t.x,r=t.y,i=t.z,a=e.x,o=e.y,s=e.z;return this.x=r*s-i*o,this.y=i*a-n*s,this.z=n*o-r*a,this},projectOnVector:function(t){var e=t.dot(this)/t.lengthSq();return this.copy(t).multiplyScalar(e)},projectOnPlane:(y=new dn,function(t){return y.copy(this).projectOnVector(t),this.sub(y)}),reflect:(v=new dn,function(t){return this.sub(v.copy(t).multiplyScalar(2*this.dot(t)))}),angleTo:function(t){var e=this.dot(t)/Math.sqrt(this.lengthSq()*t.lengthSq());return Math.acos(cn.clamp(e,-1,1))},distanceTo:function(t){return Math.sqrt(this.distanceToSquared(t))},distanceToSquared:function(t){var e=this.x-t.x,n=this.y-t.y,r=this.z-t.z;return e*e+n*n+r*r},manhattanDistanceTo:function(t){return Math.abs(this.x-t.x)+Math.abs(this.y-t.y)+Math.abs(this.z-t.z)},setFromSpherical:function(t){return this.setFromSphericalCoords(t.radius,t.phi,t.theta)},setFromSphericalCoords:function(t,e,n){var r=Math.sin(e)*t;return this.x=r*Math.sin(n),this.y=Math.cos(e)*t,this.z=r*Math.cos(n),this},setFromCylindrical:function(t){return this.setFromCylindricalCoords(t.radius,t.theta,t.y)},setFromCylindricalCoords:function(t,e,n){return this.x=t*Math.sin(e),this.y=n,this.z=t*Math.cos(e),this},setFromMatrixPosition:function(t){var e=t.elements;return this.x=e[12],this.y=e[13],this.z=e[14],this},setFromMatrixScale:function(t){var e=this.setFromMatrixColumn(t,0).length(),n=this.setFromMatrixColumn(t,1).length(),r=this.setFromMatrixColumn(t,2).length();return this.x=e,this.y=n,this.z=r,this},setFromMatrixColumn:function(t,e){return this.fromArray(t.elements,4*e)},equals:function(t){return t.x===this.x&&t.y===this.y&&t.z===this.z},fromArray:function(t,e){return void 0===e&&(e=0),this.x=t[e],this.y=t[e+1],this.z=t[e+2],this},toArray:function(t,e){return void 0===t&&(t=[]),void 0===e&&(e=0),t[e]=this.x,t[e+1]=this.y,t[e+2]=this.z,t},fromBufferAttribute:function(t,e,n){return void 0!==n&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute()."),this.x=t.getX(e),this.y=t.getY(e),this.z=t.getZ(e),this}}),Object.assign(pn.prototype,{isMatrix3:!0,set:function(t,e,n,r,i,a,o,s,c){var u=this.elements;return u[0]=t,u[1]=r,u[2]=o,u[3]=e,u[4]=i,u[5]=s,u[6]=n,u[7]=a,u[8]=c,this},identity:function(){return this.set(1,0,0,0,1,0,0,0,1),this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(t){var e=this.elements,n=t.elements;return e[0]=n[0],e[1]=n[1],e[2]=n[2],e[3]=n[3],e[4]=n[4],e[5]=n[5],e[6]=n[6],e[7]=n[7],e[8]=n[8],this},setFromMatrix4:function(t){var e=t.elements;return this.set(e[0],e[4],e[8],e[1],e[5],e[9],e[2],e[6],e[10]),this},applyToBufferAttribute:(E=new dn,function(t){for(var e=0,n=t.count;ethis.max.x||t.ythis.max.y||t.zthis.max.z)},containsBox:function(t){return this.min.x<=t.min.x&&t.max.x<=this.max.x&&this.min.y<=t.min.y&&t.max.y<=this.max.y&&this.min.z<=t.min.z&&t.max.z<=this.max.z},getParameter:function(t,e){return void 0===e&&(console.warn("THREE.Box3: .getParameter() target is now required"),e=new dn),e.set((t.x-this.min.x)/(this.max.x-this.min.x),(t.y-this.min.y)/(this.max.y-this.min.y),(t.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(t){return!(t.max.xthis.max.x||t.max.ythis.max.y||t.max.zthis.max.z)},intersectsSphere:(xn=new dn,function(t){return this.clampPoint(t.center,xn),xn.distanceToSquared(t.center)<=t.radius*t.radius}),intersectsPlane:function(t){var e,n;return n=0=-t.constant},intersectsTriangle:function(){var s=new dn,c=new dn,u=new dn,n=new dn,r=new dn,i=new dn,h=new dn,a=new dn,l=new dn,o=new dn;function d(t){var e,n;for(e=0,n=t.length-3;e<=n;e+=3){h.fromArray(t,e);var r=l.x*Math.abs(h.x)+l.y*Math.abs(h.y)+l.z*Math.abs(h.z),i=s.dot(h),a=c.dot(h),o=u.dot(h);if(Math.max(-Math.max(i,a,o),Math.min(i,a,o))>r)return!1}return!0}return function(t){if(this.isEmpty())return!1;this.getCenter(a),l.subVectors(this.max,a),s.subVectors(t.a,a),c.subVectors(t.b,a),u.subVectors(t.c,a),n.subVectors(c,s),r.subVectors(u,c),i.subVectors(s,u);var e=[0,-n.z,n.y,0,-r.z,r.y,0,-i.z,i.y,n.z,0,-n.x,r.z,0,-r.x,i.z,0,-i.x,-n.y,n.x,0,-r.y,r.x,0,-i.y,i.x,0];return!!d(e)&&(!!d(e=[1,0,0,0,1,0,0,0,1])&&(o.crossVectors(n,r),d(e=[o.x,o.y,o.z])))}}(),clampPoint:function(t,e){return void 0===e&&(console.warn("THREE.Box3: .clampPoint() target is now required"),e=new dn),e.copy(t).clamp(this.min,this.max)},distanceToPoint:(yn=new dn,function(t){return yn.copy(t).clamp(this.min,this.max).sub(t).length()}),getBoundingSphere:(vn=new dn,function(t){return void 0===t&&(console.warn("THREE.Box3: .getBoundingSphere() target is now required"),t=new Un),this.getCenter(t.center),t.radius=.5*this.getSize(vn).length(),t}),intersect:function(t){return this.min.max(t.min),this.max.min(t.max),this.isEmpty()&&this.makeEmpty(),this},union:function(t){return this.min.min(t.min),this.max.max(t.max),this},applyMatrix4:(gn=[new dn,new dn,new dn,new dn,new dn,new dn,new dn,new dn],function(t){return this.isEmpty()||(gn[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(t),gn[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(t),gn[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(t),gn[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(t),gn[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(t),gn[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(t),gn[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(t),gn[7].set(this.max.x,this.max.y,this.max.z).applyMatrix4(t),this.setFromPoints(gn)),this}),translate:function(t){return this.min.add(t),this.max.add(t),this},equals:function(t){return t.min.equals(this.min)&&t.max.equals(this.max)}}),Object.assign(Un.prototype,{set:function(t,e){return this.center.copy(t),this.radius=e,this},setFromPoints:(wn=new zn,function(t,e){var n=this.center;void 0!==e?n.copy(e):wn.setFromPoints(t).getCenter(n);for(var r=0,i=0,a=t.length;ithis.radius*this.radius&&(e.sub(this.center).normalize(),e.multiplyScalar(this.radius).add(this.center)),e},getBoundingBox:function(t){return void 0===t&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),t=new zn),t.set(this.center,this.center),t.expandByScalar(this.radius),t},applyMatrix4:function(t){return this.center.applyMatrix4(t),this.radius=this.radius*t.getMaxScaleOnAxis(),this},translate:function(t){return this.center.add(t),this},equals:function(t){return t.center.equals(this.center)&&t.radius===this.radius}}),Object.assign(Gn.prototype,{set:function(t,e){return this.normal.copy(t),this.constant=e,this},setComponents:function(t,e,n,r){return this.normal.set(t,e,n),this.constant=r,this},setFromNormalAndCoplanarPoint:function(t,e){return this.normal.copy(t),this.constant=-e.dot(this.normal),this},setFromCoplanarPoints:(Sn=new dn,Tn=new dn,function(t,e,n){var r=Sn.subVectors(n,e).cross(Tn.subVectors(t,e)).normalize();return this.setFromNormalAndCoplanarPoint(r,t),this}),clone:function(){return(new this.constructor).copy(this)},copy:function(t){return this.normal.copy(t.normal),this.constant=t.constant,this},normalize:function(){var t=1/this.normal.length();return this.normal.multiplyScalar(t),this.constant*=t,this},negate:function(){return this.constant*=-1,this.normal.negate(),this},distanceToPoint:function(t){return this.normal.dot(t)+this.constant},distanceToSphere:function(t){return this.distanceToPoint(t.center)-t.radius},projectPoint:function(t,e){return void 0===e&&(console.warn("THREE.Plane: .projectPoint() target is now required"),e=new dn),e.copy(this.normal).multiplyScalar(-this.distanceToPoint(t)).add(t)},intersectLine:(En=new dn,function(t,e){void 0===e&&(console.warn("THREE.Plane: .intersectLine() target is now required"),e=new dn);var n=t.delta(En),r=this.normal.dot(n);if(0===r)return 0===this.distanceToPoint(t.start)?e.copy(t.start):void 0;var i=-(t.start.dot(this.normal)+this.constant)/r;return i<0||1 0.0 ) {\n\t\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\n\t}\n\treturn distanceFalloff;\n#else\n\tif( cutoffDistance > 0.0 && decayExponent > 0.0 ) {\n\t\treturn pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );\n\t}\n\treturn 1.0;\n#endif\n}\nvec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {\n\treturn RECIPROCAL_PI * diffuseColor;\n}\nvec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );\n\treturn ( 1.0 - specularColor ) * fresnel + specularColor;\n}\nfloat G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\tfloat gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\treturn 1.0 / ( gl * gv );\n}\nfloat G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {\n\tfloat a2 = pow2( alpha );\n\tfloat gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );\n\tfloat gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );\n\treturn 0.5 / max( gv + gl, EPSILON );\n}\nfloat D_GGX( const in float alpha, const in float dotNH ) {\n\tfloat a2 = pow2( alpha );\n\tfloat denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;\n\treturn RECIPROCAL_PI * a2 / pow2( denom );\n}\nvec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );\n\tfloat D = D_GGX( alpha, dotNH );\n\treturn F * ( G * D );\n}\nvec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {\n\tconst float LUT_SIZE = 64.0;\n\tconst float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;\n\tconst float LUT_BIAS = 0.5 / LUT_SIZE;\n\tfloat dotNV = saturate( dot( N, V ) );\n\tvec2 uv = vec2( roughness, sqrt( 1.0 - dotNV ) );\n\tuv = uv * LUT_SCALE + LUT_BIAS;\n\treturn uv;\n}\nfloat LTC_ClippedSphereFormFactor( const in vec3 f ) {\n\tfloat l = length( f );\n\treturn max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );\n}\nvec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {\n\tfloat x = dot( v1, v2 );\n\tfloat y = abs( x );\n\tfloat a = 0.8543985 + ( 0.4965155 + 0.0145206 * y ) * y;\n\tfloat b = 3.4175940 + ( 4.1616724 + y ) * y;\n\tfloat v = a / b;\n\tfloat theta_sintheta = ( x > 0.0 ) ? v : 0.5 * inversesqrt( max( 1.0 - x * x, 1e-7 ) ) - v;\n\treturn cross( v1, v2 ) * theta_sintheta;\n}\nvec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {\n\tvec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];\n\tvec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];\n\tvec3 lightNormal = cross( v1, v2 );\n\tif( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );\n\tvec3 T1, T2;\n\tT1 = normalize( V - N * dot( V, N ) );\n\tT2 = - cross( N, T1 );\n\tmat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );\n\tvec3 coords[ 4 ];\n\tcoords[ 0 ] = mat * ( rectCoords[ 0 ] - P );\n\tcoords[ 1 ] = mat * ( rectCoords[ 1 ] - P );\n\tcoords[ 2 ] = mat * ( rectCoords[ 2 ] - P );\n\tcoords[ 3 ] = mat * ( rectCoords[ 3 ] - P );\n\tcoords[ 0 ] = normalize( coords[ 0 ] );\n\tcoords[ 1 ] = normalize( coords[ 1 ] );\n\tcoords[ 2 ] = normalize( coords[ 2 ] );\n\tcoords[ 3 ] = normalize( coords[ 3 ] );\n\tvec3 vectorFormFactor = vec3( 0.0 );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );\n\tvectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );\n\tfloat result = LTC_ClippedSphereFormFactor( vectorFormFactor );\n\treturn vec3( result );\n}\nvec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tconst vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );\n\tconst vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );\n\tvec4 r = roughness * c0 + c1;\n\tfloat a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;\n\tvec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;\n\treturn specularColor * AB.x + AB.y;\n}\nfloat G_BlinnPhong_Implicit( ) {\n\treturn 0.25;\n}\nfloat D_BlinnPhong( const in float shininess, const in float dotNH ) {\n\treturn RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );\n}\nvec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {\n\tvec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );\n\tfloat dotNH = saturate( dot( geometry.normal, halfDir ) );\n\tfloat dotLH = saturate( dot( incidentLight.direction, halfDir ) );\n\tvec3 F = F_Schlick( specularColor, dotLH );\n\tfloat G = G_BlinnPhong_Implicit( );\n\tfloat D = D_BlinnPhong( shininess, dotNH );\n\treturn F * ( G * D );\n}\nfloat GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\treturn ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );\n}\nfloat BlinnExponentToGGXRoughness( const in float blinnExponent ) {\n\treturn sqrt( 2.0 / ( blinnExponent + 2.0 ) );\n}",bumpmap_pars_fragment:"#ifdef USE_BUMPMAP\n\tuniform sampler2D bumpMap;\n\tuniform float bumpScale;\n\tvec2 dHdxy_fwd() {\n\t\tvec2 dSTdx = dFdx( vUv );\n\t\tvec2 dSTdy = dFdy( vUv );\n\t\tfloat Hll = bumpScale * texture2D( bumpMap, vUv ).x;\n\t\tfloat dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;\n\t\tfloat dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;\n\t\treturn vec2( dBx, dBy );\n\t}\n\tvec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {\n\t\tvec3 vSigmaX = vec3( dFdx( surf_pos.x ), dFdx( surf_pos.y ), dFdx( surf_pos.z ) );\n\t\tvec3 vSigmaY = vec3( dFdy( surf_pos.x ), dFdy( surf_pos.y ), dFdy( surf_pos.z ) );\n\t\tvec3 vN = surf_norm;\n\t\tvec3 R1 = cross( vSigmaY, vN );\n\t\tvec3 R2 = cross( vN, vSigmaX );\n\t\tfloat fDet = dot( vSigmaX, R1 );\n\t\tfDet *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\tvec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );\n\t\treturn normalize( abs( fDet ) * surf_norm - vGrad );\n\t}\n#endif",clipping_planes_fragment:"#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vViewPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vViewPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\tif ( clipped ) discard;\n\t#endif\n#endif",clipping_planes_pars_fragment:"#if NUM_CLIPPING_PLANES > 0\n\t#if ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\t\tvarying vec3 vViewPosition;\n\t#endif\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif",clipping_planes_pars_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvarying vec3 vViewPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( PHYSICAL ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif",color_fragment:"#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif",color_pars_fragment:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_pars_vertex:"#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif",color_vertex:"#ifdef USE_COLOR\n\tvColor.xyz = color.xyz;\n#endif",common:"#define PI 3.14159265359\n#define PI2 6.28318530718\n#define PI_HALF 1.5707963267949\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\n#define LOG2 1.442695\n#define EPSILON 1e-6\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#define whiteCompliment(a) ( 1.0 - saturate( a ) )\nfloat pow2( const in float x ) { return x*x; }\nfloat pow3( const in float x ) { return x*x*x; }\nfloat pow4( const in float x ) { float x2 = x*x; return x2*x2; }\nfloat average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }\nhighp float rand( const in vec2 uv ) {\n\tconst highp float a = 12.9898, b = 78.233, c = 43758.5453;\n\thighp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );\n\treturn fract(sin(sn) * c);\n}\nstruct IncidentLight {\n\tvec3 color;\n\tvec3 direction;\n\tbool visible;\n};\nstruct ReflectedLight {\n\tvec3 directDiffuse;\n\tvec3 directSpecular;\n\tvec3 indirectDiffuse;\n\tvec3 indirectSpecular;\n};\nstruct GeometricContext {\n\tvec3 position;\n\tvec3 normal;\n\tvec3 viewDir;\n};\nvec3 transformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );\n}\nvec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {\n\treturn normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );\n}\nvec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\tfloat distance = dot( planeNormal, point - pointOnPlane );\n\treturn - distance * planeNormal + point;\n}\nfloat sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn sign( dot( point - pointOnPlane, planeNormal ) );\n}\nvec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {\n\treturn lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;\n}\nmat3 transposeMat3( const in mat3 m ) {\n\tmat3 tmp;\n\ttmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );\n\ttmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );\n\ttmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );\n\treturn tmp;\n}\nfloat linearToRelativeLuminance( const in vec3 color ) {\n\tvec3 weights = vec3( 0.2126, 0.7152, 0.0722 );\n\treturn dot( weights, color.rgb );\n}",cube_uv_reflection_fragment:"#ifdef ENVMAP_TYPE_CUBE_UV\n#define cubeUV_textureSize (1024.0)\nint getFaceFromDirection(vec3 direction) {\n\tvec3 absDirection = abs(direction);\n\tint face = -1;\n\tif( absDirection.x > absDirection.z ) {\n\t\tif(absDirection.x > absDirection.y )\n\t\t\tface = direction.x > 0.0 ? 0 : 3;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\telse {\n\t\tif(absDirection.z > absDirection.y )\n\t\t\tface = direction.z > 0.0 ? 2 : 5;\n\t\telse\n\t\t\tface = direction.y > 0.0 ? 1 : 4;\n\t}\n\treturn face;\n}\n#define cubeUV_maxLods1 (log2(cubeUV_textureSize*0.25) - 1.0)\n#define cubeUV_rangeClamp (exp2((6.0 - 1.0) * 2.0))\nvec2 MipLevelInfo( vec3 vec, float roughnessLevel, float roughness ) {\n\tfloat scale = exp2(cubeUV_maxLods1 - roughnessLevel);\n\tfloat dxRoughness = dFdx(roughness);\n\tfloat dyRoughness = dFdy(roughness);\n\tvec3 dx = dFdx( vec * scale * dxRoughness );\n\tvec3 dy = dFdy( vec * scale * dyRoughness );\n\tfloat d = max( dot( dx, dx ), dot( dy, dy ) );\n\td = clamp(d, 1.0, cubeUV_rangeClamp);\n\tfloat mipLevel = 0.5 * log2(d);\n\treturn vec2(floor(mipLevel), fract(mipLevel));\n}\n#define cubeUV_maxLods2 (log2(cubeUV_textureSize*0.25) - 2.0)\n#define cubeUV_rcpTextureSize (1.0 / cubeUV_textureSize)\nvec2 getCubeUV(vec3 direction, float roughnessLevel, float mipLevel) {\n\tmipLevel = roughnessLevel > cubeUV_maxLods2 - 3.0 ? 0.0 : mipLevel;\n\tfloat a = 16.0 * cubeUV_rcpTextureSize;\n\tvec2 exp2_packed = exp2( vec2( roughnessLevel, mipLevel ) );\n\tvec2 rcp_exp2_packed = vec2( 1.0 ) / exp2_packed;\n\tfloat powScale = exp2_packed.x * exp2_packed.y;\n\tfloat scale = rcp_exp2_packed.x * rcp_exp2_packed.y * 0.25;\n\tfloat mipOffset = 0.75*(1.0 - rcp_exp2_packed.y) * rcp_exp2_packed.x;\n\tbool bRes = mipLevel == 0.0;\n\tscale = bRes && (scale < a) ? a : scale;\n\tvec3 r;\n\tvec2 offset;\n\tint face = getFaceFromDirection(direction);\n\tfloat rcpPowScale = 1.0 / powScale;\n\tif( face == 0) {\n\t\tr = vec3(direction.x, -direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 1) {\n\t\tr = vec3(direction.y, direction.x, direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 2) {\n\t\tr = vec3(direction.z, direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.75 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? a : offset.y;\n\t}\n\telse if( face == 3) {\n\t\tr = vec3(direction.x, direction.z, direction.y);\n\t\toffset = vec2(0.0+mipOffset,0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse if( face == 4) {\n\t\tr = vec3(direction.y, direction.x, -direction.z);\n\t\toffset = vec2(scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\telse {\n\t\tr = vec3(direction.z, -direction.x, direction.y);\n\t\toffset = vec2(2.0*scale+mipOffset, 0.5 * rcpPowScale);\n\t\toffset.y = bRes && (offset.y < 2.0*a) ? 0.0 : offset.y;\n\t}\n\tr = normalize(r);\n\tfloat texelOffset = 0.5 * cubeUV_rcpTextureSize;\n\tvec2 s = ( r.yz / abs( r.x ) + vec2( 1.0 ) ) * 0.5;\n\tvec2 base = offset + vec2( texelOffset );\n\treturn base + s * ( scale - 2.0 * texelOffset );\n}\n#define cubeUV_maxLods3 (log2(cubeUV_textureSize*0.25) - 3.0)\nvec4 textureCubeUV( sampler2D envMap, vec3 reflectedDirection, float roughness ) {\n\tfloat roughnessVal = roughness* cubeUV_maxLods3;\n\tfloat r1 = floor(roughnessVal);\n\tfloat r2 = r1 + 1.0;\n\tfloat t = fract(roughnessVal);\n\tvec2 mipInfo = MipLevelInfo(reflectedDirection, r1, roughness);\n\tfloat s = mipInfo.y;\n\tfloat level0 = mipInfo.x;\n\tfloat level1 = level0 + 1.0;\n\tlevel1 = level1 > 5.0 ? 5.0 : level1;\n\tlevel0 += min( floor( s + 0.5 ), 5.0 );\n\tvec2 uv_10 = getCubeUV(reflectedDirection, r1, level0);\n\tvec4 color10 = envMapTexelToLinear(texture2D(envMap, uv_10));\n\tvec2 uv_20 = getCubeUV(reflectedDirection, r2, level0);\n\tvec4 color20 = envMapTexelToLinear(texture2D(envMap, uv_20));\n\tvec4 result = mix(color10, color20, t);\n\treturn vec4(result.rgb, 1.0);\n}\n#endif",defaultnormal_vertex:"vec3 transformedNormal = normalMatrix * objectNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif",displacementmap_pars_vertex:"#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif",displacementmap_vertex:"#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, uv ).x * displacementScale + displacementBias );\n#endif",emissivemap_fragment:"#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif",emissivemap_pars_fragment:"#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif",encodings_fragment:"gl_FragColor = linearToOutputTexel( gl_FragColor );",encodings_pars_fragment:"\nvec4 LinearToLinear( in vec4 value ) {\n\treturn value;\n}\nvec4 GammaToLinear( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( gammaFactor ) ), value.a );\n}\nvec4 LinearToGamma( in vec4 value, in float gammaFactor ) {\n\treturn vec4( pow( value.rgb, vec3( 1.0 / gammaFactor ) ), value.a );\n}\nvec4 sRGBToLinear( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.a );\n}\nvec4 LinearTosRGB( in vec4 value ) {\n\treturn vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.a );\n}\nvec4 RGBEToLinear( in vec4 value ) {\n\treturn vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );\n}\nvec4 LinearToRGBE( in vec4 value ) {\n\tfloat maxComponent = max( max( value.r, value.g ), value.b );\n\tfloat fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );\n\treturn vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );\n}\nvec4 RGBMToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * value.a * maxRange, 1.0 );\n}\nvec4 LinearToRGBM( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat M = clamp( maxRGB / maxRange, 0.0, 1.0 );\n\tM = ceil( M * 255.0 ) / 255.0;\n\treturn vec4( value.rgb / ( M * maxRange ), M );\n}\nvec4 RGBDToLinear( in vec4 value, in float maxRange ) {\n\treturn vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );\n}\nvec4 LinearToRGBD( in vec4 value, in float maxRange ) {\n\tfloat maxRGB = max( value.r, max( value.g, value.b ) );\n\tfloat D = max( maxRange / maxRGB, 1.0 );\n\tD = min( floor( D ) / 255.0, 1.0 );\n\treturn vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );\n}\nconst mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );\nvec4 LinearToLogLuv( in vec4 value ) {\n\tvec3 Xp_Y_XYZp = value.rgb * cLogLuvM;\n\tXp_Y_XYZp = max( Xp_Y_XYZp, vec3( 1e-6, 1e-6, 1e-6 ) );\n\tvec4 vResult;\n\tvResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;\n\tfloat Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;\n\tvResult.w = fract( Le );\n\tvResult.z = ( Le - ( floor( vResult.w * 255.0 ) ) / 255.0 ) / 255.0;\n\treturn vResult;\n}\nconst mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );\nvec4 LogLuvToLinear( in vec4 value ) {\n\tfloat Le = value.z * 255.0 + value.w;\n\tvec3 Xp_Y_XYZp;\n\tXp_Y_XYZp.y = exp2( ( Le - 127.0 ) / 2.0 );\n\tXp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;\n\tXp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;\n\tvec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}",envmap_fragment:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#else\n\t\tvec3 reflectVec = vReflect;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tvec4 envColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );\n\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\tvec2 sampleUV;\n\t\treflectVec = normalize( reflectVec );\n\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\tvec4 envColor = texture2D( envMap, sampleUV );\n\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\treflectVec = normalize( reflectVec );\n\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0, 0.0, 1.0 ) );\n\t\tvec4 envColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\tenvColor = envMapTexelToLinear( envColor );\n\t#ifdef ENVMAP_BLENDING_MULTIPLY\n\t\toutgoingLight = mix( outgoingLight, outgoingLight * envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_MIX )\n\t\toutgoingLight = mix( outgoingLight, envColor.xyz, specularStrength * reflectivity );\n\t#elif defined( ENVMAP_BLENDING_ADD )\n\t\toutgoingLight += envColor.xyz * specularStrength * reflectivity;\n\t#endif\n#endif",envmap_pars_fragment:"#if defined( USE_ENVMAP ) || defined( PHYSICAL )\n\tuniform float reflectivity;\n\tuniform float envMapIntensity;\n#endif\n#ifdef USE_ENVMAP\n\t#if ! defined( PHYSICAL ) && ( defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) )\n\t\tvarying vec3 vWorldPosition;\n\t#endif\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG ) || defined( PHYSICAL )\n\t\tuniform float refractionRatio;\n\t#else\n\t\tvarying vec3 vReflect;\n\t#endif\n#endif",envmap_pars_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvarying vec3 vWorldPosition;\n\t#else\n\t\tvarying vec3 vReflect;\n\t\tuniform float refractionRatio;\n\t#endif\n#endif",envmap_physical_pars_fragment:"#if defined( USE_ENVMAP ) && defined( PHYSICAL )\n\tvec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {\n\t\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryVec, 1.0 );\n\t\t#else\n\t\t\tvec4 envMapColor = vec4( 0.0 );\n\t\t#endif\n\t\treturn PI * envMapColor.rgb * envMapIntensity;\n\t}\n\tfloat getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );\n\t\t#ifdef ENVMAP_TYPE_CUBE\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_CUBE_UV )\n\t\t\tvec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );\n\t\t\tvec4 envMapColor = textureCubeUV( envMap, queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent ));\n\t\t#elif defined( ENVMAP_TYPE_EQUIREC )\n\t\t\tvec2 sampleUV;\n\t\t\tsampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\t\t\tsampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#elif defined( ENVMAP_TYPE_SPHERE )\n\t\t\tvec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );\n\t\t\t#ifdef TEXTURE_LOD_EXT\n\t\t\t\tvec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#else\n\t\t\t\tvec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );\n\t\t\t#endif\n\t\t\tenvMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif",envmap_vertex:"#ifdef USE_ENVMAP\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\tvec3 worldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvReflect = reflect( cameraToVertex, worldNormal );\n\t\t#else\n\t\t\tvReflect = refract( cameraToVertex, worldNormal, refractionRatio );\n\t\t#endif\n\t#endif\n#endif",fog_vertex:"#ifdef USE_FOG\n\tfogDepth = -mvPosition.z;\n#endif",fog_pars_vertex:"#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif",fog_fragment:"#ifdef USE_FOG\n\t#ifdef FOG_EXP2\n\t\tfloat fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );\n\t#else\n\t\tfloat fogFactor = smoothstep( fogNear, fogFar, fogDepth );\n\t#endif\n\tgl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );\n#endif",fog_pars_fragment:"#ifdef USE_FOG\n\tuniform vec3 fogColor;\n\tvarying float fogDepth;\n\t#ifdef FOG_EXP2\n\t\tuniform float fogDensity;\n\t#else\n\t\tuniform float fogNear;\n\t\tuniform float fogFar;\n\t#endif\n#endif",gradientmap_pars_fragment:"#ifdef TOON\n\tuniform sampler2D gradientMap;\n\tvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\t\tfloat dotNL = dot( normal, lightDirection );\n\t\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t\t#ifdef USE_GRADIENTMAP\n\t\t\treturn texture2D( gradientMap, coord ).rgb;\n\t\t#else\n\t\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t\t#endif\n\t}\n#endif",lightmap_fragment:"#ifdef USE_LIGHTMAP\n\treflectedLight.indirectDiffuse += PI * texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n#endif",lightmap_pars_fragment:"#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif",lights_lambert_vertex:"vec3 diffuse = vec3( 1.0 );\nGeometricContext geometry;\ngeometry.position = mvPosition.xyz;\ngeometry.normal = normalize( transformedNormal );\ngeometry.viewDir = normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n#endif\nIncidentLight directLight;\nfloat dotNL;\nvec3 directLightColor_Diffuse;\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tgetPointDirectLightIrradiance( pointLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tgetSpotDirectLightIrradiance( spotLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tgetDirectionalDirectLightIrradiance( directionalLights[ i ], geometry, directLight );\n\t\tdotNL = dot( geometry.normal, directLight.direction );\n\t\tdirectLightColor_Diffuse = PI * directLight.color;\n\t\tvLightFront += saturate( dotNL ) * directLightColor_Diffuse;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += saturate( -dotNL ) * directLightColor_Diffuse;\n\t\t#endif\n\t}\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\tvLightFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvLightBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif",lights_pars_begin:"uniform vec3 ambientLightColor;\nvec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {\n\tvec3 irradiance = ambientLightColor;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treturn irradiance;\n}\n#if NUM_DIR_LIGHTS > 0\n\tstruct DirectionalLight {\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform DirectionalLight directionalLights[ NUM_DIR_LIGHTS ];\n\tvoid getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tdirectLight.color = directionalLight.color;\n\t\tdirectLight.direction = directionalLight.direction;\n\t\tdirectLight.visible = true;\n\t}\n#endif\n#if NUM_POINT_LIGHTS > 0\n\tstruct PointLight {\n\t\tvec3 position;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t\tfloat shadowCameraNear;\n\t\tfloat shadowCameraFar;\n\t};\n\tuniform PointLight pointLights[ NUM_POINT_LIGHTS ];\n\tvoid getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = pointLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tdirectLight.color = pointLight.color;\n\t\tdirectLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );\n\t\tdirectLight.visible = ( directLight.color != vec3( 0.0 ) );\n\t}\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\tstruct SpotLight {\n\t\tvec3 position;\n\t\tvec3 direction;\n\t\tvec3 color;\n\t\tfloat distance;\n\t\tfloat decay;\n\t\tfloat coneCos;\n\t\tfloat penumbraCos;\n\t\tint shadow;\n\t\tfloat shadowBias;\n\t\tfloat shadowRadius;\n\t\tvec2 shadowMapSize;\n\t};\n\tuniform SpotLight spotLights[ NUM_SPOT_LIGHTS ];\n\tvoid getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight ) {\n\t\tvec3 lVector = spotLight.position - geometry.position;\n\t\tdirectLight.direction = normalize( lVector );\n\t\tfloat lightDistance = length( lVector );\n\t\tfloat angleCos = dot( directLight.direction, spotLight.direction );\n\t\tif ( angleCos > spotLight.coneCos ) {\n\t\t\tfloat spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );\n\t\t\tdirectLight.color = spotLight.color;\n\t\t\tdirectLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );\n\t\t\tdirectLight.visible = true;\n\t\t} else {\n\t\t\tdirectLight.color = vec3( 0.0 );\n\t\t\tdirectLight.visible = false;\n\t\t}\n\t}\n#endif\n#if NUM_RECT_AREA_LIGHTS > 0\n\tstruct RectAreaLight {\n\t\tvec3 color;\n\t\tvec3 position;\n\t\tvec3 halfWidth;\n\t\tvec3 halfHeight;\n\t};\n\tuniform sampler2D ltc_1;\tuniform sampler2D ltc_2;\n\tuniform RectAreaLight rectAreaLights[ NUM_RECT_AREA_LIGHTS ];\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\tstruct HemisphereLight {\n\t\tvec3 direction;\n\t\tvec3 skyColor;\n\t\tvec3 groundColor;\n\t};\n\tuniform HemisphereLight hemisphereLights[ NUM_HEMI_LIGHTS ];\n\tvec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {\n\t\tfloat dotNL = dot( geometry.normal, hemiLight.direction );\n\t\tfloat hemiDiffuseWeight = 0.5 * dotNL + 0.5;\n\t\tvec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tirradiance *= PI;\n\t\t#endif\n\t\treturn irradiance;\n\t}\n#endif",lights_phong_fragment:"BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;",lights_phong_pars_fragment:"varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3\tdiffuseColor;\n\tvec3\tspecularColor;\n\tfloat\tspecularShininess;\n\tfloat\tspecularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifdef TOON\n\t\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#else\n\t\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\t\tvec3 irradiance = dotNL * directLight.color;\n\t#endif\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\treflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength;\n}\nvoid RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_BlinnPhong\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_BlinnPhong\n#define Material_LightProbeLOD( material )\t(0)",lights_physical_fragment:"PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nmaterial.specularRoughness = clamp( roughnessFactor, 0.04, 1.0 );\n#ifdef STANDARD\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n\tmaterial.clearCoat = saturate( clearCoat );\tmaterial.clearCoatRoughness = clamp( clearCoatRoughness, 0.04, 1.0 );\n#endif",lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n\t#ifndef STANDARD\n\t\tfloat clearCoat;\n\t\tfloat clearCoatRoughness;\n\t#endif\n};\n#define MAXIMUM_SPECULAR_COEFFICIENT 0.16\n#define DEFAULT_SPECULAR_COEFFICIENT 0.04\nfloat clearCoatDHRApprox( const in float roughness, const in float dotNL ) {\n\treturn DEFAULT_SPECULAR_COEFFICIENT + ( 1.0 - DEFAULT_SPECULAR_COEFFICIENT ) * ( pow( 1.0 - dotNL, 5.0 ) * pow( 1.0 - roughness, 2.0 ) );\n}\n#if NUM_RECT_AREA_LIGHTS > 0\n\tvoid RE_Direct_RectArea_Physical( const in RectAreaLight rectAreaLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t\tvec3 normal = geometry.normal;\n\t\tvec3 viewDir = geometry.viewDir;\n\t\tvec3 position = geometry.position;\n\t\tvec3 lightPos = rectAreaLight.position;\n\t\tvec3 halfWidth = rectAreaLight.halfWidth;\n\t\tvec3 halfHeight = rectAreaLight.halfHeight;\n\t\tvec3 lightColor = rectAreaLight.color;\n\t\tfloat roughness = material.specularRoughness;\n\t\tvec3 rectCoords[ 4 ];\n\t\trectCoords[ 0 ] = lightPos + halfWidth - halfHeight;\t\trectCoords[ 1 ] = lightPos - halfWidth - halfHeight;\n\t\trectCoords[ 2 ] = lightPos - halfWidth + halfHeight;\n\t\trectCoords[ 3 ] = lightPos + halfWidth + halfHeight;\n\t\tvec2 uv = LTC_Uv( normal, viewDir, roughness );\n\t\tvec4 t1 = texture2D( ltc_1, uv );\n\t\tvec4 t2 = texture2D( ltc_2, uv );\n\t\tmat3 mInv = mat3(\n\t\t\tvec3( t1.x, 0, t1.y ),\n\t\t\tvec3( 0, 1, 0 ),\n\t\t\tvec3( t1.z, 0, t1.w )\n\t\t);\n\t\tvec3 fresnel = ( material.specularColor * t2.x + ( vec3( 1.0 ) - material.specularColor ) * t2.y );\n\t\treflectedLight.directSpecular += lightColor * fresnel * LTC_Evaluate( normal, viewDir, position, mInv, rectCoords );\n\t\treflectedLight.directDiffuse += lightColor * material.diffuseColor * LTC_Evaluate( normal, viewDir, position, mat3( 1.0 ), rectCoords );\n\t}\n#endif\nvoid RE_Direct_Physical( const in IncidentLight directLight, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\tfloat dotNL = saturate( dot( geometry.normal, directLight.direction ) );\n\tvec3 irradiance = dotNL * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\t#ifndef STANDARD\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.directSpecular += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry, material.specularColor, material.specularRoughness );\n\treflectedLight.directDiffuse += ( 1.0 - clearCoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n\t#ifndef STANDARD\n\t\treflectedLight.directSpecular += irradiance * material.clearCoat * BRDF_Specular_GGX( directLight, geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\nvoid RE_IndirectDiffuse_Physical( const in vec3 irradiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectSpecular_Physical( const in vec3 radiance, const in vec3 clearCoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight ) {\n\t#ifndef STANDARD\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\tfloat dotNL = dotNV;\n\t\tfloat clearCoatDHR = material.clearCoat * clearCoatDHRApprox( material.clearCoatRoughness, dotNL );\n\t#else\n\t\tfloat clearCoatDHR = 0.0;\n\t#endif\n\treflectedLight.indirectSpecular += ( 1.0 - clearCoatDHR ) * radiance * BRDF_Specular_GGX_Environment( geometry, material.specularColor, material.specularRoughness );\n\t#ifndef STANDARD\n\t\treflectedLight.indirectSpecular += clearCoatRadiance * material.clearCoat * BRDF_Specular_GGX_Environment( geometry, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearCoatRoughness );\n\t#endif\n}\n#define RE_Direct\t\t\t\tRE_Direct_Physical\n#define RE_Direct_RectArea\t\tRE_Direct_RectArea_Physical\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Physical\n#define RE_IndirectSpecular\t\tRE_IndirectSpecular_Physical\n#define Material_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.specularRoughness )\n#define Material_ClearCoat_BlinnShininessExponent( material ) GGXRoughnessToBlinnExponent( material.clearCoatRoughness )\nfloat computeSpecularOcclusion( const in float dotNV, const in float ambientOcclusion, const in float roughness ) {\n\treturn saturate( pow( dotNV + ambientOcclusion, exp2( - 16.0 * roughness - 1.0 ) ) - 1.0 + ambientOcclusion );\n}",lights_fragment_begin:"\nGeometricContext geometry;\ngeometry.position = - vViewPosition;\ngeometry.normal = normal;\ngeometry.viewDir = normalize( vViewPosition );\nIncidentLight directLight;\n#if ( NUM_POINT_LIGHTS > 0 ) && defined( RE_Direct )\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tgetPointDirectLightIrradiance( pointLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( pointLight.shadow, directLight.visible ) ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tgetSpotDirectLightIrradiance( spotLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( spotLight.shadow, directLight.visible ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tgetDirectionalDirectLightIrradiance( directionalLight, geometry, directLight );\n\t\t#ifdef USE_SHADOWMAP\n\t\tdirectLight.color *= all( bvec2( directionalLight.shadow, directLight.visible ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_RECT_AREA_LIGHTS; i ++ ) {\n\t\trectAreaLight = rectAreaLights[ i ];\n\t\tRE_Direct_RectArea( rectAreaLight, geometry, material, reflectedLight );\n\t}\n#endif\n#if defined( RE_IndirectDiffuse )\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\t#if ( NUM_HEMI_LIGHTS > 0 )\n\t\t#pragma unroll_loop\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearCoatRadiance = vec3( 0.0 );\n#endif",lights_fragment_maps:"#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec3 lightMapIrradiance = texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tlightMapIrradiance *= PI;\n\t\t#endif\n\t\tirradiance += lightMapIrradiance;\n\t#endif\n\t#if defined( USE_ENVMAP ) && defined( PHYSICAL ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tirradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry, Material_BlinnShininessExponent( material ), maxMipLevel );\n\t#ifndef STANDARD\n\t\tclearCoatRadiance += getLightProbeIndirectRadiance( geometry, Material_ClearCoat_BlinnShininessExponent( material ), maxMipLevel );\n\t#endif\n#endif",lights_fragment_end:"#if defined( RE_IndirectDiffuse )\n\tRE_IndirectDiffuse( irradiance, geometry, material, reflectedLight );\n#endif\n#if defined( RE_IndirectSpecular )\n\tRE_IndirectSpecular( radiance, clearCoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = log2( vFragDepth ) * logDepthBufFC * 0.5;\n#endif",logdepthbuf_pars_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tuniform float logDepthBufFC;\n\tvarying float vFragDepth;\n#endif",logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t#else\n\t\tuniform float logDepthBufFC;\n\t#endif\n#endif",logdepthbuf_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvFragDepth = 1.0 + gl_Position.w;\n\t#else\n\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\tgl_Position.z *= gl_Position.w;\n\t#endif\n#endif",map_fragment:"#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif",map_pars_fragment:"#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif",map_particle_fragment:"#ifdef USE_MAP\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif",map_particle_pars_fragment:"#ifdef USE_MAP\n\tuniform mat3 uvTransform;\n\tuniform sampler2D map;\n#endif",metalnessmap_fragment:"float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif",metalnessmap_pars_fragment:"#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif",morphnormal_vertex:"#ifdef USE_MORPHNORMALS\n\tobjectNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];\n\tobjectNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];\n\tobjectNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];\n\tobjectNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];\n#endif",morphtarget_pars_vertex:"#ifdef USE_MORPHTARGETS\n\t#ifndef USE_MORPHNORMALS\n\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif",morphtarget_vertex:"#ifdef USE_MORPHTARGETS\n\ttransformed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];\n\ttransformed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];\n\ttransformed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];\n\ttransformed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\ttransformed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];\n\ttransformed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];\n\ttransformed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];\n\ttransformed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];\n\t#endif\n#endif",normal_fragment_begin:"#ifdef FLAT_SHADED\n\tvec3 fdx = vec3( dFdx( vViewPosition.x ), dFdx( vViewPosition.y ), dFdx( vViewPosition.z ) );\n\tvec3 fdy = vec3( dFdy( vViewPosition.x ), dFdy( vViewPosition.y ), dFdy( vViewPosition.z ) );\n\tvec3 normal = normalize( cross( fdx, fdy ) );\n#else\n\tvec3 normal = normalize( vNormal );\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n#endif",normal_fragment_maps:"#ifdef USE_NORMALMAP\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t#ifdef FLIP_SIDED\n\t\t\tnormal = - normal;\n\t\t#endif\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tnormal = normalize( normalMatrix * normal );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif",normalmap_pars_fragment:"#ifdef USE_NORMALMAP\n\tuniform sampler2D normalMap;\n\tuniform vec2 normalScale;\n\t#ifdef OBJECTSPACE_NORMALMAP\n\t\tuniform mat3 normalMatrix;\n\t#else\n\t\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {\n\t\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\t\tvec2 st0 = dFdx( vUv.st );\n\t\t\tvec2 st1 = dFdy( vUv.st );\n\t\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\t\tvec3 N = normalize( surf_norm );\n\t\t\tmat3 tsn = mat3( S, T, N );\n\t\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\t\tmapN.xy *= normalScale;\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\treturn normalize( tsn * mapN );\n\t\t}\n\t#endif\n#endif",packing:"vec3 packNormalToRGB( const in vec3 normal ) {\n\treturn normalize( normal ) * 0.5 + 0.5;\n}\nvec3 unpackRGBToNormal( const in vec3 rgb ) {\n\treturn 2.0 * rgb.xyz - 1.0;\n}\nconst float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;\nconst vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256., 256. );\nconst vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );\nconst float ShiftRight8 = 1. / 256.;\nvec4 packDepthToRGBA( const in float v ) {\n\tvec4 r = vec4( fract( v * PackFactors ), v );\n\tr.yzw -= r.xyz * ShiftRight8;\treturn r * PackUpscale;\n}\nfloat unpackRGBAToDepth( const in vec4 v ) {\n\treturn dot( v, UnpackFactors );\n}\nfloat viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn ( viewZ + near ) / ( near - far );\n}\nfloat orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {\n\treturn linearClipZ * ( near - far ) - near;\n}\nfloat viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {\n\treturn (( near + viewZ ) * far ) / (( far - near ) * viewZ );\n}\nfloat perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {\n\treturn ( near * far ) / ( ( far - near ) * invClipZ - far );\n}",premultiplied_alpha_fragment:"#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif",project_vertex:"vec4 mvPosition = modelViewMatrix * vec4( transformed, 1.0 );\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#if defined( DITHERING )\n gl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#if defined( DITHERING )\n\tvec3 dithering( vec3 color ) {\n\t\tfloat grid_position = rand( gl_FragCoord.xy );\n\t\tvec3 dither_shift_RGB = vec3( 0.25 / 255.0, -0.25 / 255.0, 0.25 / 255.0 );\n\t\tdither_shift_RGB = mix( 2.0 * dither_shift_RGB, -2.0 * dither_shift_RGB, grid_position );\n\t\treturn color + dither_shift_RGB;\n\t}\n#endif",roughnessmap_fragment:"float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif",roughnessmap_pars_fragment:"#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif",shadowmap_pars_fragment:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tfloat texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {\n\t\tconst vec2 offset = vec2( 0.0, 1.0 );\n\t\tvec2 texelSize = vec2( 1.0 ) / size;\n\t\tvec2 centroidUV = floor( uv * size + 0.5 ) / size;\n\t\tfloat lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );\n\t\tfloat lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );\n\t\tfloat rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );\n\t\tfloat rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );\n\t\tvec2 f = fract( uv * size + 0.5 );\n\t\tfloat a = mix( lb, lt, f.y );\n\t\tfloat b = mix( rb, rt, f.y );\n\t\tfloat c = mix( a, b, f.x );\n\t\treturn c;\n\t}\n\tfloat getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {\n\t\tfloat shadow = 1.0;\n\t\tshadowCoord.xyz /= shadowCoord.w;\n\t\tshadowCoord.z += shadowBias;\n\t\tbvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );\n\t\tbool inFrustum = all( inFrustumVec );\n\t\tbvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );\n\t\tbool frustumTest = all( frustumTestVec );\n\t\tif ( frustumTest ) {\n\t\t#if defined( SHADOWMAP_TYPE_PCF )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#elif defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 texelSize = vec2( 1.0 ) / shadowMapSize;\n\t\t\tfloat dx0 = - texelSize.x * shadowRadius;\n\t\t\tfloat dy0 = - texelSize.y * shadowRadius;\n\t\t\tfloat dx1 = + texelSize.x * shadowRadius;\n\t\t\tfloat dy1 = + texelSize.y * shadowRadius;\n\t\t\tshadow = (\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +\n\t\t\t\ttexture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\tshadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );\n\t\t#endif\n\t\t}\n\t\treturn shadow;\n\t}\n\tvec2 cubeToUV( vec3 v, float texelSizeY ) {\n\t\tvec3 absV = abs( v );\n\t\tfloat scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );\n\t\tabsV *= scaleToCube;\n\t\tv *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );\n\t\tvec2 planar = v.xy;\n\t\tfloat almostATexel = 1.5 * texelSizeY;\n\t\tfloat almostOne = 1.0 - almostATexel;\n\t\tif ( absV.z >= almostOne ) {\n\t\t\tif ( v.z > 0.0 )\n\t\t\t\tplanar.x = 4.0 - v.x;\n\t\t} else if ( absV.x >= almostOne ) {\n\t\t\tfloat signX = sign( v.x );\n\t\t\tplanar.x = v.z * signX + 2.0 * signX;\n\t\t} else if ( absV.y >= almostOne ) {\n\t\t\tfloat signY = sign( v.y );\n\t\t\tplanar.x = v.x + 2.0 * signY + 2.0;\n\t\t\tplanar.y = v.z * signY - 2.0;\n\t\t}\n\t\treturn vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );\n\t}\n\tfloat getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\n\t\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\n\t\tvec3 lightToPosition = shadowCoord.xyz;\n\t\tfloat dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\t\tdp += shadowBias;\n\t\tvec3 bd3D = normalize( lightToPosition );\n\t\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )\n\t\t\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\n\t\t\treturn (\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\n\t\t\t\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\n\t\t\t) * ( 1.0 / 9.0 );\n\t\t#else\n\t\t\treturn texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\n\t\t#endif\n\t}\n#endif",shadowmap_pars_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHTS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHTS ];\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHTS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHTS ];\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHTS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHTS ];\n\t#endif\n#endif",shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n#endif",shadowmask_pars_fragment:"float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHTS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHTS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHTS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHTS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHTS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHTS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#endif\n\t#endif\n\treturn shadow;\n}",skinbase_vertex:"#ifdef USE_SKINNING\n\tmat4 boneMatX = getBoneMatrix( skinIndex.x );\n\tmat4 boneMatY = getBoneMatrix( skinIndex.y );\n\tmat4 boneMatZ = getBoneMatrix( skinIndex.z );\n\tmat4 boneMatW = getBoneMatrix( skinIndex.w );\n#endif",skinning_pars_vertex:"#ifdef USE_SKINNING\n\tuniform mat4 bindMatrix;\n\tuniform mat4 bindMatrixInverse;\n\t#ifdef BONE_TEXTURE\n\t\tuniform sampler2D boneTexture;\n\t\tuniform int boneTextureSize;\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tfloat j = i * 4.0;\n\t\t\tfloat x = mod( j, float( boneTextureSize ) );\n\t\t\tfloat y = floor( j / float( boneTextureSize ) );\n\t\t\tfloat dx = 1.0 / float( boneTextureSize );\n\t\t\tfloat dy = 1.0 / float( boneTextureSize );\n\t\t\ty = dy * ( y + 0.5 );\n\t\t\tvec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );\n\t\t\tvec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );\n\t\t\tvec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );\n\t\t\tvec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );\n\t\t\tmat4 bone = mat4( v1, v2, v3, v4 );\n\t\t\treturn bone;\n\t\t}\n\t#else\n\t\tuniform mat4 boneMatrices[ MAX_BONES ];\n\t\tmat4 getBoneMatrix( const in float i ) {\n\t\t\tmat4 bone = boneMatrices[ int(i) ];\n\t\t\treturn bone;\n\t\t}\n\t#endif\n#endif",skinning_vertex:"#ifdef USE_SKINNING\n\tvec4 skinVertex = bindMatrix * vec4( transformed, 1.0 );\n\tvec4 skinned = vec4( 0.0 );\n\tskinned += boneMatX * skinVertex * skinWeight.x;\n\tskinned += boneMatY * skinVertex * skinWeight.y;\n\tskinned += boneMatZ * skinVertex * skinWeight.z;\n\tskinned += boneMatW * skinVertex * skinWeight.w;\n\ttransformed = ( bindMatrixInverse * skinned ).xyz;\n#endif",skinnormal_vertex:"#ifdef USE_SKINNING\n\tmat4 skinMatrix = mat4( 0.0 );\n\tskinMatrix += skinWeight.x * boneMatX;\n\tskinMatrix += skinWeight.y * boneMatY;\n\tskinMatrix += skinWeight.z * boneMatZ;\n\tskinMatrix += skinWeight.w * boneMatW;\n\tskinMatrix = bindMatrixInverse * skinMatrix * bindMatrix;\n\tobjectNormal = vec4( skinMatrix * vec4( objectNormal, 0.0 ) ).xyz;\n#endif",specularmap_fragment:"float specularStrength;\n#ifdef USE_SPECULARMAP\n\tvec4 texelSpecular = texture2D( specularMap, vUv );\n\tspecularStrength = texelSpecular.r;\n#else\n\tspecularStrength = 1.0;\n#endif",specularmap_pars_fragment:"#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif",tonemapping_fragment:"#if defined( TONE_MAPPING )\n gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n\t#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\nuniform float toneMappingWhitePoint;\nvec3 LinearToneMapping( vec3 color ) {\n\treturn toneMappingExposure * color;\n}\nvec3 ReinhardToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( color / ( vec3( 1.0 ) + color ) );\n}\n#define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )\nvec3 Uncharted2ToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );\n}\nvec3 OptimizedCineonToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\tcolor = max( vec3( 0.0 ), color - 0.004 );\n\treturn pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tcolor *= toneMappingExposure;\n\treturn saturate( ( color * ( 2.51 * color + 0.03 ) ) / ( color * ( 2.43 * color + 0.59 ) + 0.14 ) );\n}",uv_pars_fragment:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvarying vec2 vUv;\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP ) || defined( USE_ALPHAMAP ) || defined( USE_EMISSIVEMAP ) || defined( USE_ROUGHNESSMAP ) || defined( USE_METALNESSMAP )\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif",uv2_pars_fragment:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif",uv2_pars_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n#endif",uv2_vertex:"#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = uv2;\n#endif",worldpos_vertex:"#if defined( USE_ENVMAP ) || defined( DISTANCE ) || defined ( USE_SHADOWMAP )\n\tvec4 worldPosition = modelMatrix * vec4( transformed, 1.0 );\n#endif",background_frag:"uniform sampler2D t2D;\nvarying vec2 vUv;\nvoid main() {\n\tvec4 texColor = texture2D( t2D, vUv );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",background_vert:"varying vec2 vUv;\nuniform mat3 uvTransform;\nvoid main() {\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n\tgl_Position = vec4( position.xy, 1.0, 1.0 );\n}",cube_frag:"uniform samplerCube tCube;\nuniform float tFlip;\nuniform float opacity;\nvarying vec3 vWorldDirection;\nvoid main() {\n\tvec4 texColor = textureCube( tCube, vec3( tFlip * vWorldDirection.x, vWorldDirection.yz ) );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}",cube_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n\tgl_Position.z = gl_Position.w;\n}",depth_frag:"#if DEPTH_PACKING == 3200\n\tuniform float opacity;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#if DEPTH_PACKING == 3200\n\t\tdiffuseColor.a = opacity;\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - gl_FragCoord.z ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( gl_FragCoord.z );\n\t#endif\n}",depth_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",distanceRGBA_frag:"#define DISTANCE\nuniform vec3 referencePosition;\nuniform float nearDistance;\nuniform float farDistance;\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main () {\n\t#include \n\tvec4 diffuseColor = vec4( 1.0 );\n\t#include \n\t#include \n\t#include \n\tfloat dist = length( vWorldPosition - referencePosition );\n\tdist = ( dist - nearDistance ) / ( farDistance - nearDistance );\n\tdist = saturate( dist );\n\tgl_FragColor = packDepthToRGBA( dist );\n}",distanceRGBA_vert:"#define DISTANCE\nvarying vec3 vWorldPosition;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#ifdef USE_DISPLACEMENTMAP\n\t\t#include \n\t\t#include \n\t\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvWorldPosition = worldPosition.xyz;\n}",equirect_frag:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV;\n\tsampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\tsampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5;\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}",equirect_vert:"varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}",linedashed_frag:"uniform vec3 diffuse;\nuniform float opacity;\nuniform float dashSize;\nuniform float totalSize;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tif ( mod( vLineDistance, totalSize ) > dashSize ) {\n\t\tdiscard;\n\t}\n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\toutgoingLight = diffuseColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",linedashed_vert:"uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvLineDistance = scale * lineDistance;\n\tvec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}",meshbasic_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\t#ifdef USE_LIGHTMAP\n\t\treflectedLight.indirectDiffuse += texture2D( lightMap, vUv2 ).xyz * lightMapIntensity;\n\t#else\n\t\treflectedLight.indirectDiffuse += vec3( 1.0 );\n\t#endif\n\t#include \n\treflectedLight.indirectDiffuse *= diffuseColor.rgb;\n\tvec3 outgoingLight = reflectedLight.indirectDiffuse;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshbasic_vert:"#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#ifdef USE_ENVMAP\n\t#include \n\t#include \n\t#include \n\t#include \n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_frag:"uniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float opacity;\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\tReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );\n\tvec3 totalEmissiveRadiance = emissive;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\treflectedLight.indirectDiffuse = getAmbientLightIrradiance( ambientLightColor );\n\t#include \n\treflectedLight.indirectDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb );\n\t#ifdef DOUBLE_SIDED\n\t\treflectedLight.directDiffuse = ( gl_FrontFacing ) ? vLightFront : vLightBack;\n\t#else\n\t\treflectedLight.directDiffuse = vLightFront;\n\t#endif\n\treflectedLight.directDiffuse *= BRDF_Diffuse_Lambert( diffuseColor.rgb ) * getShadowMask();\n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + totalEmissiveRadiance;\n\t#include \n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshlambert_vert:"#define LAMBERT\nvarying vec3 vLightFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_frag:"#define MATCAP\nuniform vec3 diffuse;\nuniform float opacity;\nuniform sampler2D matcap;\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 viewDir = normalize( vViewPosition );\n\tvec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n\tvec3 y = cross( viewDir, x );\n\tvec2 uv = vec2( dot( x, normal ), dot( y, normal ) ) * 0.495 + 0.5;\n\t#ifdef USE_MATCAP\n\t\tvec4 matcapColor = texture2D( matcap, uv );\n\t\tmatcapColor = matcapTexelToLinear( matcapColor );\n\t#else\n\t\tvec4 matcapColor = vec4( 1.0 );\n\t#endif\n\tvec3 outgoingLight = diffuseColor.rgb * matcapColor.rgb;\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n}",meshmatcap_vert:"#define MATCAP\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\n#include \n#include \n#include \n#include