/*! @name videojs-vr @version 2.0.0 @license MIT */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('video.js')) :
typeof define === 'function' && define.amd ? define(['video.js'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.videojsVr = factory(global.videojs));
}(this, (function (videojs) { 'use strict';
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
var videojs__default = /*#__PURE__*/_interopDefaultLegacy(videojs);
var version$1 = "2.0.0";
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const isMobile = function () {
return /Android/i.test(navigator.userAgent) || /iPhone|iPad|iPod/i.test(navigator.userAgent);
};
const copyArray$1 = function (source, dest) {
for (var i = 0, n = source.length; i < n; i++) {
dest[i] = source[i];
}
};
const extend = function (dest, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) {
dest[key] = src[key];
}
}
return dest;
};
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var cardboardVrDisplay = {exports: {}};
/**
* @license
* cardboard-vr-display
* Copyright (c) 2015-2017 Google
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
(function (module, exports) {
/**
* @license
* gl-preserve-state
* Copyright (c) 2016, Brandon Jones.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* @license
* webvr-polyfill-dpdb
* Copyright (c) 2015-2017 Google
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @license
* nosleep.js
* Copyright (c) 2017, Rich Tibbett
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
(function (global, factory) {
module.exports = factory() ;
})(commonjsGlobal, function () {
var classCallCheck = function (instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
};
var createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
var slicedToArray = function () {
function sliceIterator(arr, i) {
var _arr = [];
var _n = true;
var _d = false;
var _e = undefined;
try {
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
_arr.push(_s.value);
if (i && _arr.length === i) break;
}
} catch (err) {
_d = true;
_e = err;
} finally {
try {
if (!_n && _i["return"]) _i["return"]();
} finally {
if (_d) throw _e;
}
}
return _arr;
}
return function (arr, i) {
if (Array.isArray(arr)) {
return arr;
} else if (Symbol.iterator in Object(arr)) {
return sliceIterator(arr, i);
} else {
throw new TypeError("Invalid attempt to destructure non-iterable instance");
}
};
}();
var MIN_TIMESTEP = 0.001;
var MAX_TIMESTEP = 1;
var dataUri = function dataUri(mimeType, svg) {
return 'data:' + mimeType + ',' + encodeURIComponent(svg);
};
var lerp = function lerp(a, b, t) {
return a + (b - a) * t;
};
var isIOS = function () {
var isIOS = /iPad|iPhone|iPod/.test(navigator.platform);
return function () {
return isIOS;
};
}();
var isWebViewAndroid = function () {
var isWebViewAndroid = navigator.userAgent.indexOf('Version') !== -1 && navigator.userAgent.indexOf('Android') !== -1 && navigator.userAgent.indexOf('Chrome') !== -1;
return function () {
return isWebViewAndroid;
};
}();
var isSafari = function () {
var isSafari = /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
return function () {
return isSafari;
};
}();
var isFirefoxAndroid = function () {
var isFirefoxAndroid = navigator.userAgent.indexOf('Firefox') !== -1 && navigator.userAgent.indexOf('Android') !== -1;
return function () {
return isFirefoxAndroid;
};
}();
var getChromeVersion = function () {
var match = navigator.userAgent.match(/.*Chrome\/([0-9]+)/);
var value = match ? parseInt(match[1], 10) : null;
return function () {
return value;
};
}();
var isSafariWithoutDeviceMotion = function () {
var value = false;
value = isIOS() && isSafari() && navigator.userAgent.indexOf('13_4') !== -1;
return function () {
return value;
};
}();
var isChromeWithoutDeviceMotion = function () {
var value = false;
if (getChromeVersion() === 65) {
var match = navigator.userAgent.match(/.*Chrome\/([0-9\.]*)/);
if (match) {
var _match$1$split = match[1].split('.'),
_match$1$split2 = slicedToArray(_match$1$split, 4);
_match$1$split2[0];
_match$1$split2[1];
var branch = _match$1$split2[2],
build = _match$1$split2[3];
value = parseInt(branch, 10) === 3325 && parseInt(build, 10) < 148;
}
}
return function () {
return value;
};
}();
var isR7 = function () {
var isR7 = navigator.userAgent.indexOf('R7 Build') !== -1;
return function () {
return isR7;
};
}();
var isLandscapeMode = function isLandscapeMode() {
var rtn = window.orientation == 90 || window.orientation == -90;
return isR7() ? !rtn : rtn;
};
var isTimestampDeltaValid = function isTimestampDeltaValid(timestampDeltaS) {
if (isNaN(timestampDeltaS)) {
return false;
}
if (timestampDeltaS <= MIN_TIMESTEP) {
return false;
}
if (timestampDeltaS > MAX_TIMESTEP) {
return false;
}
return true;
};
var getScreenWidth = function getScreenWidth() {
return Math.max(window.screen.width, window.screen.height) * window.devicePixelRatio;
};
var getScreenHeight = function getScreenHeight() {
return Math.min(window.screen.width, window.screen.height) * window.devicePixelRatio;
};
var requestFullscreen = function requestFullscreen(element) {
if (isWebViewAndroid()) {
return false;
}
if (element.requestFullscreen) {
element.requestFullscreen();
} else if (element.webkitRequestFullscreen) {
element.webkitRequestFullscreen();
} else if (element.mozRequestFullScreen) {
element.mozRequestFullScreen();
} else if (element.msRequestFullscreen) {
element.msRequestFullscreen();
} else {
return false;
}
return true;
};
var exitFullscreen = function exitFullscreen() {
if (document.exitFullscreen) {
document.exitFullscreen();
} else if (document.webkitExitFullscreen) {
document.webkitExitFullscreen();
} else if (document.mozCancelFullScreen) {
document.mozCancelFullScreen();
} else if (document.msExitFullscreen) {
document.msExitFullscreen();
} else {
return false;
}
return true;
};
var getFullscreenElement = function getFullscreenElement() {
return document.fullscreenElement || document.webkitFullscreenElement || document.mozFullScreenElement || document.msFullscreenElement;
};
var linkProgram = function linkProgram(gl, vertexSource, fragmentSource, attribLocationMap) {
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexSource);
gl.compileShader(vertexShader);
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentSource);
gl.compileShader(fragmentShader);
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
for (var attribName in attribLocationMap) {
gl.bindAttribLocation(program, attribLocationMap[attribName], attribName);
}
gl.linkProgram(program);
gl.deleteShader(vertexShader);
gl.deleteShader(fragmentShader);
return program;
};
var getProgramUniforms = function getProgramUniforms(gl, program) {
var uniforms = {};
var uniformCount = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
var uniformName = '';
for (var i = 0; i < uniformCount; i++) {
var uniformInfo = gl.getActiveUniform(program, i);
uniformName = uniformInfo.name.replace('[0]', '');
uniforms[uniformName] = gl.getUniformLocation(program, uniformName);
}
return uniforms;
};
var orthoMatrix = function orthoMatrix(out, left, right, bottom, top, near, far) {
var lr = 1 / (left - right),
bt = 1 / (bottom - top),
nf = 1 / (near - far);
out[0] = -2 * lr;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = -2 * bt;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 2 * nf;
out[11] = 0;
out[12] = (left + right) * lr;
out[13] = (top + bottom) * bt;
out[14] = (far + near) * nf;
out[15] = 1;
return out;
};
var isMobile = function isMobile() {
var check = false;
(function (a) {
if (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(a) || /1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0, 4))) check = true;
})(navigator.userAgent || navigator.vendor || window.opera);
return check;
};
var extend = function extend(dest, src) {
for (var key in src) {
if (src.hasOwnProperty(key)) {
dest[key] = src[key];
}
}
return dest;
};
var safariCssSizeWorkaround = function safariCssSizeWorkaround(canvas) {
if (isIOS()) {
var width = canvas.style.width;
var height = canvas.style.height;
canvas.style.width = parseInt(width) + 1 + 'px';
canvas.style.height = parseInt(height) + 'px';
setTimeout(function () {
canvas.style.width = width;
canvas.style.height = height;
}, 100);
}
window.canvas = canvas;
};
var frameDataFromPose = function () {
var piOver180 = Math.PI / 180.0;
var rad45 = Math.PI * 0.25;
function mat4_perspectiveFromFieldOfView(out, fov, near, far) {
var upTan = Math.tan(fov ? fov.upDegrees * piOver180 : rad45),
downTan = Math.tan(fov ? fov.downDegrees * piOver180 : rad45),
leftTan = Math.tan(fov ? fov.leftDegrees * piOver180 : rad45),
rightTan = Math.tan(fov ? fov.rightDegrees * piOver180 : rad45),
xScale = 2.0 / (leftTan + rightTan),
yScale = 2.0 / (upTan + downTan);
out[0] = xScale;
out[1] = 0.0;
out[2] = 0.0;
out[3] = 0.0;
out[4] = 0.0;
out[5] = yScale;
out[6] = 0.0;
out[7] = 0.0;
out[8] = -((leftTan - rightTan) * xScale * 0.5);
out[9] = (upTan - downTan) * yScale * 0.5;
out[10] = far / (near - far);
out[11] = -1.0;
out[12] = 0.0;
out[13] = 0.0;
out[14] = far * near / (near - far);
out[15] = 0.0;
return out;
}
function mat4_fromRotationTranslation(out, q, v) {
var x = q[0],
y = q[1],
z = q[2],
w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
xy = x * y2,
xz = x * z2,
yy = y * y2,
yz = y * z2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - (yy + zz);
out[1] = xy + wz;
out[2] = xz - wy;
out[3] = 0;
out[4] = xy - wz;
out[5] = 1 - (xx + zz);
out[6] = yz + wx;
out[7] = 0;
out[8] = xz + wy;
out[9] = yz - wx;
out[10] = 1 - (xx + yy);
out[11] = 0;
out[12] = v[0];
out[13] = v[1];
out[14] = v[2];
out[15] = 1;
return out;
}
function mat4_translate(out, a, v) {
var x = v[0],
y = v[1],
z = v[2],
a00,
a01,
a02,
a03,
a10,
a11,
a12,
a13,
a20,
a21,
a22,
a23;
if (a === out) {
out[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
out[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
out[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
out[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
} else {
a00 = a[0];
a01 = a[1];
a02 = a[2];
a03 = a[3];
a10 = a[4];
a11 = a[5];
a12 = a[6];
a13 = a[7];
a20 = a[8];
a21 = a[9];
a22 = a[10];
a23 = a[11];
out[0] = a00;
out[1] = a01;
out[2] = a02;
out[3] = a03;
out[4] = a10;
out[5] = a11;
out[6] = a12;
out[7] = a13;
out[8] = a20;
out[9] = a21;
out[10] = a22;
out[11] = a23;
out[12] = a00 * x + a10 * y + a20 * z + a[12];
out[13] = a01 * x + a11 * y + a21 * z + a[13];
out[14] = a02 * x + a12 * y + a22 * z + a[14];
out[15] = a03 * x + a13 * y + a23 * z + a[15];
}
return out;
}
function mat4_invert(out, a) {
var a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11],
a30 = a[12],
a31 = a[13],
a32 = a[14],
a33 = a[15],
b00 = a00 * a11 - a01 * a10,
b01 = a00 * a12 - a02 * a10,
b02 = a00 * a13 - a03 * a10,
b03 = a01 * a12 - a02 * a11,
b04 = a01 * a13 - a03 * a11,
b05 = a02 * a13 - a03 * a12,
b06 = a20 * a31 - a21 * a30,
b07 = a20 * a32 - a22 * a30,
b08 = a20 * a33 - a23 * a30,
b09 = a21 * a32 - a22 * a31,
b10 = a21 * a33 - a23 * a31,
b11 = a22 * a33 - a23 * a32,
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
if (!det) {
return null;
}
det = 1.0 / det;
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
out[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
out[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
out[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
out[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
out[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
out[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
out[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
out[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
out[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
out[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
out[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
out[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
out[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
out[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
return out;
}
var defaultOrientation = new Float32Array([0, 0, 0, 1]);
var defaultPosition = new Float32Array([0, 0, 0]);
function updateEyeMatrices(projection, view, pose, fov, offset, vrDisplay) {
mat4_perspectiveFromFieldOfView(projection, fov || null, vrDisplay.depthNear, vrDisplay.depthFar);
var orientation = pose.orientation || defaultOrientation;
var position = pose.position || defaultPosition;
mat4_fromRotationTranslation(view, orientation, position);
if (offset) mat4_translate(view, view, offset);
mat4_invert(view, view);
}
return function (frameData, pose, vrDisplay) {
if (!frameData || !pose) return false;
frameData.pose = pose;
frameData.timestamp = pose.timestamp;
updateEyeMatrices(frameData.leftProjectionMatrix, frameData.leftViewMatrix, pose, vrDisplay._getFieldOfView("left"), vrDisplay._getEyeOffset("left"), vrDisplay);
updateEyeMatrices(frameData.rightProjectionMatrix, frameData.rightViewMatrix, pose, vrDisplay._getFieldOfView("right"), vrDisplay._getEyeOffset("right"), vrDisplay);
return true;
};
}();
var isInsideCrossOriginIFrame = function isInsideCrossOriginIFrame() {
var isFramed = window.self !== window.top;
var refOrigin = getOriginFromUrl(document.referrer);
var thisOrigin = getOriginFromUrl(window.location.href);
return isFramed && refOrigin !== thisOrigin;
};
var getOriginFromUrl = function getOriginFromUrl(url) {
var domainIdx;
var protoSepIdx = url.indexOf("://");
if (protoSepIdx !== -1) {
domainIdx = protoSepIdx + 3;
} else {
domainIdx = 0;
}
var domainEndIdx = url.indexOf('/', domainIdx);
if (domainEndIdx === -1) {
domainEndIdx = url.length;
}
return url.substring(0, domainEndIdx);
};
var getQuaternionAngle = function getQuaternionAngle(quat) {
if (quat.w > 1) {
console.warn('getQuaternionAngle: w > 1');
return 0;
}
var angle = 2 * Math.acos(quat.w);
return angle;
};
var warnOnce = function () {
var observedWarnings = {};
return function (key, message) {
if (observedWarnings[key] === undefined) {
console.warn('webvr-polyfill: ' + message);
observedWarnings[key] = true;
}
};
}();
var deprecateWarning = function deprecateWarning(deprecated, suggested) {
var alternative = suggested ? 'Please use ' + suggested + ' instead.' : '';
warnOnce(deprecated, deprecated + ' has been deprecated. ' + 'This may not work on native WebVR displays. ' + alternative);
};
function WGLUPreserveGLState(gl, bindings, callback) {
if (!bindings) {
callback(gl);
return;
}
var boundValues = [];
var activeTexture = null;
for (var i = 0; i < bindings.length; ++i) {
var binding = bindings[i];
switch (binding) {
case gl.TEXTURE_BINDING_2D:
case gl.TEXTURE_BINDING_CUBE_MAP:
var textureUnit = bindings[++i];
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) {
console.error("TEXTURE_BINDING_2D or TEXTURE_BINDING_CUBE_MAP must be followed by a valid texture unit");
boundValues.push(null, null);
break;
}
if (!activeTexture) {
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
}
gl.activeTexture(textureUnit);
boundValues.push(gl.getParameter(binding), null);
break;
case gl.ACTIVE_TEXTURE:
activeTexture = gl.getParameter(gl.ACTIVE_TEXTURE);
boundValues.push(null);
break;
default:
boundValues.push(gl.getParameter(binding));
break;
}
}
callback(gl);
for (var i = 0; i < bindings.length; ++i) {
var binding = bindings[i];
var boundValue = boundValues[i];
switch (binding) {
case gl.ACTIVE_TEXTURE:
break;
case gl.ARRAY_BUFFER_BINDING:
gl.bindBuffer(gl.ARRAY_BUFFER, boundValue);
break;
case gl.COLOR_CLEAR_VALUE:
gl.clearColor(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
break;
case gl.COLOR_WRITEMASK:
gl.colorMask(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
break;
case gl.CURRENT_PROGRAM:
gl.useProgram(boundValue);
break;
case gl.ELEMENT_ARRAY_BUFFER_BINDING:
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, boundValue);
break;
case gl.FRAMEBUFFER_BINDING:
gl.bindFramebuffer(gl.FRAMEBUFFER, boundValue);
break;
case gl.RENDERBUFFER_BINDING:
gl.bindRenderbuffer(gl.RENDERBUFFER, boundValue);
break;
case gl.TEXTURE_BINDING_2D:
var textureUnit = bindings[++i];
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) break;
gl.activeTexture(textureUnit);
gl.bindTexture(gl.TEXTURE_2D, boundValue);
break;
case gl.TEXTURE_BINDING_CUBE_MAP:
var textureUnit = bindings[++i];
if (textureUnit < gl.TEXTURE0 || textureUnit > gl.TEXTURE31) break;
gl.activeTexture(textureUnit);
gl.bindTexture(gl.TEXTURE_CUBE_MAP, boundValue);
break;
case gl.VIEWPORT:
gl.viewport(boundValue[0], boundValue[1], boundValue[2], boundValue[3]);
break;
case gl.BLEND:
case gl.CULL_FACE:
case gl.DEPTH_TEST:
case gl.SCISSOR_TEST:
case gl.STENCIL_TEST:
if (boundValue) {
gl.enable(binding);
} else {
gl.disable(binding);
}
break;
default:
console.log("No GL restore behavior for 0x" + binding.toString(16));
break;
}
if (activeTexture) {
gl.activeTexture(activeTexture);
}
}
}
var glPreserveState = WGLUPreserveGLState;
var distortionVS = ['attribute vec2 position;', 'attribute vec3 texCoord;', 'varying vec2 vTexCoord;', 'uniform vec4 viewportOffsetScale[2];', 'void main() {', ' vec4 viewport = viewportOffsetScale[int(texCoord.z)];', ' vTexCoord = (texCoord.xy * viewport.zw) + viewport.xy;', ' gl_Position = vec4( position, 1.0, 1.0 );', '}'].join('\n');
var distortionFS = ['precision mediump float;', 'uniform sampler2D diffuse;', 'varying vec2 vTexCoord;', 'void main() {', ' gl_FragColor = texture2D(diffuse, vTexCoord);', '}'].join('\n');
function CardboardDistorter(gl, cardboardUI, bufferScale, dirtySubmitFrameBindings) {
this.gl = gl;
this.cardboardUI = cardboardUI;
this.bufferScale = bufferScale;
this.dirtySubmitFrameBindings = dirtySubmitFrameBindings;
this.ctxAttribs = gl.getContextAttributes();
this.instanceExt = gl.getExtension('ANGLE_instanced_arrays');
this.meshWidth = 20;
this.meshHeight = 20;
this.bufferWidth = gl.drawingBufferWidth;
this.bufferHeight = gl.drawingBufferHeight;
this.realBindFramebuffer = gl.bindFramebuffer;
this.realEnable = gl.enable;
this.realDisable = gl.disable;
this.realColorMask = gl.colorMask;
this.realClearColor = gl.clearColor;
this.realViewport = gl.viewport;
if (!isIOS()) {
this.realCanvasWidth = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'width');
this.realCanvasHeight = Object.getOwnPropertyDescriptor(gl.canvas.__proto__, 'height');
}
this.isPatched = false;
this.lastBoundFramebuffer = null;
this.cullFace = false;
this.depthTest = false;
this.blend = false;
this.scissorTest = false;
this.stencilTest = false;
this.viewport = [0, 0, 0, 0];
this.colorMask = [true, true, true, true];
this.clearColor = [0, 0, 0, 0];
this.attribs = {
position: 0,
texCoord: 1
};
this.program = linkProgram(gl, distortionVS, distortionFS, this.attribs);
this.uniforms = getProgramUniforms(gl, this.program);
this.viewportOffsetScale = new Float32Array(8);
this.setTextureBounds();
this.vertexBuffer = gl.createBuffer();
this.indexBuffer = gl.createBuffer();
this.indexCount = 0;
this.renderTarget = gl.createTexture();
this.framebuffer = gl.createFramebuffer();
this.depthStencilBuffer = null;
this.depthBuffer = null;
this.stencilBuffer = null;
if (this.ctxAttribs.depth && this.ctxAttribs.stencil) {
this.depthStencilBuffer = gl.createRenderbuffer();
} else if (this.ctxAttribs.depth) {
this.depthBuffer = gl.createRenderbuffer();
} else if (this.ctxAttribs.stencil) {
this.stencilBuffer = gl.createRenderbuffer();
}
this.patch();
this.onResize();
}
CardboardDistorter.prototype.destroy = function () {
var gl = this.gl;
this.unpatch();
gl.deleteProgram(this.program);
gl.deleteBuffer(this.vertexBuffer);
gl.deleteBuffer(this.indexBuffer);
gl.deleteTexture(this.renderTarget);
gl.deleteFramebuffer(this.framebuffer);
if (this.depthStencilBuffer) {
gl.deleteRenderbuffer(this.depthStencilBuffer);
}
if (this.depthBuffer) {
gl.deleteRenderbuffer(this.depthBuffer);
}
if (this.stencilBuffer) {
gl.deleteRenderbuffer(this.stencilBuffer);
}
if (this.cardboardUI) {
this.cardboardUI.destroy();
}
};
CardboardDistorter.prototype.onResize = function () {
var gl = this.gl;
var self = this;
var glState = [gl.RENDERBUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0];
glPreserveState(gl, glState, function (gl) {
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
if (self.scissorTest) {
self.realDisable.call(gl, gl.SCISSOR_TEST);
}
self.realColorMask.call(gl, true, true, true, true);
self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
self.realClearColor.call(gl, 0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.framebuffer);
gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
gl.texImage2D(gl.TEXTURE_2D, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, self.bufferWidth, self.bufferHeight, 0, self.ctxAttribs.alpha ? gl.RGBA : gl.RGB, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, self.renderTarget, 0);
if (self.ctxAttribs.depth && self.ctxAttribs.stencil) {
gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthStencilBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, self.bufferWidth, self.bufferHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.depthStencilBuffer);
} else if (self.ctxAttribs.depth) {
gl.bindRenderbuffer(gl.RENDERBUFFER, self.depthBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, self.bufferWidth, self.bufferHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, self.depthBuffer);
} else if (self.ctxAttribs.stencil) {
gl.bindRenderbuffer(gl.RENDERBUFFER, self.stencilBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.STENCIL_INDEX8, self.bufferWidth, self.bufferHeight);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.STENCIL_ATTACHMENT, gl.RENDERBUFFER, self.stencilBuffer);
}
if (!gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) {
console.error('Framebuffer incomplete!');
}
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
if (self.scissorTest) {
self.realEnable.call(gl, gl.SCISSOR_TEST);
}
self.realColorMask.apply(gl, self.colorMask);
self.realViewport.apply(gl, self.viewport);
self.realClearColor.apply(gl, self.clearColor);
});
if (this.cardboardUI) {
this.cardboardUI.onResize();
}
};
CardboardDistorter.prototype.patch = function () {
if (this.isPatched) {
return;
}
var self = this;
var canvas = this.gl.canvas;
var gl = this.gl;
if (!isIOS()) {
canvas.width = getScreenWidth() * this.bufferScale;
canvas.height = getScreenHeight() * this.bufferScale;
Object.defineProperty(canvas, 'width', {
configurable: true,
enumerable: true,
get: function get() {
return self.bufferWidth;
},
set: function set(value) {
self.bufferWidth = value;
self.realCanvasWidth.set.call(canvas, value);
self.onResize();
}
});
Object.defineProperty(canvas, 'height', {
configurable: true,
enumerable: true,
get: function get() {
return self.bufferHeight;
},
set: function set(value) {
self.bufferHeight = value;
self.realCanvasHeight.set.call(canvas, value);
self.onResize();
}
});
}
this.lastBoundFramebuffer = gl.getParameter(gl.FRAMEBUFFER_BINDING);
if (this.lastBoundFramebuffer == null) {
this.lastBoundFramebuffer = this.framebuffer;
this.gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
}
this.gl.bindFramebuffer = function (target, framebuffer) {
self.lastBoundFramebuffer = framebuffer ? framebuffer : self.framebuffer;
self.realBindFramebuffer.call(gl, target, self.lastBoundFramebuffer);
};
this.cullFace = gl.getParameter(gl.CULL_FACE);
this.depthTest = gl.getParameter(gl.DEPTH_TEST);
this.blend = gl.getParameter(gl.BLEND);
this.scissorTest = gl.getParameter(gl.SCISSOR_TEST);
this.stencilTest = gl.getParameter(gl.STENCIL_TEST);
gl.enable = function (pname) {
switch (pname) {
case gl.CULL_FACE:
self.cullFace = true;
break;
case gl.DEPTH_TEST:
self.depthTest = true;
break;
case gl.BLEND:
self.blend = true;
break;
case gl.SCISSOR_TEST:
self.scissorTest = true;
break;
case gl.STENCIL_TEST:
self.stencilTest = true;
break;
}
self.realEnable.call(gl, pname);
};
gl.disable = function (pname) {
switch (pname) {
case gl.CULL_FACE:
self.cullFace = false;
break;
case gl.DEPTH_TEST:
self.depthTest = false;
break;
case gl.BLEND:
self.blend = false;
break;
case gl.SCISSOR_TEST:
self.scissorTest = false;
break;
case gl.STENCIL_TEST:
self.stencilTest = false;
break;
}
self.realDisable.call(gl, pname);
};
this.colorMask = gl.getParameter(gl.COLOR_WRITEMASK);
gl.colorMask = function (r, g, b, a) {
self.colorMask[0] = r;
self.colorMask[1] = g;
self.colorMask[2] = b;
self.colorMask[3] = a;
self.realColorMask.call(gl, r, g, b, a);
};
this.clearColor = gl.getParameter(gl.COLOR_CLEAR_VALUE);
gl.clearColor = function (r, g, b, a) {
self.clearColor[0] = r;
self.clearColor[1] = g;
self.clearColor[2] = b;
self.clearColor[3] = a;
self.realClearColor.call(gl, r, g, b, a);
};
this.viewport = gl.getParameter(gl.VIEWPORT);
gl.viewport = function (x, y, w, h) {
self.viewport[0] = x;
self.viewport[1] = y;
self.viewport[2] = w;
self.viewport[3] = h;
self.realViewport.call(gl, x, y, w, h);
};
this.isPatched = true;
safariCssSizeWorkaround(canvas);
};
CardboardDistorter.prototype.unpatch = function () {
if (!this.isPatched) {
return;
}
var gl = this.gl;
var canvas = this.gl.canvas;
if (!isIOS()) {
Object.defineProperty(canvas, 'width', this.realCanvasWidth);
Object.defineProperty(canvas, 'height', this.realCanvasHeight);
}
canvas.width = this.bufferWidth;
canvas.height = this.bufferHeight;
gl.bindFramebuffer = this.realBindFramebuffer;
gl.enable = this.realEnable;
gl.disable = this.realDisable;
gl.colorMask = this.realColorMask;
gl.clearColor = this.realClearColor;
gl.viewport = this.realViewport;
if (this.lastBoundFramebuffer == this.framebuffer) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
this.isPatched = false;
setTimeout(function () {
safariCssSizeWorkaround(canvas);
}, 1);
};
CardboardDistorter.prototype.setTextureBounds = function (leftBounds, rightBounds) {
if (!leftBounds) {
leftBounds = [0, 0, 0.5, 1];
}
if (!rightBounds) {
rightBounds = [0.5, 0, 0.5, 1];
}
this.viewportOffsetScale[0] = leftBounds[0];
this.viewportOffsetScale[1] = leftBounds[1];
this.viewportOffsetScale[2] = leftBounds[2];
this.viewportOffsetScale[3] = leftBounds[3];
this.viewportOffsetScale[4] = rightBounds[0];
this.viewportOffsetScale[5] = rightBounds[1];
this.viewportOffsetScale[6] = rightBounds[2];
this.viewportOffsetScale[7] = rightBounds[3];
};
CardboardDistorter.prototype.submitFrame = function () {
var gl = this.gl;
var self = this;
var glState = [];
if (!this.dirtySubmitFrameBindings) {
glState.push(gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING, gl.TEXTURE_BINDING_2D, gl.TEXTURE0);
}
glPreserveState(gl, glState, function (gl) {
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, null);
var positionDivisor = 0;
var texCoordDivisor = 0;
if (self.instanceExt) {
positionDivisor = gl.getVertexAttrib(self.attribs.position, self.instanceExt.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
texCoordDivisor = gl.getVertexAttrib(self.attribs.texCoord, self.instanceExt.VERTEX_ATTRIB_ARRAY_DIVISOR_ANGLE);
}
if (self.cullFace) {
self.realDisable.call(gl, gl.CULL_FACE);
}
if (self.depthTest) {
self.realDisable.call(gl, gl.DEPTH_TEST);
}
if (self.blend) {
self.realDisable.call(gl, gl.BLEND);
}
if (self.scissorTest) {
self.realDisable.call(gl, gl.SCISSOR_TEST);
}
if (self.stencilTest) {
self.realDisable.call(gl, gl.STENCIL_TEST);
}
self.realColorMask.call(gl, true, true, true, true);
self.realViewport.call(gl, 0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
if (self.ctxAttribs.alpha || isIOS()) {
self.realClearColor.call(gl, 0, 0, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
}
gl.useProgram(self.program);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
gl.enableVertexAttribArray(self.attribs.position);
gl.enableVertexAttribArray(self.attribs.texCoord);
gl.vertexAttribPointer(self.attribs.position, 2, gl.FLOAT, false, 20, 0);
gl.vertexAttribPointer(self.attribs.texCoord, 3, gl.FLOAT, false, 20, 8);
if (self.instanceExt) {
if (positionDivisor != 0) {
self.instanceExt.vertexAttribDivisorANGLE(self.attribs.position, 0);
}
if (texCoordDivisor != 0) {
self.instanceExt.vertexAttribDivisorANGLE(self.attribs.texCoord, 0);
}
}
gl.activeTexture(gl.TEXTURE0);
gl.uniform1i(self.uniforms.diffuse, 0);
gl.bindTexture(gl.TEXTURE_2D, self.renderTarget);
gl.uniform4fv(self.uniforms.viewportOffsetScale, self.viewportOffsetScale);
gl.drawElements(gl.TRIANGLES, self.indexCount, gl.UNSIGNED_SHORT, 0);
if (self.cardboardUI) {
self.cardboardUI.renderNoState();
}
self.realBindFramebuffer.call(self.gl, gl.FRAMEBUFFER, self.framebuffer);
if (!self.ctxAttribs.preserveDrawingBuffer) {
self.realClearColor.call(gl, 0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
}
if (!self.dirtySubmitFrameBindings) {
self.realBindFramebuffer.call(gl, gl.FRAMEBUFFER, self.lastBoundFramebuffer);
}
if (self.cullFace) {
self.realEnable.call(gl, gl.CULL_FACE);
}
if (self.depthTest) {
self.realEnable.call(gl, gl.DEPTH_TEST);
}
if (self.blend) {
self.realEnable.call(gl, gl.BLEND);
}
if (self.scissorTest) {
self.realEnable.call(gl, gl.SCISSOR_TEST);
}
if (self.stencilTest) {
self.realEnable.call(gl, gl.STENCIL_TEST);
}
self.realColorMask.apply(gl, self.colorMask);
self.realViewport.apply(gl, self.viewport);
if (self.ctxAttribs.alpha || !self.ctxAttribs.preserveDrawingBuffer) {
self.realClearColor.apply(gl, self.clearColor);
}
if (self.instanceExt) {
if (positionDivisor != 0) {
self.instanceExt.vertexAttribDivisorANGLE(self.attribs.position, positionDivisor);
}
if (texCoordDivisor != 0) {
self.instanceExt.vertexAttribDivisorANGLE(self.attribs.texCoord, texCoordDivisor);
}
}
});
if (isIOS()) {
var canvas = gl.canvas;
if (canvas.width != self.bufferWidth || canvas.height != self.bufferHeight) {
self.bufferWidth = canvas.width;
self.bufferHeight = canvas.height;
self.onResize();
}
}
};
CardboardDistorter.prototype.updateDeviceInfo = function (deviceInfo) {
var gl = this.gl;
var self = this;
var glState = [gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING];
glPreserveState(gl, glState, function (gl) {
var vertices = self.computeMeshVertices_(self.meshWidth, self.meshHeight, deviceInfo);
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
if (!self.indexCount) {
var indices = self.computeMeshIndices_(self.meshWidth, self.meshHeight);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, self.indexBuffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
self.indexCount = indices.length;
}
});
};
CardboardDistorter.prototype.computeMeshVertices_ = function (width, height, deviceInfo) {
var vertices = new Float32Array(2 * width * height * 5);
var lensFrustum = deviceInfo.getLeftEyeVisibleTanAngles();
var noLensFrustum = deviceInfo.getLeftEyeNoLensTanAngles();
var viewport = deviceInfo.getLeftEyeVisibleScreenRect(noLensFrustum);
var vidx = 0;
for (var e = 0; e < 2; e++) {
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++, vidx++) {
var u = i / (width - 1);
var v = j / (height - 1);
var s = u;
var t = v;
var x = lerp(lensFrustum[0], lensFrustum[2], u);
var y = lerp(lensFrustum[3], lensFrustum[1], v);
var d = Math.sqrt(x * x + y * y);
var r = deviceInfo.distortion.distortInverse(d);
var p = x * r / d;
var q = y * r / d;
u = (p - noLensFrustum[0]) / (noLensFrustum[2] - noLensFrustum[0]);
v = (q - noLensFrustum[3]) / (noLensFrustum[1] - noLensFrustum[3]);
u = (viewport.x + u * viewport.width - 0.5) * 2.0;
v = (viewport.y + v * viewport.height - 0.5) * 2.0;
vertices[vidx * 5 + 0] = u;
vertices[vidx * 5 + 1] = v;
vertices[vidx * 5 + 2] = s;
vertices[vidx * 5 + 3] = t;
vertices[vidx * 5 + 4] = e;
}
}
var w = lensFrustum[2] - lensFrustum[0];
lensFrustum[0] = -(w + lensFrustum[0]);
lensFrustum[2] = w - lensFrustum[2];
w = noLensFrustum[2] - noLensFrustum[0];
noLensFrustum[0] = -(w + noLensFrustum[0]);
noLensFrustum[2] = w - noLensFrustum[2];
viewport.x = 1 - (viewport.x + viewport.width);
}
return vertices;
};
CardboardDistorter.prototype.computeMeshIndices_ = function (width, height) {
var indices = new Uint16Array(2 * (width - 1) * (height - 1) * 6);
var halfwidth = width / 2;
var halfheight = height / 2;
var vidx = 0;
var iidx = 0;
for (var e = 0; e < 2; e++) {
for (var j = 0; j < height; j++) {
for (var i = 0; i < width; i++, vidx++) {
if (i == 0 || j == 0) continue;
if (i <= halfwidth == j <= halfheight) {
indices[iidx++] = vidx;
indices[iidx++] = vidx - width - 1;
indices[iidx++] = vidx - width;
indices[iidx++] = vidx - width - 1;
indices[iidx++] = vidx;
indices[iidx++] = vidx - 1;
} else {
indices[iidx++] = vidx - 1;
indices[iidx++] = vidx - width;
indices[iidx++] = vidx;
indices[iidx++] = vidx - width;
indices[iidx++] = vidx - 1;
indices[iidx++] = vidx - width - 1;
}
}
}
}
return indices;
};
CardboardDistorter.prototype.getOwnPropertyDescriptor_ = function (proto, attrName) {
var descriptor = Object.getOwnPropertyDescriptor(proto, attrName);
if (descriptor.get === undefined || descriptor.set === undefined) {
descriptor.configurable = true;
descriptor.enumerable = true;
descriptor.get = function () {
return this.getAttribute(attrName);
};
descriptor.set = function (val) {
this.setAttribute(attrName, val);
};
}
return descriptor;
};
var uiVS = ['attribute vec2 position;', 'uniform mat4 projectionMat;', 'void main() {', ' gl_Position = projectionMat * vec4( position, -1.0, 1.0 );', '}'].join('\n');
var uiFS = ['precision mediump float;', 'uniform vec4 color;', 'void main() {', ' gl_FragColor = color;', '}'].join('\n');
var DEG2RAD = Math.PI / 180.0;
var kAnglePerGearSection = 60;
var kOuterRimEndAngle = 12;
var kInnerRimBeginAngle = 20;
var kOuterRadius = 1;
var kMiddleRadius = 0.75;
var kInnerRadius = 0.3125;
var kCenterLineThicknessDp = 4;
var kButtonWidthDp = 28;
var kTouchSlopFactor = 1.5;
function CardboardUI(gl) {
this.gl = gl;
this.attribs = {
position: 0
};
this.program = linkProgram(gl, uiVS, uiFS, this.attribs);
this.uniforms = getProgramUniforms(gl, this.program);
this.vertexBuffer = gl.createBuffer();
this.gearOffset = 0;
this.gearVertexCount = 0;
this.arrowOffset = 0;
this.arrowVertexCount = 0;
this.projMat = new Float32Array(16);
this.listener = null;
this.onResize();
}
CardboardUI.prototype.destroy = function () {
var gl = this.gl;
if (this.listener) {
gl.canvas.removeEventListener('click', this.listener, false);
}
gl.deleteProgram(this.program);
gl.deleteBuffer(this.vertexBuffer);
};
CardboardUI.prototype.listen = function (optionsCallback, backCallback) {
var canvas = this.gl.canvas;
this.listener = function (event) {
var midline = canvas.clientWidth / 2;
var buttonSize = kButtonWidthDp * kTouchSlopFactor;
if (event.clientX > midline - buttonSize && event.clientX < midline + buttonSize && event.clientY > canvas.clientHeight - buttonSize) {
optionsCallback(event);
} else if (event.clientX < buttonSize && event.clientY < buttonSize) {
backCallback(event);
}
};
canvas.addEventListener('click', this.listener, false);
};
CardboardUI.prototype.onResize = function () {
var gl = this.gl;
var self = this;
var glState = [gl.ARRAY_BUFFER_BINDING];
glPreserveState(gl, glState, function (gl) {
var vertices = [];
var midline = gl.drawingBufferWidth / 2;
var physicalPixels = Math.max(screen.width, screen.height) * window.devicePixelRatio;
var scalingRatio = gl.drawingBufferWidth / physicalPixels;
var dps = scalingRatio * window.devicePixelRatio;
var lineWidth = kCenterLineThicknessDp * dps / 2;
var buttonSize = kButtonWidthDp * kTouchSlopFactor * dps;
var buttonScale = kButtonWidthDp * dps / 2;
var buttonBorder = (kButtonWidthDp * kTouchSlopFactor - kButtonWidthDp) * dps;
vertices.push(midline - lineWidth, buttonSize);
vertices.push(midline - lineWidth, gl.drawingBufferHeight);
vertices.push(midline + lineWidth, buttonSize);
vertices.push(midline + lineWidth, gl.drawingBufferHeight);
self.gearOffset = vertices.length / 2;
function addGearSegment(theta, r) {
var angle = (90 - theta) * DEG2RAD;
var x = Math.cos(angle);
var y = Math.sin(angle);
vertices.push(kInnerRadius * x * buttonScale + midline, kInnerRadius * y * buttonScale + buttonScale);
vertices.push(r * x * buttonScale + midline, r * y * buttonScale + buttonScale);
}
for (var i = 0; i <= 6; i++) {
var segmentTheta = i * kAnglePerGearSection;
addGearSegment(segmentTheta, kOuterRadius);
addGearSegment(segmentTheta + kOuterRimEndAngle, kOuterRadius);
addGearSegment(segmentTheta + kInnerRimBeginAngle, kMiddleRadius);
addGearSegment(segmentTheta + (kAnglePerGearSection - kInnerRimBeginAngle), kMiddleRadius);
addGearSegment(segmentTheta + (kAnglePerGearSection - kOuterRimEndAngle), kOuterRadius);
}
self.gearVertexCount = vertices.length / 2 - self.gearOffset;
self.arrowOffset = vertices.length / 2;
function addArrowVertex(x, y) {
vertices.push(buttonBorder + x, gl.drawingBufferHeight - buttonBorder - y);
}
var angledLineWidth = lineWidth / Math.sin(45 * DEG2RAD);
addArrowVertex(0, buttonScale);
addArrowVertex(buttonScale, 0);
addArrowVertex(buttonScale + angledLineWidth, angledLineWidth);
addArrowVertex(angledLineWidth, buttonScale + angledLineWidth);
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
addArrowVertex(0, buttonScale);
addArrowVertex(buttonScale, buttonScale * 2);
addArrowVertex(buttonScale + angledLineWidth, buttonScale * 2 - angledLineWidth);
addArrowVertex(angledLineWidth, buttonScale - angledLineWidth);
addArrowVertex(0, buttonScale);
addArrowVertex(angledLineWidth, buttonScale - lineWidth);
addArrowVertex(kButtonWidthDp * dps, buttonScale - lineWidth);
addArrowVertex(angledLineWidth, buttonScale + lineWidth);
addArrowVertex(kButtonWidthDp * dps, buttonScale + lineWidth);
self.arrowVertexCount = vertices.length / 2 - self.arrowOffset;
gl.bindBuffer(gl.ARRAY_BUFFER, self.vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
});
};
CardboardUI.prototype.render = function () {
var gl = this.gl;
var self = this;
var glState = [gl.CULL_FACE, gl.DEPTH_TEST, gl.BLEND, gl.SCISSOR_TEST, gl.STENCIL_TEST, gl.COLOR_WRITEMASK, gl.VIEWPORT, gl.CURRENT_PROGRAM, gl.ARRAY_BUFFER_BINDING];
glPreserveState(gl, glState, function (gl) {
gl.disable(gl.CULL_FACE);
gl.disable(gl.DEPTH_TEST);
gl.disable(gl.BLEND);
gl.disable(gl.SCISSOR_TEST);
gl.disable(gl.STENCIL_TEST);
gl.colorMask(true, true, true, true);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
self.renderNoState();
});
};
CardboardUI.prototype.renderNoState = function () {
var gl = this.gl;
gl.useProgram(this.program);
gl.bindBuffer(gl.ARRAY_BUFFER, this.vertexBuffer);
gl.enableVertexAttribArray(this.attribs.position);
gl.vertexAttribPointer(this.attribs.position, 2, gl.FLOAT, false, 8, 0);
gl.uniform4f(this.uniforms.color, 1.0, 1.0, 1.0, 1.0);
orthoMatrix(this.projMat, 0, gl.drawingBufferWidth, 0, gl.drawingBufferHeight, 0.1, 1024.0);
gl.uniformMatrix4fv(this.uniforms.projectionMat, false, this.projMat);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
gl.drawArrays(gl.TRIANGLE_STRIP, this.gearOffset, this.gearVertexCount);
gl.drawArrays(gl.TRIANGLE_STRIP, this.arrowOffset, this.arrowVertexCount);
};
function Distortion(coefficients) {
this.coefficients = coefficients;
}
Distortion.prototype.distortInverse = function (radius) {
var r0 = 0;
var r1 = 1;
var dr0 = radius - this.distort(r0);
while (Math.abs(r1 - r0) > 0.0001) {
var dr1 = radius - this.distort(r1);
var r2 = r1 - dr1 * ((r1 - r0) / (dr1 - dr0));
r0 = r1;
r1 = r2;
dr0 = dr1;
}
return r1;
};
Distortion.prototype.distort = function (radius) {
var r2 = radius * radius;
var ret = 0;
for (var i = 0; i < this.coefficients.length; i++) {
ret = r2 * (ret + this.coefficients[i]);
}
return (ret + 1) * radius;
};
var degToRad = Math.PI / 180;
var radToDeg = 180 / Math.PI;
var Vector3 = function Vector3(x, y, z) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
};
Vector3.prototype = {
constructor: Vector3,
set: function set(x, y, z) {
this.x = x;
this.y = y;
this.z = z;
return this;
},
copy: function copy(v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
},
length: function length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
},
normalize: function normalize() {
var scalar = this.length();
if (scalar !== 0) {
var invScalar = 1 / scalar;
this.multiplyScalar(invScalar);
} else {
this.x = 0;
this.y = 0;
this.z = 0;
}
return this;
},
multiplyScalar: function multiplyScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
},
applyQuaternion: function applyQuaternion(q) {
var x = this.x;
var y = this.y;
var z = this.z;
var qx = q.x;
var qy = q.y;
var qz = q.z;
var qw = q.w;
var ix = qw * x + qy * z - qz * y;
var iy = qw * y + qz * x - qx * z;
var iz = qw * z + qx * y - qy * x;
var iw = -qx * x - qy * y - qz * z;
this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return this;
},
dot: function dot(v) {
return this.x * v.x + this.y * v.y + this.z * v.z;
},
crossVectors: function crossVectors(a, b) {
var ax = a.x,
ay = a.y,
az = a.z;
var bx = b.x,
by = b.y,
bz = b.z;
this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;
return this;
}
};
var Quaternion = function Quaternion(x, y, z, w) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = w !== undefined ? w : 1;
};
Quaternion.prototype = {
constructor: Quaternion,
set: function set(x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
},
copy: function copy(quaternion) {
this.x = quaternion.x;
this.y = quaternion.y;
this.z = quaternion.z;
this.w = quaternion.w;
return this;
},
setFromEulerXYZ: function setFromEulerXYZ(x, y, z) {
var c1 = Math.cos(x / 2);
var c2 = Math.cos(y / 2);
var c3 = Math.cos(z / 2);
var s1 = Math.sin(x / 2);
var s2 = Math.sin(y / 2);
var s3 = Math.sin(z / 2);
this.x = s1 * c2 * c3 + c1 * s2 * s3;
this.y = c1 * s2 * c3 - s1 * c2 * s3;
this.z = c1 * c2 * s3 + s1 * s2 * c3;
this.w = c1 * c2 * c3 - s1 * s2 * s3;
return this;
},
setFromEulerYXZ: function setFromEulerYXZ(x, y, z) {
var c1 = Math.cos(x / 2);
var c2 = Math.cos(y / 2);
var c3 = Math.cos(z / 2);
var s1 = Math.sin(x / 2);
var s2 = Math.sin(y / 2);
var s3 = Math.sin(z / 2);
this.x = s1 * c2 * c3 + c1 * s2 * s3;
this.y = c1 * s2 * c3 - s1 * c2 * s3;
this.z = c1 * c2 * s3 - s1 * s2 * c3;
this.w = c1 * c2 * c3 + s1 * s2 * s3;
return this;
},
setFromAxisAngle: function setFromAxisAngle(axis, angle) {
var halfAngle = angle / 2,
s = Math.sin(halfAngle);
this.x = axis.x * s;
this.y = axis.y * s;
this.z = axis.z * s;
this.w = Math.cos(halfAngle);
return this;
},
multiply: function multiply(q) {
return this.multiplyQuaternions(this, q);
},
multiplyQuaternions: function multiplyQuaternions(a, b) {
var qax = a.x,
qay = a.y,
qaz = a.z,
qaw = a.w;
var qbx = b.x,
qby = b.y,
qbz = b.z,
qbw = b.w;
this.x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
this.y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
this.z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
this.w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
return this;
},
inverse: function inverse() {
this.x *= -1;
this.y *= -1;
this.z *= -1;
this.normalize();
return this;
},
normalize: function normalize() {
var l = Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
if (l === 0) {
this.x = 0;
this.y = 0;
this.z = 0;
this.w = 1;
} else {
l = 1 / l;
this.x = this.x * l;
this.y = this.y * l;
this.z = this.z * l;
this.w = this.w * l;
}
return this;
},
slerp: function slerp(qb, t) {
if (t === 0) return this;
if (t === 1) return this.copy(qb);
var x = this.x,
y = this.y,
z = this.z,
w = this.w;
var cosHalfTheta = w * qb.w + x * qb.x + y * qb.y + z * qb.z;
if (cosHalfTheta < 0) {
this.w = -qb.w;
this.x = -qb.x;
this.y = -qb.y;
this.z = -qb.z;
cosHalfTheta = -cosHalfTheta;
} else {
this.copy(qb);
}
if (cosHalfTheta >= 1.0) {
this.w = w;
this.x = x;
this.y = y;
this.z = z;
return this;
}
var halfTheta = Math.acos(cosHalfTheta);
var sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta);
if (Math.abs(sinHalfTheta) < 0.001) {
this.w = 0.5 * (w + this.w);
this.x = 0.5 * (x + this.x);
this.y = 0.5 * (y + this.y);
this.z = 0.5 * (z + this.z);
return this;
}
var ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
this.w = w * ratioA + this.w * ratioB;
this.x = x * ratioA + this.x * ratioB;
this.y = y * ratioA + this.y * ratioB;
this.z = z * ratioA + this.z * ratioB;
return this;
},
setFromUnitVectors: function () {
var v1, r;
var EPS = 0.000001;
return function (vFrom, vTo) {
if (v1 === undefined) v1 = new Vector3();
r = vFrom.dot(vTo) + 1;
if (r < EPS) {
r = 0;
if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
v1.set(-vFrom.y, vFrom.x, 0);
} else {
v1.set(0, -vFrom.z, vFrom.y);
}
} else {
v1.crossVectors(vFrom, vTo);
}
this.x = v1.x;
this.y = v1.y;
this.z = v1.z;
this.w = r;
this.normalize();
return this;
};
}()
};
function Device(params) {
this.width = params.width || getScreenWidth();
this.height = params.height || getScreenHeight();
this.widthMeters = params.widthMeters;
this.heightMeters = params.heightMeters;
this.bevelMeters = params.bevelMeters;
}
var DEFAULT_ANDROID = new Device({
widthMeters: 0.110,
heightMeters: 0.062,
bevelMeters: 0.004
});
var DEFAULT_IOS = new Device({
widthMeters: 0.1038,
heightMeters: 0.0584,
bevelMeters: 0.004
});
var Viewers = {
CardboardV1: new CardboardViewer({
id: 'CardboardV1',
label: 'Cardboard I/O 2014',
fov: 40,
interLensDistance: 0.060,
baselineLensDistance: 0.035,
screenLensDistance: 0.042,
distortionCoefficients: [0.441, 0.156],
inverseCoefficients: [-0.4410035, 0.42756155, -0.4804439, 0.5460139, -0.58821183, 0.5733938, -0.48303202, 0.33299083, -0.17573841, 0.0651772, -0.01488963, 0.001559834]
}),
CardboardV2: new CardboardViewer({
id: 'CardboardV2',
label: 'Cardboard I/O 2015',
fov: 60,
interLensDistance: 0.064,
baselineLensDistance: 0.035,
screenLensDistance: 0.039,
distortionCoefficients: [0.34, 0.55],
inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051, 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956, -9.904169E-4, 6.183535E-5, -1.6981803E-6]
})
};
function DeviceInfo(deviceParams, additionalViewers) {
this.viewer = Viewers.CardboardV2;
this.updateDeviceParams(deviceParams);
this.distortion = new Distortion(this.viewer.distortionCoefficients);
for (var i = 0; i < additionalViewers.length; i++) {
var viewer = additionalViewers[i];
Viewers[viewer.id] = new CardboardViewer(viewer);
}
}
DeviceInfo.prototype.updateDeviceParams = function (deviceParams) {
this.device = this.determineDevice_(deviceParams) || this.device;
};
DeviceInfo.prototype.getDevice = function () {
return this.device;
};
DeviceInfo.prototype.setViewer = function (viewer) {
this.viewer = viewer;
this.distortion = new Distortion(this.viewer.distortionCoefficients);
};
DeviceInfo.prototype.determineDevice_ = function (deviceParams) {
if (!deviceParams) {
if (isIOS()) {
console.warn('Using fallback iOS device measurements.');
return DEFAULT_IOS;
} else {
console.warn('Using fallback Android device measurements.');
return DEFAULT_ANDROID;
}
}
var METERS_PER_INCH = 0.0254;
var metersPerPixelX = METERS_PER_INCH / deviceParams.xdpi;
var metersPerPixelY = METERS_PER_INCH / deviceParams.ydpi;
var width = getScreenWidth();
var height = getScreenHeight();
return new Device({
widthMeters: metersPerPixelX * width,
heightMeters: metersPerPixelY * height,
bevelMeters: deviceParams.bevelMm * 0.001
});
};
DeviceInfo.prototype.getDistortedFieldOfViewLeftEye = function () {
var viewer = this.viewer;
var device = this.device;
var distortion = this.distortion;
var eyeToScreenDistance = viewer.screenLensDistance;
var outerDist = (device.widthMeters - viewer.interLensDistance) / 2;
var innerDist = viewer.interLensDistance / 2;
var bottomDist = viewer.baselineLensDistance - device.bevelMeters;
var topDist = device.heightMeters - bottomDist;
var outerAngle = radToDeg * Math.atan(distortion.distort(outerDist / eyeToScreenDistance));
var innerAngle = radToDeg * Math.atan(distortion.distort(innerDist / eyeToScreenDistance));
var bottomAngle = radToDeg * Math.atan(distortion.distort(bottomDist / eyeToScreenDistance));
var topAngle = radToDeg * Math.atan(distortion.distort(topDist / eyeToScreenDistance));
return {
leftDegrees: Math.min(outerAngle, viewer.fov),
rightDegrees: Math.min(innerAngle, viewer.fov),
downDegrees: Math.min(bottomAngle, viewer.fov),
upDegrees: Math.min(topAngle, viewer.fov)
};
};
DeviceInfo.prototype.getLeftEyeVisibleTanAngles = function () {
var viewer = this.viewer;
var device = this.device;
var distortion = this.distortion;
var fovLeft = Math.tan(-degToRad * viewer.fov);
var fovTop = Math.tan(degToRad * viewer.fov);
var fovRight = Math.tan(degToRad * viewer.fov);
var fovBottom = Math.tan(-degToRad * viewer.fov);
var halfWidth = device.widthMeters / 4;
var halfHeight = device.heightMeters / 2;
var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
var centerX = viewer.interLensDistance / 2 - halfWidth;
var centerY = -verticalLensOffset;
var centerZ = viewer.screenLensDistance;
var screenLeft = distortion.distort((centerX - halfWidth) / centerZ);
var screenTop = distortion.distort((centerY + halfHeight) / centerZ);
var screenRight = distortion.distort((centerX + halfWidth) / centerZ);
var screenBottom = distortion.distort((centerY - halfHeight) / centerZ);
var result = new Float32Array(4);
result[0] = Math.max(fovLeft, screenLeft);
result[1] = Math.min(fovTop, screenTop);
result[2] = Math.min(fovRight, screenRight);
result[3] = Math.max(fovBottom, screenBottom);
return result;
};
DeviceInfo.prototype.getLeftEyeNoLensTanAngles = function () {
var viewer = this.viewer;
var device = this.device;
var distortion = this.distortion;
var result = new Float32Array(4);
var fovLeft = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
var fovTop = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
var fovRight = distortion.distortInverse(Math.tan(degToRad * viewer.fov));
var fovBottom = distortion.distortInverse(Math.tan(-degToRad * viewer.fov));
var halfWidth = device.widthMeters / 4;
var halfHeight = device.heightMeters / 2;
var verticalLensOffset = viewer.baselineLensDistance - device.bevelMeters - halfHeight;
var centerX = viewer.interLensDistance / 2 - halfWidth;
var centerY = -verticalLensOffset;
var centerZ = viewer.screenLensDistance;
var screenLeft = (centerX - halfWidth) / centerZ;
var screenTop = (centerY + halfHeight) / centerZ;
var screenRight = (centerX + halfWidth) / centerZ;
var screenBottom = (centerY - halfHeight) / centerZ;
result[0] = Math.max(fovLeft, screenLeft);
result[1] = Math.min(fovTop, screenTop);
result[2] = Math.min(fovRight, screenRight);
result[3] = Math.max(fovBottom, screenBottom);
return result;
};
DeviceInfo.prototype.getLeftEyeVisibleScreenRect = function (undistortedFrustum) {
var viewer = this.viewer;
var device = this.device;
var dist = viewer.screenLensDistance;
var eyeX = (device.widthMeters - viewer.interLensDistance) / 2;
var eyeY = viewer.baselineLensDistance - device.bevelMeters;
var left = (undistortedFrustum[0] * dist + eyeX) / device.widthMeters;
var top = (undistortedFrustum[1] * dist + eyeY) / device.heightMeters;
var right = (undistortedFrustum[2] * dist + eyeX) / device.widthMeters;
var bottom = (undistortedFrustum[3] * dist + eyeY) / device.heightMeters;
return {
x: left,
y: bottom,
width: right - left,
height: top - bottom
};
};
DeviceInfo.prototype.getFieldOfViewLeftEye = function (opt_isUndistorted) {
return opt_isUndistorted ? this.getUndistortedFieldOfViewLeftEye() : this.getDistortedFieldOfViewLeftEye();
};
DeviceInfo.prototype.getFieldOfViewRightEye = function (opt_isUndistorted) {
var fov = this.getFieldOfViewLeftEye(opt_isUndistorted);
return {
leftDegrees: fov.rightDegrees,
rightDegrees: fov.leftDegrees,
upDegrees: fov.upDegrees,
downDegrees: fov.downDegrees
};
};
DeviceInfo.prototype.getUndistortedFieldOfViewLeftEye = function () {
var p = this.getUndistortedParams_();
return {
leftDegrees: radToDeg * Math.atan(p.outerDist),
rightDegrees: radToDeg * Math.atan(p.innerDist),
downDegrees: radToDeg * Math.atan(p.bottomDist),
upDegrees: radToDeg * Math.atan(p.topDist)
};
};
DeviceInfo.prototype.getUndistortedViewportLeftEye = function () {
var p = this.getUndistortedParams_();
var viewer = this.viewer;
var device = this.device;
var eyeToScreenDistance = viewer.screenLensDistance;
var screenWidth = device.widthMeters / eyeToScreenDistance;
var screenHeight = device.heightMeters / eyeToScreenDistance;
var xPxPerTanAngle = device.width / screenWidth;
var yPxPerTanAngle = device.height / screenHeight;
var x = Math.round((p.eyePosX - p.outerDist) * xPxPerTanAngle);
var y = Math.round((p.eyePosY - p.bottomDist) * yPxPerTanAngle);
return {
x: x,
y: y,
width: Math.round((p.eyePosX + p.innerDist) * xPxPerTanAngle) - x,
height: Math.round((p.eyePosY + p.topDist) * yPxPerTanAngle) - y
};
};
DeviceInfo.prototype.getUndistortedParams_ = function () {
var viewer = this.viewer;
var device = this.device;
var distortion = this.distortion;
var eyeToScreenDistance = viewer.screenLensDistance;
var halfLensDistance = viewer.interLensDistance / 2 / eyeToScreenDistance;
var screenWidth = device.widthMeters / eyeToScreenDistance;
var screenHeight = device.heightMeters / eyeToScreenDistance;
var eyePosX = screenWidth / 2 - halfLensDistance;
var eyePosY = (viewer.baselineLensDistance - device.bevelMeters) / eyeToScreenDistance;
var maxFov = viewer.fov;
var viewerMax = distortion.distortInverse(Math.tan(degToRad * maxFov));
var outerDist = Math.min(eyePosX, viewerMax);
var innerDist = Math.min(halfLensDistance, viewerMax);
var bottomDist = Math.min(eyePosY, viewerMax);
var topDist = Math.min(screenHeight - eyePosY, viewerMax);
return {
outerDist: outerDist,
innerDist: innerDist,
topDist: topDist,
bottomDist: bottomDist,
eyePosX: eyePosX,
eyePosY: eyePosY
};
};
function CardboardViewer(params) {
this.id = params.id;
this.label = params.label;
this.fov = params.fov;
this.interLensDistance = params.interLensDistance;
this.baselineLensDistance = params.baselineLensDistance;
this.screenLensDistance = params.screenLensDistance;
this.distortionCoefficients = params.distortionCoefficients;
this.inverseCoefficients = params.inverseCoefficients;
}
DeviceInfo.Viewers = Viewers;
var format = 1;
var last_updated = "2019-11-09T17:36:14Z";
var devices = [{
"type": "android",
"rules": [{
"mdmh": "asus/*/Nexus 7/*"
}, {
"ua": "Nexus 7"
}],
"dpi": [320.8, 323],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "asus/*/ASUS_X00PD/*"
}, {
"ua": "ASUS_X00PD"
}],
"dpi": 245,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "asus/*/ASUS_X008D/*"
}, {
"ua": "ASUS_X008D"
}],
"dpi": 282,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "asus/*/ASUS_Z00AD/*"
}, {
"ua": "ASUS_Z00AD"
}],
"dpi": [403, 404.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel 2 XL/*"
}, {
"ua": "Pixel 2 XL"
}],
"dpi": 537.9,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel 3 XL/*"
}, {
"ua": "Pixel 3 XL"
}],
"dpi": [558.5, 553.8],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel XL/*"
}, {
"ua": "Pixel XL"
}],
"dpi": [537.9, 533],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel 3/*"
}, {
"ua": "Pixel 3"
}],
"dpi": 442.4,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel 2/*"
}, {
"ua": "Pixel 2"
}],
"dpi": 441,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "Google/*/Pixel/*"
}, {
"ua": "Pixel"
}],
"dpi": [432.6, 436.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "HTC/*/HTC6435LVW/*"
}, {
"ua": "HTC6435LVW"
}],
"dpi": [449.7, 443.3],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "HTC/*/HTC One XL/*"
}, {
"ua": "HTC One XL"
}],
"dpi": [315.3, 314.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "htc/*/Nexus 9/*"
}, {
"ua": "Nexus 9"
}],
"dpi": 289,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "HTC/*/HTC One M9/*"
}, {
"ua": "HTC One M9"
}],
"dpi": [442.5, 443.3],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "HTC/*/HTC One_M8/*"
}, {
"ua": "HTC One_M8"
}],
"dpi": [449.7, 447.4],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "HTC/*/HTC One/*"
}, {
"ua": "HTC One"
}],
"dpi": 472.8,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Huawei/*/Nexus 6P/*"
}, {
"ua": "Nexus 6P"
}],
"dpi": [515.1, 518],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Huawei/*/BLN-L24/*"
}, {
"ua": "HONORBLN-L24"
}],
"dpi": 480,
"bw": 4,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "Huawei/*/BKL-L09/*"
}, {
"ua": "BKL-L09"
}],
"dpi": 403,
"bw": 3.47,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "LENOVO/*/Lenovo PB2-690Y/*"
}, {
"ua": "Lenovo PB2-690Y"
}],
"dpi": [457.2, 454.713],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/Nexus 5X/*"
}, {
"ua": "Nexus 5X"
}],
"dpi": [422, 419.9],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LGMS345/*"
}, {
"ua": "LGMS345"
}],
"dpi": [221.7, 219.1],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LG-D800/*"
}, {
"ua": "LG-D800"
}],
"dpi": [422, 424.1],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LG-D850/*"
}, {
"ua": "LG-D850"
}],
"dpi": [537.9, 541.9],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/VS985 4G/*"
}, {
"ua": "VS985 4G"
}],
"dpi": [537.9, 535.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/Nexus 5/*"
}, {
"ua": "Nexus 5 B"
}],
"dpi": [442.4, 444.8],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/Nexus 4/*"
}, {
"ua": "Nexus 4"
}],
"dpi": [319.8, 318.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LG-P769/*"
}, {
"ua": "LG-P769"
}],
"dpi": [240.6, 247.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LGMS323/*"
}, {
"ua": "LGMS323"
}],
"dpi": [206.6, 204.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "LGE/*/LGLS996/*"
}, {
"ua": "LGLS996"
}],
"dpi": [403.4, 401.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Micromax/*/4560MMX/*"
}, {
"ua": "4560MMX"
}],
"dpi": [240, 219.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Micromax/*/A250/*"
}, {
"ua": "Micromax A250"
}],
"dpi": [480, 446.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Micromax/*/Micromax AQ4501/*"
}, {
"ua": "Micromax AQ4501"
}],
"dpi": 240,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/G5/*"
}, {
"ua": "Moto G (5) Plus"
}],
"dpi": [403.4, 403],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/DROID RAZR/*"
}, {
"ua": "DROID RAZR"
}],
"dpi": [368.1, 256.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT830C/*"
}, {
"ua": "XT830C"
}],
"dpi": [254, 255.9],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1021/*"
}, {
"ua": "XT1021"
}],
"dpi": [254, 256.7],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1023/*"
}, {
"ua": "XT1023"
}],
"dpi": [254, 256.7],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1028/*"
}, {
"ua": "XT1028"
}],
"dpi": [326.6, 327.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1034/*"
}, {
"ua": "XT1034"
}],
"dpi": [326.6, 328.4],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1053/*"
}, {
"ua": "XT1053"
}],
"dpi": [315.3, 316.1],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1562/*"
}, {
"ua": "XT1562"
}],
"dpi": [403.4, 402.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/Nexus 6/*"
}, {
"ua": "Nexus 6 B"
}],
"dpi": [494.3, 489.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1063/*"
}, {
"ua": "XT1063"
}],
"dpi": [295, 296.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1064/*"
}, {
"ua": "XT1064"
}],
"dpi": [295, 295.6],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1092/*"
}, {
"ua": "XT1092"
}],
"dpi": [422, 424.1],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/XT1095/*"
}, {
"ua": "XT1095"
}],
"dpi": [422, 423.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "motorola/*/G4/*"
}, {
"ua": "Moto G (4)"
}],
"dpi": 401,
"bw": 4,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/A0001/*"
}, {
"ua": "A0001"
}],
"dpi": [403.4, 401],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE E1001/*"
}, {
"ua": "ONE E1001"
}],
"dpi": [442.4, 441.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE E1003/*"
}, {
"ua": "ONE E1003"
}],
"dpi": [442.4, 441.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE E1005/*"
}, {
"ua": "ONE E1005"
}],
"dpi": [442.4, 441.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE A2001/*"
}, {
"ua": "ONE A2001"
}],
"dpi": [391.9, 405.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE A2003/*"
}, {
"ua": "ONE A2003"
}],
"dpi": [391.9, 405.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE A2005/*"
}, {
"ua": "ONE A2005"
}],
"dpi": [391.9, 405.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A3000/*"
}, {
"ua": "ONEPLUS A3000"
}],
"dpi": 401,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A3003/*"
}, {
"ua": "ONEPLUS A3003"
}],
"dpi": 401,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A3010/*"
}, {
"ua": "ONEPLUS A3010"
}],
"dpi": 401,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A5000/*"
}, {
"ua": "ONEPLUS A5000 "
}],
"dpi": [403.411, 399.737],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONE A5010/*"
}, {
"ua": "ONEPLUS A5010"
}],
"dpi": [403, 400],
"bw": 2,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A6000/*"
}, {
"ua": "ONEPLUS A6000"
}],
"dpi": 401,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A6003/*"
}, {
"ua": "ONEPLUS A6003"
}],
"dpi": 401,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A6010/*"
}, {
"ua": "ONEPLUS A6010"
}],
"dpi": 401,
"bw": 2,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OnePlus/*/ONEPLUS A6013/*"
}, {
"ua": "ONEPLUS A6013"
}],
"dpi": 401,
"bw": 2,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "OPPO/*/X909/*"
}, {
"ua": "X909"
}],
"dpi": [442.4, 444.1],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9082/*"
}, {
"ua": "GT-I9082"
}],
"dpi": [184.7, 185.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G360P/*"
}, {
"ua": "SM-G360P"
}],
"dpi": [196.7, 205.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/Nexus S/*"
}, {
"ua": "Nexus S"
}],
"dpi": [234.5, 229.8],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9300/*"
}, {
"ua": "GT-I9300"
}],
"dpi": [304.8, 303.9],
"bw": 5,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-T230NU/*"
}, {
"ua": "SM-T230NU"
}],
"dpi": 216,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SGH-T399/*"
}, {
"ua": "SGH-T399"
}],
"dpi": [217.7, 231.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SGH-M919/*"
}, {
"ua": "SGH-M919"
}],
"dpi": [440.8, 437.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N9005/*"
}, {
"ua": "SM-N9005"
}],
"dpi": [386.4, 387],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SAMSUNG-SM-N900A/*"
}, {
"ua": "SAMSUNG-SM-N900A"
}],
"dpi": [386.4, 387.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9500/*"
}, {
"ua": "GT-I9500"
}],
"dpi": [442.5, 443.3],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9505/*"
}, {
"ua": "GT-I9505"
}],
"dpi": 439.4,
"bw": 4,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G900F/*"
}, {
"ua": "SM-G900F"
}],
"dpi": [415.6, 431.6],
"bw": 5,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G900M/*"
}, {
"ua": "SM-G900M"
}],
"dpi": [415.6, 431.6],
"bw": 5,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G800F/*"
}, {
"ua": "SM-G800F"
}],
"dpi": 326.8,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G906S/*"
}, {
"ua": "SM-G906S"
}],
"dpi": [562.7, 572.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9300/*"
}, {
"ua": "GT-I9300"
}],
"dpi": [306.7, 304.8],
"bw": 5,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-T535/*"
}, {
"ua": "SM-T535"
}],
"dpi": [142.6, 136.4],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N920C/*"
}, {
"ua": "SM-N920C"
}],
"dpi": [515.1, 518.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N920P/*"
}, {
"ua": "SM-N920P"
}],
"dpi": [386.3655, 390.144],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N920W8/*"
}, {
"ua": "SM-N920W8"
}],
"dpi": [515.1, 518.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9300I/*"
}, {
"ua": "GT-I9300I"
}],
"dpi": [304.8, 305.8],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-I9195/*"
}, {
"ua": "GT-I9195"
}],
"dpi": [249.4, 256.7],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SPH-L520/*"
}, {
"ua": "SPH-L520"
}],
"dpi": [249.4, 255.9],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SAMSUNG-SGH-I717/*"
}, {
"ua": "SAMSUNG-SGH-I717"
}],
"dpi": 285.8,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SPH-D710/*"
}, {
"ua": "SPH-D710"
}],
"dpi": [217.7, 204.2],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/GT-N7100/*"
}, {
"ua": "GT-N7100"
}],
"dpi": 265.1,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SCH-I605/*"
}, {
"ua": "SCH-I605"
}],
"dpi": 265.1,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/Galaxy Nexus/*"
}, {
"ua": "Galaxy Nexus"
}],
"dpi": [315.3, 314.2],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N910H/*"
}, {
"ua": "SM-N910H"
}],
"dpi": [515.1, 518],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-N910C/*"
}, {
"ua": "SM-N910C"
}],
"dpi": [515.2, 520.2],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G130M/*"
}, {
"ua": "SM-G130M"
}],
"dpi": [165.9, 164.8],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G928I/*"
}, {
"ua": "SM-G928I"
}],
"dpi": [515.1, 518.4],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G920F/*"
}, {
"ua": "SM-G920F"
}],
"dpi": 580.6,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G920P/*"
}, {
"ua": "SM-G920P"
}],
"dpi": [522.5, 577],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G925F/*"
}, {
"ua": "SM-G925F"
}],
"dpi": 580.6,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G925V/*"
}, {
"ua": "SM-G925V"
}],
"dpi": [522.5, 576.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G930F/*"
}, {
"ua": "SM-G930F"
}],
"dpi": 576.6,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G935F/*"
}, {
"ua": "SM-G935F"
}],
"dpi": 533,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G950F/*"
}, {
"ua": "SM-G950F"
}],
"dpi": [562.707, 565.293],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G955U/*"
}, {
"ua": "SM-G955U"
}],
"dpi": [522.514, 525.762],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G955F/*"
}, {
"ua": "SM-G955F"
}],
"dpi": [522.514, 525.762],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960F/*"
}, {
"ua": "SM-G960F"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G9600/*"
}, {
"ua": "SM-G9600"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960T/*"
}, {
"ua": "SM-G960T"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960N/*"
}, {
"ua": "SM-G960N"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960U/*"
}, {
"ua": "SM-G960U"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G9608/*"
}, {
"ua": "SM-G9608"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960FD/*"
}, {
"ua": "SM-G960FD"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G960W/*"
}, {
"ua": "SM-G960W"
}],
"dpi": [569.575, 571.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G965F/*"
}, {
"ua": "SM-G965F"
}],
"dpi": 529,
"bw": 2,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Sony/*/C6903/*"
}, {
"ua": "C6903"
}],
"dpi": [442.5, 443.3],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "Sony/*/D6653/*"
}, {
"ua": "D6653"
}],
"dpi": [428.6, 427.6],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Sony/*/E6653/*"
}, {
"ua": "E6653"
}],
"dpi": [428.6, 425.7],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Sony/*/E6853/*"
}, {
"ua": "E6853"
}],
"dpi": [403.4, 401.9],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Sony/*/SGP321/*"
}, {
"ua": "SGP321"
}],
"dpi": [224.7, 224.1],
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "TCT/*/ALCATEL ONE TOUCH Fierce/*"
}, {
"ua": "ALCATEL ONE TOUCH Fierce"
}],
"dpi": [240, 247.5],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "THL/*/thl 5000/*"
}, {
"ua": "thl 5000"
}],
"dpi": [480, 443.3],
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Fly/*/IQ4412/*"
}, {
"ua": "IQ4412"
}],
"dpi": 307.9,
"bw": 3,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "ZTE/*/ZTE Blade L2/*"
}, {
"ua": "ZTE Blade L2"
}],
"dpi": 240,
"bw": 3,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "BENEVE/*/VR518/*"
}, {
"ua": "VR518"
}],
"dpi": 480,
"bw": 3,
"ac": 500
}, {
"type": "ios",
"rules": [{
"res": [640, 960]
}],
"dpi": [325.1, 328.4],
"bw": 4,
"ac": 1000
}, {
"type": "ios",
"rules": [{
"res": [640, 1136]
}],
"dpi": [317.1, 320.2],
"bw": 3,
"ac": 1000
}, {
"type": "ios",
"rules": [{
"res": [750, 1334]
}],
"dpi": 326.4,
"bw": 4,
"ac": 1000
}, {
"type": "ios",
"rules": [{
"res": [1242, 2208]
}],
"dpi": [453.6, 458.4],
"bw": 4,
"ac": 1000
}, {
"type": "ios",
"rules": [{
"res": [1125, 2001]
}],
"dpi": [410.9, 415.4],
"bw": 4,
"ac": 1000
}, {
"type": "ios",
"rules": [{
"res": [1125, 2436]
}],
"dpi": 458,
"bw": 4,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "Huawei/*/EML-L29/*"
}, {
"ua": "EML-L29"
}],
"dpi": 428,
"bw": 3.45,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "Nokia/*/Nokia 7.1/*"
}, {
"ua": "Nokia 7.1"
}],
"dpi": [432, 431.9],
"bw": 3,
"ac": 500
}, {
"type": "ios",
"rules": [{
"res": [1242, 2688]
}],
"dpi": 458,
"bw": 4,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G570M/*"
}, {
"ua": "SM-G570M"
}],
"dpi": 320,
"bw": 3.684,
"ac": 1000
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G970F/*"
}, {
"ua": "SM-G970F"
}],
"dpi": 438,
"bw": 2.281,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G973F/*"
}, {
"ua": "SM-G973F"
}],
"dpi": 550,
"bw": 2.002,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G975F/*"
}, {
"ua": "SM-G975F"
}],
"dpi": 522,
"bw": 2.054,
"ac": 500
}, {
"type": "android",
"rules": [{
"mdmh": "samsung/*/SM-G977F/*"
}, {
"ua": "SM-G977F"
}],
"dpi": 505,
"bw": 2.334,
"ac": 500
}, {
"type": "ios",
"rules": [{
"res": [828, 1792]
}],
"dpi": 326,
"bw": 5,
"ac": 500
}];
var DPDB_CACHE = {
format: format,
last_updated: last_updated,
devices: devices
};
function Dpdb(url, onDeviceParamsUpdated) {
this.dpdb = DPDB_CACHE;
this.recalculateDeviceParams_();
if (url) {
this.onDeviceParamsUpdated = onDeviceParamsUpdated;
var xhr = new XMLHttpRequest();
var obj = this;
xhr.open('GET', url, true);
xhr.addEventListener('load', function () {
obj.loading = false;
if (xhr.status >= 200 && xhr.status <= 299) {
obj.dpdb = JSON.parse(xhr.response);
obj.recalculateDeviceParams_();
} else {
console.error('Error loading online DPDB!');
}
});
xhr.send();
}
}
Dpdb.prototype.getDeviceParams = function () {
return this.deviceParams;
};
Dpdb.prototype.recalculateDeviceParams_ = function () {
var newDeviceParams = this.calcDeviceParams_();
if (newDeviceParams) {
this.deviceParams = newDeviceParams;
if (this.onDeviceParamsUpdated) {
this.onDeviceParamsUpdated(this.deviceParams);
}
} else {
console.error('Failed to recalculate device parameters.');
}
};
Dpdb.prototype.calcDeviceParams_ = function () {
var db = this.dpdb;
if (!db) {
console.error('DPDB not available.');
return null;
}
if (db.format != 1) {
console.error('DPDB has unexpected format version.');
return null;
}
if (!db.devices || !db.devices.length) {
console.error('DPDB does not have a devices section.');
return null;
}
var userAgent = navigator.userAgent || navigator.vendor || window.opera;
var width = getScreenWidth();
var height = getScreenHeight();
if (!db.devices) {
console.error('DPDB has no devices section.');
return null;
}
for (var i = 0; i < db.devices.length; i++) {
var device = db.devices[i];
if (!device.rules) {
console.warn('Device[' + i + '] has no rules section.');
continue;
}
if (device.type != 'ios' && device.type != 'android') {
console.warn('Device[' + i + '] has invalid type.');
continue;
}
if (isIOS() != (device.type == 'ios')) continue;
var matched = false;
for (var j = 0; j < device.rules.length; j++) {
var rule = device.rules[j];
if (this.ruleMatches_(rule, userAgent, width, height)) {
matched = true;
break;
}
}
if (!matched) continue;
var xdpi = device.dpi[0] || device.dpi;
var ydpi = device.dpi[1] || device.dpi;
return new DeviceParams({
xdpi: xdpi,
ydpi: ydpi,
bevelMm: device.bw
});
}
console.warn('No DPDB device match.');
return null;
};
Dpdb.prototype.ruleMatches_ = function (rule, ua, screenWidth, screenHeight) {
if (!rule.ua && !rule.res) return false;
if (rule.ua && rule.ua.substring(0, 2) === 'SM') rule.ua = rule.ua.substring(0, 7);
if (rule.ua && ua.indexOf(rule.ua) < 0) return false;
if (rule.res) {
if (!rule.res[0] || !rule.res[1]) return false;
var resX = rule.res[0];
var resY = rule.res[1];
if (Math.min(screenWidth, screenHeight) != Math.min(resX, resY) || Math.max(screenWidth, screenHeight) != Math.max(resX, resY)) {
return false;
}
}
return true;
};
function DeviceParams(params) {
this.xdpi = params.xdpi;
this.ydpi = params.ydpi;
this.bevelMm = params.bevelMm;
}
function SensorSample(sample, timestampS) {
this.set(sample, timestampS);
}
SensorSample.prototype.set = function (sample, timestampS) {
this.sample = sample;
this.timestampS = timestampS;
};
SensorSample.prototype.copy = function (sensorSample) {
this.set(sensorSample.sample, sensorSample.timestampS);
};
function ComplementaryFilter(kFilter, isDebug) {
this.kFilter = kFilter;
this.isDebug = isDebug;
this.currentAccelMeasurement = new SensorSample();
this.currentGyroMeasurement = new SensorSample();
this.previousGyroMeasurement = new SensorSample();
if (isIOS()) {
this.filterQ = new Quaternion(-1, 0, 0, 1);
} else {
this.filterQ = new Quaternion(1, 0, 0, 1);
}
this.previousFilterQ = new Quaternion();
this.previousFilterQ.copy(this.filterQ);
this.accelQ = new Quaternion();
this.isOrientationInitialized = false;
this.estimatedGravity = new Vector3();
this.measuredGravity = new Vector3();
this.gyroIntegralQ = new Quaternion();
}
ComplementaryFilter.prototype.addAccelMeasurement = function (vector, timestampS) {
this.currentAccelMeasurement.set(vector, timestampS);
};
ComplementaryFilter.prototype.addGyroMeasurement = function (vector, timestampS) {
this.currentGyroMeasurement.set(vector, timestampS);
var deltaT = timestampS - this.previousGyroMeasurement.timestampS;
if (isTimestampDeltaValid(deltaT)) {
this.run_();
}
this.previousGyroMeasurement.copy(this.currentGyroMeasurement);
};
ComplementaryFilter.prototype.run_ = function () {
if (!this.isOrientationInitialized) {
this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
this.previousFilterQ.copy(this.accelQ);
this.isOrientationInitialized = true;
return;
}
var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS;
var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
this.gyroIntegralQ.multiply(gyroDeltaQ);
this.filterQ.copy(this.previousFilterQ);
this.filterQ.multiply(gyroDeltaQ);
var invFilterQ = new Quaternion();
invFilterQ.copy(this.filterQ);
invFilterQ.inverse();
this.estimatedGravity.set(0, 0, -1);
this.estimatedGravity.applyQuaternion(invFilterQ);
this.estimatedGravity.normalize();
this.measuredGravity.copy(this.currentAccelMeasurement.sample);
this.measuredGravity.normalize();
var deltaQ = new Quaternion();
deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
deltaQ.inverse();
if (this.isDebug) {
console.log('Delta: %d deg, G_est: (%s, %s, %s), G_meas: (%s, %s, %s)', radToDeg * getQuaternionAngle(deltaQ), this.estimatedGravity.x.toFixed(1), this.estimatedGravity.y.toFixed(1), this.estimatedGravity.z.toFixed(1), this.measuredGravity.x.toFixed(1), this.measuredGravity.y.toFixed(1), this.measuredGravity.z.toFixed(1));
}
var targetQ = new Quaternion();
targetQ.copy(this.filterQ);
targetQ.multiply(deltaQ);
this.filterQ.slerp(targetQ, 1 - this.kFilter);
this.previousFilterQ.copy(this.filterQ);
};
ComplementaryFilter.prototype.getOrientation = function () {
return this.filterQ;
};
ComplementaryFilter.prototype.accelToQuaternion_ = function (accel) {
var normAccel = new Vector3();
normAccel.copy(accel);
normAccel.normalize();
var quat = new Quaternion();
quat.setFromUnitVectors(new Vector3(0, 0, -1), normAccel);
quat.inverse();
return quat;
};
ComplementaryFilter.prototype.gyroToQuaternionDelta_ = function (gyro, dt) {
var quat = new Quaternion();
var axis = new Vector3();
axis.copy(gyro);
axis.normalize();
quat.setFromAxisAngle(axis, gyro.length() * dt);
return quat;
};
function PosePredictor(predictionTimeS, isDebug) {
this.predictionTimeS = predictionTimeS;
this.isDebug = isDebug;
this.previousQ = new Quaternion();
this.previousTimestampS = null;
this.deltaQ = new Quaternion();
this.outQ = new Quaternion();
}
PosePredictor.prototype.getPrediction = function (currentQ, gyro, timestampS) {
if (!this.previousTimestampS) {
this.previousQ.copy(currentQ);
this.previousTimestampS = timestampS;
return currentQ;
}
var axis = new Vector3();
axis.copy(gyro);
axis.normalize();
var angularSpeed = gyro.length();
if (angularSpeed < degToRad * 20) {
if (this.isDebug) {
console.log('Moving slowly, at %s deg/s: no prediction', (radToDeg * angularSpeed).toFixed(1));
}
this.outQ.copy(currentQ);
this.previousQ.copy(currentQ);
return this.outQ;
}
var predictAngle = angularSpeed * this.predictionTimeS;
this.deltaQ.setFromAxisAngle(axis, predictAngle);
this.outQ.copy(this.previousQ);
this.outQ.multiply(this.deltaQ);
this.previousQ.copy(currentQ);
this.previousTimestampS = timestampS;
return this.outQ;
};
function FusionPoseSensor(kFilter, predictionTime, yawOnly, isDebug) {
this.yawOnly = yawOnly;
this.accelerometer = new Vector3();
this.gyroscope = new Vector3();
this.filter = new ComplementaryFilter(kFilter, isDebug);
this.posePredictor = new PosePredictor(predictionTime, isDebug);
this.isFirefoxAndroid = isFirefoxAndroid();
this.isIOS = isIOS();
var chromeVersion = getChromeVersion();
this.isDeviceMotionInRadians = !this.isIOS && chromeVersion && chromeVersion < 66;
this.isWithoutDeviceMotion = isChromeWithoutDeviceMotion() || isSafariWithoutDeviceMotion();
this.filterToWorldQ = new Quaternion();
if (isIOS()) {
this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);
} else {
this.filterToWorldQ.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
}
this.inverseWorldToScreenQ = new Quaternion();
this.worldToScreenQ = new Quaternion();
this.originalPoseAdjustQ = new Quaternion();
this.originalPoseAdjustQ.setFromAxisAngle(new Vector3(0, 0, 1), -window.orientation * Math.PI / 180);
this.setScreenTransform_();
if (isLandscapeMode()) {
this.filterToWorldQ.multiply(this.inverseWorldToScreenQ);
}
this.resetQ = new Quaternion();
this.orientationOut_ = new Float32Array(4);
this.start();
}
FusionPoseSensor.prototype.getPosition = function () {
return null;
};
FusionPoseSensor.prototype.getOrientation = function () {
var orientation = void 0;
if (this.isWithoutDeviceMotion && this._deviceOrientationQ) {
this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
var z = new Quaternion().setFromAxisAngle(new Vector3(0, 0, -1), 0);
var y = new Quaternion();
if (window.orientation === -90) {
y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / -2);
} else {
y.setFromAxisAngle(new Vector3(0, 1, 0), Math.PI / 2);
}
return z.multiply(y);
}();
this.deviceOrientationFilterToWorldQ = this.deviceOrientationFilterToWorldQ || function () {
var q = new Quaternion();
q.setFromAxisAngle(new Vector3(1, 0, 0), -Math.PI / 2);
return q;
}();
orientation = this._deviceOrientationQ;
var out = new Quaternion();
out.copy(orientation);
out.multiply(this.deviceOrientationFilterToWorldQ);
out.multiply(this.resetQ);
out.multiply(this.worldToScreenQ);
out.multiplyQuaternions(this.deviceOrientationFixQ, out);
if (this.yawOnly) {
out.x = 0;
out.z = 0;
out.normalize();
}
this.orientationOut_[0] = out.x;
this.orientationOut_[1] = out.y;
this.orientationOut_[2] = out.z;
this.orientationOut_[3] = out.w;
return this.orientationOut_;
} else {
var filterOrientation = this.filter.getOrientation();
orientation = this.posePredictor.getPrediction(filterOrientation, this.gyroscope, this.previousTimestampS);
}
var out = new Quaternion();
out.copy(this.filterToWorldQ);
out.multiply(this.resetQ);
out.multiply(orientation);
out.multiply(this.worldToScreenQ);
if (this.yawOnly) {
out.x = 0;
out.z = 0;
out.normalize();
}
this.orientationOut_[0] = out.x;
this.orientationOut_[1] = out.y;
this.orientationOut_[2] = out.z;
this.orientationOut_[3] = out.w;
return this.orientationOut_;
};
FusionPoseSensor.prototype.resetPose = function () {
this.resetQ.copy(this.filter.getOrientation());
this.resetQ.x = 0;
this.resetQ.y = 0;
this.resetQ.z *= -1;
this.resetQ.normalize();
if (isLandscapeMode()) {
this.resetQ.multiply(this.inverseWorldToScreenQ);
}
this.resetQ.multiply(this.originalPoseAdjustQ);
};
FusionPoseSensor.prototype.onDeviceOrientation_ = function (e) {
this._deviceOrientationQ = this._deviceOrientationQ || new Quaternion();
var alpha = e.alpha,
beta = e.beta,
gamma = e.gamma;
alpha = (alpha || 0) * Math.PI / 180;
beta = (beta || 0) * Math.PI / 180;
gamma = (gamma || 0) * Math.PI / 180;
this._deviceOrientationQ.setFromEulerYXZ(beta, alpha, -gamma);
};
FusionPoseSensor.prototype.onDeviceMotion_ = function (deviceMotion) {
this.updateDeviceMotion_(deviceMotion);
};
FusionPoseSensor.prototype.updateDeviceMotion_ = function (deviceMotion) {
var accGravity = deviceMotion.accelerationIncludingGravity;
var rotRate = deviceMotion.rotationRate;
var timestampS = deviceMotion.timeStamp / 1000;
var deltaS = timestampS - this.previousTimestampS;
if (deltaS < 0) {
warnOnce('fusion-pose-sensor:invalid:non-monotonic', 'Invalid timestamps detected: non-monotonic timestamp from devicemotion');
this.previousTimestampS = timestampS;
return;
} else if (deltaS <= MIN_TIMESTEP || deltaS > MAX_TIMESTEP) {
warnOnce('fusion-pose-sensor:invalid:outside-threshold', 'Invalid timestamps detected: Timestamp from devicemotion outside expected range.');
this.previousTimestampS = timestampS;
return;
}
this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
if (rotRate) {
if (isR7()) {
this.gyroscope.set(-rotRate.beta, rotRate.alpha, rotRate.gamma);
} else {
this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma);
}
if (!this.isDeviceMotionInRadians) {
this.gyroscope.multiplyScalar(Math.PI / 180);
}
this.filter.addGyroMeasurement(this.gyroscope, timestampS);
}
this.filter.addAccelMeasurement(this.accelerometer, timestampS);
this.previousTimestampS = timestampS;
};
FusionPoseSensor.prototype.onOrientationChange_ = function (screenOrientation) {
this.setScreenTransform_();
};
FusionPoseSensor.prototype.onMessage_ = function (event) {
var message = event.data;
if (!message || !message.type) {
return;
}
var type = message.type.toLowerCase();
if (type !== 'devicemotion') {
return;
}
this.updateDeviceMotion_(message.deviceMotionEvent);
};
FusionPoseSensor.prototype.setScreenTransform_ = function () {
this.worldToScreenQ.set(0, 0, 0, 1);
switch (window.orientation) {
case 0:
break;
case 90:
this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), -Math.PI / 2);
break;
case -90:
this.worldToScreenQ.setFromAxisAngle(new Vector3(0, 0, 1), Math.PI / 2);
break;
}
this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
this.inverseWorldToScreenQ.inverse();
};
FusionPoseSensor.prototype.start = function () {
this.onDeviceMotionCallback_ = this.onDeviceMotion_.bind(this);
this.onOrientationChangeCallback_ = this.onOrientationChange_.bind(this);
this.onMessageCallback_ = this.onMessage_.bind(this);
this.onDeviceOrientationCallback_ = this.onDeviceOrientation_.bind(this);
if (isIOS() && isInsideCrossOriginIFrame()) {
window.addEventListener('message', this.onMessageCallback_);
}
window.addEventListener('orientationchange', this.onOrientationChangeCallback_);
if (this.isWithoutDeviceMotion) {
window.addEventListener('deviceorientation', this.onDeviceOrientationCallback_);
} else {
window.addEventListener('devicemotion', this.onDeviceMotionCallback_);
}
};
FusionPoseSensor.prototype.stop = function () {
window.removeEventListener('devicemotion', this.onDeviceMotionCallback_);
window.removeEventListener('deviceorientation', this.onDeviceOrientationCallback_);
window.removeEventListener('orientationchange', this.onOrientationChangeCallback_);
window.removeEventListener('message', this.onMessageCallback_);
};
var SENSOR_FREQUENCY = 60;
var X_AXIS = new Vector3(1, 0, 0);
var Z_AXIS = new Vector3(0, 0, 1);
var SENSOR_TO_VR = new Quaternion();
SENSOR_TO_VR.setFromAxisAngle(X_AXIS, -Math.PI / 2);
SENSOR_TO_VR.multiply(new Quaternion().setFromAxisAngle(Z_AXIS, Math.PI / 2));
var PoseSensor = function () {
function PoseSensor(config) {
classCallCheck(this, PoseSensor);
this.config = config;
this.sensor = null;
this.fusionSensor = null;
this._out = new Float32Array(4);
this.api = null;
this.errors = [];
this._sensorQ = new Quaternion();
this._outQ = new Quaternion();
this._onSensorRead = this._onSensorRead.bind(this);
this._onSensorError = this._onSensorError.bind(this);
this.init();
}
createClass(PoseSensor, [{
key: 'init',
value: function init() {
var sensor = null;
try {
sensor = new RelativeOrientationSensor({
frequency: SENSOR_FREQUENCY,
referenceFrame: 'screen'
});
sensor.addEventListener('error', this._onSensorError);
} catch (error) {
this.errors.push(error);
if (error.name === 'SecurityError') {
console.error('Cannot construct sensors due to the Feature Policy');
console.warn('Attempting to fall back using "devicemotion"; however this will ' + 'fail in the future without correct permissions.');
this.useDeviceMotion();
} else if (error.name === 'ReferenceError') {
this.useDeviceMotion();
} else {
console.error(error);
}
}
if (sensor) {
this.api = 'sensor';
this.sensor = sensor;
this.sensor.addEventListener('reading', this._onSensorRead);
this.sensor.start();
}
}
}, {
key: 'useDeviceMotion',
value: function useDeviceMotion() {
this.api = 'devicemotion';
this.fusionSensor = new FusionPoseSensor(this.config.K_FILTER, this.config.PREDICTION_TIME_S, this.config.YAW_ONLY, this.config.DEBUG);
if (this.sensor) {
this.sensor.removeEventListener('reading', this._onSensorRead);
this.sensor.removeEventListener('error', this._onSensorError);
this.sensor = null;
}
}
}, {
key: 'getOrientation',
value: function getOrientation() {
if (this.fusionSensor) {
return this.fusionSensor.getOrientation();
}
if (!this.sensor || !this.sensor.quaternion) {
this._out[0] = this._out[1] = this._out[2] = 0;
this._out[3] = 1;
return this._out;
}
var q = this.sensor.quaternion;
this._sensorQ.set(q[0], q[1], q[2], q[3]);
var out = this._outQ;
out.copy(SENSOR_TO_VR);
out.multiply(this._sensorQ);
if (this.config.YAW_ONLY) {
out.x = out.z = 0;
out.normalize();
}
this._out[0] = out.x;
this._out[1] = out.y;
this._out[2] = out.z;
this._out[3] = out.w;
return this._out;
}
}, {
key: '_onSensorError',
value: function _onSensorError(event) {
this.errors.push(event.error);
if (event.error.name === 'NotAllowedError') {
console.error('Permission to access sensor was denied');
} else if (event.error.name === 'NotReadableError') {
console.error('Sensor could not be read');
} else {
console.error(event.error);
}
this.useDeviceMotion();
}
}, {
key: '_onSensorRead',
value: function _onSensorRead() {}
}]);
return PoseSensor;
}();
var rotateInstructionsAsset = "";
function RotateInstructions() {
this.loadIcon_();
var overlay = document.createElement('div');
var s = overlay.style;
s.position = 'fixed';
s.top = 0;
s.right = 0;
s.bottom = 0;
s.left = 0;
s.backgroundColor = 'gray';
s.fontFamily = 'sans-serif';
s.zIndex = 1000000;
var img = document.createElement('img');
img.src = this.icon;
var s = img.style;
s.marginLeft = '25%';
s.marginTop = '25%';
s.width = '50%';
overlay.appendChild(img);
var text = document.createElement('div');
var s = text.style;
s.textAlign = 'center';
s.fontSize = '16px';
s.lineHeight = '24px';
s.margin = '24px 25%';
s.width = '50%';
text.innerHTML = 'Place your phone into your Cardboard viewer.';
overlay.appendChild(text);
var snackbar = document.createElement('div');
var s = snackbar.style;
s.backgroundColor = '#CFD8DC';
s.position = 'fixed';
s.bottom = 0;
s.width = '100%';
s.height = '48px';
s.padding = '14px 24px';
s.boxSizing = 'border-box';
s.color = '#656A6B';
overlay.appendChild(snackbar);
var snackbarText = document.createElement('div');
snackbarText.style.float = 'left';
snackbarText.innerHTML = 'No Cardboard viewer?';
var snackbarButton = document.createElement('a');
snackbarButton.href = 'https://www.google.com/get/cardboard/get-cardboard/';
snackbarButton.innerHTML = 'get one';
snackbarButton.target = '_blank';
var s = snackbarButton.style;
s.float = 'right';
s.fontWeight = 600;
s.textTransform = 'uppercase';
s.borderLeft = '1px solid gray';
s.paddingLeft = '24px';
s.textDecoration = 'none';
s.color = '#656A6B';
snackbar.appendChild(snackbarText);
snackbar.appendChild(snackbarButton);
this.overlay = overlay;
this.text = text;
this.hide();
}
RotateInstructions.prototype.show = function (parent) {
if (!parent && !this.overlay.parentElement) {
document.body.appendChild(this.overlay);
} else if (parent) {
if (this.overlay.parentElement && this.overlay.parentElement != parent) this.overlay.parentElement.removeChild(this.overlay);
parent.appendChild(this.overlay);
}
this.overlay.style.display = 'block';
var img = this.overlay.querySelector('img');
var s = img.style;
if (isLandscapeMode()) {
s.width = '20%';
s.marginLeft = '40%';
s.marginTop = '3%';
} else {
s.width = '50%';
s.marginLeft = '25%';
s.marginTop = '25%';
}
};
RotateInstructions.prototype.hide = function () {
this.overlay.style.display = 'none';
};
RotateInstructions.prototype.showTemporarily = function (ms, parent) {
this.show(parent);
this.timer = setTimeout(this.hide.bind(this), ms);
};
RotateInstructions.prototype.disableShowTemporarily = function () {
clearTimeout(this.timer);
};
RotateInstructions.prototype.update = function () {
this.disableShowTemporarily();
if (!isLandscapeMode() && isMobile()) {
this.show();
} else {
this.hide();
}
};
RotateInstructions.prototype.loadIcon_ = function () {
this.icon = dataUri('image/svg+xml', rotateInstructionsAsset);
};
var DEFAULT_VIEWER = 'CardboardV1';
var VIEWER_KEY = 'WEBVR_CARDBOARD_VIEWER';
var CLASS_NAME = 'webvr-polyfill-viewer-selector';
function ViewerSelector(defaultViewer) {
try {
this.selectedKey = localStorage.getItem(VIEWER_KEY);
} catch (error) {
console.error('Failed to load viewer profile: %s', error);
}
if (!this.selectedKey) {
this.selectedKey = defaultViewer || DEFAULT_VIEWER;
}
this.dialog = this.createDialog_(DeviceInfo.Viewers);
this.root = null;
this.onChangeCallbacks_ = [];
}
ViewerSelector.prototype.show = function (root) {
this.root = root;
root.appendChild(this.dialog);
var selected = this.dialog.querySelector('#' + this.selectedKey);
selected.checked = true;
this.dialog.style.display = 'block';
};
ViewerSelector.prototype.hide = function () {
if (this.root && this.root.contains(this.dialog)) {
this.root.removeChild(this.dialog);
}
this.dialog.style.display = 'none';
};
ViewerSelector.prototype.getCurrentViewer = function () {
return DeviceInfo.Viewers[this.selectedKey];
};
ViewerSelector.prototype.getSelectedKey_ = function () {
var input = this.dialog.querySelector('input[name=field]:checked');
if (input) {
return input.id;
}
return null;
};
ViewerSelector.prototype.onChange = function (cb) {
this.onChangeCallbacks_.push(cb);
};
ViewerSelector.prototype.fireOnChange_ = function (viewer) {
for (var i = 0; i < this.onChangeCallbacks_.length; i++) {
this.onChangeCallbacks_[i](viewer);
}
};
ViewerSelector.prototype.onSave_ = function () {
this.selectedKey = this.getSelectedKey_();
if (!this.selectedKey || !DeviceInfo.Viewers[this.selectedKey]) {
console.error('ViewerSelector.onSave_: this should never happen!');
return;
}
this.fireOnChange_(DeviceInfo.Viewers[this.selectedKey]);
try {
localStorage.setItem(VIEWER_KEY, this.selectedKey);
} catch (error) {
console.error('Failed to save viewer profile: %s', error);
}
this.hide();
};
ViewerSelector.prototype.createDialog_ = function (options) {
var container = document.createElement('div');
container.classList.add(CLASS_NAME);
container.style.display = 'none';
var overlay = document.createElement('div');
var s = overlay.style;
s.position = 'fixed';
s.left = 0;
s.top = 0;
s.width = '100%';
s.height = '100%';
s.background = 'rgba(0, 0, 0, 0.3)';
overlay.addEventListener('click', this.hide.bind(this));
var width = 280;
var dialog = document.createElement('div');
var s = dialog.style;
s.boxSizing = 'border-box';
s.position = 'fixed';
s.top = '24px';
s.left = '50%';
s.marginLeft = -width / 2 + 'px';
s.width = width + 'px';
s.padding = '24px';
s.overflow = 'hidden';
s.background = '#fafafa';
s.fontFamily = "'Roboto', sans-serif";
s.boxShadow = '0px 5px 20px #666';
dialog.appendChild(this.createH1_('Select your viewer'));
for (var id in options) {
dialog.appendChild(this.createChoice_(id, options[id].label));
}
dialog.appendChild(this.createButton_('Save', this.onSave_.bind(this)));
container.appendChild(overlay);
container.appendChild(dialog);
return container;
};
ViewerSelector.prototype.createH1_ = function (name) {
var h1 = document.createElement('h1');
var s = h1.style;
s.color = 'black';
s.fontSize = '20px';
s.fontWeight = 'bold';
s.marginTop = 0;
s.marginBottom = '24px';
h1.innerHTML = name;
return h1;
};
ViewerSelector.prototype.createChoice_ = function (id, name) {
var div = document.createElement('div');
div.style.marginTop = '8px';
div.style.color = 'black';
var input = document.createElement('input');
input.style.fontSize = '30px';
input.setAttribute('id', id);
input.setAttribute('type', 'radio');
input.setAttribute('value', id);
input.setAttribute('name', 'field');
var label = document.createElement('label');
label.style.marginLeft = '4px';
label.setAttribute('for', id);
label.innerHTML = name;
div.appendChild(input);
div.appendChild(label);
return div;
};
ViewerSelector.prototype.createButton_ = function (label, onclick) {
var button = document.createElement('button');
button.innerHTML = label;
var s = button.style;
s.float = 'right';
s.textTransform = 'uppercase';
s.color = '#1094f7';
s.fontSize = '14px';
s.letterSpacing = 0;
s.border = 0;
s.background = 'none';
s.marginTop = '16px';
button.addEventListener('click', onclick);
return button;
};
var commonjsGlobal$1 = typeof window !== 'undefined' ? window : typeof commonjsGlobal !== 'undefined' ? commonjsGlobal : typeof self !== 'undefined' ? self : {};
function unwrapExports(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
function createCommonjsModule(fn, module) {
return module = {
exports: {}
}, fn(module, module.exports), module.exports;
}
var NoSleep = createCommonjsModule(function (module, exports) {
(function webpackUniversalModuleDefinition(root, factory) {
module.exports = factory();
})(commonjsGlobal$1, function () {
return function (modules) {
var installedModules = {};
function __webpack_require__(moduleId) {
if (installedModules[moduleId]) {
return installedModules[moduleId].exports;
}
var module = installedModules[moduleId] = {
i: moduleId,
l: false,
exports: {}
};
modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
module.l = true;
return module.exports;
}
__webpack_require__.m = modules;
__webpack_require__.c = installedModules;
__webpack_require__.d = function (exports, name, getter) {
if (!__webpack_require__.o(exports, name)) {
Object.defineProperty(exports, name, {
configurable: false,
enumerable: true,
get: getter
});
}
};
__webpack_require__.n = function (module) {
var getter = module && module.__esModule ? function getDefault() {
return module['default'];
} : function getModuleExports() {
return module;
};
__webpack_require__.d(getter, 'a', getter);
return getter;
};
__webpack_require__.o = function (object, property) {
return Object.prototype.hasOwnProperty.call(object, property);
};
__webpack_require__.p = "";
return __webpack_require__(__webpack_require__.s = 0);
}([function (module, exports, __webpack_require__) {
var _createClass = function () {
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
var descriptor = props[i];
descriptor.enumerable = descriptor.enumerable || false;
descriptor.configurable = true;
if ("value" in descriptor) descriptor.writable = true;
Object.defineProperty(target, descriptor.key, descriptor);
}
}
return function (Constructor, protoProps, staticProps) {
if (protoProps) defineProperties(Constructor.prototype, protoProps);
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError("Cannot call a class as a function");
}
}
var mediaFile = __webpack_require__(1);
var oldIOS = typeof navigator !== 'undefined' && parseFloat(('' + (/CPU.*OS ([0-9_]{3,4})[0-9_]{0,1}|(CPU like).*AppleWebKit.*Mobile/i.exec(navigator.userAgent) || [0, ''])[1]).replace('undefined', '3_2').replace('_', '.').replace('_', '')) < 10 && !window.MSStream;
var NoSleep = function () {
function NoSleep() {
_classCallCheck(this, NoSleep);
if (oldIOS) {
this.noSleepTimer = null;
} else {
this.noSleepVideo = document.createElement('video');
this.noSleepVideo.setAttribute('playsinline', '');
this.noSleepVideo.setAttribute('src', mediaFile);
this.noSleepVideo.addEventListener('timeupdate', function (e) {
if (this.noSleepVideo.currentTime > 0.5) {
this.noSleepVideo.currentTime = Math.random();
}
}.bind(this));
}
}
_createClass(NoSleep, [{
key: 'enable',
value: function enable() {
if (oldIOS) {
this.disable();
this.noSleepTimer = window.setInterval(function () {
window.location.href = '/';
window.setTimeout(window.stop, 0);
}, 15000);
} else {
this.noSleepVideo.play();
}
}
}, {
key: 'disable',
value: function disable() {
if (oldIOS) {
if (this.noSleepTimer) {
window.clearInterval(this.noSleepTimer);
this.noSleepTimer = null;
}
} else {
this.noSleepVideo.pause();
}
}
}]);
return NoSleep;
}();
module.exports = NoSleep;
}, function (module, exports, __webpack_require__) {
module.exports = 'data:video/mp4;base64,AAAAIGZ0eXBtcDQyAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAACKBtZGF0AAAC8wYF///v3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0MiByMjQ3OSBkZDc5YTYxIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNCAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTEgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MToweDExMSBtZT1oZXggc3VibWU9MiBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0wIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MCA4eDhkY3Q9MCBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0wIHRocmVhZHM9NiBsb29rYWhlYWRfdGhyZWFkcz0xIHNsaWNlZF90aHJlYWRzPTAgbnI9MCBkZWNpbWF0ZT0xIGludGVybGFjZWQ9MCBibHVyYXlfY29tcGF0PTAgY29uc3RyYWluZWRfaW50cmE9MCBiZnJhbWVzPTMgYl9weXJhbWlkPTIgYl9hZGFwdD0xIGJfYmlhcz0wIGRpcmVjdD0xIHdlaWdodGI9MSBvcGVuX2dvcD0wIHdlaWdodHA9MSBrZXlpbnQ9MzAwIGtleWludF9taW49MzAgc2NlbmVjdXQ9NDAgaW50cmFfcmVmcmVzaD0wIHJjX2xvb2thaGVhZD0xMCByYz1jcmYgbWJ0cmVlPTEgY3JmPTIwLjAgcWNvbXA9MC42MCBxcG1pbj0wIHFwbWF4PTY5IHFwc3RlcD00IHZidl9tYXhyYXRlPTIwMDAwIHZidl9idWZzaXplPTI1MDAwIGNyZl9tYXg9MC4wIG5hbF9ocmQ9bm9uZSBmaWxsZXI9MCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAOWWIhAA3//p+C7v8tDDSTjf97w55i3SbRPO4ZY+hkjD5hbkAkL3zpJ6h/LR1CAABzgB1kqqzUorlhQAAAAxBmiQYhn/+qZYADLgAAAAJQZ5CQhX/AAj5IQADQGgcIQADQGgcAAAACQGeYUQn/wALKCEAA0BoHAAAAAkBnmNEJ/8ACykhAANAaBwhAANAaBwAAAANQZpoNExDP/6plgAMuSEAA0BoHAAAAAtBnoZFESwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBnqVEJ/8ACykhAANAaBwAAAAJAZ6nRCf/AAsoIQADQGgcIQADQGgcAAAADUGarDRMQz/+qZYADLghAANAaBwAAAALQZ7KRRUsK/8ACPkhAANAaBwAAAAJAZ7pRCf/AAsoIQADQGgcIQADQGgcAAAACQGe60Qn/wALKCEAA0BoHAAAAA1BmvA0TEM//qmWAAy5IQADQGgcIQADQGgcAAAAC0GfDkUVLCv/AAj5IQADQGgcAAAACQGfLUQn/wALKSEAA0BoHCEAA0BoHAAAAAkBny9EJ/8ACyghAANAaBwAAAANQZs0NExDP/6plgAMuCEAA0BoHAAAAAtBn1JFFSwr/wAI+SEAA0BoHCEAA0BoHAAAAAkBn3FEJ/8ACyghAANAaBwAAAAJAZ9zRCf/AAsoIQADQGgcIQADQGgcAAAADUGbeDRMQz/+qZYADLkhAANAaBwAAAALQZ+WRRUsK/8ACPghAANAaBwhAANAaBwAAAAJAZ+1RCf/AAspIQADQGgcAAAACQGft0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bm7w0TEM//qmWAAy4IQADQGgcAAAAC0Gf2kUVLCv/AAj5IQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHAAAAAkBn/tEJ/8ACykhAANAaBwAAAANQZvgNExDP/6plgAMuSEAA0BoHCEAA0BoHAAAAAtBnh5FFSwr/wAI+CEAA0BoHAAAAAkBnj1EJ/8ACyghAANAaBwhAANAaBwAAAAJAZ4/RCf/AAspIQADQGgcAAAADUGaJDRMQz/+qZYADLghAANAaBwAAAALQZ5CRRUsK/8ACPkhAANAaBwhAANAaBwAAAAJAZ5hRCf/AAsoIQADQGgcAAAACQGeY0Qn/wALKSEAA0BoHCEAA0BoHAAAAA1Bmmg0TEM//qmWAAy5IQADQGgcAAAAC0GehkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGepUQn/wALKSEAA0BoHAAAAAkBnqdEJ/8ACyghAANAaBwAAAANQZqsNExDP/6plgAMuCEAA0BoHCEAA0BoHAAAAAtBnspFFSwr/wAI+SEAA0BoHAAAAAkBnulEJ/8ACyghAANAaBwhAANAaBwAAAAJAZ7rRCf/AAsoIQADQGgcAAAADUGa8DRMQz/+qZYADLkhAANAaBwhAANAaBwAAAALQZ8ORRUsK/8ACPkhAANAaBwAAAAJAZ8tRCf/AAspIQADQGgcIQADQGgcAAAACQGfL0Qn/wALKCEAA0BoHAAAAA1BmzQ0TEM//qmWAAy4IQADQGgcAAAAC0GfUkUVLCv/AAj5IQADQGgcIQADQGgcAAAACQGfcUQn/wALKCEAA0BoHAAAAAkBn3NEJ/8ACyghAANAaBwhAANAaBwAAAANQZt4NExC//6plgAMuSEAA0BoHAAAAAtBn5ZFFSwr/wAI+CEAA0BoHCEAA0BoHAAAAAkBn7VEJ/8ACykhAANAaBwAAAAJAZ+3RCf/AAspIQADQGgcAAAADUGbuzRMQn/+nhAAYsAhAANAaBwhAANAaBwAAAAJQZ/aQhP/AAspIQADQGgcAAAACQGf+UQn/wALKCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHCEAA0BoHAAACiFtb292AAAAbG12aGQAAAAA1YCCX9WAgl8AAAPoAAAH/AABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAAAAGGlvZHMAAAAAEICAgAcAT////v7/AAAF+XRyYWsAAABcdGtoZAAAAAPVgIJf1YCCXwAAAAEAAAAAAAAH0AAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAygAAAMoAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAB9AAABdwAAEAAAAABXFtZGlhAAAAIG1kaGQAAAAA1YCCX9WAgl8AAV+QAAK/IFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAUcbWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAE3HN0YmwAAACYc3RzZAAAAAAAAAABAAAAiGF2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAygDKAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAyYXZjQwFNQCj/4QAbZ01AKOyho3ySTUBAQFAAAAMAEAAr8gDxgxlgAQAEaO+G8gAAABhzdHRzAAAAAAAAAAEAAAA8AAALuAAAABRzdHNzAAAAAAAAAAEAAAABAAAB8GN0dHMAAAAAAAAAPAAAAAEAABdwAAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAADqYAAAAAQAAF3AAAAABAAAAAAAAAAEAAAu4AAAAAQAAOpgAAAABAAAXcAAAAAEAAAAAAAAAAQAAC7gAAAABAAA6mAAAAAEAABdwAAAAAQAAAAAAAAABAAALuAAAAAEAAC7gAAAAAQAAF3AAAAABAAAAAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAEEc3RzegAAAAAAAAAAAAAAPAAAAzQAAAAQAAAADQAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAAPAAAADQAAAA0AAAARAAAADwAAAA0AAAANAAAAEQAAAA8AAAANAAAADQAAABEAAAANAAAADQAAAQBzdGNvAAAAAAAAADwAAAAwAAADZAAAA3QAAAONAAADoAAAA7kAAAPQAAAD6wAAA/4AAAQXAAAELgAABEMAAARcAAAEbwAABIwAAAShAAAEugAABM0AAATkAAAE/wAABRIAAAUrAAAFQgAABV0AAAVwAAAFiQAABaAAAAW1AAAFzgAABeEAAAX+AAAGEwAABiwAAAY/AAAGVgAABnEAAAaEAAAGnQAABrQAAAbPAAAG4gAABvUAAAcSAAAHJwAAB0AAAAdTAAAHcAAAB4UAAAeeAAAHsQAAB8gAAAfjAAAH9gAACA8AAAgmAAAIQQAACFQAAAhnAAAIhAAACJcAAAMsdHJhawAAAFx0a2hkAAAAA9WAgl/VgIJfAAAAAgAAAAAAAAf8AAAAAAAAAAAAAAABAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAACsm1kaWEAAAAgbWRoZAAAAADVgIJf1YCCXwAArEQAAWAAVcQAAAAAACdoZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU3RlcmVvAAAAAmNtaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAidzdGJsAAAAZ3N0c2QAAAAAAAAAAQAAAFdtcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAADNlc2RzAAAAAAOAgIAiAAIABICAgBRAFQAAAAADDUAAAAAABYCAgAISEAaAgIABAgAAABhzdHRzAAAAAAAAAAEAAABYAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAGAAAAWAAAAXBzdGNvAAAAAAAAAFgAAAOBAAADhwAAA5oAAAOtAAADswAAA8oAAAPfAAAD5QAAA/gAAAQLAAAEEQAABCgAAAQ9AAAEUAAABFYAAARpAAAEgAAABIYAAASbAAAErgAABLQAAATHAAAE3gAABPMAAAT5AAAFDAAABR8AAAUlAAAFPAAABVEAAAVXAAAFagAABX0AAAWDAAAFmgAABa8AAAXCAAAFyAAABdsAAAXyAAAF+AAABg0AAAYgAAAGJgAABjkAAAZQAAAGZQAABmsAAAZ+AAAGkQAABpcAAAauAAAGwwAABskAAAbcAAAG7wAABwYAAAcMAAAHIQAABzQAAAc6AAAHTQAAB2QAAAdqAAAHfwAAB5IAAAeYAAAHqwAAB8IAAAfXAAAH3QAAB/AAAAgDAAAICQAACCAAAAg1AAAIOwAACE4AAAhhAAAIeAAACH4AAAiRAAAIpAAACKoAAAiwAAAItgAACLwAAAjCAAAAFnVkdGEAAAAObmFtZVN0ZXJlbwAAAHB1ZHRhAAAAaG1ldGEAAAAAAAAAIWhkbHIAAAAAAAAAAG1kaXJhcHBsAAAAAAAAAAAAAAAAO2lsc3QAAAAzqXRvbwAAACtkYXRhAAAAAQAAAABIYW5kQnJha2UgMC4xMC4yIDIwMTUwNjExMDA=';
}]);
});
});
var NoSleep$1 = unwrapExports(NoSleep);
var nextDisplayId = 1000;
var defaultLeftBounds = [0, 0, 0.5, 1];
var defaultRightBounds = [0.5, 0, 0.5, 1];
var raf = window.requestAnimationFrame;
var caf = window.cancelAnimationFrame;
function VRFrameData() {
this.leftProjectionMatrix = new Float32Array(16);
this.leftViewMatrix = new Float32Array(16);
this.rightProjectionMatrix = new Float32Array(16);
this.rightViewMatrix = new Float32Array(16);
this.pose = null;
}
function VRDisplayCapabilities(config) {
Object.defineProperties(this, {
hasPosition: {
writable: false,
enumerable: true,
value: config.hasPosition
},
hasExternalDisplay: {
writable: false,
enumerable: true,
value: config.hasExternalDisplay
},
canPresent: {
writable: false,
enumerable: true,
value: config.canPresent
},
maxLayers: {
writable: false,
enumerable: true,
value: config.maxLayers
},
hasOrientation: {
enumerable: true,
get: function get() {
deprecateWarning('VRDisplayCapabilities.prototype.hasOrientation', 'VRDisplay.prototype.getFrameData');
return config.hasOrientation;
}
}
});
}
function VRDisplay(config) {
config = config || {};
var USE_WAKELOCK = 'wakelock' in config ? config.wakelock : true;
this.isPolyfilled = true;
this.displayId = nextDisplayId++;
this.displayName = '';
this.depthNear = 0.01;
this.depthFar = 10000.0;
this.isPresenting = false;
Object.defineProperty(this, 'isConnected', {
get: function get() {
deprecateWarning('VRDisplay.prototype.isConnected', 'VRDisplayCapabilities.prototype.hasExternalDisplay');
return false;
}
});
this.capabilities = new VRDisplayCapabilities({
hasPosition: false,
hasOrientation: false,
hasExternalDisplay: false,
canPresent: false,
maxLayers: 1
});
this.stageParameters = null;
this.waitingForPresent_ = false;
this.layer_ = null;
this.originalParent_ = null;
this.fullscreenElement_ = null;
this.fullscreenWrapper_ = null;
this.fullscreenElementCachedStyle_ = null;
this.fullscreenEventTarget_ = null;
this.fullscreenChangeHandler_ = null;
this.fullscreenErrorHandler_ = null;
if (USE_WAKELOCK && isMobile()) {
this.wakelock_ = new NoSleep$1();
}
}
VRDisplay.prototype.getFrameData = function (frameData) {
return frameDataFromPose(frameData, this._getPose(), this);
};
VRDisplay.prototype.getPose = function () {
deprecateWarning('VRDisplay.prototype.getPose', 'VRDisplay.prototype.getFrameData');
return this._getPose();
};
VRDisplay.prototype.resetPose = function () {
deprecateWarning('VRDisplay.prototype.resetPose');
return this._resetPose();
};
VRDisplay.prototype.getImmediatePose = function () {
deprecateWarning('VRDisplay.prototype.getImmediatePose', 'VRDisplay.prototype.getFrameData');
return this._getPose();
};
VRDisplay.prototype.requestAnimationFrame = function (callback) {
return raf(callback);
};
VRDisplay.prototype.cancelAnimationFrame = function (id) {
return caf(id);
};
VRDisplay.prototype.wrapForFullscreen = function (element) {
if (isIOS()) {
return element;
}
if (!this.fullscreenWrapper_) {
this.fullscreenWrapper_ = document.createElement('div');
var cssProperties = ['height: ' + Math.min(screen.height, screen.width) + 'px !important', 'top: 0 !important', 'left: 0 !important', 'right: 0 !important', 'border: 0', 'margin: 0', 'padding: 0', 'z-index: 999999 !important', 'position: fixed'];
this.fullscreenWrapper_.setAttribute('style', cssProperties.join('; ') + ';');
this.fullscreenWrapper_.classList.add('webvr-polyfill-fullscreen-wrapper');
}
if (this.fullscreenElement_ == element) {
return this.fullscreenWrapper_;
}
if (this.fullscreenElement_) {
if (this.originalParent_) {
this.originalParent_.appendChild(this.fullscreenElement_);
} else {
this.fullscreenElement_.parentElement.removeChild(this.fullscreenElement_);
}
}
this.fullscreenElement_ = element;
this.originalParent_ = element.parentElement;
if (!this.originalParent_) {
document.body.appendChild(element);
}
if (!this.fullscreenWrapper_.parentElement) {
var parent = this.fullscreenElement_.parentElement;
parent.insertBefore(this.fullscreenWrapper_, this.fullscreenElement_);
parent.removeChild(this.fullscreenElement_);
}
this.fullscreenWrapper_.insertBefore(this.fullscreenElement_, this.fullscreenWrapper_.firstChild);
this.fullscreenElementCachedStyle_ = this.fullscreenElement_.getAttribute('style');
var self = this;
function applyFullscreenElementStyle() {
if (!self.fullscreenElement_) {
return;
}
var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: ' + Math.max(screen.width, screen.height) + 'px', 'height: ' + Math.min(screen.height, screen.width) + 'px', 'border: 0', 'margin: 0', 'padding: 0'];
self.fullscreenElement_.setAttribute('style', cssProperties.join('; ') + ';');
}
applyFullscreenElementStyle();
return this.fullscreenWrapper_;
};
VRDisplay.prototype.removeFullscreenWrapper = function () {
if (!this.fullscreenElement_) {
return;
}
var element = this.fullscreenElement_;
if (this.fullscreenElementCachedStyle_) {
element.setAttribute('style', this.fullscreenElementCachedStyle_);
} else {
element.removeAttribute('style');
}
this.fullscreenElement_ = null;
this.fullscreenElementCachedStyle_ = null;
var parent = this.fullscreenWrapper_.parentElement;
this.fullscreenWrapper_.removeChild(element);
if (this.originalParent_ === parent) {
parent.insertBefore(element, this.fullscreenWrapper_);
} else if (this.originalParent_) {
this.originalParent_.appendChild(element);
}
parent.removeChild(this.fullscreenWrapper_);
return element;
};
VRDisplay.prototype.requestPresent = function (layers) {
var wasPresenting = this.isPresenting;
var self = this;
if (!(layers instanceof Array)) {
deprecateWarning('VRDisplay.prototype.requestPresent with non-array argument', 'an array of VRLayers as the first argument');
layers = [layers];
}
return new Promise(function (resolve, reject) {
if (!self.capabilities.canPresent) {
reject(new Error('VRDisplay is not capable of presenting.'));
return;
}
if (layers.length == 0 || layers.length > self.capabilities.maxLayers) {
reject(new Error('Invalid number of layers.'));
return;
}
var incomingLayer = layers[0];
if (!incomingLayer.source) {
resolve();
return;
}
var leftBounds = incomingLayer.leftBounds || defaultLeftBounds;
var rightBounds = incomingLayer.rightBounds || defaultRightBounds;
if (wasPresenting) {
var layer = self.layer_;
if (layer.source !== incomingLayer.source) {
layer.source = incomingLayer.source;
}
for (var i = 0; i < 4; i++) {
layer.leftBounds[i] = leftBounds[i];
layer.rightBounds[i] = rightBounds[i];
}
self.wrapForFullscreen(self.layer_.source);
self.updatePresent_();
resolve();
return;
}
self.layer_ = {
predistorted: incomingLayer.predistorted,
source: incomingLayer.source,
leftBounds: leftBounds.slice(0),
rightBounds: rightBounds.slice(0)
};
self.waitingForPresent_ = false;
if (self.layer_ && self.layer_.source) {
var fullscreenElement = self.wrapForFullscreen(self.layer_.source);
var onFullscreenChange = function onFullscreenChange() {
var actualFullscreenElement = getFullscreenElement();
self.isPresenting = fullscreenElement === actualFullscreenElement;
if (self.isPresenting) {
if (screen.orientation && screen.orientation.lock) {
screen.orientation.lock('landscape-primary').catch(function (error) {
console.error('screen.orientation.lock() failed due to', error.message);
});
}
self.waitingForPresent_ = false;
self.beginPresent_();
resolve();
} else {
if (screen.orientation && screen.orientation.unlock) {
screen.orientation.unlock();
}
self.removeFullscreenWrapper();
self.disableWakeLock();
self.endPresent_();
self.removeFullscreenListeners_();
}
self.fireVRDisplayPresentChange_();
};
var onFullscreenError = function onFullscreenError() {
if (!self.waitingForPresent_) {
return;
}
self.removeFullscreenWrapper();
self.removeFullscreenListeners_();
self.disableWakeLock();
self.waitingForPresent_ = false;
self.isPresenting = false;
reject(new Error('Unable to present.'));
};
self.addFullscreenListeners_(fullscreenElement, onFullscreenChange, onFullscreenError);
if (requestFullscreen(fullscreenElement)) {
self.enableWakeLock();
self.waitingForPresent_ = true;
} else if (isIOS() || isWebViewAndroid()) {
self.enableWakeLock();
self.isPresenting = true;
self.beginPresent_();
self.fireVRDisplayPresentChange_();
resolve();
}
}
if (!self.waitingForPresent_ && !isIOS()) {
exitFullscreen();
reject(new Error('Unable to present.'));
}
});
};
VRDisplay.prototype.exitPresent = function () {
var wasPresenting = this.isPresenting;
var self = this;
this.isPresenting = false;
this.layer_ = null;
this.disableWakeLock();
return new Promise(function (resolve, reject) {
if (wasPresenting) {
if (!exitFullscreen() && isIOS()) {
self.endPresent_();
self.fireVRDisplayPresentChange_();
}
if (isWebViewAndroid()) {
self.removeFullscreenWrapper();
self.removeFullscreenListeners_();
self.endPresent_();
self.fireVRDisplayPresentChange_();
}
resolve();
} else {
reject(new Error('Was not presenting to VRDisplay.'));
}
});
};
VRDisplay.prototype.getLayers = function () {
if (this.layer_) {
return [this.layer_];
}
return [];
};
VRDisplay.prototype.fireVRDisplayPresentChange_ = function () {
var event = new CustomEvent('vrdisplaypresentchange', {
detail: {
display: this
}
});
window.dispatchEvent(event);
};
VRDisplay.prototype.fireVRDisplayConnect_ = function () {
var event = new CustomEvent('vrdisplayconnect', {
detail: {
display: this
}
});
window.dispatchEvent(event);
};
VRDisplay.prototype.addFullscreenListeners_ = function (element, changeHandler, errorHandler) {
this.removeFullscreenListeners_();
this.fullscreenEventTarget_ = element;
this.fullscreenChangeHandler_ = changeHandler;
this.fullscreenErrorHandler_ = errorHandler;
if (changeHandler) {
if (document.fullscreenEnabled) {
element.addEventListener('fullscreenchange', changeHandler, false);
} else if (document.webkitFullscreenEnabled) {
element.addEventListener('webkitfullscreenchange', changeHandler, false);
} else if (document.mozFullScreenEnabled) {
document.addEventListener('mozfullscreenchange', changeHandler, false);
} else if (document.msFullscreenEnabled) {
element.addEventListener('msfullscreenchange', changeHandler, false);
}
}
if (errorHandler) {
if (document.fullscreenEnabled) {
element.addEventListener('fullscreenerror', errorHandler, false);
} else if (document.webkitFullscreenEnabled) {
element.addEventListener('webkitfullscreenerror', errorHandler, false);
} else if (document.mozFullScreenEnabled) {
document.addEventListener('mozfullscreenerror', errorHandler, false);
} else if (document.msFullscreenEnabled) {
element.addEventListener('msfullscreenerror', errorHandler, false);
}
}
};
VRDisplay.prototype.removeFullscreenListeners_ = function () {
if (!this.fullscreenEventTarget_) return;
var element = this.fullscreenEventTarget_;
if (this.fullscreenChangeHandler_) {
var changeHandler = this.fullscreenChangeHandler_;
element.removeEventListener('fullscreenchange', changeHandler, false);
element.removeEventListener('webkitfullscreenchange', changeHandler, false);
document.removeEventListener('mozfullscreenchange', changeHandler, false);
element.removeEventListener('msfullscreenchange', changeHandler, false);
}
if (this.fullscreenErrorHandler_) {
var errorHandler = this.fullscreenErrorHandler_;
element.removeEventListener('fullscreenerror', errorHandler, false);
element.removeEventListener('webkitfullscreenerror', errorHandler, false);
document.removeEventListener('mozfullscreenerror', errorHandler, false);
element.removeEventListener('msfullscreenerror', errorHandler, false);
}
this.fullscreenEventTarget_ = null;
this.fullscreenChangeHandler_ = null;
this.fullscreenErrorHandler_ = null;
};
VRDisplay.prototype.enableWakeLock = function () {
if (this.wakelock_) {
this.wakelock_.enable();
}
};
VRDisplay.prototype.disableWakeLock = function () {
if (this.wakelock_) {
this.wakelock_.disable();
}
};
VRDisplay.prototype.beginPresent_ = function () {};
VRDisplay.prototype.endPresent_ = function () {};
VRDisplay.prototype.submitFrame = function (pose) {};
VRDisplay.prototype.getEyeParameters = function (whichEye) {
return null;
};
var config = {
ADDITIONAL_VIEWERS: [],
DEFAULT_VIEWER: '',
MOBILE_WAKE_LOCK: true,
DEBUG: false,
DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
K_FILTER: 0.98,
PREDICTION_TIME_S: 0.040,
CARDBOARD_UI_DISABLED: false,
ROTATE_INSTRUCTIONS_DISABLED: false,
YAW_ONLY: false,
BUFFER_SCALE: 0.5,
DIRTY_SUBMIT_FRAME_BINDINGS: false
};
var Eye = {
LEFT: 'left',
RIGHT: 'right'
};
function CardboardVRDisplay(config$$1) {
var defaults = extend({}, config);
config$$1 = extend(defaults, config$$1 || {});
VRDisplay.call(this, {
wakelock: config$$1.MOBILE_WAKE_LOCK
});
this.config = config$$1;
this.displayName = 'Cardboard VRDisplay';
this.capabilities = new VRDisplayCapabilities({
hasPosition: false,
hasOrientation: true,
hasExternalDisplay: false,
canPresent: true,
maxLayers: 1
});
this.stageParameters = null;
this.bufferScale_ = this.config.BUFFER_SCALE;
this.poseSensor_ = new PoseSensor(this.config);
this.distorter_ = null;
this.cardboardUI_ = null;
this.dpdb_ = new Dpdb(this.config.DPDB_URL, this.onDeviceParamsUpdated_.bind(this));
this.deviceInfo_ = new DeviceInfo(this.dpdb_.getDeviceParams(), config$$1.ADDITIONAL_VIEWERS);
this.viewerSelector_ = new ViewerSelector(config$$1.DEFAULT_VIEWER);
this.viewerSelector_.onChange(this.onViewerChanged_.bind(this));
this.deviceInfo_.setViewer(this.viewerSelector_.getCurrentViewer());
if (!this.config.ROTATE_INSTRUCTIONS_DISABLED) {
this.rotateInstructions_ = new RotateInstructions();
}
if (isIOS()) {
window.addEventListener('resize', this.onResize_.bind(this));
}
}
CardboardVRDisplay.prototype = Object.create(VRDisplay.prototype);
CardboardVRDisplay.prototype._getPose = function () {
return {
position: null,
orientation: this.poseSensor_.getOrientation(),
linearVelocity: null,
linearAcceleration: null,
angularVelocity: null,
angularAcceleration: null
};
};
CardboardVRDisplay.prototype._resetPose = function () {
if (this.poseSensor_.resetPose) {
this.poseSensor_.resetPose();
}
};
CardboardVRDisplay.prototype._getFieldOfView = function (whichEye) {
var fieldOfView;
if (whichEye == Eye.LEFT) {
fieldOfView = this.deviceInfo_.getFieldOfViewLeftEye();
} else if (whichEye == Eye.RIGHT) {
fieldOfView = this.deviceInfo_.getFieldOfViewRightEye();
} else {
console.error('Invalid eye provided: %s', whichEye);
return null;
}
return fieldOfView;
};
CardboardVRDisplay.prototype._getEyeOffset = function (whichEye) {
var offset;
if (whichEye == Eye.LEFT) {
offset = [-this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
} else if (whichEye == Eye.RIGHT) {
offset = [this.deviceInfo_.viewer.interLensDistance * 0.5, 0.0, 0.0];
} else {
console.error('Invalid eye provided: %s', whichEye);
return null;
}
return offset;
};
CardboardVRDisplay.prototype.getEyeParameters = function (whichEye) {
var offset = this._getEyeOffset(whichEye);
var fieldOfView = this._getFieldOfView(whichEye);
var eyeParams = {
offset: offset,
renderWidth: this.deviceInfo_.device.width * 0.5 * this.bufferScale_,
renderHeight: this.deviceInfo_.device.height * this.bufferScale_
};
Object.defineProperty(eyeParams, 'fieldOfView', {
enumerable: true,
get: function get() {
deprecateWarning('VRFieldOfView', 'VRFrameData\'s projection matrices');
return fieldOfView;
}
});
return eyeParams;
};
CardboardVRDisplay.prototype.onDeviceParamsUpdated_ = function (newParams) {
if (this.config.DEBUG) {
console.log('DPDB reported that device params were updated.');
}
this.deviceInfo_.updateDeviceParams(newParams);
if (this.distorter_) {
this.distorter_.updateDeviceInfo(this.deviceInfo_);
}
};
CardboardVRDisplay.prototype.updateBounds_ = function () {
if (this.layer_ && this.distorter_ && (this.layer_.leftBounds || this.layer_.rightBounds)) {
this.distorter_.setTextureBounds(this.layer_.leftBounds, this.layer_.rightBounds);
}
};
CardboardVRDisplay.prototype.beginPresent_ = function () {
var gl = this.layer_.source.getContext('webgl');
if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
if (!gl) gl = this.layer_.source.getContext('webgl2');
if (!gl) return;
if (this.layer_.predistorted) {
if (!this.config.CARDBOARD_UI_DISABLED) {
gl.canvas.width = getScreenWidth() * this.bufferScale_;
gl.canvas.height = getScreenHeight() * this.bufferScale_;
this.cardboardUI_ = new CardboardUI(gl);
}
} else {
if (!this.config.CARDBOARD_UI_DISABLED) {
this.cardboardUI_ = new CardboardUI(gl);
}
this.distorter_ = new CardboardDistorter(gl, this.cardboardUI_, this.config.BUFFER_SCALE, this.config.DIRTY_SUBMIT_FRAME_BINDINGS);
this.distorter_.updateDeviceInfo(this.deviceInfo_);
}
if (this.cardboardUI_) {
this.cardboardUI_.listen(function (e) {
this.viewerSelector_.show(this.layer_.source.parentElement);
e.stopPropagation();
e.preventDefault();
}.bind(this), function (e) {
this.exitPresent();
e.stopPropagation();
e.preventDefault();
}.bind(this));
}
if (this.rotateInstructions_) {
if (isLandscapeMode() && isMobile()) {
this.rotateInstructions_.showTemporarily(3000, this.layer_.source.parentElement);
} else {
this.rotateInstructions_.update();
}
}
this.orientationHandler = this.onOrientationChange_.bind(this);
window.addEventListener('orientationchange', this.orientationHandler);
this.vrdisplaypresentchangeHandler = this.updateBounds_.bind(this);
window.addEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
this.fireVRDisplayDeviceParamsChange_();
};
CardboardVRDisplay.prototype.endPresent_ = function () {
if (this.distorter_) {
this.distorter_.destroy();
this.distorter_ = null;
}
if (this.cardboardUI_) {
this.cardboardUI_.destroy();
this.cardboardUI_ = null;
}
if (this.rotateInstructions_) {
this.rotateInstructions_.hide();
}
this.viewerSelector_.hide();
window.removeEventListener('orientationchange', this.orientationHandler);
window.removeEventListener('vrdisplaypresentchange', this.vrdisplaypresentchangeHandler);
};
CardboardVRDisplay.prototype.updatePresent_ = function () {
this.endPresent_();
this.beginPresent_();
};
CardboardVRDisplay.prototype.submitFrame = function (pose) {
if (this.distorter_) {
this.updateBounds_();
this.distorter_.submitFrame();
} else if (this.cardboardUI_ && this.layer_) {
var gl = this.layer_.source.getContext('webgl');
if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
if (!gl) gl = this.layer_.source.getContext('webgl2');
var canvas = gl.canvas;
if (canvas.width != this.lastWidth || canvas.height != this.lastHeight) {
this.cardboardUI_.onResize();
}
this.lastWidth = canvas.width;
this.lastHeight = canvas.height;
this.cardboardUI_.render();
}
};
CardboardVRDisplay.prototype.onOrientationChange_ = function (e) {
this.viewerSelector_.hide();
if (this.rotateInstructions_) {
this.rotateInstructions_.update();
}
this.onResize_();
};
CardboardVRDisplay.prototype.onResize_ = function (e) {
if (this.layer_) {
var gl = this.layer_.source.getContext('webgl');
if (!gl) gl = this.layer_.source.getContext('experimental-webgl');
if (!gl) gl = this.layer_.source.getContext('webgl2');
var cssProperties = ['position: absolute', 'top: 0', 'left: 0', 'width: 100vw', 'height: 100vh', 'border: 0', 'margin: 0', 'padding: 0px', 'box-sizing: content-box'];
gl.canvas.setAttribute('style', cssProperties.join('; ') + ';');
safariCssSizeWorkaround(gl.canvas);
}
};
CardboardVRDisplay.prototype.onViewerChanged_ = function (viewer) {
this.deviceInfo_.setViewer(viewer);
if (this.distorter_) {
this.distorter_.updateDeviceInfo(this.deviceInfo_);
}
this.fireVRDisplayDeviceParamsChange_();
};
CardboardVRDisplay.prototype.fireVRDisplayDeviceParamsChange_ = function () {
var event = new CustomEvent('vrdisplaydeviceparamschange', {
detail: {
vrdisplay: this,
deviceInfo: this.deviceInfo_
}
});
window.dispatchEvent(event);
};
CardboardVRDisplay.VRFrameData = VRFrameData;
CardboardVRDisplay.VRDisplay = VRDisplay;
return CardboardVRDisplay;
});
})(cardboardVrDisplay);
var CardboardVRDisplay = /*@__PURE__*/getDefaultExportFromCjs(cardboardVrDisplay.exports);
var version = "0.10.12";
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var DefaultConfig = {
// Optionally inject custom Viewer parameters as an option. Each item
// in the array must be an object with the following properties; here is
// an example of the built in CardboardV2 viewer:
//
// {
// id: 'CardboardV2',
// label: 'Cardboard I/O 2015',
// fov: 60,
// interLensDistance: 0.064,
// baselineLensDistance: 0.035,
// screenLensDistance: 0.039,
// distortionCoefficients: [0.34, 0.55],
// inverseCoefficients: [-0.33836704, -0.18162185, 0.862655, -1.2462051,
// 1.0560602, -0.58208317, 0.21609078, -0.05444823, 0.009177956,
// -9.904169E-4, 6.183535E-5, -1.6981803E-6]
// }
// Added in 0.10.6.
ADDITIONAL_VIEWERS: [],
// Select the viewer by ID. If unspecified, defaults to 'CardboardV1'.
// Added in 0.10.6.
DEFAULT_VIEWER: '',
// Provides a CardboardVRDisplay when the native WebVR API exists on
// mobile platforms that do not have a native VRDisplay.
// Added in 0.10.0.
PROVIDE_MOBILE_VRDISPLAY: true,
/**
* Options passed into the underlying CardboardVRDisplay
*/
// By default, on mobile, a wakelock is necessary to prevent the device's screen
// from turning off without user input. Disable if you're keeping the screen awake through
// other means on mobile. A wakelock is never used on desktop.
// Added in 0.10.2.
MOBILE_WAKE_LOCK: true,
// Whether or not CardboardVRDisplay is in debug mode. Logs extra
// messages. Added in 0.10.0.
DEBUG: false,
// The URL to JSON of DPDB information. By default, uses the data
// from https://github.com/WebVRRocks/webvr-polyfill-dpdb; if left
// falsy, then no attempt is made.
// Added in 0.10.0
DPDB_URL: 'https://dpdb.webvr.rocks/dpdb.json',
// Complementary filter coefficient. 0 for accelerometer, 1 for gyro.
K_FILTER: 0.98,
// How far into the future to predict during fast motion (in seconds).
PREDICTION_TIME_S: 0.040,
// Flag to disabled the UI in VR Mode.
CARDBOARD_UI_DISABLED: false,
// Default: false
// Flag to disable the instructions to rotate your device.
ROTATE_INSTRUCTIONS_DISABLED: false,
// Default: false.
// Enable yaw panning only, disabling roll and pitch. This can be useful
// for panoramas with nothing interesting above or below.
YAW_ONLY: false,
// Scales the recommended buffer size reported by WebVR, which can improve
// performance.
// UPDATE(2016-05-03): Setting this to 0.5 by default since 1.0 does not
// perform well on many mobile devices.
BUFFER_SCALE: 0.5,
// Allow VRDisplay.submitFrame to change gl bindings, which is more
// efficient if the application code will re-bind its resources on the
// next frame anyway. This has been seen to cause rendering glitches with
// THREE.js.
// Dirty bindings include: gl.FRAMEBUFFER_BINDING, gl.CURRENT_PROGRAM,
// gl.ARRAY_BUFFER_BINDING, gl.ELEMENT_ARRAY_BUFFER_BINDING,
// and gl.TEXTURE_BINDING_2D for texture unit 0.
DIRTY_SUBMIT_FRAME_BINDINGS: false
};
/*
* Copyright 2015 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
function WebVRPolyfill(config) {
this.config = extend(extend({}, DefaultConfig), config);
this.polyfillDisplays = [];
this.enabled = false;
// Must handle this in constructor before we start
// destructively polyfilling `navigator`
this.hasNative = 'getVRDisplays' in navigator;
// Store initial references to native constructors
// and functions
this.native = {};
this.native.getVRDisplays = navigator.getVRDisplays;
this.native.VRFrameData = window.VRFrameData;
this.native.VRDisplay = window.VRDisplay;
// If we don't have native 1.1 support, or if we want to provide
// a CardboardVRDisplay in the event of native support with no displays,
// inject our own polyfill
if (!this.hasNative || this.config.PROVIDE_MOBILE_VRDISPLAY && isMobile()) {
this.enable();
// If we need to create a CardboardVRDisplay, fire the `vrdisplayconnect`
// event when the polyfill is enabled
this.getVRDisplays().then(function (displays) {
if (displays && displays[0] && displays[0].fireVRDisplayConnect_) {
displays[0].fireVRDisplayConnect_();
}
});
}
}
WebVRPolyfill.prototype.getPolyfillDisplays = function () {
if (this._polyfillDisplaysPopulated) {
return this.polyfillDisplays;
}
// Add a Cardboard VRDisplay on compatible mobile devices
if (isMobile()) {
var vrDisplay = new CardboardVRDisplay({
ADDITIONAL_VIEWERS: this.config.ADDITIONAL_VIEWERS,
DEFAULT_VIEWER: this.config.DEFAULT_VIEWER,
MOBILE_WAKE_LOCK: this.config.MOBILE_WAKE_LOCK,
DEBUG: this.config.DEBUG,
DPDB_URL: this.config.DPDB_URL,
CARDBOARD_UI_DISABLED: this.config.CARDBOARD_UI_DISABLED,
K_FILTER: this.config.K_FILTER,
PREDICTION_TIME_S: this.config.PREDICTION_TIME_S,
ROTATE_INSTRUCTIONS_DISABLED: this.config.ROTATE_INSTRUCTIONS_DISABLED,
YAW_ONLY: this.config.YAW_ONLY,
BUFFER_SCALE: this.config.BUFFER_SCALE,
DIRTY_SUBMIT_FRAME_BINDINGS: this.config.DIRTY_SUBMIT_FRAME_BINDINGS
});
this.polyfillDisplays.push(vrDisplay);
}
this._polyfillDisplaysPopulated = true;
return this.polyfillDisplays;
};
WebVRPolyfill.prototype.enable = function () {
this.enabled = true;
// Polyfill native VRDisplay.getFrameData when the platform
// has native WebVR support, but for use with a polyfilled
// CardboardVRDisplay
if (this.hasNative && this.native.VRFrameData) {
var NativeVRFrameData = this.native.VRFrameData;
var nativeFrameData = new this.native.VRFrameData();
var nativeGetFrameData = this.native.VRDisplay.prototype.getFrameData;
// When using a native display with a polyfilled VRFrameData
window.VRDisplay.prototype.getFrameData = function (frameData) {
// This should only be called in the event of code instantiating
// `window.VRFrameData` before the polyfill kicks in, which is
// unrecommended, but happens anyway
if (frameData instanceof NativeVRFrameData) {
nativeGetFrameData.call(this, frameData);
return;
}
/*
Copy frame data from the native object into the polyfilled object.
*/
nativeGetFrameData.call(this, nativeFrameData);
frameData.pose = nativeFrameData.pose;
copyArray$1(nativeFrameData.leftProjectionMatrix, frameData.leftProjectionMatrix);
copyArray$1(nativeFrameData.rightProjectionMatrix, frameData.rightProjectionMatrix);
copyArray$1(nativeFrameData.leftViewMatrix, frameData.leftViewMatrix);
copyArray$1(nativeFrameData.rightViewMatrix, frameData.rightViewMatrix);
//todo: copy
};
}
// Provide navigator.getVRDisplays.
navigator.getVRDisplays = this.getVRDisplays.bind(this);
// Provide the `VRDisplay` object.
window.VRDisplay = CardboardVRDisplay.VRDisplay;
// Provide the VRFrameData object.
window.VRFrameData = CardboardVRDisplay.VRFrameData;
};
WebVRPolyfill.prototype.getVRDisplays = function () {
this.config;
if (!this.hasNative) {
return Promise.resolve(this.getPolyfillDisplays());
}
return this.native.getVRDisplays.call(navigator).then(nativeDisplays => {
return nativeDisplays.length > 0 ? nativeDisplays : this.getPolyfillDisplays();
});
};
WebVRPolyfill.version = version;
// Attach polyfilled constructors
WebVRPolyfill.VRFrameData = CardboardVRDisplay.VRFrameData;
WebVRPolyfill.VRDisplay = CardboardVRDisplay.VRDisplay;
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
try {
var info = gen[key](arg);
var value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
Promise.resolve(value).then(_next, _throw);
}
}
function _asyncToGenerator(fn) {
return function () {
var self = this,
args = arguments;
return new Promise(function (resolve, reject) {
var gen = fn.apply(self, args);
function _next(value) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
}
function _throw(err) {
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
}
_next(undefined);
});
};
}
function _extends() {
_extends = Object.assign ? Object.assign.bind() : function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
// threejs.org/license
const REVISION = '125';
const MOUSE = {
LEFT: 0,
MIDDLE: 1,
RIGHT: 2,
ROTATE: 0,
DOLLY: 1,
PAN: 2
};
const CullFaceNone = 0;
const CullFaceBack = 1;
const CullFaceFront = 2;
const PCFShadowMap = 1;
const PCFSoftShadowMap = 2;
const VSMShadowMap = 3;
const FrontSide = 0;
const BackSide = 1;
const DoubleSide = 2;
const FlatShading = 1;
const NoBlending = 0;
const NormalBlending = 1;
const AdditiveBlending = 2;
const SubtractiveBlending = 3;
const MultiplyBlending = 4;
const CustomBlending = 5;
const AddEquation = 100;
const SubtractEquation = 101;
const ReverseSubtractEquation = 102;
const MinEquation = 103;
const MaxEquation = 104;
const ZeroFactor = 200;
const OneFactor = 201;
const SrcColorFactor = 202;
const OneMinusSrcColorFactor = 203;
const SrcAlphaFactor = 204;
const OneMinusSrcAlphaFactor = 205;
const DstAlphaFactor = 206;
const OneMinusDstAlphaFactor = 207;
const DstColorFactor = 208;
const OneMinusDstColorFactor = 209;
const SrcAlphaSaturateFactor = 210;
const NeverDepth = 0;
const AlwaysDepth = 1;
const LessDepth = 2;
const LessEqualDepth = 3;
const EqualDepth = 4;
const GreaterEqualDepth = 5;
const GreaterDepth = 6;
const NotEqualDepth = 7;
const MultiplyOperation = 0;
const MixOperation = 1;
const AddOperation = 2;
const NoToneMapping = 0;
const LinearToneMapping = 1;
const ReinhardToneMapping = 2;
const CineonToneMapping = 3;
const ACESFilmicToneMapping = 4;
const CustomToneMapping = 5;
const UVMapping = 300;
const CubeReflectionMapping = 301;
const CubeRefractionMapping = 302;
const EquirectangularReflectionMapping = 303;
const EquirectangularRefractionMapping = 304;
const CubeUVReflectionMapping = 306;
const CubeUVRefractionMapping = 307;
const RepeatWrapping = 1000;
const ClampToEdgeWrapping = 1001;
const MirroredRepeatWrapping = 1002;
const NearestFilter = 1003;
const NearestMipmapNearestFilter = 1004;
const NearestMipmapLinearFilter = 1005;
const LinearFilter = 1006;
const LinearMipmapNearestFilter = 1007;
const LinearMipmapLinearFilter = 1008;
const UnsignedByteType = 1009;
const ByteType = 1010;
const ShortType = 1011;
const UnsignedShortType = 1012;
const IntType = 1013;
const UnsignedIntType = 1014;
const FloatType = 1015;
const HalfFloatType = 1016;
const UnsignedShort4444Type = 1017;
const UnsignedShort5551Type = 1018;
const UnsignedShort565Type = 1019;
const UnsignedInt248Type = 1020;
const AlphaFormat = 1021;
const RGBFormat = 1022;
const RGBAFormat = 1023;
const LuminanceFormat = 1024;
const LuminanceAlphaFormat = 1025;
const DepthFormat = 1026;
const DepthStencilFormat = 1027;
const RedFormat = 1028;
const RedIntegerFormat = 1029;
const RGFormat = 1030;
const RGIntegerFormat = 1031;
const RGBIntegerFormat = 1032;
const RGBAIntegerFormat = 1033;
const RGB_S3TC_DXT1_Format = 33776;
const RGBA_S3TC_DXT1_Format = 33777;
const RGBA_S3TC_DXT3_Format = 33778;
const RGBA_S3TC_DXT5_Format = 33779;
const RGB_PVRTC_4BPPV1_Format = 35840;
const RGB_PVRTC_2BPPV1_Format = 35841;
const RGBA_PVRTC_4BPPV1_Format = 35842;
const RGBA_PVRTC_2BPPV1_Format = 35843;
const RGB_ETC1_Format = 36196;
const RGB_ETC2_Format = 37492;
const RGBA_ETC2_EAC_Format = 37496;
const RGBA_ASTC_4x4_Format = 37808;
const RGBA_ASTC_5x4_Format = 37809;
const RGBA_ASTC_5x5_Format = 37810;
const RGBA_ASTC_6x5_Format = 37811;
const RGBA_ASTC_6x6_Format = 37812;
const RGBA_ASTC_8x5_Format = 37813;
const RGBA_ASTC_8x6_Format = 37814;
const RGBA_ASTC_8x8_Format = 37815;
const RGBA_ASTC_10x5_Format = 37816;
const RGBA_ASTC_10x6_Format = 37817;
const RGBA_ASTC_10x8_Format = 37818;
const RGBA_ASTC_10x10_Format = 37819;
const RGBA_ASTC_12x10_Format = 37820;
const RGBA_ASTC_12x12_Format = 37821;
const RGBA_BPTC_Format = 36492;
const SRGB8_ALPHA8_ASTC_4x4_Format = 37840;
const SRGB8_ALPHA8_ASTC_5x4_Format = 37841;
const SRGB8_ALPHA8_ASTC_5x5_Format = 37842;
const SRGB8_ALPHA8_ASTC_6x5_Format = 37843;
const SRGB8_ALPHA8_ASTC_6x6_Format = 37844;
const SRGB8_ALPHA8_ASTC_8x5_Format = 37845;
const SRGB8_ALPHA8_ASTC_8x6_Format = 37846;
const SRGB8_ALPHA8_ASTC_8x8_Format = 37847;
const SRGB8_ALPHA8_ASTC_10x5_Format = 37848;
const SRGB8_ALPHA8_ASTC_10x6_Format = 37849;
const SRGB8_ALPHA8_ASTC_10x8_Format = 37850;
const SRGB8_ALPHA8_ASTC_10x10_Format = 37851;
const SRGB8_ALPHA8_ASTC_12x10_Format = 37852;
const SRGB8_ALPHA8_ASTC_12x12_Format = 37853;
const LoopOnce = 2200;
const LoopRepeat = 2201;
const LoopPingPong = 2202;
const InterpolateDiscrete = 2300;
const InterpolateLinear = 2301;
const InterpolateSmooth = 2302;
const ZeroCurvatureEnding = 2400;
const ZeroSlopeEnding = 2401;
const WrapAroundEnding = 2402;
const NormalAnimationBlendMode = 2500;
const AdditiveAnimationBlendMode = 2501;
const TrianglesDrawMode = 0;
const LinearEncoding = 3000;
const sRGBEncoding = 3001;
const GammaEncoding = 3007;
const RGBEEncoding = 3002;
const LogLuvEncoding = 3003;
const RGBM7Encoding = 3004;
const RGBM16Encoding = 3005;
const RGBDEncoding = 3006;
const BasicDepthPacking = 3200;
const RGBADepthPacking = 3201;
const TangentSpaceNormalMap = 0;
const ObjectSpaceNormalMap = 1;
const KeepStencilOp = 7680;
const AlwaysStencilFunc = 519;
const StaticDrawUsage = 35044;
const DynamicDrawUsage = 35048;
const GLSL3 = '300 es';
/**
* https://github.com/mrdoob/eventdispatcher.js/
*/
function EventDispatcher() {}
_extends(EventDispatcher.prototype, {
addEventListener: function (type, listener) {
if (this._listeners === undefined) this._listeners = {};
const listeners = this._listeners;
if (listeners[type] === undefined) {
listeners[type] = [];
}
if (listeners[type].indexOf(listener) === -1) {
listeners[type].push(listener);
}
},
hasEventListener: function (type, listener) {
if (this._listeners === undefined) return false;
const listeners = this._listeners;
return listeners[type] !== undefined && listeners[type].indexOf(listener) !== -1;
},
removeEventListener: function (type, listener) {
if (this._listeners === undefined) return;
const listeners = this._listeners;
const listenerArray = listeners[type];
if (listenerArray !== undefined) {
const index = listenerArray.indexOf(listener);
if (index !== -1) {
listenerArray.splice(index, 1);
}
}
},
dispatchEvent: function (event) {
if (this._listeners === undefined) return;
const listeners = this._listeners;
const listenerArray = listeners[event.type];
if (listenerArray !== undefined) {
event.target = this;
// Make a copy, in case listeners are removed while iterating.
const array = listenerArray.slice(0);
for (let i = 0, l = array.length; i < l; i++) {
array[i].call(this, event);
}
}
}
});
const _lut = [];
for (let i = 0; i < 256; i++) {
_lut[i] = (i < 16 ? '0' : '') + i.toString(16);
}
let _seed = 1234567;
const MathUtils = {
DEG2RAD: Math.PI / 180,
RAD2DEG: 180 / Math.PI,
generateUUID: function () {
// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
const d0 = Math.random() * 0xffffffff | 0;
const d1 = Math.random() * 0xffffffff | 0;
const d2 = Math.random() * 0xffffffff | 0;
const d3 = Math.random() * 0xffffffff | 0;
const uuid = _lut[d0 & 0xff] + _lut[d0 >> 8 & 0xff] + _lut[d0 >> 16 & 0xff] + _lut[d0 >> 24 & 0xff] + '-' + _lut[d1 & 0xff] + _lut[d1 >> 8 & 0xff] + '-' + _lut[d1 >> 16 & 0x0f | 0x40] + _lut[d1 >> 24 & 0xff] + '-' + _lut[d2 & 0x3f | 0x80] + _lut[d2 >> 8 & 0xff] + '-' + _lut[d2 >> 16 & 0xff] + _lut[d2 >> 24 & 0xff] + _lut[d3 & 0xff] + _lut[d3 >> 8 & 0xff] + _lut[d3 >> 16 & 0xff] + _lut[d3 >> 24 & 0xff];
// .toUpperCase() here flattens concatenated strings to save heap memory space.
return uuid.toUpperCase();
},
clamp: function (value, min, max) {
return Math.max(min, Math.min(max, value));
},
// compute euclidian modulo of m % n
// https://en.wikipedia.org/wiki/Modulo_operation
euclideanModulo: function (n, m) {
return (n % m + m) % m;
},
// Linear mapping from range to range
mapLinear: function (x, a1, a2, b1, b2) {
return b1 + (x - a1) * (b2 - b1) / (a2 - a1);
},
// https://en.wikipedia.org/wiki/Linear_interpolation
lerp: function (x, y, t) {
return (1 - t) * x + t * y;
},
// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/
damp: function (x, y, lambda, dt) {
return MathUtils.lerp(x, y, 1 - Math.exp(-lambda * dt));
},
// https://www.desmos.com/calculator/vcsjnyz7x4
pingpong: function (x, length = 1) {
return length - Math.abs(MathUtils.euclideanModulo(x, length * 2) - length);
},
// http://en.wikipedia.org/wiki/Smoothstep
smoothstep: function (x, min, max) {
if (x <= min) return 0;
if (x >= max) return 1;
x = (x - min) / (max - min);
return x * x * (3 - 2 * x);
},
smootherstep: function (x, min, max) {
if (x <= min) return 0;
if (x >= max) return 1;
x = (x - min) / (max - min);
return x * x * x * (x * (x * 6 - 15) + 10);
},
// Random integer from interval
randInt: function (low, high) {
return low + Math.floor(Math.random() * (high - low + 1));
},
// Random float from interval
randFloat: function (low, high) {
return low + Math.random() * (high - low);
},
// Random float from <-range/2, range/2> interval
randFloatSpread: function (range) {
return range * (0.5 - Math.random());
},
// Deterministic pseudo-random float in the interval [ 0, 1 ]
seededRandom: function (s) {
if (s !== undefined) _seed = s % 2147483647;
// Park-Miller algorithm
_seed = _seed * 16807 % 2147483647;
return (_seed - 1) / 2147483646;
},
degToRad: function (degrees) {
return degrees * MathUtils.DEG2RAD;
},
radToDeg: function (radians) {
return radians * MathUtils.RAD2DEG;
},
isPowerOfTwo: function (value) {
return (value & value - 1) === 0 && value !== 0;
},
ceilPowerOfTwo: function (value) {
return Math.pow(2, Math.ceil(Math.log(value) / Math.LN2));
},
floorPowerOfTwo: function (value) {
return Math.pow(2, Math.floor(Math.log(value) / Math.LN2));
},
setQuaternionFromProperEuler: function (q, a, b, c, order) {
// Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles
// rotations are applied to the axes in the order specified by 'order'
// rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'
// angles are in radians
const cos = Math.cos;
const sin = Math.sin;
const c2 = cos(b / 2);
const s2 = sin(b / 2);
const c13 = cos((a + c) / 2);
const s13 = sin((a + c) / 2);
const c1_3 = cos((a - c) / 2);
const s1_3 = sin((a - c) / 2);
const c3_1 = cos((c - a) / 2);
const s3_1 = sin((c - a) / 2);
switch (order) {
case 'XYX':
q.set(c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13);
break;
case 'YZY':
q.set(s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13);
break;
case 'ZXZ':
q.set(s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13);
break;
case 'XZX':
q.set(c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13);
break;
case 'YXY':
q.set(s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13);
break;
case 'ZYZ':
q.set(s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13);
break;
default:
console.warn('THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order);
}
}
};
class Vector2 {
constructor(x = 0, y = 0) {
Object.defineProperty(this, 'isVector2', {
value: true
});
this.x = x;
this.y = y;
}
get width() {
return this.x;
}
set width(value) {
this.x = value;
}
get height() {
return this.y;
}
set height(value) {
this.y = value;
}
set(x, y) {
this.x = x;
this.y = y;
return this;
}
setScalar(scalar) {
this.x = scalar;
this.y = scalar;
return this;
}
setX(x) {
this.x = x;
return this;
}
setY(y) {
this.y = y;
return this;
}
setComponent(index, value) {
switch (index) {
case 0:
this.x = value;
break;
case 1:
this.y = value;
break;
default:
throw new Error('index is out of range: ' + index);
}
return this;
}
getComponent(index) {
switch (index) {
case 0:
return this.x;
case 1:
return this.y;
default:
throw new Error('index is out of range: ' + index);
}
}
clone() {
return new this.constructor(this.x, this.y);
}
copy(v) {
this.x = v.x;
this.y = v.y;
return this;
}
add(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector2: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
return this.addVectors(v, w);
}
this.x += v.x;
this.y += v.y;
return this;
}
addScalar(s) {
this.x += s;
this.y += s;
return this;
}
addVectors(a, b) {
this.x = a.x + b.x;
this.y = a.y + b.y;
return this;
}
addScaledVector(v, s) {
this.x += v.x * s;
this.y += v.y * s;
return this;
}
sub(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector2: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
return this.subVectors(v, w);
}
this.x -= v.x;
this.y -= v.y;
return this;
}
subScalar(s) {
this.x -= s;
this.y -= s;
return this;
}
subVectors(a, b) {
this.x = a.x - b.x;
this.y = a.y - b.y;
return this;
}
multiply(v) {
this.x *= v.x;
this.y *= v.y;
return this;
}
multiplyScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
return this;
}
divide(v) {
this.x /= v.x;
this.y /= v.y;
return this;
}
divideScalar(scalar) {
return this.multiplyScalar(1 / scalar);
}
applyMatrix3(m) {
const x = this.x,
y = this.y;
const e = m.elements;
this.x = e[0] * x + e[3] * y + e[6];
this.y = e[1] * x + e[4] * y + e[7];
return this;
}
min(v) {
this.x = Math.min(this.x, v.x);
this.y = Math.min(this.y, v.y);
return this;
}
max(v) {
this.x = Math.max(this.x, v.x);
this.y = Math.max(this.y, v.y);
return this;
}
clamp(min, max) {
// assumes min < max, componentwise
this.x = Math.max(min.x, Math.min(max.x, this.x));
this.y = Math.max(min.y, Math.min(max.y, this.y));
return this;
}
clampScalar(minVal, maxVal) {
this.x = Math.max(minVal, Math.min(maxVal, this.x));
this.y = Math.max(minVal, Math.min(maxVal, this.y));
return this;
}
clampLength(min, max) {
const length = this.length();
return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
}
floor() {
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
return this;
}
ceil() {
this.x = Math.ceil(this.x);
this.y = Math.ceil(this.y);
return this;
}
round() {
this.x = Math.round(this.x);
this.y = Math.round(this.y);
return this;
}
roundToZero() {
this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
return this;
}
negate() {
this.x = -this.x;
this.y = -this.y;
return this;
}
dot(v) {
return this.x * v.x + this.y * v.y;
}
cross(v) {
return this.x * v.y - this.y * v.x;
}
lengthSq() {
return this.x * this.x + this.y * this.y;
}
length() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
manhattanLength() {
return Math.abs(this.x) + Math.abs(this.y);
}
normalize() {
return this.divideScalar(this.length() || 1);
}
angle() {
// computes the angle in radians with respect to the positive x-axis
const angle = Math.atan2(-this.y, -this.x) + Math.PI;
return angle;
}
distanceTo(v) {
return Math.sqrt(this.distanceToSquared(v));
}
distanceToSquared(v) {
const dx = this.x - v.x,
dy = this.y - v.y;
return dx * dx + dy * dy;
}
manhattanDistanceTo(v) {
return Math.abs(this.x - v.x) + Math.abs(this.y - v.y);
}
setLength(length) {
return this.normalize().multiplyScalar(length);
}
lerp(v, alpha) {
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
return this;
}
lerpVectors(v1, v2, alpha) {
this.x = v1.x + (v2.x - v1.x) * alpha;
this.y = v1.y + (v2.y - v1.y) * alpha;
return this;
}
equals(v) {
return v.x === this.x && v.y === this.y;
}
fromArray(array, offset = 0) {
this.x = array[offset];
this.y = array[offset + 1];
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this.x;
array[offset + 1] = this.y;
return array;
}
fromBufferAttribute(attribute, index, offset) {
if (offset !== undefined) {
console.warn('THREE.Vector2: offset has been removed from .fromBufferAttribute().');
}
this.x = attribute.getX(index);
this.y = attribute.getY(index);
return this;
}
rotateAround(center, angle) {
const c = Math.cos(angle),
s = Math.sin(angle);
const x = this.x - center.x;
const y = this.y - center.y;
this.x = x * c - y * s + center.x;
this.y = x * s + y * c + center.y;
return this;
}
random() {
this.x = Math.random();
this.y = Math.random();
return this;
}
}
class Matrix3 {
constructor() {
Object.defineProperty(this, 'isMatrix3', {
value: true
});
this.elements = [1, 0, 0, 0, 1, 0, 0, 0, 1];
if (arguments.length > 0) {
console.error('THREE.Matrix3: the constructor no longer reads arguments. use .set() instead.');
}
}
set(n11, n12, n13, n21, n22, n23, n31, n32, n33) {
const te = this.elements;
te[0] = n11;
te[1] = n21;
te[2] = n31;
te[3] = n12;
te[4] = n22;
te[5] = n32;
te[6] = n13;
te[7] = n23;
te[8] = n33;
return this;
}
identity() {
this.set(1, 0, 0, 0, 1, 0, 0, 0, 1);
return this;
}
clone() {
return new this.constructor().fromArray(this.elements);
}
copy(m) {
const te = this.elements;
const me = m.elements;
te[0] = me[0];
te[1] = me[1];
te[2] = me[2];
te[3] = me[3];
te[4] = me[4];
te[5] = me[5];
te[6] = me[6];
te[7] = me[7];
te[8] = me[8];
return this;
}
extractBasis(xAxis, yAxis, zAxis) {
xAxis.setFromMatrix3Column(this, 0);
yAxis.setFromMatrix3Column(this, 1);
zAxis.setFromMatrix3Column(this, 2);
return this;
}
setFromMatrix4(m) {
const me = m.elements;
this.set(me[0], me[4], me[8], me[1], me[5], me[9], me[2], me[6], me[10]);
return this;
}
multiply(m) {
return this.multiplyMatrices(this, m);
}
premultiply(m) {
return this.multiplyMatrices(m, this);
}
multiplyMatrices(a, b) {
const ae = a.elements;
const be = b.elements;
const te = this.elements;
const a11 = ae[0],
a12 = ae[3],
a13 = ae[6];
const a21 = ae[1],
a22 = ae[4],
a23 = ae[7];
const a31 = ae[2],
a32 = ae[5],
a33 = ae[8];
const b11 = be[0],
b12 = be[3],
b13 = be[6];
const b21 = be[1],
b22 = be[4],
b23 = be[7];
const b31 = be[2],
b32 = be[5],
b33 = be[8];
te[0] = a11 * b11 + a12 * b21 + a13 * b31;
te[3] = a11 * b12 + a12 * b22 + a13 * b32;
te[6] = a11 * b13 + a12 * b23 + a13 * b33;
te[1] = a21 * b11 + a22 * b21 + a23 * b31;
te[4] = a21 * b12 + a22 * b22 + a23 * b32;
te[7] = a21 * b13 + a22 * b23 + a23 * b33;
te[2] = a31 * b11 + a32 * b21 + a33 * b31;
te[5] = a31 * b12 + a32 * b22 + a33 * b32;
te[8] = a31 * b13 + a32 * b23 + a33 * b33;
return this;
}
multiplyScalar(s) {
const te = this.elements;
te[0] *= s;
te[3] *= s;
te[6] *= s;
te[1] *= s;
te[4] *= s;
te[7] *= s;
te[2] *= s;
te[5] *= s;
te[8] *= s;
return this;
}
determinant() {
const te = this.elements;
const a = te[0],
b = te[1],
c = te[2],
d = te[3],
e = te[4],
f = te[5],
g = te[6],
h = te[7],
i = te[8];
return a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;
}
invert() {
const te = this.elements,
n11 = te[0],
n21 = te[1],
n31 = te[2],
n12 = te[3],
n22 = te[4],
n32 = te[5],
n13 = te[6],
n23 = te[7],
n33 = te[8],
t11 = n33 * n22 - n32 * n23,
t12 = n32 * n13 - n33 * n12,
t13 = n23 * n12 - n22 * n13,
det = n11 * t11 + n21 * t12 + n31 * t13;
if (det === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0);
const detInv = 1 / det;
te[0] = t11 * detInv;
te[1] = (n31 * n23 - n33 * n21) * detInv;
te[2] = (n32 * n21 - n31 * n22) * detInv;
te[3] = t12 * detInv;
te[4] = (n33 * n11 - n31 * n13) * detInv;
te[5] = (n31 * n12 - n32 * n11) * detInv;
te[6] = t13 * detInv;
te[7] = (n21 * n13 - n23 * n11) * detInv;
te[8] = (n22 * n11 - n21 * n12) * detInv;
return this;
}
transpose() {
let tmp;
const m = this.elements;
tmp = m[1];
m[1] = m[3];
m[3] = tmp;
tmp = m[2];
m[2] = m[6];
m[6] = tmp;
tmp = m[5];
m[5] = m[7];
m[7] = tmp;
return this;
}
getNormalMatrix(matrix4) {
return this.setFromMatrix4(matrix4).copy(this).invert().transpose();
}
transposeIntoArray(r) {
const m = this.elements;
r[0] = m[0];
r[1] = m[3];
r[2] = m[6];
r[3] = m[1];
r[4] = m[4];
r[5] = m[7];
r[6] = m[2];
r[7] = m[5];
r[8] = m[8];
return this;
}
setUvTransform(tx, ty, sx, sy, rotation, cx, cy) {
const c = Math.cos(rotation);
const s = Math.sin(rotation);
this.set(sx * c, sx * s, -sx * (c * cx + s * cy) + cx + tx, -sy * s, sy * c, -sy * (-s * cx + c * cy) + cy + ty, 0, 0, 1);
return this;
}
scale(sx, sy) {
const te = this.elements;
te[0] *= sx;
te[3] *= sx;
te[6] *= sx;
te[1] *= sy;
te[4] *= sy;
te[7] *= sy;
return this;
}
rotate(theta) {
const c = Math.cos(theta);
const s = Math.sin(theta);
const te = this.elements;
const a11 = te[0],
a12 = te[3],
a13 = te[6];
const a21 = te[1],
a22 = te[4],
a23 = te[7];
te[0] = c * a11 + s * a21;
te[3] = c * a12 + s * a22;
te[6] = c * a13 + s * a23;
te[1] = -s * a11 + c * a21;
te[4] = -s * a12 + c * a22;
te[7] = -s * a13 + c * a23;
return this;
}
translate(tx, ty) {
const te = this.elements;
te[0] += tx * te[2];
te[3] += tx * te[5];
te[6] += tx * te[8];
te[1] += ty * te[2];
te[4] += ty * te[5];
te[7] += ty * te[8];
return this;
}
equals(matrix) {
const te = this.elements;
const me = matrix.elements;
for (let i = 0; i < 9; i++) {
if (te[i] !== me[i]) return false;
}
return true;
}
fromArray(array, offset = 0) {
for (let i = 0; i < 9; i++) {
this.elements[i] = array[i + offset];
}
return this;
}
toArray(array = [], offset = 0) {
const te = this.elements;
array[offset] = te[0];
array[offset + 1] = te[1];
array[offset + 2] = te[2];
array[offset + 3] = te[3];
array[offset + 4] = te[4];
array[offset + 5] = te[5];
array[offset + 6] = te[6];
array[offset + 7] = te[7];
array[offset + 8] = te[8];
return array;
}
}
let _canvas;
const ImageUtils = {
getDataURL: function (image) {
if (/^data:/i.test(image.src)) {
return image.src;
}
if (typeof HTMLCanvasElement == 'undefined') {
return image.src;
}
let canvas;
if (image instanceof HTMLCanvasElement) {
canvas = image;
} else {
if (_canvas === undefined) _canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas');
_canvas.width = image.width;
_canvas.height = image.height;
const context = _canvas.getContext('2d');
if (image instanceof ImageData) {
context.putImageData(image, 0, 0);
} else {
context.drawImage(image, 0, 0, image.width, image.height);
}
canvas = _canvas;
}
if (canvas.width > 2048 || canvas.height > 2048) {
return canvas.toDataURL('image/jpeg', 0.6);
} else {
return canvas.toDataURL('image/png');
}
}
};
let textureId = 0;
function Texture(image = Texture.DEFAULT_IMAGE, mapping = Texture.DEFAULT_MAPPING, wrapS = ClampToEdgeWrapping, wrapT = ClampToEdgeWrapping, magFilter = LinearFilter, minFilter = LinearMipmapLinearFilter, format = RGBAFormat, type = UnsignedByteType, anisotropy = 1, encoding = LinearEncoding) {
Object.defineProperty(this, 'id', {
value: textureId++
});
this.uuid = MathUtils.generateUUID();
this.name = '';
this.image = image;
this.mipmaps = [];
this.mapping = mapping;
this.wrapS = wrapS;
this.wrapT = wrapT;
this.magFilter = magFilter;
this.minFilter = minFilter;
this.anisotropy = anisotropy;
this.format = format;
this.internalFormat = null;
this.type = type;
this.offset = new Vector2(0, 0);
this.repeat = new Vector2(1, 1);
this.center = new Vector2(0, 0);
this.rotation = 0;
this.matrixAutoUpdate = true;
this.matrix = new Matrix3();
this.generateMipmaps = true;
this.premultiplyAlpha = false;
this.flipY = true;
this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)
// Values of encoding !== THREE.LinearEncoding only supported on map, envMap and emissiveMap.
//
// Also changing the encoding after already used by a Material will not automatically make the Material
// update. You need to explicitly call Material.needsUpdate to trigger it to recompile.
this.encoding = encoding;
this.version = 0;
this.onUpdate = null;
}
Texture.DEFAULT_IMAGE = undefined;
Texture.DEFAULT_MAPPING = UVMapping;
Texture.prototype = _extends(Object.create(EventDispatcher.prototype), {
constructor: Texture,
isTexture: true,
updateMatrix: function () {
this.matrix.setUvTransform(this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y);
},
clone: function () {
return new this.constructor().copy(this);
},
copy: function (source) {
this.name = source.name;
this.image = source.image;
this.mipmaps = source.mipmaps.slice(0);
this.mapping = source.mapping;
this.wrapS = source.wrapS;
this.wrapT = source.wrapT;
this.magFilter = source.magFilter;
this.minFilter = source.minFilter;
this.anisotropy = source.anisotropy;
this.format = source.format;
this.internalFormat = source.internalFormat;
this.type = source.type;
this.offset.copy(source.offset);
this.repeat.copy(source.repeat);
this.center.copy(source.center);
this.rotation = source.rotation;
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrix.copy(source.matrix);
this.generateMipmaps = source.generateMipmaps;
this.premultiplyAlpha = source.premultiplyAlpha;
this.flipY = source.flipY;
this.unpackAlignment = source.unpackAlignment;
this.encoding = source.encoding;
return this;
},
toJSON: function (meta) {
const isRootObject = meta === undefined || typeof meta === 'string';
if (!isRootObject && meta.textures[this.uuid] !== undefined) {
return meta.textures[this.uuid];
}
const output = {
metadata: {
version: 4.5,
type: 'Texture',
generator: 'Texture.toJSON'
},
uuid: this.uuid,
name: this.name,
mapping: this.mapping,
repeat: [this.repeat.x, this.repeat.y],
offset: [this.offset.x, this.offset.y],
center: [this.center.x, this.center.y],
rotation: this.rotation,
wrap: [this.wrapS, this.wrapT],
format: this.format,
type: this.type,
encoding: this.encoding,
minFilter: this.minFilter,
magFilter: this.magFilter,
anisotropy: this.anisotropy,
flipY: this.flipY,
premultiplyAlpha: this.premultiplyAlpha,
unpackAlignment: this.unpackAlignment
};
if (this.image !== undefined) {
// TODO: Move to THREE.Image
const image = this.image;
if (image.uuid === undefined) {
image.uuid = MathUtils.generateUUID(); // UGH
}
if (!isRootObject && meta.images[image.uuid] === undefined) {
let url;
if (Array.isArray(image)) {
// process array of images e.g. CubeTexture
url = [];
for (let i = 0, l = image.length; i < l; i++) {
// check cube texture with data textures
if (image[i].isDataTexture) {
url.push(serializeImage(image[i].image));
} else {
url.push(serializeImage(image[i]));
}
}
} else {
// process single image
url = serializeImage(image);
}
meta.images[image.uuid] = {
uuid: image.uuid,
url: url
};
}
output.image = image.uuid;
}
if (!isRootObject) {
meta.textures[this.uuid] = output;
}
return output;
},
dispose: function () {
this.dispatchEvent({
type: 'dispose'
});
},
transformUv: function (uv) {
if (this.mapping !== UVMapping) return uv;
uv.applyMatrix3(this.matrix);
if (uv.x < 0 || uv.x > 1) {
switch (this.wrapS) {
case RepeatWrapping:
uv.x = uv.x - Math.floor(uv.x);
break;
case ClampToEdgeWrapping:
uv.x = uv.x < 0 ? 0 : 1;
break;
case MirroredRepeatWrapping:
if (Math.abs(Math.floor(uv.x) % 2) === 1) {
uv.x = Math.ceil(uv.x) - uv.x;
} else {
uv.x = uv.x - Math.floor(uv.x);
}
break;
}
}
if (uv.y < 0 || uv.y > 1) {
switch (this.wrapT) {
case RepeatWrapping:
uv.y = uv.y - Math.floor(uv.y);
break;
case ClampToEdgeWrapping:
uv.y = uv.y < 0 ? 0 : 1;
break;
case MirroredRepeatWrapping:
if (Math.abs(Math.floor(uv.y) % 2) === 1) {
uv.y = Math.ceil(uv.y) - uv.y;
} else {
uv.y = uv.y - Math.floor(uv.y);
}
break;
}
}
if (this.flipY) {
uv.y = 1 - uv.y;
}
return uv;
}
});
Object.defineProperty(Texture.prototype, 'needsUpdate', {
set: function (value) {
if (value === true) this.version++;
}
});
function serializeImage(image) {
if (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement || typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement || typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap) {
// default images
return ImageUtils.getDataURL(image);
} else {
if (image.data) {
// images of DataTexture
return {
data: Array.prototype.slice.call(image.data),
width: image.width,
height: image.height,
type: image.data.constructor.name
};
} else {
console.warn('THREE.Texture: Unable to serialize Texture.');
return {};
}
}
}
class Vector4 {
constructor(x = 0, y = 0, z = 0, w = 1) {
Object.defineProperty(this, 'isVector4', {
value: true
});
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
get width() {
return this.z;
}
set width(value) {
this.z = value;
}
get height() {
return this.w;
}
set height(value) {
this.w = value;
}
set(x, y, z, w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
return this;
}
setScalar(scalar) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
this.w = scalar;
return this;
}
setX(x) {
this.x = x;
return this;
}
setY(y) {
this.y = y;
return this;
}
setZ(z) {
this.z = z;
return this;
}
setW(w) {
this.w = w;
return this;
}
setComponent(index, value) {
switch (index) {
case 0:
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
this.z = value;
break;
case 3:
this.w = value;
break;
default:
throw new Error('index is out of range: ' + index);
}
return this;
}
getComponent(index) {
switch (index) {
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.z;
case 3:
return this.w;
default:
throw new Error('index is out of range: ' + index);
}
}
clone() {
return new this.constructor(this.x, this.y, this.z, this.w);
}
copy(v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
this.w = v.w !== undefined ? v.w : 1;
return this;
}
add(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector4: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
return this.addVectors(v, w);
}
this.x += v.x;
this.y += v.y;
this.z += v.z;
this.w += v.w;
return this;
}
addScalar(s) {
this.x += s;
this.y += s;
this.z += s;
this.w += s;
return this;
}
addVectors(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(v, s) {
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
this.w += v.w * s;
return this;
}
sub(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector4: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
return this.subVectors(v, w);
}
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
this.w -= v.w;
return this;
}
subScalar(s) {
this.x -= s;
this.y -= s;
this.z -= s;
this.w -= s;
return this;
}
subVectors(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;
}
multiply(v) {
this.x *= v.x;
this.y *= v.y;
this.z *= v.z;
this.w *= v.w;
return this;
}
multiplyScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
this.w *= scalar;
return this;
}
applyMatrix4(m) {
const x = this.x,
y = this.y,
z = this.z,
w = this.w;
const e = m.elements;
this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w;
this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w;
this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w;
this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w;
return this;
}
divideScalar(scalar) {
return this.multiplyScalar(1 / scalar);
}
setAxisAngleFromQuaternion(q) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm
// q is assumed to be normalized
this.w = 2 * Math.acos(q.w);
const s = Math.sqrt(1 - q.w * q.w);
if (s < 0.0001) {
this.x = 1;
this.y = 0;
this.z = 0;
} else {
this.x = q.x / s;
this.y = q.y / s;
this.z = q.z / s;
}
return this;
}
setAxisAngleFromRotationMatrix(m) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
let angle, x, y, z; // variables for result
const epsilon = 0.01,
// margin to allow for rounding errors
epsilon2 = 0.1,
// margin to distinguish between 0 and 180 degrees
te = m.elements,
m11 = te[0],
m12 = te[4],
m13 = te[8],
m21 = te[1],
m22 = te[5],
m23 = te[9],
m31 = te[2],
m32 = te[6],
m33 = te[10];
if (Math.abs(m12 - m21) < epsilon && Math.abs(m13 - m31) < epsilon && Math.abs(m23 - m32) < epsilon) {
// singularity found
// first check for identity matrix which must have +1 for all terms
// in leading diagonal and zero in other terms
if (Math.abs(m12 + m21) < epsilon2 && Math.abs(m13 + m31) < epsilon2 && Math.abs(m23 + m32) < epsilon2 && Math.abs(m11 + m22 + m33 - 3) < epsilon2) {
// this singularity is identity matrix so angle = 0
this.set(1, 0, 0, 0);
return this; // zero angle, arbitrary axis
}
// otherwise this singularity is angle = 180
angle = Math.PI;
const xx = (m11 + 1) / 2;
const yy = (m22 + 1) / 2;
const zz = (m33 + 1) / 2;
const xy = (m12 + m21) / 4;
const xz = (m13 + m31) / 4;
const yz = (m23 + m32) / 4;
if (xx > yy && xx > zz) {
// m11 is the largest diagonal term
if (xx < epsilon) {
x = 0;
y = 0.707106781;
z = 0.707106781;
} else {
x = Math.sqrt(xx);
y = xy / x;
z = xz / x;
}
} else if (yy > zz) {
// m22 is the largest diagonal term
if (yy < epsilon) {
x = 0.707106781;
y = 0;
z = 0.707106781;
} else {
y = Math.sqrt(yy);
x = xy / y;
z = yz / y;
}
} else {
// m33 is the largest diagonal term so base result on this
if (zz < epsilon) {
x = 0.707106781;
y = 0.707106781;
z = 0;
} else {
z = Math.sqrt(zz);
x = xz / z;
y = yz / z;
}
}
this.set(x, y, z, angle);
return this; // return 180 deg rotation
}
// as we have reached here there are no singularities so we can handle normally
let s = Math.sqrt((m32 - m23) * (m32 - m23) + (m13 - m31) * (m13 - m31) + (m21 - m12) * (m21 - m12)); // used to normalize
if (Math.abs(s) < 0.001) s = 1;
// prevent divide by zero, should not happen if matrix is orthogonal and should be
// caught by singularity test above, but I've left it in just in case
this.x = (m32 - m23) / s;
this.y = (m13 - m31) / s;
this.z = (m21 - m12) / s;
this.w = Math.acos((m11 + m22 + m33 - 1) / 2);
return this;
}
min(v) {
this.x = Math.min(this.x, v.x);
this.y = Math.min(this.y, v.y);
this.z = Math.min(this.z, v.z);
this.w = Math.min(this.w, v.w);
return this;
}
max(v) {
this.x = Math.max(this.x, v.x);
this.y = Math.max(this.y, v.y);
this.z = Math.max(this.z, v.z);
this.w = Math.max(this.w, v.w);
return this;
}
clamp(min, max) {
// assumes min < max, componentwise
this.x = Math.max(min.x, Math.min(max.x, this.x));
this.y = Math.max(min.y, Math.min(max.y, this.y));
this.z = Math.max(min.z, Math.min(max.z, this.z));
this.w = Math.max(min.w, Math.min(max.w, this.w));
return this;
}
clampScalar(minVal, maxVal) {
this.x = Math.max(minVal, Math.min(maxVal, this.x));
this.y = Math.max(minVal, Math.min(maxVal, this.y));
this.z = Math.max(minVal, Math.min(maxVal, this.z));
this.w = Math.max(minVal, Math.min(maxVal, this.w));
return this;
}
clampLength(min, max) {
const length = this.length();
return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
}
floor() {
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() {
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() {
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() {
this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z);
this.w = this.w < 0 ? Math.ceil(this.w) : Math.floor(this.w);
return this;
}
negate() {
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
this.w = -this.w;
return this;
}
dot(v) {
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
}
lengthSq() {
return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;
}
length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w);
}
manhattanLength() {
return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z) + Math.abs(this.w);
}
normalize() {
return this.divideScalar(this.length() || 1);
}
setLength(length) {
return this.normalize().multiplyScalar(length);
}
lerp(v, alpha) {
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
this.z += (v.z - this.z) * alpha;
this.w += (v.w - this.w) * alpha;
return this;
}
lerpVectors(v1, v2, alpha) {
this.x = v1.x + (v2.x - v1.x) * alpha;
this.y = v1.y + (v2.y - v1.y) * alpha;
this.z = v1.z + (v2.z - v1.z) * alpha;
this.w = v1.w + (v2.w - v1.w) * alpha;
return this;
}
equals(v) {
return v.x === this.x && v.y === this.y && v.z === this.z && v.w === this.w;
}
fromArray(array, offset = 0) {
this.x = array[offset];
this.y = array[offset + 1];
this.z = array[offset + 2];
this.w = array[offset + 3];
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this.x;
array[offset + 1] = this.y;
array[offset + 2] = this.z;
array[offset + 3] = this.w;
return array;
}
fromBufferAttribute(attribute, index, offset) {
if (offset !== undefined) {
console.warn('THREE.Vector4: offset has been removed from .fromBufferAttribute().');
}
this.x = attribute.getX(index);
this.y = attribute.getY(index);
this.z = attribute.getZ(index);
this.w = attribute.getW(index);
return this;
}
random() {
this.x = Math.random();
this.y = Math.random();
this.z = Math.random();
this.w = Math.random();
return this;
}
}
/*
In options, we can specify:
* Texture parameters for an auto-generated target texture
* depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers
*/
class WebGLRenderTarget extends EventDispatcher {
constructor(width, height, options) {
super();
Object.defineProperty(this, 'isWebGLRenderTarget', {
value: true
});
this.width = width;
this.height = height;
this.scissor = new Vector4(0, 0, width, height);
this.scissorTest = false;
this.viewport = new Vector4(0, 0, width, height);
options = options || {};
this.texture = new Texture(undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding);
this.texture.image = {};
this.texture.image.width = width;
this.texture.image.height = height;
this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true;
this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : false;
this.depthTexture = options.depthTexture !== undefined ? options.depthTexture : null;
}
setSize(width, height) {
if (this.width !== width || this.height !== height) {
this.width = width;
this.height = height;
this.texture.image.width = width;
this.texture.image.height = height;
this.dispose();
}
this.viewport.set(0, 0, width, height);
this.scissor.set(0, 0, width, height);
}
clone() {
return new this.constructor().copy(this);
}
copy(source) {
this.width = source.width;
this.height = source.height;
this.viewport.copy(source.viewport);
this.texture = source.texture.clone();
this.depthBuffer = source.depthBuffer;
this.stencilBuffer = source.stencilBuffer;
this.depthTexture = source.depthTexture;
return this;
}
dispose() {
this.dispatchEvent({
type: 'dispose'
});
}
}
class Quaternion {
constructor(x = 0, y = 0, z = 0, w = 1) {
Object.defineProperty(this, 'isQuaternion', {
value: true
});
this._x = x;
this._y = y;
this._z = z;
this._w = w;
}
static slerp(qa, qb, qm, t) {
return qm.copy(qa).slerp(qb, t);
}
static slerpFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t) {
// fuzz-free, array-based Quaternion SLERP operation
let x0 = src0[srcOffset0 + 0],
y0 = src0[srcOffset0 + 1],
z0 = src0[srcOffset0 + 2],
w0 = src0[srcOffset0 + 3];
const x1 = src1[srcOffset1 + 0],
y1 = src1[srcOffset1 + 1],
z1 = src1[srcOffset1 + 2],
w1 = src1[srcOffset1 + 3];
if (w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1) {
let s = 1 - t;
const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
dir = cos >= 0 ? 1 : -1,
sqrSin = 1 - cos * cos;
// Skip the Slerp for tiny steps to avoid numeric problems:
if (sqrSin > Number.EPSILON) {
const sin = Math.sqrt(sqrSin),
len = Math.atan2(sin, cos * dir);
s = Math.sin(s * len) / sin;
t = Math.sin(t * len) / sin;
}
const tDir = t * dir;
x0 = x0 * s + x1 * tDir;
y0 = y0 * s + y1 * tDir;
z0 = z0 * s + z1 * tDir;
w0 = w0 * s + w1 * tDir;
// Normalize in case we just did a lerp:
if (s === 1 - t) {
const f = 1 / Math.sqrt(x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0);
x0 *= f;
y0 *= f;
z0 *= f;
w0 *= f;
}
}
dst[dstOffset] = x0;
dst[dstOffset + 1] = y0;
dst[dstOffset + 2] = z0;
dst[dstOffset + 3] = w0;
}
static multiplyQuaternionsFlat(dst, dstOffset, src0, srcOffset0, src1, srcOffset1) {
const x0 = src0[srcOffset0];
const y0 = src0[srcOffset0 + 1];
const z0 = src0[srcOffset0 + 2];
const w0 = src0[srcOffset0 + 3];
const x1 = src1[srcOffset1];
const y1 = src1[srcOffset1 + 1];
const z1 = src1[srcOffset1 + 2];
const w1 = src1[srcOffset1 + 3];
dst[dstOffset] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;
dst[dstOffset + 1] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;
dst[dstOffset + 2] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;
dst[dstOffset + 3] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;
return dst;
}
get x() {
return this._x;
}
set x(value) {
this._x = value;
this._onChangeCallback();
}
get y() {
return this._y;
}
set y(value) {
this._y = value;
this._onChangeCallback();
}
get z() {
return this._z;
}
set z(value) {
this._z = value;
this._onChangeCallback();
}
get w() {
return this._w;
}
set w(value) {
this._w = value;
this._onChangeCallback();
}
set(x, y, z, w) {
this._x = x;
this._y = y;
this._z = z;
this._w = w;
this._onChangeCallback();
return this;
}
clone() {
return new this.constructor(this._x, this._y, this._z, this._w);
}
copy(quaternion) {
this._x = quaternion.x;
this._y = quaternion.y;
this._z = quaternion.z;
this._w = quaternion.w;
this._onChangeCallback();
return this;
}
setFromEuler(euler, update) {
if (!(euler && euler.isEuler)) {
throw new Error('THREE.Quaternion: .setFromEuler() now expects an Euler rotation rather than a Vector3 and order.');
}
const x = euler._x,
y = euler._y,
z = euler._z,
order = euler._order;
// http://www.mathworks.com/matlabcentral/fileexchange/
// 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/
// content/SpinCalc.m
const cos = Math.cos;
const sin = Math.sin;
const c1 = cos(x / 2);
const c2 = cos(y / 2);
const c3 = cos(z / 2);
const s1 = sin(x / 2);
const s2 = sin(y / 2);
const s3 = sin(z / 2);
switch (order) {
case 'XYZ':
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
break;
case 'YXZ':
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
break;
case 'ZXY':
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
break;
case 'ZYX':
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
break;
case 'YZX':
this._x = s1 * c2 * c3 + c1 * s2 * s3;
this._y = c1 * s2 * c3 + s1 * c2 * s3;
this._z = c1 * c2 * s3 - s1 * s2 * c3;
this._w = c1 * c2 * c3 - s1 * s2 * s3;
break;
case 'XZY':
this._x = s1 * c2 * c3 - c1 * s2 * s3;
this._y = c1 * s2 * c3 - s1 * c2 * s3;
this._z = c1 * c2 * s3 + s1 * s2 * c3;
this._w = c1 * c2 * c3 + s1 * s2 * s3;
break;
default:
console.warn('THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order);
}
if (update !== false) this._onChangeCallback();
return this;
}
setFromAxisAngle(axis, angle) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm
// assumes axis is normalized
const halfAngle = angle / 2,
s = Math.sin(halfAngle);
this._x = axis.x * s;
this._y = axis.y * s;
this._z = axis.z * s;
this._w = Math.cos(halfAngle);
this._onChangeCallback();
return this;
}
setFromRotationMatrix(m) {
// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
const te = m.elements,
m11 = te[0],
m12 = te[4],
m13 = te[8],
m21 = te[1],
m22 = te[5],
m23 = te[9],
m31 = te[2],
m32 = te[6],
m33 = te[10],
trace = m11 + m22 + m33;
if (trace > 0) {
const s = 0.5 / Math.sqrt(trace + 1.0);
this._w = 0.25 / s;
this._x = (m32 - m23) * s;
this._y = (m13 - m31) * s;
this._z = (m21 - m12) * s;
} else if (m11 > m22 && m11 > m33) {
const s = 2.0 * Math.sqrt(1.0 + m11 - m22 - m33);
this._w = (m32 - m23) / s;
this._x = 0.25 * s;
this._y = (m12 + m21) / s;
this._z = (m13 + m31) / s;
} else if (m22 > m33) {
const s = 2.0 * Math.sqrt(1.0 + m22 - m11 - m33);
this._w = (m13 - m31) / s;
this._x = (m12 + m21) / s;
this._y = 0.25 * s;
this._z = (m23 + m32) / s;
} else {
const s = 2.0 * Math.sqrt(1.0 + m33 - m11 - m22);
this._w = (m21 - m12) / s;
this._x = (m13 + m31) / s;
this._y = (m23 + m32) / s;
this._z = 0.25 * s;
}
this._onChangeCallback();
return this;
}
setFromUnitVectors(vFrom, vTo) {
// assumes direction vectors vFrom and vTo are normalized
const EPS = 0.000001;
let r = vFrom.dot(vTo) + 1;
if (r < EPS) {
r = 0;
if (Math.abs(vFrom.x) > Math.abs(vFrom.z)) {
this._x = -vFrom.y;
this._y = vFrom.x;
this._z = 0;
this._w = r;
} else {
this._x = 0;
this._y = -vFrom.z;
this._z = vFrom.y;
this._w = r;
}
} else {
// crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3
this._x = vFrom.y * vTo.z - vFrom.z * vTo.y;
this._y = vFrom.z * vTo.x - vFrom.x * vTo.z;
this._z = vFrom.x * vTo.y - vFrom.y * vTo.x;
this._w = r;
}
return this.normalize();
}
angleTo(q) {
return 2 * Math.acos(Math.abs(MathUtils.clamp(this.dot(q), -1, 1)));
}
rotateTowards(q, step) {
const angle = this.angleTo(q);
if (angle === 0) return this;
const t = Math.min(1, step / angle);
this.slerp(q, t);
return this;
}
identity() {
return this.set(0, 0, 0, 1);
}
invert() {
// quaternion is assumed to have unit length
return this.conjugate();
}
conjugate() {
this._x *= -1;
this._y *= -1;
this._z *= -1;
this._onChangeCallback();
return this;
}
dot(v) {
return this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;
}
lengthSq() {
return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;
}
length() {
return Math.sqrt(this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w);
}
normalize() {
let l = this.length();
if (l === 0) {
this._x = 0;
this._y = 0;
this._z = 0;
this._w = 1;
} else {
l = 1 / l;
this._x = this._x * l;
this._y = this._y * l;
this._z = this._z * l;
this._w = this._w * l;
}
this._onChangeCallback();
return this;
}
multiply(q, p) {
if (p !== undefined) {
console.warn('THREE.Quaternion: .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.');
return this.multiplyQuaternions(q, p);
}
return this.multiplyQuaternions(this, q);
}
premultiply(q) {
return this.multiplyQuaternions(q, this);
}
multiplyQuaternions(a, b) {
// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm
const qax = a._x,
qay = a._y,
qaz = a._z,
qaw = a._w;
const qbx = b._x,
qby = b._y,
qbz = b._z,
qbw = b._w;
this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;
this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;
this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;
this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;
this._onChangeCallback();
return this;
}
slerp(qb, t) {
if (t === 0) return this;
if (t === 1) return this.copy(qb);
const x = this._x,
y = this._y,
z = this._z,
w = this._w;
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
let cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;
if (cosHalfTheta < 0) {
this._w = -qb._w;
this._x = -qb._x;
this._y = -qb._y;
this._z = -qb._z;
cosHalfTheta = -cosHalfTheta;
} else {
this.copy(qb);
}
if (cosHalfTheta >= 1.0) {
this._w = w;
this._x = x;
this._y = y;
this._z = z;
return this;
}
const sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;
if (sqrSinHalfTheta <= Number.EPSILON) {
const s = 1 - t;
this._w = s * w + t * this._w;
this._x = s * x + t * this._x;
this._y = s * y + t * this._y;
this._z = s * z + t * this._z;
this.normalize();
this._onChangeCallback();
return this;
}
const sinHalfTheta = Math.sqrt(sqrSinHalfTheta);
const halfTheta = Math.atan2(sinHalfTheta, cosHalfTheta);
const ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta,
ratioB = Math.sin(t * halfTheta) / sinHalfTheta;
this._w = w * ratioA + this._w * ratioB;
this._x = x * ratioA + this._x * ratioB;
this._y = y * ratioA + this._y * ratioB;
this._z = z * ratioA + this._z * ratioB;
this._onChangeCallback();
return this;
}
equals(quaternion) {
return quaternion._x === this._x && quaternion._y === this._y && quaternion._z === this._z && quaternion._w === this._w;
}
fromArray(array, offset = 0) {
this._x = array[offset];
this._y = array[offset + 1];
this._z = array[offset + 2];
this._w = array[offset + 3];
this._onChangeCallback();
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this._x;
array[offset + 1] = this._y;
array[offset + 2] = this._z;
array[offset + 3] = this._w;
return array;
}
fromBufferAttribute(attribute, index) {
this._x = attribute.getX(index);
this._y = attribute.getY(index);
this._z = attribute.getZ(index);
this._w = attribute.getW(index);
return this;
}
_onChange(callback) {
this._onChangeCallback = callback;
return this;
}
_onChangeCallback() {}
}
class Vector3 {
constructor(x = 0, y = 0, z = 0) {
Object.defineProperty(this, 'isVector3', {
value: true
});
this.x = x;
this.y = y;
this.z = z;
}
set(x, y, z) {
if (z === undefined) z = this.z; // sprite.scale.set(x,y)
this.x = x;
this.y = y;
this.z = z;
return this;
}
setScalar(scalar) {
this.x = scalar;
this.y = scalar;
this.z = scalar;
return this;
}
setX(x) {
this.x = x;
return this;
}
setY(y) {
this.y = y;
return this;
}
setZ(z) {
this.z = z;
return this;
}
setComponent(index, value) {
switch (index) {
case 0:
this.x = value;
break;
case 1:
this.y = value;
break;
case 2:
this.z = value;
break;
default:
throw new Error('index is out of range: ' + index);
}
return this;
}
getComponent(index) {
switch (index) {
case 0:
return this.x;
case 1:
return this.y;
case 2:
return this.z;
default:
throw new Error('index is out of range: ' + index);
}
}
clone() {
return new this.constructor(this.x, this.y, this.z);
}
copy(v) {
this.x = v.x;
this.y = v.y;
this.z = v.z;
return this;
}
add(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.');
return this.addVectors(v, w);
}
this.x += v.x;
this.y += v.y;
this.z += v.z;
return this;
}
addScalar(s) {
this.x += s;
this.y += s;
this.z += s;
return this;
}
addVectors(a, b) {
this.x = a.x + b.x;
this.y = a.y + b.y;
this.z = a.z + b.z;
return this;
}
addScaledVector(v, s) {
this.x += v.x * s;
this.y += v.y * s;
this.z += v.z * s;
return this;
}
sub(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.');
return this.subVectors(v, w);
}
this.x -= v.x;
this.y -= v.y;
this.z -= v.z;
return this;
}
subScalar(s) {
this.x -= s;
this.y -= s;
this.z -= s;
return this;
}
subVectors(a, b) {
this.x = a.x - b.x;
this.y = a.y - b.y;
this.z = a.z - b.z;
return this;
}
multiply(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.');
return this.multiplyVectors(v, w);
}
this.x *= v.x;
this.y *= v.y;
this.z *= v.z;
return this;
}
multiplyScalar(scalar) {
this.x *= scalar;
this.y *= scalar;
this.z *= scalar;
return this;
}
multiplyVectors(a, b) {
this.x = a.x * b.x;
this.y = a.y * b.y;
this.z = a.z * b.z;
return this;
}
applyEuler(euler) {
if (!(euler && euler.isEuler)) {
console.error('THREE.Vector3: .applyEuler() now expects an Euler rotation rather than a Vector3 and order.');
}
return this.applyQuaternion(_quaternion.setFromEuler(euler));
}
applyAxisAngle(axis, angle) {
return this.applyQuaternion(_quaternion.setFromAxisAngle(axis, angle));
}
applyMatrix3(m) {
const x = this.x,
y = this.y,
z = this.z;
const e = m.elements;
this.x = e[0] * x + e[3] * y + e[6] * z;
this.y = e[1] * x + e[4] * y + e[7] * z;
this.z = e[2] * x + e[5] * y + e[8] * z;
return this;
}
applyNormalMatrix(m) {
return this.applyMatrix3(m).normalize();
}
applyMatrix4(m) {
const x = this.x,
y = this.y,
z = this.z;
const e = m.elements;
const w = 1 / (e[3] * x + e[7] * y + e[11] * z + e[15]);
this.x = (e[0] * x + e[4] * y + e[8] * z + e[12]) * w;
this.y = (e[1] * x + e[5] * y + e[9] * z + e[13]) * w;
this.z = (e[2] * x + e[6] * y + e[10] * z + e[14]) * w;
return this;
}
applyQuaternion(q) {
const x = this.x,
y = this.y,
z = this.z;
const qx = q.x,
qy = q.y,
qz = q.z,
qw = q.w;
// calculate quat * vector
const ix = qw * x + qy * z - qz * y;
const iy = qw * y + qz * x - qx * z;
const iz = qw * z + qx * y - qy * x;
const iw = -qx * x - qy * y - qz * z;
// calculate result * inverse quat
this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return this;
}
project(camera) {
return this.applyMatrix4(camera.matrixWorldInverse).applyMatrix4(camera.projectionMatrix);
}
unproject(camera) {
return this.applyMatrix4(camera.projectionMatrixInverse).applyMatrix4(camera.matrixWorld);
}
transformDirection(m) {
// input: THREE.Matrix4 affine matrix
// vector interpreted as a direction
const x = this.x,
y = this.y,
z = this.z;
const e = m.elements;
this.x = e[0] * x + e[4] * y + e[8] * z;
this.y = e[1] * x + e[5] * y + e[9] * z;
this.z = e[2] * x + e[6] * y + e[10] * z;
return this.normalize();
}
divide(v) {
this.x /= v.x;
this.y /= v.y;
this.z /= v.z;
return this;
}
divideScalar(scalar) {
return this.multiplyScalar(1 / scalar);
}
min(v) {
this.x = Math.min(this.x, v.x);
this.y = Math.min(this.y, v.y);
this.z = Math.min(this.z, v.z);
return this;
}
max(v) {
this.x = Math.max(this.x, v.x);
this.y = Math.max(this.y, v.y);
this.z = Math.max(this.z, v.z);
return this;
}
clamp(min, max) {
// assumes min < max, componentwise
this.x = Math.max(min.x, Math.min(max.x, this.x));
this.y = Math.max(min.y, Math.min(max.y, this.y));
this.z = Math.max(min.z, Math.min(max.z, this.z));
return this;
}
clampScalar(minVal, maxVal) {
this.x = Math.max(minVal, Math.min(maxVal, this.x));
this.y = Math.max(minVal, Math.min(maxVal, this.y));
this.z = Math.max(minVal, Math.min(maxVal, this.z));
return this;
}
clampLength(min, max) {
const length = this.length();
return this.divideScalar(length || 1).multiplyScalar(Math.max(min, Math.min(max, length)));
}
floor() {
this.x = Math.floor(this.x);
this.y = Math.floor(this.y);
this.z = Math.floor(this.z);
return this;
}
ceil() {
this.x = Math.ceil(this.x);
this.y = Math.ceil(this.y);
this.z = Math.ceil(this.z);
return this;
}
round() {
this.x = Math.round(this.x);
this.y = Math.round(this.y);
this.z = Math.round(this.z);
return this;
}
roundToZero() {
this.x = this.x < 0 ? Math.ceil(this.x) : Math.floor(this.x);
this.y = this.y < 0 ? Math.ceil(this.y) : Math.floor(this.y);
this.z = this.z < 0 ? Math.ceil(this.z) : Math.floor(this.z);
return this;
}
negate() {
this.x = -this.x;
this.y = -this.y;
this.z = -this.z;
return this;
}
dot(v) {
return this.x * v.x + this.y * v.y + this.z * v.z;
}
// TODO lengthSquared?
lengthSq() {
return this.x * this.x + this.y * this.y + this.z * this.z;
}
length() {
return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z);
}
manhattanLength() {
return Math.abs(this.x) + Math.abs(this.y) + Math.abs(this.z);
}
normalize() {
return this.divideScalar(this.length() || 1);
}
setLength(length) {
return this.normalize().multiplyScalar(length);
}
lerp(v, alpha) {
this.x += (v.x - this.x) * alpha;
this.y += (v.y - this.y) * alpha;
this.z += (v.z - this.z) * alpha;
return this;
}
lerpVectors(v1, v2, alpha) {
this.x = v1.x + (v2.x - v1.x) * alpha;
this.y = v1.y + (v2.y - v1.y) * alpha;
this.z = v1.z + (v2.z - v1.z) * alpha;
return this;
}
cross(v, w) {
if (w !== undefined) {
console.warn('THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.');
return this.crossVectors(v, w);
}
return this.crossVectors(this, v);
}
crossVectors(a, b) {
const ax = a.x,
ay = a.y,
az = a.z;
const bx = b.x,
by = b.y,
bz = b.z;
this.x = ay * bz - az * by;
this.y = az * bx - ax * bz;
this.z = ax * by - ay * bx;
return this;
}
projectOnVector(v) {
const denominator = v.lengthSq();
if (denominator === 0) return this.set(0, 0, 0);
const scalar = v.dot(this) / denominator;
return this.copy(v).multiplyScalar(scalar);
}
projectOnPlane(planeNormal) {
_vector.copy(this).projectOnVector(planeNormal);
return this.sub(_vector);
}
reflect(normal) {
// reflect incident vector off plane orthogonal to normal
// normal is assumed to have unit length
return this.sub(_vector.copy(normal).multiplyScalar(2 * this.dot(normal)));
}
angleTo(v) {
const denominator = Math.sqrt(this.lengthSq() * v.lengthSq());
if (denominator === 0) return Math.PI / 2;
const theta = this.dot(v) / denominator;
// clamp, to handle numerical problems
return Math.acos(MathUtils.clamp(theta, -1, 1));
}
distanceTo(v) {
return Math.sqrt(this.distanceToSquared(v));
}
distanceToSquared(v) {
const dx = this.x - v.x,
dy = this.y - v.y,
dz = this.z - v.z;
return dx * dx + dy * dy + dz * dz;
}
manhattanDistanceTo(v) {
return Math.abs(this.x - v.x) + Math.abs(this.y - v.y) + Math.abs(this.z - v.z);
}
setFromSpherical(s) {
return this.setFromSphericalCoords(s.radius, s.phi, s.theta);
}
setFromSphericalCoords(radius, phi, theta) {
const sinPhiRadius = Math.sin(phi) * radius;
this.x = sinPhiRadius * Math.sin(theta);
this.y = Math.cos(phi) * radius;
this.z = sinPhiRadius * Math.cos(theta);
return this;
}
setFromCylindrical(c) {
return this.setFromCylindricalCoords(c.radius, c.theta, c.y);
}
setFromCylindricalCoords(radius, theta, y) {
this.x = radius * Math.sin(theta);
this.y = y;
this.z = radius * Math.cos(theta);
return this;
}
setFromMatrixPosition(m) {
const e = m.elements;
this.x = e[12];
this.y = e[13];
this.z = e[14];
return this;
}
setFromMatrixScale(m) {
const sx = this.setFromMatrixColumn(m, 0).length();
const sy = this.setFromMatrixColumn(m, 1).length();
const sz = this.setFromMatrixColumn(m, 2).length();
this.x = sx;
this.y = sy;
this.z = sz;
return this;
}
setFromMatrixColumn(m, index) {
return this.fromArray(m.elements, index * 4);
}
setFromMatrix3Column(m, index) {
return this.fromArray(m.elements, index * 3);
}
equals(v) {
return v.x === this.x && v.y === this.y && v.z === this.z;
}
fromArray(array, offset = 0) {
this.x = array[offset];
this.y = array[offset + 1];
this.z = array[offset + 2];
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this.x;
array[offset + 1] = this.y;
array[offset + 2] = this.z;
return array;
}
fromBufferAttribute(attribute, index, offset) {
if (offset !== undefined) {
console.warn('THREE.Vector3: offset has been removed from .fromBufferAttribute().');
}
this.x = attribute.getX(index);
this.y = attribute.getY(index);
this.z = attribute.getZ(index);
return this;
}
random() {
this.x = Math.random();
this.y = Math.random();
this.z = Math.random();
return this;
}
}
const _vector = /*@__PURE__*/new Vector3();
const _quaternion = /*@__PURE__*/new Quaternion();
class Box3 {
constructor(min, max) {
Object.defineProperty(this, 'isBox3', {
value: true
});
this.min = min !== undefined ? min : new Vector3(+Infinity, +Infinity, +Infinity);
this.max = max !== undefined ? max : new Vector3(-Infinity, -Infinity, -Infinity);
}
set(min, max) {
this.min.copy(min);
this.max.copy(max);
return this;
}
setFromArray(array) {
let minX = +Infinity;
let minY = +Infinity;
let minZ = +Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
let maxZ = -Infinity;
for (let i = 0, l = array.length; i < l; i += 3) {
const x = array[i];
const y = array[i + 1];
const z = array[i + 2];
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
if (z > maxZ) maxZ = z;
}
this.min.set(minX, minY, minZ);
this.max.set(maxX, maxY, maxZ);
return this;
}
setFromBufferAttribute(attribute) {
let minX = +Infinity;
let minY = +Infinity;
let minZ = +Infinity;
let maxX = -Infinity;
let maxY = -Infinity;
let maxZ = -Infinity;
for (let i = 0, l = attribute.count; i < l; i++) {
const x = attribute.getX(i);
const y = attribute.getY(i);
const z = attribute.getZ(i);
if (x < minX) minX = x;
if (y < minY) minY = y;
if (z < minZ) minZ = z;
if (x > maxX) maxX = x;
if (y > maxY) maxY = y;
if (z > maxZ) maxZ = z;
}
this.min.set(minX, minY, minZ);
this.max.set(maxX, maxY, maxZ);
return this;
}
setFromPoints(points) {
this.makeEmpty();
for (let i = 0, il = points.length; i < il; i++) {
this.expandByPoint(points[i]);
}
return this;
}
setFromCenterAndSize(center, size) {
const halfSize = _vector$1.copy(size).multiplyScalar(0.5);
this.min.copy(center).sub(halfSize);
this.max.copy(center).add(halfSize);
return this;
}
setFromObject(object) {
this.makeEmpty();
return this.expandByObject(object);
}
clone() {
return new this.constructor().copy(this);
}
copy(box) {
this.min.copy(box.min);
this.max.copy(box.max);
return this;
}
makeEmpty() {
this.min.x = this.min.y = this.min.z = +Infinity;
this.max.x = this.max.y = this.max.z = -Infinity;
return this;
}
isEmpty() {
// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes
return this.max.x < this.min.x || this.max.y < this.min.y || this.max.z < this.min.z;
}
getCenter(target) {
if (target === undefined) {
console.warn('THREE.Box3: .getCenter() target is now required');
target = new Vector3();
}
return this.isEmpty() ? target.set(0, 0, 0) : target.addVectors(this.min, this.max).multiplyScalar(0.5);
}
getSize(target) {
if (target === undefined) {
console.warn('THREE.Box3: .getSize() target is now required');
target = new Vector3();
}
return this.isEmpty() ? target.set(0, 0, 0) : target.subVectors(this.max, this.min);
}
expandByPoint(point) {
this.min.min(point);
this.max.max(point);
return this;
}
expandByVector(vector) {
this.min.sub(vector);
this.max.add(vector);
return this;
}
expandByScalar(scalar) {
this.min.addScalar(-scalar);
this.max.addScalar(scalar);
return this;
}
expandByObject(object) {
// Computes the world-axis-aligned bounding box of an object (including its children),
// accounting for both the object's, and children's, world transforms
object.updateWorldMatrix(false, false);
const geometry = object.geometry;
if (geometry !== undefined) {
if (geometry.boundingBox === null) {
geometry.computeBoundingBox();
}
_box.copy(geometry.boundingBox);
_box.applyMatrix4(object.matrixWorld);
this.union(_box);
}
const children = object.children;
for (let i = 0, l = children.length; i < l; i++) {
this.expandByObject(children[i]);
}
return this;
}
containsPoint(point) {
return point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y || point.z < this.min.z || point.z > this.max.z ? false : true;
}
containsBox(box) {
return this.min.x <= box.min.x && box.max.x <= this.max.x && this.min.y <= box.min.y && box.max.y <= this.max.y && this.min.z <= box.min.z && box.max.z <= this.max.z;
}
getParameter(point, target) {
// This can potentially have a divide by zero if the box
// has a size dimension of 0.
if (target === undefined) {
console.warn('THREE.Box3: .getParameter() target is now required');
target = new Vector3();
}
return target.set((point.x - this.min.x) / (this.max.x - this.min.x), (point.y - this.min.y) / (this.max.y - this.min.y), (point.z - this.min.z) / (this.max.z - this.min.z));
}
intersectsBox(box) {
// using 6 splitting planes to rule out intersections.
return box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y || box.max.z < this.min.z || box.min.z > this.max.z ? false : true;
}
intersectsSphere(sphere) {
// Find the point on the AABB closest to the sphere center.
this.clampPoint(sphere.center, _vector$1);
// If that point is inside the sphere, the AABB and sphere intersect.
return _vector$1.distanceToSquared(sphere.center) <= sphere.radius * sphere.radius;
}
intersectsPlane(plane) {
// We compute the minimum and maximum dot product values. If those values
// are on the same side (back or front) of the plane, then there is no intersection.
let min, max;
if (plane.normal.x > 0) {
min = plane.normal.x * this.min.x;
max = plane.normal.x * this.max.x;
} else {
min = plane.normal.x * this.max.x;
max = plane.normal.x * this.min.x;
}
if (plane.normal.y > 0) {
min += plane.normal.y * this.min.y;
max += plane.normal.y * this.max.y;
} else {
min += plane.normal.y * this.max.y;
max += plane.normal.y * this.min.y;
}
if (plane.normal.z > 0) {
min += plane.normal.z * this.min.z;
max += plane.normal.z * this.max.z;
} else {
min += plane.normal.z * this.max.z;
max += plane.normal.z * this.min.z;
}
return min <= -plane.constant && max >= -plane.constant;
}
intersectsTriangle(triangle) {
if (this.isEmpty()) {
return false;
}
// compute box center and extents
this.getCenter(_center);
_extents.subVectors(this.max, _center);
// translate triangle to aabb origin
_v0.subVectors(triangle.a, _center);
_v1.subVectors(triangle.b, _center);
_v2.subVectors(triangle.c, _center);
// compute edge vectors for triangle
_f0.subVectors(_v1, _v0);
_f1.subVectors(_v2, _v1);
_f2.subVectors(_v0, _v2);
// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
let axes = [0, -_f0.z, _f0.y, 0, -_f1.z, _f1.y, 0, -_f2.z, _f2.y, _f0.z, 0, -_f0.x, _f1.z, 0, -_f1.x, _f2.z, 0, -_f2.x, -_f0.y, _f0.x, 0, -_f1.y, _f1.x, 0, -_f2.y, _f2.x, 0];
if (!satForAxes(axes, _v0, _v1, _v2, _extents)) {
return false;
}
// test 3 face normals from the aabb
axes = [1, 0, 0, 0, 1, 0, 0, 0, 1];
if (!satForAxes(axes, _v0, _v1, _v2, _extents)) {
return false;
}
// finally testing the face normal of the triangle
// use already existing triangle edge vectors here
_triangleNormal.crossVectors(_f0, _f1);
axes = [_triangleNormal.x, _triangleNormal.y, _triangleNormal.z];
return satForAxes(axes, _v0, _v1, _v2, _extents);
}
clampPoint(point, target) {
if (target === undefined) {
console.warn('THREE.Box3: .clampPoint() target is now required');
target = new Vector3();
}
return target.copy(point).clamp(this.min, this.max);
}
distanceToPoint(point) {
const clampedPoint = _vector$1.copy(point).clamp(this.min, this.max);
return clampedPoint.sub(point).length();
}
getBoundingSphere(target) {
if (target === undefined) {
console.error('THREE.Box3: .getBoundingSphere() target is now required');
//target = new Sphere(); // removed to avoid cyclic dependency
}
this.getCenter(target.center);
target.radius = this.getSize(_vector$1).length() * 0.5;
return target;
}
intersect(box) {
this.min.max(box.min);
this.max.min(box.max);
// ensure that if there is no overlap, the result is fully empty, not slightly empty with non-inf/+inf values that will cause subsequence intersects to erroneously return valid values.
if (this.isEmpty()) this.makeEmpty();
return this;
}
union(box) {
this.min.min(box.min);
this.max.max(box.max);
return this;
}
applyMatrix4(matrix) {
// transform of empty box is an empty box.
if (this.isEmpty()) return this;
// NOTE: I am using a binary pattern to specify all 2^3 combinations below
_points[0].set(this.min.x, this.min.y, this.min.z).applyMatrix4(matrix); // 000
_points[1].set(this.min.x, this.min.y, this.max.z).applyMatrix4(matrix); // 001
_points[2].set(this.min.x, this.max.y, this.min.z).applyMatrix4(matrix); // 010
_points[3].set(this.min.x, this.max.y, this.max.z).applyMatrix4(matrix); // 011
_points[4].set(this.max.x, this.min.y, this.min.z).applyMatrix4(matrix); // 100
_points[5].set(this.max.x, this.min.y, this.max.z).applyMatrix4(matrix); // 101
_points[6].set(this.max.x, this.max.y, this.min.z).applyMatrix4(matrix); // 110
_points[7].set(this.max.x, this.max.y, this.max.z).applyMatrix4(matrix); // 111
this.setFromPoints(_points);
return this;
}
translate(offset) {
this.min.add(offset);
this.max.add(offset);
return this;
}
equals(box) {
return box.min.equals(this.min) && box.max.equals(this.max);
}
}
function satForAxes(axes, v0, v1, v2, extents) {
for (let i = 0, j = axes.length - 3; i <= j; i += 3) {
_testAxis.fromArray(axes, i);
// project the aabb onto the seperating axis
const r = extents.x * Math.abs(_testAxis.x) + extents.y * Math.abs(_testAxis.y) + extents.z * Math.abs(_testAxis.z);
// project all 3 vertices of the triangle onto the seperating axis
const p0 = v0.dot(_testAxis);
const p1 = v1.dot(_testAxis);
const p2 = v2.dot(_testAxis);
// actual test, basically see if either of the most extreme of the triangle points intersects r
if (Math.max(-Math.max(p0, p1, p2), Math.min(p0, p1, p2)) > r) {
// points of the projected triangle are outside the projected half-length of the aabb
// the axis is seperating and we can exit
return false;
}
}
return true;
}
const _points = [/*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3(), /*@__PURE__*/new Vector3()];
const _vector$1 = /*@__PURE__*/new Vector3();
const _box = /*@__PURE__*/new Box3();
// triangle centered vertices
const _v0 = /*@__PURE__*/new Vector3();
const _v1 = /*@__PURE__*/new Vector3();
const _v2 = /*@__PURE__*/new Vector3();
// triangle edge vectors
const _f0 = /*@__PURE__*/new Vector3();
const _f1 = /*@__PURE__*/new Vector3();
const _f2 = /*@__PURE__*/new Vector3();
const _center = /*@__PURE__*/new Vector3();
const _extents = /*@__PURE__*/new Vector3();
const _triangleNormal = /*@__PURE__*/new Vector3();
const _testAxis = /*@__PURE__*/new Vector3();
const _box$1 = /*@__PURE__*/new Box3();
class Sphere {
constructor(center, radius) {
this.center = center !== undefined ? center : new Vector3();
this.radius = radius !== undefined ? radius : -1;
}
set(center, radius) {
this.center.copy(center);
this.radius = radius;
return this;
}
setFromPoints(points, optionalCenter) {
const center = this.center;
if (optionalCenter !== undefined) {
center.copy(optionalCenter);
} else {
_box$1.setFromPoints(points).getCenter(center);
}
let maxRadiusSq = 0;
for (let i = 0, il = points.length; i < il; i++) {
maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(points[i]));
}
this.radius = Math.sqrt(maxRadiusSq);
return this;
}
clone() {
return new this.constructor().copy(this);
}
copy(sphere) {
this.center.copy(sphere.center);
this.radius = sphere.radius;
return this;
}
isEmpty() {
return this.radius < 0;
}
makeEmpty() {
this.center.set(0, 0, 0);
this.radius = -1;
return this;
}
containsPoint(point) {
return point.distanceToSquared(this.center) <= this.radius * this.radius;
}
distanceToPoint(point) {
return point.distanceTo(this.center) - this.radius;
}
intersectsSphere(sphere) {
const radiusSum = this.radius + sphere.radius;
return sphere.center.distanceToSquared(this.center) <= radiusSum * radiusSum;
}
intersectsBox(box) {
return box.intersectsSphere(this);
}
intersectsPlane(plane) {
return Math.abs(plane.distanceToPoint(this.center)) <= this.radius;
}
clampPoint(point, target) {
const deltaLengthSq = this.center.distanceToSquared(point);
if (target === undefined) {
console.warn('THREE.Sphere: .clampPoint() target is now required');
target = new Vector3();
}
target.copy(point);
if (deltaLengthSq > this.radius * this.radius) {
target.sub(this.center).normalize();
target.multiplyScalar(this.radius).add(this.center);
}
return target;
}
getBoundingBox(target) {
if (target === undefined) {
console.warn('THREE.Sphere: .getBoundingBox() target is now required');
target = new Box3();
}
if (this.isEmpty()) {
// Empty sphere produces empty bounding box
target.makeEmpty();
return target;
}
target.set(this.center, this.center);
target.expandByScalar(this.radius);
return target;
}
applyMatrix4(matrix) {
this.center.applyMatrix4(matrix);
this.radius = this.radius * matrix.getMaxScaleOnAxis();
return this;
}
translate(offset) {
this.center.add(offset);
return this;
}
equals(sphere) {
return sphere.center.equals(this.center) && sphere.radius === this.radius;
}
}
const _vector$2 = /*@__PURE__*/new Vector3();
const _segCenter = /*@__PURE__*/new Vector3();
const _segDir = /*@__PURE__*/new Vector3();
const _diff = /*@__PURE__*/new Vector3();
const _edge1 = /*@__PURE__*/new Vector3();
const _edge2 = /*@__PURE__*/new Vector3();
const _normal = /*@__PURE__*/new Vector3();
class Ray {
constructor(origin, direction) {
this.origin = origin !== undefined ? origin : new Vector3();
this.direction = direction !== undefined ? direction : new Vector3(0, 0, -1);
}
set(origin, direction) {
this.origin.copy(origin);
this.direction.copy(direction);
return this;
}
clone() {
return new this.constructor().copy(this);
}
copy(ray) {
this.origin.copy(ray.origin);
this.direction.copy(ray.direction);
return this;
}
at(t, target) {
if (target === undefined) {
console.warn('THREE.Ray: .at() target is now required');
target = new Vector3();
}
return target.copy(this.direction).multiplyScalar(t).add(this.origin);
}
lookAt(v) {
this.direction.copy(v).sub(this.origin).normalize();
return this;
}
recast(t) {
this.origin.copy(this.at(t, _vector$2));
return this;
}
closestPointToPoint(point, target) {
if (target === undefined) {
console.warn('THREE.Ray: .closestPointToPoint() target is now required');
target = new Vector3();
}
target.subVectors(point, this.origin);
const directionDistance = target.dot(this.direction);
if (directionDistance < 0) {
return target.copy(this.origin);
}
return target.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
}
distanceToPoint(point) {
return Math.sqrt(this.distanceSqToPoint(point));
}
distanceSqToPoint(point) {
const directionDistance = _vector$2.subVectors(point, this.origin).dot(this.direction);
// point behind the ray
if (directionDistance < 0) {
return this.origin.distanceToSquared(point);
}
_vector$2.copy(this.direction).multiplyScalar(directionDistance).add(this.origin);
return _vector$2.distanceToSquared(point);
}
distanceSqToSegment(v0, v1, optionalPointOnRay, optionalPointOnSegment) {
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
// It returns the min distance between the ray and the segment
// defined by v0 and v1
// It can also set two optional targets :
// - The closest point on the ray
// - The closest point on the segment
_segCenter.copy(v0).add(v1).multiplyScalar(0.5);
_segDir.copy(v1).sub(v0).normalize();
_diff.copy(this.origin).sub(_segCenter);
const segExtent = v0.distanceTo(v1) * 0.5;
const a01 = -this.direction.dot(_segDir);
const b0 = _diff.dot(this.direction);
const b1 = -_diff.dot(_segDir);
const c = _diff.lengthSq();
const det = Math.abs(1 - a01 * a01);
let s0, s1, sqrDist, extDet;
if (det > 0) {
// The ray and segment are not parallel.
s0 = a01 * b1 - b0;
s1 = a01 * b0 - b1;
extDet = segExtent * det;
if (s0 >= 0) {
if (s1 >= -extDet) {
if (s1 <= extDet) {
// region 0
// Minimum at interior points of ray and segment.
const invDet = 1 / det;
s0 *= invDet;
s1 *= invDet;
sqrDist = s0 * (s0 + a01 * s1 + 2 * b0) + s1 * (a01 * s0 + s1 + 2 * b1) + c;
} else {
// region 1
s1 = segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
} else {
// region 5
s1 = -segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
} else {
if (s1 <= -extDet) {
// region 4
s0 = Math.max(0, -(-a01 * segExtent + b0));
s1 = s0 > 0 ? -segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
} else if (s1 <= extDet) {
// region 3
s0 = 0;
s1 = Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = s1 * (s1 + 2 * b1) + c;
} else {
// region 2
s0 = Math.max(0, -(a01 * segExtent + b0));
s1 = s0 > 0 ? segExtent : Math.min(Math.max(-segExtent, -b1), segExtent);
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
}
} else {
// Ray and segment are parallel.
s1 = a01 > 0 ? -segExtent : segExtent;
s0 = Math.max(0, -(a01 * s1 + b0));
sqrDist = -s0 * s0 + s1 * (s1 + 2 * b1) + c;
}
if (optionalPointOnRay) {
optionalPointOnRay.copy(this.direction).multiplyScalar(s0).add(this.origin);
}
if (optionalPointOnSegment) {
optionalPointOnSegment.copy(_segDir).multiplyScalar(s1).add(_segCenter);
}
return sqrDist;
}
intersectSphere(sphere, target) {
_vector$2.subVectors(sphere.center, this.origin);
const tca = _vector$2.dot(this.direction);
const d2 = _vector$2.dot(_vector$2) - tca * tca;
const radius2 = sphere.radius * sphere.radius;
if (d2 > radius2) return null;
const thc = Math.sqrt(radius2 - d2);
// t0 = first intersect point - entrance on front of sphere
const t0 = tca - thc;
// t1 = second intersect point - exit point on back of sphere
const t1 = tca + thc;
// test to see if both t0 and t1 are behind the ray - if so, return null
if (t0 < 0 && t1 < 0) return null;
// test to see if t0 is behind the ray:
// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
// in order to always return an intersect point that is in front of the ray.
if (t0 < 0) return this.at(t1, target);
// else t0 is in front of the ray, so return the first collision point scaled by t0
return this.at(t0, target);
}
intersectsSphere(sphere) {
return this.distanceSqToPoint(sphere.center) <= sphere.radius * sphere.radius;
}
distanceToPlane(plane) {
const denominator = plane.normal.dot(this.direction);
if (denominator === 0) {
// line is coplanar, return origin
if (plane.distanceToPoint(this.origin) === 0) {
return 0;
}
// Null is preferable to undefined since undefined means.... it is undefined
return null;
}
const t = -(this.origin.dot(plane.normal) + plane.constant) / denominator;
// Return if the ray never intersects the plane
return t >= 0 ? t : null;
}
intersectPlane(plane, target) {
const t = this.distanceToPlane(plane);
if (t === null) {
return null;
}
return this.at(t, target);
}
intersectsPlane(plane) {
// check if the ray lies on the plane first
const distToPoint = plane.distanceToPoint(this.origin);
if (distToPoint === 0) {
return true;
}
const denominator = plane.normal.dot(this.direction);
if (denominator * distToPoint < 0) {
return true;
}
// ray origin is behind the plane (and is pointing behind it)
return false;
}
intersectBox(box, target) {
let tmin, tmax, tymin, tymax, tzmin, tzmax;
const invdirx = 1 / this.direction.x,
invdiry = 1 / this.direction.y,
invdirz = 1 / this.direction.z;
const origin = this.origin;
if (invdirx >= 0) {
tmin = (box.min.x - origin.x) * invdirx;
tmax = (box.max.x - origin.x) * invdirx;
} else {
tmin = (box.max.x - origin.x) * invdirx;
tmax = (box.min.x - origin.x) * invdirx;
}
if (invdiry >= 0) {
tymin = (box.min.y - origin.y) * invdiry;
tymax = (box.max.y - origin.y) * invdiry;
} else {
tymin = (box.max.y - origin.y) * invdiry;
tymax = (box.min.y - origin.y) * invdiry;
}
if (tmin > tymax || tymin > tmax) return null;
// These lines also handle the case where tmin or tmax is NaN
// (result of 0 * Infinity). x !== x returns true if x is NaN
if (tymin > tmin || tmin !== tmin) tmin = tymin;
if (tymax < tmax || tmax !== tmax) tmax = tymax;
if (invdirz >= 0) {
tzmin = (box.min.z - origin.z) * invdirz;
tzmax = (box.max.z - origin.z) * invdirz;
} else {
tzmin = (box.max.z - origin.z) * invdirz;
tzmax = (box.min.z - origin.z) * invdirz;
}
if (tmin > tzmax || tzmin > tmax) return null;
if (tzmin > tmin || tmin !== tmin) tmin = tzmin;
if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
//return point closest to the ray (positive side)
if (tmax < 0) return null;
return this.at(tmin >= 0 ? tmin : tmax, target);
}
intersectsBox(box) {
return this.intersectBox(box, _vector$2) !== null;
}
intersectTriangle(a, b, c, backfaceCulling, target) {
// Compute the offset origin, edges, and normal.
// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
_edge1.subVectors(b, a);
_edge2.subVectors(c, a);
_normal.crossVectors(_edge1, _edge2);
// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
let DdN = this.direction.dot(_normal);
let sign;
if (DdN > 0) {
if (backfaceCulling) return null;
sign = 1;
} else if (DdN < 0) {
sign = -1;
DdN = -DdN;
} else {
return null;
}
_diff.subVectors(this.origin, a);
const DdQxE2 = sign * this.direction.dot(_edge2.crossVectors(_diff, _edge2));
// b1 < 0, no intersection
if (DdQxE2 < 0) {
return null;
}
const DdE1xQ = sign * this.direction.dot(_edge1.cross(_diff));
// b2 < 0, no intersection
if (DdE1xQ < 0) {
return null;
}
// b1+b2 > 1, no intersection
if (DdQxE2 + DdE1xQ > DdN) {
return null;
}
// Line intersects triangle, check if ray does.
const QdN = -sign * _diff.dot(_normal);
// t < 0, no intersection
if (QdN < 0) {
return null;
}
// Ray intersects triangle.
return this.at(QdN / DdN, target);
}
applyMatrix4(matrix4) {
this.origin.applyMatrix4(matrix4);
this.direction.transformDirection(matrix4);
return this;
}
equals(ray) {
return ray.origin.equals(this.origin) && ray.direction.equals(this.direction);
}
}
class Matrix4 {
constructor() {
Object.defineProperty(this, 'isMatrix4', {
value: true
});
this.elements = [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
if (arguments.length > 0) {
console.error('THREE.Matrix4: the constructor no longer reads arguments. use .set() instead.');
}
}
set(n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44) {
const te = this.elements;
te[0] = n11;
te[4] = n12;
te[8] = n13;
te[12] = n14;
te[1] = n21;
te[5] = n22;
te[9] = n23;
te[13] = n24;
te[2] = n31;
te[6] = n32;
te[10] = n33;
te[14] = n34;
te[3] = n41;
te[7] = n42;
te[11] = n43;
te[15] = n44;
return this;
}
identity() {
this.set(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
return this;
}
clone() {
return new Matrix4().fromArray(this.elements);
}
copy(m) {
const te = this.elements;
const me = m.elements;
te[0] = me[0];
te[1] = me[1];
te[2] = me[2];
te[3] = me[3];
te[4] = me[4];
te[5] = me[5];
te[6] = me[6];
te[7] = me[7];
te[8] = me[8];
te[9] = me[9];
te[10] = me[10];
te[11] = me[11];
te[12] = me[12];
te[13] = me[13];
te[14] = me[14];
te[15] = me[15];
return this;
}
copyPosition(m) {
const te = this.elements,
me = m.elements;
te[12] = me[12];
te[13] = me[13];
te[14] = me[14];
return this;
}
setFromMatrix3(m) {
const me = m.elements;
this.set(me[0], me[3], me[6], 0, me[1], me[4], me[7], 0, me[2], me[5], me[8], 0, 0, 0, 0, 1);
return this;
}
extractBasis(xAxis, yAxis, zAxis) {
xAxis.setFromMatrixColumn(this, 0);
yAxis.setFromMatrixColumn(this, 1);
zAxis.setFromMatrixColumn(this, 2);
return this;
}
makeBasis(xAxis, yAxis, zAxis) {
this.set(xAxis.x, yAxis.x, zAxis.x, 0, xAxis.y, yAxis.y, zAxis.y, 0, xAxis.z, yAxis.z, zAxis.z, 0, 0, 0, 0, 1);
return this;
}
extractRotation(m) {
// this method does not support reflection matrices
const te = this.elements;
const me = m.elements;
const scaleX = 1 / _v1$1.setFromMatrixColumn(m, 0).length();
const scaleY = 1 / _v1$1.setFromMatrixColumn(m, 1).length();
const scaleZ = 1 / _v1$1.setFromMatrixColumn(m, 2).length();
te[0] = me[0] * scaleX;
te[1] = me[1] * scaleX;
te[2] = me[2] * scaleX;
te[3] = 0;
te[4] = me[4] * scaleY;
te[5] = me[5] * scaleY;
te[6] = me[6] * scaleY;
te[7] = 0;
te[8] = me[8] * scaleZ;
te[9] = me[9] * scaleZ;
te[10] = me[10] * scaleZ;
te[11] = 0;
te[12] = 0;
te[13] = 0;
te[14] = 0;
te[15] = 1;
return this;
}
makeRotationFromEuler(euler) {
if (!(euler && euler.isEuler)) {
console.error('THREE.Matrix4: .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order.');
}
const te = this.elements;
const x = euler.x,
y = euler.y,
z = euler.z;
const a = Math.cos(x),
b = Math.sin(x);
const c = Math.cos(y),
d = Math.sin(y);
const e = Math.cos(z),
f = Math.sin(z);
if (euler.order === 'XYZ') {
const ae = a * e,
af = a * f,
be = b * e,
bf = b * f;
te[0] = c * e;
te[4] = -c * f;
te[8] = d;
te[1] = af + be * d;
te[5] = ae - bf * d;
te[9] = -b * c;
te[2] = bf - ae * d;
te[6] = be + af * d;
te[10] = a * c;
} else if (euler.order === 'YXZ') {
const ce = c * e,
cf = c * f,
de = d * e,
df = d * f;
te[0] = ce + df * b;
te[4] = de * b - cf;
te[8] = a * d;
te[1] = a * f;
te[5] = a * e;
te[9] = -b;
te[2] = cf * b - de;
te[6] = df + ce * b;
te[10] = a * c;
} else if (euler.order === 'ZXY') {
const ce = c * e,
cf = c * f,
de = d * e,
df = d * f;
te[0] = ce - df * b;
te[4] = -a * f;
te[8] = de + cf * b;
te[1] = cf + de * b;
te[5] = a * e;
te[9] = df - ce * b;
te[2] = -a * d;
te[6] = b;
te[10] = a * c;
} else if (euler.order === 'ZYX') {
const ae = a * e,
af = a * f,
be = b * e,
bf = b * f;
te[0] = c * e;
te[4] = be * d - af;
te[8] = ae * d + bf;
te[1] = c * f;
te[5] = bf * d + ae;
te[9] = af * d - be;
te[2] = -d;
te[6] = b * c;
te[10] = a * c;
} else if (euler.order === 'YZX') {
const ac = a * c,
ad = a * d,
bc = b * c,
bd = b * d;
te[0] = c * e;
te[4] = bd - ac * f;
te[8] = bc * f + ad;
te[1] = f;
te[5] = a * e;
te[9] = -b * e;
te[2] = -d * e;
te[6] = ad * f + bc;
te[10] = ac - bd * f;
} else if (euler.order === 'XZY') {
const ac = a * c,
ad = a * d,
bc = b * c,
bd = b * d;
te[0] = c * e;
te[4] = -f;
te[8] = d * e;
te[1] = ac * f + bd;
te[5] = a * e;
te[9] = ad * f - bc;
te[2] = bc * f - ad;
te[6] = b * e;
te[10] = bd * f + ac;
}
// bottom row
te[3] = 0;
te[7] = 0;
te[11] = 0;
// last column
te[12] = 0;
te[13] = 0;
te[14] = 0;
te[15] = 1;
return this;
}
makeRotationFromQuaternion(q) {
return this.compose(_zero, q, _one);
}
lookAt(eye, target, up) {
const te = this.elements;
_z.subVectors(eye, target);
if (_z.lengthSq() === 0) {
// eye and target are in the same position
_z.z = 1;
}
_z.normalize();
_x.crossVectors(up, _z);
if (_x.lengthSq() === 0) {
// up and z are parallel
if (Math.abs(up.z) === 1) {
_z.x += 0.0001;
} else {
_z.z += 0.0001;
}
_z.normalize();
_x.crossVectors(up, _z);
}
_x.normalize();
_y.crossVectors(_z, _x);
te[0] = _x.x;
te[4] = _y.x;
te[8] = _z.x;
te[1] = _x.y;
te[5] = _y.y;
te[9] = _z.y;
te[2] = _x.z;
te[6] = _y.z;
te[10] = _z.z;
return this;
}
multiply(m, n) {
if (n !== undefined) {
console.warn('THREE.Matrix4: .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.');
return this.multiplyMatrices(m, n);
}
return this.multiplyMatrices(this, m);
}
premultiply(m) {
return this.multiplyMatrices(m, this);
}
multiplyMatrices(a, b) {
const ae = a.elements;
const be = b.elements;
const te = this.elements;
const a11 = ae[0],
a12 = ae[4],
a13 = ae[8],
a14 = ae[12];
const a21 = ae[1],
a22 = ae[5],
a23 = ae[9],
a24 = ae[13];
const a31 = ae[2],
a32 = ae[6],
a33 = ae[10],
a34 = ae[14];
const a41 = ae[3],
a42 = ae[7],
a43 = ae[11],
a44 = ae[15];
const b11 = be[0],
b12 = be[4],
b13 = be[8],
b14 = be[12];
const b21 = be[1],
b22 = be[5],
b23 = be[9],
b24 = be[13];
const b31 = be[2],
b32 = be[6],
b33 = be[10],
b34 = be[14];
const b41 = be[3],
b42 = be[7],
b43 = be[11],
b44 = be[15];
te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;
te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;
te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;
te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;
te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;
te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;
te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;
te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;
te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;
te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;
te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;
te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;
te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;
te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;
te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;
te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;
return this;
}
multiplyScalar(s) {
const te = this.elements;
te[0] *= s;
te[4] *= s;
te[8] *= s;
te[12] *= s;
te[1] *= s;
te[5] *= s;
te[9] *= s;
te[13] *= s;
te[2] *= s;
te[6] *= s;
te[10] *= s;
te[14] *= s;
te[3] *= s;
te[7] *= s;
te[11] *= s;
te[15] *= s;
return this;
}
determinant() {
const te = this.elements;
const n11 = te[0],
n12 = te[4],
n13 = te[8],
n14 = te[12];
const n21 = te[1],
n22 = te[5],
n23 = te[9],
n24 = te[13];
const n31 = te[2],
n32 = te[6],
n33 = te[10],
n34 = te[14];
const n41 = te[3],
n42 = te[7],
n43 = te[11],
n44 = te[15];
//TODO: make this more efficient
//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )
return n41 * (+n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34) + n42 * (+n11 * n23 * n34 - n11 * n24 * n33 + n14 * n21 * n33 - n13 * n21 * n34 + n13 * n24 * n31 - n14 * n23 * n31) + n43 * (+n11 * n24 * n32 - n11 * n22 * n34 - n14 * n21 * n32 + n12 * n21 * n34 + n14 * n22 * n31 - n12 * n24 * n31) + n44 * (-n13 * n22 * n31 - n11 * n23 * n32 + n11 * n22 * n33 + n13 * n21 * n32 - n12 * n21 * n33 + n12 * n23 * n31);
}
transpose() {
const te = this.elements;
let tmp;
tmp = te[1];
te[1] = te[4];
te[4] = tmp;
tmp = te[2];
te[2] = te[8];
te[8] = tmp;
tmp = te[6];
te[6] = te[9];
te[9] = tmp;
tmp = te[3];
te[3] = te[12];
te[12] = tmp;
tmp = te[7];
te[7] = te[13];
te[13] = tmp;
tmp = te[11];
te[11] = te[14];
te[14] = tmp;
return this;
}
setPosition(x, y, z) {
const te = this.elements;
if (x.isVector3) {
te[12] = x.x;
te[13] = x.y;
te[14] = x.z;
} else {
te[12] = x;
te[13] = y;
te[14] = z;
}
return this;
}
invert() {
// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm
const te = this.elements,
n11 = te[0],
n21 = te[1],
n31 = te[2],
n41 = te[3],
n12 = te[4],
n22 = te[5],
n32 = te[6],
n42 = te[7],
n13 = te[8],
n23 = te[9],
n33 = te[10],
n43 = te[11],
n14 = te[12],
n24 = te[13],
n34 = te[14],
n44 = te[15],
t11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,
t12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,
t13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,
t14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
const det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;
if (det === 0) return this.set(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
const detInv = 1 / det;
te[0] = t11 * detInv;
te[1] = (n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44) * detInv;
te[2] = (n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44) * detInv;
te[3] = (n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43) * detInv;
te[4] = t12 * detInv;
te[5] = (n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44) * detInv;
te[6] = (n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44) * detInv;
te[7] = (n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43) * detInv;
te[8] = t13 * detInv;
te[9] = (n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44) * detInv;
te[10] = (n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44) * detInv;
te[11] = (n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43) * detInv;
te[12] = t14 * detInv;
te[13] = (n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34) * detInv;
te[14] = (n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34) * detInv;
te[15] = (n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33) * detInv;
return this;
}
scale(v) {
const te = this.elements;
const x = v.x,
y = v.y,
z = v.z;
te[0] *= x;
te[4] *= y;
te[8] *= z;
te[1] *= x;
te[5] *= y;
te[9] *= z;
te[2] *= x;
te[6] *= y;
te[10] *= z;
te[3] *= x;
te[7] *= y;
te[11] *= z;
return this;
}
getMaxScaleOnAxis() {
const te = this.elements;
const scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2];
const scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6];
const scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10];
return Math.sqrt(Math.max(scaleXSq, scaleYSq, scaleZSq));
}
makeTranslation(x, y, z) {
this.set(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1);
return this;
}
makeRotationX(theta) {
const c = Math.cos(theta),
s = Math.sin(theta);
this.set(1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1);
return this;
}
makeRotationY(theta) {
const c = Math.cos(theta),
s = Math.sin(theta);
this.set(c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1);
return this;
}
makeRotationZ(theta) {
const c = Math.cos(theta),
s = Math.sin(theta);
this.set(c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
return this;
}
makeRotationAxis(axis, angle) {
// Based on http://www.gamedev.net/reference/articles/article1199.asp
const c = Math.cos(angle);
const s = Math.sin(angle);
const t = 1 - c;
const x = axis.x,
y = axis.y,
z = axis.z;
const tx = t * x,
ty = t * y;
this.set(tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1);
return this;
}
makeScale(x, y, z) {
this.set(x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1);
return this;
}
makeShear(x, y, z) {
this.set(1, y, z, 0, x, 1, z, 0, x, y, 1, 0, 0, 0, 0, 1);
return this;
}
compose(position, quaternion, scale) {
const te = this.elements;
const x = quaternion._x,
y = quaternion._y,
z = quaternion._z,
w = quaternion._w;
const x2 = x + x,
y2 = y + y,
z2 = z + z;
const xx = x * x2,
xy = x * y2,
xz = x * z2;
const yy = y * y2,
yz = y * z2,
zz = z * z2;
const wx = w * x2,
wy = w * y2,
wz = w * z2;
const sx = scale.x,
sy = scale.y,
sz = scale.z;
te[0] = (1 - (yy + zz)) * sx;
te[1] = (xy + wz) * sx;
te[2] = (xz - wy) * sx;
te[3] = 0;
te[4] = (xy - wz) * sy;
te[5] = (1 - (xx + zz)) * sy;
te[6] = (yz + wx) * sy;
te[7] = 0;
te[8] = (xz + wy) * sz;
te[9] = (yz - wx) * sz;
te[10] = (1 - (xx + yy)) * sz;
te[11] = 0;
te[12] = position.x;
te[13] = position.y;
te[14] = position.z;
te[15] = 1;
return this;
}
decompose(position, quaternion, scale) {
const te = this.elements;
let sx = _v1$1.set(te[0], te[1], te[2]).length();
const sy = _v1$1.set(te[4], te[5], te[6]).length();
const sz = _v1$1.set(te[8], te[9], te[10]).length();
// if determine is negative, we need to invert one scale
const det = this.determinant();
if (det < 0) sx = -sx;
position.x = te[12];
position.y = te[13];
position.z = te[14];
// scale the rotation part
_m1.copy(this);
const invSX = 1 / sx;
const invSY = 1 / sy;
const invSZ = 1 / sz;
_m1.elements[0] *= invSX;
_m1.elements[1] *= invSX;
_m1.elements[2] *= invSX;
_m1.elements[4] *= invSY;
_m1.elements[5] *= invSY;
_m1.elements[6] *= invSY;
_m1.elements[8] *= invSZ;
_m1.elements[9] *= invSZ;
_m1.elements[10] *= invSZ;
quaternion.setFromRotationMatrix(_m1);
scale.x = sx;
scale.y = sy;
scale.z = sz;
return this;
}
makePerspective(left, right, top, bottom, near, far) {
if (far === undefined) {
console.warn('THREE.Matrix4: .makePerspective() has been redefined and has a new signature. Please check the docs.');
}
const te = this.elements;
const x = 2 * near / (right - left);
const y = 2 * near / (top - bottom);
const a = (right + left) / (right - left);
const b = (top + bottom) / (top - bottom);
const c = -(far + near) / (far - near);
const d = -2 * far * near / (far - near);
te[0] = x;
te[4] = 0;
te[8] = a;
te[12] = 0;
te[1] = 0;
te[5] = y;
te[9] = b;
te[13] = 0;
te[2] = 0;
te[6] = 0;
te[10] = c;
te[14] = d;
te[3] = 0;
te[7] = 0;
te[11] = -1;
te[15] = 0;
return this;
}
makeOrthographic(left, right, top, bottom, near, far) {
const te = this.elements;
const w = 1.0 / (right - left);
const h = 1.0 / (top - bottom);
const p = 1.0 / (far - near);
const x = (right + left) * w;
const y = (top + bottom) * h;
const z = (far + near) * p;
te[0] = 2 * w;
te[4] = 0;
te[8] = 0;
te[12] = -x;
te[1] = 0;
te[5] = 2 * h;
te[9] = 0;
te[13] = -y;
te[2] = 0;
te[6] = 0;
te[10] = -2 * p;
te[14] = -z;
te[3] = 0;
te[7] = 0;
te[11] = 0;
te[15] = 1;
return this;
}
equals(matrix) {
const te = this.elements;
const me = matrix.elements;
for (let i = 0; i < 16; i++) {
if (te[i] !== me[i]) return false;
}
return true;
}
fromArray(array, offset = 0) {
for (let i = 0; i < 16; i++) {
this.elements[i] = array[i + offset];
}
return this;
}
toArray(array = [], offset = 0) {
const te = this.elements;
array[offset] = te[0];
array[offset + 1] = te[1];
array[offset + 2] = te[2];
array[offset + 3] = te[3];
array[offset + 4] = te[4];
array[offset + 5] = te[5];
array[offset + 6] = te[6];
array[offset + 7] = te[7];
array[offset + 8] = te[8];
array[offset + 9] = te[9];
array[offset + 10] = te[10];
array[offset + 11] = te[11];
array[offset + 12] = te[12];
array[offset + 13] = te[13];
array[offset + 14] = te[14];
array[offset + 15] = te[15];
return array;
}
}
const _v1$1 = /*@__PURE__*/new Vector3();
const _m1 = /*@__PURE__*/new Matrix4();
const _zero = /*@__PURE__*/new Vector3(0, 0, 0);
const _one = /*@__PURE__*/new Vector3(1, 1, 1);
const _x = /*@__PURE__*/new Vector3();
const _y = /*@__PURE__*/new Vector3();
const _z = /*@__PURE__*/new Vector3();
class Euler {
constructor(x = 0, y = 0, z = 0, order = Euler.DefaultOrder) {
Object.defineProperty(this, 'isEuler', {
value: true
});
this._x = x;
this._y = y;
this._z = z;
this._order = order;
}
get x() {
return this._x;
}
set x(value) {
this._x = value;
this._onChangeCallback();
}
get y() {
return this._y;
}
set y(value) {
this._y = value;
this._onChangeCallback();
}
get z() {
return this._z;
}
set z(value) {
this._z = value;
this._onChangeCallback();
}
get order() {
return this._order;
}
set order(value) {
this._order = value;
this._onChangeCallback();
}
set(x, y, z, order) {
this._x = x;
this._y = y;
this._z = z;
this._order = order || this._order;
this._onChangeCallback();
return this;
}
clone() {
return new this.constructor(this._x, this._y, this._z, this._order);
}
copy(euler) {
this._x = euler._x;
this._y = euler._y;
this._z = euler._z;
this._order = euler._order;
this._onChangeCallback();
return this;
}
setFromRotationMatrix(m, order, update) {
const clamp = MathUtils.clamp;
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
const te = m.elements;
const m11 = te[0],
m12 = te[4],
m13 = te[8];
const m21 = te[1],
m22 = te[5],
m23 = te[9];
const m31 = te[2],
m32 = te[6],
m33 = te[10];
order = order || this._order;
switch (order) {
case 'XYZ':
this._y = Math.asin(clamp(m13, -1, 1));
if (Math.abs(m13) < 0.9999999) {
this._x = Math.atan2(-m23, m33);
this._z = Math.atan2(-m12, m11);
} else {
this._x = Math.atan2(m32, m22);
this._z = 0;
}
break;
case 'YXZ':
this._x = Math.asin(-clamp(m23, -1, 1));
if (Math.abs(m23) < 0.9999999) {
this._y = Math.atan2(m13, m33);
this._z = Math.atan2(m21, m22);
} else {
this._y = Math.atan2(-m31, m11);
this._z = 0;
}
break;
case 'ZXY':
this._x = Math.asin(clamp(m32, -1, 1));
if (Math.abs(m32) < 0.9999999) {
this._y = Math.atan2(-m31, m33);
this._z = Math.atan2(-m12, m22);
} else {
this._y = 0;
this._z = Math.atan2(m21, m11);
}
break;
case 'ZYX':
this._y = Math.asin(-clamp(m31, -1, 1));
if (Math.abs(m31) < 0.9999999) {
this._x = Math.atan2(m32, m33);
this._z = Math.atan2(m21, m11);
} else {
this._x = 0;
this._z = Math.atan2(-m12, m22);
}
break;
case 'YZX':
this._z = Math.asin(clamp(m21, -1, 1));
if (Math.abs(m21) < 0.9999999) {
this._x = Math.atan2(-m23, m22);
this._y = Math.atan2(-m31, m11);
} else {
this._x = 0;
this._y = Math.atan2(m13, m33);
}
break;
case 'XZY':
this._z = Math.asin(-clamp(m12, -1, 1));
if (Math.abs(m12) < 0.9999999) {
this._x = Math.atan2(m32, m22);
this._y = Math.atan2(m13, m11);
} else {
this._x = Math.atan2(-m23, m33);
this._y = 0;
}
break;
default:
console.warn('THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order);
}
this._order = order;
if (update !== false) this._onChangeCallback();
return this;
}
setFromQuaternion(q, order, update) {
_matrix.makeRotationFromQuaternion(q);
return this.setFromRotationMatrix(_matrix, order, update);
}
setFromVector3(v, order) {
return this.set(v.x, v.y, v.z, order || this._order);
}
reorder(newOrder) {
// WARNING: this discards revolution information -bhouston
_quaternion$1.setFromEuler(this);
return this.setFromQuaternion(_quaternion$1, newOrder);
}
equals(euler) {
return euler._x === this._x && euler._y === this._y && euler._z === this._z && euler._order === this._order;
}
fromArray(array) {
this._x = array[0];
this._y = array[1];
this._z = array[2];
if (array[3] !== undefined) this._order = array[3];
this._onChangeCallback();
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this._x;
array[offset + 1] = this._y;
array[offset + 2] = this._z;
array[offset + 3] = this._order;
return array;
}
toVector3(optionalResult) {
if (optionalResult) {
return optionalResult.set(this._x, this._y, this._z);
} else {
return new Vector3(this._x, this._y, this._z);
}
}
_onChange(callback) {
this._onChangeCallback = callback;
return this;
}
_onChangeCallback() {}
}
Euler.DefaultOrder = 'XYZ';
Euler.RotationOrders = ['XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX'];
const _matrix = /*@__PURE__*/new Matrix4();
const _quaternion$1 = /*@__PURE__*/new Quaternion();
class Layers {
constructor() {
this.mask = 1 | 0;
}
set(channel) {
this.mask = 1 << channel | 0;
}
enable(channel) {
this.mask |= 1 << channel | 0;
}
enableAll() {
this.mask = 0xffffffff | 0;
}
toggle(channel) {
this.mask ^= 1 << channel | 0;
}
disable(channel) {
this.mask &= ~(1 << channel | 0);
}
disableAll() {
this.mask = 0;
}
test(layers) {
return (this.mask & layers.mask) !== 0;
}
}
let _object3DId = 0;
const _v1$2 = new Vector3();
const _q1 = new Quaternion();
const _m1$1 = new Matrix4();
const _target = new Vector3();
const _position = new Vector3();
const _scale = new Vector3();
const _quaternion$2 = new Quaternion();
const _xAxis = new Vector3(1, 0, 0);
const _yAxis = new Vector3(0, 1, 0);
const _zAxis = new Vector3(0, 0, 1);
const _addedEvent = {
type: 'added'
};
const _removedEvent = {
type: 'removed'
};
function Object3D() {
Object.defineProperty(this, 'id', {
value: _object3DId++
});
this.uuid = MathUtils.generateUUID();
this.name = '';
this.type = 'Object3D';
this.parent = null;
this.children = [];
this.up = Object3D.DefaultUp.clone();
const position = new Vector3();
const rotation = new Euler();
const quaternion = new Quaternion();
const scale = new Vector3(1, 1, 1);
function onRotationChange() {
quaternion.setFromEuler(rotation, false);
}
function onQuaternionChange() {
rotation.setFromQuaternion(quaternion, undefined, false);
}
rotation._onChange(onRotationChange);
quaternion._onChange(onQuaternionChange);
Object.defineProperties(this, {
position: {
configurable: true,
enumerable: true,
value: position
},
rotation: {
configurable: true,
enumerable: true,
value: rotation
},
quaternion: {
configurable: true,
enumerable: true,
value: quaternion
},
scale: {
configurable: true,
enumerable: true,
value: scale
},
modelViewMatrix: {
value: new Matrix4()
},
normalMatrix: {
value: new Matrix3()
}
});
this.matrix = new Matrix4();
this.matrixWorld = new Matrix4();
this.matrixAutoUpdate = Object3D.DefaultMatrixAutoUpdate;
this.matrixWorldNeedsUpdate = false;
this.layers = new Layers();
this.visible = true;
this.castShadow = false;
this.receiveShadow = false;
this.frustumCulled = true;
this.renderOrder = 0;
this.animations = [];
this.userData = {};
}
Object3D.DefaultUp = new Vector3(0, 1, 0);
Object3D.DefaultMatrixAutoUpdate = true;
Object3D.prototype = _extends(Object.create(EventDispatcher.prototype), {
constructor: Object3D,
isObject3D: true,
onBeforeRender: function () {},
onAfterRender: function () {},
applyMatrix4: function (matrix) {
if (this.matrixAutoUpdate) this.updateMatrix();
this.matrix.premultiply(matrix);
this.matrix.decompose(this.position, this.quaternion, this.scale);
},
applyQuaternion: function (q) {
this.quaternion.premultiply(q);
return this;
},
setRotationFromAxisAngle: function (axis, angle) {
// assumes axis is normalized
this.quaternion.setFromAxisAngle(axis, angle);
},
setRotationFromEuler: function (euler) {
this.quaternion.setFromEuler(euler, true);
},
setRotationFromMatrix: function (m) {
// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)
this.quaternion.setFromRotationMatrix(m);
},
setRotationFromQuaternion: function (q) {
// assumes q is normalized
this.quaternion.copy(q);
},
rotateOnAxis: function (axis, angle) {
// rotate object on axis in object space
// axis is assumed to be normalized
_q1.setFromAxisAngle(axis, angle);
this.quaternion.multiply(_q1);
return this;
},
rotateOnWorldAxis: function (axis, angle) {
// rotate object on axis in world space
// axis is assumed to be normalized
// method assumes no rotated parent
_q1.setFromAxisAngle(axis, angle);
this.quaternion.premultiply(_q1);
return this;
},
rotateX: function (angle) {
return this.rotateOnAxis(_xAxis, angle);
},
rotateY: function (angle) {
return this.rotateOnAxis(_yAxis, angle);
},
rotateZ: function (angle) {
return this.rotateOnAxis(_zAxis, angle);
},
translateOnAxis: function (axis, distance) {
// translate object by distance along axis in object space
// axis is assumed to be normalized
_v1$2.copy(axis).applyQuaternion(this.quaternion);
this.position.add(_v1$2.multiplyScalar(distance));
return this;
},
translateX: function (distance) {
return this.translateOnAxis(_xAxis, distance);
},
translateY: function (distance) {
return this.translateOnAxis(_yAxis, distance);
},
translateZ: function (distance) {
return this.translateOnAxis(_zAxis, distance);
},
localToWorld: function (vector) {
return vector.applyMatrix4(this.matrixWorld);
},
worldToLocal: function (vector) {
return vector.applyMatrix4(_m1$1.copy(this.matrixWorld).invert());
},
lookAt: function (x, y, z) {
// This method does not support objects having non-uniformly-scaled parent(s)
if (x.isVector3) {
_target.copy(x);
} else {
_target.set(x, y, z);
}
const parent = this.parent;
this.updateWorldMatrix(true, false);
_position.setFromMatrixPosition(this.matrixWorld);
if (this.isCamera || this.isLight) {
_m1$1.lookAt(_position, _target, this.up);
} else {
_m1$1.lookAt(_target, _position, this.up);
}
this.quaternion.setFromRotationMatrix(_m1$1);
if (parent) {
_m1$1.extractRotation(parent.matrixWorld);
_q1.setFromRotationMatrix(_m1$1);
this.quaternion.premultiply(_q1.invert());
}
},
add: function (object) {
if (arguments.length > 1) {
for (let i = 0; i < arguments.length; i++) {
this.add(arguments[i]);
}
return this;
}
if (object === this) {
console.error('THREE.Object3D.add: object can\'t be added as a child of itself.', object);
return this;
}
if (object && object.isObject3D) {
if (object.parent !== null) {
object.parent.remove(object);
}
object.parent = this;
this.children.push(object);
object.dispatchEvent(_addedEvent);
} else {
console.error('THREE.Object3D.add: object not an instance of THREE.Object3D.', object);
}
return this;
},
remove: function (object) {
if (arguments.length > 1) {
for (let i = 0; i < arguments.length; i++) {
this.remove(arguments[i]);
}
return this;
}
const index = this.children.indexOf(object);
if (index !== -1) {
object.parent = null;
this.children.splice(index, 1);
object.dispatchEvent(_removedEvent);
}
return this;
},
clear: function () {
for (let i = 0; i < this.children.length; i++) {
const object = this.children[i];
object.parent = null;
object.dispatchEvent(_removedEvent);
}
this.children.length = 0;
return this;
},
attach: function (object) {
// adds object as a child of this, while maintaining the object's world transform
this.updateWorldMatrix(true, false);
_m1$1.copy(this.matrixWorld).invert();
if (object.parent !== null) {
object.parent.updateWorldMatrix(true, false);
_m1$1.multiply(object.parent.matrixWorld);
}
object.applyMatrix4(_m1$1);
object.updateWorldMatrix(false, false);
this.add(object);
return this;
},
getObjectById: function (id) {
return this.getObjectByProperty('id', id);
},
getObjectByName: function (name) {
return this.getObjectByProperty('name', name);
},
getObjectByProperty: function (name, value) {
if (this[name] === value) return this;
for (let i = 0, l = this.children.length; i < l; i++) {
const child = this.children[i];
const object = child.getObjectByProperty(name, value);
if (object !== undefined) {
return object;
}
}
return undefined;
},
getWorldPosition: function (target) {
if (target === undefined) {
console.warn('THREE.Object3D: .getWorldPosition() target is now required');
target = new Vector3();
}
this.updateWorldMatrix(true, false);
return target.setFromMatrixPosition(this.matrixWorld);
},
getWorldQuaternion: function (target) {
if (target === undefined) {
console.warn('THREE.Object3D: .getWorldQuaternion() target is now required');
target = new Quaternion();
}
this.updateWorldMatrix(true, false);
this.matrixWorld.decompose(_position, target, _scale);
return target;
},
getWorldScale: function (target) {
if (target === undefined) {
console.warn('THREE.Object3D: .getWorldScale() target is now required');
target = new Vector3();
}
this.updateWorldMatrix(true, false);
this.matrixWorld.decompose(_position, _quaternion$2, target);
return target;
},
getWorldDirection: function (target) {
if (target === undefined) {
console.warn('THREE.Object3D: .getWorldDirection() target is now required');
target = new Vector3();
}
this.updateWorldMatrix(true, false);
const e = this.matrixWorld.elements;
return target.set(e[8], e[9], e[10]).normalize();
},
raycast: function () {},
traverse: function (callback) {
callback(this);
const children = this.children;
for (let i = 0, l = children.length; i < l; i++) {
children[i].traverse(callback);
}
},
traverseVisible: function (callback) {
if (this.visible === false) return;
callback(this);
const children = this.children;
for (let i = 0, l = children.length; i < l; i++) {
children[i].traverseVisible(callback);
}
},
traverseAncestors: function (callback) {
const parent = this.parent;
if (parent !== null) {
callback(parent);
parent.traverseAncestors(callback);
}
},
updateMatrix: function () {
this.matrix.compose(this.position, this.quaternion, this.scale);
this.matrixWorldNeedsUpdate = true;
},
updateMatrixWorld: function (force) {
if (this.matrixAutoUpdate) this.updateMatrix();
if (this.matrixWorldNeedsUpdate || force) {
if (this.parent === null) {
this.matrixWorld.copy(this.matrix);
} else {
this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
}
this.matrixWorldNeedsUpdate = false;
force = true;
}
// update children
const children = this.children;
for (let i = 0, l = children.length; i < l; i++) {
children[i].updateMatrixWorld(force);
}
},
updateWorldMatrix: function (updateParents, updateChildren) {
const parent = this.parent;
if (updateParents === true && parent !== null) {
parent.updateWorldMatrix(true, false);
}
if (this.matrixAutoUpdate) this.updateMatrix();
if (this.parent === null) {
this.matrixWorld.copy(this.matrix);
} else {
this.matrixWorld.multiplyMatrices(this.parent.matrixWorld, this.matrix);
}
// update children
if (updateChildren === true) {
const children = this.children;
for (let i = 0, l = children.length; i < l; i++) {
children[i].updateWorldMatrix(false, true);
}
}
},
toJSON: function (meta) {
// meta is a string when called from JSON.stringify
const isRootObject = meta === undefined || typeof meta === 'string';
const output = {};
// meta is a hash used to collect geometries, materials.
// not providing it implies that this is the root object
// being serialized.
if (isRootObject) {
// initialize meta obj
meta = {
geometries: {},
materials: {},
textures: {},
images: {},
shapes: {},
skeletons: {},
animations: {}
};
output.metadata = {
version: 4.5,
type: 'Object',
generator: 'Object3D.toJSON'
};
}
// standard Object3D serialization
const object = {};
object.uuid = this.uuid;
object.type = this.type;
if (this.name !== '') object.name = this.name;
if (this.castShadow === true) object.castShadow = true;
if (this.receiveShadow === true) object.receiveShadow = true;
if (this.visible === false) object.visible = false;
if (this.frustumCulled === false) object.frustumCulled = false;
if (this.renderOrder !== 0) object.renderOrder = this.renderOrder;
if (JSON.stringify(this.userData) !== '{}') object.userData = this.userData;
object.layers = this.layers.mask;
object.matrix = this.matrix.toArray();
if (this.matrixAutoUpdate === false) object.matrixAutoUpdate = false;
// object specific properties
if (this.isInstancedMesh) {
object.type = 'InstancedMesh';
object.count = this.count;
object.instanceMatrix = this.instanceMatrix.toJSON();
}
//
function serialize(library, element) {
if (library[element.uuid] === undefined) {
library[element.uuid] = element.toJSON(meta);
}
return element.uuid;
}
if (this.isMesh || this.isLine || this.isPoints) {
object.geometry = serialize(meta.geometries, this.geometry);
const parameters = this.geometry.parameters;
if (parameters !== undefined && parameters.shapes !== undefined) {
const shapes = parameters.shapes;
if (Array.isArray(shapes)) {
for (let i = 0, l = shapes.length; i < l; i++) {
const shape = shapes[i];
serialize(meta.shapes, shape);
}
} else {
serialize(meta.shapes, shapes);
}
}
}
if (this.isSkinnedMesh) {
object.bindMode = this.bindMode;
object.bindMatrix = this.bindMatrix.toArray();
if (this.skeleton !== undefined) {
serialize(meta.skeletons, this.skeleton);
object.skeleton = this.skeleton.uuid;
}
}
if (this.material !== undefined) {
if (Array.isArray(this.material)) {
const uuids = [];
for (let i = 0, l = this.material.length; i < l; i++) {
uuids.push(serialize(meta.materials, this.material[i]));
}
object.material = uuids;
} else {
object.material = serialize(meta.materials, this.material);
}
}
//
if (this.children.length > 0) {
object.children = [];
for (let i = 0; i < this.children.length; i++) {
object.children.push(this.children[i].toJSON(meta).object);
}
}
//
if (this.animations.length > 0) {
object.animations = [];
for (let i = 0; i < this.animations.length; i++) {
const animation = this.animations[i];
object.animations.push(serialize(meta.animations, animation));
}
}
if (isRootObject) {
const geometries = extractFromCache(meta.geometries);
const materials = extractFromCache(meta.materials);
const textures = extractFromCache(meta.textures);
const images = extractFromCache(meta.images);
const shapes = extractFromCache(meta.shapes);
const skeletons = extractFromCache(meta.skeletons);
const animations = extractFromCache(meta.animations);
if (geometries.length > 0) output.geometries = geometries;
if (materials.length > 0) output.materials = materials;
if (textures.length > 0) output.textures = textures;
if (images.length > 0) output.images = images;
if (shapes.length > 0) output.shapes = shapes;
if (skeletons.length > 0) output.skeletons = skeletons;
if (animations.length > 0) output.animations = animations;
}
output.object = object;
return output;
// extract data from the cache hash
// remove metadata on each item
// and return as array
function extractFromCache(cache) {
const values = [];
for (const key in cache) {
const data = cache[key];
delete data.metadata;
values.push(data);
}
return values;
}
},
clone: function (recursive) {
return new this.constructor().copy(this, recursive);
},
copy: function (source, recursive = true) {
this.name = source.name;
this.up.copy(source.up);
this.position.copy(source.position);
this.rotation.order = source.rotation.order;
this.quaternion.copy(source.quaternion);
this.scale.copy(source.scale);
this.matrix.copy(source.matrix);
this.matrixWorld.copy(source.matrixWorld);
this.matrixAutoUpdate = source.matrixAutoUpdate;
this.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;
this.layers.mask = source.layers.mask;
this.visible = source.visible;
this.castShadow = source.castShadow;
this.receiveShadow = source.receiveShadow;
this.frustumCulled = source.frustumCulled;
this.renderOrder = source.renderOrder;
this.userData = JSON.parse(JSON.stringify(source.userData));
if (recursive === true) {
for (let i = 0; i < source.children.length; i++) {
const child = source.children[i];
this.add(child.clone());
}
}
return this;
}
});
const _vector1 = /*@__PURE__*/new Vector3();
const _vector2 = /*@__PURE__*/new Vector3();
const _normalMatrix = /*@__PURE__*/new Matrix3();
class Plane {
constructor(normal, constant) {
Object.defineProperty(this, 'isPlane', {
value: true
});
// normal is assumed to be normalized
this.normal = normal !== undefined ? normal : new Vector3(1, 0, 0);
this.constant = constant !== undefined ? constant : 0;
}
set(normal, constant) {
this.normal.copy(normal);
this.constant = constant;
return this;
}
setComponents(x, y, z, w) {
this.normal.set(x, y, z);
this.constant = w;
return this;
}
setFromNormalAndCoplanarPoint(normal, point) {
this.normal.copy(normal);
this.constant = -point.dot(this.normal);
return this;
}
setFromCoplanarPoints(a, b, c) {
const normal = _vector1.subVectors(c, b).cross(_vector2.subVectors(a, b)).normalize();
// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?
this.setFromNormalAndCoplanarPoint(normal, a);
return this;
}
clone() {
return new this.constructor().copy(this);
}
copy(plane) {
this.normal.copy(plane.normal);
this.constant = plane.constant;
return this;
}
normalize() {
// Note: will lead to a divide by zero if the plane is invalid.
const inverseNormalLength = 1.0 / this.normal.length();
this.normal.multiplyScalar(inverseNormalLength);
this.constant *= inverseNormalLength;
return this;
}
negate() {
this.constant *= -1;
this.normal.negate();
return this;
}
distanceToPoint(point) {
return this.normal.dot(point) + this.constant;
}
distanceToSphere(sphere) {
return this.distanceToPoint(sphere.center) - sphere.radius;
}
projectPoint(point, target) {
if (target === undefined) {
console.warn('THREE.Plane: .projectPoint() target is now required');
target = new Vector3();
}
return target.copy(this.normal).multiplyScalar(-this.distanceToPoint(point)).add(point);
}
intersectLine(line, target) {
if (target === undefined) {
console.warn('THREE.Plane: .intersectLine() target is now required');
target = new Vector3();
}
const direction = line.delta(_vector1);
const denominator = this.normal.dot(direction);
if (denominator === 0) {
// line is coplanar, return origin
if (this.distanceToPoint(line.start) === 0) {
return target.copy(line.start);
}
// Unsure if this is the correct method to handle this case.
return undefined;
}
const t = -(line.start.dot(this.normal) + this.constant) / denominator;
if (t < 0 || t > 1) {
return undefined;
}
return target.copy(direction).multiplyScalar(t).add(line.start);
}
intersectsLine(line) {
// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.
const startSign = this.distanceToPoint(line.start);
const endSign = this.distanceToPoint(line.end);
return startSign < 0 && endSign > 0 || endSign < 0 && startSign > 0;
}
intersectsBox(box) {
return box.intersectsPlane(this);
}
intersectsSphere(sphere) {
return sphere.intersectsPlane(this);
}
coplanarPoint(target) {
if (target === undefined) {
console.warn('THREE.Plane: .coplanarPoint() target is now required');
target = new Vector3();
}
return target.copy(this.normal).multiplyScalar(-this.constant);
}
applyMatrix4(matrix, optionalNormalMatrix) {
const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix(matrix);
const referencePoint = this.coplanarPoint(_vector1).applyMatrix4(matrix);
const normal = this.normal.applyMatrix3(normalMatrix).normalize();
this.constant = -referencePoint.dot(normal);
return this;
}
translate(offset) {
this.constant -= offset.dot(this.normal);
return this;
}
equals(plane) {
return plane.normal.equals(this.normal) && plane.constant === this.constant;
}
}
const _v0$1 = /*@__PURE__*/new Vector3();
const _v1$3 = /*@__PURE__*/new Vector3();
const _v2$1 = /*@__PURE__*/new Vector3();
const _v3 = /*@__PURE__*/new Vector3();
const _vab = /*@__PURE__*/new Vector3();
const _vac = /*@__PURE__*/new Vector3();
const _vbc = /*@__PURE__*/new Vector3();
const _vap = /*@__PURE__*/new Vector3();
const _vbp = /*@__PURE__*/new Vector3();
const _vcp = /*@__PURE__*/new Vector3();
class Triangle {
constructor(a, b, c) {
this.a = a !== undefined ? a : new Vector3();
this.b = b !== undefined ? b : new Vector3();
this.c = c !== undefined ? c : new Vector3();
}
static getNormal(a, b, c, target) {
if (target === undefined) {
console.warn('THREE.Triangle: .getNormal() target is now required');
target = new Vector3();
}
target.subVectors(c, b);
_v0$1.subVectors(a, b);
target.cross(_v0$1);
const targetLengthSq = target.lengthSq();
if (targetLengthSq > 0) {
return target.multiplyScalar(1 / Math.sqrt(targetLengthSq));
}
return target.set(0, 0, 0);
}
// static/instance method to calculate barycentric coordinates
// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
static getBarycoord(point, a, b, c, target) {
_v0$1.subVectors(c, a);
_v1$3.subVectors(b, a);
_v2$1.subVectors(point, a);
const dot00 = _v0$1.dot(_v0$1);
const dot01 = _v0$1.dot(_v1$3);
const dot02 = _v0$1.dot(_v2$1);
const dot11 = _v1$3.dot(_v1$3);
const dot12 = _v1$3.dot(_v2$1);
const denom = dot00 * dot11 - dot01 * dot01;
if (target === undefined) {
console.warn('THREE.Triangle: .getBarycoord() target is now required');
target = new Vector3();
}
// collinear or singular triangle
if (denom === 0) {
// arbitrary location outside of triangle?
// not sure if this is the best idea, maybe should be returning undefined
return target.set(-2, -1, -1);
}
const invDenom = 1 / denom;
const u = (dot11 * dot02 - dot01 * dot12) * invDenom;
const v = (dot00 * dot12 - dot01 * dot02) * invDenom;
// barycentric coordinates must always sum to 1
return target.set(1 - u - v, v, u);
}
static containsPoint(point, a, b, c) {
this.getBarycoord(point, a, b, c, _v3);
return _v3.x >= 0 && _v3.y >= 0 && _v3.x + _v3.y <= 1;
}
static getUV(point, p1, p2, p3, uv1, uv2, uv3, target) {
this.getBarycoord(point, p1, p2, p3, _v3);
target.set(0, 0);
target.addScaledVector(uv1, _v3.x);
target.addScaledVector(uv2, _v3.y);
target.addScaledVector(uv3, _v3.z);
return target;
}
static isFrontFacing(a, b, c, direction) {
_v0$1.subVectors(c, b);
_v1$3.subVectors(a, b);
// strictly front facing
return _v0$1.cross(_v1$3).dot(direction) < 0 ? true : false;
}
set(a, b, c) {
this.a.copy(a);
this.b.copy(b);
this.c.copy(c);
return this;
}
setFromPointsAndIndices(points, i0, i1, i2) {
this.a.copy(points[i0]);
this.b.copy(points[i1]);
this.c.copy(points[i2]);
return this;
}
clone() {
return new this.constructor().copy(this);
}
copy(triangle) {
this.a.copy(triangle.a);
this.b.copy(triangle.b);
this.c.copy(triangle.c);
return this;
}
getArea() {
_v0$1.subVectors(this.c, this.b);
_v1$3.subVectors(this.a, this.b);
return _v0$1.cross(_v1$3).length() * 0.5;
}
getMidpoint(target) {
if (target === undefined) {
console.warn('THREE.Triangle: .getMidpoint() target is now required');
target = new Vector3();
}
return target.addVectors(this.a, this.b).add(this.c).multiplyScalar(1 / 3);
}
getNormal(target) {
return Triangle.getNormal(this.a, this.b, this.c, target);
}
getPlane(target) {
if (target === undefined) {
console.warn('THREE.Triangle: .getPlane() target is now required');
target = new Plane();
}
return target.setFromCoplanarPoints(this.a, this.b, this.c);
}
getBarycoord(point, target) {
return Triangle.getBarycoord(point, this.a, this.b, this.c, target);
}
getUV(point, uv1, uv2, uv3, target) {
return Triangle.getUV(point, this.a, this.b, this.c, uv1, uv2, uv3, target);
}
containsPoint(point) {
return Triangle.containsPoint(point, this.a, this.b, this.c);
}
isFrontFacing(direction) {
return Triangle.isFrontFacing(this.a, this.b, this.c, direction);
}
intersectsBox(box) {
return box.intersectsTriangle(this);
}
closestPointToPoint(p, target) {
if (target === undefined) {
console.warn('THREE.Triangle: .closestPointToPoint() target is now required');
target = new Vector3();
}
const a = this.a,
b = this.b,
c = this.c;
let v, w;
// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
// under the accompanying license; see chapter 5.1.5 for detailed explanation.
// basically, we're distinguishing which of the voronoi regions of the triangle
// the point lies in with the minimum amount of redundant computation.
_vab.subVectors(b, a);
_vac.subVectors(c, a);
_vap.subVectors(p, a);
const d1 = _vab.dot(_vap);
const d2 = _vac.dot(_vap);
if (d1 <= 0 && d2 <= 0) {
// vertex region of A; barycentric coords (1, 0, 0)
return target.copy(a);
}
_vbp.subVectors(p, b);
const d3 = _vab.dot(_vbp);
const d4 = _vac.dot(_vbp);
if (d3 >= 0 && d4 <= d3) {
// vertex region of B; barycentric coords (0, 1, 0)
return target.copy(b);
}
const vc = d1 * d4 - d3 * d2;
if (vc <= 0 && d1 >= 0 && d3 <= 0) {
v = d1 / (d1 - d3);
// edge region of AB; barycentric coords (1-v, v, 0)
return target.copy(a).addScaledVector(_vab, v);
}
_vcp.subVectors(p, c);
const d5 = _vab.dot(_vcp);
const d6 = _vac.dot(_vcp);
if (d6 >= 0 && d5 <= d6) {
// vertex region of C; barycentric coords (0, 0, 1)
return target.copy(c);
}
const vb = d5 * d2 - d1 * d6;
if (vb <= 0 && d2 >= 0 && d6 <= 0) {
w = d2 / (d2 - d6);
// edge region of AC; barycentric coords (1-w, 0, w)
return target.copy(a).addScaledVector(_vac, w);
}
const va = d3 * d6 - d5 * d4;
if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0) {
_vbc.subVectors(c, b);
w = (d4 - d3) / (d4 - d3 + (d5 - d6));
// edge region of BC; barycentric coords (0, 1-w, w)
return target.copy(b).addScaledVector(_vbc, w); // edge region of BC
}
// face region
const denom = 1 / (va + vb + vc);
// u = va * denom
v = vb * denom;
w = vc * denom;
return target.copy(a).addScaledVector(_vab, v).addScaledVector(_vac, w);
}
equals(triangle) {
return triangle.a.equals(this.a) && triangle.b.equals(this.b) && triangle.c.equals(this.c);
}
}
const _colorKeywords = {
'aliceblue': 0xF0F8FF,
'antiquewhite': 0xFAEBD7,
'aqua': 0x00FFFF,
'aquamarine': 0x7FFFD4,
'azure': 0xF0FFFF,
'beige': 0xF5F5DC,
'bisque': 0xFFE4C4,
'black': 0x000000,
'blanchedalmond': 0xFFEBCD,
'blue': 0x0000FF,
'blueviolet': 0x8A2BE2,
'brown': 0xA52A2A,
'burlywood': 0xDEB887,
'cadetblue': 0x5F9EA0,
'chartreuse': 0x7FFF00,
'chocolate': 0xD2691E,
'coral': 0xFF7F50,
'cornflowerblue': 0x6495ED,
'cornsilk': 0xFFF8DC,
'crimson': 0xDC143C,
'cyan': 0x00FFFF,
'darkblue': 0x00008B,
'darkcyan': 0x008B8B,
'darkgoldenrod': 0xB8860B,
'darkgray': 0xA9A9A9,
'darkgreen': 0x006400,
'darkgrey': 0xA9A9A9,
'darkkhaki': 0xBDB76B,
'darkmagenta': 0x8B008B,
'darkolivegreen': 0x556B2F,
'darkorange': 0xFF8C00,
'darkorchid': 0x9932CC,
'darkred': 0x8B0000,
'darksalmon': 0xE9967A,
'darkseagreen': 0x8FBC8F,
'darkslateblue': 0x483D8B,
'darkslategray': 0x2F4F4F,
'darkslategrey': 0x2F4F4F,
'darkturquoise': 0x00CED1,
'darkviolet': 0x9400D3,
'deeppink': 0xFF1493,
'deepskyblue': 0x00BFFF,
'dimgray': 0x696969,
'dimgrey': 0x696969,
'dodgerblue': 0x1E90FF,
'firebrick': 0xB22222,
'floralwhite': 0xFFFAF0,
'forestgreen': 0x228B22,
'fuchsia': 0xFF00FF,
'gainsboro': 0xDCDCDC,
'ghostwhite': 0xF8F8FF,
'gold': 0xFFD700,
'goldenrod': 0xDAA520,
'gray': 0x808080,
'green': 0x008000,
'greenyellow': 0xADFF2F,
'grey': 0x808080,
'honeydew': 0xF0FFF0,
'hotpink': 0xFF69B4,
'indianred': 0xCD5C5C,
'indigo': 0x4B0082,
'ivory': 0xFFFFF0,
'khaki': 0xF0E68C,
'lavender': 0xE6E6FA,
'lavenderblush': 0xFFF0F5,
'lawngreen': 0x7CFC00,
'lemonchiffon': 0xFFFACD,
'lightblue': 0xADD8E6,
'lightcoral': 0xF08080,
'lightcyan': 0xE0FFFF,
'lightgoldenrodyellow': 0xFAFAD2,
'lightgray': 0xD3D3D3,
'lightgreen': 0x90EE90,
'lightgrey': 0xD3D3D3,
'lightpink': 0xFFB6C1,
'lightsalmon': 0xFFA07A,
'lightseagreen': 0x20B2AA,
'lightskyblue': 0x87CEFA,
'lightslategray': 0x778899,
'lightslategrey': 0x778899,
'lightsteelblue': 0xB0C4DE,
'lightyellow': 0xFFFFE0,
'lime': 0x00FF00,
'limegreen': 0x32CD32,
'linen': 0xFAF0E6,
'magenta': 0xFF00FF,
'maroon': 0x800000,
'mediumaquamarine': 0x66CDAA,
'mediumblue': 0x0000CD,
'mediumorchid': 0xBA55D3,
'mediumpurple': 0x9370DB,
'mediumseagreen': 0x3CB371,
'mediumslateblue': 0x7B68EE,
'mediumspringgreen': 0x00FA9A,
'mediumturquoise': 0x48D1CC,
'mediumvioletred': 0xC71585,
'midnightblue': 0x191970,
'mintcream': 0xF5FFFA,
'mistyrose': 0xFFE4E1,
'moccasin': 0xFFE4B5,
'navajowhite': 0xFFDEAD,
'navy': 0x000080,
'oldlace': 0xFDF5E6,
'olive': 0x808000,
'olivedrab': 0x6B8E23,
'orange': 0xFFA500,
'orangered': 0xFF4500,
'orchid': 0xDA70D6,
'palegoldenrod': 0xEEE8AA,
'palegreen': 0x98FB98,
'paleturquoise': 0xAFEEEE,
'palevioletred': 0xDB7093,
'papayawhip': 0xFFEFD5,
'peachpuff': 0xFFDAB9,
'peru': 0xCD853F,
'pink': 0xFFC0CB,
'plum': 0xDDA0DD,
'powderblue': 0xB0E0E6,
'purple': 0x800080,
'rebeccapurple': 0x663399,
'red': 0xFF0000,
'rosybrown': 0xBC8F8F,
'royalblue': 0x4169E1,
'saddlebrown': 0x8B4513,
'salmon': 0xFA8072,
'sandybrown': 0xF4A460,
'seagreen': 0x2E8B57,
'seashell': 0xFFF5EE,
'sienna': 0xA0522D,
'silver': 0xC0C0C0,
'skyblue': 0x87CEEB,
'slateblue': 0x6A5ACD,
'slategray': 0x708090,
'slategrey': 0x708090,
'snow': 0xFFFAFA,
'springgreen': 0x00FF7F,
'steelblue': 0x4682B4,
'tan': 0xD2B48C,
'teal': 0x008080,
'thistle': 0xD8BFD8,
'tomato': 0xFF6347,
'turquoise': 0x40E0D0,
'violet': 0xEE82EE,
'wheat': 0xF5DEB3,
'white': 0xFFFFFF,
'whitesmoke': 0xF5F5F5,
'yellow': 0xFFFF00,
'yellowgreen': 0x9ACD32
};
const _hslA = {
h: 0,
s: 0,
l: 0
};
const _hslB = {
h: 0,
s: 0,
l: 0
};
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * 6 * (2 / 3 - t);
return p;
}
function SRGBToLinear(c) {
return c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4);
}
function LinearToSRGB(c) {
return c < 0.0031308 ? c * 12.92 : 1.055 * Math.pow(c, 0.41666) - 0.055;
}
class Color {
constructor(r, g, b) {
Object.defineProperty(this, 'isColor', {
value: true
});
if (g === undefined && b === undefined) {
// r is THREE.Color, hex or string
return this.set(r);
}
return this.setRGB(r, g, b);
}
set(value) {
if (value && value.isColor) {
this.copy(value);
} else if (typeof value === 'number') {
this.setHex(value);
} else if (typeof value === 'string') {
this.setStyle(value);
}
return this;
}
setScalar(scalar) {
this.r = scalar;
this.g = scalar;
this.b = scalar;
return this;
}
setHex(hex) {
hex = Math.floor(hex);
this.r = (hex >> 16 & 255) / 255;
this.g = (hex >> 8 & 255) / 255;
this.b = (hex & 255) / 255;
return this;
}
setRGB(r, g, b) {
this.r = r;
this.g = g;
this.b = b;
return this;
}
setHSL(h, s, l) {
// h,s,l ranges are in 0.0 - 1.0
h = MathUtils.euclideanModulo(h, 1);
s = MathUtils.clamp(s, 0, 1);
l = MathUtils.clamp(l, 0, 1);
if (s === 0) {
this.r = this.g = this.b = l;
} else {
const p = l <= 0.5 ? l * (1 + s) : l + s - l * s;
const q = 2 * l - p;
this.r = hue2rgb(q, p, h + 1 / 3);
this.g = hue2rgb(q, p, h);
this.b = hue2rgb(q, p, h - 1 / 3);
}
return this;
}
setStyle(style) {
function handleAlpha(string) {
if (string === undefined) return;
if (parseFloat(string) < 1) {
console.warn('THREE.Color: Alpha component of ' + style + ' will be ignored.');
}
}
let m;
if (m = /^((?:rgb|hsl)a?)\(([^\)]*)\)/.exec(style)) {
// rgb / hsl
let color;
const name = m[1];
const components = m[2];
switch (name) {
case 'rgb':
case 'rgba':
if (color = /^\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) {
// rgb(255,0,0) rgba(255,0,0,0.5)
this.r = Math.min(255, parseInt(color[1], 10)) / 255;
this.g = Math.min(255, parseInt(color[2], 10)) / 255;
this.b = Math.min(255, parseInt(color[3], 10)) / 255;
handleAlpha(color[4]);
return this;
}
if (color = /^\s*(\d+)\%\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) {
// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)
this.r = Math.min(100, parseInt(color[1], 10)) / 100;
this.g = Math.min(100, parseInt(color[2], 10)) / 100;
this.b = Math.min(100, parseInt(color[3], 10)) / 100;
handleAlpha(color[4]);
return this;
}
break;
case 'hsl':
case 'hsla':
if (color = /^\s*(\d*\.?\d+)\s*,\s*(\d+)\%\s*,\s*(\d+)\%\s*(?:,\s*(\d*\.?\d+)\s*)?$/.exec(components)) {
// hsl(120,50%,50%) hsla(120,50%,50%,0.5)
const h = parseFloat(color[1]) / 360;
const s = parseInt(color[2], 10) / 100;
const l = parseInt(color[3], 10) / 100;
handleAlpha(color[4]);
return this.setHSL(h, s, l);
}
break;
}
} else if (m = /^\#([A-Fa-f\d]+)$/.exec(style)) {
// hex color
const hex = m[1];
const size = hex.length;
if (size === 3) {
// #ff0
this.r = parseInt(hex.charAt(0) + hex.charAt(0), 16) / 255;
this.g = parseInt(hex.charAt(1) + hex.charAt(1), 16) / 255;
this.b = parseInt(hex.charAt(2) + hex.charAt(2), 16) / 255;
return this;
} else if (size === 6) {
// #ff0000
this.r = parseInt(hex.charAt(0) + hex.charAt(1), 16) / 255;
this.g = parseInt(hex.charAt(2) + hex.charAt(3), 16) / 255;
this.b = parseInt(hex.charAt(4) + hex.charAt(5), 16) / 255;
return this;
}
}
if (style && style.length > 0) {
return this.setColorName(style);
}
return this;
}
setColorName(style) {
// color keywords
const hex = _colorKeywords[style];
if (hex !== undefined) {
// red
this.setHex(hex);
} else {
// unknown color
console.warn('THREE.Color: Unknown color ' + style);
}
return this;
}
clone() {
return new this.constructor(this.r, this.g, this.b);
}
copy(color) {
this.r = color.r;
this.g = color.g;
this.b = color.b;
return this;
}
copyGammaToLinear(color, gammaFactor = 2.0) {
this.r = Math.pow(color.r, gammaFactor);
this.g = Math.pow(color.g, gammaFactor);
this.b = Math.pow(color.b, gammaFactor);
return this;
}
copyLinearToGamma(color, gammaFactor = 2.0) {
const safeInverse = gammaFactor > 0 ? 1.0 / gammaFactor : 1.0;
this.r = Math.pow(color.r, safeInverse);
this.g = Math.pow(color.g, safeInverse);
this.b = Math.pow(color.b, safeInverse);
return this;
}
convertGammaToLinear(gammaFactor) {
this.copyGammaToLinear(this, gammaFactor);
return this;
}
convertLinearToGamma(gammaFactor) {
this.copyLinearToGamma(this, gammaFactor);
return this;
}
copySRGBToLinear(color) {
this.r = SRGBToLinear(color.r);
this.g = SRGBToLinear(color.g);
this.b = SRGBToLinear(color.b);
return this;
}
copyLinearToSRGB(color) {
this.r = LinearToSRGB(color.r);
this.g = LinearToSRGB(color.g);
this.b = LinearToSRGB(color.b);
return this;
}
convertSRGBToLinear() {
this.copySRGBToLinear(this);
return this;
}
convertLinearToSRGB() {
this.copyLinearToSRGB(this);
return this;
}
getHex() {
return this.r * 255 << 16 ^ this.g * 255 << 8 ^ this.b * 255 << 0;
}
getHexString() {
return ('000000' + this.getHex().toString(16)).slice(-6);
}
getHSL(target) {
// h,s,l ranges are in 0.0 - 1.0
if (target === undefined) {
console.warn('THREE.Color: .getHSL() target is now required');
target = {
h: 0,
s: 0,
l: 0
};
}
const r = this.r,
g = this.g,
b = this.b;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let hue, saturation;
const lightness = (min + max) / 2.0;
if (min === max) {
hue = 0;
saturation = 0;
} else {
const delta = max - min;
saturation = lightness <= 0.5 ? delta / (max + min) : delta / (2 - max - min);
switch (max) {
case r:
hue = (g - b) / delta + (g < b ? 6 : 0);
break;
case g:
hue = (b - r) / delta + 2;
break;
case b:
hue = (r - g) / delta + 4;
break;
}
hue /= 6;
}
target.h = hue;
target.s = saturation;
target.l = lightness;
return target;
}
getStyle() {
return 'rgb(' + (this.r * 255 | 0) + ',' + (this.g * 255 | 0) + ',' + (this.b * 255 | 0) + ')';
}
offsetHSL(h, s, l) {
this.getHSL(_hslA);
_hslA.h += h;
_hslA.s += s;
_hslA.l += l;
this.setHSL(_hslA.h, _hslA.s, _hslA.l);
return this;
}
add(color) {
this.r += color.r;
this.g += color.g;
this.b += color.b;
return this;
}
addColors(color1, color2) {
this.r = color1.r + color2.r;
this.g = color1.g + color2.g;
this.b = color1.b + color2.b;
return this;
}
addScalar(s) {
this.r += s;
this.g += s;
this.b += s;
return this;
}
sub(color) {
this.r = Math.max(0, this.r - color.r);
this.g = Math.max(0, this.g - color.g);
this.b = Math.max(0, this.b - color.b);
return this;
}
multiply(color) {
this.r *= color.r;
this.g *= color.g;
this.b *= color.b;
return this;
}
multiplyScalar(s) {
this.r *= s;
this.g *= s;
this.b *= s;
return this;
}
lerp(color, alpha) {
this.r += (color.r - this.r) * alpha;
this.g += (color.g - this.g) * alpha;
this.b += (color.b - this.b) * alpha;
return this;
}
lerpColors(color1, color2, alpha) {
this.r = color1.r + (color2.r - color1.r) * alpha;
this.g = color1.g + (color2.g - color1.g) * alpha;
this.b = color1.b + (color2.b - color1.b) * alpha;
return this;
}
lerpHSL(color, alpha) {
this.getHSL(_hslA);
color.getHSL(_hslB);
const h = MathUtils.lerp(_hslA.h, _hslB.h, alpha);
const s = MathUtils.lerp(_hslA.s, _hslB.s, alpha);
const l = MathUtils.lerp(_hslA.l, _hslB.l, alpha);
this.setHSL(h, s, l);
return this;
}
equals(c) {
return c.r === this.r && c.g === this.g && c.b === this.b;
}
fromArray(array, offset = 0) {
this.r = array[offset];
this.g = array[offset + 1];
this.b = array[offset + 2];
return this;
}
toArray(array = [], offset = 0) {
array[offset] = this.r;
array[offset + 1] = this.g;
array[offset + 2] = this.b;
return array;
}
fromBufferAttribute(attribute, index) {
this.r = attribute.getX(index);
this.g = attribute.getY(index);
this.b = attribute.getZ(index);
if (attribute.normalized === true) {
// assuming Uint8Array
this.r /= 255;
this.g /= 255;
this.b /= 255;
}
return this;
}
toJSON() {
return this.getHex();
}
}
Color.NAMES = _colorKeywords;
Color.prototype.r = 1;
Color.prototype.g = 1;
Color.prototype.b = 1;
class Face3 {
constructor(a, b, c, normal, color, materialIndex = 0) {
this.a = a;
this.b = b;
this.c = c;
this.normal = normal && normal.isVector3 ? normal : new Vector3();
this.vertexNormals = Array.isArray(normal) ? normal : [];
this.color = color && color.isColor ? color : new Color();
this.vertexColors = Array.isArray(color) ? color : [];
this.materialIndex = materialIndex;
}
clone() {
return new this.constructor().copy(this);
}
copy(source) {
this.a = source.a;
this.b = source.b;
this.c = source.c;
this.normal.copy(source.normal);
this.color.copy(source.color);
this.materialIndex = source.materialIndex;
for (let i = 0, il = source.vertexNormals.length; i < il; i++) {
this.vertexNormals[i] = source.vertexNormals[i].clone();
}
for (let i = 0, il = source.vertexColors.length; i < il; i++) {
this.vertexColors[i] = source.vertexColors[i].clone();
}
return this;
}
}
let materialId = 0;
function Material() {
Object.defineProperty(this, 'id', {
value: materialId++
});
this.uuid = MathUtils.generateUUID();
this.name = '';
this.type = 'Material';
this.fog = true;
this.blending = NormalBlending;
this.side = FrontSide;
this.flatShading = false;
this.vertexColors = false;
this.opacity = 1;
this.transparent = false;
this.blendSrc = SrcAlphaFactor;
this.blendDst = OneMinusSrcAlphaFactor;
this.blendEquation = AddEquation;
this.blendSrcAlpha = null;
this.blendDstAlpha = null;
this.blendEquationAlpha = null;
this.depthFunc = LessEqualDepth;
this.depthTest = true;
this.depthWrite = true;
this.stencilWriteMask = 0xff;
this.stencilFunc = AlwaysStencilFunc;
this.stencilRef = 0;
this.stencilFuncMask = 0xff;
this.stencilFail = KeepStencilOp;
this.stencilZFail = KeepStencilOp;
this.stencilZPass = KeepStencilOp;
this.stencilWrite = false;
this.clippingPlanes = null;
this.clipIntersection = false;
this.clipShadows = false;
this.shadowSide = null;
this.colorWrite = true;
this.precision = null; // override the renderer's default precision for this material
this.polygonOffset = false;
this.polygonOffsetFactor = 0;
this.polygonOffsetUnits = 0;
this.dithering = false;
this.alphaTest = 0;
this.premultipliedAlpha = false;
this.visible = true;
this.toneMapped = true;
this.userData = {};
this.version = 0;
}
Material.prototype = _extends(Object.create(EventDispatcher.prototype), {
constructor: Material,
isMaterial: true,
onBeforeCompile: function /* shaderobject, renderer */ () {},
customProgramCacheKey: function () {
return this.onBeforeCompile.toString();
},
setValues: function (values) {
if (values === undefined) return;
for (const key in values) {
const newValue = values[key];
if (newValue === undefined) {
console.warn('THREE.Material: \'' + key + '\' parameter is undefined.');
continue;
}
// for backward compatability if shading is set in the constructor
if (key === 'shading') {
console.warn('THREE.' + this.type + ': .shading has been removed. Use the boolean .flatShading instead.');
this.flatShading = newValue === FlatShading ? true : false;
continue;
}
const currentValue = this[key];
if (currentValue === undefined) {
console.warn('THREE.' + this.type + ': \'' + key + '\' is not a property of this material.');
continue;
}
if (currentValue && currentValue.isColor) {
currentValue.set(newValue);
} else if (currentValue && currentValue.isVector3 && newValue && newValue.isVector3) {
currentValue.copy(newValue);
} else {
this[key] = newValue;
}
}
},
toJSON: function (meta) {
const isRoot = meta === undefined || typeof meta === 'string';
if (isRoot) {
meta = {
textures: {},
images: {}
};
}
const data = {
metadata: {
version: 4.5,
type: 'Material',
generator: 'Material.toJSON'
}
};
// standard Material serialization
data.uuid = this.uuid;
data.type = this.type;
if (this.name !== '') data.name = this.name;
if (this.color && this.color.isColor) data.color = this.color.getHex();
if (this.roughness !== undefined) data.roughness = this.roughness;
if (this.metalness !== undefined) data.metalness = this.metalness;
if (this.sheen && this.sheen.isColor) data.sheen = this.sheen.getHex();
if (this.emissive && this.emissive.isColor) data.emissive = this.emissive.getHex();
if (this.emissiveIntensity && this.emissiveIntensity !== 1) data.emissiveIntensity = this.emissiveIntensity;
if (this.specular && this.specular.isColor) data.specular = this.specular.getHex();
if (this.shininess !== undefined) data.shininess = this.shininess;
if (this.clearcoat !== undefined) data.clearcoat = this.clearcoat;
if (this.clearcoatRoughness !== undefined) data.clearcoatRoughness = this.clearcoatRoughness;
if (this.clearcoatMap && this.clearcoatMap.isTexture) {
data.clearcoatMap = this.clearcoatMap.toJSON(meta).uuid;
}
if (this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture) {
data.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON(meta).uuid;
}
if (this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture) {
data.clearcoatNormalMap = this.clearcoatNormalMap.toJSON(meta).uuid;
data.clearcoatNormalScale = this.clearcoatNormalScale.toArray();
}
if (this.map && this.map.isTexture) data.map = this.map.toJSON(meta).uuid;
if (this.matcap && this.matcap.isTexture) data.matcap = this.matcap.toJSON(meta).uuid;
if (this.alphaMap && this.alphaMap.isTexture) data.alphaMap = this.alphaMap.toJSON(meta).uuid;
if (this.lightMap && this.lightMap.isTexture) data.lightMap = this.lightMap.toJSON(meta).uuid;
if (this.aoMap && this.aoMap.isTexture) {
data.aoMap = this.aoMap.toJSON(meta).uuid;
data.aoMapIntensity = this.aoMapIntensity;
}
if (this.bumpMap && this.bumpMap.isTexture) {
data.bumpMap = this.bumpMap.toJSON(meta).uuid;
data.bumpScale = this.bumpScale;
}
if (this.normalMap && this.normalMap.isTexture) {
data.normalMap = this.normalMap.toJSON(meta).uuid;
data.normalMapType = this.normalMapType;
data.normalScale = this.normalScale.toArray();
}
if (this.displacementMap && this.displacementMap.isTexture) {
data.displacementMap = this.displacementMap.toJSON(meta).uuid;
data.displacementScale = this.displacementScale;
data.displacementBias = this.displacementBias;
}
if (this.roughnessMap && this.roughnessMap.isTexture) data.roughnessMap = this.roughnessMap.toJSON(meta).uuid;
if (this.metalnessMap && this.metalnessMap.isTexture) data.metalnessMap = this.metalnessMap.toJSON(meta).uuid;
if (this.emissiveMap && this.emissiveMap.isTexture) data.emissiveMap = this.emissiveMap.toJSON(meta).uuid;
if (this.specularMap && this.specularMap.isTexture) data.specularMap = this.specularMap.toJSON(meta).uuid;
if (this.envMap && this.envMap.isTexture) {
data.envMap = this.envMap.toJSON(meta).uuid;
data.reflectivity = this.reflectivity; // Scale behind envMap
data.refractionRatio = this.refractionRatio;
if (this.combine !== undefined) data.combine = this.combine;
if (this.envMapIntensity !== undefined) data.envMapIntensity = this.envMapIntensity;
}
if (this.gradientMap && this.gradientMap.isTexture) {
data.gradientMap = this.gradientMap.toJSON(meta).uuid;
}
if (this.size !== undefined) data.size = this.size;
if (this.sizeAttenuation !== undefined) data.sizeAttenuation = this.sizeAttenuation;
if (this.blending !== NormalBlending) data.blending = this.blending;
if (this.flatShading === true) data.flatShading = this.flatShading;
if (this.side !== FrontSide) data.side = this.side;
if (this.vertexColors) data.vertexColors = true;
if (this.opacity < 1) data.opacity = this.opacity;
if (this.transparent === true) data.transparent = this.transparent;
data.depthFunc = this.depthFunc;
data.depthTest = this.depthTest;
data.depthWrite = this.depthWrite;
data.stencilWrite = this.stencilWrite;
data.stencilWriteMask = this.stencilWriteMask;
data.stencilFunc = this.stencilFunc;
data.stencilRef = this.stencilRef;
data.stencilFuncMask = this.stencilFuncMask;
data.stencilFail = this.stencilFail;
data.stencilZFail = this.stencilZFail;
data.stencilZPass = this.stencilZPass;
// rotation (SpriteMaterial)
if (this.rotation && this.rotation !== 0) data.rotation = this.rotation;
if (this.polygonOffset === true) data.polygonOffset = true;
if (this.polygonOffsetFactor !== 0) data.polygonOffsetFactor = this.polygonOffsetFactor;
if (this.polygonOffsetUnits !== 0) data.polygonOffsetUnits = this.polygonOffsetUnits;
if (this.linewidth && this.linewidth !== 1) data.linewidth = this.linewidth;
if (this.dashSize !== undefined) data.dashSize = this.dashSize;
if (this.gapSize !== undefined) data.gapSize = this.gapSize;
if (this.scale !== undefined) data.scale = this.scale;
if (this.dithering === true) data.dithering = true;
if (this.alphaTest > 0) data.alphaTest = this.alphaTest;
if (this.premultipliedAlpha === true) data.premultipliedAlpha = this.premultipliedAlpha;
if (this.wireframe === true) data.wireframe = this.wireframe;
if (this.wireframeLinewidth > 1) data.wireframeLinewidth = this.wireframeLinewidth;
if (this.wireframeLinecap !== 'round') data.wireframeLinecap = this.wireframeLinecap;
if (this.wireframeLinejoin !== 'round') data.wireframeLinejoin = this.wireframeLinejoin;
if (this.morphTargets === true) data.morphTargets = true;
if (this.morphNormals === true) data.morphNormals = true;
if (this.skinning === true) data.skinning = true;
if (this.visible === false) data.visible = false;
if (this.toneMapped === false) data.toneMapped = false;
if (JSON.stringify(this.userData) !== '{}') data.userData = this.userData;
// TODO: Copied from Object3D.toJSON
function extractFromCache(cache) {
const values = [];
for (const key in cache) {
const data = cache[key];
delete data.metadata;
values.push(data);
}
return values;
}
if (isRoot) {
const textures = extractFromCache(meta.textures);
const images = extractFromCache(meta.images);
if (textures.length > 0) data.textures = textures;
if (images.length > 0) data.images = images;
}
return data;
},
clone: function () {
return new this.constructor().copy(this);
},
copy: function (source) {
this.name = source.name;
this.fog = source.fog;
this.blending = source.blending;
this.side = source.side;
this.flatShading = source.flatShading;
this.vertexColors = source.vertexColors;
this.opacity = source.opacity;
this.transparent = source.transparent;
this.blendSrc = source.blendSrc;
this.blendDst = source.blendDst;
this.blendEquation = source.blendEquation;
this.blendSrcAlpha = source.blendSrcAlpha;
this.blendDstAlpha = source.blendDstAlpha;
this.blendEquationAlpha = source.blendEquationAlpha;
this.depthFunc = source.depthFunc;
this.depthTest = source.depthTest;
this.depthWrite = source.depthWrite;
this.stencilWriteMask = source.stencilWriteMask;
this.stencilFunc = source.stencilFunc;
this.stencilRef = source.stencilRef;
this.stencilFuncMask = source.stencilFuncMask;
this.stencilFail = source.stencilFail;
this.stencilZFail = source.stencilZFail;
this.stencilZPass = source.stencilZPass;
this.stencilWrite = source.stencilWrite;
const srcPlanes = source.clippingPlanes;
let dstPlanes = null;
if (srcPlanes !== null) {
const n = srcPlanes.length;
dstPlanes = new Array(n);
for (let i = 0; i !== n; ++i) {
dstPlanes[i] = srcPlanes[i].clone();
}
}
this.clippingPlanes = dstPlanes;
this.clipIntersection = source.clipIntersection;
this.clipShadows = source.clipShadows;
this.shadowSide = source.shadowSide;
this.colorWrite = source.colorWrite;
this.precision = source.precision;
this.polygonOffset = source.polygonOffset;
this.polygonOffsetFactor = source.polygonOffsetFactor;
this.polygonOffsetUnits = source.polygonOffsetUnits;
this.dithering = source.dithering;
this.alphaTest = source.alphaTest;
this.premultipliedAlpha = source.premultipliedAlpha;
this.visible = source.visible;
this.toneMapped = source.toneMapped;
this.userData = JSON.parse(JSON.stringify(source.userData));
return this;
},
dispose: function () {
this.dispatchEvent({
type: 'dispose'
});
}
});
Object.defineProperty(Material.prototype, 'needsUpdate', {
set: function (value) {
if (value === true) this.version++;
}
});
/**
* parameters = {
* color: ,
* opacity: ,
* map: new THREE.Texture( ),
*
* lightMap: new THREE.Texture( ),
* lightMapIntensity:
*
* aoMap: new THREE.Texture( ),
* aoMapIntensity:
*
* specularMap: new THREE.Texture( ),
*
* alphaMap: new THREE.Texture( ),
*
* envMap: new THREE.CubeTexture( [posx, negx, posy, negy, posz, negz] ),
* combine: THREE.Multiply,
* reflectivity: ,
* refractionRatio: ,
*
* depthTest: ,
* depthWrite: ,
*
* wireframe: ,
* wireframeLinewidth: ,
*
* skinning: ,
* morphTargets:
* }
*/
function MeshBasicMaterial(parameters) {
Material.call(this);
this.type = 'MeshBasicMaterial';
this.color = new Color(0xffffff); // emissive
this.map = null;
this.lightMap = null;
this.lightMapIntensity = 1.0;
this.aoMap = null;
this.aoMapIntensity = 1.0;
this.specularMap = null;
this.alphaMap = null;
this.envMap = null;
this.combine = MultiplyOperation;
this.reflectivity = 1;
this.refractionRatio = 0.98;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.wireframeLinecap = 'round';
this.wireframeLinejoin = 'round';
this.skinning = false;
this.morphTargets = false;
this.setValues(parameters);
}
MeshBasicMaterial.prototype = Object.create(Material.prototype);
MeshBasicMaterial.prototype.constructor = MeshBasicMaterial;
MeshBasicMaterial.prototype.isMeshBasicMaterial = true;
MeshBasicMaterial.prototype.copy = function (source) {
Material.prototype.copy.call(this, source);
this.color.copy(source.color);
this.map = source.map;
this.lightMap = source.lightMap;
this.lightMapIntensity = source.lightMapIntensity;
this.aoMap = source.aoMap;
this.aoMapIntensity = source.aoMapIntensity;
this.specularMap = source.specularMap;
this.alphaMap = source.alphaMap;
this.envMap = source.envMap;
this.combine = source.combine;
this.reflectivity = source.reflectivity;
this.refractionRatio = source.refractionRatio;
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.wireframeLinecap = source.wireframeLinecap;
this.wireframeLinejoin = source.wireframeLinejoin;
this.skinning = source.skinning;
this.morphTargets = source.morphTargets;
return this;
};
const _vector$3 = new Vector3();
const _vector2$1 = new Vector2();
function BufferAttribute(array, itemSize, normalized) {
if (Array.isArray(array)) {
throw new TypeError('THREE.BufferAttribute: array should be a Typed Array.');
}
this.name = '';
this.array = array;
this.itemSize = itemSize;
this.count = array !== undefined ? array.length / itemSize : 0;
this.normalized = normalized === true;
this.usage = StaticDrawUsage;
this.updateRange = {
offset: 0,
count: -1
};
this.version = 0;
}
Object.defineProperty(BufferAttribute.prototype, 'needsUpdate', {
set: function (value) {
if (value === true) this.version++;
}
});
_extends(BufferAttribute.prototype, {
isBufferAttribute: true,
onUploadCallback: function () {},
setUsage: function (value) {
this.usage = value;
return this;
},
copy: function (source) {
this.name = source.name;
this.array = new source.array.constructor(source.array);
this.itemSize = source.itemSize;
this.count = source.count;
this.normalized = source.normalized;
this.usage = source.usage;
return this;
},
copyAt: function (index1, attribute, index2) {
index1 *= this.itemSize;
index2 *= attribute.itemSize;
for (let i = 0, l = this.itemSize; i < l; i++) {
this.array[index1 + i] = attribute.array[index2 + i];
}
return this;
},
copyArray: function (array) {
this.array.set(array);
return this;
},
copyColorsArray: function (colors) {
const array = this.array;
let offset = 0;
for (let i = 0, l = colors.length; i < l; i++) {
let color = colors[i];
if (color === undefined) {
console.warn('THREE.BufferAttribute.copyColorsArray(): color is undefined', i);
color = new Color();
}
array[offset++] = color.r;
array[offset++] = color.g;
array[offset++] = color.b;
}
return this;
},
copyVector2sArray: function (vectors) {
const array = this.array;
let offset = 0;
for (let i = 0, l = vectors.length; i < l; i++) {
let vector = vectors[i];
if (vector === undefined) {
console.warn('THREE.BufferAttribute.copyVector2sArray(): vector is undefined', i);
vector = new Vector2();
}
array[offset++] = vector.x;
array[offset++] = vector.y;
}
return this;
},
copyVector3sArray: function (vectors) {
const array = this.array;
let offset = 0;
for (let i = 0, l = vectors.length; i < l; i++) {
let vector = vectors[i];
if (vector === undefined) {
console.warn('THREE.BufferAttribute.copyVector3sArray(): vector is undefined', i);
vector = new Vector3();
}
array[offset++] = vector.x;
array[offset++] = vector.y;
array[offset++] = vector.z;
}
return this;
},
copyVector4sArray: function (vectors) {
const array = this.array;
let offset = 0;
for (let i = 0, l = vectors.length; i < l; i++) {
let vector = vectors[i];
if (vector === undefined) {
console.warn('THREE.BufferAttribute.copyVector4sArray(): vector is undefined', i);
vector = new Vector4();
}
array[offset++] = vector.x;
array[offset++] = vector.y;
array[offset++] = vector.z;
array[offset++] = vector.w;
}
return this;
},
applyMatrix3: function (m) {
if (this.itemSize === 2) {
for (let i = 0, l = this.count; i < l; i++) {
_vector2$1.fromBufferAttribute(this, i);
_vector2$1.applyMatrix3(m);
this.setXY(i, _vector2$1.x, _vector2$1.y);
}
} else if (this.itemSize === 3) {
for (let i = 0, l = this.count; i < l; i++) {
_vector$3.fromBufferAttribute(this, i);
_vector$3.applyMatrix3(m);
this.setXYZ(i, _vector$3.x, _vector$3.y, _vector$3.z);
}
}
return this;
},
applyMatrix4: function (m) {
for (let i = 0, l = this.count; i < l; i++) {
_vector$3.x = this.getX(i);
_vector$3.y = this.getY(i);
_vector$3.z = this.getZ(i);
_vector$3.applyMatrix4(m);
this.setXYZ(i, _vector$3.x, _vector$3.y, _vector$3.z);
}
return this;
},
applyNormalMatrix: function (m) {
for (let i = 0, l = this.count; i < l; i++) {
_vector$3.x = this.getX(i);
_vector$3.y = this.getY(i);
_vector$3.z = this.getZ(i);
_vector$3.applyNormalMatrix(m);
this.setXYZ(i, _vector$3.x, _vector$3.y, _vector$3.z);
}
return this;
},
transformDirection: function (m) {
for (let i = 0, l = this.count; i < l; i++) {
_vector$3.x = this.getX(i);
_vector$3.y = this.getY(i);
_vector$3.z = this.getZ(i);
_vector$3.transformDirection(m);
this.setXYZ(i, _vector$3.x, _vector$3.y, _vector$3.z);
}
return this;
},
set: function (value, offset = 0) {
this.array.set(value, offset);
return this;
},
getX: function (index) {
return this.array[index * this.itemSize];
},
setX: function (index, x) {
this.array[index * this.itemSize] = x;
return this;
},
getY: function (index) {
return this.array[index * this.itemSize + 1];
},
setY: function (index, y) {
this.array[index * this.itemSize + 1] = y;
return this;
},
getZ: function (index) {
return this.array[index * this.itemSize + 2];
},
setZ: function (index, z) {
this.array[index * this.itemSize + 2] = z;
return this;
},
getW: function (index) {
return this.array[index * this.itemSize + 3];
},
setW: function (index, w) {
this.array[index * this.itemSize + 3] = w;
return this;
},
setXY: function (index, x, y) {
index *= this.itemSize;
this.array[index + 0] = x;
this.array[index + 1] = y;
return this;
},
setXYZ: function (index, x, y, z) {
index *= this.itemSize;
this.array[index + 0] = x;
this.array[index + 1] = y;
this.array[index + 2] = z;
return this;
},
setXYZW: function (index, x, y, z, w) {
index *= this.itemSize;
this.array[index + 0] = x;
this.array[index + 1] = y;
this.array[index + 2] = z;
this.array[index + 3] = w;
return this;
},
onUpload: function (callback) {
this.onUploadCallback = callback;
return this;
},
clone: function () {
return new this.constructor(this.array, this.itemSize).copy(this);
},
toJSON: function () {
return {
itemSize: this.itemSize,
type: this.array.constructor.name,
array: Array.prototype.slice.call(this.array),
normalized: this.normalized
};
}
});
//
function Int8BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Int8Array(array), itemSize, normalized);
}
Int8BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Int8BufferAttribute.prototype.constructor = Int8BufferAttribute;
function Uint8BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Uint8Array(array), itemSize, normalized);
}
Uint8BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Uint8BufferAttribute.prototype.constructor = Uint8BufferAttribute;
function Uint8ClampedBufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Uint8ClampedArray(array), itemSize, normalized);
}
Uint8ClampedBufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Uint8ClampedBufferAttribute.prototype.constructor = Uint8ClampedBufferAttribute;
function Int16BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Int16Array(array), itemSize, normalized);
}
Int16BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Int16BufferAttribute.prototype.constructor = Int16BufferAttribute;
function Uint16BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Uint16Array(array), itemSize, normalized);
}
Uint16BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Uint16BufferAttribute.prototype.constructor = Uint16BufferAttribute;
function Int32BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Int32Array(array), itemSize, normalized);
}
Int32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Int32BufferAttribute.prototype.constructor = Int32BufferAttribute;
function Uint32BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Uint32Array(array), itemSize, normalized);
}
Uint32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Uint32BufferAttribute.prototype.constructor = Uint32BufferAttribute;
function Float16BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Uint16Array(array), itemSize, normalized);
}
Float16BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Float16BufferAttribute.prototype.constructor = Float16BufferAttribute;
Float16BufferAttribute.prototype.isFloat16BufferAttribute = true;
function Float32BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Float32Array(array), itemSize, normalized);
}
Float32BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Float32BufferAttribute.prototype.constructor = Float32BufferAttribute;
function Float64BufferAttribute(array, itemSize, normalized) {
BufferAttribute.call(this, new Float64Array(array), itemSize, normalized);
}
Float64BufferAttribute.prototype = Object.create(BufferAttribute.prototype);
Float64BufferAttribute.prototype.constructor = Float64BufferAttribute;
function arrayMax(array) {
if (array.length === 0) return -Infinity;
let max = array[0];
for (let i = 1, l = array.length; i < l; ++i) {
if (array[i] > max) max = array[i];
}
return max;
}
const TYPED_ARRAYS = {
Int8Array: Int8Array,
Uint8Array: Uint8Array,
// Workaround for IE11 pre KB2929437. See #11440
Uint8ClampedArray: typeof Uint8ClampedArray !== 'undefined' ? Uint8ClampedArray : Uint8Array,
Int16Array: Int16Array,
Uint16Array: Uint16Array,
Int32Array: Int32Array,
Uint32Array: Uint32Array,
Float32Array: Float32Array,
Float64Array: Float64Array
};
function getTypedArray(type, buffer) {
return new TYPED_ARRAYS[type](buffer);
}
let _id = 0;
const _m1$2 = new Matrix4();
const _obj = new Object3D();
const _offset = new Vector3();
const _box$2 = new Box3();
const _boxMorphTargets = new Box3();
const _vector$4 = new Vector3();
function BufferGeometry() {
Object.defineProperty(this, 'id', {
value: _id++
});
this.uuid = MathUtils.generateUUID();
this.name = '';
this.type = 'BufferGeometry';
this.index = null;
this.attributes = {};
this.morphAttributes = {};
this.morphTargetsRelative = false;
this.groups = [];
this.boundingBox = null;
this.boundingSphere = null;
this.drawRange = {
start: 0,
count: Infinity
};
this.userData = {};
}
BufferGeometry.prototype = _extends(Object.create(EventDispatcher.prototype), {
constructor: BufferGeometry,
isBufferGeometry: true,
getIndex: function () {
return this.index;
},
setIndex: function (index) {
if (Array.isArray(index)) {
this.index = new (arrayMax(index) > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute)(index, 1);
} else {
this.index = index;
}
return this;
},
getAttribute: function (name) {
return this.attributes[name];
},
setAttribute: function (name, attribute) {
this.attributes[name] = attribute;
return this;
},
deleteAttribute: function (name) {
delete this.attributes[name];
return this;
},
hasAttribute: function (name) {
return this.attributes[name] !== undefined;
},
addGroup: function (start, count, materialIndex = 0) {
this.groups.push({
start: start,
count: count,
materialIndex: materialIndex
});
},
clearGroups: function () {
this.groups = [];
},
setDrawRange: function (start, count) {
this.drawRange.start = start;
this.drawRange.count = count;
},
applyMatrix4: function (matrix) {
const position = this.attributes.position;
if (position !== undefined) {
position.applyMatrix4(matrix);
position.needsUpdate = true;
}
const normal = this.attributes.normal;
if (normal !== undefined) {
const normalMatrix = new Matrix3().getNormalMatrix(matrix);
normal.applyNormalMatrix(normalMatrix);
normal.needsUpdate = true;
}
const tangent = this.attributes.tangent;
if (tangent !== undefined) {
tangent.transformDirection(matrix);
tangent.needsUpdate = true;
}
if (this.boundingBox !== null) {
this.computeBoundingBox();
}
if (this.boundingSphere !== null) {
this.computeBoundingSphere();
}
return this;
},
rotateX: function (angle) {
// rotate geometry around world x-axis
_m1$2.makeRotationX(angle);
this.applyMatrix4(_m1$2);
return this;
},
rotateY: function (angle) {
// rotate geometry around world y-axis
_m1$2.makeRotationY(angle);
this.applyMatrix4(_m1$2);
return this;
},
rotateZ: function (angle) {
// rotate geometry around world z-axis
_m1$2.makeRotationZ(angle);
this.applyMatrix4(_m1$2);
return this;
},
translate: function (x, y, z) {
// translate geometry
_m1$2.makeTranslation(x, y, z);
this.applyMatrix4(_m1$2);
return this;
},
scale: function (x, y, z) {
// scale geometry
_m1$2.makeScale(x, y, z);
this.applyMatrix4(_m1$2);
return this;
},
lookAt: function (vector) {
_obj.lookAt(vector);
_obj.updateMatrix();
this.applyMatrix4(_obj.matrix);
return this;
},
center: function () {
this.computeBoundingBox();
this.boundingBox.getCenter(_offset).negate();
this.translate(_offset.x, _offset.y, _offset.z);
return this;
},
setFromPoints: function (points) {
const position = [];
for (let i = 0, l = points.length; i < l; i++) {
const point = points[i];
position.push(point.x, point.y, point.z || 0);
}
this.setAttribute('position', new Float32BufferAttribute(position, 3));
return this;
},
computeBoundingBox: function () {
if (this.boundingBox === null) {
this.boundingBox = new Box3();
}
const position = this.attributes.position;
const morphAttributesPosition = this.morphAttributes.position;
if (position && position.isGLBufferAttribute) {
console.error('THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box. Alternatively set "mesh.frustumCulled" to "false".', this);
this.boundingBox.set(new Vector3(-Infinity, -Infinity, -Infinity), new Vector3(+Infinity, +Infinity, +Infinity));
return;
}
if (position !== undefined) {
this.boundingBox.setFromBufferAttribute(position);
// process morph attributes if present
if (morphAttributesPosition) {
for (let i = 0, il = morphAttributesPosition.length; i < il; i++) {
const morphAttribute = morphAttributesPosition[i];
_box$2.setFromBufferAttribute(morphAttribute);
if (this.morphTargetsRelative) {
_vector$4.addVectors(this.boundingBox.min, _box$2.min);
this.boundingBox.expandByPoint(_vector$4);
_vector$4.addVectors(this.boundingBox.max, _box$2.max);
this.boundingBox.expandByPoint(_vector$4);
} else {
this.boundingBox.expandByPoint(_box$2.min);
this.boundingBox.expandByPoint(_box$2.max);
}
}
}
} else {
this.boundingBox.makeEmpty();
}
if (isNaN(this.boundingBox.min.x) || isNaN(this.boundingBox.min.y) || isNaN(this.boundingBox.min.z)) {
console.error('THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The "position" attribute is likely to have NaN values.', this);
}
},
computeBoundingSphere: function () {
if (this.boundingSphere === null) {
this.boundingSphere = new Sphere();
}
const position = this.attributes.position;
const morphAttributesPosition = this.morphAttributes.position;
if (position && position.isGLBufferAttribute) {
console.error('THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere. Alternatively set "mesh.frustumCulled" to "false".', this);
this.boundingSphere.set(new Vector3(), Infinity);
return;
}
if (position) {
// first, find the center of the bounding sphere
const center = this.boundingSphere.center;
_box$2.setFromBufferAttribute(position);
// process morph attributes if present
if (morphAttributesPosition) {
for (let i = 0, il = morphAttributesPosition.length; i < il; i++) {
const morphAttribute = morphAttributesPosition[i];
_boxMorphTargets.setFromBufferAttribute(morphAttribute);
if (this.morphTargetsRelative) {
_vector$4.addVectors(_box$2.min, _boxMorphTargets.min);
_box$2.expandByPoint(_vector$4);
_vector$4.addVectors(_box$2.max, _boxMorphTargets.max);
_box$2.expandByPoint(_vector$4);
} else {
_box$2.expandByPoint(_boxMorphTargets.min);
_box$2.expandByPoint(_boxMorphTargets.max);
}
}
}
_box$2.getCenter(center);
// second, try to find a boundingSphere with a radius smaller than the
// boundingSphere of the boundingBox: sqrt(3) smaller in the best case
let maxRadiusSq = 0;
for (let i = 0, il = position.count; i < il; i++) {
_vector$4.fromBufferAttribute(position, i);
maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$4));
}
// process morph attributes if present
if (morphAttributesPosition) {
for (let i = 0, il = morphAttributesPosition.length; i < il; i++) {
const morphAttribute = morphAttributesPosition[i];
const morphTargetsRelative = this.morphTargetsRelative;
for (let j = 0, jl = morphAttribute.count; j < jl; j++) {
_vector$4.fromBufferAttribute(morphAttribute, j);
if (morphTargetsRelative) {
_offset.fromBufferAttribute(position, j);
_vector$4.add(_offset);
}
maxRadiusSq = Math.max(maxRadiusSq, center.distanceToSquared(_vector$4));
}
}
}
this.boundingSphere.radius = Math.sqrt(maxRadiusSq);
if (isNaN(this.boundingSphere.radius)) {
console.error('THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.', this);
}
}
},
computeFaceNormals: function () {
// backwards compatibility
},
computeTangents: function () {
const index = this.index;
const attributes = this.attributes;
// based on http://www.terathon.com/code/tangent.html
// (per vertex tangents)
if (index === null || attributes.position === undefined || attributes.normal === undefined || attributes.uv === undefined) {
console.error('THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)');
return;
}
const indices = index.array;
const positions = attributes.position.array;
const normals = attributes.normal.array;
const uvs = attributes.uv.array;
const nVertices = positions.length / 3;
if (attributes.tangent === undefined) {
this.setAttribute('tangent', new BufferAttribute(new Float32Array(4 * nVertices), 4));
}
const tangents = attributes.tangent.array;
const tan1 = [],
tan2 = [];
for (let i = 0; i < nVertices; i++) {
tan1[i] = new Vector3();
tan2[i] = new Vector3();
}
const vA = new Vector3(),
vB = new Vector3(),
vC = new Vector3(),
uvA = new Vector2(),
uvB = new Vector2(),
uvC = new Vector2(),
sdir = new Vector3(),
tdir = new Vector3();
function handleTriangle(a, b, c) {
vA.fromArray(positions, a * 3);
vB.fromArray(positions, b * 3);
vC.fromArray(positions, c * 3);
uvA.fromArray(uvs, a * 2);
uvB.fromArray(uvs, b * 2);
uvC.fromArray(uvs, c * 2);
vB.sub(vA);
vC.sub(vA);
uvB.sub(uvA);
uvC.sub(uvA);
const r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y);
// silently ignore degenerate uv triangles having coincident or colinear vertices
if (!isFinite(r)) return;
sdir.copy(vB).multiplyScalar(uvC.y).addScaledVector(vC, -uvB.y).multiplyScalar(r);
tdir.copy(vC).multiplyScalar(uvB.x).addScaledVector(vB, -uvC.x).multiplyScalar(r);
tan1[a].add(sdir);
tan1[b].add(sdir);
tan1[c].add(sdir);
tan2[a].add(tdir);
tan2[b].add(tdir);
tan2[c].add(tdir);
}
let groups = this.groups;
if (groups.length === 0) {
groups = [{
start: 0,
count: indices.length
}];
}
for (let i = 0, il = groups.length; i < il; ++i) {
const group = groups[i];
const start = group.start;
const count = group.count;
for (let j = start, jl = start + count; j < jl; j += 3) {
handleTriangle(indices[j + 0], indices[j + 1], indices[j + 2]);
}
}
const tmp = new Vector3(),
tmp2 = new Vector3();
const n = new Vector3(),
n2 = new Vector3();
function handleVertex(v) {
n.fromArray(normals, v * 3);
n2.copy(n);
const t = tan1[v];
// Gram-Schmidt orthogonalize
tmp.copy(t);
tmp.sub(n.multiplyScalar(n.dot(t))).normalize();
// Calculate handedness
tmp2.crossVectors(n2, t);
const test = tmp2.dot(tan2[v]);
const w = test < 0.0 ? -1.0 : 1.0;
tangents[v * 4] = tmp.x;
tangents[v * 4 + 1] = tmp.y;
tangents[v * 4 + 2] = tmp.z;
tangents[v * 4 + 3] = w;
}
for (let i = 0, il = groups.length; i < il; ++i) {
const group = groups[i];
const start = group.start;
const count = group.count;
for (let j = start, jl = start + count; j < jl; j += 3) {
handleVertex(indices[j + 0]);
handleVertex(indices[j + 1]);
handleVertex(indices[j + 2]);
}
}
},
computeVertexNormals: function () {
const index = this.index;
const positionAttribute = this.getAttribute('position');
if (positionAttribute !== undefined) {
let normalAttribute = this.getAttribute('normal');
if (normalAttribute === undefined) {
normalAttribute = new BufferAttribute(new Float32Array(positionAttribute.count * 3), 3);
this.setAttribute('normal', normalAttribute);
} else {
// reset existing normals to zero
for (let i = 0, il = normalAttribute.count; i < il; i++) {
normalAttribute.setXYZ(i, 0, 0, 0);
}
}
const pA = new Vector3(),
pB = new Vector3(),
pC = new Vector3();
const nA = new Vector3(),
nB = new Vector3(),
nC = new Vector3();
const cb = new Vector3(),
ab = new Vector3();
// indexed elements
if (index) {
for (let i = 0, il = index.count; i < il; i += 3) {
const vA = index.getX(i + 0);
const vB = index.getX(i + 1);
const vC = index.getX(i + 2);
pA.fromBufferAttribute(positionAttribute, vA);
pB.fromBufferAttribute(positionAttribute, vB);
pC.fromBufferAttribute(positionAttribute, vC);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
nA.fromBufferAttribute(normalAttribute, vA);
nB.fromBufferAttribute(normalAttribute, vB);
nC.fromBufferAttribute(normalAttribute, vC);
nA.add(cb);
nB.add(cb);
nC.add(cb);
normalAttribute.setXYZ(vA, nA.x, nA.y, nA.z);
normalAttribute.setXYZ(vB, nB.x, nB.y, nB.z);
normalAttribute.setXYZ(vC, nC.x, nC.y, nC.z);
}
} else {
// non-indexed elements (unconnected triangle soup)
for (let i = 0, il = positionAttribute.count; i < il; i += 3) {
pA.fromBufferAttribute(positionAttribute, i + 0);
pB.fromBufferAttribute(positionAttribute, i + 1);
pC.fromBufferAttribute(positionAttribute, i + 2);
cb.subVectors(pC, pB);
ab.subVectors(pA, pB);
cb.cross(ab);
normalAttribute.setXYZ(i + 0, cb.x, cb.y, cb.z);
normalAttribute.setXYZ(i + 1, cb.x, cb.y, cb.z);
normalAttribute.setXYZ(i + 2, cb.x, cb.y, cb.z);
}
}
this.normalizeNormals();
normalAttribute.needsUpdate = true;
}
},
merge: function (geometry, offset) {
if (!(geometry && geometry.isBufferGeometry)) {
console.error('THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry);
return;
}
if (offset === undefined) {
offset = 0;
console.warn('THREE.BufferGeometry.merge(): Overwriting original geometry, starting at offset=0. ' + 'Use BufferGeometryUtils.mergeBufferGeometries() for lossless merge.');
}
const attributes = this.attributes;
for (const key in attributes) {
if (geometry.attributes[key] === undefined) continue;
const attribute1 = attributes[key];
const attributeArray1 = attribute1.array;
const attribute2 = geometry.attributes[key];
const attributeArray2 = attribute2.array;
const attributeOffset = attribute2.itemSize * offset;
const length = Math.min(attributeArray2.length, attributeArray1.length - attributeOffset);
for (let i = 0, j = attributeOffset; i < length; i++, j++) {
attributeArray1[j] = attributeArray2[i];
}
}
return this;
},
normalizeNormals: function () {
const normals = this.attributes.normal;
for (let i = 0, il = normals.count; i < il; i++) {
_vector$4.fromBufferAttribute(normals, i);
_vector$4.normalize();
normals.setXYZ(i, _vector$4.x, _vector$4.y, _vector$4.z);
}
},
toNonIndexed: function () {
function convertBufferAttribute(attribute, indices) {
const array = attribute.array;
const itemSize = attribute.itemSize;
const normalized = attribute.normalized;
const array2 = new array.constructor(indices.length * itemSize);
let index = 0,
index2 = 0;
for (let i = 0, l = indices.length; i < l; i++) {
index = indices[i] * itemSize;
for (let j = 0; j < itemSize; j++) {
array2[index2++] = array[index++];
}
}
return new BufferAttribute(array2, itemSize, normalized);
}
//
if (this.index === null) {
console.warn('THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.');
return this;
}
const geometry2 = new BufferGeometry();
const indices = this.index.array;
const attributes = this.attributes;
// attributes
for (const name in attributes) {
const attribute = attributes[name];
const newAttribute = convertBufferAttribute(attribute, indices);
geometry2.setAttribute(name, newAttribute);
}
// morph attributes
const morphAttributes = this.morphAttributes;
for (const name in morphAttributes) {
const morphArray = [];
const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes
for (let i = 0, il = morphAttribute.length; i < il; i++) {
const attribute = morphAttribute[i];
const newAttribute = convertBufferAttribute(attribute, indices);
morphArray.push(newAttribute);
}
geometry2.morphAttributes[name] = morphArray;
}
geometry2.morphTargetsRelative = this.morphTargetsRelative;
// groups
const groups = this.groups;
for (let i = 0, l = groups.length; i < l; i++) {
const group = groups[i];
geometry2.addGroup(group.start, group.count, group.materialIndex);
}
return geometry2;
},
toJSON: function () {
const data = {
metadata: {
version: 4.5,
type: 'BufferGeometry',
generator: 'BufferGeometry.toJSON'
}
};
// standard BufferGeometry serialization
data.uuid = this.uuid;
data.type = this.type;
if (this.name !== '') data.name = this.name;
if (Object.keys(this.userData).length > 0) data.userData = this.userData;
if (this.parameters !== undefined) {
const parameters = this.parameters;
for (const key in parameters) {
if (parameters[key] !== undefined) data[key] = parameters[key];
}
return data;
}
data.data = {
attributes: {}
};
const index = this.index;
if (index !== null) {
data.data.index = {
type: index.array.constructor.name,
array: Array.prototype.slice.call(index.array)
};
}
const attributes = this.attributes;
for (const key in attributes) {
const attribute = attributes[key];
const attributeData = attribute.toJSON(data.data);
if (attribute.name !== '') attributeData.name = attribute.name;
data.data.attributes[key] = attributeData;
}
const morphAttributes = {};
let hasMorphAttributes = false;
for (const key in this.morphAttributes) {
const attributeArray = this.morphAttributes[key];
const array = [];
for (let i = 0, il = attributeArray.length; i < il; i++) {
const attribute = attributeArray[i];
const attributeData = attribute.toJSON(data.data);
if (attribute.name !== '') attributeData.name = attribute.name;
array.push(attributeData);
}
if (array.length > 0) {
morphAttributes[key] = array;
hasMorphAttributes = true;
}
}
if (hasMorphAttributes) {
data.data.morphAttributes = morphAttributes;
data.data.morphTargetsRelative = this.morphTargetsRelative;
}
const groups = this.groups;
if (groups.length > 0) {
data.data.groups = JSON.parse(JSON.stringify(groups));
}
const boundingSphere = this.boundingSphere;
if (boundingSphere !== null) {
data.data.boundingSphere = {
center: boundingSphere.center.toArray(),
radius: boundingSphere.radius
};
}
return data;
},
clone: function () {
/*
// Handle primitives
const parameters = this.parameters;
if ( parameters !== undefined ) {
const values = [];
for ( const key in parameters ) {
values.push( parameters[ key ] );
}
const geometry = Object.create( this.constructor.prototype );
this.constructor.apply( geometry, values );
return geometry;
}
return new this.constructor().copy( this );
*/
return new BufferGeometry().copy(this);
},
copy: function (source) {
// reset
this.index = null;
this.attributes = {};
this.morphAttributes = {};
this.groups = [];
this.boundingBox = null;
this.boundingSphere = null;
// used for storing cloned, shared data
const data = {};
// name
this.name = source.name;
// index
const index = source.index;
if (index !== null) {
this.setIndex(index.clone(data));
}
// attributes
const attributes = source.attributes;
for (const name in attributes) {
const attribute = attributes[name];
this.setAttribute(name, attribute.clone(data));
}
// morph attributes
const morphAttributes = source.morphAttributes;
for (const name in morphAttributes) {
const array = [];
const morphAttribute = morphAttributes[name]; // morphAttribute: array of Float32BufferAttributes
for (let i = 0, l = morphAttribute.length; i < l; i++) {
array.push(morphAttribute[i].clone(data));
}
this.morphAttributes[name] = array;
}
this.morphTargetsRelative = source.morphTargetsRelative;
// groups
const groups = source.groups;
for (let i = 0, l = groups.length; i < l; i++) {
const group = groups[i];
this.addGroup(group.start, group.count, group.materialIndex);
}
// bounding box
const boundingBox = source.boundingBox;
if (boundingBox !== null) {
this.boundingBox = boundingBox.clone();
}
// bounding sphere
const boundingSphere = source.boundingSphere;
if (boundingSphere !== null) {
this.boundingSphere = boundingSphere.clone();
}
// draw range
this.drawRange.start = source.drawRange.start;
this.drawRange.count = source.drawRange.count;
// user data
this.userData = source.userData;
return this;
},
dispose: function () {
this.dispatchEvent({
type: 'dispose'
});
}
});
const _inverseMatrix = new Matrix4();
const _ray = new Ray();
const _sphere = new Sphere();
const _vA = new Vector3();
const _vB = new Vector3();
const _vC = new Vector3();
const _tempA = new Vector3();
const _tempB = new Vector3();
const _tempC = new Vector3();
const _morphA = new Vector3();
const _morphB = new Vector3();
const _morphC = new Vector3();
const _uvA = new Vector2();
const _uvB = new Vector2();
const _uvC = new Vector2();
const _intersectionPoint = new Vector3();
const _intersectionPointWorld = new Vector3();
function Mesh(geometry = new BufferGeometry(), material = new MeshBasicMaterial()) {
Object3D.call(this);
this.type = 'Mesh';
this.geometry = geometry;
this.material = material;
this.updateMorphTargets();
}
Mesh.prototype = _extends(Object.create(Object3D.prototype), {
constructor: Mesh,
isMesh: true,
copy: function (source) {
Object3D.prototype.copy.call(this, source);
if (source.morphTargetInfluences !== undefined) {
this.morphTargetInfluences = source.morphTargetInfluences.slice();
}
if (source.morphTargetDictionary !== undefined) {
this.morphTargetDictionary = _extends({}, source.morphTargetDictionary);
}
this.material = source.material;
this.geometry = source.geometry;
return this;
},
updateMorphTargets: function () {
const geometry = this.geometry;
if (geometry.isBufferGeometry) {
const morphAttributes = geometry.morphAttributes;
const keys = Object.keys(morphAttributes);
if (keys.length > 0) {
const morphAttribute = morphAttributes[keys[0]];
if (morphAttribute !== undefined) {
this.morphTargetInfluences = [];
this.morphTargetDictionary = {};
for (let m = 0, ml = morphAttribute.length; m < ml; m++) {
const name = morphAttribute[m].name || String(m);
this.morphTargetInfluences.push(0);
this.morphTargetDictionary[name] = m;
}
}
}
} else {
const morphTargets = geometry.morphTargets;
if (morphTargets !== undefined && morphTargets.length > 0) {
console.error('THREE.Mesh.updateMorphTargets() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.');
}
}
},
raycast: function (raycaster, intersects) {
const geometry = this.geometry;
const material = this.material;
const matrixWorld = this.matrixWorld;
if (material === undefined) return;
// Checking boundingSphere distance to ray
if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
_sphere.copy(geometry.boundingSphere);
_sphere.applyMatrix4(matrixWorld);
if (raycaster.ray.intersectsSphere(_sphere) === false) return;
//
_inverseMatrix.copy(matrixWorld).invert();
_ray.copy(raycaster.ray).applyMatrix4(_inverseMatrix);
// Check boundingBox before continuing
if (geometry.boundingBox !== null) {
if (_ray.intersectsBox(geometry.boundingBox) === false) return;
}
let intersection;
if (geometry.isBufferGeometry) {
const index = geometry.index;
const position = geometry.attributes.position;
const morphPosition = geometry.morphAttributes.position;
const morphTargetsRelative = geometry.morphTargetsRelative;
const uv = geometry.attributes.uv;
const uv2 = geometry.attributes.uv2;
const groups = geometry.groups;
const drawRange = geometry.drawRange;
if (index !== null) {
// indexed buffer geometry
if (Array.isArray(material)) {
for (let i = 0, il = groups.length; i < il; i++) {
const group = groups[i];
const groupMaterial = material[group.materialIndex];
const start = Math.max(group.start, drawRange.start);
const end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (let j = start, jl = end; j < jl; j += 3) {
const a = index.getX(j);
const b = index.getX(j + 1);
const c = index.getX(j + 2);
intersection = checkBufferGeometryIntersection(this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c);
if (intersection) {
intersection.faceIndex = Math.floor(j / 3); // triangle number in indexed buffer semantics
intersection.face.materialIndex = group.materialIndex;
intersects.push(intersection);
}
}
}
} else {
const start = Math.max(0, drawRange.start);
const end = Math.min(index.count, drawRange.start + drawRange.count);
for (let i = start, il = end; i < il; i += 3) {
const a = index.getX(i);
const b = index.getX(i + 1);
const c = index.getX(i + 2);
intersection = checkBufferGeometryIntersection(this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c);
if (intersection) {
intersection.faceIndex = Math.floor(i / 3); // triangle number in indexed buffer semantics
intersects.push(intersection);
}
}
}
} else if (position !== undefined) {
// non-indexed buffer geometry
if (Array.isArray(material)) {
for (let i = 0, il = groups.length; i < il; i++) {
const group = groups[i];
const groupMaterial = material[group.materialIndex];
const start = Math.max(group.start, drawRange.start);
const end = Math.min(group.start + group.count, drawRange.start + drawRange.count);
for (let j = start, jl = end; j < jl; j += 3) {
const a = j;
const b = j + 1;
const c = j + 2;
intersection = checkBufferGeometryIntersection(this, groupMaterial, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c);
if (intersection) {
intersection.faceIndex = Math.floor(j / 3); // triangle number in non-indexed buffer semantics
intersection.face.materialIndex = group.materialIndex;
intersects.push(intersection);
}
}
}
} else {
const start = Math.max(0, drawRange.start);
const end = Math.min(position.count, drawRange.start + drawRange.count);
for (let i = start, il = end; i < il; i += 3) {
const a = i;
const b = i + 1;
const c = i + 2;
intersection = checkBufferGeometryIntersection(this, material, raycaster, _ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c);
if (intersection) {
intersection.faceIndex = Math.floor(i / 3); // triangle number in non-indexed buffer semantics
intersects.push(intersection);
}
}
}
}
} else if (geometry.isGeometry) {
console.error('THREE.Mesh.raycast() no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.');
}
}
});
function checkIntersection(object, material, raycaster, ray, pA, pB, pC, point) {
let intersect;
if (material.side === BackSide) {
intersect = ray.intersectTriangle(pC, pB, pA, true, point);
} else {
intersect = ray.intersectTriangle(pA, pB, pC, material.side !== DoubleSide, point);
}
if (intersect === null) return null;
_intersectionPointWorld.copy(point);
_intersectionPointWorld.applyMatrix4(object.matrixWorld);
const distance = raycaster.ray.origin.distanceTo(_intersectionPointWorld);
if (distance < raycaster.near || distance > raycaster.far) return null;
return {
distance: distance,
point: _intersectionPointWorld.clone(),
object: object
};
}
function checkBufferGeometryIntersection(object, material, raycaster, ray, position, morphPosition, morphTargetsRelative, uv, uv2, a, b, c) {
_vA.fromBufferAttribute(position, a);
_vB.fromBufferAttribute(position, b);
_vC.fromBufferAttribute(position, c);
const morphInfluences = object.morphTargetInfluences;
if (material.morphTargets && morphPosition && morphInfluences) {
_morphA.set(0, 0, 0);
_morphB.set(0, 0, 0);
_morphC.set(0, 0, 0);
for (let i = 0, il = morphPosition.length; i < il; i++) {
const influence = morphInfluences[i];
const morphAttribute = morphPosition[i];
if (influence === 0) continue;
_tempA.fromBufferAttribute(morphAttribute, a);
_tempB.fromBufferAttribute(morphAttribute, b);
_tempC.fromBufferAttribute(morphAttribute, c);
if (morphTargetsRelative) {
_morphA.addScaledVector(_tempA, influence);
_morphB.addScaledVector(_tempB, influence);
_morphC.addScaledVector(_tempC, influence);
} else {
_morphA.addScaledVector(_tempA.sub(_vA), influence);
_morphB.addScaledVector(_tempB.sub(_vB), influence);
_morphC.addScaledVector(_tempC.sub(_vC), influence);
}
}
_vA.add(_morphA);
_vB.add(_morphB);
_vC.add(_morphC);
}
if (object.isSkinnedMesh) {
object.boneTransform(a, _vA);
object.boneTransform(b, _vB);
object.boneTransform(c, _vC);
}
const intersection = checkIntersection(object, material, raycaster, ray, _vA, _vB, _vC, _intersectionPoint);
if (intersection) {
if (uv) {
_uvA.fromBufferAttribute(uv, a);
_uvB.fromBufferAttribute(uv, b);
_uvC.fromBufferAttribute(uv, c);
intersection.uv = Triangle.getUV(_intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2());
}
if (uv2) {
_uvA.fromBufferAttribute(uv2, a);
_uvB.fromBufferAttribute(uv2, b);
_uvC.fromBufferAttribute(uv2, c);
intersection.uv2 = Triangle.getUV(_intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2());
}
const face = new Face3(a, b, c);
Triangle.getNormal(_vA, _vB, _vC, face.normal);
intersection.face = face;
}
return intersection;
}
class BoxGeometry extends BufferGeometry {
constructor(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1) {
super();
this.type = 'BoxGeometry';
this.parameters = {
width: width,
height: height,
depth: depth,
widthSegments: widthSegments,
heightSegments: heightSegments,
depthSegments: depthSegments
};
const scope = this;
// segments
widthSegments = Math.floor(widthSegments);
heightSegments = Math.floor(heightSegments);
depthSegments = Math.floor(depthSegments);
// buffers
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
// helper variables
let numberOfVertices = 0;
let groupStart = 0;
// build each side of the box geometry
buildPlane('z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0); // px
buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1); // nx
buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2); // py
buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3); // ny
buildPlane('x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4); // pz
buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5); // nz
// build geometry
this.setIndex(indices);
this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
this.setAttribute('normal', new Float32BufferAttribute(normals, 3));
this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
function buildPlane(u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex) {
const segmentWidth = width / gridX;
const segmentHeight = height / gridY;
const widthHalf = width / 2;
const heightHalf = height / 2;
const depthHalf = depth / 2;
const gridX1 = gridX + 1;
const gridY1 = gridY + 1;
let vertexCounter = 0;
let groupCount = 0;
const vector = new Vector3();
// generate vertices, normals and uvs
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segmentHeight - heightHalf;
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segmentWidth - widthHalf;
// set values to correct vector component
vector[u] = x * udir;
vector[v] = y * vdir;
vector[w] = depthHalf;
// now apply vector to vertex buffer
vertices.push(vector.x, vector.y, vector.z);
// set values to correct vector component
vector[u] = 0;
vector[v] = 0;
vector[w] = depth > 0 ? 1 : -1;
// now apply vector to normal buffer
normals.push(vector.x, vector.y, vector.z);
// uvs
uvs.push(ix / gridX);
uvs.push(1 - iy / gridY);
// counters
vertexCounter += 1;
}
}
// indices
// 1. you need three indices to draw a single face
// 2. a single segment consists of two faces
// 3. so we need to generate six (2*3) indices per segment
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = numberOfVertices + ix + gridX1 * iy;
const b = numberOfVertices + ix + gridX1 * (iy + 1);
const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1);
const d = numberOfVertices + (ix + 1) + gridX1 * iy;
// faces
indices.push(a, b, d);
indices.push(b, c, d);
// increase counter
groupCount += 6;
}
}
// add a group to the geometry. this will ensure multi material support
scope.addGroup(groupStart, groupCount, materialIndex);
// calculate new start value for groups
groupStart += groupCount;
// update total number of vertices
numberOfVertices += vertexCounter;
}
}
}
/**
* Uniform Utilities
*/
function cloneUniforms(src) {
const dst = {};
for (const u in src) {
dst[u] = {};
for (const p in src[u]) {
const property = src[u][p];
if (property && (property.isColor || property.isMatrix3 || property.isMatrix4 || property.isVector2 || property.isVector3 || property.isVector4 || property.isTexture)) {
dst[u][p] = property.clone();
} else if (Array.isArray(property)) {
dst[u][p] = property.slice();
} else {
dst[u][p] = property;
}
}
}
return dst;
}
function mergeUniforms(uniforms) {
const merged = {};
for (let u = 0; u < uniforms.length; u++) {
const tmp = cloneUniforms(uniforms[u]);
for (const p in tmp) {
merged[p] = tmp[p];
}
}
return merged;
}
// Legacy
const UniformsUtils = {
clone: cloneUniforms,
merge: mergeUniforms
};
var default_vertex = "void main() {\n\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n}";
var default_fragment = "void main() {\n\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\n}";
/**
* parameters = {
* defines: { "label" : "value" },
* uniforms: { "parameter1": { value: 1.0 }, "parameter2": { value2: 2 } },
*
* fragmentShader: ,
* vertexShader: ,
*
* wireframe: ,
* wireframeLinewidth: ,
*
* lights: ,
*
* skinning: ,
* morphTargets: ,
* morphNormals:
* }
*/
function ShaderMaterial(parameters) {
Material.call(this);
this.type = 'ShaderMaterial';
this.defines = {};
this.uniforms = {};
this.vertexShader = default_vertex;
this.fragmentShader = default_fragment;
this.linewidth = 1;
this.wireframe = false;
this.wireframeLinewidth = 1;
this.fog = false; // set to use scene fog
this.lights = false; // set to use scene lights
this.clipping = false; // set to use user-defined clipping planes
this.skinning = false; // set to use skinning attribute streams
this.morphTargets = false; // set to use morph targets
this.morphNormals = false; // set to use morph normals
this.extensions = {
derivatives: false,
// set to use derivatives
fragDepth: false,
// set to use fragment depth values
drawBuffers: false,
// set to use draw buffers
shaderTextureLOD: false // set to use shader texture LOD
};
// When rendered geometry doesn't include these attributes but the material does,
// use these default values in WebGL. This avoids errors when buffer data is missing.
this.defaultAttributeValues = {
'color': [1, 1, 1],
'uv': [0, 0],
'uv2': [0, 0]
};
this.index0AttributeName = undefined;
this.uniformsNeedUpdate = false;
this.glslVersion = null;
if (parameters !== undefined) {
if (parameters.attributes !== undefined) {
console.error('THREE.ShaderMaterial: attributes should now be defined in THREE.BufferGeometry instead.');
}
this.setValues(parameters);
}
}
ShaderMaterial.prototype = Object.create(Material.prototype);
ShaderMaterial.prototype.constructor = ShaderMaterial;
ShaderMaterial.prototype.isShaderMaterial = true;
ShaderMaterial.prototype.copy = function (source) {
Material.prototype.copy.call(this, source);
this.fragmentShader = source.fragmentShader;
this.vertexShader = source.vertexShader;
this.uniforms = cloneUniforms(source.uniforms);
this.defines = _extends({}, source.defines);
this.wireframe = source.wireframe;
this.wireframeLinewidth = source.wireframeLinewidth;
this.lights = source.lights;
this.clipping = source.clipping;
this.skinning = source.skinning;
this.morphTargets = source.morphTargets;
this.morphNormals = source.morphNormals;
this.extensions = _extends({}, source.extensions);
this.glslVersion = source.glslVersion;
return this;
};
ShaderMaterial.prototype.toJSON = function (meta) {
const data = Material.prototype.toJSON.call(this, meta);
data.glslVersion = this.glslVersion;
data.uniforms = {};
for (const name in this.uniforms) {
const uniform = this.uniforms[name];
const value = uniform.value;
if (value && value.isTexture) {
data.uniforms[name] = {
type: 't',
value: value.toJSON(meta).uuid
};
} else if (value && value.isColor) {
data.uniforms[name] = {
type: 'c',
value: value.getHex()
};
} else if (value && value.isVector2) {
data.uniforms[name] = {
type: 'v2',
value: value.toArray()
};
} else if (value && value.isVector3) {
data.uniforms[name] = {
type: 'v3',
value: value.toArray()
};
} else if (value && value.isVector4) {
data.uniforms[name] = {
type: 'v4',
value: value.toArray()
};
} else if (value && value.isMatrix3) {
data.uniforms[name] = {
type: 'm3',
value: value.toArray()
};
} else if (value && value.isMatrix4) {
data.uniforms[name] = {
type: 'm4',
value: value.toArray()
};
} else {
data.uniforms[name] = {
value: value
};
// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far
}
}
if (Object.keys(this.defines).length > 0) data.defines = this.defines;
data.vertexShader = this.vertexShader;
data.fragmentShader = this.fragmentShader;
const extensions = {};
for (const key in this.extensions) {
if (this.extensions[key] === true) extensions[key] = true;
}
if (Object.keys(extensions).length > 0) data.extensions = extensions;
return data;
};
function Camera() {
Object3D.call(this);
this.type = 'Camera';
this.matrixWorldInverse = new Matrix4();
this.projectionMatrix = new Matrix4();
this.projectionMatrixInverse = new Matrix4();
}
Camera.prototype = _extends(Object.create(Object3D.prototype), {
constructor: Camera,
isCamera: true,
copy: function (source, recursive) {
Object3D.prototype.copy.call(this, source, recursive);
this.matrixWorldInverse.copy(source.matrixWorldInverse);
this.projectionMatrix.copy(source.projectionMatrix);
this.projectionMatrixInverse.copy(source.projectionMatrixInverse);
return this;
},
getWorldDirection: function (target) {
if (target === undefined) {
console.warn('THREE.Camera: .getWorldDirection() target is now required');
target = new Vector3();
}
this.updateWorldMatrix(true, false);
const e = this.matrixWorld.elements;
return target.set(-e[8], -e[9], -e[10]).normalize();
},
updateMatrixWorld: function (force) {
Object3D.prototype.updateMatrixWorld.call(this, force);
this.matrixWorldInverse.copy(this.matrixWorld).invert();
},
updateWorldMatrix: function (updateParents, updateChildren) {
Object3D.prototype.updateWorldMatrix.call(this, updateParents, updateChildren);
this.matrixWorldInverse.copy(this.matrixWorld).invert();
},
clone: function () {
return new this.constructor().copy(this);
}
});
function PerspectiveCamera(fov = 50, aspect = 1, near = 0.1, far = 2000) {
Camera.call(this);
this.type = 'PerspectiveCamera';
this.fov = fov;
this.zoom = 1;
this.near = near;
this.far = far;
this.focus = 10;
this.aspect = aspect;
this.view = null;
this.filmGauge = 35; // width of the film (default in millimeters)
this.filmOffset = 0; // horizontal film offset (same unit as gauge)
this.updateProjectionMatrix();
}
PerspectiveCamera.prototype = _extends(Object.create(Camera.prototype), {
constructor: PerspectiveCamera,
isPerspectiveCamera: true,
copy: function (source, recursive) {
Camera.prototype.copy.call(this, source, recursive);
this.fov = source.fov;
this.zoom = source.zoom;
this.near = source.near;
this.far = source.far;
this.focus = source.focus;
this.aspect = source.aspect;
this.view = source.view === null ? null : _extends({}, source.view);
this.filmGauge = source.filmGauge;
this.filmOffset = source.filmOffset;
return this;
},
/**
* Sets the FOV by focal length in respect to the current .filmGauge.
*
* The default film gauge is 35, so that the focal length can be specified for
* a 35mm (full frame) camera.
*
* Values for focal length and film gauge must have the same unit.
*/
setFocalLength: function (focalLength) {
/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */
const vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;
this.fov = MathUtils.RAD2DEG * 2 * Math.atan(vExtentSlope);
this.updateProjectionMatrix();
},
/**
* Calculates the focal length from the current .fov and .filmGauge.
*/
getFocalLength: function () {
const vExtentSlope = Math.tan(MathUtils.DEG2RAD * 0.5 * this.fov);
return 0.5 * this.getFilmHeight() / vExtentSlope;
},
getEffectiveFOV: function () {
return MathUtils.RAD2DEG * 2 * Math.atan(Math.tan(MathUtils.DEG2RAD * 0.5 * this.fov) / this.zoom);
},
getFilmWidth: function () {
// film not completely covered in portrait format (aspect < 1)
return this.filmGauge * Math.min(this.aspect, 1);
},
getFilmHeight: function () {
// film not completely covered in landscape format (aspect > 1)
return this.filmGauge / Math.max(this.aspect, 1);
},
/**
* Sets an offset in a larger frustum. This is useful for multi-window or
* multi-monitor/multi-machine setups.
*
* For example, if you have 3x2 monitors and each monitor is 1920x1080 and
* the monitors are in grid like this
*
* +---+---+---+
* | A | B | C |
* +---+---+---+
* | D | E | F |
* +---+---+---+
*
* then for each monitor you would call it like this
*
* const w = 1920;
* const h = 1080;
* const fullWidth = w * 3;
* const fullHeight = h * 2;
*
* --A--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );
* --B--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );
* --C--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );
* --D--
* camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );
* --E--
* camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );
* --F--
* camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );
*
* Note there is no reason monitors have to be the same size or in a grid.
*/
setViewOffset: function (fullWidth, fullHeight, x, y, width, height) {
this.aspect = fullWidth / fullHeight;
if (this.view === null) {
this.view = {
enabled: true,
fullWidth: 1,
fullHeight: 1,
offsetX: 0,
offsetY: 0,
width: 1,
height: 1
};
}
this.view.enabled = true;
this.view.fullWidth = fullWidth;
this.view.fullHeight = fullHeight;
this.view.offsetX = x;
this.view.offsetY = y;
this.view.width = width;
this.view.height = height;
this.updateProjectionMatrix();
},
clearViewOffset: function () {
if (this.view !== null) {
this.view.enabled = false;
}
this.updateProjectionMatrix();
},
updateProjectionMatrix: function () {
const near = this.near;
let top = near * Math.tan(MathUtils.DEG2RAD * 0.5 * this.fov) / this.zoom;
let height = 2 * top;
let width = this.aspect * height;
let left = -0.5 * width;
const view = this.view;
if (this.view !== null && this.view.enabled) {
const fullWidth = view.fullWidth,
fullHeight = view.fullHeight;
left += view.offsetX * width / fullWidth;
top -= view.offsetY * height / fullHeight;
width *= view.width / fullWidth;
height *= view.height / fullHeight;
}
const skew = this.filmOffset;
if (skew !== 0) left += near * skew / this.getFilmWidth();
this.projectionMatrix.makePerspective(left, left + width, top, top - height, near, this.far);
this.projectionMatrixInverse.copy(this.projectionMatrix).invert();
},
toJSON: function (meta) {
const data = Object3D.prototype.toJSON.call(this, meta);
data.object.fov = this.fov;
data.object.zoom = this.zoom;
data.object.near = this.near;
data.object.far = this.far;
data.object.focus = this.focus;
data.object.aspect = this.aspect;
if (this.view !== null) data.object.view = _extends({}, this.view);
data.object.filmGauge = this.filmGauge;
data.object.filmOffset = this.filmOffset;
return data;
}
});
const fov = 90,
aspect = 1;
function CubeCamera(near, far, renderTarget) {
Object3D.call(this);
this.type = 'CubeCamera';
if (renderTarget.isWebGLCubeRenderTarget !== true) {
console.error('THREE.CubeCamera: The constructor now expects an instance of WebGLCubeRenderTarget as third parameter.');
return;
}
this.renderTarget = renderTarget;
const cameraPX = new PerspectiveCamera(fov, aspect, near, far);
cameraPX.layers = this.layers;
cameraPX.up.set(0, -1, 0);
cameraPX.lookAt(new Vector3(1, 0, 0));
this.add(cameraPX);
const cameraNX = new PerspectiveCamera(fov, aspect, near, far);
cameraNX.layers = this.layers;
cameraNX.up.set(0, -1, 0);
cameraNX.lookAt(new Vector3(-1, 0, 0));
this.add(cameraNX);
const cameraPY = new PerspectiveCamera(fov, aspect, near, far);
cameraPY.layers = this.layers;
cameraPY.up.set(0, 0, 1);
cameraPY.lookAt(new Vector3(0, 1, 0));
this.add(cameraPY);
const cameraNY = new PerspectiveCamera(fov, aspect, near, far);
cameraNY.layers = this.layers;
cameraNY.up.set(0, 0, -1);
cameraNY.lookAt(new Vector3(0, -1, 0));
this.add(cameraNY);
const cameraPZ = new PerspectiveCamera(fov, aspect, near, far);
cameraPZ.layers = this.layers;
cameraPZ.up.set(0, -1, 0);
cameraPZ.lookAt(new Vector3(0, 0, 1));
this.add(cameraPZ);
const cameraNZ = new PerspectiveCamera(fov, aspect, near, far);
cameraNZ.layers = this.layers;
cameraNZ.up.set(0, -1, 0);
cameraNZ.lookAt(new Vector3(0, 0, -1));
this.add(cameraNZ);
this.update = function (renderer, scene) {
if (this.parent === null) this.updateMatrixWorld();
const currentXrEnabled = renderer.xr.enabled;
const currentRenderTarget = renderer.getRenderTarget();
renderer.xr.enabled = false;
const generateMipmaps = renderTarget.texture.generateMipmaps;
renderTarget.texture.generateMipmaps = false;
renderer.setRenderTarget(renderTarget, 0);
renderer.render(scene, cameraPX);
renderer.setRenderTarget(renderTarget, 1);
renderer.render(scene, cameraNX);
renderer.setRenderTarget(renderTarget, 2);
renderer.render(scene, cameraPY);
renderer.setRenderTarget(renderTarget, 3);
renderer.render(scene, cameraNY);
renderer.setRenderTarget(renderTarget, 4);
renderer.render(scene, cameraPZ);
renderTarget.texture.generateMipmaps = generateMipmaps;
renderer.setRenderTarget(renderTarget, 5);
renderer.render(scene, cameraNZ);
renderer.setRenderTarget(currentRenderTarget);
renderer.xr.enabled = currentXrEnabled;
};
}
CubeCamera.prototype = Object.create(Object3D.prototype);
CubeCamera.prototype.constructor = CubeCamera;
function CubeTexture(images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding) {
images = images !== undefined ? images : [];
mapping = mapping !== undefined ? mapping : CubeReflectionMapping;
format = format !== undefined ? format : RGBFormat;
Texture.call(this, images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding);
this.flipY = false;
// Why CubeTexture._needsFlipEnvMap is necessary:
//
// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
// and the flag _needsFlipEnvMap controls this conversion. The flip is not required (and thus _needsFlipEnvMap is set to false)
// when using WebGLCubeRenderTarget.texture as a cube texture.
this._needsFlipEnvMap = true;
}
CubeTexture.prototype = Object.create(Texture.prototype);
CubeTexture.prototype.constructor = CubeTexture;
CubeTexture.prototype.isCubeTexture = true;
Object.defineProperty(CubeTexture.prototype, 'images', {
get: function () {
return this.image;
},
set: function (value) {
this.image = value;
}
});
class WebGLCubeRenderTarget extends WebGLRenderTarget {
constructor(size, options, dummy) {
if (Number.isInteger(options)) {
console.warn('THREE.WebGLCubeRenderTarget: constructor signature is now WebGLCubeRenderTarget( size, options )');
options = dummy;
}
super(size, size, options);
Object.defineProperty(this, 'isWebGLCubeRenderTarget', {
value: true
});
options = options || {};
this.texture = new CubeTexture(undefined, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.encoding);
this.texture._needsFlipEnvMap = false;
}
fromEquirectangularTexture(renderer, texture) {
this.texture.type = texture.type;
this.texture.format = RGBAFormat; // see #18859
this.texture.encoding = texture.encoding;
this.texture.generateMipmaps = texture.generateMipmaps;
this.texture.minFilter = texture.minFilter;
this.texture.magFilter = texture.magFilter;
const shader = {
uniforms: {
tEquirect: {
value: null
}
},
vertexShader: /* glsl */`
varying vec3 vWorldDirection;
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: /* glsl */`
uniform sampler2D tEquirect;
varying vec3 vWorldDirection;
#include
void main() {
vec3 direction = normalize( vWorldDirection );
vec2 sampleUV = equirectUv( direction );
gl_FragColor = texture2D( tEquirect, sampleUV );
}
`
};
const geometry = new BoxGeometry(5, 5, 5);
const material = new ShaderMaterial({
name: 'CubemapFromEquirect',
uniforms: cloneUniforms(shader.uniforms),
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
side: BackSide,
blending: NoBlending
});
material.uniforms.tEquirect.value = texture;
const mesh = new Mesh(geometry, material);
const currentMinFilter = texture.minFilter;
// Avoid blurred poles
if (texture.minFilter === LinearMipmapLinearFilter) texture.minFilter = LinearFilter;
const camera = new CubeCamera(1, 10, this);
camera.update(renderer, mesh);
texture.minFilter = currentMinFilter;
mesh.geometry.dispose();
mesh.material.dispose();
return this;
}
clear(renderer, color, depth, stencil) {
const currentRenderTarget = renderer.getRenderTarget();
for (let i = 0; i < 6; i++) {
renderer.setRenderTarget(this, i);
renderer.clear(color, depth, stencil);
}
renderer.setRenderTarget(currentRenderTarget);
}
}
function DataTexture(data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, encoding) {
Texture.call(this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, encoding);
this.image = {
data: data || null,
width: width || 1,
height: height || 1
};
this.magFilter = magFilter !== undefined ? magFilter : NearestFilter;
this.minFilter = minFilter !== undefined ? minFilter : NearestFilter;
this.generateMipmaps = false;
this.flipY = false;
this.unpackAlignment = 1;
this.needsUpdate = true;
}
DataTexture.prototype = Object.create(Texture.prototype);
DataTexture.prototype.constructor = DataTexture;
DataTexture.prototype.isDataTexture = true;
const _sphere$1 = /*@__PURE__*/new Sphere();
const _vector$5 = /*@__PURE__*/new Vector3();
class Frustum {
constructor(p0, p1, p2, p3, p4, p5) {
this.planes = [p0 !== undefined ? p0 : new Plane(), p1 !== undefined ? p1 : new Plane(), p2 !== undefined ? p2 : new Plane(), p3 !== undefined ? p3 : new Plane(), p4 !== undefined ? p4 : new Plane(), p5 !== undefined ? p5 : new Plane()];
}
set(p0, p1, p2, p3, p4, p5) {
const planes = this.planes;
planes[0].copy(p0);
planes[1].copy(p1);
planes[2].copy(p2);
planes[3].copy(p3);
planes[4].copy(p4);
planes[5].copy(p5);
return this;
}
clone() {
return new this.constructor().copy(this);
}
copy(frustum) {
const planes = this.planes;
for (let i = 0; i < 6; i++) {
planes[i].copy(frustum.planes[i]);
}
return this;
}
setFromProjectionMatrix(m) {
const planes = this.planes;
const me = m.elements;
const me0 = me[0],
me1 = me[1],
me2 = me[2],
me3 = me[3];
const me4 = me[4],
me5 = me[5],
me6 = me[6],
me7 = me[7];
const me8 = me[8],
me9 = me[9],
me10 = me[10],
me11 = me[11];
const me12 = me[12],
me13 = me[13],
me14 = me[14],
me15 = me[15];
planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize();
planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize();
planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize();
planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize();
planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize();
planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize();
return this;
}
intersectsObject(object) {
const geometry = object.geometry;
if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
_sphere$1.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld);
return this.intersectsSphere(_sphere$1);
}
intersectsSprite(sprite) {
_sphere$1.center.set(0, 0, 0);
_sphere$1.radius = 0.7071067811865476;
_sphere$1.applyMatrix4(sprite.matrixWorld);
return this.intersectsSphere(_sphere$1);
}
intersectsSphere(sphere) {
const planes = this.planes;
const center = sphere.center;
const negRadius = -sphere.radius;
for (let i = 0; i < 6; i++) {
const distance = planes[i].distanceToPoint(center);
if (distance < negRadius) {
return false;
}
}
return true;
}
intersectsBox(box) {
const planes = this.planes;
for (let i = 0; i < 6; i++) {
const plane = planes[i];
// corner at max distance
_vector$5.x = plane.normal.x > 0 ? box.max.x : box.min.x;
_vector$5.y = plane.normal.y > 0 ? box.max.y : box.min.y;
_vector$5.z = plane.normal.z > 0 ? box.max.z : box.min.z;
if (plane.distanceToPoint(_vector$5) < 0) {
return false;
}
}
return true;
}
containsPoint(point) {
const planes = this.planes;
for (let i = 0; i < 6; i++) {
if (planes[i].distanceToPoint(point) < 0) {
return false;
}
}
return true;
}
}
function WebGLAnimation() {
let context = null;
let isAnimating = false;
let animationLoop = null;
let requestId = null;
function onAnimationFrame(time, frame) {
animationLoop(time, frame);
requestId = context.requestAnimationFrame(onAnimationFrame);
}
return {
start: function () {
if (isAnimating === true) return;
if (animationLoop === null) return;
requestId = context.requestAnimationFrame(onAnimationFrame);
isAnimating = true;
},
stop: function () {
context.cancelAnimationFrame(requestId);
isAnimating = false;
},
setAnimationLoop: function (callback) {
animationLoop = callback;
},
setContext: function (value) {
context = value;
}
};
}
function WebGLAttributes(gl, capabilities) {
const isWebGL2 = capabilities.isWebGL2;
const buffers = new WeakMap();
function createBuffer(attribute, bufferType) {
const array = attribute.array;
const usage = attribute.usage;
const buffer = gl.createBuffer();
gl.bindBuffer(bufferType, buffer);
gl.bufferData(bufferType, array, usage);
attribute.onUploadCallback();
let type = 5126;
if (array instanceof Float32Array) {
type = 5126;
} else if (array instanceof Float64Array) {
console.warn('THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.');
} else if (array instanceof Uint16Array) {
if (attribute.isFloat16BufferAttribute) {
if (isWebGL2) {
type = 5131;
} else {
console.warn('THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.');
}
} else {
type = 5123;
}
} else if (array instanceof Int16Array) {
type = 5122;
} else if (array instanceof Uint32Array) {
type = 5125;
} else if (array instanceof Int32Array) {
type = 5124;
} else if (array instanceof Int8Array) {
type = 5120;
} else if (array instanceof Uint8Array) {
type = 5121;
}
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version
};
}
function updateBuffer(buffer, attribute, bufferType) {
const array = attribute.array;
const updateRange = attribute.updateRange;
gl.bindBuffer(bufferType, buffer);
if (updateRange.count === -1) {
// Not using update ranges
gl.bufferSubData(bufferType, 0, array);
} else {
if (isWebGL2) {
gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, array, updateRange.offset, updateRange.count);
} else {
gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, array.subarray(updateRange.offset, updateRange.offset + updateRange.count));
}
updateRange.count = -1; // reset range
}
}
//
function get(attribute) {
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
return buffers.get(attribute);
}
function remove(attribute) {
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
const data = buffers.get(attribute);
if (data) {
gl.deleteBuffer(data.buffer);
buffers.delete(attribute);
}
}
function update(attribute, bufferType) {
if (attribute.isGLBufferAttribute) {
const cached = buffers.get(attribute);
if (!cached || cached.version < attribute.version) {
buffers.set(attribute, {
buffer: attribute.buffer,
type: attribute.type,
bytesPerElement: attribute.elementSize,
version: attribute.version
});
}
return;
}
if (attribute.isInterleavedBufferAttribute) attribute = attribute.data;
const data = buffers.get(attribute);
if (data === undefined) {
buffers.set(attribute, createBuffer(attribute, bufferType));
} else if (data.version < attribute.version) {
updateBuffer(data.buffer, attribute, bufferType);
data.version = attribute.version;
}
}
return {
get: get,
remove: remove,
update: update
};
}
class PlaneGeometry extends BufferGeometry {
constructor(width = 1, height = 1, widthSegments = 1, heightSegments = 1) {
super();
this.type = 'PlaneGeometry';
this.parameters = {
width: width,
height: height,
widthSegments: widthSegments,
heightSegments: heightSegments
};
const width_half = width / 2;
const height_half = height / 2;
const gridX = Math.floor(widthSegments);
const gridY = Math.floor(heightSegments);
const gridX1 = gridX + 1;
const gridY1 = gridY + 1;
const segment_width = width / gridX;
const segment_height = height / gridY;
//
const indices = [];
const vertices = [];
const normals = [];
const uvs = [];
for (let iy = 0; iy < gridY1; iy++) {
const y = iy * segment_height - height_half;
for (let ix = 0; ix < gridX1; ix++) {
const x = ix * segment_width - width_half;
vertices.push(x, -y, 0);
normals.push(0, 0, 1);
uvs.push(ix / gridX);
uvs.push(1 - iy / gridY);
}
}
for (let iy = 0; iy < gridY; iy++) {
for (let ix = 0; ix < gridX; ix++) {
const a = ix + gridX1 * iy;
const b = ix + gridX1 * (iy + 1);
const c = ix + 1 + gridX1 * (iy + 1);
const d = ix + 1 + gridX1 * iy;
indices.push(a, b, d);
indices.push(b, c, d);
}
}
this.setIndex(indices);
this.setAttribute('position', new Float32BufferAttribute(vertices, 3));
this.setAttribute('normal', new Float32BufferAttribute(normals, 3));
this.setAttribute('uv', new Float32BufferAttribute(uvs, 2));
}
}
var alphamap_fragment = "#ifdef USE_ALPHAMAP\n\tdiffuseColor.a *= texture2D( alphaMap, vUv ).g;\n#endif";
var alphamap_pars_fragment = "#ifdef USE_ALPHAMAP\n\tuniform sampler2D alphaMap;\n#endif";
var alphatest_fragment = "#ifdef ALPHATEST\n\tif ( diffuseColor.a < ALPHATEST ) discard;\n#endif";
var 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";
var aomap_pars_fragment = "#ifdef USE_AOMAP\n\tuniform sampler2D aoMap;\n\tuniform float aoMapIntensity;\n#endif";
var begin_vertex = "vec3 transformed = vec3( position );";
var beginnormal_vertex = "vec3 objectNormal = vec3( normal );\n#ifdef USE_TANGENT\n\tvec3 objectTangent = vec3( tangent.xyz );\n#endif";
var 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";
var 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";
var clipping_planes_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvec4 plane;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < UNION_CLIPPING_PLANES; i ++ ) {\n\t\tplane = clippingPlanes[ i ];\n\t\tif ( dot( vClipPosition, plane.xyz ) > plane.w ) discard;\n\t}\n\t#pragma unroll_loop_end\n\t#if UNION_CLIPPING_PLANES < NUM_CLIPPING_PLANES\n\t\tbool clipped = true;\n\t\t#pragma unroll_loop_start\n\t\tfor ( int i = UNION_CLIPPING_PLANES; i < NUM_CLIPPING_PLANES; i ++ ) {\n\t\t\tplane = clippingPlanes[ i ];\n\t\t\tclipped = ( dot( vClipPosition, plane.xyz ) > plane.w ) && clipped;\n\t\t}\n\t\t#pragma unroll_loop_end\n\t\tif ( clipped ) discard;\n\t#endif\n#endif";
var clipping_planes_pars_fragment = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\n#endif";
var clipping_planes_pars_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvarying vec3 vClipPosition;\n#endif";
var clipping_planes_vertex = "#if NUM_CLIPPING_PLANES > 0\n\tvClipPosition = - mvPosition.xyz;\n#endif";
var color_fragment = "#ifdef USE_COLOR\n\tdiffuseColor.rgb *= vColor;\n#endif";
var color_pars_fragment = "#ifdef USE_COLOR\n\tvarying vec3 vColor;\n#endif";
var color_pars_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvarying vec3 vColor;\n#endif";
var color_vertex = "#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )\n\tvColor = vec3( 1.0 );\n#endif\n#ifdef USE_COLOR\n\tvColor.xyz *= color.xyz;\n#endif\n#ifdef USE_INSTANCING_COLOR\n\tvColor.xyz *= instanceColor.xyz;\n#endif";
var common = "#define PI 3.141592653589793\n#define PI2 6.283185307179586\n#define PI_HALF 1.5707963267948966\n#define RECIPROCAL_PI 0.3183098861837907\n#define RECIPROCAL_PI2 0.15915494309189535\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\treturn m[ 2 ][ 3 ] == - 1.0;\n}\nvec2 equirectUv( in vec3 dir ) {\n\tfloat u = atan( dir.z, dir.x ) * RECIPROCAL_PI2 + 0.5;\n\tfloat v = asin( clamp( dir.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;\n\treturn vec2( u, v );\n}";
var cube_uv_reflection_fragment = "#ifdef ENVMAP_TYPE_CUBE_UV\n\t#define cubeUV_maxMipLevel 8.0\n\t#define cubeUV_minMipLevel 4.0\n\t#define cubeUV_maxTileSize 256.0\n\t#define cubeUV_minTileSize 16.0\n\tfloat getFace( vec3 direction ) {\n\t\tvec3 absDirection = abs( direction );\n\t\tfloat face = - 1.0;\n\t\tif ( absDirection.x > absDirection.z ) {\n\t\t\tif ( absDirection.x > absDirection.y )\n\t\t\t\tface = direction.x > 0.0 ? 0.0 : 3.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t} else {\n\t\t\tif ( absDirection.z > absDirection.y )\n\t\t\t\tface = direction.z > 0.0 ? 2.0 : 5.0;\n\t\t\telse\n\t\t\t\tface = direction.y > 0.0 ? 1.0 : 4.0;\n\t\t}\n\t\treturn face;\n\t}\n\tvec2 getUV( vec3 direction, float face ) {\n\t\tvec2 uv;\n\t\tif ( face == 0.0 ) {\n\t\t\tuv = vec2( direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 1.0 ) {\n\t\t\tuv = vec2( - direction.x, - direction.z ) / abs( direction.y );\n\t\t} else if ( face == 2.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.y ) / abs( direction.z );\n\t\t} else if ( face == 3.0 ) {\n\t\t\tuv = vec2( - direction.z, direction.y ) / abs( direction.x );\n\t\t} else if ( face == 4.0 ) {\n\t\t\tuv = vec2( - direction.x, direction.z ) / abs( direction.y );\n\t\t} else {\n\t\t\tuv = vec2( direction.x, direction.y ) / abs( direction.z );\n\t\t}\n\t\treturn 0.5 * ( uv + 1.0 );\n\t}\n\tvec3 bilinearCubeUV( sampler2D envMap, vec3 direction, float mipInt ) {\n\t\tfloat face = getFace( direction );\n\t\tfloat filterInt = max( cubeUV_minMipLevel - mipInt, 0.0 );\n\t\tmipInt = max( mipInt, cubeUV_minMipLevel );\n\t\tfloat faceSize = exp2( mipInt );\n\t\tfloat texelSize = 1.0 / ( 3.0 * cubeUV_maxTileSize );\n\t\tvec2 uv = getUV( direction, face ) * ( faceSize - 1.0 );\n\t\tvec2 f = fract( uv );\n\t\tuv += 0.5 - f;\n\t\tif ( face > 2.0 ) {\n\t\t\tuv.y += faceSize;\n\t\t\tface -= 3.0;\n\t\t}\n\t\tuv.x += face * faceSize;\n\t\tif ( mipInt < cubeUV_maxMipLevel ) {\n\t\t\tuv.y += 2.0 * cubeUV_maxTileSize;\n\t\t}\n\t\tuv.y += filterInt * 2.0 * cubeUV_minTileSize;\n\t\tuv.x += 3.0 * max( 0.0, cubeUV_maxTileSize - 2.0 * faceSize );\n\t\tuv *= texelSize;\n\t\tvec3 tl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x += texelSize;\n\t\tvec3 tr = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.y += texelSize;\n\t\tvec3 br = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tuv.x -= texelSize;\n\t\tvec3 bl = envMapTexelToLinear( texture2D( envMap, uv ) ).rgb;\n\t\tvec3 tm = mix( tl, tr, f.x );\n\t\tvec3 bm = mix( bl, br, f.x );\n\t\treturn mix( tm, bm, f.y );\n\t}\n\t#define r0 1.0\n\t#define v0 0.339\n\t#define m0 - 2.0\n\t#define r1 0.8\n\t#define v1 0.276\n\t#define m1 - 1.0\n\t#define r4 0.4\n\t#define v4 0.046\n\t#define m4 2.0\n\t#define r5 0.305\n\t#define v5 0.016\n\t#define m5 3.0\n\t#define r6 0.21\n\t#define v6 0.0038\n\t#define m6 4.0\n\tfloat roughnessToMip( float roughness ) {\n\t\tfloat mip = 0.0;\n\t\tif ( roughness >= r1 ) {\n\t\t\tmip = ( r0 - roughness ) * ( m1 - m0 ) / ( r0 - r1 ) + m0;\n\t\t} else if ( roughness >= r4 ) {\n\t\t\tmip = ( r1 - roughness ) * ( m4 - m1 ) / ( r1 - r4 ) + m1;\n\t\t} else if ( roughness >= r5 ) {\n\t\t\tmip = ( r4 - roughness ) * ( m5 - m4 ) / ( r4 - r5 ) + m4;\n\t\t} else if ( roughness >= r6 ) {\n\t\t\tmip = ( r5 - roughness ) * ( m6 - m5 ) / ( r5 - r6 ) + m5;\n\t\t} else {\n\t\t\tmip = - 2.0 * log2( 1.16 * roughness );\t\t}\n\t\treturn mip;\n\t}\n\tvec4 textureCubeUV( sampler2D envMap, vec3 sampleDir, float roughness ) {\n\t\tfloat mip = clamp( roughnessToMip( roughness ), m0, cubeUV_maxMipLevel );\n\t\tfloat mipF = fract( mip );\n\t\tfloat mipInt = floor( mip );\n\t\tvec3 color0 = bilinearCubeUV( envMap, sampleDir, mipInt );\n\t\tif ( mipF == 0.0 ) {\n\t\t\treturn vec4( color0, 1.0 );\n\t\t} else {\n\t\t\tvec3 color1 = bilinearCubeUV( envMap, sampleDir, mipInt + 1.0 );\n\t\t\treturn vec4( mix( color0, color1, mipF ), 1.0 );\n\t\t}\n\t}\n#endif";
var defaultnormal_vertex = "vec3 transformedNormal = objectNormal;\n#ifdef USE_INSTANCING\n\tmat3 m = mat3( instanceMatrix );\n\ttransformedNormal /= vec3( dot( m[ 0 ], m[ 0 ] ), dot( m[ 1 ], m[ 1 ] ), dot( m[ 2 ], m[ 2 ] ) );\n\ttransformedNormal = m * transformedNormal;\n#endif\ntransformedNormal = normalMatrix * transformedNormal;\n#ifdef FLIP_SIDED\n\ttransformedNormal = - transformedNormal;\n#endif\n#ifdef USE_TANGENT\n\tvec3 transformedTangent = ( modelViewMatrix * vec4( objectTangent, 0.0 ) ).xyz;\n\t#ifdef FLIP_SIDED\n\t\ttransformedTangent = - transformedTangent;\n\t#endif\n#endif";
var displacementmap_pars_vertex = "#ifdef USE_DISPLACEMENTMAP\n\tuniform sampler2D displacementMap;\n\tuniform float displacementScale;\n\tuniform float displacementBias;\n#endif";
var displacementmap_vertex = "#ifdef USE_DISPLACEMENTMAP\n\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vUv ).x * displacementScale + displacementBias );\n#endif";
var emissivemap_fragment = "#ifdef USE_EMISSIVEMAP\n\tvec4 emissiveColor = texture2D( emissiveMap, vUv );\n\temissiveColor.rgb = emissiveMapTexelToLinear( emissiveColor ).rgb;\n\ttotalEmissiveRadiance *= emissiveColor.rgb;\n#endif";
var emissivemap_pars_fragment = "#ifdef USE_EMISSIVEMAP\n\tuniform sampler2D emissiveMap;\n#endif";
var encodings_fragment = "gl_FragColor = linearToOutputTexel( gl_FragColor );";
var 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 = clamp( floor( D ) / 255.0, 0.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}";
var envmap_fragment = "#ifdef USE_ENVMAP\n\t#ifdef ENV_WORLDPOS\n\t\tvec3 cameraToFrag;\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_CUBE_UV )\n\t\tvec4 envColor = textureCubeUV( envMap, reflectVec, 0.0 );\n\t#else\n\t\tvec4 envColor = vec4( 0.0 );\n\t#endif\n\t#ifndef ENVMAP_TYPE_CUBE_UV\n\t\tenvColor = envMapTexelToLinear( envColor );\n\t#endif\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";
var 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";
var 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";
var 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";
var 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";
var fog_vertex = "#ifdef USE_FOG\n\tfogDepth = - mvPosition.z;\n#endif";
var fog_pars_vertex = "#ifdef USE_FOG\n\tvarying float fogDepth;\n#endif";
var 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";
var 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";
var gradientmap_pars_fragment = "#ifdef USE_GRADIENTMAP\n\tuniform sampler2D gradientMap;\n#endif\nvec3 getGradientIrradiance( vec3 normal, vec3 lightDirection ) {\n\tfloat dotNL = dot( normal, lightDirection );\n\tvec2 coord = vec2( dotNL * 0.5 + 0.5, 0.0 );\n\t#ifdef USE_GRADIENTMAP\n\t\treturn texture2D( gradientMap, coord ).rgb;\n\t#else\n\t\treturn ( coord.x < 0.7 ) ? vec3( 0.7 ) : vec3( 1.0 );\n\t#endif\n}";
var lightmap_fragment = "#ifdef USE_LIGHTMAP\n\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\treflectedLight.indirectDiffuse += PI * lightMapTexelToLinear( lightMapTexel ).rgb * lightMapIntensity;\n#endif";
var lightmap_pars_fragment = "#ifdef USE_LIGHTMAP\n\tuniform sampler2D lightMap;\n\tuniform float lightMapIntensity;\n#endif";
var 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;\nvIndirectFront += getAmbientLightIrradiance( ambientLightColor );\nvIndirectFront += getLightProbeIrradiance( lightProbe, geometry );\n#ifdef DOUBLE_SIDED\n\tvIndirectBack += getAmbientLightIrradiance( ambientLightColor );\n\tvIndirectBack += getLightProbeIrradiance( lightProbe, backGeometry );\n#endif\n#if NUM_POINT_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_SPOT_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_DIR_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif\n#if NUM_HEMI_LIGHTS > 0\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\n#endif";
var 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};\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};\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};\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";
var 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\tvec4 envMapColor = textureCubeUV( envMap, worldNormal, 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\tvec3 reflectVec = reflect( -viewDir, normal );\n\t\t\treflectVec = normalize( mix( reflectVec, normal, roughness * roughness) );\n\t\t#else\n\t\t\tvec3 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\tvec4 envMapColor = textureCubeUV( envMap, reflectVec, roughness );\n\t\t#endif\n\t\treturn envMapColor.rgb * envMapIntensity;\n\t}\n#endif";
var lights_toon_fragment = "ToonMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;";
var lights_toon_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct ToonMaterial {\n\tvec3 diffuseColor;\n};\nvoid RE_Direct_Toon( const in IncidentLight directLight, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\tvec3 irradiance = getGradientIrradiance( geometry.normal, directLight.direction ) * directLight.color;\n\t#ifndef PHYSICALLY_CORRECT_LIGHTS\n\t\tirradiance *= PI;\n\t#endif\n\treflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\nvoid RE_IndirectDiffuse_Toon( const in vec3 irradiance, const in GeometricContext geometry, const in ToonMaterial material, inout ReflectedLight reflectedLight ) {\n\treflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor );\n}\n#define RE_Direct\t\t\t\tRE_Direct_Toon\n#define RE_IndirectDiffuse\t\tRE_IndirectDiffuse_Toon\n#define Material_LightProbeLOD( material )\t(0)";
var lights_phong_fragment = "BlinnPhongMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb;\nmaterial.specularColor = specular;\nmaterial.specularShininess = shininess;\nmaterial.specularStrength = specularStrength;";
var lights_phong_pars_fragment = "varying vec3 vViewPosition;\n#ifndef FLAT_SHADED\n\tvarying vec3 vNormal;\n#endif\nstruct BlinnPhongMaterial {\n\tvec3 diffuseColor;\n\tvec3 specularColor;\n\tfloat specularShininess;\n\tfloat specularStrength;\n};\nvoid RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial 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\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)";
var lights_physical_fragment = "PhysicalMaterial material;\nmaterial.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor );\nvec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) );\nfloat geometryRoughness = max( max( dxy.x, dxy.y ), dxy.z );\nmaterial.specularRoughness = max( roughnessFactor, 0.0525 );material.specularRoughness += geometryRoughness;\nmaterial.specularRoughness = min( material.specularRoughness, 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 = clearcoat;\n\tmaterial.clearcoatRoughness = clearcoatRoughness;\n\t#ifdef USE_CLEARCOATMAP\n\t\tmaterial.clearcoat *= texture2D( clearcoatMap, vUv ).x;\n\t#endif\n\t#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\t\tmaterial.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y;\n\t#endif\n\tmaterial.clearcoat = saturate( material.clearcoat );\tmaterial.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 );\n\tmaterial.clearcoatRoughness += geometryRoughness;\n\tmaterial.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 );\n#endif\n#ifdef USE_SHEEN\n\tmaterial.sheenColor = sheen;\n#endif";
var lights_physical_pars_fragment = "struct PhysicalMaterial {\n\tvec3 diffuseColor;\n\tfloat specularRoughness;\n\tvec3 specularColor;\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}";
var 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#if defined( USE_SHADOWMAP ) && NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\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\tpointLightShadow = pointLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getPointShadow( pointShadowMap[ i ], pointLightShadow.shadowMapSize, pointLightShadow.shadowBias, pointLightShadow.shadowRadius, vPointShadowCoord[ i ], pointLightShadow.shadowCameraNear, pointLightShadow.shadowCameraFar ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_SPOT_LIGHTS > 0 ) && defined( RE_Direct )\n\tSpotLight spotLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\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\tspotLightShadow = spotLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( spotShadowMap[ i ], spotLightShadow.shadowMapSize, spotLightShadow.shadowBias, spotLightShadow.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_DIR_LIGHTS > 0 ) && defined( RE_Direct )\n\tDirectionalLight directionalLight;\n\t#if defined( USE_SHADOWMAP ) && NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLightShadow;\n\t#endif\n\t#pragma unroll_loop_start\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\tdirectionalLightShadow = directionalLightShadows[ i ];\n\t\tdirectLight.color *= all( bvec2( directLight.visible, receiveShadow ) ) ? getShadow( directionalShadowMap[ i ], directionalLightShadow.shadowMapSize, directionalLightShadow.shadowBias, directionalLightShadow.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t\t#endif\n\t\tRE_Direct( directLight, geometry, material, reflectedLight );\n\t}\n\t#pragma unroll_loop_end\n#endif\n#if ( NUM_RECT_AREA_LIGHTS > 0 ) && defined( RE_Direct_RectArea )\n\tRectAreaLight rectAreaLight;\n\t#pragma unroll_loop_start\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\t#pragma unroll_loop_end\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_start\n\t\tfor ( int i = 0; i < NUM_HEMI_LIGHTS; i ++ ) {\n\t\t\tirradiance += getHemisphereLightIrradiance( hemisphereLights[ i ], geometry );\n\t\t}\n\t\t#pragma unroll_loop_end\n\t#endif\n#endif\n#if defined( RE_IndirectSpecular )\n\tvec3 radiance = vec3( 0.0 );\n\tvec3 clearcoatRadiance = vec3( 0.0 );\n#endif";
var lights_fragment_maps = "#if defined( RE_IndirectDiffuse )\n\t#ifdef USE_LIGHTMAP\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\tvec3 lightMapIrradiance = lightMapTexelToLinear( lightMapTexel ).rgb * 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";
var 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";
var 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";
var 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";
var 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";
var 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";
var map_fragment = "#ifdef USE_MAP\n\tvec4 texelColor = texture2D( map, vUv );\n\ttexelColor = mapTexelToLinear( texelColor );\n\tdiffuseColor *= texelColor;\n#endif";
var map_pars_fragment = "#ifdef USE_MAP\n\tuniform sampler2D map;\n#endif";
var 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";
var 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";
var metalnessmap_fragment = "float metalnessFactor = metalness;\n#ifdef USE_METALNESSMAP\n\tvec4 texelMetalness = texture2D( metalnessMap, vUv );\n\tmetalnessFactor *= texelMetalness.b;\n#endif";
var metalnessmap_pars_fragment = "#ifdef USE_METALNESSMAP\n\tuniform sampler2D metalnessMap;\n#endif";
var morphnormal_vertex = "#ifdef USE_MORPHNORMALS\n\tobjectNormal *= morphTargetBaseInfluence;\n\tobjectNormal += morphNormal0 * morphTargetInfluences[ 0 ];\n\tobjectNormal += morphNormal1 * morphTargetInfluences[ 1 ];\n\tobjectNormal += morphNormal2 * morphTargetInfluences[ 2 ];\n\tobjectNormal += morphNormal3 * morphTargetInfluences[ 3 ];\n#endif";
var morphtarget_pars_vertex = "#ifdef USE_MORPHTARGETS\n\tuniform float morphTargetBaseInfluence;\n\t#ifndef USE_MORPHNORMALS\n\t\tuniform float morphTargetInfluences[ 8 ];\n\t#else\n\t\tuniform float morphTargetInfluences[ 4 ];\n\t#endif\n#endif";
var morphtarget_vertex = "#ifdef USE_MORPHTARGETS\n\ttransformed *= morphTargetBaseInfluence;\n\ttransformed += morphTarget0 * morphTargetInfluences[ 0 ];\n\ttransformed += morphTarget1 * morphTargetInfluences[ 1 ];\n\ttransformed += morphTarget2 * morphTargetInfluences[ 2 ];\n\ttransformed += morphTarget3 * morphTargetInfluences[ 3 ];\n\t#ifndef USE_MORPHNORMALS\n\t\ttransformed += morphTarget4 * morphTargetInfluences[ 4 ];\n\t\ttransformed += morphTarget5 * morphTargetInfluences[ 5 ];\n\t\ttransformed += morphTarget6 * morphTargetInfluences[ 6 ];\n\t\ttransformed += morphTarget7 * morphTargetInfluences[ 7 ];\n\t#endif\n#endif";
var 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\t#if defined( TANGENTSPACE_NORMALMAP ) || defined( USE_CLEARCOAT_NORMALMAP )\n\t\t\tmat3 vTBN = mat3( tangent, bitangent, normal );\n\t\t#endif\n\t#endif\n#endif\nvec3 geometryNormal = normal;";
var 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\tvec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;\n\tmapN.xy *= normalScale;\n\t#ifdef USE_TANGENT\n\t\tnormal = normalize( vTBN * mapN );\n\t#else\n\t\tnormal = perturbNormal2Arb( -vViewPosition, normal, mapN );\n\t#endif\n#elif defined( USE_BUMPMAP )\n\tnormal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );\n#endif";
var 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, vec3 mapN ) {\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\tmat3 tsn = mat3( S, T, N );\n\t\tmapN.xy *= ( float( gl_FrontFacing ) * 2.0 - 1.0 );\n\t\treturn normalize( tsn * mapN );\n\t}\n#endif";
var clearcoat_normal_fragment_begin = "#ifdef CLEARCOAT\n\tvec3 clearcoatNormal = geometryNormal;\n#endif";
var clearcoat_normal_fragment_maps = "#ifdef USE_CLEARCOAT_NORMALMAP\n\tvec3 clearcoatMapN = texture2D( clearcoatNormalMap, vUv ).xyz * 2.0 - 1.0;\n\tclearcoatMapN.xy *= clearcoatNormalScale;\n\t#ifdef USE_TANGENT\n\t\tclearcoatNormal = normalize( vTBN * clearcoatMapN );\n\t#else\n\t\tclearcoatNormal = perturbNormal2Arb( - vViewPosition, clearcoatNormal, clearcoatMapN );\n\t#endif\n#endif";
var clearcoat_pars_fragment = "#ifdef USE_CLEARCOATMAP\n\tuniform sampler2D clearcoatMap;\n#endif\n#ifdef USE_CLEARCOAT_ROUGHNESSMAP\n\tuniform sampler2D clearcoatRoughnessMap;\n#endif\n#ifdef USE_CLEARCOAT_NORMALMAP\n\tuniform sampler2D clearcoatNormalMap;\n\tuniform vec2 clearcoatNormalScale;\n#endif";
var 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 pack2HalfToRGBA( vec2 v ) {\n\tvec4 r = vec4( v.x, fract( v.x * 255.0 ), v.y, fract( v.y * 255.0 ));\n\treturn vec4( r.x - r.y / 255.0, r.y, r.z - r.w / 255.0, r.w);\n}\nvec2 unpackRGBATo2Half( 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}";
var premultiplied_alpha_fragment = "#ifdef PREMULTIPLIED_ALPHA\n\tgl_FragColor.rgb *= gl_FragColor.a;\n#endif";
var 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;";
var dithering_fragment = "#ifdef DITHERING\n\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\n#endif";
var 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";
var roughnessmap_fragment = "float roughnessFactor = roughness;\n#ifdef USE_ROUGHNESSMAP\n\tvec4 texelRoughness = texture2D( roughnessMap, vUv );\n\troughnessFactor *= texelRoughness.g;\n#endif";
var roughnessmap_pars_fragment = "#ifdef USE_ROUGHNESSMAP\n\tuniform sampler2D roughnessMap;\n#endif";
var 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\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ 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\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ 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\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ 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 unpackRGBATo2Half( 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 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 dx = texelSize.x;\n\t\t\tfloat dy = texelSize.y;\n\t\t\tvec2 uv = shadowCoord.xy;\n\t\t\tvec2 f = fract( uv * shadowMapSize + 0.5 );\n\t\t\tuv -= f * texelSize;\n\t\t\tshadow = (\n\t\t\t\ttexture2DCompare( shadowMap, uv, shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) +\n\t\t\t\ttexture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ),\n\t\t\t\t\t f.x ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t f.y ) +\n\t\t\t\tmix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), \n\t\t\t\t\t\t texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ),\n\t\t\t\t\t\t f.x ),\n\t\t\t\t\t f.y )\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";
var 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\tstruct DirectionalLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform DirectionalLightShadow directionalLightShadows[ 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\tstruct SpotLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t};\n\t\tuniform SpotLightShadow spotLightShadows[ 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\tstruct PointLightShadow {\n\t\t\tfloat shadowBias;\n\t\t\tfloat shadowNormalBias;\n\t\t\tfloat shadowRadius;\n\t\t\tvec2 shadowMapSize;\n\t\t\tfloat shadowCameraNear;\n\t\t\tfloat shadowCameraFar;\n\t\t};\n\t\tuniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ];\n\t#endif\n#endif";
var shadowmap_vertex = "#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0 || NUM_SPOT_LIGHT_SHADOWS > 0 || NUM_POINT_LIGHT_SHADOWS > 0\n\t\tvec3 shadowWorldNormal = inverseTransformDirection( transformedNormal, viewMatrix );\n\t\tvec4 shadowWorldPosition;\n\t#endif\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * directionalLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvDirectionalShadowCoord[ i ] = directionalShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * spotLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvSpotShadowCoord[ i ] = spotShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tshadowWorldPosition = worldPosition + vec4( shadowWorldNormal * pointLightShadows[ i ].shadowNormalBias, 0 );\n\t\tvPointShadowCoord[ i ] = pointShadowMatrix[ i ] * shadowWorldPosition;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n#endif";
var shadowmask_pars_fragment = "float getShadowMask() {\n\tfloat shadow = 1.0;\n\t#ifdef USE_SHADOWMAP\n\t#if NUM_DIR_LIGHT_SHADOWS > 0\n\tDirectionalLightShadow directionalLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_DIR_LIGHT_SHADOWS; i ++ ) {\n\t\tdirectionalLight = directionalLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_SPOT_LIGHT_SHADOWS > 0\n\tSpotLightShadow spotLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_SPOT_LIGHT_SHADOWS; i ++ ) {\n\t\tspotLight = spotLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#if NUM_POINT_LIGHT_SHADOWS > 0\n\tPointLightShadow pointLight;\n\t#pragma unroll_loop_start\n\tfor ( int i = 0; i < NUM_POINT_LIGHT_SHADOWS; i ++ ) {\n\t\tpointLight = pointLightShadows[ i ];\n\t\tshadow *= receiveShadow ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;\n\t}\n\t#pragma unroll_loop_end\n\t#endif\n\t#endif\n\treturn shadow;\n}";
var 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";
var 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";
var 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";
var 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";
var 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";
var specularmap_pars_fragment = "#ifdef USE_SPECULARMAP\n\tuniform sampler2D specularMap;\n#endif";
var tonemapping_fragment = "#if defined( TONE_MAPPING )\n\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\n#endif";
var tonemapping_pars_fragment = "#ifndef saturate\n#define saturate(a) clamp( a, 0.0, 1.0 )\n#endif\nuniform float toneMappingExposure;\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}\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 RRTAndODTFit( vec3 v ) {\n\tvec3 a = v * ( v + 0.0245786 ) - 0.000090537;\n\tvec3 b = v * ( 0.983729 * v + 0.4329510 ) + 0.238081;\n\treturn a / b;\n}\nvec3 ACESFilmicToneMapping( vec3 color ) {\n\tconst mat3 ACESInputMat = mat3(\n\t\tvec3( 0.59719, 0.07600, 0.02840 ),\t\tvec3( 0.35458, 0.90834, 0.13383 ),\n\t\tvec3( 0.04823, 0.01566, 0.83777 )\n\t);\n\tconst mat3 ACESOutputMat = mat3(\n\t\tvec3( 1.60475, -0.10208, -0.00327 ),\t\tvec3( -0.53108, 1.10813, -0.07276 ),\n\t\tvec3( -0.07367, -0.00605, 1.07602 )\n\t);\n\tcolor *= toneMappingExposure / 0.6;\n\tcolor = ACESInputMat * color;\n\tcolor = RRTAndODTFit( color );\n\tcolor = ACESOutputMat * color;\n\treturn saturate( color );\n}\nvec3 CustomToneMapping( vec3 color ) { return color; }";
var transmissionmap_fragment = "#ifdef USE_TRANSMISSIONMAP\n\ttotalTransmission *= texture2D( transmissionMap, vUv ).r;\n#endif";
var transmissionmap_pars_fragment = "#ifdef USE_TRANSMISSIONMAP\n\tuniform sampler2D transmissionMap;\n#endif";
var uv_pars_fragment = "#if ( defined( USE_UV ) && ! defined( UVS_VERTEX_ONLY ) )\n\tvarying vec2 vUv;\n#endif";
var 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";
var uv_vertex = "#ifdef USE_UV\n\tvUv = ( uvTransform * vec3( uv, 1 ) ).xy;\n#endif";
var uv2_pars_fragment = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvarying vec2 vUv2;\n#endif";
var uv2_pars_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tattribute vec2 uv2;\n\tvarying vec2 vUv2;\n\tuniform mat3 uv2Transform;\n#endif";
var uv2_vertex = "#if defined( USE_LIGHTMAP ) || defined( USE_AOMAP )\n\tvUv2 = ( uv2Transform * vec3( uv2, 1 ) ).xy;\n#endif";
var 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";
var 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}";
var 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}";
var cube_frag = "#include \nuniform float opacity;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 vReflect = vWorldDirection;\n\t#include \n\tgl_FragColor = envColor;\n\tgl_FragColor.a *= opacity;\n\t#include \n\t#include \n}";
var 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}";
var 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 \nvarying vec2 vHighPrecisionZW;\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\tfloat fragCoordZ = 0.5 * vHighPrecisionZW[0] / vHighPrecisionZW[1] + 0.5;\n\t#if DEPTH_PACKING == 3200\n\t\tgl_FragColor = vec4( vec3( 1.0 - fragCoordZ ), opacity );\n\t#elif DEPTH_PACKING == 3201\n\t\tgl_FragColor = packDepthToRGBA( fragCoordZ );\n\t#endif\n}";
var depth_vert = "#include \n#include \n#include \n#include \n#include \n#include \n#include \nvarying vec2 vHighPrecisionZW;\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\tvHighPrecisionZW = gl_Position.zw;\n}";
var 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}";
var 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}";
var equirect_frag = "uniform sampler2D tEquirect;\nvarying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvec3 direction = normalize( vWorldDirection );\n\tvec2 sampleUV = equirectUv( direction );\n\tvec4 texColor = texture2D( tEquirect, sampleUV );\n\tgl_FragColor = mapTexelToLinear( texColor );\n\t#include \n\t#include \n}";
var equirect_vert = "varying vec3 vWorldDirection;\n#include \nvoid main() {\n\tvWorldDirection = transformDirection( position, modelMatrix );\n\t#include \n\t#include \n}";
var 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}";
var linedashed_vert = "uniform float scale;\nattribute float lineDistance;\nvarying float vLineDistance;\n#include \n#include \n#include \n#include \n#include \n#include \nvoid main() {\n\tvLineDistance = scale * lineDistance;\n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n\t#include \n}";
var 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 \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\n\t\tvec4 lightMapTexel= texture2D( lightMap, vUv2 );\n\t\treflectedLight.indirectDiffuse += lightMapTexelToLinear( lightMapTexel ).rgb * 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\t#include \n}";
var 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}";
var 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 \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#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}";
var 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