From ecd548bad74d2b2005bf77c84b2fa5aaa94ba63f Mon Sep 17 00:00:00 2001 From: Jian Sun Date: Mon, 5 Dec 2022 12:21:57 +0800 Subject: [PATCH] :tada: Add wechat 3d model rendering --- src/wechat_app/app.js | 5 + src/wechat_app/app.json | 14 + src/wechat_app/app.wxss | 17 + src/wechat_app/jsm/controls/OrbitControls.js | 1183 ++++++ .../jsm/controls/TrackballControls.js | 712 ++++ src/wechat_app/jsm/loaders/DDSLoader.js | 285 ++ .../loaders/EquirectangularToCubeGenerator.js | 252 ++ src/wechat_app/jsm/loaders/GLTFLoader.js | 3284 +++++++++++++++++ src/wechat_app/jsm/loaders/MTLLoader.js | 547 +++ src/wechat_app/jsm/loaders/OBJLoader.js | 812 ++++ src/wechat_app/jsm/loaders/RGBELoader.js | 542 +++ src/wechat_app/jsm/loaders/STLLoader.js | 409 ++ src/wechat_app/jsm/pmrem/PMREMCubeUVPacker.js | 254 ++ src/wechat_app/jsm/pmrem/PMREMGenerator.js | 311 ++ src/wechat_app/jsm/utils/SkeletonUtils.js | 599 +++ src/wechat_app/libs/three.weapp.js | 1073 ++++++ src/wechat_app/pages/cube/index.js | 92 + src/wechat_app/pages/cube/index.json | 4 + src/wechat_app/pages/cube/index.wxml | 3 + src/wechat_app/pages/cube/index.wxss | 0 src/wechat_app/pages/cube/rainbow.jpg | Bin 0 -> 16069 bytes src/wechat_app/pages/index/index.js | 12 + src/wechat_app/pages/index/index.json | 3 + src/wechat_app/pages/index/index.wxml | 5 + src/wechat_app/pages/index/index.wxss | 11 + src/wechat_app/pages/logs/logs.js | 18 + src/wechat_app/pages/logs/logs.json | 4 + src/wechat_app/pages/logs/logs.wxml | 6 + src/wechat_app/pages/logs/logs.wxss | 8 + src/wechat_app/project.config.json | 53 + src/wechat_app/project.private.config.json | 7 + src/wechat_app/sitemap.json | 7 + src/wechat_app/utils/util.js | 19 + 33 files changed, 10551 insertions(+) create mode 100644 src/wechat_app/app.js create mode 100644 src/wechat_app/app.json create mode 100644 src/wechat_app/app.wxss create mode 100644 src/wechat_app/jsm/controls/OrbitControls.js create mode 100644 src/wechat_app/jsm/controls/TrackballControls.js create mode 100644 src/wechat_app/jsm/loaders/DDSLoader.js create mode 100644 src/wechat_app/jsm/loaders/EquirectangularToCubeGenerator.js create mode 100644 src/wechat_app/jsm/loaders/GLTFLoader.js create mode 100644 src/wechat_app/jsm/loaders/MTLLoader.js create mode 100644 src/wechat_app/jsm/loaders/OBJLoader.js create mode 100644 src/wechat_app/jsm/loaders/RGBELoader.js create mode 100644 src/wechat_app/jsm/loaders/STLLoader.js create mode 100644 src/wechat_app/jsm/pmrem/PMREMCubeUVPacker.js create mode 100644 src/wechat_app/jsm/pmrem/PMREMGenerator.js create mode 100644 src/wechat_app/jsm/utils/SkeletonUtils.js create mode 100644 src/wechat_app/libs/three.weapp.js create mode 100644 src/wechat_app/pages/cube/index.js create mode 100644 src/wechat_app/pages/cube/index.json create mode 100644 src/wechat_app/pages/cube/index.wxml create mode 100644 src/wechat_app/pages/cube/index.wxss create mode 100644 src/wechat_app/pages/cube/rainbow.jpg create mode 100644 src/wechat_app/pages/index/index.js create mode 100644 src/wechat_app/pages/index/index.json create mode 100644 src/wechat_app/pages/index/index.wxml create mode 100644 src/wechat_app/pages/index/index.wxss create mode 100644 src/wechat_app/pages/logs/logs.js create mode 100644 src/wechat_app/pages/logs/logs.json create mode 100644 src/wechat_app/pages/logs/logs.wxml create mode 100644 src/wechat_app/pages/logs/logs.wxss create mode 100644 src/wechat_app/project.config.json create mode 100644 src/wechat_app/project.private.config.json create mode 100644 src/wechat_app/sitemap.json create mode 100644 src/wechat_app/utils/util.js diff --git a/src/wechat_app/app.js b/src/wechat_app/app.js new file mode 100644 index 0000000..1e038f4 --- /dev/null +++ b/src/wechat_app/app.js @@ -0,0 +1,5 @@ +App({ + onLaunch: function () { + // wx.THREE = THREE + } +}) diff --git a/src/wechat_app/app.json b/src/wechat_app/app.json new file mode 100644 index 0000000..5b2f401 --- /dev/null +++ b/src/wechat_app/app.json @@ -0,0 +1,14 @@ +{ + "pages": [ + "pages/index/index", + "pages/cube/index", + "pages/logs/logs" + ], + "window": { + "backgroundTextStyle": "light", + "navigationBarBackgroundColor": "#fff", + "navigationBarTitleText": "WeChat", + "navigationBarTextStyle": "black" + }, + "sitemapLocation": "sitemap.json" +} \ No newline at end of file diff --git a/src/wechat_app/app.wxss b/src/wechat_app/app.wxss new file mode 100644 index 0000000..6841b44 --- /dev/null +++ b/src/wechat_app/app.wxss @@ -0,0 +1,17 @@ +/**app.wxss**/ +page { + width: 100%; + height: 100%; + margin: 0; + padding: 0; +} + +.container { + height: 100%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + padding: 200rpx 0; + box-sizing: border-box; +} diff --git a/src/wechat_app/jsm/controls/OrbitControls.js b/src/wechat_app/jsm/controls/OrbitControls.js new file mode 100644 index 0000000..0f26a55 --- /dev/null +++ b/src/wechat_app/jsm/controls/OrbitControls.js @@ -0,0 +1,1183 @@ +/** + * @author qiao / https://github.com/qiao + * @author mrdoob / http://mrdoob.com + * @author alteredq / http://alteredqualia.com/ + * @author WestLangley / http://github.com/WestLangley + * @author erich666 / http://erichaines.com + * @author ScieCode / http://github.com/sciecode + */ + +import { + EventDispatcher, + MOUSE, + Quaternion, + Spherical, + TOUCH, + Vector2, + Vector3, + global as window +} from "../../libs/three.weapp.js"; + +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// +// Orbit - left mouse / touch: one-finger move +// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish +// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move + +var OrbitControls = function (object, domElement) { + + this.object = object; + + this.domElement = (domElement !== undefined) ? domElement : document; + + // Set to false to disable this control + this.enabled = true; + + // "target" sets the location of focus, where the object orbits around + this.target = new Vector3(); + + // How far you can dolly in and out ( PerspectiveCamera only ) + this.minDistance = 0; + this.maxDistance = Infinity; + + // How far you can zoom in and out ( OrthographicCamera only ) + this.minZoom = 0; + this.maxZoom = Infinity; + + // How far you can orbit vertically, upper and lower limits. + // Range is 0 to Math.PI radians. + this.minPolarAngle = 0; // radians + this.maxPolarAngle = Math.PI; // radians + + // How far you can orbit horizontally, upper and lower limits. + // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ]. + this.minAzimuthAngle = - Infinity; // radians + this.maxAzimuthAngle = Infinity; // radians + + // Set to true to enable damping (inertia) + // If damping is enabled, you must call controls.update() in your animation loop + this.enableDamping = false; + this.dampingFactor = 0.05; + + // This option actually enables dollying in and out; left as "zoom" for backwards compatibility. + // Set to false to disable zooming + this.enableZoom = true; + this.zoomSpeed = 1.0; + + // Set to false to disable rotating + this.enableRotate = true; + this.rotateSpeed = 1.0; + + // Set to false to disable panning + this.enablePan = true; + this.panSpeed = 1.0; + this.screenSpacePanning = false; // if true, pan in screen-space + this.keyPanSpeed = 7.0; // pixels moved per arrow key push + + // Set to true to automatically rotate around the target + // If auto-rotate is enabled, you must call controls.update() in your animation loop + this.autoRotate = false; + this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60 + + // Set to false to disable use of the keys + this.enableKeys = true; + + // The four arrow keys + this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 }; + + // Mouse buttons + this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.DOLLY, RIGHT: MOUSE.PAN }; + + // Touch fingers + this.touches = { ONE: TOUCH.ROTATE, TWO: TOUCH.DOLLY_PAN }; + + // for reset + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.zoom0 = this.object.zoom; + + // + // public methods + // + + this.getPolarAngle = function () { + + return spherical.phi; + + }; + + this.getAzimuthalAngle = function () { + + return spherical.theta; + + }; + + this.saveState = function () { + + scope.target0.copy(scope.target); + scope.position0.copy(scope.object.position); + scope.zoom0 = scope.object.zoom; + + }; + + this.reset = function () { + + scope.target.copy(scope.target0); + scope.object.position.copy(scope.position0); + scope.object.zoom = scope.zoom0; + + scope.object.updateProjectionMatrix(); + scope.dispatchEvent(changeEvent); + + scope.update(); + + state = STATE.NONE; + + }; + + // this method is exposed, but perhaps it would be better if we can make it private... + this.update = function () { + + var offset = new Vector3(); + + // so camera.up is the orbit axis + var quat = new Quaternion().setFromUnitVectors(object.up, new Vector3(0, 1, 0)); + var quatInverse = quat.clone().inverse(); + + var lastPosition = new Vector3(); + var lastQuaternion = new Quaternion(); + + return function update() { + + var position = scope.object.position; + + offset.copy(position).sub(scope.target); + + // rotate offset to "y-axis-is-up" space + offset.applyQuaternion(quat); + + // angle from z-axis around y-axis + spherical.setFromVector3(offset); + + if (scope.autoRotate && state === STATE.NONE) { + + rotateLeft(getAutoRotationAngle()); + + } + + if (scope.enableDamping) { + + spherical.theta += sphericalDelta.theta * scope.dampingFactor; + spherical.phi += sphericalDelta.phi * scope.dampingFactor; + + } else { + + spherical.theta += sphericalDelta.theta; + spherical.phi += sphericalDelta.phi; + + } + + // restrict theta to be between desired limits + spherical.theta = Math.max(scope.minAzimuthAngle, Math.min(scope.maxAzimuthAngle, spherical.theta)); + + // restrict phi to be between desired limits + spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi)); + + spherical.makeSafe(); + + + spherical.radius *= scale; + + // restrict radius to be between desired limits + spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius)); + + // move target to panned location + + if (scope.enableDamping === true) { + + scope.target.addScaledVector(panOffset, scope.dampingFactor); + + } else { + + scope.target.add(panOffset); + + } + + offset.setFromSpherical(spherical); + + // rotate offset back to "camera-up-vector-is-up" space + offset.applyQuaternion(quatInverse); + + position.copy(scope.target).add(offset); + + scope.object.lookAt(scope.target); + + if (scope.enableDamping === true) { + + sphericalDelta.theta *= (1 - scope.dampingFactor); + sphericalDelta.phi *= (1 - scope.dampingFactor); + + panOffset.multiplyScalar(1 - scope.dampingFactor); + + } else { + + sphericalDelta.set(0, 0, 0); + + panOffset.set(0, 0, 0); + + } + + scale = 1; + + // update condition is: + // min(camera displacement, camera rotation in radians)^2 > EPS + // using small-angle approximation cos(x/2) = 1 - x^2 / 8 + + if (zoomChanged || + lastPosition.distanceToSquared(scope.object.position) > EPS || + 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) { + + scope.dispatchEvent(changeEvent); + + lastPosition.copy(scope.object.position); + lastQuaternion.copy(scope.object.quaternion); + zoomChanged = false; + + return true; + + } + + return false; + + }; + + }(); + + this.dispose = function () { + + scope.domElement.removeEventListener('contextmenu', onContextMenu, false); + scope.domElement.removeEventListener('mousedown', onMouseDown, false); + scope.domElement.removeEventListener('wheel', onMouseWheel, false); + + scope.domElement.removeEventListener('touchstart', onTouchStart, false); + scope.domElement.removeEventListener('touchend', onTouchEnd, false); + scope.domElement.removeEventListener('touchmove', onTouchMove, false); + + document.removeEventListener('mousemove', onMouseMove, false); + document.removeEventListener('mouseup', onMouseUp, false); + + window.removeEventListener('keydown', onKeyDown, false); + + //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here? + + }; + + // + // internals + // + + var scope = this; + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + var STATE = { + NONE: - 1, + ROTATE: 0, + DOLLY: 1, + PAN: 2, + TOUCH_ROTATE: 3, + TOUCH_PAN: 4, + TOUCH_DOLLY_PAN: 5, + TOUCH_DOLLY_ROTATE: 6 + }; + + var state = STATE.NONE; + + var EPS = 0.000001; + + // current position in spherical coordinates + var spherical = new Spherical(); + var sphericalDelta = new Spherical(); + + var scale = 1; + var panOffset = new Vector3(); + var zoomChanged = false; + + var rotateStart = new Vector2(); + var rotateEnd = new Vector2(); + var rotateDelta = new Vector2(); + + var panStart = new Vector2(); + var panEnd = new Vector2(); + var panDelta = new Vector2(); + + var dollyStart = new Vector2(); + var dollyEnd = new Vector2(); + var dollyDelta = new Vector2(); + + function getAutoRotationAngle() { + + return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed; + + } + + function getZoomScale() { + + return Math.pow(0.95, scope.zoomSpeed); + + } + + function rotateLeft(angle) { + + sphericalDelta.theta -= angle; + + } + + function rotateUp(angle) { + + sphericalDelta.phi -= angle; + + } + + var panLeft = function () { + + var v = new Vector3(); + + return function panLeft(distance, objectMatrix) { + + v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix + v.multiplyScalar(- distance); + + panOffset.add(v); + + }; + + }(); + + var panUp = function () { + + var v = new Vector3(); + + return function panUp(distance, objectMatrix) { + + if (scope.screenSpacePanning === true) { + + v.setFromMatrixColumn(objectMatrix, 1); + + } else { + + v.setFromMatrixColumn(objectMatrix, 0); + v.crossVectors(scope.object.up, v); + + } + + v.multiplyScalar(distance); + + panOffset.add(v); + + }; + + }(); + + // deltaX and deltaY are in pixels; right and down are positive + var pan = function () { + + var offset = new Vector3(); + + return function pan(deltaX, deltaY) { + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + if (scope.object.isPerspectiveCamera) { + + // perspective + var position = scope.object.position; + offset.copy(position).sub(scope.target); + var targetDistance = offset.length(); + + // half of the fov is center to top of screen + targetDistance *= Math.tan((scope.object.fov / 2) * Math.PI / 180.0); + + // we use only clientHeight here so aspect ratio does not distort speed + panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix); + panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix); + + } else if (scope.object.isOrthographicCamera) { + + // orthographic + panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix); + panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix); + + } else { + + // camera neither orthographic nor perspective + console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.'); + scope.enablePan = false; + + } + + }; + + }(); + + function dollyIn(dollyScale) { + + if (scope.object.isPerspectiveCamera) { + + scale /= dollyScale; + + } else if (scope.object.isOrthographicCamera) { + + scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale)); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.'); + scope.enableZoom = false; + + } + + } + + function dollyOut(dollyScale) { + + if (scope.object.isPerspectiveCamera) { + + scale *= dollyScale; + + } else if (scope.object.isOrthographicCamera) { + + scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale)); + scope.object.updateProjectionMatrix(); + zoomChanged = true; + + } else { + + console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.'); + scope.enableZoom = false; + + } + + } + + // + // event callbacks - update the object state + // + + function handleMouseDownRotate(event) { + + rotateStart.set(event.clientX, event.clientY); + + } + + function handleMouseDownDolly(event) { + + dollyStart.set(event.clientX, event.clientY); + + } + + function handleMouseDownPan(event) { + + panStart.set(event.clientX, event.clientY); + + } + + function handleMouseMoveRotate(event) { + + rotateEnd.set(event.clientX, event.clientY); + + rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height + + rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); + + rotateStart.copy(rotateEnd); + + scope.update(); + + } + + function handleMouseMoveDolly(event) { + + dollyEnd.set(event.clientX, event.clientY); + + dollyDelta.subVectors(dollyEnd, dollyStart); + + if (dollyDelta.y > 0) { + + dollyIn(getZoomScale()); + + } else if (dollyDelta.y < 0) { + + dollyOut(getZoomScale()); + + } + + dollyStart.copy(dollyEnd); + + scope.update(); + + } + + function handleMouseMovePan(event) { + + panEnd.set(event.clientX, event.clientY); + + panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); + + pan(panDelta.x, panDelta.y); + + panStart.copy(panEnd); + + scope.update(); + + } + + function handleMouseUp( /*event*/) { + + // no-op + + } + + function handleMouseWheel(event) { + + if (event.deltaY < 0) { + + dollyOut(getZoomScale()); + + } else if (event.deltaY > 0) { + + dollyIn(getZoomScale()); + + } + + scope.update(); + + } + + function handleKeyDown(event) { + + var needsUpdate = false; + + switch (event.keyCode) { + + case scope.keys.UP: + pan(0, scope.keyPanSpeed); + needsUpdate = true; + break; + + case scope.keys.BOTTOM: + pan(0, - scope.keyPanSpeed); + needsUpdate = true; + break; + + case scope.keys.LEFT: + pan(scope.keyPanSpeed, 0); + needsUpdate = true; + break; + + case scope.keys.RIGHT: + pan(- scope.keyPanSpeed, 0); + needsUpdate = true; + break; + + } + + if (needsUpdate) { + + // prevent the browser from scrolling on cursor keys + event.preventDefault(); + + scope.update(); + + } + + + } + + function handleTouchStartRotate(event) { + + if (event.touches.length == 1) { + + rotateStart.set(event.touches[0].pageX, event.touches[0].pageY); + + } else { + + var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX); + var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY); + + rotateStart.set(x, y); + + } + + } + + function handleTouchStartPan(event) { + + if (event.touches.length == 1) { + + panStart.set(event.touches[0].pageX, event.touches[0].pageY); + + } else { + + var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX); + var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY); + + panStart.set(x, y); + + } + + } + + function handleTouchStartDolly(event) { + + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + + var distance = Math.sqrt(dx * dx + dy * dy); + + dollyStart.set(0, distance); + + } + + function handleTouchStartDollyPan(event) { + + if (scope.enableZoom) handleTouchStartDolly(event); + + if (scope.enablePan) handleTouchStartPan(event); + + } + + function handleTouchStartDollyRotate(event) { + + if (scope.enableZoom) handleTouchStartDolly(event); + + if (scope.enableRotate) handleTouchStartRotate(event); + + } + + function handleTouchMoveRotate(event) { + + if (event.touches.length == 1) { + + rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY); + + } else { + + var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX); + var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY); + + rotateEnd.set(x, y); + + } + + rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed); + + var element = scope.domElement === document ? scope.domElement.body : scope.domElement; + + rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height + + rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight); + + rotateStart.copy(rotateEnd); + + } + + function handleTouchMovePan(event) { + + if (event.touches.length == 1) { + + panEnd.set(event.touches[0].pageX, event.touches[0].pageY); + + } else { + + var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX); + var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY); + + panEnd.set(x, y); + + } + + panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed); + + pan(panDelta.x, panDelta.y); + + panStart.copy(panEnd); + + } + + function handleTouchMoveDolly(event) { + + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + + var distance = Math.sqrt(dx * dx + dy * dy); + + dollyEnd.set(0, distance); + + dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed)); + + dollyIn(dollyDelta.y); + + dollyStart.copy(dollyEnd); + + } + + function handleTouchMoveDollyPan(event) { + + if (scope.enableZoom) handleTouchMoveDolly(event); + + if (scope.enablePan) handleTouchMovePan(event); + + } + + function handleTouchMoveDollyRotate(event) { + + if (scope.enableZoom) handleTouchMoveDolly(event); + + if (scope.enableRotate) handleTouchMoveRotate(event); + + } + + function handleTouchEnd( /*event*/) { + + // no-op + + } + + // + // event handlers - FSM: listen for events and reset state + // + + function onMouseDown(event) { + + if (scope.enabled === false) return; + + // Prevent the browser from scrolling. + + event.preventDefault(); + + // Manually set the focus since calling preventDefault above + // prevents the browser from setting it automatically. + + scope.domElement.focus ? scope.domElement.focus() : window.focus(); + + switch (event.button) { + + case 0: + + switch (scope.mouseButtons.LEFT) { + + case MOUSE.ROTATE: + + if (event.ctrlKey || event.metaKey || event.shiftKey) { + + if (scope.enablePan === false) return; + + handleMouseDownPan(event); + + state = STATE.PAN; + + } else { + + if (scope.enableRotate === false) return; + + handleMouseDownRotate(event); + + state = STATE.ROTATE; + + } + + break; + + case MOUSE.PAN: + + if (event.ctrlKey || event.metaKey || event.shiftKey) { + + if (scope.enableRotate === false) return; + + handleMouseDownRotate(event); + + state = STATE.ROTATE; + + } else { + + if (scope.enablePan === false) return; + + handleMouseDownPan(event); + + state = STATE.PAN; + + } + + break; + + default: + + state = STATE.NONE; + + } + + break; + + + case 1: + + switch (scope.mouseButtons.MIDDLE) { + + case MOUSE.DOLLY: + + if (scope.enableZoom === false) return; + + handleMouseDownDolly(event); + + state = STATE.DOLLY; + + break; + + + default: + + state = STATE.NONE; + + } + + break; + + case 2: + + switch (scope.mouseButtons.RIGHT) { + + case MOUSE.ROTATE: + + if (scope.enableRotate === false) return; + + handleMouseDownRotate(event); + + state = STATE.ROTATE; + + break; + + case MOUSE.PAN: + + if (scope.enablePan === false) return; + + handleMouseDownPan(event); + + state = STATE.PAN; + + break; + + default: + + state = STATE.NONE; + + } + + break; + + } + + if (state !== STATE.NONE) { + + document.addEventListener('mousemove', onMouseMove, false); + document.addEventListener('mouseup', onMouseUp, false); + + scope.dispatchEvent(startEvent); + + } + + } + + function onMouseMove(event) { + + if (scope.enabled === false) return; + + event.preventDefault(); + + switch (state) { + + case STATE.ROTATE: + + if (scope.enableRotate === false) return; + + handleMouseMoveRotate(event); + + break; + + case STATE.DOLLY: + + if (scope.enableZoom === false) return; + + handleMouseMoveDolly(event); + + break; + + case STATE.PAN: + + if (scope.enablePan === false) return; + + handleMouseMovePan(event); + + break; + + } + + } + + function onMouseUp(event) { + + if (scope.enabled === false) return; + + handleMouseUp(event); + + document.removeEventListener('mousemove', onMouseMove, false); + document.removeEventListener('mouseup', onMouseUp, false); + + scope.dispatchEvent(endEvent); + + state = STATE.NONE; + + } + + function onMouseWheel(event) { + + if (scope.enabled === false || scope.enableZoom === false || (state !== STATE.NONE && state !== STATE.ROTATE)) return; + + event.preventDefault(); + event.stopPropagation(); + + scope.dispatchEvent(startEvent); + + handleMouseWheel(event); + + scope.dispatchEvent(endEvent); + + } + + function onKeyDown(event) { + + if (scope.enabled === false || scope.enableKeys === false || scope.enablePan === false) return; + + handleKeyDown(event); + + } + + function onTouchStart(event) { + + if (scope.enabled === false) return; + + event.preventDefault(); + + switch (event.touches.length) { + + case 1: + + switch (scope.touches.ONE) { + + case TOUCH.ROTATE: + + if (scope.enableRotate === false) return; + + handleTouchStartRotate(event); + + state = STATE.TOUCH_ROTATE; + + break; + + case TOUCH.PAN: + + if (scope.enablePan === false) return; + + handleTouchStartPan(event); + + state = STATE.TOUCH_PAN; + + break; + + default: + + state = STATE.NONE; + + } + + break; + + case 2: + + switch (scope.touches.TWO) { + + case TOUCH.DOLLY_PAN: + + if (scope.enableZoom === false && scope.enablePan === false) return; + + handleTouchStartDollyPan(event); + + state = STATE.TOUCH_DOLLY_PAN; + + break; + + case TOUCH.DOLLY_ROTATE: + + if (scope.enableZoom === false && scope.enableRotate === false) return; + + handleTouchStartDollyRotate(event); + + state = STATE.TOUCH_DOLLY_ROTATE; + + break; + + default: + + state = STATE.NONE; + + } + + break; + + default: + + state = STATE.NONE; + + } + + if (state !== STATE.NONE) { + + scope.dispatchEvent(startEvent); + + } + + } + + function onTouchMove(event) { + + if (scope.enabled === false) return; + + event.preventDefault(); + event.stopPropagation(); + + switch (state) { + + case STATE.TOUCH_ROTATE: + + if (scope.enableRotate === false) return; + + handleTouchMoveRotate(event); + + scope.update(); + + break; + + case STATE.TOUCH_PAN: + + if (scope.enablePan === false) return; + + handleTouchMovePan(event); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_PAN: + + if (scope.enableZoom === false && scope.enablePan === false) return; + + handleTouchMoveDollyPan(event); + + scope.update(); + + break; + + case STATE.TOUCH_DOLLY_ROTATE: + + if (scope.enableZoom === false && scope.enableRotate === false) return; + + handleTouchMoveDollyRotate(event); + + scope.update(); + + break; + + default: + + state = STATE.NONE; + + } + + } + + function onTouchEnd(event) { + + if (scope.enabled === false) return; + + handleTouchEnd(event); + + scope.dispatchEvent(endEvent); + + state = STATE.NONE; + + } + + function onContextMenu(event) { + + if (scope.enabled === false) return; + + event.preventDefault(); + + } + + // + + scope.domElement.addEventListener('contextmenu', onContextMenu, false); + + scope.domElement.addEventListener('mousedown', onMouseDown, false); + scope.domElement.addEventListener('wheel', onMouseWheel, false); + + scope.domElement.addEventListener('touchstart', onTouchStart, false); + scope.domElement.addEventListener('touchend', onTouchEnd, false); + scope.domElement.addEventListener('touchmove', onTouchMove, false); + + window.addEventListener('keydown', onKeyDown, false); + + // force an update at start + + this.update(); + +}; + +OrbitControls.prototype = Object.create(EventDispatcher.prototype); +OrbitControls.prototype.constructor = OrbitControls; + + +// This set of controls performs orbiting, dollying (zooming), and panning. +// Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default). +// This is very similar to OrbitControls, another set of touch behavior +// +// Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate +// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish +// Pan - left mouse, or arrow keys / touch: one-finger move + +var MapControls = function (object, domElement) { + + OrbitControls.call(this, object, domElement); + + this.mouseButtons.LEFT = MOUSE.PAN; + this.mouseButtons.RIGHT = MOUSE.ROTATE; + + this.touches.ONE = TOUCH.PAN; + this.touches.TWO = TOUCH.DOLLY_ROTATE; + +}; + +MapControls.prototype = Object.create(EventDispatcher.prototype); +MapControls.prototype.constructor = MapControls; + +export { OrbitControls, MapControls }; \ No newline at end of file diff --git a/src/wechat_app/jsm/controls/TrackballControls.js b/src/wechat_app/jsm/controls/TrackballControls.js new file mode 100644 index 0000000..71b82a3 --- /dev/null +++ b/src/wechat_app/jsm/controls/TrackballControls.js @@ -0,0 +1,712 @@ +/** + * @author Eberhard Graether / http://egraether.com/ + * @author Mark Lundin / http://mark-lundin.com + * @author Simone Manini / http://daron1337.github.io + * @author Luca Antiga / http://lantiga.github.io + */ +export default function (THREE) { + + let { + EventDispatcher, + MOUSE, + Quaternion, + Vector2, + Vector3, + global: window, + } = THREE; + let document = window.document; + + + var TrackballControls = function (object, domElement) { + + if (domElement === undefined) console.warn('THREE.TrackballControls: The second parameter "domElement" is now mandatory.'); + if (domElement === document) console.error('THREE.TrackballControls: "document" should not be used as the target "domElement". Please use "renderer.domElement" instead.'); + + var _this = this; + var STATE = { NONE: - 1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM_PAN: 4 }; + + this.object = object; + this.domElement = domElement; + + // API + + this.enabled = true; + + this.screen = { left: 0, top: 0, width: 0, height: 0 }; + + this.rotateSpeed = 1.0; + this.zoomSpeed = 1.2; + this.panSpeed = 0.3; + + this.noRotate = false; + this.noZoom = false; + this.noPan = false; + + this.staticMoving = false; + this.dynamicDampingFactor = 0.2; + + this.minDistance = 0; + this.maxDistance = Infinity; + + this.keys = [65 /*A*/, 83 /*S*/, 68 /*D*/]; + + this.mouseButtons = { LEFT: MOUSE.ROTATE, MIDDLE: MOUSE.ZOOM, RIGHT: MOUSE.PAN }; + + // internals + + this.target = new Vector3(); + + var EPS = 0.000001; + + var lastPosition = new Vector3(); + var lastZoom = 1; + + var _state = STATE.NONE, + _keyState = STATE.NONE, + + _eye = new Vector3(), + + _movePrev = new Vector2(), + _moveCurr = new Vector2(), + + _lastAxis = new Vector3(), + _lastAngle = 0, + + _zoomStart = new Vector2(), + _zoomEnd = new Vector2(), + + _touchZoomDistanceStart = 0, + _touchZoomDistanceEnd = 0, + + _panStart = new Vector2(), + _panEnd = new Vector2(); + + // for reset + + this.target0 = this.target.clone(); + this.position0 = this.object.position.clone(); + this.up0 = this.object.up.clone(); + this.zoom0 = this.object.zoom; + + // events + + var changeEvent = { type: 'change' }; + var startEvent = { type: 'start' }; + var endEvent = { type: 'end' }; + + + // methods + + this.handleResize = function () { + + var box = this.domElement.getBoundingClientRect(); + // adjustments come from similar code in the jquery offset() function + // var d = this.domElement.ownerDocument.documentElement; + var d = document.documentElement; + this.screen.left = box.left + window.scrollX - d.clientLeft; + this.screen.top = box.top + window.scrollY - d.clientTop; + this.screen.width = box.width; + this.screen.height = box.height; + + }; + + var getMouseOnScreen = (function () { + + var vector = new Vector2(); + + return function getMouseOnScreen(pageX, pageY) { + + vector.set( + (pageX - _this.screen.left) / _this.screen.width, + (pageY - _this.screen.top) / _this.screen.height + ); + + return vector; + + }; + + }()); + + var getMouseOnCircle = (function () { + + var vector = new Vector2(); + + return function getMouseOnCircle(pageX, pageY) { + + vector.set( + ((pageX - _this.screen.width * 0.5 - _this.screen.left) / (_this.screen.width * 0.5)), + ((_this.screen.height + 2 * (_this.screen.top - pageY)) / _this.screen.width) // screen.width intentional + ); + + return vector; + + }; + + }()); + + this.rotateCamera = (function () { + + var axis = new Vector3(), + quaternion = new Quaternion(), + eyeDirection = new Vector3(), + objectUpDirection = new Vector3(), + objectSidewaysDirection = new Vector3(), + moveDirection = new Vector3(), + angle; + + return function rotateCamera() { + + moveDirection.set(_moveCurr.x - _movePrev.x, _moveCurr.y - _movePrev.y, 0); + angle = moveDirection.length(); + + if (angle) { + + _eye.copy(_this.object.position).sub(_this.target); + + eyeDirection.copy(_eye).normalize(); + objectUpDirection.copy(_this.object.up).normalize(); + objectSidewaysDirection.crossVectors(objectUpDirection, eyeDirection).normalize(); + + objectUpDirection.setLength(_moveCurr.y - _movePrev.y); + objectSidewaysDirection.setLength(_moveCurr.x - _movePrev.x); + + moveDirection.copy(objectUpDirection.add(objectSidewaysDirection)); + + axis.crossVectors(moveDirection, _eye).normalize(); + + angle *= _this.rotateSpeed; + quaternion.setFromAxisAngle(axis, angle); + + _eye.applyQuaternion(quaternion); + _this.object.up.applyQuaternion(quaternion); + + _lastAxis.copy(axis); + _lastAngle = angle; + + } else if (!_this.staticMoving && _lastAngle) { + + _lastAngle *= Math.sqrt(1.0 - _this.dynamicDampingFactor); + _eye.copy(_this.object.position).sub(_this.target); + quaternion.setFromAxisAngle(_lastAxis, _lastAngle); + _eye.applyQuaternion(quaternion); + _this.object.up.applyQuaternion(quaternion); + + } + + _movePrev.copy(_moveCurr); + + }; + + }()); + + + this.zoomCamera = function () { + + var factor; + + if (_state === STATE.TOUCH_ZOOM_PAN) { + + factor = _touchZoomDistanceStart / _touchZoomDistanceEnd; + _touchZoomDistanceStart = _touchZoomDistanceEnd; + + if (_this.object.isPerspectiveCamera) { + + _eye.multiplyScalar(factor); + + } else if (_this.object.isOrthographicCamera) { + + _this.object.zoom *= factor; + _this.object.updateProjectionMatrix(); + + } else { + + console.warn('THREE.TrackballControls: Unsupported camera type'); + + } + + } else { + + factor = 1.0 + (_zoomEnd.y - _zoomStart.y) * _this.zoomSpeed; + + if (factor !== 1.0 && factor > 0.0) { + + if (_this.object.isPerspectiveCamera) { + + _eye.multiplyScalar(factor); + + } else if (_this.object.isOrthographicCamera) { + + _this.object.zoom /= factor; + _this.object.updateProjectionMatrix(); + + } else { + + console.warn('THREE.TrackballControls: Unsupported camera type'); + + } + + } + + if (_this.staticMoving) { + + _zoomStart.copy(_zoomEnd); + + } else { + + _zoomStart.y += (_zoomEnd.y - _zoomStart.y) * this.dynamicDampingFactor; + + } + + } + + }; + + this.panCamera = (function () { + + var mouseChange = new Vector2(), + objectUp = new Vector3(), + pan = new Vector3(); + + return function panCamera() { + + mouseChange.copy(_panEnd).sub(_panStart); + + if (mouseChange.lengthSq()) { + + if (_this.object.isOrthographicCamera) { + + var scale_x = (_this.object.right - _this.object.left) / _this.object.zoom / _this.domElement.clientWidth; + var scale_y = (_this.object.top - _this.object.bottom) / _this.object.zoom / _this.domElement.clientWidth; + + mouseChange.x *= scale_x; + mouseChange.y *= scale_y; + + } + + mouseChange.multiplyScalar(_eye.length() * _this.panSpeed); + + pan.copy(_eye).cross(_this.object.up).setLength(mouseChange.x); + pan.add(objectUp.copy(_this.object.up).setLength(mouseChange.y)); + + _this.object.position.add(pan); + _this.target.add(pan); + + if (_this.staticMoving) { + + _panStart.copy(_panEnd); + + } else { + + _panStart.add(mouseChange.subVectors(_panEnd, _panStart).multiplyScalar(_this.dynamicDampingFactor)); + + } + + } + + }; + + }()); + + this.checkDistances = function () { + + if (!_this.noZoom || !_this.noPan) { + + if (_eye.lengthSq() > _this.maxDistance * _this.maxDistance) { + + _this.object.position.addVectors(_this.target, _eye.setLength(_this.maxDistance)); + _zoomStart.copy(_zoomEnd); + + } + + if (_eye.lengthSq() < _this.minDistance * _this.minDistance) { + + _this.object.position.addVectors(_this.target, _eye.setLength(_this.minDistance)); + _zoomStart.copy(_zoomEnd); + + } + + } + + }; + + this.update = function () { + + _eye.subVectors(_this.object.position, _this.target); + + if (!_this.noRotate) { + + _this.rotateCamera(); + + } + + if (!_this.noZoom) { + + _this.zoomCamera(); + + } + + if (!_this.noPan) { + + _this.panCamera(); + + } + + _this.object.position.addVectors(_this.target, _eye); + + if (_this.object.isPerspectiveCamera) { + + _this.checkDistances(); + + _this.object.lookAt(_this.target); + + if (lastPosition.distanceToSquared(_this.object.position) > EPS) { + + _this.dispatchEvent(changeEvent); + + lastPosition.copy(_this.object.position); + + } + + } else if (_this.object.isOrthographicCamera) { + + _this.object.lookAt(_this.target); + + if (lastPosition.distanceToSquared(_this.object.position) > EPS || lastZoom !== _this.object.zoom) { + + _this.dispatchEvent(changeEvent); + + lastPosition.copy(_this.object.position); + lastZoom = _this.object.zoom; + + } + + } else { + + console.warn('THREE.TrackballControls: Unsupported camera type'); + + } + + }; + + this.reset = function () { + + _state = STATE.NONE; + _keyState = STATE.NONE; + + _this.target.copy(_this.target0); + _this.object.position.copy(_this.position0); + _this.object.up.copy(_this.up0); + _this.object.zoom = _this.zoom0; + + _this.object.updateProjectionMatrix(); + + _eye.subVectors(_this.object.position, _this.target); + + _this.object.lookAt(_this.target); + + _this.dispatchEvent(changeEvent); + + lastPosition.copy(_this.object.position); + lastZoom = _this.object.zoom; + + }; + + // listeners + + function keydown(event) { + + if (_this.enabled === false) return; + + window.removeEventListener('keydown', keydown); + + if (_keyState !== STATE.NONE) { + + return; + + } else if (event.keyCode === _this.keys[STATE.ROTATE] && !_this.noRotate) { + + _keyState = STATE.ROTATE; + + } else if (event.keyCode === _this.keys[STATE.ZOOM] && !_this.noZoom) { + + _keyState = STATE.ZOOM; + + } else if (event.keyCode === _this.keys[STATE.PAN] && !_this.noPan) { + + _keyState = STATE.PAN; + + } + + } + + function keyup() { + + if (_this.enabled === false) return; + + _keyState = STATE.NONE; + + window.addEventListener('keydown', keydown, false); + + } + + function mousedown(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + event.stopPropagation(); + + if (_state === STATE.NONE) { + + switch (event.button) { + + case _this.mouseButtons.LEFT: + _state = STATE.ROTATE; + break; + + case _this.mouseButtons.MIDDLE: + _state = STATE.ZOOM; + break; + + case _this.mouseButtons.RIGHT: + _state = STATE.PAN; + break; + + default: + _state = STATE.NONE; + + } + + } + + var state = (_keyState !== STATE.NONE) ? _keyState : _state; + + if (state === STATE.ROTATE && !_this.noRotate) { + + _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); + _movePrev.copy(_moveCurr); + + } else if (state === STATE.ZOOM && !_this.noZoom) { + + _zoomStart.copy(getMouseOnScreen(event.pageX, event.pageY)); + _zoomEnd.copy(_zoomStart); + + } else if (state === STATE.PAN && !_this.noPan) { + + _panStart.copy(getMouseOnScreen(event.pageX, event.pageY)); + _panEnd.copy(_panStart); + + } + + document.addEventListener('mousemove', mousemove, false); + document.addEventListener('mouseup', mouseup, false); + + _this.dispatchEvent(startEvent); + + } + + function mousemove(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + event.stopPropagation(); + + var state = (_keyState !== STATE.NONE) ? _keyState : _state; + + if (state === STATE.ROTATE && !_this.noRotate) { + + _movePrev.copy(_moveCurr); + _moveCurr.copy(getMouseOnCircle(event.pageX, event.pageY)); + + } else if (state === STATE.ZOOM && !_this.noZoom) { + + _zoomEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); + + } else if (state === STATE.PAN && !_this.noPan) { + + _panEnd.copy(getMouseOnScreen(event.pageX, event.pageY)); + + } + + } + + function mouseup(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + event.stopPropagation(); + + _state = STATE.NONE; + + document.removeEventListener('mousemove', mousemove); + document.removeEventListener('mouseup', mouseup); + _this.dispatchEvent(endEvent); + + } + + function mousewheel(event) { + + if (_this.enabled === false) return; + + if (_this.noZoom === true) return; + + event.preventDefault(); + event.stopPropagation(); + + switch (event.deltaMode) { + + case 2: + // Zoom in pages + _zoomStart.y -= event.deltaY * 0.025; + break; + + case 1: + // Zoom in lines + _zoomStart.y -= event.deltaY * 0.01; + break; + + default: + // undefined, 0, assume pixels + _zoomStart.y -= event.deltaY * 0.00025; + break; + + } + + _this.dispatchEvent(startEvent); + _this.dispatchEvent(endEvent); + + } + + function touchstart(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + + switch (event.touches.length) { + + case 1: + _state = STATE.TOUCH_ROTATE; + _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); + _movePrev.copy(_moveCurr); + break; + + default: // 2 or more + _state = STATE.TOUCH_ZOOM_PAN; + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + _touchZoomDistanceEnd = _touchZoomDistanceStart = Math.sqrt(dx * dx + dy * dy); + + var x = (event.touches[0].pageX + event.touches[1].pageX) / 2; + var y = (event.touches[0].pageY + event.touches[1].pageY) / 2; + _panStart.copy(getMouseOnScreen(x, y)); + _panEnd.copy(_panStart); + break; + + } + + _this.dispatchEvent(startEvent); + + } + + function touchmove(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + event.stopPropagation(); + + switch (event.touches.length) { + + case 1: + _movePrev.copy(_moveCurr); + _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); + break; + + default: // 2 or more + var dx = event.touches[0].pageX - event.touches[1].pageX; + var dy = event.touches[0].pageY - event.touches[1].pageY; + _touchZoomDistanceEnd = Math.sqrt(dx * dx + dy * dy); + + var x = (event.touches[0].pageX + event.touches[1].pageX) / 2; + var y = (event.touches[0].pageY + event.touches[1].pageY) / 2; + _panEnd.copy(getMouseOnScreen(x, y)); + break; + + } + + } + + function touchend(event) { + + if (_this.enabled === false) return; + + switch (event.touches.length) { + + case 0: + _state = STATE.NONE; + break; + + case 1: + _state = STATE.TOUCH_ROTATE; + _moveCurr.copy(getMouseOnCircle(event.touches[0].pageX, event.touches[0].pageY)); + _movePrev.copy(_moveCurr); + break; + + } + + _this.dispatchEvent(endEvent); + + } + + function contextmenu(event) { + + if (_this.enabled === false) return; + + event.preventDefault(); + + } + + this.dispose = function () { + + this.domElement.removeEventListener('contextmenu', contextmenu, false); + this.domElement.removeEventListener('mousedown', mousedown, false); + this.domElement.removeEventListener('wheel', mousewheel, false); + + this.domElement.removeEventListener('touchstart', touchstart, false); + this.domElement.removeEventListener('touchend', touchend, false); + this.domElement.removeEventListener('touchmove', touchmove, false); + + document.removeEventListener('mousemove', mousemove, false); + document.removeEventListener('mouseup', mouseup, false); + + window.removeEventListener('keydown', keydown, false); + window.removeEventListener('keyup', keyup, false); + + }; + + this.domElement.addEventListener('contextmenu', contextmenu, false); + this.domElement.addEventListener('mousedown', mousedown, false); + this.domElement.addEventListener('wheel', mousewheel, false); + + this.domElement.addEventListener('touchstart', touchstart, false); + this.domElement.addEventListener('touchend', touchend, false); + this.domElement.addEventListener('touchmove', touchmove, false); + + window.addEventListener('keydown', keydown, false); + window.addEventListener('keyup', keyup, false); + + this.handleResize(); + + // force an update at start + this.update(); + + }; + + TrackballControls.prototype = Object.create(EventDispatcher.prototype); + TrackballControls.prototype.constructor = TrackballControls; + + return { TrackballControls }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/loaders/DDSLoader.js b/src/wechat_app/jsm/loaders/DDSLoader.js new file mode 100644 index 0000000..319e360 --- /dev/null +++ b/src/wechat_app/jsm/loaders/DDSLoader.js @@ -0,0 +1,285 @@ +/** + * @author mrdoob / http://mrdoob.com/ + */ +export default function (THREE) { + let { + CompressedTextureLoader, + RGBAFormat, + RGBA_S3TC_DXT3_Format, + RGBA_S3TC_DXT5_Format, + RGB_ETC1_Format, + RGB_S3TC_DXT1_Format + } = THREE; + + var DDSLoader = function (manager) { + + CompressedTextureLoader.call(this, manager); + + }; + + DDSLoader.prototype = Object.assign(Object.create(CompressedTextureLoader.prototype), { + + constructor: DDSLoader, + + parse: function (buffer, loadMipmaps) { + + var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; + + // Adapted from @toji's DDS utils + // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js + + // All values and structures referenced from: + // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ + + var DDS_MAGIC = 0x20534444; + + var DDSD_CAPS = 0x1, + DDSD_HEIGHT = 0x2, + DDSD_WIDTH = 0x4, + DDSD_PITCH = 0x8, + DDSD_PIXELFORMAT = 0x1000, + DDSD_MIPMAPCOUNT = 0x20000, + DDSD_LINEARSIZE = 0x80000, + DDSD_DEPTH = 0x800000; + + var DDSCAPS_COMPLEX = 0x8, + DDSCAPS_MIPMAP = 0x400000, + DDSCAPS_TEXTURE = 0x1000; + + var DDSCAPS2_CUBEMAP = 0x200, + DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, + DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, + DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, + DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, + DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, + DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, + DDSCAPS2_VOLUME = 0x200000; + + var DDPF_ALPHAPIXELS = 0x1, + DDPF_ALPHA = 0x2, + DDPF_FOURCC = 0x4, + DDPF_RGB = 0x40, + DDPF_YUV = 0x200, + DDPF_LUMINANCE = 0x20000; + + function fourCCToInt32(value) { + + return value.charCodeAt(0) + + (value.charCodeAt(1) << 8) + + (value.charCodeAt(2) << 16) + + (value.charCodeAt(3) << 24); + + } + + function int32ToFourCC(value) { + + return String.fromCharCode( + value & 0xff, + (value >> 8) & 0xff, + (value >> 16) & 0xff, + (value >> 24) & 0xff + ); + + } + + function loadARGBMip(buffer, dataOffset, width, height) { + + var dataLength = width * height * 4; + var srcBuffer = new Uint8Array(buffer, dataOffset, dataLength); + var byteArray = new Uint8Array(dataLength); + var dst = 0; + var src = 0; + for (var y = 0; y < height; y++) { + + for (var x = 0; x < width; x++) { + + var b = srcBuffer[src]; src++; + var g = srcBuffer[src]; src++; + var r = srcBuffer[src]; src++; + var a = srcBuffer[src]; src++; + byteArray[dst] = r; dst++; //r + byteArray[dst] = g; dst++; //g + byteArray[dst] = b; dst++; //b + byteArray[dst] = a; dst++; //a + + } + + } + return byteArray; + + } + + var FOURCC_DXT1 = fourCCToInt32("DXT1"); + var FOURCC_DXT3 = fourCCToInt32("DXT3"); + var FOURCC_DXT5 = fourCCToInt32("DXT5"); + var FOURCC_ETC1 = fourCCToInt32("ETC1"); + + var headerLengthInt = 31; // The header length in 32 bit ints + + // Offsets into the header array + + var off_magic = 0; + + var off_size = 1; + var off_flags = 2; + var off_height = 3; + var off_width = 4; + + var off_mipmapCount = 7; + + var off_pfFlags = 20; + var off_pfFourCC = 21; + var off_RGBBitCount = 22; + var off_RBitMask = 23; + var off_GBitMask = 24; + var off_BBitMask = 25; + var off_ABitMask = 26; + + var off_caps = 27; + var off_caps2 = 28; + var off_caps3 = 29; + var off_caps4 = 30; + + // Parse header + + var header = new Int32Array(buffer, 0, headerLengthInt); + + if (header[off_magic] !== DDS_MAGIC) { + + console.error('THREE.DDSLoader.parse: Invalid magic number in DDS header.'); + return dds; + + } + + if (!header[off_pfFlags] & DDPF_FOURCC) { + + console.error('THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.'); + return dds; + + } + + var blockBytes; + + var fourCC = header[off_pfFourCC]; + + var isRGBAUncompressed = false; + + switch (fourCC) { + + case FOURCC_DXT1: + + blockBytes = 8; + dds.format = RGB_S3TC_DXT1_Format; + break; + + case FOURCC_DXT3: + + blockBytes = 16; + dds.format = RGBA_S3TC_DXT3_Format; + break; + + case FOURCC_DXT5: + + blockBytes = 16; + dds.format = RGBA_S3TC_DXT5_Format; + break; + + case FOURCC_ETC1: + + blockBytes = 8; + dds.format = RGB_ETC1_Format; + break; + + default: + + if (header[off_RGBBitCount] === 32 + && header[off_RBitMask] & 0xff0000 + && header[off_GBitMask] & 0xff00 + && header[off_BBitMask] & 0xff + && header[off_ABitMask] & 0xff000000) { + + isRGBAUncompressed = true; + blockBytes = 64; + dds.format = RGBAFormat; + + } else { + + console.error('THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC(fourCC)); + return dds; + + } + + } + + dds.mipmapCount = 1; + + if (header[off_flags] & DDSD_MIPMAPCOUNT && loadMipmaps !== false) { + + dds.mipmapCount = Math.max(1, header[off_mipmapCount]); + + } + + var caps2 = header[off_caps2]; + dds.isCubemap = caps2 & DDSCAPS2_CUBEMAP ? true : false; + if (dds.isCubemap && ( + !(caps2 & DDSCAPS2_CUBEMAP_POSITIVEX) || + !(caps2 & DDSCAPS2_CUBEMAP_NEGATIVEX) || + !(caps2 & DDSCAPS2_CUBEMAP_POSITIVEY) || + !(caps2 & DDSCAPS2_CUBEMAP_NEGATIVEY) || + !(caps2 & DDSCAPS2_CUBEMAP_POSITIVEZ) || + !(caps2 & DDSCAPS2_CUBEMAP_NEGATIVEZ) + )) { + + console.error('THREE.DDSLoader.parse: Incomplete cubemap faces'); + return dds; + + } + + dds.width = header[off_width]; + dds.height = header[off_height]; + + var dataOffset = header[off_size] + 4; + + // Extract mipmaps buffers + + var faces = dds.isCubemap ? 6 : 1; + + for (var face = 0; face < faces; face++) { + + var width = dds.width; + var height = dds.height; + + for (var i = 0; i < dds.mipmapCount; i++) { + + if (isRGBAUncompressed) { + + var byteArray = loadARGBMip(buffer, dataOffset, width, height); + var dataLength = byteArray.length; + + } else { + + var dataLength = Math.max(4, width) / 4 * Math.max(4, height) / 4 * blockBytes; + var byteArray = new Uint8Array(buffer, dataOffset, dataLength); + + } + + var mipmap = { "data": byteArray, "width": width, "height": height }; + dds.mipmaps.push(mipmap); + + dataOffset += dataLength; + + width = Math.max(width >> 1, 1); + height = Math.max(height >> 1, 1); + + } + + } + + return dds; + + } + + }); + + return { DDSLoader }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/loaders/EquirectangularToCubeGenerator.js b/src/wechat_app/jsm/loaders/EquirectangularToCubeGenerator.js new file mode 100644 index 0000000..bd32096 --- /dev/null +++ b/src/wechat_app/jsm/loaders/EquirectangularToCubeGenerator.js @@ -0,0 +1,252 @@ +/** +* @author Richard M. / https://github.com/richardmonette +* @author WestLangley / http://github.com/WestLangley +*/ +export default function (THREE) { +let { + BackSide, + BoxBufferGeometry, + CubeCamera, + Mesh, + NoBlending, + PerspectiveCamera, + Scene, + ShaderMaterial, + UniformsUtils, + WebGLRenderTargetCube +} = THREE; + +var CubemapGenerator = function ( renderer ) { + + this.renderer = renderer; + +}; + +CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) { + + options = options || {}; + + var scene = new Scene(); + + var shader = { + + uniforms: { + tEquirect: { value: null }, + }, + + vertexShader: + + ` + varying vec3 vWorldDirection; + + //include + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { + + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); + + } + + void main() { + + vWorldDirection = transformDirection( position, modelMatrix ); + + #include + #include + + } + `, + + fragmentShader: + + ` + uniform sampler2D tEquirect; + + varying vec3 vWorldDirection; + + //include + #define RECIPROCAL_PI 0.31830988618 + #define RECIPROCAL_PI2 0.15915494 + + void main() { + + vec3 direction = normalize( vWorldDirection ); + + vec2 sampleUV; + + sampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; + + sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5; + + gl_FragColor = texture2D( tEquirect, sampleUV ); + + } + ` + }; + + var material = new ShaderMaterial( { + + type: 'CubemapFromEquirect', + + uniforms: UniformsUtils.clone( shader.uniforms ), + vertexShader: shader.vertexShader, + fragmentShader: shader.fragmentShader, + side: BackSide, + blending: NoBlending + + } ); + + material.uniforms.tEquirect.value = texture; + + var mesh = new Mesh( new BoxBufferGeometry( 5, 5, 5 ), material ); + + scene.add( mesh ); + + var resolution = options.resolution || 512; + + var params = { + type: texture.type, + format: texture.format, + encoding: texture.encoding, + generateMipmaps: ( options.generateMipmaps !== undefined ) ? options.generateMipmaps : texture.generateMipmaps, + minFilter: ( options.minFilter !== undefined ) ? options.minFilter : texture.minFilter, + magFilter: ( options.magFilter !== undefined ) ? options.magFilter : texture.magFilter + }; + + var camera = new CubeCamera( 1, 10, resolution, params ); + + camera.update( this.renderer, scene ); + + mesh.geometry.dispose(); + mesh.material.dispose(); + + return camera.renderTarget; + +}; + +// + +var EquirectangularToCubeGenerator = ( function () { + + var camera = new PerspectiveCamera( 90, 1, 0.1, 10 ); + var scene = new Scene(); + var boxMesh = new Mesh( new BoxBufferGeometry( 1, 1, 1 ), getShader() ); + boxMesh.material.side = BackSide; + scene.add( boxMesh ); + + var EquirectangularToCubeGenerator = function ( sourceTexture, options ) { + + options = options || {}; + + this.sourceTexture = sourceTexture; + this.resolution = options.resolution || 512; + + this.views = [ + { t: [ 1, 0, 0 ], u: [ 0, - 1, 0 ] }, + { t: [ - 1, 0, 0 ], u: [ 0, - 1, 0 ] }, + { t: [ 0, 1, 0 ], u: [ 0, 0, 1 ] }, + { t: [ 0, - 1, 0 ], u: [ 0, 0, - 1 ] }, + { t: [ 0, 0, 1 ], u: [ 0, - 1, 0 ] }, + { t: [ 0, 0, - 1 ], u: [ 0, - 1, 0 ] }, + ]; + + var params = { + format: options.format || this.sourceTexture.format, + magFilter: this.sourceTexture.magFilter, + minFilter: this.sourceTexture.minFilter, + type: options.type || this.sourceTexture.type, + generateMipmaps: this.sourceTexture.generateMipmaps, + anisotropy: this.sourceTexture.anisotropy, + encoding: this.sourceTexture.encoding + }; + + this.renderTarget = new WebGLRenderTargetCube( this.resolution, this.resolution, params ); + + }; + + EquirectangularToCubeGenerator.prototype = { + + constructor: EquirectangularToCubeGenerator, + + update: function ( renderer ) { + + var currentRenderTarget = renderer.getRenderTarget(); + + boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture; + + for ( var i = 0; i < 6; i ++ ) { + + var v = this.views[ i ]; + + camera.position.set( 0, 0, 0 ); + camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] ); + camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] ); + + renderer.setRenderTarget( this.renderTarget, i ); + renderer.clear(); + renderer.render( scene, camera ); + + } + + renderer.setRenderTarget( currentRenderTarget ); + + return this.renderTarget.texture; + + }, + + dispose: function () { + + this.renderTarget.dispose(); + + } + + }; + + function getShader() { + + var shaderMaterial = new ShaderMaterial( { + + uniforms: { + "equirectangularMap": { value: null }, + }, + + vertexShader: + "varying vec3 localPosition;\n\ + \n\ + void main() {\n\ + localPosition = position;\n\ + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ + }", + + fragmentShader: + "#include \n\ + varying vec3 localPosition;\n\ + uniform sampler2D equirectangularMap;\n\ + \n\ + vec2 EquirectangularSampleUV(vec3 v) {\n\ + vec2 uv = vec2(atan(v.z, v.x), asin(v.y));\n\ + uv *= vec2(0.1591, 0.3183); // inverse atan\n\ + uv += 0.5;\n\ + return uv;\n\ + }\n\ + \n\ + void main() {\n\ + vec2 uv = EquirectangularSampleUV(normalize(localPosition));\n\ + gl_FragColor = texture2D(equirectangularMap, uv);\n\ + }", + + blending: NoBlending + + } ); + + shaderMaterial.type = 'EquirectangularToCubeGenerator'; + + return shaderMaterial; + + } + + return EquirectangularToCubeGenerator; + +} )(); + +return { CubemapGenerator, EquirectangularToCubeGenerator }; +} diff --git a/src/wechat_app/jsm/loaders/GLTFLoader.js b/src/wechat_app/jsm/loaders/GLTFLoader.js new file mode 100644 index 0000000..d747b15 --- /dev/null +++ b/src/wechat_app/jsm/loaders/GLTFLoader.js @@ -0,0 +1,3284 @@ +/** + * @author Rich Tibbett / https://github.com/richtr + * @author mrdoob / http://mrdoob.com/ + * @author Tony Parisi / http://www.tonyparisi.com/ + * @author Takahiro / https://github.com/takahirox + * @author Don McCurdy / https://www.donmccurdy.com + */ + + +export default function (THREE) { + let { + AnimationClip, + Bone, + BufferAttribute, + BufferGeometry, + ClampToEdgeWrapping, + Color, + DefaultLoadingManager, + DirectionalLight, + DoubleSide, + FileLoader, + FrontSide, + Group, + InterleavedBuffer, + InterleavedBufferAttribute, + Interpolant, + InterpolateDiscrete, + InterpolateLinear, + Line, + LineBasicMaterial, + LineLoop, + LineSegments, + LinearFilter, + LinearMipmapLinearFilter, + LinearMipmapNearestFilter, + Loader, + LoaderUtils, + Material, + Math: _Math, + Matrix4, + Mesh, + MeshBasicMaterial, + MeshStandardMaterial, + MirroredRepeatWrapping, + NearestFilter, + NearestMipmapLinearFilter, + NearestMipmapNearestFilter, + NumberKeyframeTrack, + Object3D, + OrthographicCamera, + PerspectiveCamera, + PointLight, + Points, + PointsMaterial, + PropertyBinding, + QuaternionKeyframeTrack, + RGBAFormat, + RGBFormat, + RepeatWrapping, + Scene, + ShaderLib, + ShaderMaterial, + Skeleton, + SkinnedMesh, + SpotLight, + TextureLoader, + TriangleFanDrawMode, + TriangleStripDrawMode, + UniformsUtils, + Vector2, + VectorKeyframeTrack, + VertexColors, + sRGBEncoding, + global: window + } = THREE; + + function GLTFLoader(manager) { + + this.manager = (manager !== undefined) ? manager : DefaultLoadingManager; + this.dracoLoader = null; + this.ddsLoader = null; + + } + + GLTFLoader.prototype = { + + constructor: GLTFLoader, + + crossOrigin: 'anonymous', + + load: function (url, onLoad, onProgress, onError) { + + var scope = this; + + var resourcePath; + + if (this.resourcePath !== undefined) { + + resourcePath = this.resourcePath; + + } else if (this.path !== undefined) { + + resourcePath = this.path; + + } else { + + resourcePath = LoaderUtils.extractUrlBase(url); + + } + + // Tells the LoadingManager to track an extra item, which resolves after + // the model is fully loaded. This means the count of items loaded will + // be incorrect, but ensures manager.onLoad() does not fire early. + scope.manager.itemStart(url); + + var _onError = function (e) { + + if (onError) { + + onError(e); + + } else { + + console.error(e); + + } + + scope.manager.itemError(url); + scope.manager.itemEnd(url); + + }; + + var loader = new FileLoader(scope.manager); + + loader.setPath(this.path); + loader.setResponseType('arraybuffer'); + + if (scope.crossOrigin === 'use-credentials') { + + loader.setWithCredentials(true); + + } + + loader.load(url, function (data) { + + try { + + scope.parse(data, resourcePath, function (gltf) { + + onLoad(gltf); + + scope.manager.itemEnd(url); + + }, _onError); + + } catch (e) { + + _onError(e); + + } + + }, onProgress, _onError); + + }, + + setCrossOrigin: function (value) { + + this.crossOrigin = value; + return this; + + }, + + setPath: function (value) { + + this.path = value; + return this; + + }, + + setResourcePath: function (value) { + + this.resourcePath = value; + return this; + + }, + + setDRACOLoader: function (dracoLoader) { + + this.dracoLoader = dracoLoader; + return this; + + }, + + setDDSLoader: function (ddsLoader) { + + this.ddsLoader = ddsLoader; + return this; + + }, + + parse: function (data, path, onLoad, onError) { + + var content; + var extensions = {}; + + if (typeof data === 'string') { + + content = data; + + } else { + + var magic = LoaderUtils.decodeText(new Uint8Array(data, 0, 4)); + + if (magic === BINARY_EXTENSION_HEADER_MAGIC) { + + try { + + extensions[EXTENSIONS.KHR_BINARY_GLTF] = new GLTFBinaryExtension(data); + + } catch (error) { + + if (onError) onError(error); + return; + + } + + content = extensions[EXTENSIONS.KHR_BINARY_GLTF].content; + + } else { + + content = LoaderUtils.decodeText(new Uint8Array(data)); + + } + + } + + var json = JSON.parse(content); + + if (json.asset === undefined || json.asset.version[0] < 2) { + + if (onError) onError(new Error('THREE.GLTFLoader: Unsupported asset. glTF versions >=2.0 are supported. Use LegacyGLTFLoader instead.')); + return; + + } + + if (json.extensionsUsed) { + + for (var i = 0; i < json.extensionsUsed.length; ++i) { + + var extensionName = json.extensionsUsed[i]; + var extensionsRequired = json.extensionsRequired || []; + + switch (extensionName) { + + case EXTENSIONS.KHR_LIGHTS_PUNCTUAL: + extensions[extensionName] = new GLTFLightsExtension(json); + break; + + case EXTENSIONS.KHR_MATERIALS_UNLIT: + extensions[extensionName] = new GLTFMaterialsUnlitExtension(); + break; + + case EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: + extensions[extensionName] = new GLTFMaterialsPbrSpecularGlossinessExtension(); + break; + + case EXTENSIONS.KHR_DRACO_MESH_COMPRESSION: + extensions[extensionName] = new GLTFDracoMeshCompressionExtension(json, this.dracoLoader); + break; + + case EXTENSIONS.MSFT_TEXTURE_DDS: + extensions[EXTENSIONS.MSFT_TEXTURE_DDS] = new GLTFTextureDDSExtension(this.ddsLoader); + break; + + case EXTENSIONS.KHR_TEXTURE_TRANSFORM: + extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] = new GLTFTextureTransformExtension(); + break; + + default: + + if (extensionsRequired.indexOf(extensionName) >= 0) { + + console.warn('THREE.GLTFLoader: Unknown extension "' + extensionName + '".'); + + } + + } + + } + + } + + var parser = new GLTFParser(json, extensions, { + + path: path || this.resourcePath || '', + crossOrigin: this.crossOrigin, + manager: this.manager + + }); + + parser.parse(onLoad, onError); + + } + + }; + + /* GLTFREGISTRY */ + + function GLTFRegistry() { + + var objects = {}; + + return { + + get: function (key) { + + return objects[key]; + + }, + + add: function (key, object) { + + objects[key] = object; + + }, + + remove: function (key) { + + delete objects[key]; + + }, + + removeAll: function () { + + objects = {}; + + } + + }; + + } + + /*********************************/ + /********** EXTENSIONS ***********/ + /*********************************/ + + var EXTENSIONS = { + KHR_BINARY_GLTF: 'KHR_binary_glTF', + KHR_DRACO_MESH_COMPRESSION: 'KHR_draco_mesh_compression', + KHR_LIGHTS_PUNCTUAL: 'KHR_lights_punctual', + KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS: 'KHR_materials_pbrSpecularGlossiness', + KHR_MATERIALS_UNLIT: 'KHR_materials_unlit', + KHR_TEXTURE_TRANSFORM: 'KHR_texture_transform', + MSFT_TEXTURE_DDS: 'MSFT_texture_dds' + }; + + /** + * DDS Texture Extension + * + * Specification: + * https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/MSFT_texture_dds + * + */ + function GLTFTextureDDSExtension(ddsLoader) { + + if (!ddsLoader) { + + throw new Error('THREE.GLTFLoader: Attempting to load .dds texture without importing DDSLoader'); + + } + + this.name = EXTENSIONS.MSFT_TEXTURE_DDS; + this.ddsLoader = ddsLoader; + + } + + /** + * Lights Extension + * + * Specification: PENDING + */ + function GLTFLightsExtension(json) { + + this.name = EXTENSIONS.KHR_LIGHTS_PUNCTUAL; + + var extension = (json.extensions && json.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL]) || {}; + this.lightDefs = extension.lights || []; + + } + + GLTFLightsExtension.prototype.loadLight = function (lightIndex) { + + var lightDef = this.lightDefs[lightIndex]; + var lightNode; + + var color = new Color(0xffffff); + if (lightDef.color !== undefined) color.fromArray(lightDef.color); + + var range = lightDef.range !== undefined ? lightDef.range : 0; + + switch (lightDef.type) { + + case 'directional': + lightNode = new DirectionalLight(color); + lightNode.target.position.set(0, 0, - 1); + lightNode.add(lightNode.target); + break; + + case 'point': + lightNode = new PointLight(color); + lightNode.distance = range; + break; + + case 'spot': + lightNode = new SpotLight(color); + lightNode.distance = range; + // Handle spotlight properties. + lightDef.spot = lightDef.spot || {}; + lightDef.spot.innerConeAngle = lightDef.spot.innerConeAngle !== undefined ? lightDef.spot.innerConeAngle : 0; + lightDef.spot.outerConeAngle = lightDef.spot.outerConeAngle !== undefined ? lightDef.spot.outerConeAngle : Math.PI / 4.0; + lightNode.angle = lightDef.spot.outerConeAngle; + lightNode.penumbra = 1.0 - lightDef.spot.innerConeAngle / lightDef.spot.outerConeAngle; + lightNode.target.position.set(0, 0, - 1); + lightNode.add(lightNode.target); + break; + + default: + throw new Error('THREE.GLTFLoader: Unexpected light type, "' + lightDef.type + '".'); + + } + + // Some lights (e.g. spot) default to a position other than the origin. Reset the position + // here, because node-level parsing will only override position if explicitly specified. + lightNode.position.set(0, 0, 0); + + lightNode.decay = 2; + + if (lightDef.intensity !== undefined) lightNode.intensity = lightDef.intensity; + + lightNode.name = lightDef.name || ('light_' + lightIndex); + + return Promise.resolve(lightNode); + + }; + + /** + * Unlit Materials Extension (pending) + * + * PR: https://github.com/KhronosGroup/glTF/pull/1163 + */ + function GLTFMaterialsUnlitExtension() { + + this.name = EXTENSIONS.KHR_MATERIALS_UNLIT; + + } + + GLTFMaterialsUnlitExtension.prototype.getMaterialType = function () { + + return MeshBasicMaterial; + + }; + + GLTFMaterialsUnlitExtension.prototype.extendParams = function (materialParams, materialDef, parser) { + + var pending = []; + + materialParams.color = new Color(1.0, 1.0, 1.0); + materialParams.opacity = 1.0; + + var metallicRoughness = materialDef.pbrMetallicRoughness; + + if (metallicRoughness) { + + if (Array.isArray(metallicRoughness.baseColorFactor)) { + + var array = metallicRoughness.baseColorFactor; + + materialParams.color.fromArray(array); + materialParams.opacity = array[3]; + + } + + if (metallicRoughness.baseColorTexture !== undefined) { + + pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture)); + + } + + } + + return Promise.all(pending); + + }; + + /* BINARY EXTENSION */ + var BINARY_EXTENSION_HEADER_MAGIC = 'glTF'; + var BINARY_EXTENSION_HEADER_LENGTH = 12; + var BINARY_EXTENSION_CHUNK_TYPES = { JSON: 0x4E4F534A, BIN: 0x004E4942 }; + + function GLTFBinaryExtension(data) { + + this.name = EXTENSIONS.KHR_BINARY_GLTF; + this.content = null; + this.body = null; + + var headerView = new DataView(data, 0, BINARY_EXTENSION_HEADER_LENGTH); + + this.header = { + magic: LoaderUtils.decodeText(new Uint8Array(data.slice(0, 4))), + version: headerView.getUint32(4, true), + length: headerView.getUint32(8, true) + }; + + if (this.header.magic !== BINARY_EXTENSION_HEADER_MAGIC) { + + throw new Error('THREE.GLTFLoader: Unsupported glTF-Binary header.'); + + } else if (this.header.version < 2.0) { + + throw new Error('THREE.GLTFLoader: Legacy binary file detected. Use LegacyGLTFLoader instead.'); + + } + + var chunkView = new DataView(data, BINARY_EXTENSION_HEADER_LENGTH); + var chunkIndex = 0; + + while (chunkIndex < chunkView.byteLength) { + + var chunkLength = chunkView.getUint32(chunkIndex, true); + chunkIndex += 4; + + var chunkType = chunkView.getUint32(chunkIndex, true); + chunkIndex += 4; + + if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.JSON) { + + var contentArray = new Uint8Array(data, BINARY_EXTENSION_HEADER_LENGTH + chunkIndex, chunkLength); + this.content = LoaderUtils.decodeText(contentArray); + + } else if (chunkType === BINARY_EXTENSION_CHUNK_TYPES.BIN) { + + var byteOffset = BINARY_EXTENSION_HEADER_LENGTH + chunkIndex; + this.body = data.slice(byteOffset, byteOffset + chunkLength); + + } + + // Clients must ignore chunks with unknown types. + + chunkIndex += chunkLength; + + } + + if (this.content === null) { + + throw new Error('THREE.GLTFLoader: JSON content not found.'); + + } + + } + + /** + * DRACO Mesh Compression Extension + * + * Specification: https://github.com/KhronosGroup/glTF/pull/874 + */ + function GLTFDracoMeshCompressionExtension(json, dracoLoader) { + + if (!dracoLoader) { + + throw new Error('THREE.GLTFLoader: No DRACOLoader instance provided.'); + + } + + this.name = EXTENSIONS.KHR_DRACO_MESH_COMPRESSION; + this.json = json; + this.dracoLoader = dracoLoader; + + } + + GLTFDracoMeshCompressionExtension.prototype.decodePrimitive = function (primitive, parser) { + + var json = this.json; + var dracoLoader = this.dracoLoader; + var bufferViewIndex = primitive.extensions[this.name].bufferView; + var gltfAttributeMap = primitive.extensions[this.name].attributes; + var threeAttributeMap = {}; + var attributeNormalizedMap = {}; + var attributeTypeMap = {}; + + for (var attributeName in gltfAttributeMap) { + + var threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); + + threeAttributeMap[threeAttributeName] = gltfAttributeMap[attributeName]; + + } + + for (attributeName in primitive.attributes) { + + var threeAttributeName = ATTRIBUTES[attributeName] || attributeName.toLowerCase(); + + if (gltfAttributeMap[attributeName] !== undefined) { + + var accessorDef = json.accessors[primitive.attributes[attributeName]]; + var componentType = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; + + attributeTypeMap[threeAttributeName] = componentType; + attributeNormalizedMap[threeAttributeName] = accessorDef.normalized === true; + + } + + } + + return parser.getDependency('bufferView', bufferViewIndex).then(function (bufferView) { + + return new Promise(function (resolve) { + + dracoLoader.decodeDracoFile(bufferView, function (geometry) { + + for (var attributeName in geometry.attributes) { + + var attribute = geometry.attributes[attributeName]; + var normalized = attributeNormalizedMap[attributeName]; + + if (normalized !== undefined) attribute.normalized = normalized; + + } + + resolve(geometry); + + }, threeAttributeMap, attributeTypeMap); + + }); + + }); + + }; + + /** + * Texture Transform Extension + * + * Specification: + */ + function GLTFTextureTransformExtension() { + + this.name = EXTENSIONS.KHR_TEXTURE_TRANSFORM; + + } + + GLTFTextureTransformExtension.prototype.extendTexture = function (texture, transform) { + + texture = texture.clone(); + + if (transform.offset !== undefined) { + + texture.offset.fromArray(transform.offset); + + } + + if (transform.rotation !== undefined) { + + texture.rotation = transform.rotation; + + } + + if (transform.scale !== undefined) { + + texture.repeat.fromArray(transform.scale); + + } + + if (transform.texCoord !== undefined) { + + console.warn('THREE.GLTFLoader: Custom UV sets in "' + this.name + '" extension not yet supported.'); + + } + + texture.needsUpdate = true; + + return texture; + + }; + + /** + * Specular-Glossiness Extension + * + * Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_materials_pbrSpecularGlossiness + */ + function GLTFMaterialsPbrSpecularGlossinessExtension() { + + return { + + name: EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS, + + specularGlossinessParams: [ + 'color', + 'map', + 'lightMap', + 'lightMapIntensity', + 'aoMap', + 'aoMapIntensity', + 'emissive', + 'emissiveIntensity', + 'emissiveMap', + 'bumpMap', + 'bumpScale', + 'normalMap', + 'displacementMap', + 'displacementScale', + 'displacementBias', + 'specularMap', + 'specular', + 'glossinessMap', + 'glossiness', + 'alphaMap', + 'envMap', + 'envMapIntensity', + 'refractionRatio', + ], + + getMaterialType: function () { + + return ShaderMaterial; + + }, + + extendParams: function (materialParams, materialDef, parser) { + + var pbrSpecularGlossiness = materialDef.extensions[this.name]; + + var shader = ShaderLib['standard']; + + var uniforms = UniformsUtils.clone(shader.uniforms); + + var specularMapParsFragmentChunk = [ + '#ifdef USE_SPECULARMAP', + ' uniform sampler2D specularMap;', + '#endif' + ].join('\n'); + + var glossinessMapParsFragmentChunk = [ + '#ifdef USE_GLOSSINESSMAP', + ' uniform sampler2D glossinessMap;', + '#endif' + ].join('\n'); + + var specularMapFragmentChunk = [ + 'vec3 specularFactor = specular;', + '#ifdef USE_SPECULARMAP', + ' vec4 texelSpecular = texture2D( specularMap, vUv );', + ' texelSpecular = sRGBToLinear( texelSpecular );', + ' // reads channel RGB, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' specularFactor *= texelSpecular.rgb;', + '#endif' + ].join('\n'); + + var glossinessMapFragmentChunk = [ + 'float glossinessFactor = glossiness;', + '#ifdef USE_GLOSSINESSMAP', + ' vec4 texelGlossiness = texture2D( glossinessMap, vUv );', + ' // reads channel A, compatible with a glTF Specular-Glossiness (RGBA) texture', + ' glossinessFactor *= texelGlossiness.a;', + '#endif' + ].join('\n'); + + var lightPhysicalFragmentChunk = [ + 'PhysicalMaterial material;', + 'material.diffuseColor = diffuseColor.rgb;', + 'material.specularRoughness = clamp( 1.0 - glossinessFactor, 0.04, 1.0 );', + 'material.specularColor = specularFactor.rgb;', + ].join('\n'); + + var fragmentShader = shader.fragmentShader + .replace('uniform float roughness;', 'uniform vec3 specular;') + .replace('uniform float metalness;', 'uniform float glossiness;') + .replace('#include ', specularMapParsFragmentChunk) + .replace('#include ', glossinessMapParsFragmentChunk) + .replace('#include ', specularMapFragmentChunk) + .replace('#include ', glossinessMapFragmentChunk) + .replace('#include ', lightPhysicalFragmentChunk); + + delete uniforms.roughness; + delete uniforms.metalness; + delete uniforms.roughnessMap; + delete uniforms.metalnessMap; + + uniforms.specular = { value: new Color().setHex(0x111111) }; + uniforms.glossiness = { value: 0.5 }; + uniforms.specularMap = { value: null }; + uniforms.glossinessMap = { value: null }; + + materialParams.vertexShader = shader.vertexShader; + materialParams.fragmentShader = fragmentShader; + materialParams.uniforms = uniforms; + materialParams.defines = { 'STANDARD': '' } + + materialParams.color = new Color(1.0, 1.0, 1.0); + materialParams.opacity = 1.0; + + var pending = []; + + if (Array.isArray(pbrSpecularGlossiness.diffuseFactor)) { + + var array = pbrSpecularGlossiness.diffuseFactor; + + materialParams.color.fromArray(array); + materialParams.opacity = array[3]; + + } + + if (pbrSpecularGlossiness.diffuseTexture !== undefined) { + + pending.push(parser.assignTexture(materialParams, 'map', pbrSpecularGlossiness.diffuseTexture)); + + } + + materialParams.emissive = new Color(0.0, 0.0, 0.0); + materialParams.glossiness = pbrSpecularGlossiness.glossinessFactor !== undefined ? pbrSpecularGlossiness.glossinessFactor : 1.0; + materialParams.specular = new Color(1.0, 1.0, 1.0); + + if (Array.isArray(pbrSpecularGlossiness.specularFactor)) { + + materialParams.specular.fromArray(pbrSpecularGlossiness.specularFactor); + + } + + if (pbrSpecularGlossiness.specularGlossinessTexture !== undefined) { + + var specGlossMapDef = pbrSpecularGlossiness.specularGlossinessTexture; + pending.push(parser.assignTexture(materialParams, 'glossinessMap', specGlossMapDef)); + pending.push(parser.assignTexture(materialParams, 'specularMap', specGlossMapDef)); + + } + + return Promise.all(pending); + + }, + + createMaterial: function (params) { + + // setup material properties based on MeshStandardMaterial for Specular-Glossiness + + var material = new ShaderMaterial({ + defines: params.defines, + vertexShader: params.vertexShader, + fragmentShader: params.fragmentShader, + uniforms: params.uniforms, + fog: true, + lights: true, + opacity: params.opacity, + transparent: params.transparent + }); + + material.isGLTFSpecularGlossinessMaterial = true; + + material.color = params.color; + + material.map = params.map === undefined ? null : params.map; + + material.lightMap = null; + material.lightMapIntensity = 1.0; + + material.aoMap = params.aoMap === undefined ? null : params.aoMap; + material.aoMapIntensity = 1.0; + + material.emissive = params.emissive; + material.emissiveIntensity = 1.0; + material.emissiveMap = params.emissiveMap === undefined ? null : params.emissiveMap; + + material.bumpMap = params.bumpMap === undefined ? null : params.bumpMap; + material.bumpScale = 1; + + material.normalMap = params.normalMap === undefined ? null : params.normalMap; + + if (params.normalScale) material.normalScale = params.normalScale; + + material.displacementMap = null; + material.displacementScale = 1; + material.displacementBias = 0; + + material.specularMap = params.specularMap === undefined ? null : params.specularMap; + material.specular = params.specular; + + material.glossinessMap = params.glossinessMap === undefined ? null : params.glossinessMap; + material.glossiness = params.glossiness; + + material.alphaMap = null; + + material.envMap = params.envMap === undefined ? null : params.envMap; + material.envMapIntensity = 1.0; + + material.refractionRatio = 0.98; + + material.extensions.derivatives = true; + + return material; + + }, + + /** + * Clones a GLTFSpecularGlossinessMaterial instance. The ShaderMaterial.copy() method can + * copy only properties it knows about or inherits, and misses many properties that would + * normally be defined by MeshStandardMaterial. + * + * This method allows GLTFSpecularGlossinessMaterials to be cloned in the process of + * loading a glTF model, but cloning later (e.g. by the user) would require these changes + * AND also updating `.onBeforeRender` on the parent mesh. + * + * @param {ShaderMaterial} source + * @return {ShaderMaterial} + */ + cloneMaterial: function (source) { + + var target = source.clone(); + + target.isGLTFSpecularGlossinessMaterial = true; + + var params = this.specularGlossinessParams; + + for (var i = 0, il = params.length; i < il; i++) { + + var value = source[params[i]]; + target[params[i]] = (value && value.isColor) ? value.clone() : value; + + } + + return target; + + }, + + // Here's based on refreshUniformsCommon() and refreshUniformsStandard() in WebGLRenderer. + refreshUniforms: function (renderer, scene, camera, geometry, material) { + + if (material.isGLTFSpecularGlossinessMaterial !== true) { + + return; + + } + + var uniforms = material.uniforms; + var defines = material.defines; + + uniforms.opacity.value = material.opacity; + + uniforms.diffuse.value.copy(material.color); + uniforms.emissive.value.copy(material.emissive).multiplyScalar(material.emissiveIntensity); + + uniforms.map.value = material.map; + uniforms.specularMap.value = material.specularMap; + uniforms.alphaMap.value = material.alphaMap; + + uniforms.lightMap.value = material.lightMap; + uniforms.lightMapIntensity.value = material.lightMapIntensity; + + uniforms.aoMap.value = material.aoMap; + uniforms.aoMapIntensity.value = material.aoMapIntensity; + + // uv repeat and offset setting priorities + // 1. color map + // 2. specular map + // 3. normal map + // 4. bump map + // 5. alpha map + // 6. emissive map + + var uvScaleMap; + + if (material.map) { + + uvScaleMap = material.map; + + } else if (material.specularMap) { + + uvScaleMap = material.specularMap; + + } else if (material.displacementMap) { + + uvScaleMap = material.displacementMap; + + } else if (material.normalMap) { + + uvScaleMap = material.normalMap; + + } else if (material.bumpMap) { + + uvScaleMap = material.bumpMap; + + } else if (material.glossinessMap) { + + uvScaleMap = material.glossinessMap; + + } else if (material.alphaMap) { + + uvScaleMap = material.alphaMap; + + } else if (material.emissiveMap) { + + uvScaleMap = material.emissiveMap; + + } + + if (uvScaleMap !== undefined) { + + // backwards compatibility + if (uvScaleMap.isWebGLRenderTarget) { + + uvScaleMap = uvScaleMap.texture; + + } + + if (uvScaleMap.matrixAutoUpdate === true) { + + uvScaleMap.updateMatrix(); + + } + + uniforms.uvTransform.value.copy(uvScaleMap.matrix); + + } + + if (material.envMap) { + + uniforms.envMap.value = material.envMap; + uniforms.envMapIntensity.value = material.envMapIntensity; + + // don't flip CubeTexture envMaps, flip everything else: + // WebGLRenderTargetCube will be flipped for backwards compatibility + // WebGLRenderTargetCube.texture will be flipped because it's a Texture and NOT a CubeTexture + // this check must be handled differently, or removed entirely, if WebGLRenderTargetCube uses a CubeTexture in the future + uniforms.flipEnvMap.value = material.envMap.isCubeTexture ? - 1 : 1; + + uniforms.reflectivity.value = material.reflectivity; + uniforms.refractionRatio.value = material.refractionRatio; + + uniforms.maxMipLevel.value = renderer.properties.get(material.envMap).__maxMipLevel; + + } + + uniforms.specular.value.copy(material.specular); + uniforms.glossiness.value = material.glossiness; + + uniforms.glossinessMap.value = material.glossinessMap; + + uniforms.emissiveMap.value = material.emissiveMap; + uniforms.bumpMap.value = material.bumpMap; + uniforms.normalMap.value = material.normalMap; + + uniforms.displacementMap.value = material.displacementMap; + uniforms.displacementScale.value = material.displacementScale; + uniforms.displacementBias.value = material.displacementBias; + + if (uniforms.glossinessMap.value !== null && defines.USE_GLOSSINESSMAP === undefined) { + + defines.USE_GLOSSINESSMAP = ''; + // set USE_ROUGHNESSMAP to enable vUv + defines.USE_ROUGHNESSMAP = ''; + + } + + if (uniforms.glossinessMap.value === null && defines.USE_GLOSSINESSMAP !== undefined) { + + delete defines.USE_GLOSSINESSMAP; + delete defines.USE_ROUGHNESSMAP; + + } + + } + + }; + + } + + /*********************************/ + /********** INTERPOLATION ********/ + /*********************************/ + + // Spline Interpolation + // Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#appendix-c-spline-interpolation + function GLTFCubicSplineInterpolant(parameterPositions, sampleValues, sampleSize, resultBuffer) { + + Interpolant.call(this, parameterPositions, sampleValues, sampleSize, resultBuffer); + + } + + GLTFCubicSplineInterpolant.prototype = Object.create(Interpolant.prototype); + GLTFCubicSplineInterpolant.prototype.constructor = GLTFCubicSplineInterpolant; + + GLTFCubicSplineInterpolant.prototype.copySampleValue_ = function (index) { + + // Copies a sample value to the result buffer. See description of glTF + // CUBICSPLINE values layout in interpolate_() function below. + + var result = this.resultBuffer, + values = this.sampleValues, + valueSize = this.valueSize, + offset = index * valueSize * 3 + valueSize; + + for (var i = 0; i !== valueSize; i++) { + + result[i] = values[offset + i]; + + } + + return result; + + }; + + GLTFCubicSplineInterpolant.prototype.beforeStart_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; + + GLTFCubicSplineInterpolant.prototype.afterEnd_ = GLTFCubicSplineInterpolant.prototype.copySampleValue_; + + GLTFCubicSplineInterpolant.prototype.interpolate_ = function (i1, t0, t, t1) { + + var result = this.resultBuffer; + var values = this.sampleValues; + var stride = this.valueSize; + + var stride2 = stride * 2; + var stride3 = stride * 3; + + var td = t1 - t0; + + var p = (t - t0) / td; + var pp = p * p; + var ppp = pp * p; + + var offset1 = i1 * stride3; + var offset0 = offset1 - stride3; + + var s2 = - 2 * ppp + 3 * pp; + var s3 = ppp - pp; + var s0 = 1 - s2; + var s1 = s3 - pp + p; + + // Layout of keyframe output values for CUBICSPLINE animations: + // [ inTangent_1, splineVertex_1, outTangent_1, inTangent_2, splineVertex_2, ... ] + for (var i = 0; i !== stride; i++) { + + var p0 = values[offset0 + i + stride]; // splineVertex_k + var m0 = values[offset0 + i + stride2] * td; // outTangent_k * (t_k+1 - t_k) + var p1 = values[offset1 + i + stride]; // splineVertex_k+1 + var m1 = values[offset1 + i] * td; // inTangent_k+1 * (t_k+1 - t_k) + + result[i] = s0 * p0 + s1 * m0 + s2 * p1 + s3 * m1; + + } + + return result; + + }; + + /*********************************/ + /********** INTERNALS ************/ + /*********************************/ + + /* CONSTANTS */ + + var WEBGL_CONSTANTS = { + FLOAT: 5126, + //FLOAT_MAT2: 35674, + FLOAT_MAT3: 35675, + FLOAT_MAT4: 35676, + FLOAT_VEC2: 35664, + FLOAT_VEC3: 35665, + FLOAT_VEC4: 35666, + LINEAR: 9729, + REPEAT: 10497, + SAMPLER_2D: 35678, + POINTS: 0, + LINES: 1, + LINE_LOOP: 2, + LINE_STRIP: 3, + TRIANGLES: 4, + TRIANGLE_STRIP: 5, + TRIANGLE_FAN: 6, + UNSIGNED_BYTE: 5121, + UNSIGNED_SHORT: 5123 + }; + + var WEBGL_COMPONENT_TYPES = { + 5120: Int8Array, + 5121: Uint8Array, + 5122: Int16Array, + 5123: Uint16Array, + 5125: Uint32Array, + 5126: Float32Array + }; + + var WEBGL_FILTERS = { + 9728: NearestFilter, + 9729: LinearFilter, + 9984: NearestMipmapNearestFilter, + 9985: LinearMipmapNearestFilter, + 9986: NearestMipmapLinearFilter, + 9987: LinearMipmapLinearFilter + }; + + var WEBGL_WRAPPINGS = { + 33071: ClampToEdgeWrapping, + 33648: MirroredRepeatWrapping, + 10497: RepeatWrapping + }; + + var WEBGL_TYPE_SIZES = { + 'SCALAR': 1, + 'VEC2': 2, + 'VEC3': 3, + 'VEC4': 4, + 'MAT2': 4, + 'MAT3': 9, + 'MAT4': 16 + }; + + var ATTRIBUTES = { + POSITION: 'position', + NORMAL: 'normal', + TANGENT: 'tangent', + TEXCOORD_0: 'uv', + TEXCOORD_1: 'uv2', + COLOR_0: 'color', + WEIGHTS_0: 'skinWeight', + JOINTS_0: 'skinIndex', + }; + + var PATH_PROPERTIES = { + scale: 'scale', + translation: 'position', + rotation: 'quaternion', + weights: 'morphTargetInfluences' + }; + + var INTERPOLATION = { + CUBICSPLINE: undefined, // We use a custom interpolant (GLTFCubicSplineInterpolation) for CUBICSPLINE tracks. Each + // keyframe track will be initialized with a default interpolation type, then modified. + LINEAR: InterpolateLinear, + STEP: InterpolateDiscrete + }; + + var ALPHA_MODES = { + OPAQUE: 'OPAQUE', + MASK: 'MASK', + BLEND: 'BLEND' + }; + + var MIME_TYPE_FORMATS = { + 'image/png': RGBAFormat, + 'image/jpeg': RGBFormat + }; + + /* UTILITY FUNCTIONS */ + + function resolveURL(url, path) { + + // Invalid URL + if (typeof url !== 'string' || url === '') return ''; + + // Host Relative URL + if (/^https?:\/\//i.test(path) && /^\//.test(url)) { + + path = path.replace(/(^https?:\/\/[^\/]+).*/i, '$1'); + + } + + // Absolute URL http://,https://,// + if (/^(https?:)?\/\//i.test(url)) return url; + + // Data URI + if (/^data:.*,.*$/i.test(url)) return url; + + // Blob URL + if (/^blob:.*$/i.test(url)) return url; + + // Relative URL + return path + url; + + } + + var defaultMaterial; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#default-material + */ + function createDefaultMaterial() { + + defaultMaterial = defaultMaterial || new MeshStandardMaterial({ + color: 0xFFFFFF, + emissive: 0x000000, + metalness: 1, + roughness: 1, + transparent: false, + depthTest: true, + side: FrontSide + }); + + return defaultMaterial; + + } + + function addUnknownExtensionsToUserData(knownExtensions, object, objectDef) { + + // Add unknown glTF extensions to an object's userData. + + for (var name in objectDef.extensions) { + + if (knownExtensions[name] === undefined) { + + object.userData.gltfExtensions = object.userData.gltfExtensions || {}; + object.userData.gltfExtensions[name] = objectDef.extensions[name]; + + } + + } + + } + + /** + * @param {Object3D|Material|BufferGeometry} object + * @param {GLTF.definition} gltfDef + */ + function assignExtrasToUserData(object, gltfDef) { + + if (gltfDef.extras !== undefined) { + + if (typeof gltfDef.extras === 'object') { + + Object.assign(object.userData, gltfDef.extras); + + } else { + + console.warn('THREE.GLTFLoader: Ignoring primitive type .extras, ' + gltfDef.extras); + + } + + } + + } + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#morph-targets + * + * @param {BufferGeometry} geometry + * @param {Array} targets + * @param {GLTFParser} parser + * @return {Promise} + */ + function addMorphTargets(geometry, targets, parser) { + + var hasMorphPosition = false; + var hasMorphNormal = false; + + for (var i = 0, il = targets.length; i < il; i++) { + + var target = targets[i]; + + if (target.POSITION !== undefined) hasMorphPosition = true; + if (target.NORMAL !== undefined) hasMorphNormal = true; + + if (hasMorphPosition && hasMorphNormal) break; + + } + + if (!hasMorphPosition && !hasMorphNormal) return Promise.resolve(geometry); + + var pendingPositionAccessors = []; + var pendingNormalAccessors = []; + + for (var i = 0, il = targets.length; i < il; i++) { + + var target = targets[i]; + + if (hasMorphPosition) { + + var pendingAccessor = target.POSITION !== undefined + ? parser.getDependency('accessor', target.POSITION) + : geometry.attributes.position; + + pendingPositionAccessors.push(pendingAccessor); + + } + + if (hasMorphNormal) { + + var pendingAccessor = target.NORMAL !== undefined + ? parser.getDependency('accessor', target.NORMAL) + : geometry.attributes.normal; + + pendingNormalAccessors.push(pendingAccessor); + + } + + } + + return Promise.all([ + Promise.all(pendingPositionAccessors), + Promise.all(pendingNormalAccessors) + ]).then(function (accessors) { + + var morphPositions = accessors[0]; + var morphNormals = accessors[1]; + + // Clone morph target accessors before modifying them. + + for (var i = 0, il = morphPositions.length; i < il; i++) { + + if (geometry.attributes.position === morphPositions[i]) continue; + + morphPositions[i] = cloneBufferAttribute(morphPositions[i]); + + } + + for (var i = 0, il = morphNormals.length; i < il; i++) { + + if (geometry.attributes.normal === morphNormals[i]) continue; + + morphNormals[i] = cloneBufferAttribute(morphNormals[i]); + + } + + for (var i = 0, il = targets.length; i < il; i++) { + + var target = targets[i]; + var attributeName = 'morphTarget' + i; + + if (hasMorphPosition) { + + // Three.js morph position is absolute value. The formula is + // basePosition + // + weight0 * ( morphPosition0 - basePosition ) + // + weight1 * ( morphPosition1 - basePosition ) + // ... + // while the glTF one is relative + // basePosition + // + weight0 * glTFmorphPosition0 + // + weight1 * glTFmorphPosition1 + // ... + // then we need to convert from relative to absolute here. + + if (target.POSITION !== undefined) { + + var positionAttribute = morphPositions[i]; + positionAttribute.name = attributeName; + + var position = geometry.attributes.position; + + for (var j = 0, jl = positionAttribute.count; j < jl; j++) { + + positionAttribute.setXYZ( + j, + positionAttribute.getX(j) + position.getX(j), + positionAttribute.getY(j) + position.getY(j), + positionAttribute.getZ(j) + position.getZ(j) + ); + + } + + } + + } + + if (hasMorphNormal) { + + // see target.POSITION's comment + + if (target.NORMAL !== undefined) { + + var normalAttribute = morphNormals[i]; + normalAttribute.name = attributeName; + + var normal = geometry.attributes.normal; + + for (var j = 0, jl = normalAttribute.count; j < jl; j++) { + + normalAttribute.setXYZ( + j, + normalAttribute.getX(j) + normal.getX(j), + normalAttribute.getY(j) + normal.getY(j), + normalAttribute.getZ(j) + normal.getZ(j) + ); + + } + + } + + } + + } + + if (hasMorphPosition) geometry.morphAttributes.position = morphPositions; + if (hasMorphNormal) geometry.morphAttributes.normal = morphNormals; + + return geometry; + + }); + + } + + /** + * @param {Mesh} mesh + * @param {GLTF.Mesh} meshDef + */ + function updateMorphTargets(mesh, meshDef) { + + mesh.updateMorphTargets(); + + if (meshDef.weights !== undefined) { + + for (var i = 0, il = meshDef.weights.length; i < il; i++) { + + mesh.morphTargetInfluences[i] = meshDef.weights[i]; + + } + + } + + // .extras has user-defined data, so check that .extras.targetNames is an array. + if (meshDef.extras && Array.isArray(meshDef.extras.targetNames)) { + + var targetNames = meshDef.extras.targetNames; + + if (mesh.morphTargetInfluences.length === targetNames.length) { + + mesh.morphTargetDictionary = {}; + + for (var i = 0, il = targetNames.length; i < il; i++) { + + mesh.morphTargetDictionary[targetNames[i]] = i; + + } + + } else { + + console.warn('THREE.GLTFLoader: Invalid extras.targetNames length. Ignoring names.'); + + } + + } + + } + + function createPrimitiveKey(primitiveDef) { + + var dracoExtension = primitiveDef.extensions && primitiveDef.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]; + var geometryKey; + + if (dracoExtension) { + + geometryKey = 'draco:' + dracoExtension.bufferView + + ':' + dracoExtension.indices + + ':' + createAttributesKey(dracoExtension.attributes); + + } else { + + geometryKey = primitiveDef.indices + ':' + createAttributesKey(primitiveDef.attributes) + ':' + primitiveDef.mode; + + } + + return geometryKey; + + } + + function createAttributesKey(attributes) { + + var attributesKey = ''; + + var keys = Object.keys(attributes).sort(); + + for (var i = 0, il = keys.length; i < il; i++) { + + attributesKey += keys[i] + ':' + attributes[keys[i]] + ';'; + + } + + return attributesKey; + + } + + function cloneBufferAttribute(attribute) { + + if (attribute.isInterleavedBufferAttribute) { + + var count = attribute.count; + var itemSize = attribute.itemSize; + var array = attribute.array.slice(0, count * itemSize); + + for (var i = 0, j = 0; i < count; ++i) { + + array[j++] = attribute.getX(i); + if (itemSize >= 2) array[j++] = attribute.getY(i); + if (itemSize >= 3) array[j++] = attribute.getZ(i); + if (itemSize >= 4) array[j++] = attribute.getW(i); + + } + + return new BufferAttribute(array, itemSize, attribute.normalized); + + } + + return attribute.clone(); + + } + + /* GLTF PARSER */ + + function GLTFParser(json, extensions, options) { + + this.json = json || {}; + this.extensions = extensions || {}; + this.options = options || {}; + + // loader object cache + this.cache = new GLTFRegistry(); + + // BufferGeometry caching + this.primitiveCache = {}; + + this.textureLoader = new TextureLoader(this.options.manager); + this.textureLoader.setCrossOrigin(this.options.crossOrigin); + + this.fileLoader = new FileLoader(this.options.manager); + this.fileLoader.setResponseType('arraybuffer'); + + if (this.options.crossOrigin === 'use-credentials') { + + this.fileLoader.setWithCredentials(true); + + } + + } + + GLTFParser.prototype.parse = function (onLoad, onError) { + + var parser = this; + var json = this.json; + var extensions = this.extensions; + + // Clear the loader cache + this.cache.removeAll(); + + // Mark the special nodes/meshes in json for efficient parse + this.markDefs(); + + Promise.all([ + + this.getDependencies('scene'), + this.getDependencies('animation'), + this.getDependencies('camera'), + + ]).then(function (dependencies) { + + var result = { + scene: dependencies[0][json.scene || 0], + scenes: dependencies[0], + animations: dependencies[1], + cameras: dependencies[2], + asset: json.asset, + parser: parser, + userData: {} + }; + + addUnknownExtensionsToUserData(extensions, result, json); + + assignExtrasToUserData(result, json); + + onLoad(result); + + }).catch(onError); + + }; + + /** + * Marks the special nodes/meshes in json for efficient parse. + */ + GLTFParser.prototype.markDefs = function () { + + var nodeDefs = this.json.nodes || []; + var skinDefs = this.json.skins || []; + var meshDefs = this.json.meshes || []; + + var meshReferences = {}; + var meshUses = {}; + + // Nothing in the node definition indicates whether it is a Bone or an + // Object3D. Use the skins' joint references to mark bones. + for (var skinIndex = 0, skinLength = skinDefs.length; skinIndex < skinLength; skinIndex++) { + + var joints = skinDefs[skinIndex].joints; + + for (var i = 0, il = joints.length; i < il; i++) { + + nodeDefs[joints[i]].isBone = true; + + } + + } + + // Meshes can (and should) be reused by multiple nodes in a glTF asset. To + // avoid having more than one Mesh with the same name, count + // references and rename instances below. + // + // Example: CesiumMilkTruck sample model reuses "Wheel" meshes. + for (var nodeIndex = 0, nodeLength = nodeDefs.length; nodeIndex < nodeLength; nodeIndex++) { + + var nodeDef = nodeDefs[nodeIndex]; + + if (nodeDef.mesh !== undefined) { + + if (meshReferences[nodeDef.mesh] === undefined) { + + meshReferences[nodeDef.mesh] = meshUses[nodeDef.mesh] = 0; + + } + + meshReferences[nodeDef.mesh]++; + + // Nothing in the mesh definition indicates whether it is + // a SkinnedMesh or Mesh. Use the node's mesh reference + // to mark SkinnedMesh if node has skin. + if (nodeDef.skin !== undefined) { + + meshDefs[nodeDef.mesh].isSkinnedMesh = true; + + } + + } + + } + + this.json.meshReferences = meshReferences; + this.json.meshUses = meshUses; + + }; + + /** + * Requests the specified dependency asynchronously, with caching. + * @param {string} type + * @param {number} index + * @return {Promise} + */ + GLTFParser.prototype.getDependency = function (type, index) { + + var cacheKey = type + ':' + index; + var dependency = this.cache.get(cacheKey); + + if (!dependency) { + + switch (type) { + + case 'scene': + dependency = this.loadScene(index); + break; + + case 'node': + dependency = this.loadNode(index); + break; + + case 'mesh': + dependency = this.loadMesh(index); + break; + + case 'accessor': + dependency = this.loadAccessor(index); + break; + + case 'bufferView': + dependency = this.loadBufferView(index); + break; + + case 'buffer': + dependency = this.loadBuffer(index); + break; + + case 'material': + dependency = this.loadMaterial(index); + break; + + case 'texture': + dependency = this.loadTexture(index); + break; + + case 'skin': + dependency = this.loadSkin(index); + break; + + case 'animation': + dependency = this.loadAnimation(index); + break; + + case 'camera': + dependency = this.loadCamera(index); + break; + + case 'light': + dependency = this.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].loadLight(index); + break; + + default: + throw new Error('Unknown type: ' + type); + + } + + this.cache.add(cacheKey, dependency); + + } + + return dependency; + + }; + + /** + * Requests all dependencies of the specified type asynchronously, with caching. + * @param {string} type + * @return {Promise>} + */ + GLTFParser.prototype.getDependencies = function (type) { + + var dependencies = this.cache.get(type); + + if (!dependencies) { + + var parser = this; + var defs = this.json[type + (type === 'mesh' ? 'es' : 's')] || []; + + dependencies = Promise.all(defs.map(function (def, index) { + + return parser.getDependency(type, index); + + })); + + this.cache.add(type, dependencies); + + } + + return dependencies; + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views + * @param {number} bufferIndex + * @return {Promise} + */ + GLTFParser.prototype.loadBuffer = function (bufferIndex) { + + var bufferDef = this.json.buffers[bufferIndex]; + var loader = this.fileLoader; + + if (bufferDef.type && bufferDef.type !== 'arraybuffer') { + + throw new Error('THREE.GLTFLoader: ' + bufferDef.type + ' buffer type is not supported.'); + + } + + // If present, GLB container is required to be the first buffer. + if (bufferDef.uri === undefined && bufferIndex === 0) { + + return Promise.resolve(this.extensions[EXTENSIONS.KHR_BINARY_GLTF].body); + + } + + var options = this.options; + + return new Promise(function (resolve, reject) { + + loader.load(resolveURL(bufferDef.uri, options.path), resolve, undefined, function () { + + reject(new Error('THREE.GLTFLoader: Failed to load buffer "' + bufferDef.uri + '".')); + + }); + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#buffers-and-buffer-views + * @param {number} bufferViewIndex + * @return {Promise} + */ + GLTFParser.prototype.loadBufferView = function (bufferViewIndex) { + + var bufferViewDef = this.json.bufferViews[bufferViewIndex]; + + return this.getDependency('buffer', bufferViewDef.buffer).then(function (buffer) { + + var byteLength = bufferViewDef.byteLength || 0; + var byteOffset = bufferViewDef.byteOffset || 0; + return buffer.slice(byteOffset, byteOffset + byteLength); + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#accessors + * @param {number} accessorIndex + * @return {Promise} + */ + GLTFParser.prototype.loadAccessor = function (accessorIndex) { + + var parser = this; + var json = this.json; + + var accessorDef = this.json.accessors[accessorIndex]; + + if (accessorDef.bufferView === undefined && accessorDef.sparse === undefined) { + + // Ignore empty accessors, which may be used to declare runtime + // information about attributes coming from another source (e.g. Draco + // compression extension). + return Promise.resolve(null); + + } + + var pendingBufferViews = []; + + if (accessorDef.bufferView !== undefined) { + + pendingBufferViews.push(this.getDependency('bufferView', accessorDef.bufferView)); + + } else { + + pendingBufferViews.push(null); + + } + + if (accessorDef.sparse !== undefined) { + + pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.indices.bufferView)); + pendingBufferViews.push(this.getDependency('bufferView', accessorDef.sparse.values.bufferView)); + + } + + return Promise.all(pendingBufferViews).then(function (bufferViews) { + + var bufferView = bufferViews[0]; + + var itemSize = WEBGL_TYPE_SIZES[accessorDef.type]; + var TypedArray = WEBGL_COMPONENT_TYPES[accessorDef.componentType]; + + // For VEC3: itemSize is 3, elementBytes is 4, itemBytes is 12. + var elementBytes = TypedArray.BYTES_PER_ELEMENT; + var itemBytes = elementBytes * itemSize; + var byteOffset = accessorDef.byteOffset || 0; + var byteStride = accessorDef.bufferView !== undefined ? json.bufferViews[accessorDef.bufferView].byteStride : undefined; + var normalized = accessorDef.normalized === true; + var array, bufferAttribute; + + // The buffer is not interleaved if the stride is the item size in bytes. + if (byteStride && byteStride !== itemBytes) { + + // Each "slice" of the buffer, as defined by 'count' elements of 'byteStride' bytes, gets its own InterleavedBuffer + // This makes sure that IBA.count reflects accessor.count properly + var ibSlice = Math.floor(byteOffset / byteStride); + var ibCacheKey = 'InterleavedBuffer:' + accessorDef.bufferView + ':' + accessorDef.componentType + ':' + ibSlice + ':' + accessorDef.count; + var ib = parser.cache.get(ibCacheKey); + + if (!ib) { + + array = new TypedArray(bufferView, ibSlice * byteStride, accessorDef.count * byteStride / elementBytes); + + // Integer parameters to IB/IBA are in array elements, not bytes. + ib = new InterleavedBuffer(array, byteStride / elementBytes); + + parser.cache.add(ibCacheKey, ib); + + } + + bufferAttribute = new InterleavedBufferAttribute(ib, itemSize, (byteOffset % byteStride) / elementBytes, normalized); + + } else { + + if (bufferView === null) { + + array = new TypedArray(accessorDef.count * itemSize); + + } else { + + array = new TypedArray(bufferView, byteOffset, accessorDef.count * itemSize); + + } + + bufferAttribute = new BufferAttribute(array, itemSize, normalized); + + } + + // https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#sparse-accessors + if (accessorDef.sparse !== undefined) { + + var itemSizeIndices = WEBGL_TYPE_SIZES.SCALAR; + var TypedArrayIndices = WEBGL_COMPONENT_TYPES[accessorDef.sparse.indices.componentType]; + + var byteOffsetIndices = accessorDef.sparse.indices.byteOffset || 0; + var byteOffsetValues = accessorDef.sparse.values.byteOffset || 0; + + var sparseIndices = new TypedArrayIndices(bufferViews[1], byteOffsetIndices, accessorDef.sparse.count * itemSizeIndices); + var sparseValues = new TypedArray(bufferViews[2], byteOffsetValues, accessorDef.sparse.count * itemSize); + + if (bufferView !== null) { + + // Avoid modifying the original ArrayBuffer, if the bufferView wasn't initialized with zeroes. + bufferAttribute.setArray(bufferAttribute.array.slice()); + + } + + for (var i = 0, il = sparseIndices.length; i < il; i++) { + + var index = sparseIndices[i]; + + bufferAttribute.setX(index, sparseValues[i * itemSize]); + if (itemSize >= 2) bufferAttribute.setY(index, sparseValues[i * itemSize + 1]); + if (itemSize >= 3) bufferAttribute.setZ(index, sparseValues[i * itemSize + 2]); + if (itemSize >= 4) bufferAttribute.setW(index, sparseValues[i * itemSize + 3]); + if (itemSize >= 5) throw new Error('THREE.GLTFLoader: Unsupported itemSize in sparse BufferAttribute.'); + + } + + } + + return bufferAttribute; + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#textures + * @param {number} textureIndex + * @return {Promise} + */ + GLTFParser.prototype.loadTexture = function (textureIndex) { + + var parser = this; + var json = this.json; + var options = this.options; + var textureLoader = this.textureLoader; + + var URL = window.URL || window.webkitURL; + + var textureDef = json.textures[textureIndex]; + + var textureExtensions = textureDef.extensions || {}; + + var source; + + if (textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS]) { + + source = json.images[textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS].source]; + + } else { + + source = json.images[textureDef.source]; + + } + + var sourceURI = source.uri; + var isObjectURL = false; + + if (source.bufferView !== undefined) { + + // Load binary image data from bufferView, if provided. + + sourceURI = parser.getDependency('bufferView', source.bufferView).then(function (bufferView) { + if (window.arrayBufferToBase64 != undefined) { + var base64 = window.arrayBufferToBase64(bufferView) + var base64String = `data:${source.mimeType};base64,${base64}` + return base64String + } + isObjectURL = true; + var blob = new Blob([bufferView], { type: source.mimeType }); + sourceURI = URL.createObjectURL(blob); + return sourceURI; + }); + + } + + return Promise.resolve(sourceURI).then(function (sourceURI) { + + // Load Texture resource. + + var loader = Loader.Handlers.get(sourceURI); + + if (!loader) { + + loader = textureExtensions[EXTENSIONS.MSFT_TEXTURE_DDS] + ? parser.extensions[EXTENSIONS.MSFT_TEXTURE_DDS].ddsLoader + : textureLoader; + + } + + return new Promise(function (resolve, reject) { + + loader.load(resolveURL(sourceURI, options.path), resolve, undefined, reject); + + }); + + }).then(function (texture) { + + // Clean up resources and configure Texture. + if (window.arrayBufferToBase64 == undefined) { + if (isObjectURL === true) { + + URL.revokeObjectURL(sourceURI); + + } + } + + texture.flipY = false; + + if (textureDef.name !== undefined) texture.name = textureDef.name; + + // Ignore unknown mime types, like DDS files. + if (source.mimeType in MIME_TYPE_FORMATS) { + + texture.format = MIME_TYPE_FORMATS[source.mimeType]; + + } + + var samplers = json.samplers || {}; + var sampler = samplers[textureDef.sampler] || {}; + + texture.magFilter = WEBGL_FILTERS[sampler.magFilter] || LinearFilter; + texture.minFilter = WEBGL_FILTERS[sampler.minFilter] || LinearMipmapLinearFilter; + texture.wrapS = WEBGL_WRAPPINGS[sampler.wrapS] || RepeatWrapping; + texture.wrapT = WEBGL_WRAPPINGS[sampler.wrapT] || RepeatWrapping; + + return texture; + + }); + + }; + + /** + * Asynchronously assigns a texture to the given material parameters. + * @param {Object} materialParams + * @param {string} mapName + * @param {Object} mapDef + * @return {Promise} + */ + GLTFParser.prototype.assignTexture = function (materialParams, mapName, mapDef) { + + var parser = this; + + return this.getDependency('texture', mapDef.index).then(function (texture) { + + if (!texture.isCompressedTexture) { + + switch (mapName) { + + case 'aoMap': + case 'emissiveMap': + case 'metalnessMap': + case 'normalMap': + case 'roughnessMap': + texture.format = RGBFormat; + break; + + } + + } + + if (parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM]) { + + var transform = mapDef.extensions !== undefined ? mapDef.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM] : undefined; + + if (transform) { + + texture = parser.extensions[EXTENSIONS.KHR_TEXTURE_TRANSFORM].extendTexture(texture, transform); + + } + + } + + materialParams[mapName] = texture; + + }); + + }; + + /** + * Assigns final material to a Mesh, Line, or Points instance. The instance + * already has a material (generated from the glTF material options alone) + * but reuse of the same glTF material may require multiple threejs materials + * to accomodate different primitive types, defines, etc. New materials will + * be created if necessary, and reused from a cache. + * @param {Object3D} mesh Mesh, Line, or Points instance. + */ + GLTFParser.prototype.assignFinalMaterial = function (mesh) { + + var geometry = mesh.geometry; + var material = mesh.material; + var extensions = this.extensions; + + var useVertexTangents = geometry.attributes.tangent !== undefined; + var useVertexColors = geometry.attributes.color !== undefined; + var useFlatShading = geometry.attributes.normal === undefined; + var useSkinning = mesh.isSkinnedMesh === true; + var useMorphTargets = Object.keys(geometry.morphAttributes).length > 0; + var useMorphNormals = useMorphTargets && geometry.morphAttributes.normal !== undefined; + + if (mesh.isPoints) { + + var cacheKey = 'PointsMaterial:' + material.uuid; + + var pointsMaterial = this.cache.get(cacheKey); + + if (!pointsMaterial) { + + pointsMaterial = new PointsMaterial(); + Material.prototype.copy.call(pointsMaterial, material); + pointsMaterial.color.copy(material.color); + pointsMaterial.map = material.map; + pointsMaterial.lights = false; // PointsMaterial doesn't support lights yet + pointsMaterial.sizeAttenuation = false; // glTF spec says points should be 1px + + this.cache.add(cacheKey, pointsMaterial); + + } + + material = pointsMaterial; + + } else if (mesh.isLine) { + + var cacheKey = 'LineBasicMaterial:' + material.uuid; + + var lineMaterial = this.cache.get(cacheKey); + + if (!lineMaterial) { + + lineMaterial = new LineBasicMaterial(); + Material.prototype.copy.call(lineMaterial, material); + lineMaterial.color.copy(material.color); + lineMaterial.lights = false; // LineBasicMaterial doesn't support lights yet + + this.cache.add(cacheKey, lineMaterial); + + } + + material = lineMaterial; + + } + + // Clone the material if it will be modified + if (useVertexTangents || useVertexColors || useFlatShading || useSkinning || useMorphTargets) { + + var cacheKey = 'ClonedMaterial:' + material.uuid + ':'; + + if (material.isGLTFSpecularGlossinessMaterial) cacheKey += 'specular-glossiness:'; + if (useSkinning) cacheKey += 'skinning:'; + if (useVertexTangents) cacheKey += 'vertex-tangents:'; + if (useVertexColors) cacheKey += 'vertex-colors:'; + if (useFlatShading) cacheKey += 'flat-shading:'; + if (useMorphTargets) cacheKey += 'morph-targets:'; + if (useMorphNormals) cacheKey += 'morph-normals:'; + + var cachedMaterial = this.cache.get(cacheKey); + + if (!cachedMaterial) { + + cachedMaterial = material.isGLTFSpecularGlossinessMaterial + ? extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].cloneMaterial(material) + : material.clone(); + + if (useSkinning) cachedMaterial.skinning = true; + if (useVertexTangents) cachedMaterial.vertexTangents = true; + if (useVertexColors) cachedMaterial.vertexColors = VertexColors; + if (useFlatShading) cachedMaterial.flatShading = true; + if (useMorphTargets) cachedMaterial.morphTargets = true; + if (useMorphNormals) cachedMaterial.morphNormals = true; + + this.cache.add(cacheKey, cachedMaterial); + + } + + material = cachedMaterial; + + } + + // workarounds for mesh and geometry + + if (material.aoMap && geometry.attributes.uv2 === undefined && geometry.attributes.uv !== undefined) { + + console.log('THREE.GLTFLoader: Duplicating UVs to support aoMap.'); + geometry.addAttribute('uv2', new BufferAttribute(geometry.attributes.uv.array, 2)); + + } + + if (material.isGLTFSpecularGlossinessMaterial) { + + // for GLTFSpecularGlossinessMaterial(ShaderMaterial) uniforms runtime update + mesh.onBeforeRender = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].refreshUniforms; + + } + + mesh.material = material; + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#materials + * @param {number} materialIndex + * @return {Promise} + */ + GLTFParser.prototype.loadMaterial = function (materialIndex) { + + var parser = this; + var json = this.json; + var extensions = this.extensions; + var materialDef = json.materials[materialIndex]; + + var materialType; + var materialParams = {}; + var materialExtensions = materialDef.extensions || {}; + + var pending = []; + + if (materialExtensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]) { + + var sgExtension = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS]; + materialType = sgExtension.getMaterialType(); + pending.push(sgExtension.extendParams(materialParams, materialDef, parser)); + + } else if (materialExtensions[EXTENSIONS.KHR_MATERIALS_UNLIT]) { + + var kmuExtension = extensions[EXTENSIONS.KHR_MATERIALS_UNLIT]; + materialType = kmuExtension.getMaterialType(); + pending.push(kmuExtension.extendParams(materialParams, materialDef, parser)); + + } else { + + // Specification: + // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#metallic-roughness-material + + materialType = MeshStandardMaterial; + + var metallicRoughness = materialDef.pbrMetallicRoughness || {}; + + materialParams.color = new Color(1.0, 1.0, 1.0); + materialParams.opacity = 1.0; + + if (Array.isArray(metallicRoughness.baseColorFactor)) { + + var array = metallicRoughness.baseColorFactor; + + materialParams.color.fromArray(array); + materialParams.opacity = array[3]; + + } + + if (metallicRoughness.baseColorTexture !== undefined) { + + pending.push(parser.assignTexture(materialParams, 'map', metallicRoughness.baseColorTexture)); + + } + + materialParams.metalness = metallicRoughness.metallicFactor !== undefined ? metallicRoughness.metallicFactor : 1.0; + materialParams.roughness = metallicRoughness.roughnessFactor !== undefined ? metallicRoughness.roughnessFactor : 1.0; + + if (metallicRoughness.metallicRoughnessTexture !== undefined) { + + pending.push(parser.assignTexture(materialParams, 'metalnessMap', metallicRoughness.metallicRoughnessTexture)); + pending.push(parser.assignTexture(materialParams, 'roughnessMap', metallicRoughness.metallicRoughnessTexture)); + + } + + } + + if (materialDef.doubleSided === true) { + + materialParams.side = DoubleSide; + + } + + var alphaMode = materialDef.alphaMode || ALPHA_MODES.OPAQUE; + + if (alphaMode === ALPHA_MODES.BLEND) { + + materialParams.transparent = true; + + } else { + + materialParams.transparent = false; + + if (alphaMode === ALPHA_MODES.MASK) { + + materialParams.alphaTest = materialDef.alphaCutoff !== undefined ? materialDef.alphaCutoff : 0.5; + + } + + } + + if (materialDef.normalTexture !== undefined && materialType !== MeshBasicMaterial) { + + pending.push(parser.assignTexture(materialParams, 'normalMap', materialDef.normalTexture)); + + materialParams.normalScale = new Vector2(1, 1); + + if (materialDef.normalTexture.scale !== undefined) { + + materialParams.normalScale.set(materialDef.normalTexture.scale, materialDef.normalTexture.scale); + + } + + } + + if (materialDef.occlusionTexture !== undefined && materialType !== MeshBasicMaterial) { + + pending.push(parser.assignTexture(materialParams, 'aoMap', materialDef.occlusionTexture)); + + if (materialDef.occlusionTexture.strength !== undefined) { + + materialParams.aoMapIntensity = materialDef.occlusionTexture.strength; + + } + + } + + if (materialDef.emissiveFactor !== undefined && materialType !== MeshBasicMaterial) { + + materialParams.emissive = new Color().fromArray(materialDef.emissiveFactor); + + } + + if (materialDef.emissiveTexture !== undefined && materialType !== MeshBasicMaterial) { + + pending.push(parser.assignTexture(materialParams, 'emissiveMap', materialDef.emissiveTexture)); + + } + + return Promise.all(pending).then(function () { + + var material; + + if (materialType === ShaderMaterial) { + + material = extensions[EXTENSIONS.KHR_MATERIALS_PBR_SPECULAR_GLOSSINESS].createMaterial(materialParams); + + } else { + + material = new materialType(materialParams); + + } + + if (materialDef.name !== undefined) material.name = materialDef.name; + + // baseColorTexture, emissiveTexture, and specularGlossinessTexture use sRGB encoding. + if (material.map) material.map.encoding = sRGBEncoding; + if (material.emissiveMap) material.emissiveMap.encoding = sRGBEncoding; + if (material.specularMap) material.specularMap.encoding = sRGBEncoding; + + assignExtrasToUserData(material, materialDef); + + if (materialDef.extensions) addUnknownExtensionsToUserData(extensions, material, materialDef); + + return material; + + }); + + }; + + /** + * @param {BufferGeometry} geometry + * @param {GLTF.Primitive} primitiveDef + * @param {GLTFParser} parser + * @return {Promise} + */ + function addPrimitiveAttributes(geometry, primitiveDef, parser) { + + var attributes = primitiveDef.attributes; + + var pending = []; + + function assignAttributeAccessor(accessorIndex, attributeName) { + + return parser.getDependency('accessor', accessorIndex) + .then(function (accessor) { + + geometry.addAttribute(attributeName, accessor); + + }); + + } + + for (var gltfAttributeName in attributes) { + + var threeAttributeName = ATTRIBUTES[gltfAttributeName] || gltfAttributeName.toLowerCase(); + + // Skip attributes already provided by e.g. Draco extension. + if (threeAttributeName in geometry.attributes) continue; + + pending.push(assignAttributeAccessor(attributes[gltfAttributeName], threeAttributeName)); + + } + + if (primitiveDef.indices !== undefined && !geometry.index) { + + var accessor = parser.getDependency('accessor', primitiveDef.indices).then(function (accessor) { + + geometry.setIndex(accessor); + + }); + + pending.push(accessor); + + } + + assignExtrasToUserData(geometry, primitiveDef); + + return Promise.all(pending).then(function () { + + return primitiveDef.targets !== undefined + ? addMorphTargets(geometry, primitiveDef.targets, parser) + : geometry; + + }); + + } + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#geometry + * + * Creates BufferGeometries from primitives. + * + * @param {Array} primitives + * @return {Promise>} + */ + GLTFParser.prototype.loadGeometries = function (primitives) { + + var parser = this; + var extensions = this.extensions; + var cache = this.primitiveCache; + + function createDracoPrimitive(primitive) { + + return extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION] + .decodePrimitive(primitive, parser) + .then(function (geometry) { + + return addPrimitiveAttributes(geometry, primitive, parser); + + }); + + } + + var pending = []; + + for (var i = 0, il = primitives.length; i < il; i++) { + + var primitive = primitives[i]; + var cacheKey = createPrimitiveKey(primitive); + + // See if we've already created this geometry + var cached = cache[cacheKey]; + + if (cached) { + + // Use the cached geometry if it exists + pending.push(cached.promise); + + } else { + + var geometryPromise; + + if (primitive.extensions && primitive.extensions[EXTENSIONS.KHR_DRACO_MESH_COMPRESSION]) { + + // Use DRACO geometry if available + geometryPromise = createDracoPrimitive(primitive); + + } else { + + // Otherwise create a new geometry + geometryPromise = addPrimitiveAttributes(new BufferGeometry(), primitive, parser); + + } + + // Cache this geometry + cache[cacheKey] = { primitive: primitive, promise: geometryPromise }; + + pending.push(geometryPromise); + + } + + } + + return Promise.all(pending); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/blob/master/specification/2.0/README.md#meshes + * @param {number} meshIndex + * @return {Promise} + */ + GLTFParser.prototype.loadMesh = function (meshIndex) { + + var parser = this; + var json = this.json; + + var meshDef = json.meshes[meshIndex]; + var primitives = meshDef.primitives; + + var pending = []; + + for (var i = 0, il = primitives.length; i < il; i++) { + + var material = primitives[i].material === undefined + ? createDefaultMaterial() + : this.getDependency('material', primitives[i].material); + + pending.push(material); + + } + + return Promise.all(pending).then(function (originalMaterials) { + + return parser.loadGeometries(primitives).then(function (geometries) { + + var meshes = []; + + for (var i = 0, il = geometries.length; i < il; i++) { + + var geometry = geometries[i]; + var primitive = primitives[i]; + + // 1. create Mesh + + var mesh; + + var material = originalMaterials[i]; + + if (primitive.mode === WEBGL_CONSTANTS.TRIANGLES || + primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP || + primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN || + primitive.mode === undefined) { + + // .isSkinnedMesh isn't in glTF spec. See .markDefs() + mesh = meshDef.isSkinnedMesh === true + ? new SkinnedMesh(geometry, material) + : new Mesh(geometry, material); + + if (mesh.isSkinnedMesh === true && !mesh.geometry.attributes.skinWeight.normalized) { + + // we normalize floating point skin weight array to fix malformed assets (see #15319) + // it's important to skip this for non-float32 data since normalizeSkinWeights assumes non-normalized inputs + mesh.normalizeSkinWeights(); + + } + + if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_STRIP) { + + mesh.drawMode = TriangleStripDrawMode; + + } else if (primitive.mode === WEBGL_CONSTANTS.TRIANGLE_FAN) { + + mesh.drawMode = TriangleFanDrawMode; + + } + + } else if (primitive.mode === WEBGL_CONSTANTS.LINES) { + + mesh = new LineSegments(geometry, material); + + } else if (primitive.mode === WEBGL_CONSTANTS.LINE_STRIP) { + + mesh = new Line(geometry, material); + + } else if (primitive.mode === WEBGL_CONSTANTS.LINE_LOOP) { + + mesh = new LineLoop(geometry, material); + + } else if (primitive.mode === WEBGL_CONSTANTS.POINTS) { + + mesh = new Points(geometry, material); + + } else { + + throw new Error('THREE.GLTFLoader: Primitive mode unsupported: ' + primitive.mode); + + } + + if (Object.keys(mesh.geometry.morphAttributes).length > 0) { + + updateMorphTargets(mesh, meshDef); + + } + + mesh.name = meshDef.name || ('mesh_' + meshIndex); + + if (geometries.length > 1) mesh.name += '_' + i; + + assignExtrasToUserData(mesh, meshDef); + + parser.assignFinalMaterial(mesh); + + meshes.push(mesh); + + } + + if (meshes.length === 1) { + + return meshes[0]; + + } + + var group = new Group(); + + for (var i = 0, il = meshes.length; i < il; i++) { + + group.add(meshes[i]); + + } + + return group; + + }); + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#cameras + * @param {number} cameraIndex + * @return {Promise} + */ + GLTFParser.prototype.loadCamera = function (cameraIndex) { + + var camera; + var cameraDef = this.json.cameras[cameraIndex]; + var params = cameraDef[cameraDef.type]; + + if (!params) { + + console.warn('THREE.GLTFLoader: Missing camera parameters.'); + return; + + } + + if (cameraDef.type === 'perspective') { + + camera = new PerspectiveCamera(_Math.radToDeg(params.yfov), params.aspectRatio || 1, params.znear || 1, params.zfar || 2e6); + + } else if (cameraDef.type === 'orthographic') { + + camera = new OrthographicCamera(params.xmag / - 2, params.xmag / 2, params.ymag / 2, params.ymag / - 2, params.znear, params.zfar); + + } + + if (cameraDef.name !== undefined) camera.name = cameraDef.name; + + assignExtrasToUserData(camera, cameraDef); + + return Promise.resolve(camera); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skins + * @param {number} skinIndex + * @return {Promise} + */ + GLTFParser.prototype.loadSkin = function (skinIndex) { + + var skinDef = this.json.skins[skinIndex]; + + var skinEntry = { joints: skinDef.joints }; + + if (skinDef.inverseBindMatrices === undefined) { + + return Promise.resolve(skinEntry); + + } + + return this.getDependency('accessor', skinDef.inverseBindMatrices).then(function (accessor) { + + skinEntry.inverseBindMatrices = accessor; + + return skinEntry; + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#animations + * @param {number} animationIndex + * @return {Promise} + */ + GLTFParser.prototype.loadAnimation = function (animationIndex) { + + var json = this.json; + + var animationDef = json.animations[animationIndex]; + + var pendingNodes = []; + var pendingInputAccessors = []; + var pendingOutputAccessors = []; + var pendingSamplers = []; + var pendingTargets = []; + + for (var i = 0, il = animationDef.channels.length; i < il; i++) { + + var channel = animationDef.channels[i]; + var sampler = animationDef.samplers[channel.sampler]; + var target = channel.target; + var name = target.node !== undefined ? target.node : target.id; // NOTE: target.id is deprecated. + var input = animationDef.parameters !== undefined ? animationDef.parameters[sampler.input] : sampler.input; + var output = animationDef.parameters !== undefined ? animationDef.parameters[sampler.output] : sampler.output; + + pendingNodes.push(this.getDependency('node', name)); + pendingInputAccessors.push(this.getDependency('accessor', input)); + pendingOutputAccessors.push(this.getDependency('accessor', output)); + pendingSamplers.push(sampler); + pendingTargets.push(target); + + } + + return Promise.all([ + + Promise.all(pendingNodes), + Promise.all(pendingInputAccessors), + Promise.all(pendingOutputAccessors), + Promise.all(pendingSamplers), + Promise.all(pendingTargets) + + ]).then(function (dependencies) { + + var nodes = dependencies[0]; + var inputAccessors = dependencies[1]; + var outputAccessors = dependencies[2]; + var samplers = dependencies[3]; + var targets = dependencies[4]; + + var tracks = []; + + for (var i = 0, il = nodes.length; i < il; i++) { + + var node = nodes[i]; + var inputAccessor = inputAccessors[i]; + var outputAccessor = outputAccessors[i]; + var sampler = samplers[i]; + var target = targets[i]; + + if (node === undefined) continue; + + node.updateMatrix(); + node.matrixAutoUpdate = true; + + var TypedKeyframeTrack; + + switch (PATH_PROPERTIES[target.path]) { + + case PATH_PROPERTIES.weights: + + TypedKeyframeTrack = NumberKeyframeTrack; + break; + + case PATH_PROPERTIES.rotation: + + TypedKeyframeTrack = QuaternionKeyframeTrack; + break; + + case PATH_PROPERTIES.position: + case PATH_PROPERTIES.scale: + default: + + TypedKeyframeTrack = VectorKeyframeTrack; + break; + + } + + var targetName = node.name ? node.name : node.uuid; + + var interpolation = sampler.interpolation !== undefined ? INTERPOLATION[sampler.interpolation] : InterpolateLinear; + + var targetNames = []; + + if (PATH_PROPERTIES[target.path] === PATH_PROPERTIES.weights) { + + // Node may be a Group (glTF mesh with several primitives) or a Mesh. + node.traverse(function (object) { + + if (object.isMesh === true && object.morphTargetInfluences) { + + targetNames.push(object.name ? object.name : object.uuid); + + } + + }); + + } else { + + targetNames.push(targetName); + + } + + var outputArray = outputAccessor.array; + + if (outputAccessor.normalized) { + + var scale; + + if (outputArray.constructor === Int8Array) { + + scale = 1 / 127; + + } else if (outputArray.constructor === Uint8Array) { + + scale = 1 / 255; + + } else if (outputArray.constructor == Int16Array) { + + scale = 1 / 32767; + + } else if (outputArray.constructor === Uint16Array) { + + scale = 1 / 65535; + + } else { + + throw new Error('THREE.GLTFLoader: Unsupported output accessor component type.'); + + } + + var scaled = new Float32Array(outputArray.length); + + for (var j = 0, jl = outputArray.length; j < jl; j++) { + + scaled[j] = outputArray[j] * scale; + + } + + outputArray = scaled; + + } + + for (var j = 0, jl = targetNames.length; j < jl; j++) { + + var track = new TypedKeyframeTrack( + targetNames[j] + '.' + PATH_PROPERTIES[target.path], + inputAccessor.array, + outputArray, + interpolation + ); + + // Override interpolation with custom factory method. + if (sampler.interpolation === 'CUBICSPLINE') { + + track.createInterpolant = function InterpolantFactoryMethodGLTFCubicSpline(result) { + + // A CUBICSPLINE keyframe in glTF has three output values for each input value, + // representing inTangent, splineVertex, and outTangent. As a result, track.getValueSize() + // must be divided by three to get the interpolant's sampleSize argument. + + return new GLTFCubicSplineInterpolant(this.times, this.values, this.getValueSize() / 3, result); + + }; + + // Mark as CUBICSPLINE. `track.getInterpolation()` doesn't support custom interpolants. + track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline = true; + + } + + tracks.push(track); + + } + + } + + var name = animationDef.name !== undefined ? animationDef.name : 'animation_' + animationIndex; + + return new AnimationClip(name, undefined, tracks); + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#nodes-and-hierarchy + * @param {number} nodeIndex + * @return {Promise} + */ + GLTFParser.prototype.loadNode = function (nodeIndex) { + + var json = this.json; + var extensions = this.extensions; + var parser = this; + + var meshReferences = json.meshReferences; + var meshUses = json.meshUses; + + var nodeDef = json.nodes[nodeIndex]; + + return (function () { + + var pending = []; + + if (nodeDef.mesh !== undefined) { + + pending.push(parser.getDependency('mesh', nodeDef.mesh).then(function (mesh) { + + var node; + + if (meshReferences[nodeDef.mesh] > 1) { + + var instanceNum = meshUses[nodeDef.mesh]++; + + node = mesh.clone(); + node.name += '_instance_' + instanceNum; + + // onBeforeRender copy for Specular-Glossiness + node.onBeforeRender = mesh.onBeforeRender; + + for (var i = 0, il = node.children.length; i < il; i++) { + + node.children[i].name += '_instance_' + instanceNum; + node.children[i].onBeforeRender = mesh.children[i].onBeforeRender; + + } + + } else { + + node = mesh; + + } + + // if weights are provided on the node, override weights on the mesh. + if (nodeDef.weights !== undefined) { + + node.traverse(function (o) { + + if (!o.isMesh) return; + + for (var i = 0, il = nodeDef.weights.length; i < il; i++) { + + o.morphTargetInfluences[i] = nodeDef.weights[i]; + + } + + }); + + } + + return node; + + })); + + } + + if (nodeDef.camera !== undefined) { + + pending.push(parser.getDependency('camera', nodeDef.camera)); + + } + + if (nodeDef.extensions + && nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL] + && nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light !== undefined) { + + pending.push(parser.getDependency('light', nodeDef.extensions[EXTENSIONS.KHR_LIGHTS_PUNCTUAL].light)); + + } + + return Promise.all(pending); + + }()).then(function (objects) { + + var node; + + // .isBone isn't in glTF spec. See .markDefs + if (nodeDef.isBone === true) { + + node = new Bone(); + + } else if (objects.length > 1) { + + node = new Group(); + + } else if (objects.length === 1) { + + node = objects[0]; + + } else { + + node = new Object3D(); + + } + + if (node !== objects[0]) { + + for (var i = 0, il = objects.length; i < il; i++) { + + node.add(objects[i]); + + } + + } + + if (nodeDef.name !== undefined) { + + node.userData.name = nodeDef.name; + node.name = PropertyBinding.sanitizeNodeName(nodeDef.name); + + } + + assignExtrasToUserData(node, nodeDef); + + if (nodeDef.extensions) addUnknownExtensionsToUserData(extensions, node, nodeDef); + + if (nodeDef.matrix !== undefined) { + + var matrix = new Matrix4(); + matrix.fromArray(nodeDef.matrix); + node.applyMatrix(matrix); + + } else { + + if (nodeDef.translation !== undefined) { + + node.position.fromArray(nodeDef.translation); + + } + + if (nodeDef.rotation !== undefined) { + + node.quaternion.fromArray(nodeDef.rotation); + + } + + if (nodeDef.scale !== undefined) { + + node.scale.fromArray(nodeDef.scale); + + } + + } + + return node; + + }); + + }; + + /** + * Specification: https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#scenes + * @param {number} sceneIndex + * @return {Promise} + */ + GLTFParser.prototype.loadScene = function () { + + // scene node hierachy builder + + function buildNodeHierachy(nodeId, parentObject, json, parser) { + + var nodeDef = json.nodes[nodeId]; + + return parser.getDependency('node', nodeId).then(function (node) { + + if (nodeDef.skin === undefined) return node; + + // build skeleton here as well + + var skinEntry; + + return parser.getDependency('skin', nodeDef.skin).then(function (skin) { + + skinEntry = skin; + + var pendingJoints = []; + + for (var i = 0, il = skinEntry.joints.length; i < il; i++) { + + pendingJoints.push(parser.getDependency('node', skinEntry.joints[i])); + + } + + return Promise.all(pendingJoints); + + }).then(function (jointNodes) { + + node.traverse(function (mesh) { + + if (!mesh.isMesh) return; + + var bones = []; + var boneInverses = []; + + for (var j = 0, jl = jointNodes.length; j < jl; j++) { + + var jointNode = jointNodes[j]; + + if (jointNode) { + + bones.push(jointNode); + + var mat = new Matrix4(); + + if (skinEntry.inverseBindMatrices !== undefined) { + + mat.fromArray(skinEntry.inverseBindMatrices.array, j * 16); + + } + + boneInverses.push(mat); + + } else { + + console.warn('THREE.GLTFLoader: Joint "%s" could not be found.', skinEntry.joints[j]); + + } + + } + + mesh.bind(new Skeleton(bones, boneInverses), mesh.matrixWorld); + + }); + + return node; + + }); + + }).then(function (node) { + + // build node hierachy + + parentObject.add(node); + + var pending = []; + + if (nodeDef.children) { + + var children = nodeDef.children; + + for (var i = 0, il = children.length; i < il; i++) { + + var child = children[i]; + pending.push(buildNodeHierachy(child, node, json, parser)); + + } + + } + + return Promise.all(pending); + + }); + + } + + return function loadScene(sceneIndex) { + + var json = this.json; + var extensions = this.extensions; + var sceneDef = this.json.scenes[sceneIndex]; + var parser = this; + + var scene = new Scene(); + if (sceneDef.name !== undefined) scene.name = sceneDef.name; + + assignExtrasToUserData(scene, sceneDef); + + if (sceneDef.extensions) addUnknownExtensionsToUserData(extensions, scene, sceneDef); + + var nodeIds = sceneDef.nodes || []; + + var pending = []; + + for (var i = 0, il = nodeIds.length; i < il; i++) { + + pending.push(buildNodeHierachy(nodeIds[i], scene, json, parser)); + + } + + return Promise.all(pending).then(function () { + + return scene; + + }); + + }; + + }(); + + return GLTFLoader; + +} diff --git a/src/wechat_app/jsm/loaders/MTLLoader.js b/src/wechat_app/jsm/loaders/MTLLoader.js new file mode 100644 index 0000000..5d89b2a --- /dev/null +++ b/src/wechat_app/jsm/loaders/MTLLoader.js @@ -0,0 +1,547 @@ +/** + * Loads a Wavefront .mtl file specifying materials + * + * @author angelxuanchang + */ +export default function (THREE) { + let { + Color, + DefaultLoadingManager, + FileLoader, + FrontSide, + Loader, + LoaderUtils, + MeshPhongMaterial, + RepeatWrapping, + TextureLoader, + Vector2 + } = THREE; + + var MTLLoader = function (manager) { + + Loader.call(this, manager); + + }; + + MTLLoader.prototype = Object.assign(Object.create(Loader.prototype), { + + constructor: MTLLoader, + + /** + * Loads and parses a MTL asset from a URL. + * + * @param {String} url - URL to the MTL file. + * @param {Function} [onLoad] - Callback invoked with the loaded object. + * @param {Function} [onProgress] - Callback for download progress. + * @param {Function} [onError] - Callback for download errors. + * + * @see setPath setResourcePath + * + * @note In order for relative texture references to resolve correctly + * you must call setResourcePath() explicitly prior to load. + */ + load: function (url, onLoad, onProgress, onError) { + + var scope = this; + + var path = (this.path === '') ? LoaderUtils.extractUrlBase(url) : this.path; + + var loader = new FileLoader(this.manager); + loader.setPath(this.path); + loader.load(url, function (text) { + + onLoad(scope.parse(text, path)); + + }, onProgress, onError); + + }, + + setMaterialOptions: function (value) { + + this.materialOptions = value; + return this; + + }, + + /** + * Parses a MTL file. + * + * @param {String} text - Content of MTL file + * @return {MTLLoader.MaterialCreator} + * + * @see setPath setResourcePath + * + * @note In order for relative texture references to resolve correctly + * you must call setResourcePath() explicitly prior to parse. + */ + parse: function (text, path) { + + var lines = text.split('\n'); + var info = {}; + var delimiter_pattern = /\s+/; + var materialsInfo = {}; + + for (var i = 0; i < lines.length; i++) { + + var line = lines[i]; + line = line.trim(); + + if (line.length === 0 || line.charAt(0) === '#') { + + // Blank line or comment ignore + continue; + + } + + var pos = line.indexOf(' '); + + var key = (pos >= 0) ? line.substring(0, pos) : line; + key = key.toLowerCase(); + + var value = (pos >= 0) ? line.substring(pos + 1) : ''; + value = value.trim(); + + if (key === 'newmtl') { + + // New material + + info = { name: value }; + materialsInfo[value] = info; + + } else { + + if (key === 'ka' || key === 'kd' || key === 'ks' || key === 'ke') { + + var ss = value.split(delimiter_pattern, 3); + info[key] = [parseFloat(ss[0]), parseFloat(ss[1]), parseFloat(ss[2])]; + + } else { + + info[key] = value; + + } + + } + + } + + var materialCreator = new MTLLoader.MaterialCreator(this.resourcePath || path, this.materialOptions); + materialCreator.setCrossOrigin(this.crossOrigin); + materialCreator.setManager(this.manager); + materialCreator.setMaterials(materialsInfo); + return materialCreator; + + } + + }); + + /** + * Create a new THREE-MTLLoader.MaterialCreator + * @param baseUrl - Url relative to which textures are loaded + * @param options - Set of options on how to construct the materials + * side: Which side to apply the material + * FrontSide (default), THREE.BackSide, THREE.DoubleSide + * wrap: What type of wrapping to apply for textures + * RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping + * normalizeRGB: RGBs need to be normalized to 0-1 from 0-255 + * Default: false, assumed to be already normalized + * ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's + * Default: false + * @constructor + */ + + MTLLoader.MaterialCreator = function (baseUrl, options) { + + this.baseUrl = baseUrl || ''; + this.options = options; + this.materialsInfo = {}; + this.materials = {}; + this.materialsArray = []; + this.nameLookup = {}; + + this.side = (this.options && this.options.side) ? this.options.side : FrontSide; + this.wrap = (this.options && this.options.wrap) ? this.options.wrap : RepeatWrapping; + + }; + + MTLLoader.MaterialCreator.prototype = { + + constructor: MTLLoader.MaterialCreator, + + crossOrigin: 'anonymous', + + setCrossOrigin: function (value) { + + this.crossOrigin = value; + return this; + + }, + + setManager: function (value) { + + this.manager = value; + + }, + + setMaterials: function (materialsInfo) { + + this.materialsInfo = this.convert(materialsInfo); + this.materials = {}; + this.materialsArray = []; + this.nameLookup = {}; + + }, + + convert: function (materialsInfo) { + + if (!this.options) return materialsInfo; + + var converted = {}; + + for (var mn in materialsInfo) { + + // Convert materials info into normalized form based on options + + var mat = materialsInfo[mn]; + + var covmat = {}; + + converted[mn] = covmat; + + for (var prop in mat) { + + var save = true; + var value = mat[prop]; + var lprop = prop.toLowerCase(); + + switch (lprop) { + + case 'kd': + case 'ka': + case 'ks': + + // Diffuse color (color under white light) using RGB values + + if (this.options && this.options.normalizeRGB) { + + value = [value[0] / 255, value[1] / 255, value[2] / 255]; + + } + + if (this.options && this.options.ignoreZeroRGBs) { + + if (value[0] === 0 && value[1] === 0 && value[2] === 0) { + + // ignore + + save = false; + + } + + } + + break; + + default: + + break; + + } + + if (save) { + + covmat[lprop] = value; + + } + + } + + } + + return converted; + + }, + + preload: function () { + + for (var mn in this.materialsInfo) { + + this.create(mn); + + } + + }, + + getIndex: function (materialName) { + + return this.nameLookup[materialName]; + + }, + + getAsArray: function () { + + var index = 0; + + for (var mn in this.materialsInfo) { + + this.materialsArray[index] = this.create(mn); + this.nameLookup[mn] = index; + index++; + + } + + return this.materialsArray; + + }, + + create: function (materialName) { + + if (this.materials[materialName] === undefined) { + + this.createMaterial_(materialName); + + } + + return this.materials[materialName]; + + }, + + createMaterial_: function (materialName) { + + // Create material + + var scope = this; + var mat = this.materialsInfo[materialName]; + var params = { + + name: materialName, + side: this.side + + }; + + function resolveURL(baseUrl, url) { + + if (typeof url !== 'string' || url === '') + return ''; + + // Absolute URL + if (/^https?:\/\//i.test(url)) return url; + + return baseUrl + url; + + } + + function setMapForType(mapType, value) { + + if (params[mapType]) return; // Keep the first encountered texture + + var texParams = scope.getTextureParams(value, params); + var map = scope.loadTexture(resolveURL(scope.baseUrl, texParams.url)); + + map.repeat.copy(texParams.scale); + map.offset.copy(texParams.offset); + + map.wrapS = scope.wrap; + map.wrapT = scope.wrap; + + params[mapType] = map; + + } + + for (var prop in mat) { + + var value = mat[prop]; + var n; + + if (value === '') continue; + + switch (prop.toLowerCase()) { + + // Ns is material specular exponent + + case 'kd': + + // Diffuse color (color under white light) using RGB values + + params.color = new Color().fromArray(value); + + break; + + case 'ks': + + // Specular color (color when light is reflected from shiny surface) using RGB values + params.specular = new Color().fromArray(value); + + break; + + case 'ke': + + // Emissive using RGB values + params.emissive = new Color().fromArray(value); + + break; + + case 'map_kd': + + // Diffuse texture map + + setMapForType("map", value); + + break; + + case 'map_ks': + + // Specular map + + setMapForType("specularMap", value); + + break; + + case 'map_ke': + + // Emissive map + + setMapForType("emissiveMap", value); + + break; + + case 'norm': + + setMapForType("normalMap", value); + + break; + + case 'map_bump': + case 'bump': + + // Bump texture map + + setMapForType("bumpMap", value); + + break; + + case 'map_d': + + // Alpha map + + setMapForType("alphaMap", value); + params.transparent = true; + + break; + + case 'ns': + + // The specular exponent (defines the focus of the specular highlight) + // A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000. + + params.shininess = parseFloat(value); + + break; + + case 'd': + n = parseFloat(value); + + if (n < 1) { + + params.opacity = n; + params.transparent = true; + + } + + break; + + case 'tr': + n = parseFloat(value); + + if (this.options && this.options.invertTrProperty) n = 1 - n; + + if (n > 0) { + + params.opacity = 1 - n; + params.transparent = true; + + } + + break; + + default: + break; + + } + + } + + this.materials[materialName] = new MeshPhongMaterial(params); + return this.materials[materialName]; + + }, + + getTextureParams: function (value, matParams) { + + var texParams = { + + scale: new Vector2(1, 1), + offset: new Vector2(0, 0) + + }; + + var items = value.split(/\s+/); + var pos; + + pos = items.indexOf('-bm'); + + if (pos >= 0) { + + matParams.bumpScale = parseFloat(items[pos + 1]); + items.splice(pos, 2); + + } + + pos = items.indexOf('-s'); + + if (pos >= 0) { + + texParams.scale.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2])); + items.splice(pos, 4); // we expect 3 parameters here! + + } + + pos = items.indexOf('-o'); + + if (pos >= 0) { + + texParams.offset.set(parseFloat(items[pos + 1]), parseFloat(items[pos + 2])); + items.splice(pos, 4); // we expect 3 parameters here! + + } + + texParams.url = items.join(' ').trim(); + return texParams; + + }, + + loadTexture: function (url, mapping, onLoad, onProgress, onError) { + + var texture; + var manager = (this.manager !== undefined) ? this.manager : DefaultLoadingManager; + var loader = manager.getHandler(url); + + if (loader === null) { + + loader = new TextureLoader(manager); + + } + + if (loader.setCrossOrigin) loader.setCrossOrigin(this.crossOrigin); + texture = loader.load(url, onLoad, onProgress, onError); + + if (mapping !== undefined) texture.mapping = mapping; + + return texture; + + } + + }; + + return { MTLLoader }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/loaders/OBJLoader.js b/src/wechat_app/jsm/loaders/OBJLoader.js new file mode 100644 index 0000000..23d320f --- /dev/null +++ b/src/wechat_app/jsm/loaders/OBJLoader.js @@ -0,0 +1,812 @@ +/** + * @author mrdoob / http://mrdoob.com/ + */ + +export default function (THREE) { + let { + BufferGeometry, + FileLoader, + Float32BufferAttribute, + Group, + LineBasicMaterial, + LineSegments, + Loader, + Material, + Mesh, + MeshPhongMaterial, + NoColors, + Points, + PointsMaterial, + VertexColors + } = THREE; + + + + // o object_name | g group_name + var object_pattern = /^[og]\s*(.+)?/; + // mtllib file_reference + var material_library_pattern = /^mtllib /; + // usemtl material_name + var material_use_pattern = /^usemtl /; + + function ParserState() { + + var state = { + objects: [], + object: {}, + + vertices: [], + normals: [], + colors: [], + uvs: [], + + materialLibraries: [], + + startObject: function (name, fromDeclaration) { + + // If the current object (initial from reset) is not from a g/o declaration in the parsed + // file. We need to use it for the first parsed g/o to keep things in sync. + if (this.object && this.object.fromDeclaration === false) { + + this.object.name = name; + this.object.fromDeclaration = (fromDeclaration !== false); + return; + + } + + var previousMaterial = (this.object && typeof this.object.currentMaterial === 'function' ? this.object.currentMaterial() : undefined); + + if (this.object && typeof this.object._finalize === 'function') { + + this.object._finalize(true); + + } + + this.object = { + name: name || '', + fromDeclaration: (fromDeclaration !== false), + + geometry: { + vertices: [], + normals: [], + colors: [], + uvs: [] + }, + materials: [], + smooth: true, + + startMaterial: function (name, libraries) { + + var previous = this._finalize(false); + + // New usemtl declaration overwrites an inherited material, except if faces were declared + // after the material, then it must be preserved for proper MultiMaterial continuation. + if (previous && (previous.inherited || previous.groupCount <= 0)) { + + this.materials.splice(previous.index, 1); + + } + + var material = { + index: this.materials.length, + name: name || '', + mtllib: (Array.isArray(libraries) && libraries.length > 0 ? libraries[libraries.length - 1] : ''), + smooth: (previous !== undefined ? previous.smooth : this.smooth), + groupStart: (previous !== undefined ? previous.groupEnd : 0), + groupEnd: - 1, + groupCount: - 1, + inherited: false, + + clone: function (index) { + + var cloned = { + index: (typeof index === 'number' ? index : this.index), + name: this.name, + mtllib: this.mtllib, + smooth: this.smooth, + groupStart: 0, + groupEnd: - 1, + groupCount: - 1, + inherited: false + }; + cloned.clone = this.clone.bind(cloned); + return cloned; + + } + }; + + this.materials.push(material); + + return material; + + }, + + currentMaterial: function () { + + if (this.materials.length > 0) { + + return this.materials[this.materials.length - 1]; + + } + + return undefined; + + }, + + _finalize: function (end) { + + var lastMultiMaterial = this.currentMaterial(); + if (lastMultiMaterial && lastMultiMaterial.groupEnd === - 1) { + + lastMultiMaterial.groupEnd = this.geometry.vertices.length / 3; + lastMultiMaterial.groupCount = lastMultiMaterial.groupEnd - lastMultiMaterial.groupStart; + lastMultiMaterial.inherited = false; + + } + + // Ignore objects tail materials if no face declarations followed them before a new o/g started. + if (end && this.materials.length > 1) { + + for (var mi = this.materials.length - 1; mi >= 0; mi--) { + + if (this.materials[mi].groupCount <= 0) { + + this.materials.splice(mi, 1); + + } + + } + + } + + // Guarantee at least one empty material, this makes the creation later more straight forward. + if (end && this.materials.length === 0) { + + this.materials.push({ + name: '', + smooth: this.smooth + }); + + } + + return lastMultiMaterial; + + } + }; + + // Inherit previous objects material. + // Spec tells us that a declared material must be set to all objects until a new material is declared. + // If a usemtl declaration is encountered while this new object is being parsed, it will + // overwrite the inherited material. Exception being that there was already face declarations + // to the inherited material, then it will be preserved for proper MultiMaterial continuation. + + if (previousMaterial && previousMaterial.name && typeof previousMaterial.clone === 'function') { + + var declared = previousMaterial.clone(0); + declared.inherited = true; + this.object.materials.push(declared); + + } + + this.objects.push(this.object); + + }, + + finalize: function () { + + if (this.object && typeof this.object._finalize === 'function') { + + this.object._finalize(true); + + } + + }, + + parseVertexIndex: function (value, len) { + + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 3) * 3; + + }, + + parseNormalIndex: function (value, len) { + + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 3) * 3; + + }, + + parseUVIndex: function (value, len) { + + var index = parseInt(value, 10); + return (index >= 0 ? index - 1 : index + len / 2) * 2; + + }, + + addVertex: function (a, b, c) { + + var src = this.vertices; + var dst = this.object.geometry.vertices; + + dst.push(src[a + 0], src[a + 1], src[a + 2]); + dst.push(src[b + 0], src[b + 1], src[b + 2]); + dst.push(src[c + 0], src[c + 1], src[c + 2]); + + }, + + addVertexPoint: function (a) { + + var src = this.vertices; + var dst = this.object.geometry.vertices; + + dst.push(src[a + 0], src[a + 1], src[a + 2]); + + }, + + addVertexLine: function (a) { + + var src = this.vertices; + var dst = this.object.geometry.vertices; + + dst.push(src[a + 0], src[a + 1], src[a + 2]); + + }, + + addNormal: function (a, b, c) { + + var src = this.normals; + var dst = this.object.geometry.normals; + + dst.push(src[a + 0], src[a + 1], src[a + 2]); + dst.push(src[b + 0], src[b + 1], src[b + 2]); + dst.push(src[c + 0], src[c + 1], src[c + 2]); + + }, + + addColor: function (a, b, c) { + + var src = this.colors; + var dst = this.object.geometry.colors; + + dst.push(src[a + 0], src[a + 1], src[a + 2]); + dst.push(src[b + 0], src[b + 1], src[b + 2]); + dst.push(src[c + 0], src[c + 1], src[c + 2]); + + }, + + addUV: function (a, b, c) { + + var src = this.uvs; + var dst = this.object.geometry.uvs; + + dst.push(src[a + 0], src[a + 1]); + dst.push(src[b + 0], src[b + 1]); + dst.push(src[c + 0], src[c + 1]); + + }, + + addUVLine: function (a) { + + var src = this.uvs; + var dst = this.object.geometry.uvs; + + dst.push(src[a + 0], src[a + 1]); + + }, + + addFace: function (a, b, c, ua, ub, uc, na, nb, nc) { + + var vLen = this.vertices.length; + + var ia = this.parseVertexIndex(a, vLen); + var ib = this.parseVertexIndex(b, vLen); + var ic = this.parseVertexIndex(c, vLen); + + this.addVertex(ia, ib, ic); + + if (this.colors.length > 0) { + + this.addColor(ia, ib, ic); + + } + + if (ua !== undefined && ua !== '') { + + var uvLen = this.uvs.length; + ia = this.parseUVIndex(ua, uvLen); + ib = this.parseUVIndex(ub, uvLen); + ic = this.parseUVIndex(uc, uvLen); + this.addUV(ia, ib, ic); + + } + + if (na !== undefined && na !== '') { + + // Normals are many times the same. If so, skip function call and parseInt. + var nLen = this.normals.length; + ia = this.parseNormalIndex(na, nLen); + + ib = na === nb ? ia : this.parseNormalIndex(nb, nLen); + ic = na === nc ? ia : this.parseNormalIndex(nc, nLen); + + this.addNormal(ia, ib, ic); + + } + + }, + + addPointGeometry: function (vertices) { + + this.object.geometry.type = 'Points'; + + var vLen = this.vertices.length; + + for (var vi = 0, l = vertices.length; vi < l; vi++) { + + this.addVertexPoint(this.parseVertexIndex(vertices[vi], vLen)); + + } + + }, + + addLineGeometry: function (vertices, uvs) { + + this.object.geometry.type = 'Line'; + + var vLen = this.vertices.length; + var uvLen = this.uvs.length; + + for (var vi = 0, l = vertices.length; vi < l; vi++) { + + this.addVertexLine(this.parseVertexIndex(vertices[vi], vLen)); + + } + + for (var uvi = 0, l = uvs.length; uvi < l; uvi++) { + + this.addUVLine(this.parseUVIndex(uvs[uvi], uvLen)); + + } + + } + + }; + + state.startObject('', false); + + return state; + + } + + // + + function OBJLoader(manager) { + + Loader.call(this, manager); + + this.materials = null; + + } + + OBJLoader.prototype = Object.assign(Object.create(Loader.prototype), { + + constructor: OBJLoader, + + load: function (url, onLoad, onProgress, onError) { + + var scope = this; + + var loader = new FileLoader(scope.manager); + loader.setPath(this.path); + loader.load(url, function (text) { + + onLoad(scope.parse(text)); + + }, onProgress, onError); + + }, + + setMaterials: function (materials) { + + this.materials = materials; + + return this; + + }, + + parse: function (text) { + + console.time('OBJLoader'); + + var state = new ParserState(); + + if (text.indexOf('\r\n') !== - 1) { + + // This is faster than String.split with regex that splits on both + text = text.replace(/\r\n/g, '\n'); + + } + + if (text.indexOf('\\\n') !== - 1) { + + // join lines separated by a line continuation character (\) + text = text.replace(/\\\n/g, ''); + + } + + var lines = text.split('\n'); + var line = '', lineFirstChar = ''; + var lineLength = 0; + var result = []; + + // Faster to just trim left side of the line. Use if available. + var trimLeft = (typeof ''.trimLeft === 'function'); + + for (var i = 0, l = lines.length; i < l; i++) { + + line = lines[i]; + + line = trimLeft ? line.trimLeft() : line.trim(); + + lineLength = line.length; + + if (lineLength === 0) continue; + + lineFirstChar = line.charAt(0); + + // @todo invoke passed in handler if any + if (lineFirstChar === '#') continue; + + if (lineFirstChar === 'v') { + // \f -> 匹配一个换页 + // \n -> 匹配一个换行符 + // \r -> 匹配一个回车符 + // \t -> 匹配一个制表符 + // \v -> 匹配一个垂直制表符 + // \s+ 表示匹配任意多个上面的字符 + var data = line.split(/\s+/); + // var data = line.split(" "); + + switch (data[0]) { + + case 'v': + state.vertices.push( + parseFloat(data[1]), + parseFloat(data[2]), + parseFloat(data[3]) + ); + if (data.length >= 7) { + + state.colors.push( + parseFloat(data[4]), + parseFloat(data[5]), + parseFloat(data[6]) + + ); + + } + break; + case 'vn': + state.normals.push( + parseFloat(data[1]), + parseFloat(data[2]), + parseFloat(data[3]) + ); + break; + case 'vt': + state.uvs.push( + parseFloat(data[1]), + parseFloat(data[2]) + ); + break; + + } + + } else if (lineFirstChar === 'f') { + + var lineData = line.substr(1).trim(); + var vertexData = lineData.split(/\s+/); + // var vertexData = lineData.split(" "); + var faceVertices = []; + + // Parse the face vertex data into an easy to work with format + + for (var j = 0, jl = vertexData.length; j < jl; j++) { + + var vertex = vertexData[j]; + + if (vertex.length > 0) { + + var vertexParts = vertex.split('/'); + faceVertices.push(vertexParts); + + } + + } + + // Draw an edge between the first vertex and all subsequent vertices to form an n-gon + + var v1 = faceVertices[0]; + + for (var j = 1, jl = faceVertices.length - 1; j < jl; j++) { + + var v2 = faceVertices[j]; + var v3 = faceVertices[j + 1]; + + state.addFace( + v1[0], v2[0], v3[0], + v1[1], v2[1], v3[1], + v1[2], v2[2], v3[2] + ); + + } + + } else if (lineFirstChar === 'l') { + + var lineParts = line.substring(1).trim().split(" "); + var lineVertices = [], lineUVs = []; + + if (line.indexOf("/") === - 1) { + + lineVertices = lineParts; + + } else { + + for (var li = 0, llen = lineParts.length; li < llen; li++) { + + var parts = lineParts[li].split("/"); + + if (parts[0] !== "") lineVertices.push(parts[0]); + if (parts[1] !== "") lineUVs.push(parts[1]); + + } + + } + state.addLineGeometry(lineVertices, lineUVs); + + } else if (lineFirstChar === 'p') { + + var lineData = line.substr(1).trim(); + var pointData = lineData.split(" "); + + state.addPointGeometry(pointData); + + } else if ((result = object_pattern.exec(line)) !== null) { + + // o object_name + // or + // g group_name + + // WORKAROUND: https://bugs.chromium.org/p/v8/issues/detail?id=2869 + // var name = result[ 0 ].substr( 1 ).trim(); + var name = (" " + result[0].substr(1).trim()).substr(1); + + state.startObject(name); + + } else if (material_use_pattern.test(line)) { + + // material + + state.object.startMaterial(line.substring(7).trim(), state.materialLibraries); + + } else if (material_library_pattern.test(line)) { + + // mtl file + + state.materialLibraries.push(line.substring(7).trim()); + + } else if (lineFirstChar === 's') { + + result = line.split(' '); + + // smooth shading + + // @todo Handle files that have varying smooth values for a set of faces inside one geometry, + // but does not define a usemtl for each face set. + // This should be detected and a dummy material created (later MultiMaterial and geometry groups). + // This requires some care to not create extra material on each smooth value for "normal" obj files. + // where explicit usemtl defines geometry groups. + // Example asset: examples/models/obj/cerberus/Cerberus.obj + + /* + * http://paulbourke.net/dataformats/obj/ + * or + * http://www.cs.utah.edu/~boulos/cs3505/obj_spec.pdf + * + * From chapter "Grouping" Syntax explanation "s group_number": + * "group_number is the smoothing group number. To turn off smoothing groups, use a value of 0 or off. + * Polygonal elements use group numbers to put elements in different smoothing groups. For free-form + * surfaces, smoothing groups are either turned on or off; there is no difference between values greater + * than 0." + */ + if (result.length > 1) { + + var value = result[1].trim().toLowerCase(); + state.object.smooth = (value !== '0' && value !== 'off'); + + } else { + + // ZBrush can produce "s" lines #11707 + state.object.smooth = true; + + } + var material = state.object.currentMaterial(); + if (material) material.smooth = state.object.smooth; + + } else { + + // Handle null terminated files without exception + if (line === '\0') continue; + + throw new Error('THREE.OBJLoader: Unexpected line: "' + line + '"'); + + } + + } + + state.finalize(); + + var container = new Group(); + container.materialLibraries = [].concat(state.materialLibraries); + + for (var i = 0, l = state.objects.length; i < l; i++) { + + var object = state.objects[i]; + var geometry = object.geometry; + var materials = object.materials; + var isLine = (geometry.type === 'Line'); + var isPoints = (geometry.type === 'Points'); + var hasVertexColors = false; + + // Skip o/g line declarations that did not follow with any faces + if (geometry.vertices.length === 0) continue; + + var buffergeometry = new BufferGeometry(); + + buffergeometry.setAttribute('position', new Float32BufferAttribute(geometry.vertices, 3)); + + if (geometry.normals.length > 0) { + + buffergeometry.setAttribute('normal', new Float32BufferAttribute(geometry.normals, 3)); + + } else { + + buffergeometry.computeVertexNormals(); + + } + + if (geometry.colors.length > 0) { + + hasVertexColors = true; + buffergeometry.setAttribute('color', new Float32BufferAttribute(geometry.colors, 3)); + + } + + if (geometry.uvs.length > 0) { + + buffergeometry.setAttribute('uv', new Float32BufferAttribute(geometry.uvs, 2)); + + } + + // Create materials + + var createdMaterials = []; + + for (var mi = 0, miLen = materials.length; mi < miLen; mi++) { + + var sourceMaterial = materials[mi]; + var material = undefined; + + if (this.materials !== null) { + + material = this.materials.create(sourceMaterial.name); + + // mtl etc. loaders probably can't create line materials correctly, copy properties to a line material. + if (isLine && material && !(material instanceof LineBasicMaterial)) { + + var materialLine = new LineBasicMaterial(); + Material.prototype.copy.call(materialLine, material); + materialLine.color.copy(material.color); + material = materialLine; + + } else if (isPoints && material && !(material instanceof PointsMaterial)) { + + var materialPoints = new PointsMaterial({ size: 10, sizeAttenuation: false }); + Material.prototype.copy.call(materialPoints, material); + materialPoints.color.copy(material.color); + materialPoints.map = material.map; + material = materialPoints; + + } + + } + + if (!material) { + + if (isLine) { + + material = new LineBasicMaterial(); + + } else if (isPoints) { + + material = new PointsMaterial({ size: 1, sizeAttenuation: false }); + + } else { + + material = new MeshPhongMaterial(); + + } + + material.name = sourceMaterial.name; + + } + + material.flatShading = sourceMaterial.smooth ? false : true; + material.vertexColors = hasVertexColors ? VertexColors : NoColors; + + createdMaterials.push(material); + + } + + // Create mesh + + var mesh; + + if (createdMaterials.length > 1) { + + for (var mi = 0, miLen = materials.length; mi < miLen; mi++) { + + var sourceMaterial = materials[mi]; + buffergeometry.addGroup(sourceMaterial.groupStart, sourceMaterial.groupCount, mi); + + } + + if (isLine) { + + mesh = new LineSegments(buffergeometry, createdMaterials); + + } else if (isPoints) { + + mesh = new Points(buffergeometry, createdMaterials); + + } else { + + mesh = new Mesh(buffergeometry, createdMaterials); + + } + + } else { + + if (isLine) { + + mesh = new LineSegments(buffergeometry, createdMaterials[0]); + + } else if (isPoints) { + + mesh = new Points(buffergeometry, createdMaterials[0]); + + } else { + + mesh = new Mesh(buffergeometry, createdMaterials[0]); + + } + + } + + mesh.name = object.name; + + container.add(mesh); + + } + + console.timeEnd('OBJLoader'); + + return container; + + } + + }); + + return OBJLoader; + +} diff --git a/src/wechat_app/jsm/loaders/RGBELoader.js b/src/wechat_app/jsm/loaders/RGBELoader.js new file mode 100644 index 0000000..12fe289 --- /dev/null +++ b/src/wechat_app/jsm/loaders/RGBELoader.js @@ -0,0 +1,542 @@ +/** + * @author Nikos M. / https://github.com/foo123/ + */ +export default function (THREE) { +let { + DataTextureLoader, + FloatType, + HalfFloatType, + LinearEncoding, + LinearFilter, + NearestFilter, + RGBEEncoding, + RGBEFormat, + RGBFormat, + UnsignedByteType +} = THREE; + +// https://github.com/mrdoob/three.js/issues/5552 +// http://en.wikipedia.org/wiki/RGBE_image_format + +var RGBELoader = function ( manager ) { + + DataTextureLoader.call( this, manager ); + + this.type = UnsignedByteType; + +}; + +RGBELoader.prototype = Object.assign( Object.create( DataTextureLoader.prototype ), { + + constructor: RGBELoader, + + // adapted from http://www.graphics.cornell.edu/~bjw/rgbe.html + + parse: function ( buffer ) { + + var + /* return codes for rgbe routines */ + //RGBE_RETURN_SUCCESS = 0, + RGBE_RETURN_FAILURE = - 1, + + /* default error routine. change this to change error handling */ + rgbe_read_error = 1, + rgbe_write_error = 2, + rgbe_format_error = 3, + rgbe_memory_error = 4, + rgbe_error = function ( rgbe_error_code, msg ) { + + switch ( rgbe_error_code ) { + + case rgbe_read_error: console.error( "RGBELoader Read Error: " + ( msg || '' ) ); + break; + case rgbe_write_error: console.error( "RGBELoader Write Error: " + ( msg || '' ) ); + break; + case rgbe_format_error: console.error( "RGBELoader Bad File Format: " + ( msg || '' ) ); + break; + default: + case rgbe_memory_error: console.error( "RGBELoader: Error: " + ( msg || '' ) ); + + } + return RGBE_RETURN_FAILURE; + + }, + + /* offsets to red, green, and blue components in a data (float) pixel */ + //RGBE_DATA_RED = 0, + //RGBE_DATA_GREEN = 1, + //RGBE_DATA_BLUE = 2, + + /* number of floats per pixel, use 4 since stored in rgba image format */ + //RGBE_DATA_SIZE = 4, + + /* flags indicating which fields in an rgbe_header_info are valid */ + RGBE_VALID_PROGRAMTYPE = 1, + RGBE_VALID_FORMAT = 2, + RGBE_VALID_DIMENSIONS = 4, + + NEWLINE = "\n", + + fgets = function ( buffer, lineLimit, consume ) { + + lineLimit = ! lineLimit ? 1024 : lineLimit; + var p = buffer.pos, + i = - 1, len = 0, s = '', chunkSize = 128, + chunk = String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ) + ; + while ( ( 0 > ( i = chunk.indexOf( NEWLINE ) ) ) && ( len < lineLimit ) && ( p < buffer.byteLength ) ) { + + s += chunk; len += chunk.length; + p += chunkSize; + chunk += String.fromCharCode.apply( null, new Uint16Array( buffer.subarray( p, p + chunkSize ) ) ); + + } + + if ( - 1 < i ) { + + /*for (i=l-1; i>=0; i--) { + byteCode = m.charCodeAt(i); + if (byteCode > 0x7f && byteCode <= 0x7ff) byteLen++; + else if (byteCode > 0x7ff && byteCode <= 0xffff) byteLen += 2; + if (byteCode >= 0xDC00 && byteCode <= 0xDFFF) i--; //trail surrogate + }*/ + if ( false !== consume ) buffer.pos += len + i + 1; + return s + chunk.slice( 0, i ); + + } + return false; + + }, + + /* minimal header reading. modify if you want to parse more information */ + RGBE_ReadHeader = function ( buffer ) { + + var line, match, + + // regexes to parse header info fields + magic_token_re = /^#\?(\S+)$/, + gamma_re = /^\s*GAMMA\s*=\s*(\d+(\.\d+)?)\s*$/, + exposure_re = /^\s*EXPOSURE\s*=\s*(\d+(\.\d+)?)\s*$/, + format_re = /^\s*FORMAT=(\S+)\s*$/, + dimensions_re = /^\s*\-Y\s+(\d+)\s+\+X\s+(\d+)\s*$/, + + // RGBE format header struct + header = { + + valid: 0, /* indicate which fields are valid */ + + string: '', /* the actual header string */ + + comments: '', /* comments found in header */ + + programtype: 'RGBE', /* listed at beginning of file to identify it after "#?". defaults to "RGBE" */ + + format: '', /* RGBE format, default 32-bit_rle_rgbe */ + + gamma: 1.0, /* image has already been gamma corrected with given gamma. defaults to 1.0 (no correction) */ + + exposure: 1.0, /* a value of 1.0 in an image corresponds to watts/steradian/m^2. defaults to 1.0 */ + + width: 0, height: 0 /* image dimensions, width/height */ + + }; + + if ( buffer.pos >= buffer.byteLength || ! ( line = fgets( buffer ) ) ) { + + return rgbe_error( rgbe_read_error, "no header found" ); + + } + /* if you want to require the magic token then uncomment the next line */ + if ( ! ( match = line.match( magic_token_re ) ) ) { + + return rgbe_error( rgbe_format_error, "bad initial token" ); + + } + header.valid |= RGBE_VALID_PROGRAMTYPE; + header.programtype = match[ 1 ]; + header.string += line + "\n"; + + while ( true ) { + + line = fgets( buffer ); + if ( false === line ) break; + header.string += line + "\n"; + + if ( '#' === line.charAt( 0 ) ) { + + header.comments += line + "\n"; + continue; // comment line + + } + + if ( match = line.match( gamma_re ) ) { + + header.gamma = parseFloat( match[ 1 ], 10 ); + + } + if ( match = line.match( exposure_re ) ) { + + header.exposure = parseFloat( match[ 1 ], 10 ); + + } + if ( match = line.match( format_re ) ) { + + header.valid |= RGBE_VALID_FORMAT; + header.format = match[ 1 ];//'32-bit_rle_rgbe'; + + } + if ( match = line.match( dimensions_re ) ) { + + header.valid |= RGBE_VALID_DIMENSIONS; + header.height = parseInt( match[ 1 ], 10 ); + header.width = parseInt( match[ 2 ], 10 ); + + } + + if ( ( header.valid & RGBE_VALID_FORMAT ) && ( header.valid & RGBE_VALID_DIMENSIONS ) ) break; + + } + + if ( ! ( header.valid & RGBE_VALID_FORMAT ) ) { + + return rgbe_error( rgbe_format_error, "missing format specifier" ); + + } + if ( ! ( header.valid & RGBE_VALID_DIMENSIONS ) ) { + + return rgbe_error( rgbe_format_error, "missing image size specifier" ); + + } + + return header; + + }, + + RGBE_ReadPixels_RLE = function ( buffer, w, h ) { + + var data_rgba, offset, pos, count, byteValue, + scanline_buffer, ptr, ptr_end, i, l, off, isEncodedRun, + scanline_width = w, num_scanlines = h, rgbeStart + ; + + if ( + // run length encoding is not allowed so read flat + ( ( scanline_width < 8 ) || ( scanline_width > 0x7fff ) ) || + // this file is not run length encoded + ( ( 2 !== buffer[ 0 ] ) || ( 2 !== buffer[ 1 ] ) || ( buffer[ 2 ] & 0x80 ) ) + ) { + + // return the flat buffer + return new Uint8Array( buffer ); + + } + + if ( scanline_width !== ( ( buffer[ 2 ] << 8 ) | buffer[ 3 ] ) ) { + + return rgbe_error( rgbe_format_error, "wrong scanline width" ); + + } + + data_rgba = new Uint8Array( 4 * w * h ); + + if ( ! data_rgba || ! data_rgba.length ) { + + return rgbe_error( rgbe_memory_error, "unable to allocate buffer space" ); + + } + + offset = 0; pos = 0; ptr_end = 4 * scanline_width; + rgbeStart = new Uint8Array( 4 ); + scanline_buffer = new Uint8Array( ptr_end ); + + // read in each successive scanline + while ( ( num_scanlines > 0 ) && ( pos < buffer.byteLength ) ) { + + if ( pos + 4 > buffer.byteLength ) { + + return rgbe_error( rgbe_read_error ); + + } + + rgbeStart[ 0 ] = buffer[ pos ++ ]; + rgbeStart[ 1 ] = buffer[ pos ++ ]; + rgbeStart[ 2 ] = buffer[ pos ++ ]; + rgbeStart[ 3 ] = buffer[ pos ++ ]; + + if ( ( 2 != rgbeStart[ 0 ] ) || ( 2 != rgbeStart[ 1 ] ) || ( ( ( rgbeStart[ 2 ] << 8 ) | rgbeStart[ 3 ] ) != scanline_width ) ) { + + return rgbe_error( rgbe_format_error, "bad rgbe scanline format" ); + + } + + // read each of the four channels for the scanline into the buffer + // first red, then green, then blue, then exponent + ptr = 0; + while ( ( ptr < ptr_end ) && ( pos < buffer.byteLength ) ) { + + count = buffer[ pos ++ ]; + isEncodedRun = count > 128; + if ( isEncodedRun ) count -= 128; + + if ( ( 0 === count ) || ( ptr + count > ptr_end ) ) { + + return rgbe_error( rgbe_format_error, "bad scanline data" ); + + } + + if ( isEncodedRun ) { + + // a (encoded) run of the same value + byteValue = buffer[ pos ++ ]; + for ( i = 0; i < count; i ++ ) { + + scanline_buffer[ ptr ++ ] = byteValue; + + } + //ptr += count; + + } else { + + // a literal-run + scanline_buffer.set( buffer.subarray( pos, pos + count ), ptr ); + ptr += count; pos += count; + + } + + } + + + // now convert data from buffer into rgba + // first red, then green, then blue, then exponent (alpha) + l = scanline_width; //scanline_buffer.byteLength; + for ( i = 0; i < l; i ++ ) { + + off = 0; + data_rgba[ offset ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 1 ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 2 ] = scanline_buffer[ i + off ]; + off += scanline_width; //1; + data_rgba[ offset + 3 ] = scanline_buffer[ i + off ]; + offset += 4; + + } + + num_scanlines --; + + } + + return data_rgba; + + }; + + var RGBEByteToRGBFloat = function ( sourceArray, sourceOffset, destArray, destOffset ) { + + var e = sourceArray[ sourceOffset + 3 ]; + var scale = Math.pow( 2.0, e - 128.0 ) / 255.0; + + destArray[ destOffset + 0 ] = sourceArray[ sourceOffset + 0 ] * scale; + destArray[ destOffset + 1 ] = sourceArray[ sourceOffset + 1 ] * scale; + destArray[ destOffset + 2 ] = sourceArray[ sourceOffset + 2 ] * scale; + + }; + + var RGBEByteToRGBHalf = ( function () { + + // Source: http://gamedev.stackexchange.com/questions/17326/conversion-of-a-number-from-single-precision-floating-point-representation-to-a/17410#17410 + + var floatView = new Float32Array( 1 ); + var int32View = new Int32Array( floatView.buffer ); + + /* This method is faster than the OpenEXR implementation (very often + * used, eg. in Ogre), with the additional benefit of rounding, inspired + * by James Tursa?s half-precision code. */ + function toHalf( val ) { + + floatView[ 0 ] = val; + var x = int32View[ 0 ]; + + var bits = ( x >> 16 ) & 0x8000; /* Get the sign */ + var m = ( x >> 12 ) & 0x07ff; /* Keep one extra bit for rounding */ + var e = ( x >> 23 ) & 0xff; /* Using int is faster here */ + + /* If zero, or denormal, or exponent underflows too much for a denormal + * half, return signed zero. */ + if ( e < 103 ) return bits; + + /* If NaN, return NaN. If Inf or exponent overflow, return Inf. */ + if ( e > 142 ) { + + bits |= 0x7c00; + /* If exponent was 0xff and one mantissa bit was set, it means NaN, + * not Inf, so make sure we set one mantissa bit too. */ + bits |= ( ( e == 255 ) ? 0 : 1 ) && ( x & 0x007fffff ); + return bits; + + } + + /* If exponent underflows but not too much, return a denormal */ + if ( e < 113 ) { + + m |= 0x0800; + /* Extra rounding may overflow and set mantissa to 0 and exponent + * to 1, which is OK. */ + bits |= ( m >> ( 114 - e ) ) + ( ( m >> ( 113 - e ) ) & 1 ); + return bits; + + } + + bits |= ( ( e - 112 ) << 10 ) | ( m >> 1 ); + /* Extra rounding. An overflow will set mantissa to 0 and increment + * the exponent, which is OK. */ + bits += m & 1; + return bits; + + } + + return function ( sourceArray, sourceOffset, destArray, destOffset ) { + + var e = sourceArray[ sourceOffset + 3 ]; + var scale = Math.pow( 2.0, e - 128.0 ) / 255.0; + + destArray[ destOffset + 0 ] = toHalf( sourceArray[ sourceOffset + 0 ] * scale ); + destArray[ destOffset + 1 ] = toHalf( sourceArray[ sourceOffset + 1 ] * scale ); + destArray[ destOffset + 2 ] = toHalf( sourceArray[ sourceOffset + 2 ] * scale ); + + }; + + } )(); + + var byteArray = new Uint8Array( buffer ); + byteArray.pos = 0; + var rgbe_header_info = RGBE_ReadHeader( byteArray ); + + if ( RGBE_RETURN_FAILURE !== rgbe_header_info ) { + + var w = rgbe_header_info.width, + h = rgbe_header_info.height, + image_rgba_data = RGBE_ReadPixels_RLE( byteArray.subarray( byteArray.pos ), w, h ); + + if ( RGBE_RETURN_FAILURE !== image_rgba_data ) { + + switch ( this.type ) { + + case UnsignedByteType: + + var data = image_rgba_data; + var format = RGBEFormat; // handled as THREE.RGBAFormat in shaders + var type = UnsignedByteType; + break; + + case FloatType: + + var numElements = ( image_rgba_data.length / 4 ) * 3; + var floatArray = new Float32Array( numElements ); + + for ( var j = 0; j < numElements; j ++ ) { + + RGBEByteToRGBFloat( image_rgba_data, j * 4, floatArray, j * 3 ); + + } + + var data = floatArray; + var format = RGBFormat; + var type = FloatType; + break; + + case HalfFloatType: + + var numElements = ( image_rgba_data.length / 4 ) * 3; + var halfArray = new Uint16Array( numElements ); + + for ( var j = 0; j < numElements; j ++ ) { + + RGBEByteToRGBHalf( image_rgba_data, j * 4, halfArray, j * 3 ); + + } + + var data = halfArray; + var format = RGBFormat; + var type = HalfFloatType; + break; + + default: + + console.error( 'THREE.RGBELoader: unsupported type: ', this.type ); + break; + + } + + return { + width: w, height: h, + data: data, + header: rgbe_header_info.string, + gamma: rgbe_header_info.gamma, + exposure: rgbe_header_info.exposure, + format: format, + type: type + }; + + } + + } + + return null; + + }, + + setDataType: function ( value ) { + + this.type = value; + return this; + + }, + + load: function ( url, onLoad, onProgress, onError ) { + + function onLoadCallback( texture, texData ) { + + switch ( texture.type ) { + + case UnsignedByteType: + + texture.encoding = RGBEEncoding; + texture.minFilter = NearestFilter; + texture.magFilter = NearestFilter; + texture.generateMipmaps = false; + texture.flipY = true; + break; + + case FloatType: + + texture.encoding = LinearEncoding; + texture.minFilter = LinearFilter; + texture.magFilter = LinearFilter; + texture.generateMipmaps = false; + texture.flipY = true; + break; + + case HalfFloatType: + + texture.encoding = LinearEncoding; + texture.minFilter = LinearFilter; + texture.magFilter = LinearFilter; + texture.generateMipmaps = false; + texture.flipY = true; + break; + + } + + if ( onLoad ) onLoad( texture, texData ); + + } + + return DataTextureLoader.prototype.load.call( this, url, onLoadCallback, onProgress, onError ); + + } + +} ); + +return { RGBELoader }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/loaders/STLLoader.js b/src/wechat_app/jsm/loaders/STLLoader.js new file mode 100644 index 0000000..1dec36c --- /dev/null +++ b/src/wechat_app/jsm/loaders/STLLoader.js @@ -0,0 +1,409 @@ +/** + * @author aleeper / http://adamleeper.com/ + * @author mrdoob / http://mrdoob.com/ + * @author gero3 / https://github.com/gero3 + * @author Mugen87 / https://github.com/Mugen87 + * @author neverhood311 / https://github.com/neverhood311 + * + * Description: A THREE loader for STL ASCII files, as created by Solidworks and other CAD programs. + * + * Supports both binary and ASCII encoded files, with automatic detection of type. + * + * The loader returns a non-indexed buffer geometry. + * + * Limitations: + * Binary decoding supports "Magics" color format (http://en.wikipedia.org/wiki/STL_(file_format)#Color_in_binary_STL). + * There is perhaps some question as to how valid it is to always assume little-endian-ness. + * ASCII decoding assumes file is UTF-8. + * + * Usage: + * var loader = new STLLoader(); + * loader.load( './models/stl/slotted_disk.stl', function ( geometry ) { + * scene.add( new THREE.Mesh( geometry ) ); + * }); + * + * For binary STLs geometry might contain colors for vertices. To use it: + * // use the same code to load STL as above + * if (geometry.hasColors) { + * material = new THREE.MeshPhongMaterial({ opacity: geometry.alpha, vertexColors: THREE.VertexColors }); + * } else { .... } + * var mesh = new THREE.Mesh( geometry, material ); + * + * For ASCII STLs containing multiple solids, each solid is assigned to a different group. + * Groups can be used to assign a different color by defining an array of materials with the same length of + * geometry.groups and passing it to the Mesh constructor: + * + * var mesh = new THREE.Mesh( geometry, material ); + * + * For example: + * + * var materials = []; + * var nGeometryGroups = geometry.groups.length; + * + * var colorMap = ...; // Some logic to index colors. + * + * for (var i = 0; i < nGeometryGroups; i++) { + * + * var material = new THREE.MeshPhongMaterial({ + * color: colorMap[i], + * wireframe: false + * }); + * + * } + * + * materials.push(material); + * var mesh = new THREE.Mesh(geometry, materials); + */ + +export default function (THREE) { + let { + BufferAttribute, + BufferGeometry, + FileLoader, + Float32BufferAttribute, + Loader, + LoaderUtils, + Vector3 + } = THREE; + + + var STLLoader = function ( manager ) { + + Loader.call( this, manager ); + + }; + + STLLoader.prototype = Object.assign( Object.create( Loader.prototype ), { + + constructor: STLLoader, + + load: function ( url, onLoad, onProgress, onError ) { + + var scope = this; + + var loader = new FileLoader( scope.manager ); + loader.setPath( scope.path ); + loader.setResponseType( 'arraybuffer' ); + loader.load( url, function ( text ) { + + try { + + onLoad( scope.parse( text ) ); + + } catch ( exception ) { + + if ( onError ) { + + onError( exception ); + + } + + } + + }, onProgress, onError ); + + }, + + parse: function ( data ) { + + function isBinary( data ) { + + var expect, face_size, n_faces, reader; + reader = new DataView( data ); + face_size = ( 32 / 8 * 3 ) + ( ( 32 / 8 * 3 ) * 3 ) + ( 16 / 8 ); + n_faces = reader.getUint32( 80, true ); + expect = 80 + ( 32 / 8 ) + ( n_faces * face_size ); + + if ( expect === reader.byteLength ) { + + return true; + + } + + // An ASCII STL data must begin with 'solid ' as the first six bytes. + // However, ASCII STLs lacking the SPACE after the 'd' are known to be + // plentiful. So, check the first 5 bytes for 'solid'. + + // Several encodings, such as UTF-8, precede the text with up to 5 bytes: + // https://en.wikipedia.org/wiki/Byte_order_mark#Byte_order_marks_by_encoding + // Search for "solid" to start anywhere after those prefixes. + + // US-ASCII ordinal values for 's', 'o', 'l', 'i', 'd' + + var solid = [ 115, 111, 108, 105, 100 ]; + + for ( var off = 0; off < 5; off ++ ) { + + // If "solid" text is matched to the current offset, declare it to be an ASCII STL. + + if ( matchDataViewAt( solid, reader, off ) ) return false; + + } + + // Couldn't find "solid" text at the beginning; it is binary STL. + + return true; + + } + + function matchDataViewAt( query, reader, offset ) { + + // Check if each byte in query matches the corresponding byte from the current offset + + for ( var i = 0, il = query.length; i < il; i ++ ) { + + if ( query[ i ] !== reader.getUint8( offset + i, false ) ) return false; + + } + + return true; + + } + + function parseBinary( data ) { + + var reader = new DataView( data ); + var faces = reader.getUint32( 80, true ); + + var r, g, b, hasColors = false, colors; + var defaultR, defaultG, defaultB, alpha; + + // process STL header + // check for default color in header ("COLOR=rgba" sequence). + + for ( var index = 0; index < 80 - 10; index ++ ) { + + if ( ( reader.getUint32( index, false ) == 0x434F4C4F /*COLO*/ ) && + ( reader.getUint8( index + 4 ) == 0x52 /*'R'*/ ) && + ( reader.getUint8( index + 5 ) == 0x3D /*'='*/ ) ) { + + hasColors = true; + colors = new Float32Array( faces * 3 * 3 ); + + defaultR = reader.getUint8( index + 6 ) / 255; + defaultG = reader.getUint8( index + 7 ) / 255; + defaultB = reader.getUint8( index + 8 ) / 255; + alpha = reader.getUint8( index + 9 ) / 255; + + } + + } + + var dataOffset = 84; + var faceLength = 12 * 4 + 2; + + var geometry = new BufferGeometry(); + + var vertices = new Float32Array( faces * 3 * 3 ); + var normals = new Float32Array( faces * 3 * 3 ); + + for ( var face = 0; face < faces; face ++ ) { + + var start = dataOffset + face * faceLength; + var normalX = reader.getFloat32( start, true ); + var normalY = reader.getFloat32( start + 4, true ); + var normalZ = reader.getFloat32( start + 8, true ); + + if ( hasColors ) { + + var packedColor = reader.getUint16( start + 48, true ); + + if ( ( packedColor & 0x8000 ) === 0 ) { + + // facet has its own unique color + + r = ( packedColor & 0x1F ) / 31; + g = ( ( packedColor >> 5 ) & 0x1F ) / 31; + b = ( ( packedColor >> 10 ) & 0x1F ) / 31; + + } else { + + r = defaultR; + g = defaultG; + b = defaultB; + + } + + } + + for ( var i = 1; i <= 3; i ++ ) { + + var vertexstart = start + i * 12; + var componentIdx = ( face * 3 * 3 ) + ( ( i - 1 ) * 3 ); + + vertices[ componentIdx ] = reader.getFloat32( vertexstart, true ); + vertices[ componentIdx + 1 ] = reader.getFloat32( vertexstart + 4, true ); + vertices[ componentIdx + 2 ] = reader.getFloat32( vertexstart + 8, true ); + + normals[ componentIdx ] = normalX; + normals[ componentIdx + 1 ] = normalY; + normals[ componentIdx + 2 ] = normalZ; + + if ( hasColors ) { + + colors[ componentIdx ] = r; + colors[ componentIdx + 1 ] = g; + colors[ componentIdx + 2 ] = b; + + } + + } + + } + + geometry.addAttribute( 'position', new BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'normal', new BufferAttribute( normals, 3 ) ); + + if ( hasColors ) { + + geometry.addAttribute( 'color', new BufferAttribute( colors, 3 ) ); + geometry.hasColors = true; + geometry.alpha = alpha; + + } + + return geometry; + + } + + function parseASCII( data ) { + + var geometry = new BufferGeometry(); + var patternSolid = /solid([\s\S]*?)endsolid/g; + var patternFace = /facet([\s\S]*?)endfacet/g; + var faceCounter = 0; + + var patternFloat = /[\s]+([+-]?(?:\d*)(?:\.\d*)?(?:[eE][+-]?\d+)?)/.source; + var patternVertex = new RegExp( 'vertex' + patternFloat + patternFloat + patternFloat, 'g' ); + var patternNormal = new RegExp( 'normal' + patternFloat + patternFloat + patternFloat, 'g' ); + + var vertices = []; + var normals = []; + + var normal = new Vector3(); + + var result; + + var groupVertexes = []; + var groupCount = 0; + var startVertex = 0; + var endVertex = 0; + + while ( ( result = patternSolid.exec( data ) ) !== null ) { + + startVertex = endVertex; + + var solid = result[ 0 ]; + + while ( ( result = patternFace.exec( solid ) ) !== null ) { + + var vertexCountPerFace = 0; + var normalCountPerFace = 0; + + var text = result[ 0 ]; + + while ( ( result = patternNormal.exec( text ) ) !== null ) { + + normal.x = parseFloat( result[ 1 ] ); + normal.y = parseFloat( result[ 2 ] ); + normal.z = parseFloat( result[ 3 ] ); + normalCountPerFace ++; + + } + + while ( ( result = patternVertex.exec( text ) ) !== null ) { + + vertices.push( parseFloat( result[ 1 ] ), parseFloat( result[ 2 ] ), parseFloat( result[ 3 ] ) ); + normals.push( normal.x, normal.y, normal.z ); + vertexCountPerFace ++; + endVertex ++; + + } + + // every face have to own ONE valid normal + + if ( normalCountPerFace !== 1 ) { + + console.error( 'THREE.STLLoader: Something isn\'t right with the normal of face number ' + faceCounter ); + + } + + // each face have to own THREE valid vertices + + if ( vertexCountPerFace !== 3 ) { + + console.error( 'THREE.STLLoader: Something isn\'t right with the vertices of face number ' + faceCounter ); + + } + + faceCounter ++; + + } + + groupVertexes.push( { startVertex: startVertex, endVertex: endVertex } ); + groupCount ++; + + } + + geometry.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) ); + geometry.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) ); + + if ( groupCount > 0 ) { + + for ( var i = 0; i < groupVertexes.length; i ++ ) { + + geometry.addGroup( groupVertexes[ i ].startVertex, groupVertexes[ i ].endVertex, i ); + + } + + } + + return geometry; + + } + + function ensureString( buffer ) { + + if ( typeof buffer !== 'string' ) { + + return LoaderUtils.decodeText( new Uint8Array( buffer ) ); + + } + + return buffer; + + } + + function ensureBinary( buffer ) { + + if ( typeof buffer === 'string' ) { + + var array_buffer = new Uint8Array( buffer.length ); + for ( var i = 0; i < buffer.length; i ++ ) { + + array_buffer[ i ] = buffer.charCodeAt( i ) & 0xff; // implicitly assumes little-endian + + } + + return array_buffer.buffer || array_buffer; + + } else { + + return buffer; + + } + + } + + // start + + var binData = ensureBinary( data ); + + return isBinary( binData ) ? parseBinary( binData ) : parseASCII( ensureString( data ) ); + + } + + } ); + + return { STLLoader }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/pmrem/PMREMCubeUVPacker.js b/src/wechat_app/jsm/pmrem/PMREMCubeUVPacker.js new file mode 100644 index 0000000..36100bd --- /dev/null +++ b/src/wechat_app/jsm/pmrem/PMREMCubeUVPacker.js @@ -0,0 +1,254 @@ +/** + * @author Prashant Sharma / spidersharma03 + * @author Ben Houston / bhouston, https://clara.io + * + * This class takes the cube lods(corresponding to different roughness values), and creates a single cubeUV + * Texture. The format for a given roughness set of faces is simply:: + * +X+Y+Z + * -X-Y-Z + * For every roughness a mip map chain is also saved, which is essential to remove the texture artifacts due to + * minification. + * Right now for every face a PlaneMesh is drawn, which leads to a lot of geometry draw calls, but can be replaced + * later by drawing a single buffer and by sending the appropriate faceIndex via vertex attributes. + * The arrangement of the faces is fixed, as assuming this arrangement, the sampling function has been written. + */ +export default function (THREE) { +let { + BackSide, + CubeUVReflectionMapping, + LinearFilter, + LinearToneMapping, + Mesh, + NoBlending, + OrthographicCamera, + PlaneBufferGeometry, + RGBEEncoding, + RGBM16Encoding, + Scene, + ShaderMaterial, + Vector2, + Vector3, + WebGLRenderTarget +} = THREE; + +var PMREMCubeUVPacker = ( function () { + + var camera = new OrthographicCamera(); + var scene = new Scene(); + var shader = getShader(); + + var PMREMCubeUVPacker = function ( cubeTextureLods ) { + + this.cubeLods = cubeTextureLods; + var size = cubeTextureLods[ 0 ].width * 4; + + var sourceTexture = cubeTextureLods[ 0 ].texture; + var params = { + format: sourceTexture.format, + magFilter: sourceTexture.magFilter, + minFilter: sourceTexture.minFilter, + type: sourceTexture.type, + generateMipmaps: sourceTexture.generateMipmaps, + anisotropy: sourceTexture.anisotropy, + encoding: ( sourceTexture.encoding === RGBEEncoding ) ? RGBM16Encoding : sourceTexture.encoding + }; + + if ( params.encoding === RGBM16Encoding ) { + + params.magFilter = LinearFilter; + params.minFilter = LinearFilter; + + } + + this.CubeUVRenderTarget = new WebGLRenderTarget( size, size, params ); + this.CubeUVRenderTarget.texture.name = "PMREMCubeUVPacker.cubeUv"; + this.CubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping; + + this.objects = []; + + var geometry = new PlaneBufferGeometry( 1, 1 ); + + var faceOffsets = []; + faceOffsets.push( new Vector2( 0, 0 ) ); + faceOffsets.push( new Vector2( 1, 0 ) ); + faceOffsets.push( new Vector2( 2, 0 ) ); + faceOffsets.push( new Vector2( 0, 1 ) ); + faceOffsets.push( new Vector2( 1, 1 ) ); + faceOffsets.push( new Vector2( 2, 1 ) ); + + var textureResolution = size; + size = cubeTextureLods[ 0 ].width; + + var offset2 = 0; + var c = 4.0; + this.numLods = Math.log( cubeTextureLods[ 0 ].width ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 + for ( var i = 0; i < this.numLods; i ++ ) { + + var offset1 = ( textureResolution - textureResolution / c ) * 0.5; + if ( size > 16 ) c *= 2; + var nMips = size > 16 ? 6 : 1; + var mipOffsetX = 0; + var mipOffsetY = 0; + var mipSize = size; + + for ( var j = 0; j < nMips; j ++ ) { + + // Mip Maps + for ( var k = 0; k < 6; k ++ ) { + + // 6 Cube Faces + var material = shader.clone(); + material.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; + material.envMap = this.cubeLods[ i ].texture; + material.uniforms[ 'faceIndex' ].value = k; + material.uniforms[ 'mapSize' ].value = mipSize; + + var planeMesh = new Mesh( geometry, material ); + planeMesh.position.x = faceOffsets[ k ].x * mipSize - offset1 + mipOffsetX; + planeMesh.position.y = faceOffsets[ k ].y * mipSize - offset1 + offset2 + mipOffsetY; + planeMesh.material.side = BackSide; + planeMesh.scale.setScalar( mipSize ); + this.objects.push( planeMesh ); + + } + mipOffsetY += 1.75 * mipSize; + mipOffsetX += 1.25 * mipSize; + mipSize /= 2; + + } + offset2 += 2 * size; + if ( size > 16 ) size /= 2; + + } + + }; + + PMREMCubeUVPacker.prototype = { + + constructor: PMREMCubeUVPacker, + + update: function ( renderer ) { + + var size = this.cubeLods[ 0 ].width * 4; + // top and bottom are swapped for some reason? + camera.left = - size * 0.5; + camera.right = size * 0.5; + camera.top = - size * 0.5; + camera.bottom = size * 0.5; + camera.near = 0; + camera.far = 1; + camera.updateProjectionMatrix(); + + for ( var i = 0; i < this.objects.length; i ++ ) { + + scene.add( this.objects[ i ] ); + + } + + var gammaInput = renderer.gammaInput; + var gammaOutput = renderer.gammaOutput; + var toneMapping = renderer.toneMapping; + var toneMappingExposure = renderer.toneMappingExposure; + var currentRenderTarget = renderer.getRenderTarget(); + + renderer.gammaInput = false; + renderer.gammaOutput = false; + renderer.toneMapping = LinearToneMapping; + renderer.toneMappingExposure = 1.0; + renderer.setRenderTarget( this.CubeUVRenderTarget ); + renderer.render( scene, camera ); + + renderer.setRenderTarget( currentRenderTarget ); + renderer.toneMapping = toneMapping; + renderer.toneMappingExposure = toneMappingExposure; + renderer.gammaInput = gammaInput; + renderer.gammaOutput = gammaOutput; + + for ( var i = 0; i < this.objects.length; i ++ ) { + + scene.remove( this.objects[ i ] ); + + } + + }, + + dispose: function () { + + for ( var i = 0, l = this.objects.length; i < l; i ++ ) { + + this.objects[ i ].material.dispose(); + + } + + this.objects[ 0 ].geometry.dispose(); + + } + + }; + + function getShader() { + + var shaderMaterial = new ShaderMaterial( { + + uniforms: { + "faceIndex": { value: 0 }, + "mapSize": { value: 0 }, + "envMap": { value: null }, + "testColor": { value: new Vector3( 1, 1, 1 ) } + }, + + vertexShader: + "precision highp float;\ + varying vec2 vUv;\ + void main() {\ + vUv = uv;\ + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\ + }", + + fragmentShader: + "precision highp float;\ + varying vec2 vUv;\ + uniform samplerCube envMap;\ + uniform float mapSize;\ + uniform vec3 testColor;\ + uniform int faceIndex;\ + \ + void main() {\ + vec3 sampleDirection;\ + vec2 uv = vUv;\ + uv = uv * 2.0 - 1.0;\ + uv.y *= -1.0;\ + if(faceIndex == 0) {\ + sampleDirection = normalize(vec3(1.0, uv.y, -uv.x));\ + } else if(faceIndex == 1) {\ + sampleDirection = normalize(vec3(uv.x, 1.0, uv.y));\ + } else if(faceIndex == 2) {\ + sampleDirection = normalize(vec3(uv.x, uv.y, 1.0));\ + } else if(faceIndex == 3) {\ + sampleDirection = normalize(vec3(-1.0, uv.y, uv.x));\ + } else if(faceIndex == 4) {\ + sampleDirection = normalize(vec3(uv.x, -1.0, -uv.y));\ + } else {\ + sampleDirection = normalize(vec3(-uv.x, uv.y, -1.0));\ + }\ + vec4 color = envMapTexelToLinear( textureCube( envMap, sampleDirection ) );\ + gl_FragColor = linearToOutputTexel( color );\ + }", + + blending: NoBlending + + } ); + + shaderMaterial.type = 'PMREMCubeUVPacker'; + + return shaderMaterial; + + } + + + return PMREMCubeUVPacker; + +} )(); + +return { PMREMCubeUVPacker }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/pmrem/PMREMGenerator.js b/src/wechat_app/jsm/pmrem/PMREMGenerator.js new file mode 100644 index 0000000..4cdf025 --- /dev/null +++ b/src/wechat_app/jsm/pmrem/PMREMGenerator.js @@ -0,0 +1,311 @@ +/** + * @author Prashant Sharma / spidersharma03 + * @author Ben Houston / bhouston, https://clara.io + * + * To avoid cube map seams, I create an extra pixel around each face. This way when the cube map is + * sampled by an application later(with a little care by sampling the centre of the texel), the extra 1 border + * of pixels makes sure that there is no seams artifacts present. This works perfectly for cubeUV format as + * well where the 6 faces can be arranged in any manner whatsoever. + * Code in the beginning of fragment shader's main function does this job for a given resolution. + * Run Scene_PMREM_Test.html in the examples directory to see the sampling from the cube lods generated + * by this class. + */ +export default function (THREE) { +let { + DoubleSide, + GammaEncoding, + LinearEncoding, + LinearFilter, + LinearToneMapping, + Mesh, + NearestFilter, + NoBlending, + OrthographicCamera, + PlaneBufferGeometry, + Scene, + ShaderMaterial, + WebGLRenderTargetCube, + sRGBEncoding +} = THREE; + +var PMREMGenerator = ( function () { + + var shader = getShader(); + var camera = new OrthographicCamera( - 1, 1, 1, - 1, 0.0, 1000 ); + var scene = new Scene(); + var planeMesh = new Mesh( new PlaneBufferGeometry( 2, 2, 0 ), shader ); + planeMesh.material.side = DoubleSide; + scene.add( planeMesh ); + scene.add( camera ); + + var PMREMGenerator = function ( sourceTexture, samplesPerLevel, resolution ) { + + this.sourceTexture = sourceTexture; + this.resolution = ( resolution !== undefined ) ? resolution : 256; // NODE: 256 is currently hard coded in the glsl code for performance reasons + this.samplesPerLevel = ( samplesPerLevel !== undefined ) ? samplesPerLevel : 32; + + var monotonicEncoding = ( this.sourceTexture.encoding === LinearEncoding ) || + ( this.sourceTexture.encoding === GammaEncoding ) || ( this.sourceTexture.encoding === sRGBEncoding ); + + this.sourceTexture.minFilter = ( monotonicEncoding ) ? LinearFilter : NearestFilter; + this.sourceTexture.magFilter = ( monotonicEncoding ) ? LinearFilter : NearestFilter; + this.sourceTexture.generateMipmaps = this.sourceTexture.generateMipmaps && monotonicEncoding; + + this.cubeLods = []; + + var size = this.resolution; + var params = { + format: this.sourceTexture.format, + magFilter: this.sourceTexture.magFilter, + minFilter: this.sourceTexture.minFilter, + type: this.sourceTexture.type, + generateMipmaps: this.sourceTexture.generateMipmaps, + anisotropy: this.sourceTexture.anisotropy, + encoding: this.sourceTexture.encoding + }; + + // how many LODs fit in the given CubeUV Texture. + this.numLods = Math.log( size ) / Math.log( 2 ) - 2; // IE11 doesn't support Math.log2 + + for ( var i = 0; i < this.numLods; i ++ ) { + + var renderTarget = new WebGLRenderTargetCube( size, size, params ); + renderTarget.texture.name = "PMREMGenerator.cube" + i; + this.cubeLods.push( renderTarget ); + size = Math.max( 16, size / 2 ); + + } + + }; + + PMREMGenerator.prototype = { + + constructor: PMREMGenerator, + + /* + * Prashant Sharma / spidersharma03: More thought and work is needed here. + * Right now it's a kind of a hack to use the previously convolved map to convolve the current one. + * I tried to use the original map to convolve all the lods, but for many textures(specially the high frequency) + * even a high number of samples(1024) dosen't lead to satisfactory results. + * By using the previous convolved maps, a lower number of samples are generally sufficient(right now 32, which + * gives okay results unless we see the reflection very carefully, or zoom in too much), however the math + * goes wrong as the distribution function tries to sample a larger area than what it should be. So I simply scaled + * the roughness by 0.9(totally empirical) to try to visually match the original result. + * The condition "if(i <5)" is also an attemt to make the result match the original result. + * This method requires the most amount of thinking I guess. Here is a paper which we could try to implement in future:: + * https://developer.nvidia.com/gpugems/GPUGems3/gpugems3_ch20.html + */ + update: function ( renderer ) { + + // Texture should only be flipped for CubeTexture, not for + // a Texture created via WebGLRenderTargetCube. + var tFlip = ( this.sourceTexture.isCubeTexture ) ? - 1 : 1; + + shader.defines[ 'SAMPLES_PER_LEVEL' ] = this.samplesPerLevel; + shader.uniforms[ 'faceIndex' ].value = 0; + shader.uniforms[ 'envMap' ].value = this.sourceTexture; + shader.envMap = this.sourceTexture; + shader.needsUpdate = true; + + var gammaInput = renderer.gammaInput; + var gammaOutput = renderer.gammaOutput; + var toneMapping = renderer.toneMapping; + var toneMappingExposure = renderer.toneMappingExposure; + var currentRenderTarget = renderer.getRenderTarget(); + + renderer.toneMapping = LinearToneMapping; + renderer.toneMappingExposure = 1.0; + renderer.gammaInput = false; + renderer.gammaOutput = false; + + for ( var i = 0; i < this.numLods; i ++ ) { + + var r = i / ( this.numLods - 1 ); + shader.uniforms[ 'roughness' ].value = r * 0.9; // see comment above, pragmatic choice + // Only apply the tFlip for the first LOD + shader.uniforms[ 'tFlip' ].value = ( i == 0 ) ? tFlip : 1; + var size = this.cubeLods[ i ].width; + shader.uniforms[ 'mapSize' ].value = size; + this.renderToCubeMapTarget( renderer, this.cubeLods[ i ] ); + + if ( i < 5 ) shader.uniforms[ 'envMap' ].value = this.cubeLods[ i ].texture; + + } + + renderer.setRenderTarget( currentRenderTarget ); + renderer.toneMapping = toneMapping; + renderer.toneMappingExposure = toneMappingExposure; + renderer.gammaInput = gammaInput; + renderer.gammaOutput = gammaOutput; + + }, + + renderToCubeMapTarget: function ( renderer, renderTarget ) { + + for ( var i = 0; i < 6; i ++ ) { + + this.renderToCubeMapTargetFace( renderer, renderTarget, i ); + + } + + }, + + renderToCubeMapTargetFace: function ( renderer, renderTarget, faceIndex ) { + + shader.uniforms[ 'faceIndex' ].value = faceIndex; + renderer.setRenderTarget( renderTarget, faceIndex ); + renderer.clear(); + renderer.render( scene, camera ); + + }, + + dispose: function () { + + for ( var i = 0, l = this.cubeLods.length; i < l; i ++ ) { + + this.cubeLods[ i ].dispose(); + + } + + }, + + }; + + function getShader() { + + var shaderMaterial = new ShaderMaterial( { + + defines: { + "SAMPLES_PER_LEVEL": 20, + }, + + uniforms: { + "faceIndex": { value: 0 }, + "roughness": { value: 0.5 }, + "mapSize": { value: 0.5 }, + "envMap": { value: null }, + "tFlip": { value: - 1 }, + }, + + vertexShader: + "varying vec2 vUv;\n\ + void main() {\n\ + vUv = uv;\n\ + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ + }", + + fragmentShader: + "#include \n\ + varying vec2 vUv;\n\ + uniform int faceIndex;\n\ + uniform float roughness;\n\ + uniform samplerCube envMap;\n\ + uniform float mapSize;\n\ + uniform float tFlip;\n\ + \n\ + float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {\n\ + float a = ggxRoughness + 0.0001;\n\ + a *= a;\n\ + return ( 2.0 / a - 2.0 );\n\ + }\n\ + vec3 ImportanceSamplePhong(vec2 uv, mat3 vecSpace, float specPow) {\n\ + float phi = uv.y * 2.0 * PI;\n\ + float cosTheta = pow(1.0 - uv.x, 1.0 / (specPow + 1.0));\n\ + float sinTheta = sqrt(1.0 - cosTheta * cosTheta);\n\ + vec3 sampleDir = vec3(cos(phi) * sinTheta, sin(phi) * sinTheta, cosTheta);\n\ + return vecSpace * sampleDir;\n\ + }\n\ + vec3 ImportanceSampleGGX( vec2 uv, mat3 vecSpace, float Roughness )\n\ + {\n\ + float a = Roughness * Roughness;\n\ + float Phi = 2.0 * PI * uv.x;\n\ + float CosTheta = sqrt( (1.0 - uv.y) / ( 1.0 + (a*a - 1.0) * uv.y ) );\n\ + float SinTheta = sqrt( 1.0 - CosTheta * CosTheta );\n\ + return vecSpace * vec3(SinTheta * cos( Phi ), SinTheta * sin( Phi ), CosTheta);\n\ + }\n\ + mat3 matrixFromVector(vec3 n) {\n\ + float a = 1.0 / (1.0 + n.z);\n\ + float b = -n.x * n.y * a;\n\ + vec3 b1 = vec3(1.0 - n.x * n.x * a, b, -n.x);\n\ + vec3 b2 = vec3(b, 1.0 - n.y * n.y * a, -n.y);\n\ + return mat3(b1, b2, n);\n\ + }\n\ + \n\ + vec4 testColorMap(float Roughness) {\n\ + vec4 color;\n\ + if(faceIndex == 0)\n\ + color = vec4(1.0,0.0,0.0,1.0);\n\ + else if(faceIndex == 1)\n\ + color = vec4(0.0,1.0,0.0,1.0);\n\ + else if(faceIndex == 2)\n\ + color = vec4(0.0,0.0,1.0,1.0);\n\ + else if(faceIndex == 3)\n\ + color = vec4(1.0,1.0,0.0,1.0);\n\ + else if(faceIndex == 4)\n\ + color = vec4(0.0,1.0,1.0,1.0);\n\ + else\n\ + color = vec4(1.0,0.0,1.0,1.0);\n\ + color *= ( 1.0 - Roughness );\n\ + return color;\n\ + }\n\ + void main() {\n\ + vec3 sampleDirection;\n\ + vec2 uv = vUv*2.0 - 1.0;\n\ + float offset = -1.0/mapSize;\n\ + const float a = -1.0;\n\ + const float b = 1.0;\n\ + float c = -1.0 + offset;\n\ + float d = 1.0 - offset;\n\ + float bminusa = b - a;\n\ + uv.x = (uv.x - a)/bminusa * d - (uv.x - b)/bminusa * c;\n\ + uv.y = (uv.y - a)/bminusa * d - (uv.y - b)/bminusa * c;\n\ + if (faceIndex==0) {\n\ + sampleDirection = vec3(1.0, -uv.y, -uv.x);\n\ + } else if (faceIndex==1) {\n\ + sampleDirection = vec3(-1.0, -uv.y, uv.x);\n\ + } else if (faceIndex==2) {\n\ + sampleDirection = vec3(uv.x, 1.0, uv.y);\n\ + } else if (faceIndex==3) {\n\ + sampleDirection = vec3(uv.x, -1.0, -uv.y);\n\ + } else if (faceIndex==4) {\n\ + sampleDirection = vec3(uv.x, -uv.y, 1.0);\n\ + } else {\n\ + sampleDirection = vec3(-uv.x, -uv.y, -1.0);\n\ + }\n\ + vec3 correctedDirection = vec3( tFlip * sampleDirection.x, sampleDirection.yz );\n\ + mat3 vecSpace = matrixFromVector( normalize( correctedDirection ) );\n\ + vec3 rgbColor = vec3(0.0);\n\ + const int NumSamples = SAMPLES_PER_LEVEL;\n\ + vec3 vect;\n\ + float weight = 0.0;\n\ + for( int i = 0; i < NumSamples; i ++ ) {\n\ + float sini = sin(float(i));\n\ + float cosi = cos(float(i));\n\ + float r = rand(vec2(sini, cosi));\n\ + vect = ImportanceSampleGGX(vec2(float(i) / float(NumSamples), r), vecSpace, roughness);\n\ + float dotProd = dot(vect, normalize(sampleDirection));\n\ + weight += dotProd;\n\ + vec3 color = envMapTexelToLinear(textureCube(envMap, vect)).rgb;\n\ + rgbColor.rgb += color;\n\ + }\n\ + rgbColor /= float(NumSamples);\n\ + //rgbColor = testColorMap( roughness ).rgb;\n\ + gl_FragColor = linearToOutputTexel( vec4( rgbColor, 1.0 ) );\n\ + }", + + blending: NoBlending + + } ); + + shaderMaterial.type = 'PMREMGenerator'; + + return shaderMaterial; + + } + + return PMREMGenerator; + +} )(); + +return { PMREMGenerator }; +} \ No newline at end of file diff --git a/src/wechat_app/jsm/utils/SkeletonUtils.js b/src/wechat_app/jsm/utils/SkeletonUtils.js new file mode 100644 index 0000000..bbba47b --- /dev/null +++ b/src/wechat_app/jsm/utils/SkeletonUtils.js @@ -0,0 +1,599 @@ +/** + * @author sunag / http://www.sunag.com.br + */ +export default function (THREE) { +let { + AnimationClip, + AnimationMixer, + Euler, + Matrix4, + Quaternion, + QuaternionKeyframeTrack, + SkeletonHelper, + Vector2, + Vector3, + VectorKeyframeTrack +} = THREE; + +var SkeletonUtils = { + + retarget: function () { + + var pos = new Vector3(), + quat = new Quaternion(), + scale = new Vector3(), + bindBoneMatrix = new Matrix4(), + relativeMatrix = new Matrix4(), + globalMatrix = new Matrix4(); + + return function ( target, source, options ) { + + options = options || {}; + options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true; + options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true; + options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false; + options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false; + options.hip = options.hip !== undefined ? options.hip : "hip"; + options.names = options.names || {}; + + var sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ), + bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ), + bindBones, + bone, name, boneTo, + bonesPosition, i; + + // reset bones + + if ( target.isObject3D ) { + + target.skeleton.pose(); + + } else { + + options.useTargetMatrix = true; + options.preserveMatrix = false; + + } + + if ( options.preservePosition ) { + + bonesPosition = []; + + for ( i = 0; i < bones.length; i ++ ) { + + bonesPosition.push( bones[ i ].position.clone() ); + + } + + } + + if ( options.preserveMatrix ) { + + // reset matrix + + target.updateMatrixWorld(); + + target.matrixWorld.identity(); + + // reset children matrix + + for ( i = 0; i < target.children.length; ++ i ) { + + target.children[ i ].updateMatrixWorld( true ); + + } + + } + + if ( options.offsets ) { + + bindBones = []; + + for ( i = 0; i < bones.length; ++ i ) { + + bone = bones[ i ]; + name = options.names[ bone.name ] || bone.name; + + if ( options.offsets && options.offsets[ name ] ) { + + bone.matrix.multiply( options.offsets[ name ] ); + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + bone.updateMatrixWorld(); + + } + + bindBones.push( bone.matrixWorld.clone() ); + + } + + } + + for ( i = 0; i < bones.length; ++ i ) { + + bone = bones[ i ]; + name = options.names[ bone.name ] || bone.name; + + boneTo = this.getBoneByName( name, sourceBones ); + + globalMatrix.copy( bone.matrixWorld ); + + if ( boneTo ) { + + boneTo.updateMatrixWorld(); + + if ( options.useTargetMatrix ) { + + relativeMatrix.copy( boneTo.matrixWorld ); + + } else { + + relativeMatrix.getInverse( target.matrixWorld ); + relativeMatrix.multiply( boneTo.matrixWorld ); + + } + + // ignore scale to extract rotation + + scale.setFromMatrixScale( relativeMatrix ); + relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) ); + + // apply to global matrix + + globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) ); + + if ( target.isObject3D ) { + + var boneIndex = bones.indexOf( bone ), + wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.getInverse( target.skeleton.boneInverses[ boneIndex ] ); + + globalMatrix.multiply( wBindMatrix ); + + } + + globalMatrix.copyPosition( relativeMatrix ); + + } + + if ( bone.parent && bone.parent.isBone ) { + + bone.matrix.getInverse( bone.parent.matrixWorld ); + bone.matrix.multiply( globalMatrix ); + + } else { + + bone.matrix.copy( globalMatrix ); + + } + + if ( options.preserveHipPosition && name === options.hip ) { + + bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) ); + + } + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + bone.updateMatrixWorld(); + + } + + if ( options.preservePosition ) { + + for ( i = 0; i < bones.length; ++ i ) { + + bone = bones[ i ]; + name = options.names[ bone.name ] || bone.name; + + if ( name !== options.hip ) { + + bone.position.copy( bonesPosition[ i ] ); + + } + + } + + } + + if ( options.preserveMatrix ) { + + // restore matrix + + target.updateMatrixWorld( true ); + + } + + }; + + }(), + + retargetClip: function ( target, source, clip, options ) { + + options = options || {}; + options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false; + options.fps = options.fps !== undefined ? options.fps : 30; + options.names = options.names || []; + + if ( ! source.isObject3D ) { + + source = this.getHelperFromSkeleton( source ); + + } + + var numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ), + delta = 1 / options.fps, + convertedTracks = [], + mixer = new AnimationMixer( source ), + bones = this.getBones( target.skeleton ), + boneDatas = [], + positionOffset, + bone, boneTo, boneData, + name, i, j; + + mixer.clipAction( clip ).play(); + mixer.update( 0 ); + + source.updateMatrixWorld(); + + for ( i = 0; i < numFrames; ++ i ) { + + var time = i * delta; + + this.retarget( target, source, options ); + + for ( j = 0; j < bones.length; ++ j ) { + + name = options.names[ bones[ j ].name ] || bones[ j ].name; + + boneTo = this.getBoneByName( name, source.skeleton ); + + if ( boneTo ) { + + bone = bones[ j ]; + boneData = boneDatas[ j ] = boneDatas[ j ] || { bone: bone }; + + if ( options.hip === name ) { + + if ( ! boneData.pos ) { + + boneData.pos = { + times: new Float32Array( numFrames ), + values: new Float32Array( numFrames * 3 ) + }; + + } + + if ( options.useFirstFramePosition ) { + + if ( i === 0 ) { + + positionOffset = bone.position.clone(); + + } + + bone.position.sub( positionOffset ); + + } + + boneData.pos.times[ i ] = time; + + bone.position.toArray( boneData.pos.values, i * 3 ); + + } + + if ( ! boneData.quat ) { + + boneData.quat = { + times: new Float32Array( numFrames ), + values: new Float32Array( numFrames * 4 ) + }; + + } + + boneData.quat.times[ i ] = time; + + bone.quaternion.toArray( boneData.quat.values, i * 4 ); + + } + + } + + mixer.update( delta ); + + source.updateMatrixWorld(); + + } + + for ( i = 0; i < boneDatas.length; ++ i ) { + + boneData = boneDatas[ i ]; + + if ( boneData ) { + + if ( boneData.pos ) { + + convertedTracks.push( new VectorKeyframeTrack( + ".bones[" + boneData.bone.name + "].position", + boneData.pos.times, + boneData.pos.values + ) ); + + } + + convertedTracks.push( new QuaternionKeyframeTrack( + ".bones[" + boneData.bone.name + "].quaternion", + boneData.quat.times, + boneData.quat.values + ) ); + + } + + } + + mixer.uncacheAction( clip ); + + return new AnimationClip( clip.name, - 1, convertedTracks ); + + }, + + getHelperFromSkeleton: function ( skeleton ) { + + var source = new SkeletonHelper( skeleton.bones[ 0 ] ); + source.skeleton = skeleton; + + return source; + + }, + + getSkeletonOffsets: function () { + + var targetParentPos = new Vector3(), + targetPos = new Vector3(), + sourceParentPos = new Vector3(), + sourcePos = new Vector3(), + targetDir = new Vector2(), + sourceDir = new Vector2(); + + return function ( target, source, options ) { + + options = options || {}; + options.hip = options.hip !== undefined ? options.hip : "hip"; + options.names = options.names || {}; + + if ( ! source.isObject3D ) { + + source = this.getHelperFromSkeleton( source ); + + } + + var nameKeys = Object.keys( options.names ), + nameValues = Object.values( options.names ), + sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ), + bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ), + offsets = [], + bone, boneTo, + name, i; + + target.skeleton.pose(); + + for ( i = 0; i < bones.length; ++ i ) { + + bone = bones[ i ]; + name = options.names[ bone.name ] || bone.name; + + boneTo = this.getBoneByName( name, sourceBones ); + + if ( boneTo && name !== options.hip ) { + + var boneParent = this.getNearestBone( bone.parent, nameKeys ), + boneToParent = this.getNearestBone( boneTo.parent, nameValues ); + + boneParent.updateMatrixWorld(); + boneToParent.updateMatrixWorld(); + + targetParentPos.setFromMatrixPosition( boneParent.matrixWorld ); + targetPos.setFromMatrixPosition( bone.matrixWorld ); + + sourceParentPos.setFromMatrixPosition( boneToParent.matrixWorld ); + sourcePos.setFromMatrixPosition( boneTo.matrixWorld ); + + targetDir.subVectors( + new Vector2( targetPos.x, targetPos.y ), + new Vector2( targetParentPos.x, targetParentPos.y ) + ).normalize(); + + sourceDir.subVectors( + new Vector2( sourcePos.x, sourcePos.y ), + new Vector2( sourceParentPos.x, sourceParentPos.y ) + ).normalize(); + + var laterialAngle = targetDir.angle() - sourceDir.angle(); + + var offset = new Matrix4().makeRotationFromEuler( + new Euler( + 0, + 0, + laterialAngle + ) + ); + + bone.matrix.multiply( offset ); + + bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); + + bone.updateMatrixWorld(); + + offsets[ name ] = offset; + + } + + } + + return offsets; + + }; + + }(), + + renameBones: function ( skeleton, names ) { + + var bones = this.getBones( skeleton ); + + for ( var i = 0; i < bones.length; ++ i ) { + + var bone = bones[ i ]; + + if ( names[ bone.name ] ) { + + bone.name = names[ bone.name ]; + + } + + } + + return this; + + }, + + getBones: function ( skeleton ) { + + return Array.isArray( skeleton ) ? skeleton : skeleton.bones; + + }, + + getBoneByName: function ( name, skeleton ) { + + for ( var i = 0, bones = this.getBones( skeleton ); i < bones.length; i ++ ) { + + if ( name === bones[ i ].name ) + + return bones[ i ]; + + } + + }, + + getNearestBone: function ( bone, names ) { + + while ( bone.isBone ) { + + if ( names.indexOf( bone.name ) !== - 1 ) { + + return bone; + + } + + bone = bone.parent; + + } + + }, + + findBoneTrackData: function ( name, tracks ) { + + var regexp = /\[(.*)\]\.(.*)/, + result = { name: name }; + + for ( var i = 0; i < tracks.length; ++ i ) { + + // 1 is track name + // 2 is track type + var trackData = regexp.exec( tracks[ i ].name ); + + if ( trackData && name === trackData[ 1 ] ) { + + result[ trackData[ 2 ] ] = i; + + } + + } + + return result; + + }, + + getEqualsBonesNames: function ( skeleton, targetSkeleton ) { + + var sourceBones = this.getBones( skeleton ), + targetBones = this.getBones( targetSkeleton ), + bones = []; + + search : for ( var i = 0; i < sourceBones.length; i ++ ) { + + var boneName = sourceBones[ i ].name; + + for ( var j = 0; j < targetBones.length; j ++ ) { + + if ( boneName === targetBones[ j ].name ) { + + bones.push( boneName ); + + continue search; + + } + + } + + } + + return bones; + + }, + + clone: function ( source ) { + + var sourceLookup = new Map(); + var cloneLookup = new Map(); + + var clone = source.clone(); + + parallelTraverse( source, clone, function ( sourceNode, clonedNode ) { + + sourceLookup.set( clonedNode, sourceNode ); + cloneLookup.set( sourceNode, clonedNode ); + + } ); + + clone.traverse( function ( node ) { + + if ( ! node.isSkinnedMesh ) return; + + var clonedMesh = node; + var sourceMesh = sourceLookup.get( node ); + var sourceBones = sourceMesh.skeleton.bones; + + clonedMesh.skeleton = sourceMesh.skeleton.clone(); + clonedMesh.bindMatrix.copy( sourceMesh.bindMatrix ); + + clonedMesh.skeleton.bones = sourceBones.map( function ( bone ) { + + return cloneLookup.get( bone ); + + } ); + + clonedMesh.bind( clonedMesh.skeleton, clonedMesh.bindMatrix ); + + } ); + + return clone; + + } + +}; + + +function parallelTraverse( a, b, callback ) { + + callback( a, b ); + + for ( var i = 0; i < a.children.length; i ++ ) { + + parallelTraverse( a.children[ i ], b.children[ i ], callback ); + + } + +} + +return { SkeletonUtils }; +} \ No newline at end of file diff --git a/src/wechat_app/libs/three.weapp.js b/src/wechat_app/libs/three.weapp.js new file mode 100644 index 0000000..27631fe --- /dev/null +++ b/src/wechat_app/libs/three.weapp.js @@ -0,0 +1,1073 @@ +(function(l,fa){"object"===typeof exports&&"undefined"!==typeof module?fa(exports):"function"===typeof define&&define.amd?define(["exports"],fa):(l=l||self,fa(l.THREE={}))})(this,function(l){function fa(){}function fb(e,h){if(!(e instanceof h))throw new TypeError("Cannot call a class as a function");}function Oh(e,h){for(var a=0;ag)return!1}return!0}function ub(e,h){this.center=void 0!==e?e:new q;this.radius=void 0!==h?h:0}function ac(e,h){this.origin=void 0!== +e?e:new q;this.direction=void 0!==h?h:new q}function Sa(e,h){this.normal=void 0!==e?e:new q(1,0,0);this.constant=void 0!==h?h:0}function va(e,h,a){this.a=void 0!==e?e:new q;this.b=void 0!==h?h:new q;this.c=void 0!==a?a:new q}function D(e,h,a){return void 0===h&&void 0===a?this.set(e):this.setRGB(e,h,a)}function tg(e,h,a){0>a&&(a+=1);1a?h:a<2/3?e+6*(h-e)*(2/3-a):e}function ug(e){return.04045>e?.0773993808*e:Math.pow(.9478672986*e+.0521327014,2.4)}function vg(e){return.0031308> +e?12.92*e:1.055*Math.pow(e,.41666)-.055}function Mc(e,h,a,b,c,d){this.a=e;this.b=h;this.c=a;this.normal=b&&b.isVector3?b:new q;this.vertexNormals=Array.isArray(b)?b:[];this.color=c&&c.isColor?c:new D;this.vertexColors=Array.isArray(c)?c:[];this.materialIndex=void 0!==d?d:0}function R(){Object.defineProperty(this,"id",{value:Qj++});this.uuid=N.generateUUID();this.name="";this.type="Material";this.fog=!0;this.blending=1;this.side=0;this.vertexTangents=this.flatShading=!1;this.vertexColors=0;this.opacity= +1;this.transparent=!1;this.blendSrc=204;this.blendDst=205;this.blendEquation=100;this.blendEquationAlpha=this.blendDstAlpha=this.blendSrcAlpha=null;this.depthFunc=3;this.depthWrite=this.depthTest=!0;this.stencilWriteMask=255;this.stencilFunc=519;this.stencilRef=0;this.stencilFuncMask=255;this.stencilZPass=this.stencilZFail=this.stencilFail=7680;this.stencilWrite=!1;this.clippingPlanes=null;this.clipShadows=this.clipIntersection=!1;this.shadowSide=null;this.colorWrite=!0;this.precision=null;this.polygonOffset= +!1;this.polygonOffsetUnits=this.polygonOffsetFactor=0;this.dithering=!1;this.alphaTest=0;this.premultipliedAlpha=!1;this.toneMapped=this.visible=!0;this.userData={};this.needsUpdate=!0}function Ia(e){R.call(this);this.type="MeshBasicMaterial";this.color=new D(16777215);this.lightMap=this.map=null;this.lightMapIntensity=1;this.aoMap=null;this.aoMapIntensity=1;this.envMap=this.alphaMap=this.specularMap=null;this.combine=0;this.reflectivity=1;this.refractionRatio=.98;this.wireframe=!1;this.wireframeLinewidth= +1;this.wireframeLinejoin=this.wireframeLinecap="round";this.morphTargets=this.skinning=!1;this.setValues(e)}function O(e,h,a){if(Array.isArray(e))throw new TypeError("THREE.BufferAttribute: array should be a Typed Array.");this.name="";this.array=e;this.itemSize=h;this.count=void 0!==e?e.length/h:0;this.normalized=!0===a;this.usage=35044;this.updateRange={offset:0,count:-1};this.version=0}function Ld(e,h,a){O.call(this,new Int8Array(e),h,a)}function Md(e,h,a){O.call(this,new Uint8Array(e),h,a)}function Nd(e, +h,a){O.call(this,new Uint8ClampedArray(e),h,a)}function Od(e,h,a){O.call(this,new Int16Array(e),h,a)}function bc(e,h,a){O.call(this,new Uint16Array(e),h,a)}function Pd(e,h,a){O.call(this,new Int32Array(e),h,a)}function cc(e,h,a){O.call(this,new Uint32Array(e),h,a)}function F(e,h,a){O.call(this,new Float32Array(e),h,a)}function Qd(e,h,a){O.call(this,new Float64Array(e),h,a)}function Vh(){this.vertices=[];this.normals=[];this.colors=[];this.uvs=[];this.uvs2=[];this.groups=[];this.morphTargets={};this.skinWeights= +[];this.skinIndices=[];this.boundingSphere=this.boundingBox=null;this.groupsNeedUpdate=this.uvsNeedUpdate=this.colorsNeedUpdate=this.normalsNeedUpdate=this.verticesNeedUpdate=!1}function Wh(e){if(0===e.length)return-Infinity;for(var h=e[0],a=1,b=e.length;ah&&(h=e[a]);return h}function G(){Object.defineProperty(this,"id",{value:Rj+=2});this.uuid=N.generateUUID();this.name="";this.type="BufferGeometry";this.index=null;this.attributes={};this.morphAttributes={};this.groups=[];this.boundingSphere= +this.boundingBox=null;this.drawRange={start:0,count:Infinity};this.userData={}}function ia(e,h){E.call(this);this.type="Mesh";this.geometry=void 0!==e?e:new G;this.material=void 0!==h?h:new Ia({color:16777215*Math.random()});this.drawMode=0;this.updateMorphTargets()}function Xh(e,h,a,b,c,d,f,g){if(null===(1===h.side?b.intersectTriangle(f,d,c,!0,g):b.intersectTriangle(c,d,f,2!==h.side,g)))return null;Xe.copy(g);Xe.applyMatrix4(e.matrixWorld);h=a.ray.origin.distanceTo(Xe);return ha.far?null: +{distance:h,point:Xe.clone(),object:e}}function Ye(e,h,a,b,c,d,f,g,k,m,n){dc.fromBufferAttribute(c,k);ec.fromBufferAttribute(c,m);fc.fromBufferAttribute(c,n);c=e.morphTargetInfluences;if(h.morphTargets&&d&&c){wg.set(0,0,0);xg.set(0,0,0);yg.set(0,0,0);for(var p=0,y=d.length;pg;g++)a.setRenderTarget(f,g),a.clear(b,c,d);a.setRenderTarget(e)}}function Ib(e,h,a){sa.call(this,e,h,a)}function hc(e,h,a,b,c,d,f,g,k,m,n,p){S.call(this,null,d,f,g,k,m,b,c,n,p);this.image={data:e||null,width:h||1,height:a||1};this.magFilter=void 0!==k?k:1003;this.minFilter=void 0!==m?m:1003;this.flipY=this.generateMipmaps=!1;this.unpackAlignment=1;this.needsUpdate=!0}function Sd(e,h,a,b,c,d){this.planes=[void 0!==e?e:new Sa,void 0!==h?h:new Sa,void 0!==a?a:new Sa,void 0!== +b?b:new Sa,void 0!==c?c:new Sa,void 0!==d?d:new Sa]}function zg(){function e(c,d){!1!==a&&(b(c,d),h.requestAnimationFrame(e))}var h=null,a=!1,b=null;return{start:function(){!0!==a&&null!==b&&(h.requestAnimationFrame(e),a=!0)},stop:function(){a=!1},setAnimationLoop:function(a){b=a},setContext:function(a){h=a}}}function Tj(e){function h(a,c){var b=a.array,f=a.usage,g=e.createBuffer();e.bindBuffer(c,g);e.bufferData(c,b,f);a.onUploadCallback();c=5126;b instanceof Float32Array?c=5126:b instanceof Float64Array? +console.warn("THREE.WebGLAttributes: Unsupported data buffer format: Float64Array."):b instanceof Uint16Array?c=5123:b instanceof Int16Array?c=5122:b instanceof Uint32Array?c=5125:b instanceof Int32Array?c=5124:b instanceof Int8Array?c=5120:b instanceof Uint8Array&&(c=5121);return{buffer:g,type:c,bytesPerElement:b.BYTES_PER_ELEMENT,version:a.version}}var a=new WeakMap;return{get:function(b){b.isInterleavedBufferAttribute&&(b=b.data);return a.get(b)},remove:function(b){b.isInterleavedBufferAttribute&& +(b=b.data);var c=a.get(b);c&&(e.deleteBuffer(c.buffer),a.delete(b))},update:function(b,c){b.isInterleavedBufferAttribute&&(b=b.data);var d=a.get(b);if(void 0===d)a.set(b,h(b,c));else if(d.versionm;m++){if(p=b[m])if(g=p[0],k=p[1]){n&&c.setAttribute("morphTarget"+m,n[g]);d&&c.setAttribute("morphNormal"+m,d[g]);a[m]=k;continue}a[m]=0}f.getUniforms().setValue(e,"morphTargetInfluences",a)}}}function ek(e,h,a,b){var c={};return{update:function(d){var e=b.render.frame,g=d.geometry,k=h.get(d,g);c[k.id]!==e&&(g.isGeometry&&k.updateFromObject(d),h.update(k),c[k.id]=e);d.isInstancedMesh&&a.update(d.instanceMatrix,34962);return k},dispose:function(){c={}}}}function vb(e,h,a,b,c,d,f,g,k,m){e= +void 0!==e?e:[];S.call(this,e,void 0!==h?h:301,a,b,c,d,void 0!==f?f:1022,g,k,m);this.flipY=!1}function Rc(e,h,a,b){S.call(this,null);this.image={data:e||null,width:h||1,height:a||1,depth:b||1};this.minFilter=this.magFilter=1003;this.wrapR=1001;this.flipY=this.generateMipmaps=!1;this.needsUpdate=!0}function Sc(e,h,a,b){S.call(this,null);this.image={data:e||null,width:h||1,height:a||1,depth:b||1};this.minFilter=this.magFilter=1003;this.wrapR=1001;this.flipY=this.generateMipmaps=!1;this.needsUpdate= +!0}function Tc(e,h,a){var b=e[0];if(0>=b||0");return e.replace(Cg,Bg)}function pi(e,h,a,b){e="";for(h=parseInt(h);ha;a++)h.probe.push(new q);var b=new q,c=new I,d=new I;return{setup:function(a,g,k){for(var f=0,n=0,p=0,y=0;9>y;y++)h.probe[y].set(0,0,0);var l=g=0,r=0,u=0,v=0,q=0,x= +0,B=0;k=k.matrixWorldInverse;a.sort(bl);y=0;for(var C=a.length;yoa;oa++)h.probe[oa].addScaledVector(A.sh.coefficients[oa],W);else if(A.isDirectionalLight){var H=e.get(A);H.color.copy(A.color).multiplyScalar(A.intensity);H.direction.setFromMatrixPosition(A.matrixWorld);b.setFromMatrixPosition(A.target.matrixWorld); +H.direction.sub(b);H.direction.transformDirection(k);if(H.shadow=A.castShadow)W=A.shadow,H.shadowBias=W.bias,H.shadowRadius=W.radius,H.shadowMapSize=W.mapSize,h.directionalShadowMap[g]=oa,h.directionalShadowMatrix[g]=A.shadow.matrix,q++;h.directional[g]=H;g++}else if(A.isSpotLight){H=e.get(A);H.position.setFromMatrixPosition(A.matrixWorld);H.position.applyMatrix4(k);H.color.copy(Ka).multiplyScalar(W);H.distance=Ca;H.direction.setFromMatrixPosition(A.matrixWorld);b.setFromMatrixPosition(A.target.matrixWorld); +H.direction.sub(b);H.direction.transformDirection(k);H.coneCos=Math.cos(A.angle);H.penumbraCos=Math.cos(A.angle*(1-A.penumbra));H.decay=A.decay;if(H.shadow=A.castShadow)W=A.shadow,H.shadowBias=W.bias,H.shadowRadius=W.radius,H.shadowMapSize=W.mapSize,h.spotShadowMap[r]=oa,h.spotShadowMatrix[r]=A.shadow.matrix,B++;h.spot[r]=H;r++}else if(A.isRectAreaLight)H=e.get(A),H.color.copy(Ka).multiplyScalar(W),H.position.setFromMatrixPosition(A.matrixWorld),H.position.applyMatrix4(k),d.identity(),c.copy(A.matrixWorld), +c.premultiply(k),d.extractRotation(c),H.halfWidth.set(.5*A.width,0,0),H.halfHeight.set(0,.5*A.height,0),H.halfWidth.applyMatrix4(d),H.halfHeight.applyMatrix4(d),h.rectArea[u]=H,u++;else if(A.isPointLight){H=e.get(A);H.position.setFromMatrixPosition(A.matrixWorld);H.position.applyMatrix4(k);H.color.copy(A.color).multiplyScalar(A.intensity);H.distance=A.distance;H.decay=A.decay;if(H.shadow=A.castShadow)W=A.shadow,H.shadowBias=W.bias,H.shadowRadius=W.radius,H.shadowMapSize=W.mapSize,H.shadowCameraNear= +W.camera.near,H.shadowCameraFar=W.camera.far,h.pointShadowMap[l]=oa,h.pointShadowMatrix[l]=A.shadow.matrix,x++;h.point[l]=H;l++}else A.isHemisphereLight&&(H=e.get(A),H.direction.setFromMatrixPosition(A.matrixWorld),H.direction.transformDirection(k),H.direction.normalize(),H.skyColor.copy(A.color).multiplyScalar(W),H.groundColor.copy(A.groundColor).multiplyScalar(W),h.hemi[v]=H,v++)}h.ambient[0]=f;h.ambient[1]=n;h.ambient[2]=p;a=h.hash;if(a.directionalLength!==g||a.pointLength!==l||a.spotLength!== +r||a.rectAreaLength!==u||a.hemiLength!==v||a.numDirectionalShadows!==q||a.numPointShadows!==x||a.numSpotShadows!==B)h.directional.length=g,h.spot.length=r,h.rectArea.length=u,h.point.length=l,h.hemi.length=v,h.directionalShadowMap.length=q,h.pointShadowMap.length=x,h.spotShadowMap.length=B,h.directionalShadowMatrix.length=q,h.pointShadowMatrix.length=x,h.spotShadowMatrix.length=B,a.directionalLength=g,a.pointLength=l,a.spotLength=r,a.rectAreaLength=u,a.hemiLength=v,a.numDirectionalShadows=q,a.numPointShadows= +x,a.numSpotShadows=B,h.version=dl++},state:h}}function ti(){var e=new cl,h=[],a=[];return{init:function(){h.length=0;a.length=0},state:{lightsArray:h,shadowsArray:a,lights:e},setupLights:function(b){e.setup(h,a,b)},pushLight:function(a){h.push(a)},pushShadow:function(b){a.push(b)}}}function el(){function e(a){a=a.target;a.removeEventListener("dispose",e);h.delete(a)}var h=new WeakMap;return{get:function(a,b){if(!1===h.has(a)){var c=new ti;h.set(a,new WeakMap);h.get(a).set(b,c);a.addEventListener("dispose", +e)}else!1===h.get(a).has(b)?(c=new ti,h.get(a).set(b,c)):c=h.get(a).get(b);return c},dispose:function(){h=new WeakMap}}}function Kb(e){R.call(this);this.type="MeshDepthMaterial";this.depthPacking=3200;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.wireframe=!1;this.wireframeLinewidth=1;this.fog=!1;this.setValues(e)}function Lb(e){R.call(this);this.type="MeshDistanceMaterial";this.referencePosition=new q;this.nearDistance= +1;this.farDistance=1E3;this.morphTargets=this.skinning=!1;this.displacementMap=this.alphaMap=this.map=null;this.displacementScale=1;this.displacementBias=0;this.fog=!1;this.setValues(e)}function ui(e,h,a){function b(a,b,c){c=a<<0|b<<1|c<<2;var d=p[c];void 0===d&&(d=new Kb({depthPacking:3201,morphTargets:a,skinning:b}),p[c]=d);return d}function c(a,b,c){c=a<<0|b<<1|c<<2;var d=l[c];void 0===d&&(d=new Lb({morphTargets:a,skinning:b}),l[c]=d);return d}function d(a,d,f,h,g,k){var m=a.geometry,n=b,p=a.customDepthMaterial; +!0===f.isPointLight&&(n=c,p=a.customDistanceMaterial);void 0===p?(p=!1,!0===d.morphTargets&&(!0===m.isBufferGeometry?p=m.morphAttributes&&m.morphAttributes.position&&0\nvoid main() {\n float mean = 0.0;\n float squared_mean = 0.0;\n \n\tfloat depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy ) / resolution ) );\n for ( float i = -1.0; i < 1.0 ; i += SAMPLE_RATE) {\n #ifdef HORIZONAL_PASS\n vec2 distribution = decodeHalfRGBA ( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( i, 0.0 ) * radius ) / resolution ) );\n mean += distribution.x;\n squared_mean += distribution.y * distribution.y + distribution.x * distribution.x;\n #else\n float depth = unpackRGBAToDepth( texture2D( shadow_pass, ( gl_FragCoord.xy + vec2( 0.0, i ) * radius ) / resolution ) );\n mean += depth;\n squared_mean += depth * depth;\n #endif\n }\n mean = mean * HALF_SAMPLE_RATE;\n squared_mean = squared_mean * HALF_SAMPLE_RATE;\n float std_dev = pow( squared_mean - mean * mean, 0.5 );\n gl_FragColor = encodeHalfRGBA( vec2( mean, std_dev ) );\n}"}), +v=u.clone();v.defines.HORIZONAL_PASS=1;var q=new G;q.setAttribute("position",new O(new Float32Array([-1,-1,.5,3,-1,.5,-1,3,.5]),3));var x=new ia(q,u),B=this;this.enabled=!1;this.autoUpdate=!0;this.needsUpdate=!1;this.type=1;this.render=function(b,c,d){if(!1!==B.enabled&&(!1!==B.autoUpdate||!1!==B.needsUpdate)&&0!==b.length){var p=e.getRenderTarget(),r=e.getActiveCubeFace(),l=e.getActiveMipmapLevel(),y=e.state;y.setBlending(0);y.buffers.color.setClear(1,1,1,1);y.buffers.depth.setTest(!0);y.setScissorTest(!1); +for(var t=0,q=b.length;ta||k.y>a)console.warn("THREE.WebGLShadowMap:",w,"has shadow exceeding max texture size, reducing"),k.x>a&&(m.x=Math.floor(a/A.x),k.x=m.x*A.x,C.mapSize.x=m.x),k.y>a&&(m.y=Math.floor(a/A.y),k.y=m.y*A.y,C.mapSize.y=m.y);null!==C.map||C.isPointLightShadow||3!==this.type||(A={minFilter:1006,magFilter:1006, +format:1023},C.map=new sa(k.x,k.y,A),C.map.texture.name=w.name+".shadowMap",C.mapPass=new sa(k.x,k.y,A),C.camera.updateProjectionMatrix());null===C.map&&(A={minFilter:1003,magFilter:1003,format:1023},C.map=new sa(k.x,k.y,A),C.map.texture.name=w.name+".shadowMap",C.camera.updateProjectionMatrix());e.setRenderTarget(C.map);e.clear();A=C.getViewportCount();for(var z=0;zd||a.height>d)e=d/Math.max(a.width,a.height);if(1>e||!0===b){if("undefined"!==typeof HTMLImageElement&&a instanceof HTMLImageElement||"undefined"!==typeof HTMLCanvasElement&&a instanceof HTMLCanvasElement||"undefined"!==typeof ImageBitmap&&a instanceof ImageBitmap)return d=b?N.floorPowerOfTwo:Math.floor,b=d(e*a.width),e=d(e*a.height),void 0===D&&(D=g(b,e)),c=c?g(b,e):D,c.width=b,c.height=e,c.getContext("2d").drawImage(a, +0,0,b,e),console.warn("THREE.WebGLRenderer: Texture has been resized from ("+a.width+"x"+a.height+") to ("+b+"x"+e+")."),c;"data"in a&&console.warn("THREE.WebGLRenderer: Image in DataTexture is too big ("+a.width+"x"+a.height+").")}return a}function m(a){return N.isPowerOfTwo(a.width)&&N.isPowerOfTwo(a.height)}function n(a,b){return a.generateMipmaps&&b&&1003!==a.minFilter&&1006!==a.minFilter}function p(a,c,d,f){e.generateMipmap(a);b.get(c).__maxMipLevel=Math.log(Math.max(d,f))*Math.LOG2E}function l(a, +b){if(!1===oa)return a;var c=a;6403===a&&(5126===b&&(c=33326),5131===b&&(c=33325),5121===b&&(c=33321));6407===a&&(5126===b&&(c=34837),5131===b&&(c=34843),5121===b&&(c=32849));6408===a&&(5126===b&&(c=34836),5131===b&&(c=34842),5121===b&&(c=32856));33325===c||33326===c||34842===c||34836===c?h.get("EXT_color_buffer_float"):(34843===c||34837===c)&&console.warn("THREE.WebGLRenderer: Floating point textures with RGB format not supported. Please use RGBA instead.");return c}function t(a){return 1003===a|| +1004===a||1005===a?9728:9729}function r(a){a=a.target;a.removeEventListener("dispose",r);var c=b.get(a);void 0!==c.__webglInit&&(e.deleteTexture(c.__webglTexture),b.remove(a));a.isVideoTexture&&G.delete(a);f.memory.textures--}function u(a){a=a.target;a.removeEventListener("dispose",u);var c=b.get(a),d=b.get(a.texture);if(a){void 0!==d.__webglTexture&&e.deleteTexture(d.__webglTexture);a.depthTexture&&a.depthTexture.dispose();if(a.isWebGLRenderTargetCube)for(d=0;6>d;d++)e.deleteFramebuffer(c.__webglFramebuffer[d]), +c.__webglDepthbuffer&&e.deleteRenderbuffer(c.__webglDepthbuffer[d]);else e.deleteFramebuffer(c.__webglFramebuffer),c.__webglDepthbuffer&&e.deleteRenderbuffer(c.__webglDepthbuffer);if(a.isWebGLMultiviewRenderTarget){e.deleteTexture(c.__webglColorTexture);e.deleteTexture(c.__webglDepthStencilTexture);f.memory.textures-=2;d=0;for(var h=c.__webglViewFramebuffers.length;dy;y++)r[y]=g||f?f?c.image[y].image:c.image[y]:k(c.image[y],!1,!0,Wd);var t=r[0],u=m(t)||oa,q=d.convert(c.format),v=d.convert(c.type),x=l(q,v);B(34067,c,u);if(g){for(y=0;6>y;y++){var w=r[y].mipmaps;for(g=0;gy;y++)if(f)for(a.texImage2D(34069+y,0,x,r[y].width,r[y].height,0,q,v,r[y].data),g=0;g=H&&console.warn("THREE.WebGLTextures: Trying to use "+a+ +" texture units while this GPU supports only "+H);M+=1;return a};this.resetTextureUnits=function(){M=0};this.setTexture2D=q;this.setTexture2DArray=function(c,d){var e=b.get(c);0x;x++)g.__webglFramebuffer[x]=e.createFramebuffer()}else if(g.__webglFramebuffer=e.createFramebuffer(),r)if(oa){g.__webglMultisampledFramebuffer=e.createFramebuffer();g.__webglColorRenderbuffer=e.createRenderbuffer(); +e.bindRenderbuffer(36161,g.__webglColorRenderbuffer);r=d.convert(c.texture.format);var w=d.convert(c.texture.type);r=l(r,w);w=Ca(c);e.renderbufferStorageMultisample(36161,w,r,c.width,c.height);e.bindFramebuffer(36160,g.__webglMultisampledFramebuffer);e.framebufferRenderbuffer(36160,36064,36161,g.__webglColorRenderbuffer);e.bindRenderbuffer(36161,null);c.depthBuffer&&(g.__webglDepthRenderbuffer=e.createRenderbuffer(),W(g.__webglDepthRenderbuffer,c,!0));e.bindFramebuffer(36160,null)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2."); +else if(t){x=c.width;var C=c.height;r=c.numViews;e.bindFramebuffer(36160,g.__webglFramebuffer);var A=h.get("OVR_multiview2");f.memory.textures+=2;w=e.createTexture();e.bindTexture(35866,w);e.texParameteri(35866,10240,9728);e.texParameteri(35866,10241,9728);e.texImage3D(35866,0,32856,x,C,r,0,6408,5121,null);A.framebufferTextureMultiviewOVR(36160,36064,w,0,0,r);var H=e.createTexture();e.bindTexture(35866,H);e.texParameteri(35866,10240,9728);e.texParameteri(35866,10241,9728);e.texImage3D(35866,0,35056, +x,C,r,0,34041,34042,null);A.framebufferTextureMultiviewOVR(36160,33306,H,0,0,r);C=Array(r);for(x=0;xx;x++)z(g.__webglFramebuffer[x],c,36064,34069+x);n(c.texture,v)&&p(34067,c.texture, +c.width,c.height);a.bindTexture(34067,null)}else t||(a.bindTexture(3553,k.__webglTexture),B(3553,c.texture,v),z(g.__webglFramebuffer,c,36064,3553),n(c.texture,v)&&p(3553,c.texture,c.width,c.height),a.bindTexture(3553,null));if(c.depthBuffer){g=b.get(c);k=!0===c.isWebGLRenderTargetCube;if(c.depthTexture){if(k)throw Error("target.depthTexture not supported in Cube render targets");if(c&&c.isWebGLRenderTargetCube)throw Error("Depth Texture with cube render targets is not supported");e.bindFramebuffer(36160, +g.__webglFramebuffer);if(!c.depthTexture||!c.depthTexture.isDepthTexture)throw Error("renderTarget.depthTexture must be an instance of THREE.DepthTexture");b.get(c.depthTexture).__webglTexture&&c.depthTexture.image.width===c.width&&c.depthTexture.image.height===c.height||(c.depthTexture.image.width=c.width,c.depthTexture.image.height=c.height,c.depthTexture.needsUpdate=!0);q(c.depthTexture,0);g=b.get(c.depthTexture).__webglTexture;if(1026===c.depthTexture.format)e.framebufferTexture2D(36160,36096, +3553,g,0);else if(1027===c.depthTexture.format)e.framebufferTexture2D(36160,33306,3553,g,0);else throw Error("Unknown depthTexture format");}else if(k)for(g.__webglDepthbuffer=[],k=0;6>k;k++)e.bindFramebuffer(36160,g.__webglFramebuffer[k]),g.__webglDepthbuffer[k]=e.createRenderbuffer(),W(g.__webglDepthbuffer[k],c);else e.bindFramebuffer(36160,g.__webglFramebuffer),g.__webglDepthbuffer=e.createRenderbuffer(),W(g.__webglDepthbuffer,c);e.bindFramebuffer(36160,null)}};this.updateRenderTargetMipmap=function(c){var d= +c.texture,e=m(c)||oa;if(n(d,e)){e=c.isWebGLRenderTargetCube?34067:3553;var f=b.get(d).__webglTexture;a.bindTexture(e,f);p(e,d,c.width,c.height);a.bindTexture(e,null)}};this.updateMultisampleRenderTarget=function(a){if(a.isWebGLMultisampleRenderTarget)if(oa){var c=b.get(a);e.bindFramebuffer(36008,c.__webglMultisampledFramebuffer);e.bindFramebuffer(36009,c.__webglFramebuffer);c=a.width;var d=a.height,f=16384;a.depthBuffer&&(f|=256);a.stencilBuffer&&(f|=1024);e.blitFramebuffer(0,0,c,d,0,0,c,d,f,9728)}else console.warn("THREE.WebGLRenderer: WebGLMultisampleRenderTarget can only be used with WebGL2.")}; +this.safeSetTexture2D=function(a,b){a&&a.isWebGLRenderTarget&&(!1===O&&(console.warn("THREE.WebGLTextures.safeSetTexture2D: don't use render targets as textures. Use their .texture property instead."),O=!0),a=a.texture);q(a,b)};this.safeSetTextureCube=function(a,b){a&&a.isWebGLRenderTargetCube&&(!1===I&&(console.warn("THREE.WebGLTextures.safeSetTextureCube: don't use cube render targets as textures. Use their .texture property instead."),I=!0),a=a.texture);a&&a.isCubeTexture||Array.isArray(a.image)&& +6===a.image.length?w(a,b):x(a,b)}}function wi(e,h,a){var b=a.isWebGL2;return{convert:function(a){if(1009===a)return 5121;if(1017===a)return 32819;if(1018===a)return 32820;if(1019===a)return 33635;if(1010===a)return 5120;if(1011===a)return 5122;if(1012===a)return 5123;if(1013===a)return 5124;if(1014===a)return 5125;if(1015===a)return 5126;if(1016===a){if(b)return 5131;var c=h.get("OES_texture_half_float");return null!==c?c.HALF_FLOAT_OES:null}if(1021===a)return 6406;if(1022===a)return 6407;if(1023=== +a)return 6408;if(1024===a)return 6409;if(1025===a)return 6410;if(1026===a)return 6402;if(1027===a)return 34041;if(1028===a)return 6403;if(33776===a||33777===a||33778===a||33779===a)if(c=h.get("WEBGL_compressed_texture_s3tc"),null!==c){if(33776===a)return c.COMPRESSED_RGB_S3TC_DXT1_EXT;if(33777===a)return c.COMPRESSED_RGBA_S3TC_DXT1_EXT;if(33778===a)return c.COMPRESSED_RGBA_S3TC_DXT3_EXT;if(33779===a)return c.COMPRESSED_RGBA_S3TC_DXT5_EXT}else return null;if(35840===a||35841===a||35842===a||35843=== +a)if(c=h.get("WEBGL_compressed_texture_pvrtc"),null!==c){if(35840===a)return c.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;if(35841===a)return c.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;if(35842===a)return c.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;if(35843===a)return c.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG}else return null;if(36196===a)return c=h.get("WEBGL_compressed_texture_etc1"),null!==c?c.COMPRESSED_RGB_ETC1_WEBGL:null;if(37808===a||37809===a||37810===a||37811===a||37812===a||37813===a||37814===a||37815===a||37816===a||37817=== +a||37818===a||37819===a||37820===a||37821===a)return c=h.get("WEBGL_compressed_texture_astc"),null!==c?a:null;if(1020===a){if(b)return 34042;c=h.get("WEBGL_depth_texture");return null!==c?c.UNSIGNED_INT_24_8_WEBGL:null}}}}function Fg(e,h,a,b){sa.call(this,e,h,b);this.stencilBuffer=this.depthBuffer=!1;this.numViews=a}function hl(e,h){function a(a){if(a.isArrayCamera)return a.cameras;n[0]=a;return n}function b(a){if(void 0===a.isArrayCamera)return!0;a=a.cameras;if(a.length>l)return!1;for(var b=1,c= +a.length;be.matrixWorld.determinant();ba.setMaterial(d,g);var k=y(a,b,d,e),m=!1;if(h!==c.id||bf!==k.id||T!==(!0===d.wireframe))h=c.id,bf=k.id,T=!0===d.wireframe,m=!0;e.morphTargetInfluences&&(xa.update(e,c,d,k), +m=!0);g=c.index;var n=c.attributes.position;b=1;!0===d.wireframe&&(g=va.getWireframeAttribute(c),b=2);a=ya;if(null!==g){var p=ka.get(g);a=Aa;a.setIndex(p)}if(m){if(!1!==Ea.isWebGL2||!e.isInstancedMesh&&!c.isInstancedBufferGeometry||null!==ta.get("ANGLE_instanced_arrays")){ba.initAttributes();m=c.attributes;k=k.getAttributes();var l=d.defaultAttributeValues;for(A in k){var r=k[A];if(0<=r){var t=m[A];if(void 0!==t){var u=t.normalized,q=t.itemSize,v=ka.get(t);if(void 0!==v){var x=v.buffer,w=v.type;v= +v.bytesPerElement;if(t.isInterleavedBufferAttribute){var B=t.data,C=B.stride;t=t.offset;B&&B.isInstancedInterleavedBuffer?(ba.enableAttributeAndDivisor(r,B.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount=B.meshPerAttribute*B.count)):ba.enableAttribute(r);J.bindBuffer(34962,x);J.vertexAttribPointer(r,q,w,u,C*v,t*v)}else t.isInstancedBufferAttribute?(ba.enableAttributeAndDivisor(r,t.meshPerAttribute),void 0===c.maxInstancedCount&&(c.maxInstancedCount=t.meshPerAttribute*t.count)): +ba.enableAttribute(r),J.bindBuffer(34962,x),J.vertexAttribPointer(r,q,w,u,0,0)}}else if("instanceMatrix"===A)v=ka.get(e.instanceMatrix),void 0!==v&&(x=v.buffer,w=v.type,ba.enableAttributeAndDivisor(r+0,1),ba.enableAttributeAndDivisor(r+1,1),ba.enableAttributeAndDivisor(r+2,1),ba.enableAttributeAndDivisor(r+3,1),J.bindBuffer(34962,x),J.vertexAttribPointer(r+0,4,w,!1,64,0),J.vertexAttribPointer(r+1,4,w,!1,64,16),J.vertexAttribPointer(r+2,4,w,!1,64,32),J.vertexAttribPointer(r+3,4,w,!1,64,48));else if(void 0!== +l&&(u=l[A],void 0!==u))switch(u.length){case 2:J.vertexAttrib2fv(r,u);break;case 3:J.vertexAttrib3fv(r,u);break;case 4:J.vertexAttrib4fv(r,u);break;default:J.vertexAttrib1fv(r,u)}}}ba.disableUnusedAttributes()}null!==g&&J.bindBuffer(34963,p.buffer)}p=Infinity;null!==g?p=g.count:void 0!==n&&(p=n.count);g=c.drawRange.start*b;n=null!==f?f.start*b:0;var A=Math.max(g,n);f=Math.max(0,Math.min(p,g+c.drawRange.count*b,n+(null!==f?f.count*b:Infinity))-1-A+1);if(0!==f){if(e.isMesh)if(!0===d.wireframe)ba.setLineWidth(d.wireframeLinewidth* +(null===Q?ha:1)),a.setMode(1);else switch(e.drawMode){case 0:a.setMode(4);break;case 1:a.setMode(5);break;case 2:a.setMode(6)}else e.isLine?(d=d.linewidth,void 0===d&&(d=1),ba.setLineWidth(d*(null===Q?ha:1)),e.isLineSegments?a.setMode(1):e.isLineLoop?a.setMode(2):a.setMode(3)):e.isPoints?a.setMode(0):e.isSprite&&a.setMode(4);e.isInstancedMesh?a.renderInstances(c,A,f,e.count):c.isInstancedBufferGeometry?a.renderInstances(c,A,f,c.maxInstancedCount):a.render(A,f)}};this.compile=function(a,b){E=ua.get(a, +b);E.init();a.traverse(function(a){a.isLight&&(E.pushLight(a),a.castShadow&&E.pushShadow(a))});E.setupLights(b);a.traverse(function(b){if(b.material)if(Array.isArray(b.material))for(var c=0;cc.far||d.push({distance:e,distanceToRay:Math.sqrt(g),point:a,index:h,face:null,object:f}))}function Lg(e,h,a,b,c,d,f,g,k){S.call(this,e,h,a,b,c,d,f,g,k);this.format=void 0!==f?f:1022;this.minFilter=void 0!==d?d:1006;this.magFilter=void 0!==c?c:1006;this.generateMipmaps=!1}function Zc(e,h,a,b,c,d,f,g,k,m,n,p){S.call(this,null,d,f,g,k,m,b,c,n,p);this.image= +{width:h,height:a};this.mipmaps=e;this.generateMipmaps=this.flipY=!1}function de(e,h,a,b,c,d,f,g,k){S.call(this,e,h,a,b,c,d,f,g,k);this.needsUpdate=!0}function ee(e,h,a,b,c,d,f,g,k,m){m=void 0!==m?m:1026;if(1026!==m&&1027!==m)throw Error("DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat");void 0===a&&1026===m&&(a=1012);void 0===a&&1027===m&&(a=1020);S.call(this,null,b,c,d,f,g,m,a,k);this.image={width:e,height:h};this.magFilter=void 0!==f?f:1003;this.minFilter=void 0!== +g?g:1003;this.generateMipmaps=this.flipY=!1}function $c(e){G.call(this);this.type="WireframeGeometry";var h=[],a,b,c,d=[0,0],f={},g=["a","b","c"];if(e&&e.isGeometry){var k=e.faces;var m=0;for(b=k.length;ma;a++){var p=n[g[a]];var l=n[g[(a+1)%3]];d[0]=Math.min(p,l);d[1]=Math.max(p,l);p=d[0]+","+d[1];void 0===f[p]&&(f[p]={index1:d[0],index2:d[1]})}}for(p in f)m=f[p],g=e.vertices[m.index1],h.push(g.x,g.y,g.z),g=e.vertices[m.index2],h.push(g.x,g.y,g.z)}else if(e&&e.isBufferGeometry)if(g= +new q,null!==e.index){k=e.attributes.position;n=e.index;var t=e.groups;0===t.length&&(t=[{start:0,count:n.count,materialIndex:0}]);e=0;for(c=t.length;ea;a++)p=n.getX(m+a),l=n.getX(m+(a+1)%3),d[0]=Math.min(p,l),d[1]=Math.max(p,l),p=d[0]+","+d[1],void 0===f[p]&&(f[p]={index1:d[0],index2:d[1]});for(p in f)m=f[p],g.fromBufferAttribute(k,m.index1),h.push(g.x,g.y,g.z),g.fromBufferAttribute(k,m.index2),h.push(g.x,g.y,g.z)}else for(k=e.attributes.position, +m=0,b=k.count/3;ma;a++)f=3*m+a,g.fromBufferAttribute(k,f),h.push(g.x,g.y,g.z),f=3*m+(a+1)%3,g.fromBufferAttribute(k,f),h.push(g.x,g.y,g.z);this.setAttribute("position",new F(h,3))}function fe(e,h,a){P.call(this);this.type="ParametricGeometry";this.parameters={func:e,slices:h,stacks:a};this.fromBufferGeometry(new ad(e,h,a));this.mergeVertices()}function ad(e,h,a){G.call(this);this.type="ParametricBufferGeometry";this.parameters={func:e,slices:h,stacks:a};var b=[],c=[],d=[],f=[],g= +new q,k=new q,m=new q,n=new q,p=new q,l,t;3>e.length&&console.error("THREE.ParametricGeometry: Function must now modify a Vector3 as third parameter.");var r=h+1;for(l=0;l<=a;l++){var u=l/a;for(t=0;t<=h;t++){var v=t/h;e(v,u,k);c.push(k.x,k.y,k.z);0<=v-1E-5?(e(v-1E-5,u,m),n.subVectors(k,m)):(e(v+1E-5,u,m),n.subVectors(m,k));0<=u-1E-5?(e(v,u-1E-5,m),p.subVectors(k,m)):(e(v,u+1E-5,m),p.subVectors(m,k));g.crossVectors(n,p).normalize();d.push(g.x,g.y,g.z);f.push(v,u)}}for(l=0;ld&&1===a.x&&(k[b]=a.x-1);0===c.x&&0===c.z&&(k[b]=d/2/Math.PI+.5)}G.call(this);this.type="PolyhedronBufferGeometry";this.parameters={vertices:e,indices:h,radius:a,detail:b};a=a||1;b=b||0;var g=[],k=[];(function(a){for(var b=new q,e=new q,f=new q,g=0;ge&&(.2>b&&(k[a+0]+=1),.2>c&&(k[a+2]+=1),.2>d&&(k[a+4]+=1))})();this.setAttribute("position", +new F(g,3));this.setAttribute("normal",new F(g.slice(),3));this.setAttribute("uv",new F(k,2));0===b?this.computeVertexNormals():this.normalizeNormals()}function he(e,h){P.call(this);this.type="TetrahedronGeometry";this.parameters={radius:e,detail:h};this.fromBufferGeometry(new bd(e,h));this.mergeVertices()}function bd(e,h){Fa.call(this,[1,1,1,-1,-1,1,-1,1,-1,1,-1,-1],[2,1,0,0,3,2,1,3,0,2,3,1],e,h);this.type="TetrahedronBufferGeometry";this.parameters={radius:e,detail:h}}function ie(e,h){P.call(this); +this.type="OctahedronGeometry";this.parameters={radius:e,detail:h};this.fromBufferGeometry(new lc(e,h));this.mergeVertices()}function lc(e,h){Fa.call(this,[1,0,0,-1,0,0,0,1,0,0,-1,0,0,0,1,0,0,-1],[0,2,4,0,4,3,0,3,5,0,5,2,1,2,5,1,5,3,1,3,4,1,4,2],e,h);this.type="OctahedronBufferGeometry";this.parameters={radius:e,detail:h}}function je(e,h){P.call(this);this.type="IcosahedronGeometry";this.parameters={radius:e,detail:h};this.fromBufferGeometry(new cd(e,h));this.mergeVertices()}function cd(e,h){var a= +(1+Math.sqrt(5))/2;Fa.call(this,[-1,a,0,1,a,0,-1,-a,0,1,-a,0,0,-1,a,0,1,a,0,-1,-a,0,1,-a,a,0,-1,a,0,1,-a,0,-1,-a,0,1],[0,11,5,0,5,1,0,1,7,0,7,10,0,10,11,1,5,9,5,11,4,11,10,2,10,7,6,7,1,8,3,9,4,3,4,2,3,2,6,3,6,8,3,8,9,4,9,5,2,4,11,6,2,10,8,6,7,9,8,1],e,h);this.type="IcosahedronBufferGeometry";this.parameters={radius:e,detail:h}}function ke(e,h){P.call(this);this.type="DodecahedronGeometry";this.parameters={radius:e,detail:h};this.fromBufferGeometry(new dd(e,h));this.mergeVertices()}function dd(e,h){var a= +(1+Math.sqrt(5))/2,b=1/a;Fa.call(this,[-1,-1,-1,-1,-1,1,-1,1,-1,-1,1,1,1,-1,-1,1,-1,1,1,1,-1,1,1,1,0,-b,-a,0,-b,a,0,b,-a,0,b,a,-b,-a,0,-b,a,0,b,-a,0,b,a,0,-a,0,-b,a,0,-b,-a,0,b,a,0,b],[3,11,7,3,7,15,3,15,13,7,19,17,7,17,6,7,6,15,17,4,8,17,8,10,17,10,6,8,0,16,8,16,2,8,2,10,0,12,1,0,1,18,0,18,16,6,10,2,6,2,13,6,13,15,2,16,18,2,18,3,2,3,13,18,1,9,18,9,11,18,11,3,4,14,12,4,12,0,4,0,8,11,9,5,11,5,19,11,19,7,19,5,14,19,14,4,19,4,17,1,12,14,1,14,5,1,5,9],e,h);this.type="DodecahedronBufferGeometry";this.parameters= +{radius:e,detail:h}}function le(e,h,a,b,c,d){P.call(this);this.type="TubeGeometry";this.parameters={path:e,tubularSegments:h,radius:a,radialSegments:b,closed:c};void 0!==d&&console.warn("THREE.TubeGeometry: taper has been removed.");e=new mc(e,h,a,b,c);this.tangents=e.tangents;this.normals=e.normals;this.binormals=e.binormals;this.fromBufferGeometry(e);this.mergeVertices()}function mc(e,h,a,b,c){function d(c){n=e.getPointAt(c/h,n);var d=f.normals[c];c=f.binormals[c];for(l=0;l<=b;l++){var m=l/b*Math.PI* +2,p=Math.sin(m);m=-Math.cos(m);k.x=m*d.x+p*c.x;k.y=m*d.y+p*c.y;k.z=m*d.z+p*c.z;k.normalize();r.push(k.x,k.y,k.z);g.x=n.x+a*k.x;g.y=n.y+a*k.y;g.z=n.z+a*k.z;t.push(g.x,g.y,g.z)}}G.call(this);this.type="TubeBufferGeometry";this.parameters={path:e,tubularSegments:h,radius:a,radialSegments:b,closed:c};h=h||64;a=a||1;b=b||8;c=c||!1;var f=e.computeFrenetFrames(h,c);this.tangents=f.tangents;this.normals=f.normals;this.binormals=f.binormals;var g=new q,k=new q,m=new z,n=new q,p,l,t=[],r=[],u=[],v=[];for(p= +0;p=h;c-=b)d=Ei(c,e[c],e[c+1],d);d&&nc(d,d.next)&&(oe(d),d=d.next);return d}function pe(e,h){if(!e)return e; +h||(h=e);do{var a=!1;if(e.steiner||!nc(e,e.next)&&0!==wa(e.prev,e,e.next))e=e.next;else{oe(e);e=h=e.prev;if(e===e.next)break;a=!0}}while(a||e!==h);return h}function qe(e,h,a,b,c,d,f){if(e){if(!f&&d){var g=e,k=g;do null===k.z&&(k.z=Mg(k.x,k.y,b,c,d)),k.prevZ=k.prev,k=k.nextZ=k.next;while(k!==g);k.prevZ.nextZ=null;k.prevZ=null;g=k;var m,n,p,l,t=1;do{k=g;var r=g=null;for(n=0;k;){n++;var u=k;for(m=p=0;mu!==r.next.y>u&&r.next.y!==r.y&&p<(r.next.x- +r.x)*(u-r.y)/(r.next.y-r.y)+r.x&&(n=!n),r=r.next;while(r!==k);r=n}k=r}if(k){e=Gi(f,g);f=pe(f,f.next);e=pe(e,e.next);qe(f,h,a,b,c,d);qe(e,h,a,b,c,d);break a}g=g.next}f=f.next}while(f!==e)}break}}}}function il(e,h,a,b){var c=e.prev,d=e.next;if(0<=wa(c,e,d))return!1;var f=c.x>e.x?c.x>d.x?c.x:d.x:e.x>d.x?e.x:d.x,g=c.y>e.y?c.y>d.y?c.y:d.y:e.y>d.y?e.y:d.y,k=Mg(c.x=k&&b&&b.z<= +h;){if(a!==e.prev&&a!==e.next&&gd(c.x,c.y,e.x,e.y,d.x,d.y,a.x,a.y)&&0<=wa(a.prev,a,a.next))return!1;a=a.prevZ;if(b!==e.prev&&b!==e.next&&gd(c.x,c.y,e.x,e.y,d.x,d.y,b.x,b.y)&&0<=wa(b.prev,b,b.next))return!1;b=b.nextZ}for(;a&&a.z>=k;){if(a!==e.prev&&a!==e.next&&gd(c.x,c.y,e.x,e.y,d.x,d.y,a.x,a.y)&&0<=wa(a.prev,a,a.next))return!1;a=a.prevZ}for(;b&&b.z<=h;){if(b!==e.prev&&b!==e.next&&gd(c.x,c.y,e.x,e.y,d.x,d.y,b.x,b.y)&&0<=wa(b.prev,b,b.next))return!1;b=b.nextZ}return!0}function jl(e,h){return e.x-h.x} +function kl(e,h){var a=h,b=e.x,c=e.y,d=-Infinity;do{if(c<=a.y&&c>=a.next.y&&a.next.y!==a.y){var f=a.x+(c-a.y)*(a.next.x-a.x)/(a.next.y-a.y);if(f<=b&&f>d){d=f;if(f===b){if(c===a.y)return a;if(c===a.next.y)return a.next}var g=a.x=a.x&&a.x>=f&&b!==a.x&&gd(cg.x)&&re(a,e)&&(g=a,m=n)}a= +a.next}return g}function Mg(e,h,a,b,c){e=32767*(e-a)*c;h=32767*(h-b)*c;e=(e|e<<8)&16711935;e=(e|e<<4)&252645135;e=(e|e<<2)&858993459;h=(h|h<<8)&16711935;h=(h|h<<4)&252645135;h=(h|h<<2)&858993459;return(e|e<<1)&1431655765|((h|h<<1)&1431655765)<<1}function ll(e){var h=e,a=e;do{if(h.xwa(e.prev,e,e.next)?0<=wa(e,h,e.next)&&0<=wa(e,e.prev,h):0>wa(e,h,e.prev)||0>wa(e,e.next,h)}function Gi(e,h){var a=new Ng(e.i,e.x,e.y),b=new Ng(h.i,h.x,h.y),c=e.next,d=h.prev;e.next=h;h.prev=e;a.next=c;c.prev=a;b.next=a;a.prev=b;d.next=b;b.prev=d;return b}function Ei(e,h,a,b){e=new Ng(e, +h,a);b?(e.next=b.next,e.prev=b,b.next.prev=e,b.next=e):(e.prev=e,e.next=e);return e}function oe(e){e.next.prev=e.prev;e.prev.next=e.next;e.prevZ&&(e.prevZ.nextZ=e.nextZ);e.nextZ&&(e.nextZ.prevZ=e.prevZ)}function Ng(e,h,a){this.i=e;this.x=h;this.y=a;this.nextZ=this.prevZ=this.z=this.next=this.prev=null;this.steiner=!1}function Hi(e){var h=e.length;2Number.EPSILON){var k=Math.sqrt(h),m=Math.sqrt(f*f+g*g);h=b.x-e/k;b=b.y+d/k;g=((c.x-g/m-h)*g-(c.y+f/m-b)*f)/(d*g-e*f);f=h+d*g-a.x;d=b+e*g-a.y;e=f*f+ +d*d;if(2>=e)return new z(f,d);e=Math.sqrt(e/2)}else a=!1,d>Number.EPSILON?f>Number.EPSILON&&(a=!0):d<-Number.EPSILON?f<-Number.EPSILON&&(a=!0):Math.sign(e)===Math.sign(g)&&(a=!0),a?(f=-e,e=Math.sqrt(h)):(f=d,d=e,e=Math.sqrt(h/2));return new z(f/e,d/e)}function g(a,d){for(L=a.length;0<=--L;){var e=L;var f=L-1;0>f&&(f=a.length-1);var g,h=x+2*D;for(g=0;gn;n++){var p=m[d[n]];var l=m[d[(n+1)%3]];b[0]=Math.min(p,l);b[1]=Math.max(p,l);p=b[0]+","+b[1];void 0===c[p]?c[p]={index1:b[0],index2:b[1],face1:g,face2:void 0}:c[p].face2=g}for(p in c)if(b=c[p],void 0===b.face2||f[b.face1].normal.dot(f[b.face2].normal)<=h)d=e[b.index1], +a.push(d.x,d.y,d.z),d=e[b.index2],a.push(d.x,d.y,d.z);this.setAttribute("position",new F(a,3))}function rc(e,h,a,b,c,d,f,g){P.call(this);this.type="CylinderGeometry";this.parameters={radiusTop:e,radiusBottom:h,height:a,radialSegments:b,heightSegments:c,openEnded:d,thetaStart:f,thetaLength:g};this.fromBufferGeometry(new yb(e,h,a,b,c,d,f,g));this.mergeVertices()}function yb(e,h,a,b,c,d,f,g){function k(a){var c,d=new z,k=new q,y=0,u=!0===a?e:h,x=!0===a?1:-1;var D=r;for(c=1;c<=b;c++)p.push(0,v*x,0),l.push(0, +x,0),t.push(.5,.5),r++;var E=r;for(c=0;c<=b;c++){var F=c/b*g+f,G=Math.cos(F);F=Math.sin(F);k.x=u*F;k.y=v*x;k.z=u*G;p.push(k.x,k.y,k.z);l.push(0,x,0);d.x=.5*G+.5;d.y=.5*F*x+.5;t.push(d.x,d.y);r++}for(c=0;cthis.duration&&this.resetDuration()}function nl(e){switch(e.toLowerCase()){case "scalar":case "double":case "float":case "number":case "integer":return nd; +case "vector":case "vector2":case "vector3":case "vector4":return od;case "color":return mf;case "quaternion":return Ae;case "bool":case "boolean":return lf;case "string":return of}throw Error("THREE.KeyframeTrack: Unsupported typeName: "+e);}function ol(e){if(void 0===e.type)throw Error("THREE.KeyframeTrack: track type undefined, can not parse");var h=nl(e.type);if(void 0===e.times){var a=[],b=[];aa.flattenJSON(e.keys,a,b,"value");e.times=a;e.values=b}return void 0!==h.parse?h.parse(e):new h(e.name, +e.times,e.values,e.interpolation)}function Og(e,h,a){var b=this,c=!1,d=0,f=0,g=void 0,k=[];this.onStart=void 0;this.onLoad=e;this.onProgress=h;this.onError=a;this.itemStart=function(a){f++;if(!1===c&&void 0!==b.onStart)b.onStart(a,d,f);c=!0};this.itemEnd=function(a){d++;if(void 0!==b.onProgress)b.onProgress(a,d,f);if(d===f&&(c=!1,void 0!==b.onLoad))b.onLoad()};this.itemError=function(a){if(void 0!==b.onError)b.onError(a)};this.resolveURL=function(a){return g?g(a):a};this.setURLModifier=function(a){g= +a;return this};this.addHandler=function(a,b){k.push(a,b);return this};this.removeHandler=function(a){a=k.indexOf(a);-1!==a&&k.splice(a,2);return this};this.getHandler=function(a){for(var b=0,c=k.length;be;e++)this.coefficients.push(new q)}function bb(e,h){da.call(this,void 0,h);this.sh=void 0!==e?e:new Gf}function Xg(e,h,a){bb.call(this, +void 0,a);e=(new D).set(e);a=(new D).set(h);h=new q(e.r,e.g,e.b);e=new q(a.r,a.g,a.b);a=Math.sqrt(Math.PI);var b=a*Math.sqrt(.75);this.sh.coefficients[0].copy(h).add(e).multiplyScalar(a);this.sh.coefficients[1].copy(h).sub(e).multiplyScalar(b)}function Yg(e,h){bb.call(this,void 0,h);e=(new D).set(e);this.sh.coefficients[0].set(e.r,e.g,e.b).multiplyScalar(2*Math.sqrt(Math.PI))}function Ni(){this.type="StereoCamera";this.aspect=1;this.eyeSep=.064;this.cameraL=new na;this.cameraL.layers.enable(1);this.cameraL.matrixAutoUpdate= +!1;this.cameraR=new na;this.cameraR.layers.enable(2);this.cameraR.matrixAutoUpdate=!1;this._cache={focus:null,fov:null,aspect:null,near:null,far:null,zoom:null,eyeSep:null}}function Zg(e){this.autoStart=void 0!==e?e:!0;this.elapsedTime=this.oldTime=this.startTime=0;this.running=!1}function $g(){E.call(this);this.type="AudioListener";this.context=ah.getContext();this.gain=this.context.createGain();this.gain.connect(this.context.destination);this.filter=null;this.timeDelta=0;this._clock=new Zg}function rd(e){E.call(this); +this.type="Audio";this.listener=e;this.context=e.context;this.gain=this.context.createGain();this.gain.connect(e.getInput());this.autoplay=!1;this.buffer=null;this.detune=0;this.loop=!1;this.offset=this.loopEnd=this.loopStart=0;this.duration=void 0;this.playbackRate=1;this.isPlaying=!1;this.hasPlaybackControl=!0;this.sourceType="empty";this._pausedAt=this._startedAt=0;this.filters=[]}function bh(e){rd.call(this,e);this.panner=this.context.createPanner();this.panner.panningModel="HRTF";this.panner.connect(this.gain)} +function ch(e,h){this.analyser=e.context.createAnalyser();this.analyser.fftSize=void 0!==h?h:2048;this.data=new Uint8Array(this.analyser.frequencyBinCount);e.getOutput().connect(this.analyser)}function dh(e,h,a){this.binding=e;this.valueSize=a;e=Float64Array;switch(h){case "quaternion":h=this._slerp;break;case "string":case "bool":e=Array;h=this._select;break;default:h=this._lerp}this.buffer=new e(4*a);this._mixBufferRegion=h;this.referenceCount=this.useCount=this.cumulativeWeight=0}function Oi(e, +h,a){a=a||ja.parseTrackName(h);this._targetGroup=e;this._bindings=e.subscribe_(h,a)}function ja(e,h,a){this.path=h;this.parsedPath=a||ja.parseTrackName(h);this.node=ja.findNode(e,this.parsedPath.nodeName)||e;this.rootNode=e}function Pi(){this.uuid=N.generateUUID();this._objects=Array.prototype.slice.call(arguments);this.nCachedObjects_=0;var e={};this._indicesByUUID=e;for(var h=0,a=arguments.length;h!==a;++h)e[arguments[h].uuid]=h;this._paths=[];this._parsedPaths=[];this._bindings=[];this._bindingsIndicesByPath= +{};var b=this;this.stats={objects:{get total(){return b._objects.length},get inUse(){return this.total-b.nCachedObjects_}},get bindingsPerObject(){return b._bindings.length}}}function Qi(e,h,a){this._mixer=e;this._clip=h;this._localRoot=a||null;e=h.tracks;h=e.length;a=Array(h);for(var b={endingStart:2400,endingEnd:2400},c=0;c!==h;++c){var d=e[c].createInterpolant(null);a[c]=d;d.settings=b}this._interpolantSettings=b;this._interpolants=a;this._propertyBindings=Array(h);this._weightInterpolant=this._timeScaleInterpolant= +this._byClipCacheIndex=this._cacheIndex=null;this.loop=2201;this._loopCount=-1;this._startTime=null;this.time=0;this._effectiveWeight=this.weight=this._effectiveTimeScale=this.timeScale=1;this.repetitions=Infinity;this.paused=!1;this.enabled=!0;this.clampWhenFinished=!1;this.zeroSlopeAtEnd=this.zeroSlopeAtStart=!0}function eh(e){this._root=e;this._initMemoryManager();this.time=this._accuIndex=0;this.timeScale=1}function Hf(e,h){"string"===typeof e&&(console.warn("THREE.Uniform: Type parameter is no longer needed."), +e=h);this.value=e}function fh(e,h,a){wb.call(this,e,h);this.meshPerAttribute=a||1}function Ri(e,h,a,b){this.ray=new ac(e,h);this.near=a||0;this.far=b||Infinity;this.camera=null;this.params={Mesh:{},Line:{},LOD:{},Points:{threshold:1},Sprite:{}};Object.defineProperties(this.params,{PointCloud:{get:function(){console.warn("THREE.Raycaster: params.PointCloud has been renamed to params.Points.");return this.Points}}})}function Si(e,h){return e.distance-h.distance}function gh(e,h,a,b){if(!1!==e.visible&& +(e.raycast(h,a),!0===b)){e=e.children;b=0;for(var c=e.length;ba;a++,b++){var c=a/32*Math.PI*2,d=b/32*Math.PI*2;h.push(Math.cos(c),Math.sin(c),1,Math.cos(d),Math.sin(d),1)}e.setAttribute("position",new F(h,3));h=new T({fog:!1});this.cone=new Z(e,h);this.add(this.cone);this.update()}function Vi(e){var h=[];e&&e.isBone&&h.push(e);for(var a=0;aa?-1:0Ne;Ne++)xa[Ne]=(16>Ne?"0":"")+Ne.toString(16);var N={DEG2RAD:Math.PI/180,RAD2DEG:180/Math.PI,generateUUID:function(){var a=4294967295*Math.random()|0,b=4294967295*Math.random()|0,c=4294967295*Math.random()| +0,d=4294967295*Math.random()|0;return(xa[a&255]+xa[a>>8&255]+xa[a>>16&255]+xa[a>>24&255]+"-"+xa[b&255]+xa[b>>8&255]+"-"+xa[b>>16&15|64]+xa[b>>24&255]+"-"+xa[c&63|128]+xa[c>>8&255]+"-"+xa[c>>16&255]+xa[c>>24&255]+xa[d&255]+xa[d>>8&255]+xa[d>>16&255]+xa[d>>24&255]).toUpperCase()},clamp:function(a,b,c){return Math.max(b,Math.min(c,a))},euclideanModulo:function(a,b){return(a%b+b)%b},mapLinear:function(a,b,c,d,f){return d+(a-b)*(f-d)/(c-b)},lerp:function(a,b,c){return(1-c)*a+c*b},smoothstep:function(a, +b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*(3-2*a)},smootherstep:function(a,b,c){if(a<=b)return 0;if(a>=c)return 1;a=(a-b)/(c-b);return a*a*a*(a*(6*a-15)+10)},randInt:function(a,b){return a+Math.floor(Math.random()*(b-a+1))},randFloat:function(a,b){return a+Math.random()*(b-a)},randFloatSpread:function(a){return a*(.5-Math.random())},degToRad:function(a){return a*N.DEG2RAD},radToDeg:function(a){return a*N.RAD2DEG},isPowerOfTwo:function(a){return 0===(a&a-1)&&0!==a},ceilPowerOfTwo:function(a){return Math.pow(2, +Math.ceil(Math.log(a)/Math.LN2))},floorPowerOfTwo:function(a){return Math.pow(2,Math.floor(Math.log(a)/Math.LN2))}};Object.defineProperties(z.prototype,{width:{get:function(){return this.x},set:function(a){this.x=a}},height:{get:function(){return this.y},set:function(a){this.y=a}}});Object.assign(z.prototype,{isVector2:!0,set:function(a,b){this.x=a;this.y=b;return this},setScalar:function(a){this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this}, +setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y)},copy:function(a){this.x=a.x;this.y=a.y;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead."), +this.addVectors(a,b);this.x+=a.x;this.y+=a.y;return this},addScalar:function(a){this.x+=a;this.y+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;return this},subScalar:function(a){this.x-=a;this.y-=a;return this}, +subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;return this},multiply:function(a){this.x*=a.x;this.y*=a.y;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;return this},divide:function(a){this.x/=a.x;this.y/=a.y;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},applyMatrix3:function(a){var b=this.x,c=this.y;a=a.elements;this.x=a[0]*b+a[3]*c+a[6];this.y=a[1]*b+a[4]*c+a[7];return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);return this}, +max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b,this.y));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y); +return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);return this},negate:function(){this.x=-this.x;this.y=-this.y;return this},dot:function(a){return this.x*a.x+this.y*a.y},cross:function(a){return this.x*a.y-this.y*a.x},lengthSq:function(){return this.x* +this.x+this.y*this.y},length:function(){return Math.sqrt(this.x*this.x+this.y*this.y)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)},normalize:function(){return this.divideScalar(this.length()||1)},angle:function(){var a=Math.atan2(this.y,this.x);0>a&&(a+=2*Math.PI);return a},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))},distanceToSquared:function(a){var b=this.x-a.x;a=this.y-a.y;return b*b+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+ +Math.abs(this.y-a.y)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;return a},fromBufferAttribute:function(a, +b,c){void 0!==c&&console.warn("THREE.Vector2: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);return this},rotateAround:function(a,b){var c=Math.cos(b);b=Math.sin(b);var d=this.x-a.x,f=this.y-a.y;this.x=d*c-f*b+a.x;this.y=d*b+f*c+a.y;return this}});Object.assign(ya,{slerp:function(a,b,c,d){return c.copy(a).slerp(b,d)},slerpFlat:function(a,b,c,d,f,g,k){var m=c[d+0],n=c[d+1],p=c[d+2];c=c[d+3];d=f[g+0];var l=f[g+1],t=f[g+2];f=f[g+3];if(c!==f||m!==d||n!==l||p!== +t){g=1-k;var r=m*d+n*l+p*t+c*f,u=0<=r?1:-1,q=1-r*r;q>Number.EPSILON&&(q=Math.sqrt(q),r=Math.atan2(q,r*u),g=Math.sin(g*r)/q,k=Math.sin(k*r)/q);u*=k;m=m*g+d*u;n=n*g+l*u;p=p*g+t*u;c=c*g+f*u;g===1-k&&(k=1/Math.sqrt(m*m+n*n+p*p+c*c),m*=k,n*=k,p*=k,c*=k)}a[b]=m;a[b+1]=n;a[b+2]=p;a[b+3]=c}});Object.defineProperties(ya.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this._onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this._onChangeCallback()}},z:{get:function(){return this._z}, +set:function(a){this._z=a;this._onChangeCallback()}},w:{get:function(){return this._w},set:function(a){this._w=a;this._onChangeCallback()}}});Object.assign(ya.prototype,{isQuaternion:!0,set:function(a,b,c,d){this._x=a;this._y=b;this._z=c;this._w=d;this._onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._w)},copy:function(a){this._x=a.x;this._y=a.y;this._z=a.z;this._w=a.w;this._onChangeCallback();return this},setFromEuler:function(a,b){if(!a|| +!a.isEuler)throw Error("THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.");var c=a._x,d=a._y,f=a._z;a=a.order;var g=Math.cos,k=Math.sin,m=g(c/2),n=g(d/2);g=g(f/2);c=k(c/2);d=k(d/2);f=k(f/2);"XYZ"===a?(this._x=c*n*g+m*d*f,this._y=m*d*g-c*n*f,this._z=m*n*f+c*d*g,this._w=m*n*g-c*d*f):"YXZ"===a?(this._x=c*n*g+m*d*f,this._y=m*d*g-c*n*f,this._z=m*n*f-c*d*g,this._w=m*n*g+c*d*f):"ZXY"===a?(this._x=c*n*g-m*d*f,this._y=m*d*g+c*n*f,this._z=m*n*f+c*d*g,this._w= +m*n*g-c*d*f):"ZYX"===a?(this._x=c*n*g-m*d*f,this._y=m*d*g+c*n*f,this._z=m*n*f-c*d*g,this._w=m*n*g+c*d*f):"YZX"===a?(this._x=c*n*g+m*d*f,this._y=m*d*g+c*n*f,this._z=m*n*f-c*d*g,this._w=m*n*g-c*d*f):"XZY"===a&&(this._x=c*n*g-m*d*f,this._y=m*d*g-c*n*f,this._z=m*n*f+c*d*g,this._w=m*n*g+c*d*f);!1!==b&&this._onChangeCallback();return this},setFromAxisAngle:function(a,b){b/=2;var c=Math.sin(b);this._x=a.x*c;this._y=a.y*c;this._z=a.z*c;this._w=Math.cos(b);this._onChangeCallback();return this},setFromRotationMatrix:function(a){var b= +a.elements,c=b[0];a=b[4];var d=b[8],f=b[1],g=b[5],k=b[9],m=b[2],n=b[6];b=b[10];var p=c+g+b;0g&&c>b?(c=2*Math.sqrt(1+c-g-b),this._w=(n-k)/c,this._x=.25*c,this._y=(a+f)/c,this._z=(d+m)/c):g>b?(c=2*Math.sqrt(1+g-c-b),this._w=(d-m)/c,this._x=(a+f)/c,this._y=.25*c,this._z=(k+n)/c):(c=2*Math.sqrt(1+b-c-g),this._w=(f-a)/c,this._x=(d+m)/c,this._y=(k+n)/c,this._z=.25*c);this._onChangeCallback();return this},setFromUnitVectors:function(a, +b){var c=a.dot(b)+1;1E-6>c?(c=0,Math.abs(a.x)>Math.abs(a.z)?(this._x=-a.y,this._y=a.x,this._z=0):(this._x=0,this._y=-a.z,this._z=a.y)):(this._x=a.y*b.z-a.z*b.y,this._y=a.z*b.x-a.x*b.z,this._z=a.x*b.y-a.y*b.x);this._w=c;return this.normalize()},angleTo:function(a){return 2*Math.acos(Math.abs(N.clamp(this.dot(a),-1,1)))},rotateTowards:function(a,b){var c=this.angleTo(a);if(0===c)return this;this.slerp(a,Math.min(1,b/c));return this},inverse:function(){return this.conjugate()},conjugate:function(){this._x*= +-1;this._y*=-1;this._z*=-1;this._onChangeCallback();return this},dot:function(a){return this._x*a._x+this._y*a._y+this._z*a._z+this._w*a._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 a=this.length();0===a?(this._z=this._y=this._x=0,this._w=1):(a=1/a,this._x*=a,this._y*=a,this._z*=a,this._w*=a);this._onChangeCallback();return this}, +multiply:function(a,b){return void 0!==b?(console.warn("THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead."),this.multiplyQuaternions(a,b)):this.multiplyQuaternions(this,a)},premultiply:function(a){return this.multiplyQuaternions(a,this)},multiplyQuaternions:function(a,b){var c=a._x,d=a._y,f=a._z;a=a._w;var g=b._x,k=b._y,m=b._z;b=b._w;this._x=c*b+a*g+d*m-f*k;this._y=d*b+a*k+f*g-c*m;this._z=f*b+a*m+c*k-d*g;this._w=a*b-c*g-d*k-f*m;this._onChangeCallback(); +return this},slerp:function(a,b){if(0===b)return this;if(1===b)return this.copy(a);var c=this._x,d=this._y,f=this._z,g=this._w,k=g*a._w+c*a._x+d*a._y+f*a._z;0>k?(this._w=-a._w,this._x=-a._x,this._y=-a._y,this._z=-a._z,k=-k):this.copy(a);if(1<=k)return this._w=g,this._x=c,this._y=d,this._z=f,this;a=1-k*k;if(a<=Number.EPSILON)return k=1-b,this._w=k*g+b*this._w,this._x=k*c+b*this._x,this._y=k*d+b*this._y,this._z=k*f+b*this._z,this.normalize(),this._onChangeCallback(),this;a=Math.sqrt(a);var m=Math.atan2(a, +k);k=Math.sin((1-b)*m)/a;b=Math.sin(b*m)/a;this._w=g*k+this._w*b;this._x=c*k+this._x*b;this._y=d*k+this._y*b;this._z=f*k+this._z*b;this._onChangeCallback();return this},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._w===this._w},fromArray:function(a,b){void 0===b&&(b=0);this._x=a[b];this._y=a[b+1];this._z=a[b+2];this._w=a[b+3];this._onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+ +3]=this._w;return a},_onChange:function(a){this._onChangeCallback=a;return this},_onChangeCallback:function(){}});var rh=new q,gj=new ya;Object.assign(q.prototype,{isVector3:!0,set:function(a,b,c){this.x=a;this.y=b;this.z=c;return this},setScalar:function(a){this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z= +b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x;case 1:return this.y;case 2:return this.z;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a, +b);this.x+=a.x;this.y+=a.y;this.z+=a.z;return this},addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;return this},subScalar:function(a){this.x-= +a;this.y-=a;this.z-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;return this},multiply:function(a,b){if(void 0!==b)return console.warn("THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead."),this.multiplyVectors(a,b);this.x*=a.x;this.y*=a.y;this.z*=a.z;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;return this},multiplyVectors:function(a,b){this.x=a.x*b.x;this.y=a.y*b.y;this.z=a.z*b.z;return this}, +applyEuler:function(a){a&&a.isEuler||console.error("THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.");return this.applyQuaternion(gj.setFromEuler(a))},applyAxisAngle:function(a,b){return this.applyQuaternion(gj.setFromAxisAngle(a,b))},applyMatrix3:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[3]*c+a[6]*d;this.y=a[1]*b+a[4]*c+a[7]*d;this.z=a[2]*b+a[5]*c+a[8]*d;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z; +a=a.elements;var f=1/(a[3]*b+a[7]*c+a[11]*d+a[15]);this.x=(a[0]*b+a[4]*c+a[8]*d+a[12])*f;this.y=(a[1]*b+a[5]*c+a[9]*d+a[13])*f;this.z=(a[2]*b+a[6]*c+a[10]*d+a[14])*f;return this},applyQuaternion:function(a){var b=this.x,c=this.y,d=this.z,f=a.x,g=a.y,k=a.z;a=a.w;var m=a*b+g*d-k*c,n=a*c+k*b-f*d,p=a*d+f*c-g*b;b=-f*b-g*c-k*d;this.x=m*a+b*-f+n*-k-p*-g;this.y=n*a+b*-g+p*-f-m*-k;this.z=p*a+b*-k+m*-g-n*-f;return this},project:function(a){return this.applyMatrix4(a.matrixWorldInverse).applyMatrix4(a.projectionMatrix)}, +unproject:function(a){return this.applyMatrix4(a.projectionMatrixInverse).applyMatrix4(a.matrixWorld)},transformDirection:function(a){var b=this.x,c=this.y,d=this.z;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d;this.y=a[1]*b+a[5]*c+a[9]*d;this.z=a[2]*b+a[6]*c+a[10]*d;return this.normalize()},divide:function(a){this.x/=a.x;this.y/=a.y;this.z/=a.z;return this},divideScalar:function(a){return this.multiplyScalar(1/a)},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y,a.y);this.z=Math.min(this.z, +a.z);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b,this.y));this.z=Math.max(a,Math.min(b,this.z));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c|| +1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);return this},round:function(){this.x=Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z= +0>this.z?Math.ceil(this.z):Math.floor(this.z);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z*a.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(a){return this.normalize().multiplyScalar(a)}, +lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z-this.z)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},cross:function(a,b){return void 0!==b?(console.warn("THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead."),this.crossVectors(a,b)):this.crossVectors(this,a)},crossVectors:function(a,b){var c=a.x,d=a.y;a=a.z;var f=b.x,g=b.y;b=b.z;this.x=d*b-a*g;this.y=a*f-c*b;this.z=c*g-d*f;return this}, +projectOnVector:function(a){var b=a.dot(this)/a.lengthSq();return this.copy(a).multiplyScalar(b)},projectOnPlane:function(a){rh.copy(this).projectOnVector(a);return this.sub(rh)},reflect:function(a){return this.sub(rh.copy(a).multiplyScalar(2*this.dot(a)))},angleTo:function(a){var b=Math.sqrt(this.lengthSq()*a.lengthSq());0===b&&console.error("THREE.Vector3: angleTo() can't handle zero length vectors.");a=this.dot(a)/b;return Math.acos(N.clamp(a,-1,1))},distanceTo:function(a){return Math.sqrt(this.distanceToSquared(a))}, +distanceToSquared:function(a){var b=this.x-a.x,c=this.y-a.y;a=this.z-a.z;return b*b+c*c+a*a},manhattanDistanceTo:function(a){return Math.abs(this.x-a.x)+Math.abs(this.y-a.y)+Math.abs(this.z-a.z)},setFromSpherical:function(a){return this.setFromSphericalCoords(a.radius,a.phi,a.theta)},setFromSphericalCoords:function(a,b,c){var d=Math.sin(b)*a;this.x=d*Math.sin(c);this.y=Math.cos(b)*a;this.z=d*Math.cos(c);return this},setFromCylindrical:function(a){return this.setFromCylindricalCoords(a.radius,a.theta, +a.y)},setFromCylindricalCoords:function(a,b,c){this.x=a*Math.sin(b);this.y=c;this.z=a*Math.cos(b);return this},setFromMatrixPosition:function(a){a=a.elements;this.x=a[12];this.y=a[13];this.z=a[14];return this},setFromMatrixScale:function(a){var b=this.setFromMatrixColumn(a,0).length(),c=this.setFromMatrixColumn(a,1).length();a=this.setFromMatrixColumn(a,2).length();this.x=b;this.y=c;this.z=a;return this},setFromMatrixColumn:function(a,b){return this.fromArray(a.elements,4*b)},equals:function(a){return a.x=== +this.x&&a.y===this.y&&a.z===this.z},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector3: offset has been removed from .fromBufferAttribute().");this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);return this}});var Bc=new q;Object.assign(ka.prototype,{isMatrix3:!0,set:function(a, +b,c,d,f,g,k,m,n){var p=this.elements;p[0]=a;p[1]=d;p[2]=k;p[3]=b;p[4]=f;p[5]=m;p[6]=c;p[7]=g;p[8]=n;return this},identity:function(){this.set(1,0,0,0,1,0,0,0,1);return this},clone:function(){return(new this.constructor).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return this},setFromMatrix4:function(a){a=a.elements;this.set(a[0],a[4],a[8],a[1],a[5],a[9],a[2],a[6],a[10]);return this}, +applyToBufferAttribute:function(a){for(var b=0,c=a.count;bc;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;9>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];return a}});var Ad,Qb={getDataURL:function(a){if("undefined"==typeof HTMLCanvasElement)return a.src;if(!(a instanceof HTMLCanvasElement)){void 0===Ad&&(Ad=V.createElementNS("http://www.w3.org/1999/xhtml", +"canvas"));Ad.width=a.width;Ad.height=a.height;var b=Ad.getContext("2d");a instanceof ImageData?b.putImageData(a,0,0):b.drawImage(a,0,0,a.width,a.height);a=Ad}return 2048a.x||1a.x?0:1;break;case 1002:a.x=1===Math.abs(Math.floor(a.x)%2)?Math.ceil(a.x)-a.x:a.x-Math.floor(a.x)}if(0>a.y||1a.y?0:1;break;case 1002:a.y=1===Math.abs(Math.floor(a.y)%2)?Math.ceil(a.y)-a.y:a.y-Math.floor(a.y)}this.flipY&&(a.y=1-a.y);return a}});Object.defineProperty(S.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.defineProperties(ca.prototype,{width:{get:function(){return this.z},set:function(a){this.z=a}},height:{get:function(){return this.w},set:function(a){this.w=a}}});Object.assign(ca.prototype,{isVector4:!0,set:function(a,b,c,d){this.x= +a;this.y=b;this.z=c;this.w=d;return this},setScalar:function(a){this.w=this.z=this.y=this.x=a;return this},setX:function(a){this.x=a;return this},setY:function(a){this.y=a;return this},setZ:function(a){this.z=a;return this},setW:function(a){this.w=a;return this},setComponent:function(a,b){switch(a){case 0:this.x=b;break;case 1:this.y=b;break;case 2:this.z=b;break;case 3:this.w=b;break;default:throw Error("index is out of range: "+a);}return this},getComponent:function(a){switch(a){case 0:return this.x; +case 1:return this.y;case 2:return this.z;case 3:return this.w;default:throw Error("index is out of range: "+a);}},clone:function(){return new this.constructor(this.x,this.y,this.z,this.w)},copy:function(a){this.x=a.x;this.y=a.y;this.z=a.z;this.w=void 0!==a.w?a.w:1;return this},add:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead."),this.addVectors(a,b);this.x+=a.x;this.y+=a.y;this.z+=a.z;this.w+=a.w;return this}, +addScalar:function(a){this.x+=a;this.y+=a;this.z+=a;this.w+=a;return this},addVectors:function(a,b){this.x=a.x+b.x;this.y=a.y+b.y;this.z=a.z+b.z;this.w=a.w+b.w;return this},addScaledVector:function(a,b){this.x+=a.x*b;this.y+=a.y*b;this.z+=a.z*b;this.w+=a.w*b;return this},sub:function(a,b){if(void 0!==b)return console.warn("THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead."),this.subVectors(a,b);this.x-=a.x;this.y-=a.y;this.z-=a.z;this.w-=a.w;return this},subScalar:function(a){this.x-= +a;this.y-=a;this.z-=a;this.w-=a;return this},subVectors:function(a,b){this.x=a.x-b.x;this.y=a.y-b.y;this.z=a.z-b.z;this.w=a.w-b.w;return this},multiplyScalar:function(a){this.x*=a;this.y*=a;this.z*=a;this.w*=a;return this},applyMatrix4:function(a){var b=this.x,c=this.y,d=this.z,f=this.w;a=a.elements;this.x=a[0]*b+a[4]*c+a[8]*d+a[12]*f;this.y=a[1]*b+a[5]*c+a[9]*d+a[13]*f;this.z=a[2]*b+a[6]*c+a[10]*d+a[14]*f;this.w=a[3]*b+a[7]*c+a[11]*d+a[15]*f;return this},divideScalar:function(a){return this.multiplyScalar(1/ +a)},setAxisAngleFromQuaternion:function(a){this.w=2*Math.acos(a.w);var b=Math.sqrt(1-a.w*a.w);1E-4>b?(this.x=1,this.z=this.y=0):(this.x=a.x/b,this.y=a.y/b,this.z=a.z/b);return this},setAxisAngleFromRotationMatrix:function(a){a=a.elements;var b=a[0];var c=a[4];var d=a[8],f=a[1],g=a[5],k=a[9];var m=a[2];var n=a[6];var p=a[10];if(.01>Math.abs(c-f)&&.01>Math.abs(d-m)&&.01>Math.abs(k-n)){if(.1>Math.abs(c+f)&&.1>Math.abs(d+m)&&.1>Math.abs(k+n)&&.1>Math.abs(b+g+p-3))return this.set(1,0,0,0),this;a=Math.PI; +b=(b+1)/2;g=(g+1)/2;p=(p+1)/2;c=(c+f)/4;d=(d+m)/4;k=(k+n)/4;b>g&&b>p?.01>b?(n=0,c=m=.707106781):(n=Math.sqrt(b),m=c/n,c=d/n):g>p?.01>g?(n=.707106781,m=0,c=.707106781):(m=Math.sqrt(g),n=c/m,c=k/m):.01>p?(m=n=.707106781,c=0):(c=Math.sqrt(p),n=d/c,m=k/c);this.set(n,m,c,a);return this}a=Math.sqrt((n-k)*(n-k)+(d-m)*(d-m)+(f-c)*(f-c));.001>Math.abs(a)&&(a=1);this.x=(n-k)/a;this.y=(d-m)/a;this.z=(f-c)/a;this.w=Math.acos((b+g+p-1)/2);return this},min:function(a){this.x=Math.min(this.x,a.x);this.y=Math.min(this.y, +a.y);this.z=Math.min(this.z,a.z);this.w=Math.min(this.w,a.w);return this},max:function(a){this.x=Math.max(this.x,a.x);this.y=Math.max(this.y,a.y);this.z=Math.max(this.z,a.z);this.w=Math.max(this.w,a.w);return this},clamp:function(a,b){this.x=Math.max(a.x,Math.min(b.x,this.x));this.y=Math.max(a.y,Math.min(b.y,this.y));this.z=Math.max(a.z,Math.min(b.z,this.z));this.w=Math.max(a.w,Math.min(b.w,this.w));return this},clampScalar:function(a,b){this.x=Math.max(a,Math.min(b,this.x));this.y=Math.max(a,Math.min(b, +this.y));this.z=Math.max(a,Math.min(b,this.z));this.w=Math.max(a,Math.min(b,this.w));return this},clampLength:function(a,b){var c=this.length();return this.divideScalar(c||1).multiplyScalar(Math.max(a,Math.min(b,c)))},floor:function(){this.x=Math.floor(this.x);this.y=Math.floor(this.y);this.z=Math.floor(this.z);this.w=Math.floor(this.w);return this},ceil:function(){this.x=Math.ceil(this.x);this.y=Math.ceil(this.y);this.z=Math.ceil(this.z);this.w=Math.ceil(this.w);return this},round:function(){this.x= +Math.round(this.x);this.y=Math.round(this.y);this.z=Math.round(this.z);this.w=Math.round(this.w);return this},roundToZero:function(){this.x=0>this.x?Math.ceil(this.x):Math.floor(this.x);this.y=0>this.y?Math.ceil(this.y):Math.floor(this.y);this.z=0>this.z?Math.ceil(this.z):Math.floor(this.z);this.w=0>this.w?Math.ceil(this.w):Math.floor(this.w);return this},negate:function(){this.x=-this.x;this.y=-this.y;this.z=-this.z;this.w=-this.w;return this},dot:function(a){return this.x*a.x+this.y*a.y+this.z* +a.z+this.w*a.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)},manhattanLength:function(){return Math.abs(this.x)+Math.abs(this.y)+Math.abs(this.z)+Math.abs(this.w)},normalize:function(){return this.divideScalar(this.length()||1)},setLength:function(a){return this.normalize().multiplyScalar(a)},lerp:function(a,b){this.x+=(a.x-this.x)*b;this.y+=(a.y-this.y)*b;this.z+=(a.z- +this.z)*b;this.w+=(a.w-this.w)*b;return this},lerpVectors:function(a,b,c){return this.subVectors(b,a).multiplyScalar(c).add(a)},equals:function(a){return a.x===this.x&&a.y===this.y&&a.z===this.z&&a.w===this.w},fromArray:function(a,b){void 0===b&&(b=0);this.x=a[b];this.y=a[b+1];this.z=a[b+2];this.w=a[b+3];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);a[b]=this.x;a[b+1]=this.y;a[b+2]=this.z;a[b+3]=this.w;return a},fromBufferAttribute:function(a,b,c){void 0!==c&&console.warn("THREE.Vector4: offset has been removed from .fromBufferAttribute()."); +this.x=a.getX(b);this.y=a.getY(b);this.z=a.getZ(b);this.w=a.getW(b);return this}});sa.prototype=Object.assign(Object.create(Ra.prototype),{constructor:sa,isWebGLRenderTarget:!0,setSize:function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.texture.image.width=a,this.texture.image.height=b,this.dispose();this.viewport.set(0,0,a,b);this.scissor.set(0,0,a,b)},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.width=a.width;this.height=a.height;this.viewport.copy(a.viewport); +this.texture=a.texture.clone();this.depthBuffer=a.depthBuffer;this.stencilBuffer=a.stencilBuffer;this.depthTexture=a.depthTexture;return this},dispose:function(){this.dispatchEvent({type:"dispose"})}});qg.prototype=Object.assign(Object.create(sa.prototype),{constructor:qg,isWebGLMultisampleRenderTarget:!0,copy:function(a){sa.prototype.copy.call(this,a);this.samples=a.samples;return this}});var Na=new q,ea=new I,Bl=new q(0,0,0),Cl=new q(1,1,1),Rb=new q,Pf=new q,Da=new q;Object.assign(I.prototype,{isMatrix4:!0, +set:function(a,b,c,d,f,g,k,m,n,p,l,t,r,u,q,w){var y=this.elements;y[0]=a;y[4]=b;y[8]=c;y[12]=d;y[1]=f;y[5]=g;y[9]=k;y[13]=m;y[2]=n;y[6]=p;y[10]=l;y[14]=t;y[3]=r;y[7]=u;y[11]=q;y[15]=w;return this},identity:function(){this.set(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1);return this},clone:function(){return(new I).fromArray(this.elements)},copy:function(a){var b=this.elements;a=a.elements;b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11]; +b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return this},copyPosition:function(a){var b=this.elements;a=a.elements;b[12]=a[12];b[13]=a[13];b[14]=a[14];return this},extractBasis:function(a,b,c){a.setFromMatrixColumn(this,0);b.setFromMatrixColumn(this,1);c.setFromMatrixColumn(this,2);return this},makeBasis:function(a,b,c){this.set(a.x,b.x,c.x,0,a.y,b.y,c.y,0,a.z,b.z,c.z,0,0,0,0,1);return this},extractRotation:function(a){var b=this.elements,c=a.elements,d=1/Na.setFromMatrixColumn(a,0).length(), +f=1/Na.setFromMatrixColumn(a,1).length();a=1/Na.setFromMatrixColumn(a,2).length();b[0]=c[0]*d;b[1]=c[1]*d;b[2]=c[2]*d;b[3]=0;b[4]=c[4]*f;b[5]=c[5]*f;b[6]=c[6]*f;b[7]=0;b[8]=c[8]*a;b[9]=c[9]*a;b[10]=c[10]*a;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromEuler:function(a){a&&a.isEuler||console.error("THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.");var b=this.elements,c=a.x,d=a.y,f=a.z,g=Math.cos(c);c=Math.sin(c);var k=Math.cos(d); +d=Math.sin(d);var m=Math.cos(f);f=Math.sin(f);if("XYZ"===a.order){a=g*m;var n=g*f,p=c*m,l=c*f;b[0]=k*m;b[4]=-k*f;b[8]=d;b[1]=n+p*d;b[5]=a-l*d;b[9]=-c*k;b[2]=l-a*d;b[6]=p+n*d;b[10]=g*k}else"YXZ"===a.order?(a=k*m,n=k*f,p=d*m,l=d*f,b[0]=a+l*c,b[4]=p*c-n,b[8]=g*d,b[1]=g*f,b[5]=g*m,b[9]=-c,b[2]=n*c-p,b[6]=l+a*c,b[10]=g*k):"ZXY"===a.order?(a=k*m,n=k*f,p=d*m,l=d*f,b[0]=a-l*c,b[4]=-g*f,b[8]=p+n*c,b[1]=n+p*c,b[5]=g*m,b[9]=l-a*c,b[2]=-g*d,b[6]=c,b[10]=g*k):"ZYX"===a.order?(a=g*m,n=g*f,p=c*m,l=c*f,b[0]=k*m, +b[4]=p*d-n,b[8]=a*d+l,b[1]=k*f,b[5]=l*d+a,b[9]=n*d-p,b[2]=-d,b[6]=c*k,b[10]=g*k):"YZX"===a.order?(a=g*k,n=g*d,p=c*k,l=c*d,b[0]=k*m,b[4]=l-a*f,b[8]=p*f+n,b[1]=f,b[5]=g*m,b[9]=-c*m,b[2]=-d*m,b[6]=n*f+p,b[10]=a-l*f):"XZY"===a.order&&(a=g*k,n=g*d,p=c*k,l=c*d,b[0]=k*m,b[4]=-f,b[8]=d*m,b[1]=a*f+l,b[5]=g*m,b[9]=n*f-p,b[2]=p*f-n,b[6]=c*m,b[10]=l*f+a);b[3]=0;b[7]=0;b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return this},makeRotationFromQuaternion:function(a){return this.compose(Bl,a,Cl)},lookAt:function(a,b, +c){var d=this.elements;Da.subVectors(a,b);0===Da.lengthSq()&&(Da.z=1);Da.normalize();Rb.crossVectors(c,Da);0===Rb.lengthSq()&&(1===Math.abs(c.z)?Da.x+=1E-4:Da.z+=1E-4,Da.normalize(),Rb.crossVectors(c,Da));Rb.normalize();Pf.crossVectors(Da,Rb);d[0]=Rb.x;d[4]=Pf.x;d[8]=Da.x;d[1]=Rb.y;d[5]=Pf.y;d[9]=Da.y;d[2]=Rb.z;d[6]=Pf.z;d[10]=Da.z;return this},multiply:function(a,b){return void 0!==b?(console.warn("THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead."), +this.multiplyMatrices(a,b)):this.multiplyMatrices(this,a)},premultiply:function(a){return this.multiplyMatrices(a,this)},multiplyMatrices:function(a,b){var c=a.elements,d=b.elements;b=this.elements;a=c[0];var f=c[4],g=c[8],k=c[12],m=c[1],n=c[5],p=c[9],l=c[13],t=c[2],r=c[6],q=c[10],v=c[14],w=c[3],x=c[7],B=c[11];c=c[15];var C=d[0],A=d[4],z=d[8],D=d[12],E=d[1],F=d[5],H=d[9],G=d[13],I=d[2],K=d[6],M=d[10],N=d[14],O=d[3],P=d[7],Q=d[11];d=d[15];b[0]=a*C+f*E+g*I+k*O;b[4]=a*A+f*F+g*K+k*P;b[8]=a*z+f*H+g*M+ +k*Q;b[12]=a*D+f*G+g*N+k*d;b[1]=m*C+n*E+p*I+l*O;b[5]=m*A+n*F+p*K+l*P;b[9]=m*z+n*H+p*M+l*Q;b[13]=m*D+n*G+p*N+l*d;b[2]=t*C+r*E+q*I+v*O;b[6]=t*A+r*F+q*K+v*P;b[10]=t*z+r*H+q*M+v*Q;b[14]=t*D+r*G+q*N+v*d;b[3]=w*C+x*E+B*I+c*O;b[7]=w*A+x*F+B*K+c*P;b[11]=w*z+x*H+B*M+c*Q;b[15]=w*D+x*G+B*N+c*d;return this},multiplyScalar:function(a){var b=this.elements;b[0]*=a;b[4]*=a;b[8]*=a;b[12]*=a;b[1]*=a;b[5]*=a;b[9]*=a;b[13]*=a;b[2]*=a;b[6]*=a;b[10]*=a;b[14]*=a;b[3]*=a;b[7]*=a;b[11]*=a;b[15]*=a;return this},applyToBufferAttribute:function(a){for(var b= +0,c=a.count;bthis.determinant()&&(f=-f);a.x=d[12];a.y=d[13];a.z=d[14];ea.copy(this);a=1/f;d=1/g;var m=1/k;ea.elements[0]*=a;ea.elements[1]*=a;ea.elements[2]*=a;ea.elements[4]*=d;ea.elements[5]*=d;ea.elements[6]*=d;ea.elements[8]*=m;ea.elements[9]*=m;ea.elements[10]*=m;b.setFromRotationMatrix(ea);c.x=f;c.y=g;c.z=k;return this},makePerspective:function(a,b,c,d,f,g){void 0===g&&console.warn("THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs."); +var k=this.elements;k[0]=2*f/(b-a);k[4]=0;k[8]=(b+a)/(b-a);k[12]=0;k[1]=0;k[5]=2*f/(c-d);k[9]=(c+d)/(c-d);k[13]=0;k[2]=0;k[6]=0;k[10]=-(g+f)/(g-f);k[14]=-2*g*f/(g-f);k[3]=0;k[7]=0;k[11]=-1;k[15]=0;return this},makeOrthographic:function(a,b,c,d,f,g){var k=this.elements,m=1/(b-a),n=1/(c-d),l=1/(g-f);k[0]=2*m;k[4]=0;k[8]=0;k[12]=-((b+a)*m);k[1]=0;k[5]=2*n;k[9]=0;k[13]=-((c+d)*n);k[2]=0;k[6]=0;k[10]=-2*l;k[14]=-((g+f)*l);k[3]=0;k[7]=0;k[11]=0;k[15]=1;return this},equals:function(a){var b=this.elements; +a=a.elements;for(var c=0;16>c;c++)if(b[c]!==a[c])return!1;return!0},fromArray:function(a,b){void 0===b&&(b=0);for(var c=0;16>c;c++)this.elements[c]=a[c+b];return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);var c=this.elements;a[b]=c[0];a[b+1]=c[1];a[b+2]=c[2];a[b+3]=c[3];a[b+4]=c[4];a[b+5]=c[5];a[b+6]=c[6];a[b+7]=c[7];a[b+8]=c[8];a[b+9]=c[9];a[b+10]=c[10];a[b+11]=c[11];a[b+12]=c[12];a[b+13]=c[13];a[b+14]=c[14];a[b+15]=c[15];return a}});var hj=new I,ij=new ya;Zb.RotationOrders= +"XYZ YZX ZXY XZY YXZ ZYX".split(" ");Zb.DefaultOrder="XYZ";Object.defineProperties(Zb.prototype,{x:{get:function(){return this._x},set:function(a){this._x=a;this._onChangeCallback()}},y:{get:function(){return this._y},set:function(a){this._y=a;this._onChangeCallback()}},z:{get:function(){return this._z},set:function(a){this._z=a;this._onChangeCallback()}},order:{get:function(){return this._order},set:function(a){this._order=a;this._onChangeCallback()}}});Object.assign(Zb.prototype,{isEuler:!0,set:function(a, +b,c,d){this._x=a;this._y=b;this._z=c;this._order=d||this._order;this._onChangeCallback();return this},clone:function(){return new this.constructor(this._x,this._y,this._z,this._order)},copy:function(a){this._x=a._x;this._y=a._y;this._z=a._z;this._order=a._order;this._onChangeCallback();return this},setFromRotationMatrix:function(a,b,c){var d=N.clamp,f=a.elements;a=f[0];var g=f[4],k=f[8],m=f[1],n=f[5],l=f[9],q=f[2],t=f[6];f=f[10];b=b||this._order;"XYZ"===b?(this._y=Math.asin(d(k,-1,1)),.9999999>Math.abs(k)? +(this._x=Math.atan2(-l,f),this._z=Math.atan2(-g,a)):(this._x=Math.atan2(t,n),this._z=0)):"YXZ"===b?(this._x=Math.asin(-d(l,-1,1)),.9999999>Math.abs(l)?(this._y=Math.atan2(k,f),this._z=Math.atan2(m,n)):(this._y=Math.atan2(-q,a),this._z=0)):"ZXY"===b?(this._x=Math.asin(d(t,-1,1)),.9999999>Math.abs(t)?(this._y=Math.atan2(-q,f),this._z=Math.atan2(-g,n)):(this._y=0,this._z=Math.atan2(m,a))):"ZYX"===b?(this._y=Math.asin(-d(q,-1,1)),.9999999>Math.abs(q)?(this._x=Math.atan2(t,f),this._z=Math.atan2(m,a)): +(this._x=0,this._z=Math.atan2(-g,n))):"YZX"===b?(this._z=Math.asin(d(m,-1,1)),.9999999>Math.abs(m)?(this._x=Math.atan2(-l,n),this._y=Math.atan2(-q,a)):(this._x=0,this._y=Math.atan2(k,f))):"XZY"===b?(this._z=Math.asin(-d(g,-1,1)),.9999999>Math.abs(g)?(this._x=Math.atan2(t,n),this._y=Math.atan2(k,a)):(this._x=Math.atan2(-l,f),this._y=0)):console.warn("THREE.Euler: .setFromRotationMatrix() given unsupported order: "+b);this._order=b;!1!==c&&this._onChangeCallback();return this},setFromQuaternion:function(a, +b,c){hj.makeRotationFromQuaternion(a);return this.setFromRotationMatrix(hj,b,c)},setFromVector3:function(a,b){return this.set(a.x,a.y,a.z,b||this._order)},reorder:function(a){ij.setFromEuler(this);return this.setFromQuaternion(ij,a)},equals:function(a){return a._x===this._x&&a._y===this._y&&a._z===this._z&&a._order===this._order},fromArray:function(a){this._x=a[0];this._y=a[1];this._z=a[2];void 0!==a[3]&&(this._order=a[3]);this._onChangeCallback();return this},toArray:function(a,b){void 0===a&&(a= +[]);void 0===b&&(b=0);a[b]=this._x;a[b+1]=this._y;a[b+2]=this._z;a[b+3]=this._order;return a},toVector3:function(a){return a?a.set(this._x,this._y,this._z):new q(this._x,this._y,this._z)},_onChange:function(a){this._onChangeCallback=a;return this},_onChangeCallback:function(){}});Object.assign(rg.prototype,{set:function(a){this.mask=1<f&&(f=l);q>g&&(g=q);t>k&&(k=t)}this.min.set(b,c,d);this.max.set(f,g,k);return this},setFromBufferAttribute:function(a){for(var b=Infinity,c=Infinity,d=Infinity,f=-Infinity,g=-Infinity,k=-Infinity,m=0,n=a.count;mf&&(f=l);q>g&&(g=q);t>k&&(k=t)}this.min.set(b,c,d); +this.max.set(f,g,k);return this},setFromPoints:function(a){this.makeEmpty();for(var b=0,c=a.length;bthis.max.x||a.ythis.max.y||a.zthis.max.z?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y&&this.min.z<=a.min.z&&a.max.z<= +this.max.z},getParameter:function(a,b){void 0===b&&(console.warn("THREE.Box3: .getParameter() target is now required"),b=new q);return b.set((a.x-this.min.x)/(this.max.x-this.min.x),(a.y-this.min.y)/(this.max.y-this.min.y),(a.z-this.min.z)/(this.max.z-this.min.z))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y||a.max.zthis.max.z?!1:!0},intersectsSphere:function(a){this.clampPoint(a.center,ob);return ob.distanceToSquared(a.center)<= +a.radius*a.radius},intersectsPlane:function(a){if(0=-a.constant},intersectsTriangle:function(a){if(this.isEmpty())return!1; +this.getCenter(Pe);Rf.subVectors(this.max,Pe);Cd.subVectors(a.a,Pe);Dd.subVectors(a.b,Pe);Ed.subVectors(a.c,Pe);Sb.subVectors(Dd,Cd);Tb.subVectors(Ed,Dd);Cc.subVectors(Cd,Ed);a=[0,-Sb.z,Sb.y,0,-Tb.z,Tb.y,0,-Cc.z,Cc.y,Sb.z,0,-Sb.x,Tb.z,0,-Tb.x,Cc.z,0,-Cc.x,-Sb.y,Sb.x,0,-Tb.y,Tb.x,0,-Cc.y,Cc.x,0];if(!sg(a,Cd,Dd,Ed,Rf))return!1;a=[1,0,0,0,1,0,0,0,1];if(!sg(a,Cd,Dd,Ed,Rf))return!1;Sf.crossVectors(Sb,Tb);a=[Sf.x,Sf.y,Sf.z];return sg(a,Cd,Dd,Ed,Rf)},clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box3: .clampPoint() target is now required"), +b=new q);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return ob.copy(a).clamp(this.min,this.max).sub(a).length()},getBoundingSphere:function(a){void 0===a&&console.error("THREE.Box3: .getBoundingSphere() target is now required");this.getCenter(a.center);a.radius=.5*this.getSize(ob).length();return a},intersect:function(a){this.min.max(a.min);this.max.min(a.max);this.isEmpty()&&this.makeEmpty();return this},union:function(a){this.min.min(a.min);this.max.max(a.max);return this}, +applyMatrix4:function(a){if(this.isEmpty())return this;Db[0].set(this.min.x,this.min.y,this.min.z).applyMatrix4(a);Db[1].set(this.min.x,this.min.y,this.max.z).applyMatrix4(a);Db[2].set(this.min.x,this.max.y,this.min.z).applyMatrix4(a);Db[3].set(this.min.x,this.max.y,this.max.z).applyMatrix4(a);Db[4].set(this.max.x,this.min.y,this.min.z).applyMatrix4(a);Db[5].set(this.max.x,this.min.y,this.max.z).applyMatrix4(a);Db[6].set(this.max.x,this.max.y,this.min.z).applyMatrix4(a);Db[7].set(this.max.x,this.max.y, +this.max.z).applyMatrix4(a);this.setFromPoints(Db);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}});var Hl=new gb;Object.assign(ub.prototype,{set:function(a,b){this.center.copy(a);this.radius=b;return this},setFromPoints:function(a,b){var c=this.center;void 0!==b?c.copy(b):Hl.setFromPoints(a).getCenter(c);for(var d=b=0,f=a.length;d=this.radius},containsPoint:function(a){return a.distanceToSquared(this.center)<=this.radius*this.radius},distanceToPoint:function(a){return a.distanceTo(this.center)-this.radius},intersectsSphere:function(a){var b=this.radius+a.radius;return a.center.distanceToSquared(this.center)<=b*b},intersectsBox:function(a){return a.intersectsSphere(this)}, +intersectsPlane:function(a){return Math.abs(a.distanceToPoint(this.center))<=this.radius},clampPoint:function(a,b){var c=this.center.distanceToSquared(a);void 0===b&&(console.warn("THREE.Sphere: .clampPoint() target is now required"),b=new q);b.copy(a);c>this.radius*this.radius&&(b.sub(this.center).normalize(),b.multiplyScalar(this.radius).add(this.center));return b},getBoundingBox:function(a){void 0===a&&(console.warn("THREE.Sphere: .getBoundingBox() target is now required"),a=new gb);a.set(this.center, +this.center);a.expandByScalar(this.radius);return a},applyMatrix4:function(a){this.center.applyMatrix4(a);this.radius*=a.getMaxScaleOnAxis();return this},translate:function(a){this.center.add(a);return this},equals:function(a){return a.center.equals(this.center)&&a.radius===this.radius}});var Eb=new q,sh=new q,Tf=new q,Ub=new q,th=new q,Uf=new q,uh=new q;Object.assign(ac.prototype,{set:function(a,b){this.origin.copy(a);this.direction.copy(b);return this},clone:function(){return(new this.constructor).copy(this)}, +copy:function(a){this.origin.copy(a.origin);this.direction.copy(a.direction);return this},at:function(a,b){void 0===b&&(console.warn("THREE.Ray: .at() target is now required"),b=new q);return b.copy(this.direction).multiplyScalar(a).add(this.origin)},lookAt:function(a){this.direction.copy(a).sub(this.origin).normalize();return this},recast:function(a){this.origin.copy(this.at(a,Eb));return this},closestPointToPoint:function(a,b){void 0===b&&(console.warn("THREE.Ray: .closestPointToPoint() target is now required"), +b=new q);b.subVectors(a,this.origin);a=b.dot(this.direction);return 0>a?b.copy(this.origin):b.copy(this.direction).multiplyScalar(a).add(this.origin)},distanceToPoint:function(a){return Math.sqrt(this.distanceSqToPoint(a))},distanceSqToPoint:function(a){var b=Eb.subVectors(a,this.origin).dot(this.direction);if(0>b)return this.origin.distanceToSquared(a);Eb.copy(this.direction).multiplyScalar(b).add(this.origin);return Eb.distanceToSquared(a)},distanceSqToSegment:function(a,b,c,d){sh.copy(a).add(b).multiplyScalar(.5); +Tf.copy(b).sub(a).normalize();Ub.copy(this.origin).sub(sh);var f=.5*a.distanceTo(b),g=-this.direction.dot(Tf),k=Ub.dot(this.direction),m=-Ub.dot(Tf),n=Ub.lengthSq(),l=Math.abs(1-g*g);if(0=-q?b<=q?(f=1/l,a*=f,b*=f,g=a*(a+g*b+2*k)+b*(g*a+b+2*m)+n):(b=f,a=Math.max(0,-(g*b+k)),g=-a*a+b*(b+2*m)+n):(b=-f,a=Math.max(0,-(g*b+k)),g=-a*a+b*(b+2*m)+n):b<=-q?(a=Math.max(0,-(-g*f+k)),b=0a)return null;a=Math.sqrt(a-d);d=c-a;c+=a;return 0>d&&0>c?null:0>d?this.at(c,b):this.at(d,b)}, +intersectsSphere:function(a){return this.distanceSqToPoint(a.center)<=a.radius*a.radius},distanceToPlane:function(a){var b=a.normal.dot(this.direction);if(0===b)return 0===a.distanceToPoint(this.origin)?0:null;a=-(this.origin.dot(a.normal)+a.constant)/b;return 0<=a?a:null},intersectPlane:function(a,b){a=this.distanceToPlane(a);return null===a?null:this.at(a,b)},intersectsPlane:function(a){var b=a.distanceToPoint(this.origin);return 0===b||0>a.normal.dot(this.direction)*b?!0:!1},intersectBox:function(a, +b){var c=1/this.direction.x;var d=1/this.direction.y;var f=1/this.direction.z,g=this.origin;if(0<=c){var k=(a.min.x-g.x)*c;c*=a.max.x-g.x}else k=(a.max.x-g.x)*c,c*=a.min.x-g.x;if(0<=d){var m=(a.min.y-g.y)*d;d*=a.max.y-g.y}else m=(a.max.y-g.y)*d,d*=a.min.y-g.y;if(k>d||m>c)return null;if(m>k||k!==k)k=m;if(da||m>c)return null;if(m>k||k!==k)k=m;if(ac?null:this.at(0<=k?k:c,b)},intersectsBox:function(a){return null!== +this.intersectBox(a,Eb)},intersectTriangle:function(a,b,c,d,f){th.subVectors(b,a);Uf.subVectors(c,a);uh.crossVectors(th,Uf);b=this.direction.dot(uh);if(0b)d=-1,b=-b;else return null;Ub.subVectors(this.origin,a);a=d*this.direction.dot(Uf.crossVectors(Ub,Uf));if(0>a)return null;c=d*this.direction.dot(th.cross(Ub));if(0>c||a+c>b)return null;a=-d*Ub.dot(uh);return 0>a?null:this.at(a/b,f)},applyMatrix4:function(a){this.origin.applyMatrix4(a);this.direction.transformDirection(a); +return this},equals:function(a){return a.origin.equals(this.origin)&&a.direction.equals(this.direction)}});var vh=new q,Il=new q,Jl=new ka;Object.assign(Sa.prototype,{isPlane:!0,set:function(a,b){this.normal.copy(a);this.constant=b;return this},setComponents:function(a,b,c,d){this.normal.set(a,b,c);this.constant=d;return this},setFromNormalAndCoplanarPoint:function(a,b){this.normal.copy(a);this.constant=-b.dot(this.normal);return this},setFromCoplanarPoints:function(a,b,c){b=vh.subVectors(c,b).cross(Il.subVectors(a, +b)).normalize();this.setFromNormalAndCoplanarPoint(b,a);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.normal.copy(a.normal);this.constant=a.constant;return this},normalize:function(){var a=1/this.normal.length();this.normal.multiplyScalar(a);this.constant*=a;return this},negate:function(){this.constant*=-1;this.normal.negate();return this},distanceToPoint:function(a){return this.normal.dot(a)+this.constant},distanceToSphere:function(a){return this.distanceToPoint(a.center)- +a.radius},projectPoint:function(a,b){void 0===b&&(console.warn("THREE.Plane: .projectPoint() target is now required"),b=new q);return b.copy(this.normal).multiplyScalar(-this.distanceToPoint(a)).add(a)},intersectLine:function(a,b){void 0===b&&(console.warn("THREE.Plane: .intersectLine() target is now required"),b=new q);var c=a.delta(vh),d=this.normal.dot(c);if(0===d){if(0===this.distanceToPoint(a.start))return b.copy(a.start)}else if(d=-(a.start.dot(this.normal)+this.constant)/d,!(0>d||1b&&0a&&0=Gb.x+Gb.y},getUV:function(a,b,c,d,f,g,k,m){this.getBarycoord(a,b,c,d,Gb);m.set(0,0);m.addScaledVector(f,Gb.x);m.addScaledVector(g,Gb.y);m.addScaledVector(k,Gb.z);return m},isFrontFacing:function(a,b,c,d){cb.subVectors(c,b);Fb.subVectors(a,b);return 0>cb.cross(Fb).dot(d)?!0:!1}});Object.assign(va.prototype,{set:function(a,b,c){this.a.copy(a);this.b.copy(b);this.c.copy(c);return this},setFromPointsAndIndices:function(a,b,c,d){this.a.copy(a[b]);this.b.copy(a[c]);this.c.copy(a[d]); +return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.a.copy(a.a);this.b.copy(a.b);this.c.copy(a.c);return this},getArea:function(){cb.subVectors(this.c,this.b);Fb.subVectors(this.a,this.b);return.5*cb.cross(Fb).length()},getMidpoint:function(a){void 0===a&&(console.warn("THREE.Triangle: .getMidpoint() target is now required"),a=new q);return a.addVectors(this.a,this.b).add(this.c).multiplyScalar(1/3)},getNormal:function(a){return va.getNormal(this.a,this.b, +this.c,a)},getPlane:function(a){void 0===a&&(console.warn("THREE.Triangle: .getPlane() target is now required"),a=new Sa);return a.setFromCoplanarPoints(this.a,this.b,this.c)},getBarycoord:function(a,b){return va.getBarycoord(a,this.a,this.b,this.c,b)},getUV:function(a,b,c,d,f){return va.getUV(a,this.a,this.b,this.c,b,c,d,f)},containsPoint:function(a){return va.containsPoint(a,this.a,this.b,this.c)},isFrontFacing:function(a){return va.isFrontFacing(this.a,this.b,this.c,a)},intersectsBox:function(a){return a.intersectsTriangle(this)}, +closestPointToPoint:function(a,b){void 0===b&&(console.warn("THREE.Triangle: .closestPointToPoint() target is now required"),b=new q);var c=this.a,d=this.b,f=this.c;Fd.subVectors(d,c);Gd.subVectors(f,c);xh.subVectors(a,c);var g=Fd.dot(xh),k=Gd.dot(xh);if(0>=g&&0>=k)return b.copy(c);yh.subVectors(a,d);var m=Fd.dot(yh),n=Gd.dot(yh);if(0<=m&&n<=m)return b.copy(d);var l=g*n-m*k;if(0>=l&&0<=g&&0>=m)return d=g/(g-m),b.copy(c).addScaledVector(Fd,d);zh.subVectors(a,f);a=Fd.dot(zh);var y=Gd.dot(zh);if(0<= +y&&a<=y)return b.copy(f);g=a*k-g*y;if(0>=g&&0<=k&&0>=y)return l=k/(k-y),b.copy(c).addScaledVector(Gd,l);k=m*y-a*n;if(0>=k&&0<=n-m&&0<=a-y)return nj.subVectors(f,d),l=(n-m)/(n-m+(a-y)),b.copy(d).addScaledVector(nj,l);f=1/(k+g+l);d=g*f;l*=f;return b.copy(c).addScaledVector(Fd,d).addScaledVector(Gd,l)},equals:function(a){return a.a.equals(this.a)&&a.b.equals(this.b)&&a.c.equals(this.c)}});var oj={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244, +black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347, +darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365, +lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683, +mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910, +purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074}, +Ha={h:0,s:0,l:0},Vf={h:0,s:0,l:0};Object.assign(D.prototype,{isColor:!0,r:1,g:1,b:1,set:function(a){a&&a.isColor?this.copy(a):"number"===typeof a?this.setHex(a):"string"===typeof a&&this.setStyle(a);return this},setScalar:function(a){this.b=this.g=this.r=a;return this},setHex:function(a){a=Math.floor(a);this.r=(a>>16&255)/255;this.g=(a>>8&255)/255;this.b=(a&255)/255;return this},setRGB:function(a,b,c){this.r=a;this.g=b;this.b=c;return this},setHSL:function(a,b,c){a=N.euclideanModulo(a,1);b=N.clamp(b, +0,1);c=N.clamp(c,0,1);0===b?this.r=this.g=this.b=c:(b=.5>=c?c*(1+b):c+b-c*b,c=2*c-b,this.r=tg(c,b,a+1/3),this.g=tg(c,b,a),this.b=tg(c,b,a-1/3));return this},setStyle:function(a){function b(b){void 0!==b&&1>parseFloat(b)&&console.warn("THREE.Color: Alpha component of "+a+" will be ignored.")}var c;if(c=/^((?:rgb|hsl)a?)\(\s*([^\)]*)\)/.exec(a)){var d=c[2];switch(c[1]){case "rgb":case "rgba":if(c=/^(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(255,parseInt(c[1], +10))/255,this.g=Math.min(255,parseInt(c[2],10))/255,this.b=Math.min(255,parseInt(c[3],10))/255,b(c[5]),this;if(c=/^(\d+)%\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d))return this.r=Math.min(100,parseInt(c[1],10))/100,this.g=Math.min(100,parseInt(c[2],10))/100,this.b=Math.min(100,parseInt(c[3],10))/100,b(c[5]),this;break;case "hsl":case "hsla":if(c=/^([0-9]*\.?[0-9]+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*(,\s*([0-9]*\.?[0-9]+)\s*)?$/.exec(d)){d=parseFloat(c[1])/360;var f=parseInt(c[2], +10)/100,g=parseInt(c[3],10)/100;b(c[5]);return this.setHSL(d,f,g)}}}else if(c=/^#([A-Fa-f0-9]+)$/.exec(a)){c=c[1];d=c.length;if(3===d)return this.r=parseInt(c.charAt(0)+c.charAt(0),16)/255,this.g=parseInt(c.charAt(1)+c.charAt(1),16)/255,this.b=parseInt(c.charAt(2)+c.charAt(2),16)/255,this;if(6===d)return this.r=parseInt(c.charAt(0)+c.charAt(1),16)/255,this.g=parseInt(c.charAt(2)+c.charAt(3),16)/255,this.b=parseInt(c.charAt(4)+c.charAt(5),16)/255,this}return a&&0=m?n/(f+g):n/(2-f-g);switch(f){case b:k=(c-d)/n+(cthis.opacity&&(d.opacity=this.opacity);!0===this.transparent&&(d.transparent=this.transparent);d.depthFunc=this.depthFunc;d.depthTest=this.depthTest;d.depthWrite=this.depthWrite;d.stencilWrite=this.stencilWrite;d.stencilWriteMask=this.stencilWriteMask;d.stencilFunc=this.stencilFunc;d.stencilRef=this.stencilRef; +d.stencilFuncMask=this.stencilFuncMask;d.stencilFail=this.stencilFail;d.stencilZFail=this.stencilZFail;d.stencilZPass=this.stencilZPass;this.rotation&&0!==this.rotation&&(d.rotation=this.rotation);!0===this.polygonOffset&&(d.polygonOffset=!0);0!==this.polygonOffsetFactor&&(d.polygonOffsetFactor=this.polygonOffsetFactor);0!==this.polygonOffsetUnits&&(d.polygonOffsetUnits=this.polygonOffsetUnits);this.linewidth&&1!==this.linewidth&&(d.linewidth=this.linewidth);void 0!==this.dashSize&&(d.dashSize=this.dashSize); +void 0!==this.gapSize&&(d.gapSize=this.gapSize);void 0!==this.scale&&(d.scale=this.scale);!0===this.dithering&&(d.dithering=!0);0k;k++)if(d[k]===d[(k+1)%3]){a.push(g);break}for(g=a.length-1;0<=g;g--)for(d=a[g],this.faces.splice(d,1),c=0,f=this.faceVertexUvs.length;c\n\t#include \n}", +fragmentShader:"uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#define RECIPROCAL_PI 0.31830988618\n#define RECIPROCAL_PI2 0.15915494\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\tgl_FragColor = texture2D( tEquirect, sampleUV );\n}",side:1,blending:0});d.uniforms.tEquirect.value=b;b=new ia(new Ud(5, +5,5),d);c.add(b);d=new Qc(1,10,1);d.renderTarget=this;d.renderTarget.texture.name="CubeCameraTexture";d.update(a,c);b.geometry.dispose();b.material.dispose();return this};hc.prototype=Object.create(S.prototype);hc.prototype.constructor=hc;hc.prototype.isDataTexture=!0;var Hd=new ub,Yf=new q;Object.assign(Sd.prototype,{set:function(a,b,c,d,f,g){var k=this.planes;k[0].copy(a);k[1].copy(b);k[2].copy(c);k[3].copy(d);k[4].copy(f);k[5].copy(g);return this},clone:function(){return(new this.constructor).copy(this)}, +copy:function(a){for(var b=this.planes,c=0;6>c;c++)b[c].copy(a.planes[c]);return this},setFromMatrix:function(a){var b=this.planes,c=a.elements;a=c[0];var d=c[1],f=c[2],g=c[3],k=c[4],m=c[5],l=c[6],p=c[7],q=c[8],t=c[9],r=c[10],u=c[11],v=c[12],w=c[13],x=c[14];c=c[15];b[0].setComponents(g-a,p-k,u-q,c-v).normalize();b[1].setComponents(g+a,p+k,u+q,c+v).normalize();b[2].setComponents(g+d,p+m,u+t,c+w).normalize();b[3].setComponents(g-d,p-m,u-t,c-w).normalize();b[4].setComponents(g-f,p-l,u-r,c-x).normalize(); +b[5].setComponents(g+f,p+l,u+r,c+x).normalize();return this},intersectsObject:function(a){var b=a.geometry;null===b.boundingSphere&&b.computeBoundingSphere();Hd.copy(b.boundingSphere).applyMatrix4(a.matrixWorld);return this.intersectsSphere(Hd)},intersectsSprite:function(a){Hd.center.set(0,0,0);Hd.radius=.7071067811865476;Hd.applyMatrix4(a.matrixWorld);return this.intersectsSphere(Hd)},intersectsSphere:function(a){var b=this.planes,c=a.center;a=-a.radius;for(var d=0;6>d;d++)if(b[d].distanceToPoint(c)< +a)return!1;return!0},intersectsBox:function(a){for(var b=this.planes,c=0;6>c;c++){var d=b[c];Yf.x=0d.distanceToPoint(Yf))return!1}return!0},containsPoint:function(a){for(var b=this.planes,c=0;6>c;c++)if(0>b[c].distanceToPoint(a))return!1;return!0}});var Q={alphamap_fragment:"#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif",alphamap_pars_fragment:"#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif", +alphatest_fragment:"#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif",aomap_fragment:"#ifdef USE_AOMAP\n\tfloat ambientOcclusion = ( texture2D( aoMap, vUv2 ).r - 1.0 ) * aoMapIntensity + 1.0;\n\treflectedLight.indirectDiffuse *= ambientOcclusion;\n\t#if defined( USE_ENVMAP ) && defined( STANDARD )\n\t\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular *= computeSpecularOcclusion( dotNV, ambientOcclusion, material.specularRoughness );\n\t#endif\n#endif", +aomap_pars_fragment:"#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif",begin_vertex:"vec3 transformed = vec3( position );",beginnormal_vertex:"vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif",bsdfs:"vec2 integrateSpecularBRDF( const in float dotNV, const in float roughness ) {\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\treturn vec2( -1.04, 1.04 ) * a004 + r.zw;\n}\nfloat punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {\n#if defined ( PHYSICALLY_CORRECT_LIGHTS )\n\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\n\tif( cutoffDistance > 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}\nvec3 F_Schlick_RoughnessDependent( const in vec3 F0, const in float dotNV, const in float roughness ) {\n\tfloat fresnel = exp2( ( -5.55473 * dotNV - 6.98316 ) * dotNV );\n\tvec3 Fr = max( vec3( 1.0 - roughness ), F0 ) - F0;\n\treturn Fr * fresnel + F0;\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 vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat alpha = pow2( roughness );\n\tvec3 halfDir = normalize( incidentLight.direction + viewDir );\n\tfloat dotNL = saturate( dot( normal, incidentLight.direction ) );\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tfloat dotNH = saturate( dot( 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 vec3 viewDir, const in vec3 normal, const in vec3 specularColor, const in float roughness ) {\n\tfloat dotNV = saturate( dot( normal, viewDir ) );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\treturn specularColor * brdf.x + brdf.y;\n}\nvoid BRDF_Specular_Multiscattering_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness, inout vec3 singleScatter, inout vec3 multiScatter ) {\n\tfloat dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );\n\tvec3 F = F_Schlick_RoughnessDependent( specularColor, dotNV, roughness );\n\tvec2 brdf = integrateSpecularBRDF( dotNV, roughness );\n\tvec3 FssEss = F * brdf.x + brdf.y;\n\tfloat Ess = brdf.x + brdf.y;\n\tfloat Ems = 1.0 - Ess;\n\tvec3 Favg = specularColor + ( 1.0 - specularColor ) * 0.047619;\tvec3 Fms = FssEss * Favg / ( 1.0 - Ems * Favg );\n\tsingleScatter += FssEss;\n\tmultiScatter += Fms * Ems;\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}\n#if defined( USE_SHEEN )\nfloat D_Charlie(float roughness, float NoH) {\n\tfloat invAlpha = 1.0 / roughness;\n\tfloat cos2h = NoH * NoH;\n\tfloat sin2h = max(1.0 - cos2h, 0.0078125);\treturn (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);\n}\nfloat V_Neubelt(float NoV, float NoL) {\n\treturn saturate(1.0 / (4.0 * (NoL + NoV - NoL * NoV)));\n}\nvec3 BRDF_Specular_Sheen( const in float roughness, const in vec3 L, const in GeometricContext geometry, vec3 specularColor ) {\n\tvec3 N = geometry.normal;\n\tvec3 V = geometry.viewDir;\n\tvec3 H = normalize( V + L );\n\tfloat dotNH = saturate( dot( N, H ) );\n\treturn specularColor * D_Charlie( roughness, dotNH ) * V_Neubelt( dot(N, V), dot(N, L) );\n}\n#endif", +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( STANDARD ) && ! 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( STANDARD ) && ! defined( PHONG ) && ! defined( MATCAP )\n\tvarying vec3 vViewPosition;\n#endif",clipping_planes_vertex:"#if NUM_CLIPPING_PLANES > 0 && ! defined( STANDARD ) && ! 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#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\n#define whiteComplement(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}\n#ifdef HIGH_PRECISION\n\tfloat precisionSafeLength( vec3 v ) { return length( v ); }\n#else\n\tfloat max3( vec3 v ) { return max( max( v.x, v.y ), v.z ); }\n\tfloat precisionSafeLength( vec3 v ) {\n\t\tfloat maxComponent = max3( abs( v ) );\n\t\treturn length( v / maxComponent ) * maxComponent;\n\t}\n#endif\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#ifdef CLEARCOAT\n\tvec3 clearcoatNormal;\n#endif\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}\nbool isPerspectiveMatrix( mat4 m ) {\n return m[ 2 ][ 3 ] == - 1.0;\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 = objectNormal;\n#ifdef USE_INSTANCING\n\ttransformedNormal = mat3( instanceMatrix ) * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = normalMatrix * objectTangent;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\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, vUv ).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 = cLogLuvM * value.rgb;\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 = cLogLuvInverseM * Xp_Y_XYZp.rgb;\n\treturn vec4( max( vRGB, 0.0 ), 1.0 );\n}", +envmap_fragment:"#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\n\t\t\n\t\tif ( isOrthographic ) {\n\t\t\tcameraToFrag = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToFrag = normalize( vWorldPosition - cameraPosition );\n\t\t}\n\t\tvec3 worldNormal = inverseTransformDirection( normal, viewMatrix );\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t\tvec3 reflectVec = reflect( cameraToFrag, worldNormal );\n\t\t#else\n\t\t\tvec3 reflectVec = refract( cameraToFrag, 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_common_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float envMapIntensity;\n\tuniform float flipEnvMap;\n\tuniform int maxMipLevel;\n\t#ifdef ENVMAP_TYPE_CUBE\n\t\tuniform samplerCube envMap;\n\t#else\n\t\tuniform sampler2D envMap;\n\t#endif\n\t\n#endif",envmap_pars_fragment:"#ifdef USE_ENVMAP\n\tuniform float reflectivity;\n\t#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( PHONG )\n\t\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\tvarying vec3 vWorldPosition;\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\t#define ENV_WORLDPOS\n\t#endif\n\t#ifdef ENV_WORLDPOS\n\t\t\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 )\n\t#ifdef ENVMAP_MODE_REFRACTION\n\t\tuniform float refractionRatio;\n\t#endif\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 roughness, const in int maxMIPLevel ) {\n\t\tfloat maxMIPLevelScalar = float( maxMIPLevel );\n\t\tfloat sigma = PI * roughness * roughness / ( 1.0 + roughness );\n\t\tfloat desiredMIPLevel = maxMIPLevelScalar + log2( sigma );\n\t\treturn clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );\n\t}\n\tvec3 getLightProbeIndirectRadiance( const in vec3 viewDir, const in vec3 normal, const in float roughness, const in int maxMIPLevel ) {\n\t\t#ifdef ENVMAP_MODE_REFLECTION\n\t\t vec3 reflectVec = reflect( -viewDir, normal );\n\t\t reflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t vec3 reflectVec = refract( -viewDir, normal, refractionRatio );\n\t\t#endif\n\t\treflectVec = inverseTransformDirection( reflectVec, viewMatrix );\n\t\tfloat specularMIPLevel = getSpecularMIPLevel( roughness, 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, roughness );\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#ifdef ENV_WORLDPOS\n\t\tvWorldPosition = worldPosition.xyz;\n\t#else\n\t\tvec3 cameraToVertex;\n\t\tif ( isOrthographic ) { \n\t\t\tcameraToVertex = normalize( vec3( - viewMatrix[ 0 ][ 2 ], - viewMatrix[ 1 ][ 2 ], - viewMatrix[ 2 ][ 2 ] ) );\n\t\t} else {\n\t\t\tcameraToVertex = normalize( worldPosition.xyz - cameraPosition );\n\t\t}\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 = 1.0 - exp( - fogDensity * fogDensity * fogDepth * fogDepth );\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 = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( -mvPosition.xyz );\nGeometricContext backGeometry;\nbackGeometry.position = geometry.position;\nbackGeometry.normal = -geometry.normal;\nbackGeometry.viewDir = geometry.viewDir;\nvLightFront = vec3( 0.0 );\nvIndirectFront = vec3( 0.0 );\n#ifdef DOUBLE_SIDED\n\tvLightBack = vec3( 0.0 );\n\tvIndirectBack = 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\tvIndirectFront += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tvIndirectBack += getHemisphereLightIrradiance( hemisphereLights[ i ], backGeometry );\n\t\t#endif\n\t}\n#endif", +lights_pars_begin:"uniform bool receiveShadow;\nuniform vec3 ambientLightColor;\nuniform vec3 lightProbe[ 9 ];\nvec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {\n\tfloat x = normal.x, y = normal.y, z = normal.z;\n\tvec3 result = shCoefficients[ 0 ] * 0.886227;\n\tresult += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;\n\tresult += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;\n\tresult += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;\n\tresult += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;\n\tresult += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;\n\tresult += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );\n\tresult += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;\n\tresult += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );\n\treturn result;\n}\nvec3 getLightProbeIrradiance( const in vec3 lightProbe[ 9 ], const in GeometricContext geometry ) {\n\tvec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );\n\tvec3 irradiance = shGetIrradianceAt( worldNormal, lightProbe );\n\treturn irradiance;\n}\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 REFLECTIVITY\n\tmaterial.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor );\n#else\n\tmaterial.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor );\n#endif\n#ifdef CLEARCOAT\n\tmaterial.clearcoat = saturate( clearcoat );\tmaterial.clearcoatRoughness = clamp( clearcoatRoughness, 0.04, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif", +lights_physical_pars_fragment:"struct PhysicalMaterial {\n\tvec3\tdiffuseColor;\n\tfloat\tspecularRoughness;\n\tvec3\tspecularColor;\n#ifdef CLEARCOAT\n\tfloat clearcoat;\n\tfloat clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tvec3 sheenColor;\n#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#ifdef CLEARCOAT\n\t\tfloat ccDotNL = saturate( dot( geometry.clearcoatNormal, directLight.direction ) );\n\t\tvec3 ccIrradiance = ccDotNL * directLight.color;\n\t\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\t\tccIrradiance *= PI;\n\t\t#endif\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t\treflectedLight.directSpecular += ccIrradiance * material.clearcoat * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\t#ifdef USE_SHEEN\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_Sheen(\n\t\t\tmaterial.specularRoughness,\n\t\t\tdirectLight.direction,\n\t\t\tgeometry,\n\t\t\tmaterial.sheenColor\n\t\t);\n\t#else\n\t\treflectedLight.directSpecular += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Specular_GGX( directLight, geometry.viewDir, geometry.normal, material.specularColor, material.specularRoughness);\n\t#endif\n\treflectedLight.directDiffuse += ( 1.0 - clearcoatDHR ) * irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\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 irradiance, const in vec3 clearcoatRadiance, const in GeometricContext geometry, const in PhysicalMaterial material, inout ReflectedLight reflectedLight) {\n\t#ifdef CLEARCOAT\n\t\tfloat ccDotNV = saturate( dot( geometry.clearcoatNormal, geometry.viewDir ) );\n\t\treflectedLight.indirectSpecular += clearcoatRadiance * material.clearcoat * BRDF_Specular_GGX_Environment( geometry.viewDir, geometry.clearcoatNormal, vec3( DEFAULT_SPECULAR_COEFFICIENT ), material.clearcoatRoughness );\n\t\tfloat ccDotNL = ccDotNV;\n\t\tfloat clearcoatDHR = material.clearcoat * clearcoatDHRApprox( material.clearcoatRoughness, ccDotNL );\n\t#else\n\t\tfloat clearcoatDHR = 0.0;\n\t#endif\n\tfloat clearcoatInv = 1.0 - clearcoatDHR;\n\tvec3 singleScattering = vec3( 0.0 );\n\tvec3 multiScattering = vec3( 0.0 );\n\tvec3 cosineWeightedIrradiance = irradiance * RECIPROCAL_PI;\n\tBRDF_Specular_Multiscattering_Environment( geometry, material.specularColor, material.specularRoughness, singleScattering, multiScattering );\n\tvec3 diffuse = material.diffuseColor * ( 1.0 - ( singleScattering + multiScattering ) );\n\treflectedLight.indirectSpecular += clearcoatInv * radiance * singleScattering;\n\treflectedLight.indirectSpecular += multiScattering * cosineWeightedIrradiance;\n\treflectedLight.indirectDiffuse += diffuse * cosineWeightedIrradiance;\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\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 = ( isOrthographic ) ? vec3( 0, 0, 1 ) : normalize( vViewPosition );\n#ifdef CLEARCOAT\n\tgeometry.clearcoatNormal = clearcoatNormal;\n#endif\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#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_POINT_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( pointLight.shadow, directLight.visible, receiveShadow ) ) ? 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#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_SPOT_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( spotLight.shadow, directLight.visible, receiveShadow ) ) ? 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#if defined( USE_SHADOWMAP ) && ( UNROLLED_LOOP_INDEX < NUM_DIR_LIGHT_SHADOWS )\n\t\tdirectLight.color *= all( bvec3( directionalLight.shadow, directLight.visible, receiveShadow ) ) ? 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 iblIrradiance = vec3( 0.0 );\n\tvec3 irradiance = getAmbientLightIrradiance( ambientLightColor );\n\tirradiance += getLightProbeIrradiance( lightProbe, geometry );\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( STANDARD ) && defined( ENVMAP_TYPE_CUBE_UV )\n\t\tiblIrradiance += getLightProbeIndirectIrradiance( geometry, maxMipLevel );\n\t#endif\n#endif\n#if defined( USE_ENVMAP ) && defined( RE_IndirectSpecular )\n\tradiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.normal, material.specularRoughness, maxMipLevel );\n\t#ifdef CLEARCOAT\n\t\tclearcoatRadiance += getLightProbeIndirectRadiance( geometry.viewDir, geometry.clearcoatNormal, material.clearcoatRoughness, 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, iblIrradiance, clearcoatRadiance, geometry, material, reflectedLight );\n#endif",logdepthbuf_fragment:"#if defined( USE_LOGDEPTHBUF ) && defined( USE_LOGDEPTHBUF_EXT )\n\tgl_FragDepthEXT = vIsPerspective == 0.0 ? gl_FragCoord.z : 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\tvarying float vIsPerspective;\n#endif", +logdepthbuf_pars_vertex:"#ifdef USE_LOGDEPTHBUF\n\t#ifdef USE_LOGDEPTHBUF_EXT\n\t\tvarying float vFragDepth;\n\t\tvarying float vIsPerspective;\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\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\n\t#else\n\t\tif ( isPerspectiveMatrix( projectionMatrix ) ) {\n\t\t\tgl_Position.z = log2( max( EPSILON, gl_Position.w + 1.0 ) ) * logDepthBufFC - 1.0;\n\t\t\tgl_Position.z *= gl_Position.w;\n\t\t}\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:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tvec2 uv = ( uvTransform * vec3( gl_PointCoord.x, 1.0 - gl_PointCoord.y, 1 ) ).xy;\n#endif\n#ifdef USE_MAP\n\tvec4 mapTexel = texture2D( map, uv );\n\tdiffuseColor *= mapTexelToLinear( mapTexel );\n#endif\n#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, uv ).g;\n#endif", +map_particle_pars_fragment:"#if defined( USE_MAP ) || defined( USE_ALPHAMAP )\n\tuniform mat3 uvTransform;\n#endif\n#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif\n#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\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\t#ifdef USE_TANGENT\n\t\tvec3 tangent = normalize( vTangent );\n\t\tvec3 bitangent = normalize( vBitangent );\n\t\t#ifdef DOUBLE_SIDED\n\t\t\ttangent = tangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t\tbitangent = bitangent * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;", +normal_fragment_maps:"#ifdef OBJECTSPACE_NORMALMAP\n\tnormal = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t#ifdef FLIP_SIDED\n\t\tnormal = - normal;\n\t#endif\n\t#ifdef DOUBLE_SIDED\n\t\tnormal = normal * ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t#endif\n\tnormal = normalize( normalMatrix * normal );\n#elif defined( TANGENTSPACE_NORMALMAP )\n\t#ifdef USE_TANGENT\n\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = normalScale * mapN.xy;\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, normalScale, normalMap );\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#endif\n#ifdef OBJECTSPACE_NORMALMAP\n\tuniform mat3 normalMatrix;\n#endif\n#if ! defined ( USE_TANGENT ) && ( defined ( TANGENTSPACE_NORMALMAP ) || defined ( USE_CLEARCOAT_NORMALMAP ) )\n\tvec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm, vec2 normalScale, in sampler2D normalMap ) {\n\t\tvec3 q0 = vec3( dFdx( eye_pos.x ), dFdx( eye_pos.y ), dFdx( eye_pos.z ) );\n\t\tvec3 q1 = vec3( dFdy( eye_pos.x ), dFdy( eye_pos.y ), dFdy( eye_pos.z ) );\n\t\tvec2 st0 = dFdx( vUv.st );\n\t\tvec2 st1 = dFdy( vUv.st );\n\t\tfloat scale = sign( st1.t * st0.s - st0.t * st1.s );\n\t\tvec3 S = normalize( ( q0 * st1.t - q1 * st0.t ) * scale );\n\t\tvec3 T = normalize( ( - q0 * st1.s + q1 * st0.s ) * scale );\n\t\tvec3 N = normalize( surf_norm );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy *= normalScale;\n\t\t#ifdef DOUBLE_SIDED\n\t\t\tbool frontFacing = dot( cross( S, T ), N ) > 0.0;\n\t\t\tmapN.xy *= ( float( frontFacing ) * 2.0 - 1.0 );\n\t\t#else\n\t\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\t#endif\n\t\tmat3 tsn = mat3( S, T, N );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif", +clearcoat_normal_fragment_begin:"#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif",clearcoat_normal_fragment_maps:"#ifdef USE_CLEARCOAT_NORMALMAP\n\t#ifdef USE_TANGENT\n\t\tmat3 vTBN = mat3( tangent, bitangent, clearcoatNormal );\n\t\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\t\tmapN.xy = clearcoatNormalScale * mapN.xy;\n\t\tclearcoatNormal = normalize( vTBN * mapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatNormalScale, clearcoatNormalMap );\n\t#endif\n#endif", +clearcoat_normalmap_pars_fragment:"#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\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}\nvec4 encodeHalfRGBA ( vec2 v ) {\n\tvec4 encoded = vec4( 0.0 );\n\tconst vec2 offset = vec2( 1.0 / 255.0, 0.0 );\n\tencoded.xy = vec2( v.x, fract( v.x * 255.0 ) );\n\tencoded.xy = encoded.xy - ( encoded.yy * offset );\n\tencoded.zw = vec2( v.y, fract( v.y * 255.0 ) );\n\tencoded.zw = encoded.zw - ( encoded.ww * offset );\n\treturn encoded;\n}\nvec2 decodeHalfRGBA( vec4 v ) {\n\treturn vec2( v.x + ( v.y / 255.0 ), v.z + ( v.w / 255.0 ) );\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 = vec4( transformed, 1.0 );\n#ifdef USE_INSTANCING\n\tmvPosition = instanceMatrix * mvPosition;\n#endif\nmvPosition = modelViewMatrix * mvPosition;\ngl_Position = projectionMatrix * mvPosition;",dithering_fragment:"#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif",dithering_pars_fragment:"#ifdef 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_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n\tfloat texture2DCompare( sampler2D depths, vec2 uv, float compare ) {\n\t\treturn step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );\n\t}\n\tvec2 texture2DDistribution( sampler2D shadow, vec2 uv ) {\n\t\treturn decodeHalfRGBA( texture2D( shadow, uv ) );\n\t}\n\tfloat VSMShadow (sampler2D shadow, vec2 uv, float compare ){\n\t\tfloat occlusion = 1.0;\n\t\tvec2 distribution = texture2DDistribution( shadow, uv );\n\t\tfloat hard_shadow = step( compare , distribution.x );\n\t\tif (hard_shadow != 1.0 ) {\n\t\t\tfloat distance = compare - distribution.x ;\n\t\t\tfloat variance = max( 0.00000, distribution.y * distribution.y );\n\t\t\tfloat softness_probability = variance / (variance + distance * distance );\t\t\tsoftness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 );\t\t\tocclusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 );\n\t\t}\n\t\treturn occlusion;\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 ) + 0.5 ) * texelSize;\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\tfloat dx2 = dx0 / 2.0;\n\t\t\tfloat dy2 = dy0 / 2.0;\n\t\t\tfloat dx3 = dx1 / 2.0;\n\t\t\tfloat dy3 = dy1 / 2.0;\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( dx2, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), 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( dx2, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), 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 / 17.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#elif defined( SHADOWMAP_TYPE_VSM )\n\t\t\tshadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z );\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 ) || defined( SHADOWMAP_TYPE_VSM )\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_LIGHT_SHADOWS > 0\n\t\tuniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ];\n\t\tvarying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ];\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t\tuniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ];\n\t\tvarying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif", +shadowmap_vertex:"#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * worldPosition;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; 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_LIGHT_SHADOWS > 0\n\tDirectionalLight directionalLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLights[ i ];\n\t\tshadow *= all( bvec2( directionalLight.shadow, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLight spotLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLights[ i ];\n\t\tshadow *= all( bvec2( spotLight.shadow, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLight pointLight;\n\t#pragma unroll_loop\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLights[ i ];\n\t\tshadow *= all( bvec2( pointLight.shadow, receiveShadow ) ) ? 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 highp 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\t#ifdef USE_TANGENT\n\t\tobjectTangent = vec4( skinMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#endif\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\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif",tonemapping_pars_fragment:"#ifndef saturate\n#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_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif",uv_pars_vertex:"#ifdef USE_UV\n\t#ifdef UVS_VERTEX_ONLY\n\t\tvec2 vUv;\n\t#else\n\t\tvarying vec2 vUv;\n\t#endif\n\tuniform mat3 uvTransform;\n#endif",uv_vertex:"#ifdef USE_UV\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 = vec4( transformed, 1.0 );\n\t#ifdef USE_INSTANCING\n\t\tworldPosition = instanceMatrix * worldPosition;\n\t#endif\n\tworldPosition = modelMatrix * worldPosition;\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 \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;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\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 \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#ifdef DOUBLE_SIDED\n\t\treflectedLight.indirectDiffuse += ( gl_FrontFacing ) ? vIndirectFront : vIndirectBack;\n\t#else\n\t\treflectedLight.indirectDiffuse += vIndirectFront;\n\t#endif\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;\nvarying vec3 vIndirectFront;\n#ifdef DOUBLE_SIDED\n\tvarying vec3 vLightBack;\n\tvarying vec3 vIndirectBack;\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 \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#ifndef FLAT_SHADED\n\t\tvNormal = normalize( transformedNormal );\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\tvViewPosition = - mvPosition.xyz;\n}", +meshphong_frag:"#define PHONG\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform vec3 specular;\nuniform float shininess;\nuniform float opacity;\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 \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\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + 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}", +meshphong_vert:"#define PHONG\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 \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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshphysical_frag:"#define STANDARD\n#ifdef PHYSICAL\n\t#define REFLECTIVITY\n\t#define CLEARCOAT\n\t#define TRANSPARENCY\n#endif\nuniform vec3 diffuse;\nuniform vec3 emissive;\nuniform float roughness;\nuniform float metalness;\nuniform float opacity;\n#ifdef TRANSPARENCY\n\tuniform float transparency;\n#endif\n#ifdef REFLECTIVITY\n\tuniform float reflectivity;\n#endif\n#ifdef CLEARCOAT\n\tuniform float clearcoat;\n\tuniform float clearcoatRoughness;\n#endif\n#ifdef USE_SHEEN\n\tuniform vec3 sheen;\n#endif\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\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 \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\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\tvec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance;\n\t#ifdef TRANSPARENCY\n\t\tdiffuseColor.a *= saturate( 1. - transparency + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) );\n\t#endif\n\tgl_FragColor = vec4( outgoingLight, diffuseColor.a );\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +meshphysical_vert:"#define STANDARD\nvarying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\tvViewPosition = - mvPosition.xyz;\n\t#include \n\t#include \n\t#include \n}", +normal_frag:"#define NORMAL\nuniform float opacity;\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\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\tgl_FragColor = vec4( packNormalToRGB( normal ), opacity );\n}", +normal_vert:"#define NORMAL\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvarying vec3 vViewPosition;\n#endif\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n\t#ifdef USE_TANGENT\n\t\tvarying vec3 vTangent;\n\t\tvarying vec3 vBitangent;\n\t#endif\n#endif\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#ifndef FLAT_SHADED\n\tvNormal = normalize( transformedNormal );\n\t#ifdef USE_TANGENT\n\t\tvTangent = normalize( transformedTangent );\n\t\tvBitangent = normalize( cross( vNormal, vTangent ) * tangent.w );\n\t#endif\n#endif\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( TANGENTSPACE_NORMALMAP )\n\tvViewPosition = - mvPosition.xyz;\n#endif\n}", +points_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \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}", +points_vert:"uniform float size;\nuniform float scale;\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\tgl_PointSize = size;\n\t#ifdef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) gl_PointSize *= ( scale / - mvPosition.z );\n\t#endif\n\t#include \n\t#include \n\t#include \n\t#include \n}", +shadow_frag:"uniform vec3 color;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tgl_FragColor = vec4( color, opacity * ( 1.0 - getShadowMask() ) );\n\t#include \n}",shadow_vert:"#include \n#include \nvoid main() {\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}", +sprite_frag:"uniform vec3 diffuse;\nuniform float opacity;\n#include \n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec3 outgoingLight = vec3( 0.0 );\n\tvec4 diffuseColor = vec4( diffuse, opacity );\n\t#include \n\t#include \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}", +sprite_vert:"uniform float rotation;\nuniform vec2 center;\n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\t#include \n\tvec4 mvPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );\n\tvec2 scale;\n\tscale.x = length( vec3( modelMatrix[ 0 ].x, modelMatrix[ 0 ].y, modelMatrix[ 0 ].z ) );\n\tscale.y = length( vec3( modelMatrix[ 1 ].x, modelMatrix[ 1 ].y, modelMatrix[ 1 ].z ) );\n\t#ifndef USE_SIZEATTENUATION\n\t\tbool isPerspective = isPerspectiveMatrix( projectionMatrix );\n\t\tif ( isPerspective ) scale *= - mvPosition.z;\n\t#endif\n\tvec2 alignedPosition = ( position.xy - ( center - vec2( 0.5 ) ) ) * scale;\n\tvec2 rotatedPosition;\n\trotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;\n\trotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;\n\tmvPosition.xy += rotatedPosition;\n\tgl_Position = projectionMatrix * mvPosition;\n\t#include \n\t#include \n\t#include \n}"}, +K={common:{diffuse:{value:new D(15658734)},opacity:{value:1},map:{value:null},uvTransform:{value:new ka},alphaMap:{value:null}},specularmap:{specularMap:{value:null}},envmap:{envMap:{value:null},flipEnvMap:{value:-1},reflectivity:{value:1},refractionRatio:{value:.98},maxMipLevel:{value:0}},aomap:{aoMap:{value:null},aoMapIntensity:{value:1}},lightmap:{lightMap:{value:null},lightMapIntensity:{value:1}},emissivemap:{emissiveMap:{value:null}},bumpmap:{bumpMap:{value:null},bumpScale:{value:1}},normalmap:{normalMap:{value:null}, +normalScale:{value:new z(1,1)}},displacementmap:{displacementMap:{value:null},displacementScale:{value:1},displacementBias:{value:0}},roughnessmap:{roughnessMap:{value:null}},metalnessmap:{metalnessMap:{value:null}},gradientmap:{gradientMap:{value:null}},fog:{fogDensity:{value:2.5E-4},fogNear:{value:1},fogFar:{value:2E3},fogColor:{value:new D(16777215)}},lights:{ambientLightColor:{value:[]},lightProbe:{value:[]},directionalLights:{value:[],properties:{direction:{},color:{},shadow:{},shadowBias:{}, +shadowRadius:{},shadowMapSize:{}}},directionalShadowMap:{value:[]},directionalShadowMatrix:{value:[]},spotLights:{value:[],properties:{color:{},position:{},direction:{},distance:{},coneCos:{},penumbraCos:{},decay:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{}}},spotShadowMap:{value:[]},spotShadowMatrix:{value:[]},pointLights:{value:[],properties:{color:{},position:{},decay:{},distance:{},shadow:{},shadowBias:{},shadowRadius:{},shadowMapSize:{},shadowCameraNear:{},shadowCameraFar:{}}}, +pointShadowMap:{value:[]},pointShadowMatrix:{value:[]},hemisphereLights:{value:[],properties:{direction:{},skyColor:{},groundColor:{}}},rectAreaLights:{value:[],properties:{color:{},position:{},width:{},height:{}}}},points:{diffuse:{value:new D(15658734)},opacity:{value:1},size:{value:1},scale:{value:1},map:{value:null},alphaMap:{value:null},uvTransform:{value:new ka}},sprite:{diffuse:{value:new D(15658734)},opacity:{value:1},center:{value:new z(.5,.5)},rotation:{value:0},map:{value:null},alphaMap:{value:null}, +uvTransform:{value:new ka}}},ib={basic:{uniforms:za([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.fog]),vertexShader:Q.meshbasic_vert,fragmentShader:Q.meshbasic_frag},lambert:{uniforms:za([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.fog,K.lights,{emissive:{value:new D(0)}}]),vertexShader:Q.meshlambert_vert,fragmentShader:Q.meshlambert_frag},phong:{uniforms:za([K.common,K.specularmap,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.bumpmap,K.normalmap,K.displacementmap,K.gradientmap, +K.fog,K.lights,{emissive:{value:new D(0)},specular:{value:new D(1118481)},shininess:{value:30}}]),vertexShader:Q.meshphong_vert,fragmentShader:Q.meshphong_frag},standard:{uniforms:za([K.common,K.envmap,K.aomap,K.lightmap,K.emissivemap,K.bumpmap,K.normalmap,K.displacementmap,K.roughnessmap,K.metalnessmap,K.fog,K.lights,{emissive:{value:new D(0)},roughness:{value:.5},metalness:{value:.5},envMapIntensity:{value:1}}]),vertexShader:Q.meshphysical_vert,fragmentShader:Q.meshphysical_frag},matcap:{uniforms:za([K.common, +K.bumpmap,K.normalmap,K.displacementmap,K.fog,{matcap:{value:null}}]),vertexShader:Q.meshmatcap_vert,fragmentShader:Q.meshmatcap_frag},points:{uniforms:za([K.points,K.fog]),vertexShader:Q.points_vert,fragmentShader:Q.points_frag},dashed:{uniforms:za([K.common,K.fog,{scale:{value:1},dashSize:{value:1},totalSize:{value:2}}]),vertexShader:Q.linedashed_vert,fragmentShader:Q.linedashed_frag},depth:{uniforms:za([K.common,K.displacementmap]),vertexShader:Q.depth_vert,fragmentShader:Q.depth_frag},normal:{uniforms:za([K.common, +K.bumpmap,K.normalmap,K.displacementmap,{opacity:{value:1}}]),vertexShader:Q.normal_vert,fragmentShader:Q.normal_frag},sprite:{uniforms:za([K.sprite,K.fog]),vertexShader:Q.sprite_vert,fragmentShader:Q.sprite_frag},background:{uniforms:{uvTransform:{value:new ka},t2D:{value:null}},vertexShader:Q.background_vert,fragmentShader:Q.background_frag},cube:{uniforms:{tCube:{value:null},tFlip:{value:-1},opacity:{value:1}},vertexShader:Q.cube_vert,fragmentShader:Q.cube_frag},equirect:{uniforms:{tEquirect:{value:null}}, +vertexShader:Q.equirect_vert,fragmentShader:Q.equirect_frag},distanceRGBA:{uniforms:za([K.common,K.displacementmap,{referencePosition:{value:new q},nearDistance:{value:1},farDistance:{value:1E3}}]),vertexShader:Q.distanceRGBA_vert,fragmentShader:Q.distanceRGBA_frag},shadow:{uniforms:za([K.lights,K.fog,{color:{value:new D(0)},opacity:{value:1}}]),vertexShader:Q.shadow_vert,fragmentShader:Q.shadow_frag}};ib.physical={uniforms:za([ib.standard.uniforms,{transparency:{value:0},clearcoat:{value:0},clearcoatRoughness:{value:0}, +sheen:{value:new D(0)},clearcoatNormalScale:{value:new z(1,1)},clearcoatNormalMap:{value:null}}]),vertexShader:Q.meshphysical_vert,fragmentShader:Q.meshphysical_frag};Td.prototype=Object.create(P.prototype);Td.prototype.constructor=Td;ic.prototype=Object.create(G.prototype);ic.prototype.constructor=ic;vb.prototype=Object.create(S.prototype);vb.prototype.constructor=vb;vb.prototype.isCubeTexture=!0;Object.defineProperty(vb.prototype,"images",{get:function(){return this.image},set:function(a){this.image= +a}});Rc.prototype=Object.create(S.prototype);Rc.prototype.constructor=Rc;Rc.prototype.isDataTexture2DArray=!0;Sc.prototype=Object.create(S.prototype);Sc.prototype.constructor=Sc;Sc.prototype.isDataTexture3D=!0;var gi=new S,ok=new Rc,qk=new Sc,hi=new vb,ai=[],ci=[],fi=new Float32Array(16),ei=new Float32Array(9),di=new Float32Array(4);ii.prototype.updateCache=function(a){var b=this.cache;a instanceof Float32Array&&b.length!==a.length&&(this.cache=new Float32Array(a.length));Ja(b,a)};ji.prototype.setValue= +function(a,b,c){for(var d=this.seq,f=0,g=d.length;f!==g;++f){var k=d[f];k.setValue(a,b[k.id],c)}};var Ag=/([\w\d_]+)(\])?(\[|\.)?/g;Jb.prototype.setValue=function(a,b,c,d){b=this.map[b];void 0!==b&&b.setValue(a,c,d)};Jb.prototype.setOptional=function(a,b,c){b=b[c];void 0!==b&&this.setValue(a,c,b)};Jb.upload=function(a,b,c,d){for(var f=0,g=b.length;f!==g;++f){var k=b[f],m=c[k.id];!1!==m.needsUpdate&&k.setValue(a,m.value,d)}};Jb.seqWithValue=function(a,b){for(var c=[],d=0,f=a.length;d!==f;++d){var g= +a[d];g.id in b&&c.push(g)}return c};var Vk=0,Cg=/^[ \t]*#include +<([\w\d./]+)>/gm,ri=/#pragma unroll_loop[\s]+?for \( int i = (\d+); i < (\d+); i \+\+ \) \{([\s\S]+?)(?=\})\}/g,dl=0;Kb.prototype=Object.create(R.prototype);Kb.prototype.constructor=Kb;Kb.prototype.isMeshDepthMaterial=!0;Kb.prototype.copy=function(a){R.prototype.copy.call(this,a);this.depthPacking=a.depthPacking;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap; +this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;return this};Lb.prototype=Object.create(R.prototype);Lb.prototype.constructor=Lb;Lb.prototype.isMeshDistanceMaterial=!0;Lb.prototype.copy=function(a){R.prototype.copy.call(this,a);this.referencePosition.copy(a.referencePosition);this.nearDistance=a.nearDistance;this.farDistance=a.farDistance;this.skinning=a.skinning;this.morphTargets=a.morphTargets; +this.map=a.map;this.alphaMap=a.alphaMap;this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;return this};Fg.prototype=Object.assign(Object.create(sa.prototype),{constructor:Fg,isWebGLMultiviewRenderTarget:!0,copy:function(a){sa.prototype.copy.call(this,a);this.numViews=a.numViews;return this},setNumViews:function(a){this.numViews!==a&&(this.numViews=a,this.dispose());return this}});Vc.prototype=Object.assign(Object.create(E.prototype), +{constructor:Vc,isGroup:!0});Yd.prototype=Object.assign(Object.create(na.prototype),{constructor:Yd,isArrayCamera:!0});var yi=new q,zi=new q;Object.assign(Gg.prototype,Ra.prototype);Object.assign(Ai.prototype,Ra.prototype);Object.assign(cf.prototype,{isFogExp2:!0,clone:function(){return new cf(this.color,this.density)},toJSON:function(){return{type:"FogExp2",color:this.color.getHex(),density:this.density}}});Object.assign(df.prototype,{isFog:!0,clone:function(){return new df(this.color,this.near, +this.far)},toJSON:function(){return{type:"Fog",color:this.color.getHex(),near:this.near,far:this.far}}});Object.defineProperty(wb.prototype,"needsUpdate",{set:function(a){!0===a&&this.version++}});Object.assign(wb.prototype,{isInterleavedBuffer:!0,onUploadCallback:function(){},setUsage:function(a){this.usage=a;return this},copy:function(a){this.array=new a.array.constructor(a.array);this.count=a.count;this.stride=a.stride;this.usage=a.usage;return this},copyAt:function(a,b,c){a*=this.stride;c*=b.stride; +for(var d=0,f=this.stride;da.far||b.push({distance:f,point:Qe.clone(),uv:va.getUV(Qe,Zf,Re,$f,qj,Fh,rj,new z),face:null,object:this})},clone:function(){return(new this.constructor(this.material)).copy(this)}, +copy:function(a){E.prototype.copy.call(this,a);void 0!==a.center&&this.center.copy(a.center);return this}});var ag=new q,sj=new q;be.prototype=Object.assign(Object.create(E.prototype),{constructor:be,isLOD:!0,copy:function(a){E.prototype.copy.call(this,a,!1);a=a.levels;for(var b=0,c=a.length;b=b[c].distance)b[c-1].object.visible=!1,b[c].object.visible=!0;else break;for(;cc||(m.applyMatrix4(this.matrixWorld),r=a.ray.origin.distanceTo(m),ra.far||b.push({distance:r,point:f.clone().applyMatrix4(this.matrixWorld),index:d,face:null,faceIndex:null,object:this}))}}else for(d=0,t=y.length/3-1;dc||(m.applyMatrix4(this.matrixWorld),r=a.ray.origin.distanceTo(m),ra.far||b.push({distance:r,point:f.clone().applyMatrix4(this.matrixWorld), +index:d,face:null,faceIndex:null,object:this}))}else if(d.isGeometry)for(g=d.vertices,k=g.length,d=0;dc||(m.applyMatrix4(this.matrixWorld),r=a.ray.origin.distanceTo(m),ra.far||b.push({distance:r,point:f.clone().applyMatrix4(this.matrixWorld),index:d,face:null,faceIndex:null,object:this}))}},clone:function(){return(new this.constructor(this.geometry,this.material)).copy(this)}});var cg=new q,dg=new q;Z.prototype=Object.assign(Object.create(pa.prototype), +{constructor:Z,isLineSegments:!0,computeLineDistances:function(){var a=this.geometry;if(a.isBufferGeometry)if(null===a.index){for(var b=a.attributes.position,c=[],d=0,f=b.count;d= +a.HAVE_CURRENT_DATA&&(this.needsUpdate=!0)}});Zc.prototype=Object.create(S.prototype);Zc.prototype.constructor=Zc;Zc.prototype.isCompressedTexture=!0;de.prototype=Object.create(S.prototype);de.prototype.constructor=de;de.prototype.isCanvasTexture=!0;ee.prototype=Object.create(S.prototype);ee.prototype.constructor=ee;ee.prototype.isDepthTexture=!0;$c.prototype=Object.create(G.prototype);$c.prototype.constructor=$c;fe.prototype=Object.create(P.prototype);fe.prototype.constructor=fe;ad.prototype=Object.create(G.prototype); +ad.prototype.constructor=ad;ge.prototype=Object.create(P.prototype);ge.prototype.constructor=ge;Fa.prototype=Object.create(G.prototype);Fa.prototype.constructor=Fa;he.prototype=Object.create(P.prototype);he.prototype.constructor=he;bd.prototype=Object.create(Fa.prototype);bd.prototype.constructor=bd;ie.prototype=Object.create(P.prototype);ie.prototype.constructor=ie;lc.prototype=Object.create(Fa.prototype);lc.prototype.constructor=lc;je.prototype=Object.create(P.prototype);je.prototype.constructor= +je;cd.prototype=Object.create(Fa.prototype);cd.prototype.constructor=cd;ke.prototype=Object.create(P.prototype);ke.prototype.constructor=ke;dd.prototype=Object.create(Fa.prototype);dd.prototype.constructor=dd;le.prototype=Object.create(P.prototype);le.prototype.constructor=le;mc.prototype=Object.create(G.prototype);mc.prototype.constructor=mc;mc.prototype.toJSON=function(){var a=G.prototype.toJSON.call(this);a.path=this.parameters.path.toJSON();return a};me.prototype=Object.create(P.prototype);me.prototype.constructor= +me;ed.prototype=Object.create(G.prototype);ed.prototype.constructor=ed;ne.prototype=Object.create(P.prototype);ne.prototype.constructor=ne;fd.prototype=Object.create(G.prototype);fd.prototype.constructor=fd;var Ml={triangulate:function(a,b,c){c=c||2;var d=b&&b.length,f=d?b[0]*c:a.length,g=Di(a,0,f,c,!0),k=[];if(!g||g.next===g.prev)return k;var m;if(d){var l=c;d=[];var p;var q=0;for(p=b.length;q80*c){var u=m=a[0];var v=d=a[1];for(l=c;lm&&(m=q),b>d&&(d=b);m=Math.max(m-u,d-v);m=0!==m?1/m:0}qe(g,k,c,u,v,m);return k}},xb={area:function(a){for(var b=a.length,c=0,d=b-1,f=0;fxb.area(a)},triangulateShape:function(a,b){var c=[],d=[],f=[];Hi(a);Ii(c,a);var g=a.length;b.forEach(Hi); +for(a=0;aMath.abs(k-l)?[new z(a,1-c),new z(m,1-d),new z(p,1-f),new z(t,1-b)]:[new z(k,1-c),new z(l,1-d),new z(q,1-f),new z(r,1-b)]}};se.prototype=Object.create(P.prototype); +se.prototype.constructor=se;hd.prototype=Object.create(jb.prototype);hd.prototype.constructor=hd;te.prototype=Object.create(P.prototype);te.prototype.constructor=te;Ob.prototype=Object.create(G.prototype);Ob.prototype.constructor=Ob;ue.prototype=Object.create(P.prototype);ue.prototype.constructor=ue;id.prototype=Object.create(G.prototype);id.prototype.constructor=id;ve.prototype=Object.create(P.prototype);ve.prototype.constructor=ve;jd.prototype=Object.create(G.prototype);jd.prototype.constructor= +jd;pc.prototype=Object.create(P.prototype);pc.prototype.constructor=pc;pc.prototype.toJSON=function(){var a=P.prototype.toJSON.call(this);return Ki(this.parameters.shapes,a)};qc.prototype=Object.create(G.prototype);qc.prototype.constructor=qc;qc.prototype.toJSON=function(){var a=G.prototype.toJSON.call(this);return Ki(this.parameters.shapes,a)};kd.prototype=Object.create(G.prototype);kd.prototype.constructor=kd;rc.prototype=Object.create(P.prototype);rc.prototype.constructor=rc;yb.prototype=Object.create(G.prototype); +yb.prototype.constructor=yb;we.prototype=Object.create(rc.prototype);we.prototype.constructor=we;xe.prototype=Object.create(yb.prototype);xe.prototype.constructor=xe;ye.prototype=Object.create(P.prototype);ye.prototype.constructor=ye;ld.prototype=Object.create(G.prototype);ld.prototype.constructor=ld;var Ba=Object.freeze({__proto__:null,WireframeGeometry:$c,ParametricGeometry:fe,ParametricBufferGeometry:ad,TetrahedronGeometry:he,TetrahedronBufferGeometry:bd,OctahedronGeometry:ie,OctahedronBufferGeometry:lc, +IcosahedronGeometry:je,IcosahedronBufferGeometry:cd,DodecahedronGeometry:ke,DodecahedronBufferGeometry:dd,PolyhedronGeometry:ge,PolyhedronBufferGeometry:Fa,TubeGeometry:le,TubeBufferGeometry:mc,TorusKnotGeometry:me,TorusKnotBufferGeometry:ed,TorusGeometry:ne,TorusBufferGeometry:fd,TextGeometry:se,TextBufferGeometry:hd,SphereGeometry:te,SphereBufferGeometry:Ob,RingGeometry:ue,RingBufferGeometry:id,PlaneGeometry:Td,PlaneBufferGeometry:ic,LatheGeometry:ve,LatheBufferGeometry:jd,ShapeGeometry:pc,ShapeBufferGeometry:qc, +ExtrudeGeometry:oc,ExtrudeBufferGeometry:jb,EdgesGeometry:kd,ConeGeometry:we,ConeBufferGeometry:xe,CylinderGeometry:rc,CylinderBufferGeometry:yb,CircleGeometry:ye,CircleBufferGeometry:ld,BoxGeometry:Eh,BoxBufferGeometry:Ud});sc.prototype=Object.create(R.prototype);sc.prototype.constructor=sc;sc.prototype.isShadowMaterial=!0;sc.prototype.copy=function(a){R.prototype.copy.call(this,a);this.color.copy(a.color);return this};md.prototype=Object.create(Aa.prototype);md.prototype.constructor=md;md.prototype.isRawShaderMaterial= +!0;kb.prototype=Object.create(R.prototype);kb.prototype.constructor=kb;kb.prototype.isMeshStandardMaterial=!0;kb.prototype.copy=function(a){R.prototype.copy.call(this,a);this.defines={STANDARD:""};this.color.copy(a.color);this.roughness=a.roughness;this.metalness=a.metalness;this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity; +this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.roughnessMap=a.roughnessMap;this.metalnessMap=a.metalnessMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.envMapIntensity=a.envMapIntensity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth= +a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};tc.prototype=Object.create(kb.prototype);tc.prototype.constructor=tc;tc.prototype.isMeshPhysicalMaterial=!0;tc.prototype.copy=function(a){kb.prototype.copy.call(this,a);this.defines={STANDARD:"",PHYSICAL:""};this.reflectivity=a.reflectivity;this.clearcoat=a.clearcoat;this.clearcoatRoughness= +a.clearcoatRoughness;this.sheen=a.sheen?(this.sheen||new D).copy(a.sheen):null;this.clearcoatNormalMap=a.clearcoatNormalMap;this.clearcoatNormalScale.copy(a.clearcoatNormalScale);this.transparency=a.transparency;return this};Wa.prototype=Object.create(R.prototype);Wa.prototype.constructor=Wa;Wa.prototype.isMeshPhongMaterial=!0;Wa.prototype.copy=function(a){R.prototype.copy.call(this,a);this.color.copy(a.color);this.specular.copy(a.specular);this.shininess=a.shininess;this.map=a.map;this.lightMap= +a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap=a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.specularMap= +a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};uc.prototype=Object.create(Wa.prototype);uc.prototype.constructor=uc;uc.prototype.isMeshToonMaterial= +!0;uc.prototype.copy=function(a){Wa.prototype.copy.call(this,a);this.gradientMap=a.gradientMap;return this};vc.prototype=Object.create(R.prototype);vc.prototype.constructor=vc;vc.prototype.isMeshNormalMaterial=!0;vc.prototype.copy=function(a){R.prototype.copy.call(this,a);this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap;this.displacementScale=a.displacementScale; +this.displacementBias=a.displacementBias;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};wc.prototype=Object.create(R.prototype);wc.prototype.constructor=wc;wc.prototype.isMeshLambertMaterial=!0;wc.prototype.copy=function(a){R.prototype.copy.call(this,a);this.color.copy(a.color);this.map=a.map;this.lightMap=a.lightMap;this.lightMapIntensity=a.lightMapIntensity;this.aoMap= +a.aoMap;this.aoMapIntensity=a.aoMapIntensity;this.emissive.copy(a.emissive);this.emissiveMap=a.emissiveMap;this.emissiveIntensity=a.emissiveIntensity;this.specularMap=a.specularMap;this.alphaMap=a.alphaMap;this.envMap=a.envMap;this.combine=a.combine;this.reflectivity=a.reflectivity;this.refractionRatio=a.refractionRatio;this.wireframe=a.wireframe;this.wireframeLinewidth=a.wireframeLinewidth;this.wireframeLinecap=a.wireframeLinecap;this.wireframeLinejoin=a.wireframeLinejoin;this.skinning=a.skinning; +this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};xc.prototype=Object.create(R.prototype);xc.prototype.constructor=xc;xc.prototype.isMeshMatcapMaterial=!0;xc.prototype.copy=function(a){R.prototype.copy.call(this,a);this.defines={MATCAP:""};this.color.copy(a.color);this.matcap=a.matcap;this.map=a.map;this.bumpMap=a.bumpMap;this.bumpScale=a.bumpScale;this.normalMap=a.normalMap;this.normalMapType=a.normalMapType;this.normalScale.copy(a.normalScale);this.displacementMap=a.displacementMap; +this.displacementScale=a.displacementScale;this.displacementBias=a.displacementBias;this.alphaMap=a.alphaMap;this.skinning=a.skinning;this.morphTargets=a.morphTargets;this.morphNormals=a.morphNormals;return this};yc.prototype=Object.create(T.prototype);yc.prototype.constructor=yc;yc.prototype.isLineDashedMaterial=!0;yc.prototype.copy=function(a){T.prototype.copy.call(this,a);this.scale=a.scale;this.dashSize=a.dashSize;this.gapSize=a.gapSize;return this};var Nl=Object.freeze({__proto__:null,ShadowMaterial:sc, +SpriteMaterial:Nb,RawShaderMaterial:md,ShaderMaterial:Aa,PointsMaterial:Va,MeshPhysicalMaterial:tc,MeshStandardMaterial:kb,MeshPhongMaterial:Wa,MeshToonMaterial:uc,MeshNormalMaterial:vc,MeshLambertMaterial:wc,MeshDepthMaterial:Kb,MeshDistanceMaterial:Lb,MeshBasicMaterial:Ia,MeshMatcapMaterial:xc,LineDashedMaterial:yc,LineBasicMaterial:T,Material:R}),aa={arraySlice:function(a,b,c){return aa.isTypedArray(a)?new a.constructor(a.subarray(b,void 0!==c?c:a.length)):a.slice(b,c)},convertArray:function(a, +b,c){return!a||!c&&a.constructor===b?a:"number"===typeof b.BYTES_PER_ELEMENT?new b(a):Array.prototype.slice.call(a)},isTypedArray:function(a){return ArrayBuffer.isView(a)&&!(a instanceof DataView)},getKeyframeOrder:function(a){for(var b=a.length,c=Array(b),d=0;d!==b;++d)c[d]=d;c.sort(function(b,c){return a[b]-a[c]});return c},sortedArray:function(a,b,c){for(var d=a.length,f=new a.constructor(d),g=0,k=0;k!==d;++g)for(var m=c[g]*b,l=0;l!==b;++l)f[k++]=a[m+l];return f},flattenJSON:function(a,b,c,d){for(var f= +1,g=a[0];void 0!==g&&void 0===g[d];)g=a[f++];if(void 0!==g){var k=g[d];if(void 0!==k)if(Array.isArray(k)){do k=g[d],void 0!==k&&(b.push(g.time),c.push.apply(c,k)),g=a[f++];while(void 0!==g)}else if(void 0!==k.toArray){do k=g[d],void 0!==k&&(b.push(g.time),k.toArray(c,c.length)),g=a[f++];while(void 0!==g)}else{do k=g[d],void 0!==k&&(b.push(g.time),c.push(k)),g=a[f++];while(void 0!==g)}}},subclip:function(a,b,c,d,f){f=f||30;a=a.clone();a.name=b;var g=[];for(b=0;b=d))for(l.push(k.times[q]),t=0;ta.tracks[b].times[0]&&(c=a.tracks[b].times[0]);for(b=0;b=f)break a;else{g=b[1];a=f)break b}d=c;c=0}}for(;c>>1,ab;)--g;++g;if(0!==f||g!==d)f>=g&&(g=Math.max(g,1),f=g-1),a=this.getValueSize(),this.times=aa.arraySlice(c,f,g),this.values=aa.arraySlice(this.values,f*a,g*a);return this},validate:function(){var a=!0,b=this.getValueSize();0!==b-Math.floor(b)&&(console.error("THREE.KeyframeTrack: Invalid value size in track.",this),a=!1);var c=this.times; +b=this.values;var d=c.length;0===d&&(console.error("THREE.KeyframeTrack: Track is empty.",this),a=!1);for(var f=null,g=0;g!==d;g++){var k=c[g];if("number"===typeof k&&isNaN(k)){console.error("THREE.KeyframeTrack: Time is not a valid number.",this,g,k);a=!1;break}if(null!==f&&f>k){console.error("THREE.KeyframeTrack: Out of order keys.",this,g,k,f);a=!1;break}f=k}if(void 0!==b&&aa.isTypedArray(b))for(g=0,c=b.length;g!==c;++g)if(d=b[g],isNaN(d)){console.error("THREE.KeyframeTrack: Value is not a valid number.", +this,g,d);a=!1;break}return a},optimize:function(){for(var a=this.times,b=this.values,c=this.getValueSize(),d=2302===this.getInterpolation(),f=1,g=a.length-1,k=1;kk)f=a+1;else if(0b&&(b=0);1Number.EPSILON&&(k.normalize(),c=Math.acos(N.clamp(d[l-1].dot(d[l]),-1,1)),f[l].applyMatrix4(m.makeRotationAxis(k,c))),g[l].crossVectors(d[l],f[l]);if(!0===b)for(c=Math.acos(N.clamp(f[0].dot(f[a]),-1,1)),c/=a,0d;)d+=c;for(;d>c;)d-=c;df&&(f=1);1E-4>d&&(d=f);1E-4>l&&(l=f);Gh.initNonuniformCatmullRom(g.x,k.x,m.x,c.x,d,f,l);Hh.initNonuniformCatmullRom(g.y,k.y,m.y,c.y,d,f,l);Ih.initNonuniformCatmullRom(g.z,k.z,m.z,c.z,d,f,l)}else"catmullrom"===this.curveType&&(Gh.initCatmullRom(g.x,k.x,m.x,c.x,this.tension),Hh.initCatmullRom(g.y,k.y,m.y,c.y,this.tension),Ih.initCatmullRom(g.z,k.z,m.z,c.z,this.tension));b.set(Gh.calc(a), +Hh.calc(a),Ih.calc(a));return b};la.prototype.copy=function(a){M.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;bc.length-2?c.length-1:a+1];c=c[a>c.length-3?c.length-1:a+2];b.set(Mi(d,f.x,g.x,k.x,c.x),Mi(d,f.y,g.y,k.y,c.y));return b};$a.prototype.copy=function(a){M.prototype.copy.call(this,a);this.points=[];for(var b=0,c=a.points.length;b=b)return b=c[a]-b,a=this.curves[a],c=a.getLength(),a.getPointAt(0===c?0:1-b/c);a++}return null},getLength:function(){var a= +this.getCurveLengths();return a[a.length-1]},updateArcLengths:function(){this.needsUpdate=!0;this.cacheLengths=null;this.getCurveLengths()},getCurveLengths:function(){if(this.cacheLengths&&this.cacheLengths.length===this.curves.length)return this.cacheLengths;for(var a=[],b=0,c=0,d=this.curves.length;cNumber.EPSILON){if(0>n&&(k=b[g],l=-l,m=b[f],n=-n),!(a.ym.y))if(a.y===k.y){if(a.x===k.x)return!0}else{f=n*(a.x-k.x)-l*(a.y-k.y);if(0===f)return!0;0>f||(d=!d)}}else if(a.y===k.y&&(m.x<=a.x&&a.x<=k.x||k.x<=a.x&&a.x<=m.x))return!0}return d} +var f=xb.isClockWise,g=this.subPaths;if(0===g.length)return[];if(!0===b)return c(g);b=[];if(1===g.length){var k=g[0];var m=new Pb;m.curves=k.curves;b.push(m);return b}var l=!f(g[0].getPoints());l=a?!l:l;m=[];var p=[],q=[],t=0;p[t]=void 0;q[t]=[];for(var r=0,u=g.length;rb;b++)this.coefficients[b].copy(a[b]);return this},zero:function(){for(var a=0;9>a;a++)this.coefficients[a].set(0,0,0);return this},getAt:function(a,b){var c=a.x,d=a.y;a=a.z;var f=this.coefficients;b.copy(f[0]).multiplyScalar(.282095); +b.addScale(f[1],.488603*d);b.addScale(f[2],.488603*a);b.addScale(f[3],.488603*c);b.addScale(f[4],1.092548*c*d);b.addScale(f[5],1.092548*d*a);b.addScale(f[6],.315392*(3*a*a-1));b.addScale(f[7],1.092548*c*a);b.addScale(f[8],.546274*(c*c-d*d));return b},getIrradianceAt:function(a,b){var c=a.x,d=a.y;a=a.z;var f=this.coefficients;b.copy(f[0]).multiplyScalar(.886227);b.addScale(f[1],1.023328*d);b.addScale(f[2],1.023328*a);b.addScale(f[3],1.023328*c);b.addScale(f[4],.858086*c*d);b.addScale(f[5],.858086* +d*a);b.addScale(f[6],.743125*a*a-.247708);b.addScale(f[7],.858086*c*a);b.addScale(f[8],.429043*(c*c-d*d));return b},add:function(a){for(var b=0;9>b;b++)this.coefficients[b].add(a.coefficients[b]);return this},scale:function(a){for(var b=0;9>b;b++)this.coefficients[b].multiplyScalar(a);return this},lerp:function(a,b){for(var c=0;9>c;c++)this.coefficients[c].lerp(a.coefficients[c],b);return this},equals:function(a){for(var b=0;9>b;b++)if(!this.coefficients[b].equals(a.coefficients[b]))return!1;return!0}, +copy:function(a){return this.set(a.coefficients)},clone:function(){return(new this.constructor).copy(this)},fromArray:function(a,b){void 0===b&&(b=0);for(var c=this.coefficients,d=0;9>d;d++)c[d].fromArray(a,b+3*d);return this},toArray:function(a,b){void 0===a&&(a=[]);void 0===b&&(b=0);for(var c=this.coefficients,d=0;9>d;d++)c[d].toArray(a,b+3*d);return a}});Object.assign(Gf,{getBasisAt:function(a,b){var c=a.x,d=a.y;a=a.z;b[0]=.282095;b[1]=.488603*d;b[2]=.488603*a;b[3]=.488603*c;b[4]=1.092548*c*d; +b[5]=1.092548*d*a;b[6]=.315392*(3*a*a-1);b[7]=1.092548*c*a;b[8]=.546274*(c*c-d*d)}});bb.prototype=Object.assign(Object.create(da.prototype),{constructor:bb,isLightProbe:!0,copy:function(a){da.prototype.copy.call(this,a);this.sh.copy(a.sh);this.intensity=a.intensity;return this},toJSON:function(a){return da.prototype.toJSON.call(this,a)}});Xg.prototype=Object.assign(Object.create(bb.prototype),{constructor:Xg,isHemisphereLightProbe:!0,copy:function(a){bb.prototype.copy.call(this,a);return this},toJSON:function(a){return bb.prototype.toJSON.call(this, +a)}});Yg.prototype=Object.assign(Object.create(bb.prototype),{constructor:Yg,isAmbientLightProbe:!0,copy:function(a){bb.prototype.copy.call(this,a);return this},toJSON:function(a){return bb.prototype.toJSON.call(this,a)}});var Aj=new I,Bj=new I;Object.assign(Ni.prototype,{update:function(a){var b=this._cache;if(b.focus!==a.focus||b.fov!==a.fov||b.aspect!==a.aspect*this.aspect||b.near!==a.near||b.far!==a.far||b.zoom!==a.zoom||b.eyeSep!==this.eyeSep){b.focus=a.focus;b.fov=a.fov;b.aspect=a.aspect*this.aspect; +b.near=a.near;b.far=a.far;b.zoom=a.zoom;b.eyeSep=this.eyeSep;var c=a.projectionMatrix.clone(),d=b.eyeSep/2,f=d*b.near/b.focus,g=b.near*Math.tan(N.DEG2RAD*b.fov*.5)/b.zoom;Bj.elements[12]=-d;Aj.elements[12]=d;d=-g*b.aspect+f;var k=g*b.aspect+f;c.elements[0]=2*b.near/(k-d);c.elements[8]=(k+d)/(k-d);this.cameraL.projectionMatrix.copy(c);d=-g*b.aspect-f;k=g*b.aspect-f;c.elements[0]=2*b.near/(k-d);c.elements[8]=(k+d)/(k-d);this.cameraR.projectionMatrix.copy(c)}this.cameraL.matrixWorld.copy(a.matrixWorld).multiply(Bj); +this.cameraR.matrixWorld.copy(a.matrixWorld).multiply(Aj)}});Object.assign(Zg.prototype,{start:function(){this.oldTime=this.startTime=("undefined"===typeof performance?Date:performance).now();this.elapsedTime=0;this.running=!0},stop:function(){this.getElapsedTime();this.autoStart=this.running=!1},getElapsedTime:function(){this.getDelta();return this.elapsedTime},getDelta:function(){var a=0;if(this.autoStart&&!this.running)return this.start(),0;if(this.running){var b=("undefined"===typeof performance? +Date:performance).now();a=(b-this.oldTime)/1E3;this.oldTime=b;this.elapsedTime+=a}return a}});var Gc=new q,Cj=new ya,Pl=new q,Hc=new q;$g.prototype=Object.assign(Object.create(E.prototype),{constructor:$g,getInput:function(){return this.gain},removeFilter:function(){null!==this.filter&&(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination),this.gain.connect(this.context.destination),this.filter=null);return this},getFilter:function(){return this.filter},setFilter:function(a){null!== +this.filter?(this.gain.disconnect(this.filter),this.filter.disconnect(this.context.destination)):this.gain.disconnect(this.context.destination);this.filter=a;this.gain.connect(this.filter);this.filter.connect(this.context.destination);return this},getMasterVolume:function(){return this.gain.gain.value},setMasterVolume:function(a){this.gain.gain.setTargetAtTime(a,this.context.currentTime,.01);return this},updateMatrixWorld:function(a){E.prototype.updateMatrixWorld.call(this,a);a=this.context.listener; +var b=this.up;this.timeDelta=this._clock.getDelta();this.matrixWorld.decompose(Gc,Cj,Pl);Hc.set(0,0,-1).applyQuaternion(Cj);if(a.positionX){var c=this.context.currentTime+this.timeDelta;a.positionX.linearRampToValueAtTime(Gc.x,c);a.positionY.linearRampToValueAtTime(Gc.y,c);a.positionZ.linearRampToValueAtTime(Gc.z,c);a.forwardX.linearRampToValueAtTime(Hc.x,c);a.forwardY.linearRampToValueAtTime(Hc.y,c);a.forwardZ.linearRampToValueAtTime(Hc.z,c);a.upX.linearRampToValueAtTime(b.x,c);a.upY.linearRampToValueAtTime(b.y, +c);a.upZ.linearRampToValueAtTime(b.z,c)}else a.setPosition(Gc.x,Gc.y,Gc.z),a.setOrientation(Hc.x,Hc.y,Hc.z,b.x,b.y,b.z)}});rd.prototype=Object.assign(Object.create(E.prototype),{constructor:rd,getOutput:function(){return this.gain},setNodeSource:function(a){this.hasPlaybackControl=!1;this.sourceType="audioNode";this.source=a;this.connect();return this},setMediaElementSource:function(a){this.hasPlaybackControl=!1;this.sourceType="mediaNode";this.source=this.context.createMediaElementSource(a);this.connect(); +return this},setMediaStreamSource:function(a){this.hasPlaybackControl=!1;this.sourceType="mediaStreamNode";this.source=this.context.createMediaStreamSource(a);this.connect();return this},setBuffer:function(a){this.buffer=a;this.sourceType="buffer";this.autoplay&&this.play();return this},play:function(a){void 0===a&&(a=0);if(!0===this.isPlaying)console.warn("THREE.Audio: Audio is already playing.");else if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control."); +else return this._startedAt=this.context.currentTime+a,a=this.context.createBufferSource(),a.buffer=this.buffer,a.loop=this.loop,a.loopStart=this.loopStart,a.loopEnd=this.loopEnd,a.onended=this.onEnded.bind(this),a.start(this._startedAt,this._pausedAt+this.offset,this.duration),this.isPlaying=!0,this.source=a,this.setDetune(this.detune),this.setPlaybackRate(this.playbackRate),this.connect()},pause:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control."); +else return!0===this.isPlaying&&(this._pausedAt=(this.context.currentTime-this._startedAt)*this.playbackRate,this.source.stop(),this.source.onended=null,this.isPlaying=!1),this},stop:function(){if(!1===this.hasPlaybackControl)console.warn("THREE.Audio: this Audio has no playback control.");else return this._pausedAt=0,this.source.stop(),this.source.onended=null,this.isPlaying=!1,this},connect:function(){if(0d&&this._mixBufferRegion(c,a,3*b,1-d,b);d=b;for(var g=b+b;d!==g;++d)if(c[d]!==c[d+b]){f.setValue(c,a);break}},saveOriginalState:function(){var a=this.buffer,b=this.valueSize,c=3*b;this.binding.getValue(a,c);for(var d=b;d!==c;++d)a[d]= +a[c+d%b];this.cumulativeWeight=0},restoreOriginalState:function(){this.binding.setValue(this.buffer,3*this.valueSize)},_select:function(a,b,c,d,f){if(.5<=d)for(d=0;d!==f;++d)a[b+d]=a[c+d]},_slerp:function(a,b,c,d){ya.slerpFlat(a,b,a,b,a,c,d)},_lerp:function(a,b,c,d,f){for(var g=1-d,k=0;k!==f;++k){var m=b+k;a[m]=a[m]*g+a[c+k]*d}}});var Rl=/[\[\]\.:\/]/g,Sl="[^"+"\\[\\]\\.:\\/".replace("\\.","")+"]",Tl=/((?:WC+[\/:])*)/.source.replace("WC","[^\\[\\]\\.:\\/]"),Ul=/(WCOD+)?/.source.replace("WCOD",Sl), +Vl=/(?:\.(WC+)(?:\[(.+)\])?)?/.source.replace("WC","[^\\[\\]\\.:\\/]"),Wl=/\.(WC+)(?:\[(.+)\])?/.source.replace("WC","[^\\[\\]\\.:\\/]"),Xl=new RegExp("^"+Tl+Ul+Vl+Wl+"$"),Yl=["material","materials","bones"];Object.assign(Oi.prototype,{getValue:function(a,b){this.bind();var c=this._bindings[this._targetGroup.nCachedObjects_];void 0!==c&&c.getValue(a,b)},setValue:function(a,b){for(var c=this._bindings,d=this._targetGroup.nCachedObjects_,f=c.length;d!==f;++d)c[d].setValue(a,b)},bind:function(){for(var a= +this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].bind()},unbind:function(){for(var a=this._bindings,b=this._targetGroup.nCachedObjects_,c=a.length;b!==c;++b)a[b].unbind()}});Object.assign(ja,{Composite:Oi,create:function(a,b,c){return a&&a.isAnimationObjectGroup?new ja.Composite(a,b,c):new ja(a,b,c)},sanitizeNodeName:function(a){return a.replace(/\s/g,"_").replace(Rl,"")},parseTrackName:function(a){var b=Xl.exec(a);if(!b)throw Error("PropertyBinding: Cannot parse trackName: "+ +a);b={nodeName:b[2],objectName:b[3],objectIndex:b[4],propertyName:b[5],propertyIndex:b[6]};var c=b.nodeName&&b.nodeName.lastIndexOf(".");if(void 0!==c&&-1!==c){var d=b.nodeName.substring(c+1);-1!==Yl.indexOf(d)&&(b.nodeName=b.nodeName.substring(0,c),b.objectName=d)}if(null===b.propertyName||0===b.propertyName.length)throw Error("PropertyBinding: can not parse propertyName from trackName: "+a);return b},findNode:function(a,b){if(!b||""===b||"root"===b||"."===b||-1===b||b===a.name||b===a.uuid)return a; +if(a.skeleton){var c=a.skeleton.getBoneByName(b);if(void 0!==c)return c}if(a.children){var d=function(a){for(var c=0;c=b){var q=b++,t=a[q];c[t.uuid]=p;a[p]=t;c[l]=q;a[q]=m;m=0;for(l=f;m!==l;++m){t=d[m];var r=t[p];t[p]=t[q];t[q]=r}}}this.nCachedObjects_=b},uncache:function(){for(var a=this._objects,b=a.length,c=this.nCachedObjects_,d=this._indicesByUUID,f=this._bindings,g=f.length,k=0,l=arguments.length;k!==l;++k){var n= +arguments[k].uuid,p=d[n];if(void 0!==p)if(delete d[n],pb||0===c)return;this._startTime=null;b*=c}b*=this._updateTimeScale(a);c=this._updateTime(b);a=this._updateWeight(a);if(0c.parameterPositions[1]&&(this.stopFading(),0===d&&(this.enabled=!1))}}return this._effectiveWeight=b},_updateTimeScale:function(a){var b=0;if(!this.paused){b=this.timeScale;var c=this._timeScaleInterpolant;if(null!==c){var d=c.evaluate(a)[0];b*=d;a>c.parameterPositions[1]&&(this.stopWarping(),0===b?this.paused=!0:this.timeScale=b)}}return this._effectiveTimeScale=b},_updateTime:function(a){var b=this.time+a,c=this._clip.duration,d=this.loop,f=this._loopCount,g=2202===d;if(0===a)return-1=== +f?b:g&&1===(f&1)?c-b:b;if(2200===d)a:{if(-1===f&&(this._loopCount=0,this._setEndings(!0,!0,!1)),b>=c)b=c;else if(0>b)b=0;else{this.time=b;break a}this.clampWhenFinished?this.paused=!0:this.enabled=!1;this.time=b;this._mixer.dispatchEvent({type:"finished",action:this,direction:0>a?-1:1})}else{-1===f&&(0<=a?(f=0,this._setEndings(!0,0===this.repetitions,g)):this._setEndings(0===this.repetitions,!0,g));if(b>=c||0>b){d=Math.floor(b/c);b-=c*d;f+=Math.abs(d);var k=this.repetitions-f;0>=k?(this.clampWhenFinished? +this.paused=!0:this.enabled=!1,this.time=b=0a,this._setEndings(a,!a,g)):this._setEndings(!1,!1,g),this._loopCount=f,this.time=b,this._mixer.dispatchEvent({type:"loop",action:this,loopDelta:d}))}else this.time=b;if(g&&1===(f&1))return c-b}return b},_setEndings:function(a,b,c){var d=this._interpolantSettings;c?(d.endingStart=2401,d.endingEnd=2401):(d.endingStart=a?this.zeroSlopeAtStart?2401:2400:2402,d.endingEnd= +b?this.zeroSlopeAtEnd?2401:2400:2402)},_scheduleFading:function(a,b,c){var d=this._mixer,f=d.time,g=this._weightInterpolant;null===g&&(this._weightInterpolant=g=d._lendControlInterpolant());d=g.parameterPositions;g=g.sampleValues;d[0]=f;g[0]=b;d[1]=f+a;g[1]=c;return this}});eh.prototype=Object.assign(Object.create(Ra.prototype),{constructor:eh,_bindAction:function(a,b){var c=a._localRoot||this._root,d=a._clip.tracks,f=d.length,g=a._propertyBindings;a=a._interpolants;var k=c.uuid,l=this._bindingsByRootAndName, +n=l[k];void 0===n&&(n={},l[k]=n);for(l=0;l!==f;++l){var p=d[l],q=p.name,t=n[q];if(void 0===t){t=g[l];if(void 0!==t){null===t._cacheIndex&&(++t.referenceCount,this._addInactiveBinding(t,k,q));continue}t=new dh(ja.create(c,q,b&&b._propertyBindings[l].binding.parsedPath),p.ValueTypeName,p.getValueSize());++t.referenceCount;this._addInactiveBinding(t,k,q)}g[l]=t;a[l].resultBuffer=t.buffer}},_activateAction:function(a){if(!this._isActiveAction(a)){if(null===a._cacheIndex){var b=(a._localRoot||this._root).uuid, +c=a._clip.uuid,d=this._actionsByClip[c];this._bindAction(a,d&&d.knownActions[0]);this._addInactiveAction(a,c,b)}b=a._propertyBindings;c=0;for(d=b.length;c!==d;++c){var f=b[c];0===f.useCount++&&(this._lendBinding(f),f.saveOriginalState())}this._lendAction(a)}},_deactivateAction:function(a){if(this._isActiveAction(a)){for(var b=a._propertyBindings,c=0,d=b.length;c!==d;++c){var f=b[c];0===--f.useCount&&(f.restoreOriginalState(),this._takeBackBinding(f))}this._takeBackAction(a)}},_initMemoryManager:function(){this._actions= +[];this._nActiveActions=0;this._actionsByClip={};this._bindings=[];this._nActiveBindings=0;this._bindingsByRootAndName={};this._controlInterpolants=[];this._nActiveControlInterpolants=0;var a=this;this.stats={actions:{get total(){return a._actions.length},get inUse(){return a._nActiveActions}},bindings:{get total(){return a._bindings.length},get inUse(){return a._nActiveBindings}},controlInterpolants:{get total(){return a._controlInterpolants.length},get inUse(){return a._nActiveControlInterpolants}}}}, +_isActiveAction:function(a){a=a._cacheIndex;return null!==a&&athis.max.x||a.ythis.max.y?!1:!0},containsBox:function(a){return this.min.x<=a.min.x&&a.max.x<=this.max.x&&this.min.y<=a.min.y&&a.max.y<=this.max.y},getParameter:function(a,b){void 0===b&&(console.warn("THREE.Box2: .getParameter() target is now required"),b=new z);return b.set((a.x-this.min.x)/(this.max.x-this.min.x), +(a.y-this.min.y)/(this.max.y-this.min.y))},intersectsBox:function(a){return a.max.xthis.max.x||a.max.ythis.max.y?!1:!0},clampPoint:function(a,b){void 0===b&&(console.warn("THREE.Box2: .clampPoint() target is now required"),b=new z);return b.copy(a).clamp(this.min,this.max)},distanceToPoint:function(a){return Ej.copy(a).clamp(this.min,this.max).sub(a).length()},intersect:function(a){this.min.max(a.min);this.max.min(a.max);return this},union:function(a){this.min.min(a.min); +this.max.max(a.max);return this},translate:function(a){this.min.add(a);this.max.add(a);return this},equals:function(a){return a.min.equals(this.min)&&a.max.equals(this.max)}});var Fj=new q,hg=new q;Object.assign(ih.prototype,{set:function(a,b){this.start.copy(a);this.end.copy(b);return this},clone:function(){return(new this.constructor).copy(this)},copy:function(a){this.start.copy(a.start);this.end.copy(a.end);return this},getCenter:function(a){void 0===a&&(console.warn("THREE.Line3: .getCenter() target is now required"), +a=new q);return a.addVectors(this.start,this.end).multiplyScalar(.5)},delta:function(a){void 0===a&&(console.warn("THREE.Line3: .delta() target is now required"),a=new q);return a.subVectors(this.end,this.start)},distanceSq:function(){return this.start.distanceToSquared(this.end)},distance:function(){return this.start.distanceTo(this.end)},at:function(a,b){void 0===b&&(console.warn("THREE.Line3: .at() target is now required"),b=new q);return this.delta(b).multiplyScalar(a).add(this.start)},closestPointToPointParameter:function(a, +b){Fj.subVectors(a,this.start);hg.subVectors(this.end,this.start);a=hg.dot(hg);a=hg.dot(Fj)/a;b&&(a=N.clamp(a,0,1));return a},closestPointToPoint:function(a,b,c){a=this.closestPointToPointParameter(a,b);void 0===c&&(console.warn("THREE.Line3: .closestPointToPoint() target is now required"),c=new q);return this.delta(c).multiplyScalar(a).add(this.start)},applyMatrix4:function(a){this.start.applyMatrix4(a);this.end.applyMatrix4(a);return this},equals:function(a){return a.start.equals(this.start)&&a.end.equals(this.end)}}); +Ee.prototype=Object.create(E.prototype);Ee.prototype.constructor=Ee;Ee.prototype.isImmediateRenderObject=!0;var rb=new q,Hb=new q,Mh=new ka,Zl=["a","b","c"];Fe.prototype=Object.create(Z.prototype);Fe.prototype.constructor=Fe;Fe.prototype.update=function(){this.object.updateMatrixWorld(!0);Mh.getNormalMatrix(this.object.matrixWorld);var a=this.object.matrixWorld,b=this.geometry.attributes.position,c=this.object.geometry;if(c&&c.isGeometry)for(var d=c.vertices,f=c.faces,g=c=0,k=f.length;gMath.abs(b)&&(b=1E-8);this.scale.set(.5*this.size,.5*this.size,b);this.children[0].material.side=0>b?1:0;this.lookAt(this.plane.normal); +E.prototype.updateMatrixWorld.call(this,a)};var Mj=new q,Lf,jh;Bb.prototype=Object.create(E.prototype);Bb.prototype.constructor=Bb;Bb.prototype.setDirection=function(a){.99999a.y?this.quaternion.set(1,0,0,0):(Mj.set(a.z,0,-a.x).normalize(),this.quaternion.setFromAxisAngle(Mj,Math.acos(a.y)))};Bb.prototype.setLength=function(a,b,c){void 0===b&&(b=.2*a);void 0===c&&(c=.2*b);this.line.scale.set(1,Math.max(1E-4,a-b),1);this.line.updateMatrix();this.cone.scale.set(c, +b,c);this.cone.position.y=a;this.cone.updateMatrix()};Bb.prototype.setColor=function(a){this.line.material.color.set(a);this.cone.material.color.set(a)};Bb.prototype.copy=function(a){E.prototype.copy.call(this,a,!1);this.line.copy(a.line);this.cone.copy(a.cone);return this};Bb.prototype.clone=function(){return(new this.constructor).copy(this)};Ke.prototype=Object.create(Z.prototype);Ke.prototype.constructor=Ke;M.create=function(a,b){console.log("THREE.Curve.create() has been deprecated");a.prototype= +Object.create(M.prototype);a.prototype.constructor=a;a.prototype.getPoint=b;return a};Object.assign(zb.prototype,{createPointsGeometry:function(a){console.warn("THREE.CurvePath: .createPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");a=this.getPoints(a);return this.createGeometry(a)},createSpacedPointsGeometry:function(a){console.warn("THREE.CurvePath: .createSpacedPointsGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead."); +a=this.getSpacedPoints(a);return this.createGeometry(a)},createGeometry:function(a){console.warn("THREE.CurvePath: .createGeometry() has been removed. Use new THREE.Geometry().setFromPoints( points ) instead.");for(var b=new P,c=0,d=a.length;c { + let canvasId = res[0].node._canvasId + const canvas = THREE.global.registerCanvas(canvasId, res[0].node) + + this.setData({ canvasId }) + + const camera = new THREE.PerspectiveCamera(70, canvas.width / canvas.height, 1, 1000); + camera.position.z = 500; + const scene = new THREE.Scene(); + scene.background = new THREE.Color(0xAAAAAA); + const renderer = new THREE.WebGLRenderer({ antialias: true }); + + const controls = new OrbitControls(camera, renderer.domElement); + // controls.enableDamping = true; + // controls.dampingFactor = 0.25; + // controls.enableZoom = false; + camera.position.set(200, 200, 500); + controls.update(); + const geometry = new THREE.BoxBufferGeometry(250, 100, 200); + + const texture = new THREE.TextureLoader().load('./rainbow.jpg'); + const material = new THREE.MeshBasicMaterial({ map: texture }); + + // const material = new THREE.MeshBasicMaterial({ color: 0x44aa88 }); + const mesh = new THREE.Mesh(geometry, material); + scene.add(mesh); + + // renderer.setPixelRatio(wx.getSystemInfoSync().pixelRatio); + // renderer.setSize(canvas.width, canvas.height); + + function onWindowResize() { + camera.aspect = window.innerWidth / window.innerHeight; + camera.updateProjectionMatrix(); + renderer.setSize(canvas.width, canvas.height); + } + function render() { + canvas.requestAnimationFrame(render); + // mesh.rotation.x += 0.005; + // mesh.rotation.y += 0.01; + controls.update(); + renderer.render(scene, camera); + } + + render() + + }) + }, + onUnload: function () { + THREE.global.unregisterCanvas(this.data.canvasId) + }, + touchStart(e) { + console.log('canvas', e) + THREE.global.touchEventHandlerFactory('canvas', 'touchstart')(e) + }, + touchMove(e) { + console.log('canvas', e) + THREE.global.touchEventHandlerFactory('canvas', 'touchmove')(e) + }, + touchEnd(e) { + console.log('canvas', e) + THREE.global.touchEventHandlerFactory('canvas', 'touchend')(e) + }, + touchCancel(e) { + // console.log('canvas', e) + }, + longTap(e) { + // console.log('canvas', e) + }, + tap(e) { + // console.log('canvas', e) + }, + documentTouchStart(e) { + // console.log('document',e) + }, + documentTouchMove(e) { + // console.log('document',e) + }, + documentTouchEnd(e) { + // console.log('document',e) + }, +}) diff --git a/src/wechat_app/pages/cube/index.json b/src/wechat_app/pages/cube/index.json new file mode 100644 index 0000000..6bd634a --- /dev/null +++ b/src/wechat_app/pages/cube/index.json @@ -0,0 +1,4 @@ +{ + "usingComponents": {}, + "disableScroll": true +} \ No newline at end of file diff --git a/src/wechat_app/pages/cube/index.wxml b/src/wechat_app/pages/cube/index.wxml new file mode 100644 index 0000000..5539731 --- /dev/null +++ b/src/wechat_app/pages/cube/index.wxml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/wechat_app/pages/cube/index.wxss b/src/wechat_app/pages/cube/index.wxss new file mode 100644 index 0000000..e69de29 diff --git a/src/wechat_app/pages/cube/rainbow.jpg b/src/wechat_app/pages/cube/rainbow.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d8a32cd91ea3417abb64693a7099a03e3e698d5e GIT binary patch literal 16069 zcmZvD1zeQR^YBB1AT5H@Agz?raFmpEqtXp3T@r_McY`#N(kk6}ga-m5Af+H6AaR@s z2N&<7-|z4DfB&EN-GgU$XJ_YjW_NaHW}m|?;=TgZT56hV03IFyXn-F8_YFw8AL!}? z06IE=0001_01+N7KmeBTzz=|T10eca1^_L*oBu5v;_>~9gAV|)t^nb`I1j=6PXa0b z>HTj`P>T0I6ie~{gN>(HO7K7BKizN#fRw(Ahp&f^i-#w>_#F{IN?B8f@DFt`{Vm`6 zTcrNPlC+cxv=Z)yljZ$9R}RAs0W_p|ig=0yc$@$}4ITjv9&Q9+14luG_c#6R1^@*3 zgm^>%F$pQz6><<^m>R$%0AU1##DpZogrvkic=!MT4IwQDktiJ}HL;R`7`?3*7s(6u zbmePhhT<*Ub|MUe-ZLs0cOyu@87bbfzkcsH)2CctwKWpKV=Up2GjofF&MvNQ0f9l!V`Agt6Vh^W z^YRNyt6o*t)Ydh>dHb%Tvuj{v^gV2BeB$G$`OgcBOJBZz-`d{!vAc)-b^8149Ch)B zOHjK1FbO{Y^7)4eLZbiSk_N!X2l*txCm_Nn!Y3q*#RFwTKuya*$S$fxM-6;W*BSnh zxN(DngPnupzchGpUjPb%zv80-7gt$!X5>%m%&4&l4X*4u;Jpr&b|m#<#THJkY#pv^ z`os^*g>+Q1b$Cc?2xvsLay0N+Bx@q>bJ3}KDkW&$O7k7b)>h(@rLK3)idCX6qvO<4>PI=~Vk~FOKCQrUR%}MIBiy`q2Xsam!pzF#xQq0iS`eN+I!R;#0>cy zUbL#biciWK9@=SS)d|?yy`nGBoxS2a;`@Y>iH2D{>M`Ta?EUA(aIx4HVtp*0V~J9J z721d|6yILB-D3Es3Iz@@d0sr0r*gnx@jH?!G-+Id#sq~W?uQIDeZCr?uj(FX`%^CciC+d#vK9V(^wBK4I)3^+=WCRD8@! zV$;QB(PTPW%B=A#$;ods)m}d25s;YhPr5B@nl~cI^Du8lYo^Z5u9YFWgO;%GXzKQr zNZq+dYE@cxab*HBw#M!J#0IK0uMNth%Z#t_5=C>mnHD)}Yul@p0~NK=Kh&ZU47kEg zh$9eQHk;fk(E}lLn zv%L}(HCRe><;s)jkvK!LqI`M|1Byz4c&-fN79Bc@^gDUnE}Vez9sa)jEAhsLmF~P+ zJlWKBYT3rF3HlT(%Is#pY$k3D3(%JFE6-;b8-H&sC&ynBNHLFBO?Roi!R{Ddny9tg zrNv;OZ>*LDS1xzEmafZgP8%0bXHsib^DsR&hlF)=+kdOUoN^d+04io6X{kOdBNM}^8RKv41!4xZjOt&1 zw`wFPms2>tu(?Kh-;u-1xQyOrAf8{fM*2z=ekR?u2~7)w@T?DWhK*!|6J*9^#`zOv zT8T;-NkA6&tsx#jTUpbGFO4?4JVVva={mKtqv&HUrXfyMA!Ea=_=+(Ng7jfea)6)z zMwBK4tpS(KEwTu0IT_{jcpm226V9Rm9^xBz+-ZCMIp;*mqTEq#chsuB-%Sf z%VPu{zMwEpt`KCNNsBg}O%RIq1a~S@@I1gH!aq<~*ZqY942+Hp=H5aA4U&~8U)Jm{ zvvsQfY4G*65o2MIWssfOIQ9k8<%<~CFE7XL&8IKQ-~iEz2g14o;)}6rv9F@o*5K>zYuW2MdN#5y z=Ur^wYOKBJZj-$qa02=;%bq=Qp_v#qk}6q}5%ERwWi>rF*VLzsP9=VKC#!ZJ?rHd4 zwGf#cpU<)Gn!tQkKWsHx-45FqJhQOw(!hLHd+HFjD|n{)x6$-=)t?ryqJf!JKg@vm zWM4KktvWh=HhtR~^Il#m`(zx+dW5AjZE0KVUwa9cJKwzAHGO zHg>I|dJQs7)dl$!i9(=HAq5p|M|u8Dmp_}3cJzIQ*0+VTawk-_I8HK98X@fphSvO4 zS+Nrjwr-uIp)^A(`wZFm|6n`-G5!J+wAlV){HIH$f+5>2u*fP3K_}%0t1C=6p@NGF!PS*8Hzkh*IUrH)` ze}$^YlEk-lSU8eszIZEFUH7ZF`j&O4dIeI3U@&EXMEBQ0^~y|Du3pEz=Q8)GI#_gE zD;8Rw8#cj+iodcW7BWmXBSbQXKbV^KS^KZ?Yeh|1oSp!Cw+f-qJ^vHRc{^E0kDY|j zFC%s5ZFUDU_|NJW#fJ6mk`!2CZ7T#^56sL=$?KauC+k19$7<0sxAtHh=ELK{#2$X+0E(?Ac(=#%5nRop70Irl|a|U;%~)5t-p?pf6r9S7swc7 z%)0E&S{$hFsHlbgel6!PQ`*b)oIyoM{=t0adaRxMii}vW*MVt)fn~UZKT05>K@YXc~?#_YH!T<$ZFm;)@t{YpjwrPuhYv(VKsA^+Yjd>m#5nO>QAWRgn758 zNiv(~K06z()YxGL&T>V>YGSqe-x*?(#5O%{A8*G@G#)o|T3?8l)j?J!G6 zkjszVLO3a=Ai+)bGlE(vV>g~JXb4Sw`ymC080?ZY#dOwno*wj5<4BIEY z3rJ1LFQ`%G1*CTTzx7ZQ4p3h&`Sri@Q#x#FKjg9I+w5{zrlgdvm~H;7 z0%QFgGJjU~Pxhw<0{_&&to(8Y+tkapcli;_sQ$^o8UowY57v&cHPcl4*q3d;NIuF~ zcxbu*rn}@gc+KDV#r>hX77kFdhMqlxo(W$Zo%#R&vao-E|2zAOi35&cm)(%dTnzMV z6SH1|nZ$NuR{zQVt^IG{zit0_)(;Nza2mUX11zzJdytj>{r=S@902AxpdaFJifQcL z@Bcd+pjQLId(Ho<{Z)bMKYy=Demb(XhLuBSFxsHxFY-Z|o{Ik~cZdHa|G#qnBj5jf zP7EMFu>b8G|EIGwq~ao}WNz2AVxO&nhXoM;DthPj6{-$4Pld0c14oI6BrBB1N8lg0 zmwb~Za5?H#dsnL!Ok5gz!`*1zS@DK$U(M57y|=J0u|IbES8%|7>RBdcZZ6CR2Rw%M zlpGe9AWJSbG2d~3FL)#s;eZ9UBi_sES2zH~XoRfko$2YJrZHaF6KGc#^bGP3uAlG! z;MP~8cd#8eAPBM=3fU1p#R2Q7XV!Yy9UNedIWI{Z#BTpB;Q&AI8xEm=5aP}o^Kd}w zzuj0QcOa**%ke)$l>X1R>ii+_&kzg$e?zQ))i3@Rq44LaN3veBV6wX7+f;sct*z79 z^u-4{0p#ya&2d2eMFVsmqYK%?RR=e?XFVgTy_9N}f1&o+ zradnlV0J3?|8%7KO8{z=f(drtzrZe7p059Upc6yzaX|XM^-drTsNp{YyGp9-ohme0 zpTX3dka7w;xf|&I>s#kIpcLKD_KPid6B~JghJFmQPQ9R-M1)xG}`uf9dwKp_{AOw!v{p zk0LI+z(chjTlx(>h;=JDO0_<NH?JEKO zU~%d{VFvs^3G{~n0G}L>2H+4?GO+b}kzUp^csxV>4Z$v=sBhyLo>tmC@bT+^Oe6>g z`SrC9a76K@&Nv_jf;O;&Y~ldU(d-ly0TOjP`BLWK2+8J>`l1xEz%gavbFR7-KA(jZG zRKMm{Q-0NVyuM;|k9&CGKgc}%iVdH)9=5k_WI`|&IW?xN7C3+$y=L;>5RC(dt0?bV zoL&FX8Zcb9Bw2ufQ#YP0suwQ9IRk`bTwh_`e4IvW2W>j0Y688Nvizar+*778yiy5b zDK%Pre1}D&H&;#HxFr_5(tVXQ9!fGU^PK3Z-a9uZLz_B#j2eE2zAuc&m=}H*(w3^f z`~G-xdQh)!phoKX#y6s6j^bwzuF;yM+ulU=8U^8ifkCGvs@i%9UN=gqx^HmZ%R?k0 zXro3_uw-5esYbm;x{Y)&?CkZ@UepQq5geIin&c%q?1}ya^;g3m5MTWs*gFGPu@b&o z$97-+9@RCydvJ0b;Bl(Q2I{$4sX5+w`H=(xFVbLWC@mdpok+C#8-$}v&ikg1&-=Ha zCzt(`8^bsNimt~2xu?e98s5VJi8$a|$J8)d_|%T-1Y_-i3IQ8(Pdy6>TEiN^Mz?ev zK(+CU7ZqY?eFm*3xru_-Rf}ELSYSO)O+8Sdk5M3<#BJ#0MzQrV_*Ez8O_}IE;Wo4a z|J|xQp@T=#PH(+)Am2t^VHm`l)JwW|&~Fy6z$uD0UcjE}UCg?|Czf8V)mooJVOZHd z*K2XjCC48v3nddwgwd`Jspszw;bS-;*=^Nu8l51&^6FYsBC9a;xF3S-{=78yx=>P( zfv?fpSQ3;ksHa?R;5toZLs$qt=*0n34GYiy)Nw$#q`=Y_9Pr`Qf~k_z8RWFZ8kOmU zHtkSH%R^@cwGi#E6HAcpI3TcZFLyNu+$z5kB;Gp10S`Y5!Y~_c&tKmG7cvfrvH)S4 z;2vyMjfIz>=5q=Ig^Q}dxh)C+aP7Hl#Il zyZ8u>>X+O?uV*5yows+^x4{)!hz#?XL{+~-dLJS6JhuDR;Uv@BwL2gbj)F>l|AYId z*e|(_UI%fl;WkHq0F(W26yy&KY}SJt9Q`4fTyk!L1CZTKI3UXm2fSav(&K;=DjdKM z>MjldReAsioP+h7IAG(j1RG)1kLJaIb!O=7ILI>O8~E7Adf|W_wqppI2CRL7j8hM~k;v1WDW}i5w6{NsF0p$ga{viktUDBa-5r$lsvy?)cyI-LxZg@(Uz+Y@;P-ZCF zXV*tQoO(_Ro#HW4sqJW3ll{w76tiixc8_57C{+Txm0KXH1NwGw80&37Rp%tr+_7=0 zrd`juc(;D6&9ZmGl&e7Wkgwtatw?X@sqIe}P;Qh~q#@9O!7zFApJi_zZM?F3qu>VT z=@8;wkaS*k@VOUr=d*T)O5d|`nVvf|fp&fU*Od=wk8hF(+C{YB07jiBx0!cx%D!FH z=^ifKhe?Jt^mJRu8ayw&<9cZ>nJ2`qbzrbPC2#Go#&wvIwY4|FG2caBJmV0&`efYd zk#f_joS}|^`F^)TpNrUZ^=L|i(&*QWn(lY%(w;~yUcu?Bq6z{m3{Ae@&m7;1bgDR= z-hZ9&a`lF~!qIV`?$K>MQ$2qpq&8LYkLPrUJyi&ZUwAby@_9qB^&4`gf=D7SBT2S| zlt;YtMg=$S>FRI>JUL-Df&3nA8@$hZ`dDD?mDYpt+*O8EpV0exlaOmKiY^<};p%Q3 z6M{keg14la@39#KiKL<#R%&_R2fAi0qhCKpr$z@|=;O6dc;y6aB)%?5kliSk?v&P9 z5IAj1x1tGtt6^EO47V&K%bC6js@OB1y#y~q&-kXyz(m?v_MnQSmD4l7u-a4xSMR`v zb0PJ+MJ#48U!#p;y%-_r5T)#4IyD1LjFE*)JYS!&_JLy4Z9iSvwvD0(Cf^^OId$ex zDEv$jdf%q`h3I0tfhh=j4K{4;NY(-A&b^;N^5tw}s6`+7I-IavTPJO2Bk8e-CG zWfykj$au+ z<#rPY*lyP0yz}8{ZeJ%jA=$SWLLeJjrp5Ja66!+Fd5&YIKFt@aO$d=>)AnULUCXJ- zNP(+sJ@eD=GK+#rMtdC&-O2v;?xar6s31x~Kx(7eE&*Ccv8Yen&IF#V!OdRgF{57! zEQxv=0#qsLh;s>sP&2B#Ds%x4n(C$FJD2ZEJHIz@mT6mFEmlFOkh82wHNM0Dh?|mM_3KVrVDkgdGPc>}C}q zusRE=(>TDTf)Cb&Ji;=Y>!o7q&}=*KqOMdV92Vt;eQG|3#;mZ{sIPAlw8YooN*Lt#7ze`y zC0L;%K_M-^VoEM8q#@A5t^S?Ev3&#%co(UMJe=%6jOp(5ZGCm-zv`7mk#|Ho%M4Ruul}0TYH=w$Bse0I(G6FU-cNQ8mSA^IF(PGj_7WL7Wo*+5|1UQ+qaQ;`+)rvz#5VnUrd4)cnvq`PCyKkeSz_-K4dAN8&A!wsbx_wr*x(7YaC=qmzHagtvytVw~Ou=Ku zREtZxQRpntnz3w2S^HF9EWpZ=zVX4{Y1QsKZMF6fFAkd|4;$s6gNCNcuy64_o?s4~PHlALKdC_n+g86@+D*X0HE@kjz#Fo+RDXBGaL2hz*4bUV0SADmS|kpj zZPREoovr4+^`ic~p{i*bEesk2(9L_KNG%~aX#4)pMFusRkS$Bnr6qvA86wctPMPKS zk=Cbf?aA!&QNrbFU+QnF_X@@LEyBMo`T#I)B~jxHRno~WgyNQ&{))Qf*jO(iMUM|} z^2pc7(}&R`0~v2GuozP(KdRCn9J*bt#spo z)%7W7#HZLGlT*{c?R$a`3qJ(tq1ea?#o6O5*@nRP0BK^7H|6`6H}v zVO{$-2(iP+LZ^m}mtOTwNxYpqLzkf%=LhT+d28w*VHF)U1UHfC$2#S^Cvi=WcZAj+ zxJO@|U;>q7T>i?_8V|V#|FUneG2EQTxA7|rFNQK$};X1V(A{3PJ`mJi|)2eqmPcuTk%fRYA>UhJ1rusj0 zW^DMZkM#`eX37`?)xc@iKL zmwy|+u~x#ivoAmO)N#&6ojk&8H#Y`*wWO`q6MB0?_GGzWDX0%lAvK&;Y;68HjhjB^(7o& zfBOIh*~Zv{W}fi$ISy!9I=+N1;($?EXcY8&uBVn`PgtLA@zdF*^QU3@ZMXL0nOH0l zes~$omOC##bm-{^aNRz>J$c|vtrGv~Vnl6S8MQ47?oa8URsZf1@)HMaCqag>usKZb zF57R&F?9JC*@boMrSJiG5JD?Xa6lVqK4Mp_L9^|d@G<1W*22%ob4S8#_P+K9cioKky8GXRLpmz(h`Z#K`0-22H73a)wf8mwUwVa79tk% z_urnnrg?dJa8LUqzDj#Yehj<1T<#;>eYw7I+24y5p0nNvt3HCpK}x^?%JuywL>TCr zGW0`wMUF0J>`Bfbqu^m0jJ77m?wohZVx|$HBxn7jXHXCn02VIxNT$#FLGN-Gn)nTS zHWFw*vP~sM7P-55I=Q{Kis*Q|Mi=@dL~glI=#+hXI<5qtAmBsmq!6NbD??QLc<0a7 zK#KP#+(gY8+7C=)74a3K&_XFV0MA2mxP#OyGcOOuq(r1nsf?h9V)`N1MN)ix*JP_7m?{Ifueg z(;FKhB1|f(-y90RAiKeu<{(faPb; zmX5a3%dtDZ`(=OkZPRyVuO`2{iR^~A^;13a8UB^tQslhjJGPpe7kD!p^YM7tN z?CEGJCQ*84*YUl1NtWlSPwx)ht<$r*ykj~ z+)j;{BqW%r%*?(bBlK&iY+4vwC0oSsuI;bZX{iefZldU%>kJGGn!lS7NTIgj51Yrl zIDll~_-S8X$Wq89ED8N2UQsWI-5!|hVm=QKwOUdectKFVb;&#Dhhn#4g*w2tpkybp zwy~@L?|NEbDr68Z{6y(ovtKOq4&8OGmSgh*=Si~F7`uM$es5#_+XR^onA^MWcA1al zrXVM?>mKzqdWT|K>8!7B7f;& zsV;rJK;1m({{qch_W2E6qOxwoPCbTdV(lTv;KY6mOPxB0&Vb6N1a2VGPR^j3zLO*Y zmAPdeRLxCUDBJHqa64I92Ne|bpr|l8Y`ZwXCJf?=wdn}823ze8b?x6PiTH&1psXbg zkG?*#_u1V>-gL~t^k_)8Nk!=4Q~q72Xzldqx535E|EyDR?}bojgb;ofm2Q#nq?TZb zjXw-$;<4vbXi&ck#F$pxw$o^7v3~*`W)KRRB!~G6X*!xscGEvIZY?+OQtI2M8*B|! zc+%OT*0P#6B7a~&B-RPvVhO4gBYZZ$vsVRI$WC^LX~gfJ+0ckL?b-Dc_V(kM(t6~U zm$y!MKRH$_ncs2nfm}SUAu-=P;=2{7yXy{njCG@iiQk_;=NtlJ$d z%3;C4rGrM&b}Z?RXprJucQP%K1nRHKNE>^KUMg1*m{z#H(J@JoN-q+WH5l>(^(sH0 z=i}EjT@zkvO%hQpk{orpMaIjvuO4teDf!CP=Tk5R`#ZDd)rZNqqDYn*%n>UKmLwvD z^U2o2mleg4Hi0#q-d_6gA}gcyac=hOk~Zu_$;i(pY6i-!BUpI$K{L&RY zFG4=uJr61r$>EKhbfob%nfAZ^}@CkGQnAM!WyOyUWKx4Kw#ncwJ72L^XU z9T|B46RR49@NAOx!1wG+27q3*}gwd0F<+$^(BnA^^OWus?``V2wQ<~ zvs=^)x?h-DC3(to^w-?jM|#RGm&F1JwOKm~1t`=}^h388`{y;{sPivtiG;k+DSUI` zh|6WVqQ(H$;@Xe-Qd8aQ1?=}3pbMrtTcq*Gb$Z4-RHo{LGfq%H)gdvjC8XUgDo9)< zyMsG{!kd=+QpD<$s&BbYVPgd<0bnrSwlBK1ok~Da zk#N=KdYDG*wcZ$!eIe3H28|rMhc?=_!(=O>M&#V?h(X&kImtNK4e(4pph=5JoY21P zAvIr9e{VoYm~5L`fCpIkPUpWayEB9sRc3_9dZxu1;efXchCE;-$K(Oid-07dCE%q_ zR83@7Ivvx-m23PpxAfD*5c`GfswvaKZ3Z@#Ba^U(7BV_HNX`JQ6b7-*JeM`>z%x=A z%j~nCDCH_$Y$tYSYT%{Rc05ItV~{m#10#L|a;M-meH{zzqO4NcTcI!1q$^t|kT2n} zEWiDvpJ{gmTOqL~`#$V@!-wLEetJ4WMHby%e8mtZRKqjSgF1LmO>8WU;v;FxO`U(a z`2%gLculm|$>LaC+_&Qu)rrfchzEADrW4Qoc0ssQ&gsDg{+E^&gHf zaiu~6HcJ9VN}RHVauKbPt#%3SP@59B@GL=aKG_%^scijWRZ+9|vZ za71o)-%LO8ptp?>PTLu@$dd_A-DqbX5J@-`17jq&6>AR{SCo=UAoRhNQ33^g7aqvR z=@}9+RO94_UfQiGOdi3KQA`e0hn+-4h;GusGr@)DE!`}R^atjPjxg^PULd5w((7RO z$;$PuiTW-y}7As0ODJRgWi)LBnuNU&XFYvhN79h z{nu*ApBqTh~paQc;l?H(l4Pd zwP}=7ni}B#7%KK@K5Sv&y@ejVC?)e-8Wmx`$ILZTQ$gjK`$Ac{p;iyXy{-`HHdr)D z&lePkuZB``4!};0ug;2;Yu$s)n``(trB)|S_KRC^FpWBJEnIg_&B;QcQ}FkOq*5P}(G;rr3<88L^?}mXTZ6m0H(q*-iuO8k24ClS z?p?`un0NKLaQL*b(Cww}g^lq1i{|_vM__cBj|}vS>4;xdmZXI4> zH9CycMCew{R%aoUXx8hf#S5qFxLE|3#LRE2NiY^@R@br0T{II@T}uaazEql@^V3OR zpX8KU-_9Y8AHGI<^STlakgah{I*i(dB@D#g4$bhrPx5}$7&2<-)AtO|jy}C1*D0e8 zKYpiBgxM^=?#9Xoq-6wNs|v^WI^OkwSZ46bYMg46F7uAj9Upa0tD(^`m2MHL+P!bX zA*=D2`(h3grIeKJ__yU9orCBUqhzr<{++kJwQ(~u&j2K=S+G~xW>FRR6K7^CD&FoPqR;P zDwTm7r;;vnQiLu=3KeunnmWt4Ng>S!nH@I+9`L#MnkoD&D%wj(7xJ?R?U~0j|4=$R z4OgU^$0vEV>s9cIZik<|!5GDrATpTySL>&wGFF1lmgEO(pF_Mqar0P^ zZG2Ezf$tDyzQ^>>Gt&I7>3~dbyeEX6?+u7fqy7BCZ~)r4s0pzbo(EnDBs9l?u4jEQ z$pN;OW>X6~d0sXIUJ|q|qao)_{aAUEDQNEKS7`1=ENCB{K2!y3f{@|8k@VDSO=snh z6Rf~A1C0ZE-Z}N;yhS1eQiw4Wh9c&t6xcTSUNB5b8hHM>cldD^p$3JS*g)8@LUNJY zZ%XVgv*pGeB&yY7vS?|t?IEgj{J}(5uhE?|6&D@p ziSw%9{x_rf0d;ikDs^q|TC0s5wK&CSyom$kn?_yR)N5*G zpFe>ySpAqnI6g>exR?-ZAEnD_0bLQ=b{o+24|#&jow2{w29Hs7^N}^3yCF9EBB(Uw z;PHv6pC6siVf9`%=N(lqb+O@q!$>N0Bp(|x25FGryj^3L_$D_IX}KdzDU4KEm2y)< zy<&q~)Y6UWnG$P_Z`P5w54ml46ihMQ&vF$vd6Lu?Sh=8NN5zJi%7@m8zR~S$UW^#l z6uuj-*79Mo!(iMd8H{t#Sl_?5e*LEN`%zh|Ct6jyL~NKcg$B6~cTXpj^WNo-Zm_zS zX=T1kdNRB>Ry1lWu6K`0LY%KA^`6A@HZy^x2ssP$em@S)^=pqSOC+0ox7wI2O3s<4 z8Gz~e0E_`4wxOy%#%cV9a`BthxUhK{pqJo@D$ougAQd^n}W&iqJRg-p(yr zX~^C1!$r9_lv0JfbT$Wfq zPtNpYK@+-Lpg30evNWS#wf`_Y`d9y9`>pf??5^Ak@Q$my_yO$vo>AhE^yf^Lt_EF~4!Wh0=_EsgX|VoH#kmbl5C@B197OfvTtwRP%fOa0jb zF=tbGTqzW4>^Z&_;;X}uV0z06a<4OrM(q5x=EGktXK!>Z^76w%=E*4Itj~;ZZQEpl zem|88alhrq%I2c9P`aS5;dqk68k^=AQ^{2))#One5P%Qt@FQ1uG(1ZNDHf;BqJ#Gf z@dwYa^FNcGY3*+{xw7SC(M3jM4*aOCJRP4sBYrlv~U6#?(9l~2r z!hVoY$Sv}Foi|bmZx4-g%v5}jB748en1+NCu<+6DrRy_?v|#2*Dc<=`eQ^UmQu$JE z5ww(=XR|>4>S!~KMn*pgo#^%P^H}K6eZF|*?EpLf6tyC`H%6+*Y{(-C>z-r*ue`F_ zGK8nYeolrNC{0vkSTlI$rn--{RW}B@0QQqNMhstM+&T*Ckd5fREmCVCg#%1UsoKvI ziN>_(1Q6P%?88XKVzLy$Z|uDu^leEa`grJ9a^~Yo1E|Ren_&Oa1eu6l4w#QdT*`N? zTMfRD!%QE#3K~1BRr(4VAi&sQdVWNSODM3)L2Za~b;8LCrVw%1G{uusQNn3^LV9p-|*O}*ese{JX zXD@m6#8)INn7w6{2jxW!^&^;gTi+Jxk&N6O8p`qUZhl}ESi7F21k~%yJaYbk0!tH4m_0c$Lo9R5HvD_||70(q)mlO*sI6o7& zt`?(O=g*XSKAZUX9T^3;Yphho&Z&iWG#5*9kM#}iqJMV*)SJ^*Ke4IFNe%c+(i^Wh z6urRcl75QZIln!AkB(8zggA{R{w74W=QAsec~w_(!>zPf1)NCkcvgiQQkw56U8r~S zEZDYtY^Y_vH;NKMphVVmnvT()N}`K5&opg~1$k6oEWq>PpQ#|;G|`e$g+NUSWGK{2 z5R)*H9ma-?lhEq9s(P67N^TpfSe2+OYuZ1y(h>YbLXB5 zOubj3N^+*SU~3P5!V?$o)?5Bu5~(FVbEYbYJg6Cn%2KEs36e|c)BKYKJBvY4N5B!!#L(P5uXP~&q-Q1;Bs`W|&82`VWO7RACn`Gqpk2t)k~ zxye{dl3yHD!f2(scnc?pdu7L?zhQ?#IbPysTuw3$F;99wd(!Tlq7 z`_*{X&*CsXy8vdd&u=0`#yJ(VTvc?AGA5UZNl{4eA{eig%;epx5^Rt}{%N+Igak%5 z=-WFlA5fj}1F4#+Y$mo`qOH&%rP$co#x?Iq`7nXV3H9T;B(WVF;9bU?IdyT~00hfp zA7rMlTh|kEp)qCyoIyL&awao;uKjy$ocjyK3N8`cs=OcM40s7Qx1Edm-fL3VLTc+M z#s!(pUkk}GcZ8sNIwPSZE(Ue;;-AkHx8%SdN}!85rr6) zuuLg*aNj5Uao$Y!357khNDg+!7(RJ(2|8Eod4bLtW6Ks%@HUyGD+r4c^xk|slJ&5D zB~0vn9Ic9EYD3f7BGpCx+{P?(zZxEDS1-Eukz%bmRhy{iNgt#;4uzQ&=G`N2I z*yD*-Cq(hco_~QQ^-CX{bKl&_h!(xW5fzlM$8Pmpulxhex7KT*yW+ez;K`r&r6`dP zHf2gTlKDG0)B?z*8973lr}bzFNpJj^sn5AGu*aIBapqXgyi58b_~Oo1 zGXdA&u$s~xXUm{An?d--mIWY_IQyj#EdDHRd_jCSH+7U>93eknls*oz zyy(=B38)S+E|aIjSOJ<1(?439PewP-TbQmA+hcr`wMCA^o%iD0qH5Q#A-*PMp`ZFL zeSoocy&m$JgnWXBT`w9>>Ty-Fqyle+*)yY3d|_}G%^q^dbb&6NrJZaFg}CmZ!mkrI2ec&~zxnHg&87fZi#@euG7qZ>phD}Ojzja0Vc zaGvmTCK;p2wk5DY?7@xW*?Gezr*7d*LTV8Xhec;S2M$U%cbJeSG_1yK=*EQn^!PBh z8EOTIpyfN7(nWMxy*DC$s&=?sum5bGw)>g`MmR@0w$mN+OfAgKkiDBv=!BZUFrF^{ zXcf>O(OB=(nsLk%N6&D?27+N?dW~u8uF3=M@r{wCgPEiGk}>3k)29qXEoW7@vX8Za zBKwj%V&x-4R>E<}4AbrGFn8*VvIS=ILP5HlmpvnC$?`KXUF#9ijTnT4!)rv3$3@*U zTd$4M`{A2YEz;X*MCZ^Hsn^_|!HM&9%qow)8*}`JxtbuK+O@B^*ijw6U1L7ibWSG? z+;~#KYpONWTph}KcudkC^PY#wV+P^b7Mqadc*XU6Z}0WKoUE+ju&9IKUWDqCY(-s9 zO>AN24b_vmX(=S`13*OsvU zY^gQY!F0&~6gq&grHuS4_dUb}U+SxLjq;BG#meil*m@ov1Mp>${3!4hxe5=Z(;(gc z%T9+}J;4h*%;@;l7ZN9Z&#~?l@5+$yka~(fIm5t+LA0?|CJi=pg+kRnD=V^OSif0) z;uqPWRLcV%S^46JH;V8{KES$3qsmW{M{8i=Nl#07Vo{0AD>83GXxn3#iK zRmGJom~yyqUviFFO48Mo4LxsGJme0pllJG4YM^G6@N;U;N}YmrB{)a|Rnh$4;}!P2 zt~#cQ^P467cAzfKclx0Ousw5CJW7YmtD&gXk)ymf>`5f|-ZH9;J|a8dtAqt%O`#bBVo3LZ6~KG~t{>W|`niXRjPLgIn+0QCeHcHV<7t576S?ip1yu4@WTT zq@;THxGAVmtNFCdA;&(7WCPq6O?Vsk&PzvN@pVci8vgpYT#>%z^vBX zNEL&1)lgMB1-1OAk3N{yR)6G(+kyCM(8|cGY0pR5P7ASpiJ8a`hE@UWv0ih757^yj z-@^*PpD*Rmp&EH8JyTQf)(xri*#F3TEs~~8f>gnW+zBdIwHVQrdO0yTB_73#0}@VH z8?EQ*sE>Gmai-EL4(aPx47I7T*TfkgC^{V49v=t{v8$?}HxTiZ7GbrtS{7;;4F4h} zX_h5%8KoT6Q2}#`IX4n%@M7Vf&nCZ85jBipevRUnyrF?ulKGeXfxGD!Zi$LlypF)1 zD(FAf^&f<+YTPi2%iC?fO;FMoR5@%B$J*D>>BqZ&XUsJ_b>`tft#a^X`4oHRm-8}w z=AdTPSTea1s~_ihvPg+Q9&R@2y_#w+f~ijf0BaER1YSBkO0VkhqI02uaK%`bZnOIf zLDmP>zP*gAv?+lC#ELoxtmCcRvG0;MI@v$#C4SI=CNcvCV}WIyGWLVFlcKm<-L+e} zQf@>kGlDNXBr%3m@9%9e`?Ch_m`kKj%%k%e37bHv6c_A076K|jS418*2=!%*;99(Sh%$`3Dt6A9xebsz2kFgB~*DWQ>p z?@NkNC0++@m6}{6DENRY*|)2?Kn4uE_)-M=P2ow|6>aJ$R8j5JtMScLUvtg~$<+KS zu>iI2d5YA zk@2Ti(>V>M10|T|;Yo&~P1Z0-;pcR@798*;@&RQp;xYHe&;TOyzG1$Yujq}Ittx}@ z-l8y9qGQISw6p6pq{`Jaha-3m=RQKJr}`pvP~la}doec*X@di39Ft^TY+`1jBkbhE zYT`s%r&Zctd_RSJHzqu$Z9BDdVCPthiWZntGz}f4vMfXN?$);qJQz3 zuCJc9HU8ziY&mr)bx^SYnJtrCHnCCerNxGt10Jq+cm5p8!9&q4Op=rsM1*K2=*$SpN`xMNUdNAGkd;2m5*c>x4w^ zSQ?4I5OIeouDI0IM+&rjW8a;E!uXmyP$;1YS0QEttJFs^0h;FQdR8F|am8dbFYo77 zC*2rM(^SDMnnxk!0<0vMBrgg{)7p#o21bxM+z1<(D5Q%!o!6}X-Z1m@<@WI_z0sF1 zQA{}CN@Uz8;Szs#$@Cu$5$YA(liQ8l&Kb@3nLh=)PZ;}RJJ{V5Dr|f;pc9(F=j1tz1D?$OpkS*f zv%$Bue&x>b4Ly@kR}VKPt4R+4J>ISRw+Z-LR8NQ8FYC{yPdzi@(TmEM74E6Py1rJ) zQ8-iDysF=li3ceTkef*;&19MJxLFj~IkJ-|T|6mOp*j@L$V!!8zs|Okm`*^+%pKgC zPS(vEo8VHWef^@R(x8}}=Wu?YO~NkbrO|{{xeKw-; + + \ No newline at end of file diff --git a/src/wechat_app/pages/index/index.wxss b/src/wechat_app/pages/index/index.wxss new file mode 100644 index 0000000..0aa5886 --- /dev/null +++ b/src/wechat_app/pages/index/index.wxss @@ -0,0 +1,11 @@ +page { + width: 100%; + height: 100%; +} +/* .list-container { + display: flex; + flex-direction: column; + justify-content: flex-start; + align-items: center; +} */ +button {margin: 10px;} \ No newline at end of file diff --git a/src/wechat_app/pages/logs/logs.js b/src/wechat_app/pages/logs/logs.js new file mode 100644 index 0000000..85f6aac --- /dev/null +++ b/src/wechat_app/pages/logs/logs.js @@ -0,0 +1,18 @@ +// logs.js +const util = require('../../utils/util.js') + +Page({ + data: { + logs: [] + }, + onLoad() { + this.setData({ + logs: (wx.getStorageSync('logs') || []).map(log => { + return { + date: util.formatTime(new Date(log)), + timeStamp: log + } + }) + }) + } +}) diff --git a/src/wechat_app/pages/logs/logs.json b/src/wechat_app/pages/logs/logs.json new file mode 100644 index 0000000..3ee76c1 --- /dev/null +++ b/src/wechat_app/pages/logs/logs.json @@ -0,0 +1,4 @@ +{ + "navigationBarTitleText": "查看启动日志", + "usingComponents": {} +} \ No newline at end of file diff --git a/src/wechat_app/pages/logs/logs.wxml b/src/wechat_app/pages/logs/logs.wxml new file mode 100644 index 0000000..0b6b645 --- /dev/null +++ b/src/wechat_app/pages/logs/logs.wxml @@ -0,0 +1,6 @@ + + + + {{index + 1}}. {{log.date}} + + diff --git a/src/wechat_app/pages/logs/logs.wxss b/src/wechat_app/pages/logs/logs.wxss new file mode 100644 index 0000000..94d4b88 --- /dev/null +++ b/src/wechat_app/pages/logs/logs.wxss @@ -0,0 +1,8 @@ +.log-list { + display: flex; + flex-direction: column; + padding: 40rpx; +} +.log-item { + margin: 10rpx; +} diff --git a/src/wechat_app/project.config.json b/src/wechat_app/project.config.json new file mode 100644 index 0000000..f76fd2c --- /dev/null +++ b/src/wechat_app/project.config.json @@ -0,0 +1,53 @@ +{ + "description": "项目配置文件", + "packOptions": { + "ignore": [], + "include": [] + }, + "setting": { + "bundle": false, + "userConfirmedBundleSwitch": false, + "urlCheck": true, + "scopeDataCheck": false, + "coverView": true, + "es6": true, + "postcss": true, + "compileHotReLoad": false, + "lazyloadPlaceholderEnable": false, + "preloadBackgroundData": false, + "minified": true, + "autoAudits": false, + "newFeature": false, + "uglifyFileName": false, + "uploadWithSourceMap": true, + "useIsolateContext": true, + "nodeModules": false, + "enhance": true, + "useMultiFrameRuntime": true, + "useApiHook": true, + "useApiHostProcess": true, + "showShadowRootInWxmlPanel": true, + "packNpmManually": false, + "enableEngineNative": false, + "packNpmRelationList": [], + "minifyWXSS": true, + "showES6CompileOption": false, + "minifyWXML": true, + "ignoreDevUnusedFiles": false, + "ignoreUploadUnusedFiles": false, + "babelSetting": { + "ignore": [], + "disablePlugins": [], + "outputPath": "" + } + }, + "compileType": "miniprogram", + "libVersion": "2.19.4", + "appid": "wx08af813924f7522e", + "projectname": "miniprogram-92", + "condition": {}, + "editorSetting": { + "tabIndent": "insertSpaces", + "tabSize": 4 + } +} \ No newline at end of file diff --git a/src/wechat_app/project.private.config.json b/src/wechat_app/project.private.config.json new file mode 100644 index 0000000..0c54f02 --- /dev/null +++ b/src/wechat_app/project.private.config.json @@ -0,0 +1,7 @@ +{ + "description": "项目私有配置文件。此文件中的内容将覆盖 project.config.json 中的相同字段。项目的改动优先同步到此文件中。详见文档:https://developers.weixin.qq.com/miniprogram/dev/devtools/projectconfig.html", + "projectname": "test_threejs", + "setting": { + "compileHotReLoad": true + } +} \ No newline at end of file diff --git a/src/wechat_app/sitemap.json b/src/wechat_app/sitemap.json new file mode 100644 index 0000000..ca02add --- /dev/null +++ b/src/wechat_app/sitemap.json @@ -0,0 +1,7 @@ +{ + "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", + "rules": [{ + "action": "allow", + "page": "*" + }] +} \ No newline at end of file diff --git a/src/wechat_app/utils/util.js b/src/wechat_app/utils/util.js new file mode 100644 index 0000000..764bc2c --- /dev/null +++ b/src/wechat_app/utils/util.js @@ -0,0 +1,19 @@ +const formatTime = date => { + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + const hour = date.getHours() + const minute = date.getMinutes() + const second = date.getSeconds() + + return `${[year, month, day].map(formatNumber).join('/')} ${[hour, minute, second].map(formatNumber).join(':')}` +} + +const formatNumber = n => { + n = n.toString() + return n[1] ? n : `0${n}` +} + +module.exports = { + formatTime +}