Repository: shrekshao/minimal-gltf-loader Branch: master Commit: 9e42301099bf Files: 26 Total size: 654.5 KB Directory structure: gitextract_ikmxro3d/ ├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── build/ │ ├── app.js │ └── minimal-gltf-loader.js ├── css/ │ └── style.css ├── examples/ │ ├── occlusion-culling-demo.html │ ├── style.css │ ├── utility.js │ ├── webgl2-renderer-old.html │ ├── webgl2-renderer.html │ └── webpack.config.js ├── gulpfile.js ├── package.json ├── src/ │ ├── glTFLoader.ts │ ├── index.js │ ├── minimal-gltf-loader.js │ └── shaders/ │ ├── fs-bbox.glsl │ ├── fs-cube-map.glsl │ ├── fs-pbr-master.glsl │ ├── vs-bbox.glsl │ ├── vs-cube-map.glsl │ └── vs-pbr-master.glsl ├── third-party-license/ │ └── glMatrix └── webpack.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ .orig # Created by https://www.gitignore.io/api/vim,emacs,sublimetext,webstorm,eclipse ### Vim ### [._]*.s[a-w][a-z] [._]s[a-w][a-z] *.un~ Session.vim .netrwhist *~ ### Emacs ### # -*- mode: gitignore; -*- *~ \#*\# /.emacs.desktop /.emacs.desktop.lock *.elc auto-save-list tramp .\#* # Org-mode .org-id-locations *_archive # flymake-mode *_flymake.* # eshell files /eshell/history /eshell/lastdir # elpa packages /elpa/ # reftex files *.rel # AUCTeX auto folder /auto/ # cask packages .cask/ ### SublimeText ### # cache files for sublime text *.tmlanguage.cache *.tmPreferences.cache *.stTheme.cache # workspace files are user-specific *.sublime-workspace # project files should be checked into the repository, unless a significant # proportion of contributors will probably not be using SublimeText # *.sublime-project # sftp configuration file sftp-config.json ### WebStorm ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio *.iml ## Directory-based project format: .idea/ # if you remove the above rule, at least ignore the following: # User-specific stuff: # .idea/workspace.xml # .idea/tasks.xml # .idea/dictionaries # Sensitive or high-churn files: # .idea/dataSources.ids # .idea/dataSources.xml # .idea/sqlDataSources.xml # .idea/dynamic.xml # .idea/uiDesigner.xml # Gradle: # .idea/gradle.xml # .idea/libraries # Mongo Explorer plugin: # .idea/mongoSettings.xml ## File-based project format: *.ipr *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties ### Eclipse ### *.pydevproject .metadata .gradle bin/ tmp/ *.tmp *.bak *.swp *~.nib local.properties .settings/ .loadpath # Eclipse Core .project # External tool builders .externalToolBuilders/ # Locally stored "Eclipse launch configurations" *.launch # CDT-specific .cproject # JDT-specific (Eclipse Java Development Tools) .classpath # Java annotation processor (APT) .factorypath # PDT-specific .buildpath # sbteclipse plugin .target # TeXlipse plugin .texlipse # VS Code jsconfig.json debug/ .DS_Store node_modules/ npm-debug.log ================================================ FILE: .travis.yml ================================================ language: node_js node_js: - 4.4 ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Shuai Shao (shrekshao) and Contributors 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. ================================================ FILE: README.md ================================================ # minimal-gltf-loader [![Build Status](https://travis-ci.org/shrekshao/minimal-gltf-loader.svg?branch=master)](https://travis-ci.org/shrekshao/minimal-gltf-loader) [![License](http://img.shields.io/:license-mit-blue.svg)](https://github.com/shrekshao/minimal-gltf-loader/blob/master/LICENSE.md) A minimal, engine-agnostic JavaScript glTF Loader, with a raw WebGL 2 simple renderer example using the loader. ## Viewer Screenshot ![](img/drone.gif) ![](img/helmet-pbr.png) ![](img/skin.gif) ![](img/viewer-screenshot-buggy-bbox.png) ## Live Demo [click here for live demo](https://shrekshao.github.io/minimal-gltf-loader/examples/webgl2-renderer.html) # Usage ```javascript import {vec3, vec4, quat, mat4} from 'gl-matrix'; var MinimalGLTFLoader = require('build/minimal-gltf-loader.js'); var glTFLoader = new MinimalGLTFLoader.glTFLoader(); glTFLoader.loadGLTF(url, function(glTF){ //... }); ``` ## Loading Features * [x] Accessors - [ ] Progressive loading / rendering * [x] Buffers * [x] BufferViews * [x] Images * [x] Meshes * [x] Nodes * [x] Primitives * [x] Samplers * [x] Textures * [x] ~~Shader Loader~~ (not part of the core of glTF 2.0) * [x] Animations * [x] Cameras * [x] Materials * [x] Skins ## Formats * [x] glTF (.gltf) with separate resources: .bin (geometry, animation, skins), .glsl (shaders), and image files * [ ] glTF (.gltf) with embedded resources * [ ] Binary glTF (.glb) using the [KHR_binary_glTF](https://github.com/KhronosGroup/glTF/blob/master/extensions/Khronos/KHR_binary_glTF/README.md) extension ## Examples * [x] WebGL 2 simple renderer * [x] baseColorFactor * [x] baseColorTexture * [x] normalTexture * [x] Skybox * [x] PBR * [x] Animation * [ ] Interpolations - [x] LINEAR - [ ] STEP - [ ] CATMULLROMSPLINE - [ ] CUBICSPLINE * [x] Skin * [ ] Camera (from glTF) * [ ] Progressive rendering (No plan for this) * [ ] Occlusion Culling experiment * [x] Bounding Box * [x] AABB (Axis Aligned Bounding Box, *static) * [x] OBB (Object/Oriented Bounding Box) * [x] Scene Bounding Box (fast iterated) And auto centered and scaled * [ ] Build octree * [ ] Occlusion Query with hierarchy ## Credits * [glTF sample Model](https://github.com/KhronosGroup/glTF-Sample-Models) and [Buster Drone By LaVADraGoN](https://sketchfab.com/models/294e79652f494130ad2ab00a13fdbafd) * Great thanks to Trung Le ([@trungtle](https://github.com/trungtle)) and Patrick Cozzi ([@pjcozzi](https://github.com/pjcozzi)) for contributing and advising. * gl-Matrix by Brandon Jones ([@toji](https://github.com/toji)) and Colin MacKenzie IV ([@sinisterchipmunk](https://github.com/sinisterchipmunk)) * [glTF-WebGL-PBR](https://github.com/KhronosGroup/glTF-WebGL-PBR) --- # minimal-gltf-loader-typescript A minimal, engine-agnostic TypeScript glTF Loader. ## What's new in gltf-loader-typescript This loader is a new instance of the minimal-gltf-loader. In this branch, the author updated the loading file fuction from XMLHttpRequest to fetch API and used Promise and async/await to make loading procedure much more clearer. In glTF 2.0 standard, the target attribute on bufferView is optional. Different 3D softwares have different interpretation of glTF exporter. For instance, the glTF files exported by Cinema4D have filled target attribute, but those exported by Blender 2.80+ **will NOT** have the target attribute filled. (Can see the issue in the following link: [KhronosGroup/glTF-Blender-IO#142](https://github.com/KhronosGroup/glTF-Blender-IO/issues/142)) Therefore, before binding buffer, the loader should infer the target attribute is whether ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER accoring to the usage of bufferview. ## Usage ```typescript import {vec3, vec4, quat, mat4} from 'gl-matrix'; import {GLTFLoader, GLTF} from './src/glTFLoader.ts' let gl : WebGLRenderingContext | WebGL2RenderingContext; new GLTFLoader(gl).loadGLTF('YourURL').then((glTF: GLTF) => { // Create with glTF object, and proceed rendering process... }).catch (() => { // Error control... }); ``` ================================================ FILE: build/app.js ================================================ /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __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; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 7); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "EPSILON", function() { return EPSILON; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ARRAY_TYPE", function() { return ARRAY_TYPE; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "RANDOM", function() { return RANDOM; }); /* harmony export (immutable) */ __webpack_exports__["setMatrixArrayType"] = setMatrixArrayType; /* harmony export (immutable) */ __webpack_exports__["toRadian"] = toRadian; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /** * Common utilities * @module glMatrix */ // Configuration Constants var EPSILON = 0.000001; var ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array; var RANDOM = Math.random; /** * Sets the type of array used when creating new vectors and matrices * * @param {Type} type Array type, such as Float32Array or Array */ function setMatrixArrayType(type) { ARRAY_TYPE = type; } var degree = Math.PI / 180; /** * Convert Degree To Radian * * @param {Number} a Angle in Degrees */ function toRadian(a) { return a * degree; } /** * Tests whether or not the arguments have approximately the same value, within an absolute * or relative tolerance of glMatrix.EPSILON (an absolute tolerance is used for values less * than or equal to 1.0, and a relative tolerance is used for larger values) * * @param {Number} a The first number to test. * @param {Number} b The second number to test. * @returns {Boolean} True if the numbers are approximately equal, false otherwise. */ function equals(a, b) { return Math.abs(a - b) <= EPSILON * Math.max(1.0, Math.abs(a), Math.abs(b)); } /***/ }), /* 1 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__gl_matrix_common_js__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__gl_matrix_mat2_js__ = __webpack_require__(8); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__gl_matrix_mat2d_js__ = __webpack_require__(9); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__gl_matrix_mat3_js__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_4__gl_matrix_mat4_js__ = __webpack_require__(3); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_5__gl_matrix_quat_js__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_6__gl_matrix_quat2_js__ = __webpack_require__(10); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_7__gl_matrix_vec2_js__ = __webpack_require__(11); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_8__gl_matrix_vec3_js__ = __webpack_require__(5); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_9__gl_matrix_vec4_js__ = __webpack_require__(6); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "glMatrix", function() { return __WEBPACK_IMPORTED_MODULE_0__gl_matrix_common_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat2", function() { return __WEBPACK_IMPORTED_MODULE_1__gl_matrix_mat2_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat2d", function() { return __WEBPACK_IMPORTED_MODULE_2__gl_matrix_mat2d_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat3", function() { return __WEBPACK_IMPORTED_MODULE_3__gl_matrix_mat3_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "mat4", function() { return __WEBPACK_IMPORTED_MODULE_4__gl_matrix_mat4_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "quat", function() { return __WEBPACK_IMPORTED_MODULE_5__gl_matrix_quat_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "quat2", function() { return __WEBPACK_IMPORTED_MODULE_6__gl_matrix_quat2_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec2", function() { return __WEBPACK_IMPORTED_MODULE_7__gl_matrix_vec2_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec3", function() { return __WEBPACK_IMPORTED_MODULE_8__gl_matrix_vec3_js__; }); /* harmony reexport (module object) */ __webpack_require__.d(__webpack_exports__, "vec4", function() { return __WEBPACK_IMPORTED_MODULE_9__gl_matrix_vec4_js__; }); /***/ }), /* 2 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["fromMat4"] = fromMat4; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; /* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["translate"] = translate; /* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; /* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; /* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; /* harmony export (immutable) */ __webpack_exports__["fromMat2d"] = fromMat2d; /* harmony export (immutable) */ __webpack_exports__["fromQuat"] = fromQuat; /* harmony export (immutable) */ __webpack_exports__["normalFromMat4"] = normalFromMat4; /* harmony export (immutable) */ __webpack_exports__["projection"] = projection; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["frob"] = frob; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; /* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 3x3 Matrix * @module mat3 */ /** * Creates a new identity mat3 * * @returns {mat3} a new 3x3 matrix */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](9); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[5] = 0; out[6] = 0; out[7] = 0; } out[0] = 1; out[4] = 1; out[8] = 1; return out; } /** * Copies the upper-left 3x3 values into the given mat3. * * @param {mat3} out the receiving 3x3 matrix * @param {mat4} a the source 4x4 matrix * @returns {mat3} out */ function fromMat4(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[4]; out[4] = a[5]; out[5] = a[6]; out[6] = a[8]; out[7] = a[9]; out[8] = a[10]; return out; } /** * Creates a new mat3 initialized with values from an existing matrix * * @param {mat3} a matrix to clone * @returns {mat3} a new 3x3 matrix */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](9); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; return out; } /** * Copy the values from one mat3 to another * * @param {mat3} out the receiving matrix * @param {mat3} a the source matrix * @returns {mat3} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; return out; } /** * Create a new mat3 with the given values * * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m02 Component in column 0, row 2 position (index 2) * @param {Number} m10 Component in column 1, row 0 position (index 3) * @param {Number} m11 Component in column 1, row 1 position (index 4) * @param {Number} m12 Component in column 1, row 2 position (index 5) * @param {Number} m20 Component in column 2, row 0 position (index 6) * @param {Number} m21 Component in column 2, row 1 position (index 7) * @param {Number} m22 Component in column 2, row 2 position (index 8) * @returns {mat3} A new mat3 */ function fromValues(m00, m01, m02, m10, m11, m12, m20, m21, m22) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](9); out[0] = m00; out[1] = m01; out[2] = m02; out[3] = m10; out[4] = m11; out[5] = m12; out[6] = m20; out[7] = m21; out[8] = m22; return out; } /** * Set the components of a mat3 to the given values * * @param {mat3} out the receiving matrix * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m02 Component in column 0, row 2 position (index 2) * @param {Number} m10 Component in column 1, row 0 position (index 3) * @param {Number} m11 Component in column 1, row 1 position (index 4) * @param {Number} m12 Component in column 1, row 2 position (index 5) * @param {Number} m20 Component in column 2, row 0 position (index 6) * @param {Number} m21 Component in column 2, row 1 position (index 7) * @param {Number} m22 Component in column 2, row 2 position (index 8) * @returns {mat3} out */ function set(out, m00, m01, m02, m10, m11, m12, m20, m21, m22) { out[0] = m00; out[1] = m01; out[2] = m02; out[3] = m10; out[4] = m11; out[5] = m12; out[6] = m20; out[7] = m21; out[8] = m22; return out; } /** * Set a mat3 to the identity matrix * * @param {mat3} out the receiving matrix * @returns {mat3} out */ function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 1; out[5] = 0; out[6] = 0; out[7] = 0; out[8] = 1; return out; } /** * Transpose the values of a mat3 * * @param {mat3} out the receiving matrix * @param {mat3} a the source matrix * @returns {mat3} out */ function transpose(out, a) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (out === a) { var a01 = a[1], a02 = a[2], a12 = a[5]; out[1] = a[3]; out[2] = a[6]; out[3] = a01; out[5] = a[7]; out[6] = a02; out[7] = a12; } else { out[0] = a[0]; out[1] = a[3]; out[2] = a[6]; out[3] = a[1]; out[4] = a[4]; out[5] = a[7]; out[6] = a[2]; out[7] = a[5]; out[8] = a[8]; } return out; } /** * Inverts a mat3 * * @param {mat3} out the receiving matrix * @param {mat3} a the source matrix * @returns {mat3} out */ function invert(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2]; var a10 = a[3], a11 = a[4], a12 = a[5]; var a20 = a[6], a21 = a[7], a22 = a[8]; var b01 = a22 * a11 - a12 * a21; var b11 = -a22 * a10 + a12 * a20; var b21 = a21 * a10 - a11 * a20; // Calculate the determinant var det = a00 * b01 + a01 * b11 + a02 * b21; if (!det) { return null; } det = 1.0 / det; out[0] = b01 * det; out[1] = (-a22 * a01 + a02 * a21) * det; out[2] = (a12 * a01 - a02 * a11) * det; out[3] = b11 * det; out[4] = (a22 * a00 - a02 * a20) * det; out[5] = (-a12 * a00 + a02 * a10) * det; out[6] = b21 * det; out[7] = (-a21 * a00 + a01 * a20) * det; out[8] = (a11 * a00 - a01 * a10) * det; return out; } /** * Calculates the adjugate of a mat3 * * @param {mat3} out the receiving matrix * @param {mat3} a the source matrix * @returns {mat3} out */ function adjoint(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2]; var a10 = a[3], a11 = a[4], a12 = a[5]; var a20 = a[6], a21 = a[7], a22 = a[8]; out[0] = a11 * a22 - a12 * a21; out[1] = a02 * a21 - a01 * a22; out[2] = a01 * a12 - a02 * a11; out[3] = a12 * a20 - a10 * a22; out[4] = a00 * a22 - a02 * a20; out[5] = a02 * a10 - a00 * a12; out[6] = a10 * a21 - a11 * a20; out[7] = a01 * a20 - a00 * a21; out[8] = a00 * a11 - a01 * a10; return out; } /** * Calculates the determinant of a mat3 * * @param {mat3} a the source matrix * @returns {Number} determinant of a */ function determinant(a) { var a00 = a[0], a01 = a[1], a02 = a[2]; var a10 = a[3], a11 = a[4], a12 = a[5]; var a20 = a[6], a21 = a[7], a22 = a[8]; return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20); } /** * Multiplies two mat3's * * @param {mat3} out the receiving matrix * @param {mat3} a the first operand * @param {mat3} b the second operand * @returns {mat3} out */ function multiply(out, a, b) { var a00 = a[0], a01 = a[1], a02 = a[2]; var a10 = a[3], a11 = a[4], a12 = a[5]; var a20 = a[6], a21 = a[7], a22 = a[8]; var b00 = b[0], b01 = b[1], b02 = b[2]; var b10 = b[3], b11 = b[4], b12 = b[5]; var b20 = b[6], b21 = b[7], b22 = b[8]; out[0] = b00 * a00 + b01 * a10 + b02 * a20; out[1] = b00 * a01 + b01 * a11 + b02 * a21; out[2] = b00 * a02 + b01 * a12 + b02 * a22; out[3] = b10 * a00 + b11 * a10 + b12 * a20; out[4] = b10 * a01 + b11 * a11 + b12 * a21; out[5] = b10 * a02 + b11 * a12 + b12 * a22; out[6] = b20 * a00 + b21 * a10 + b22 * a20; out[7] = b20 * a01 + b21 * a11 + b22 * a21; out[8] = b20 * a02 + b21 * a12 + b22 * a22; return out; } /** * Translate a mat3 by the given vector * * @param {mat3} out the receiving matrix * @param {mat3} a the matrix to translate * @param {vec2} v vector to translate by * @returns {mat3} out */ function translate(out, a, v) { var a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8], x = v[0], y = v[1]; out[0] = a00; out[1] = a01; out[2] = a02; out[3] = a10; out[4] = a11; out[5] = a12; out[6] = x * a00 + y * a10 + a20; out[7] = x * a01 + y * a11 + a21; out[8] = x * a02 + y * a12 + a22; return out; } /** * Rotates a mat3 by the given angle * * @param {mat3} out the receiving matrix * @param {mat3} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat3} out */ function rotate(out, a, rad) { var a00 = a[0], a01 = a[1], a02 = a[2], a10 = a[3], a11 = a[4], a12 = a[5], a20 = a[6], a21 = a[7], a22 = a[8], s = Math.sin(rad), c = Math.cos(rad); out[0] = c * a00 + s * a10; out[1] = c * a01 + s * a11; out[2] = c * a02 + s * a12; out[3] = c * a10 - s * a00; out[4] = c * a11 - s * a01; out[5] = c * a12 - s * a02; out[6] = a20; out[7] = a21; out[8] = a22; return out; }; /** * Scales the mat3 by the dimensions in the given vec2 * * @param {mat3} out the receiving matrix * @param {mat3} a the matrix to rotate * @param {vec2} v the vec2 to scale the matrix by * @returns {mat3} out **/ function scale(out, a, v) { var x = v[0], y = v[1]; out[0] = x * a[0]; out[1] = x * a[1]; out[2] = x * a[2]; out[3] = y * a[3]; out[4] = y * a[4]; out[5] = y * a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; return out; } /** * Creates a matrix from a vector translation * This is equivalent to (but much faster than): * * mat3.identity(dest); * mat3.translate(dest, dest, vec); * * @param {mat3} out mat3 receiving operation result * @param {vec2} v Translation vector * @returns {mat3} out */ function fromTranslation(out, v) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 1; out[5] = 0; out[6] = v[0]; out[7] = v[1]; out[8] = 1; return out; } /** * Creates a matrix from a given angle * This is equivalent to (but much faster than): * * mat3.identity(dest); * mat3.rotate(dest, dest, rad); * * @param {mat3} out mat3 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat3} out */ function fromRotation(out, rad) { var s = Math.sin(rad), c = Math.cos(rad); out[0] = c; out[1] = s; out[2] = 0; out[3] = -s; out[4] = c; out[5] = 0; out[6] = 0; out[7] = 0; out[8] = 1; return out; } /** * Creates a matrix from a vector scaling * This is equivalent to (but much faster than): * * mat3.identity(dest); * mat3.scale(dest, dest, vec); * * @param {mat3} out mat3 receiving operation result * @param {vec2} v Scaling vector * @returns {mat3} out */ function fromScaling(out, v) { out[0] = v[0]; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = v[1]; out[5] = 0; out[6] = 0; out[7] = 0; out[8] = 1; return out; } /** * Copies the values from a mat2d into a mat3 * * @param {mat3} out the receiving matrix * @param {mat2d} a the matrix to copy * @returns {mat3} out **/ function fromMat2d(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = 0; out[3] = a[2]; out[4] = a[3]; out[5] = 0; out[6] = a[4]; out[7] = a[5]; out[8] = 1; return out; } /** * Calculates a 3x3 matrix from the given quaternion * * @param {mat3} out mat3 receiving operation result * @param {quat} q Quaternion to create matrix from * * @returns {mat3} out */ function fromQuat(out, q) { var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var yx = y * x2; var yy = y * y2; var zx = z * x2; var zy = z * y2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var wz = w * z2; out[0] = 1 - yy - zz; out[3] = yx - wz; out[6] = zx + wy; out[1] = yx + wz; out[4] = 1 - xx - zz; out[7] = zy - wx; out[2] = zx - wy; out[5] = zy + wx; out[8] = 1 - xx - yy; return out; } /** * Calculates a 3x3 normal matrix (transpose inverse) from the 4x4 matrix * * @param {mat3} out mat3 receiving operation result * @param {mat4} a Mat4 to derive the normal matrix from * * @returns {mat3} out */ function normalFromMat4(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b00 = a00 * a11 - a01 * a10; var b01 = a00 * a12 - a02 * a10; var b02 = a00 * a13 - a03 * a10; var b03 = a01 * a12 - a02 * a11; var b04 = a01 * a13 - a03 * a11; var b05 = a02 * a13 - a03 * a12; var b06 = a20 * a31 - a21 * a30; var b07 = a20 * a32 - a22 * a30; var b08 = a20 * a33 - a23 * a30; var b09 = a21 * a32 - a22 * a31; var b10 = a21 * a33 - a23 * a31; var b11 = a22 * a33 - a23 * a32; // Calculate the determinant var 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] = (a12 * b08 - a10 * b11 - a13 * b07) * det; out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det; out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det; out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det; out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det; out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det; out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det; out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det; return out; } /** * Generates a 2D projection matrix with the given bounds * * @param {mat3} out mat3 frustum matrix will be written into * @param {number} width Width of your gl context * @param {number} height Height of gl context * @returns {mat3} out */ function projection(out, width, height) { out[0] = 2 / width; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = -2 / height; out[5] = 0; out[6] = -1; out[7] = 1; out[8] = 1; return out; } /** * Returns a string representation of a mat3 * * @param {mat3} a matrix to represent as a string * @returns {String} string representation of the matrix */ function str(a) { return 'mat3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ')'; } /** * Returns Frobenius norm of a mat3 * * @param {mat3} a the matrix to calculate Frobenius norm of * @returns {Number} Frobenius norm */ function frob(a) { return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2)); } /** * Adds two mat3's * * @param {mat3} out the receiving matrix * @param {mat3} a the first operand * @param {mat3} b the second operand * @returns {mat3} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; out[6] = a[6] + b[6]; out[7] = a[7] + b[7]; out[8] = a[8] + b[8]; return out; } /** * Subtracts matrix b from matrix a * * @param {mat3} out the receiving matrix * @param {mat3} a the first operand * @param {mat3} b the second operand * @returns {mat3} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; out[4] = a[4] - b[4]; out[5] = a[5] - b[5]; out[6] = a[6] - b[6]; out[7] = a[7] - b[7]; out[8] = a[8] - b[8]; return out; } /** * Multiply each element of the matrix by a scalar. * * @param {mat3} out the receiving matrix * @param {mat3} a the matrix to scale * @param {Number} b amount to scale the matrix's elements by * @returns {mat3} out */ function multiplyScalar(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; out[4] = a[4] * b; out[5] = a[5] * b; out[6] = a[6] * b; out[7] = a[7] * b; out[8] = a[8] * b; return out; } /** * Adds two mat3's after multiplying each element of the second operand by a scalar value. * * @param {mat3} out the receiving vector * @param {mat3} a the first operand * @param {mat3} b the second operand * @param {Number} scale the amount to scale b's elements by before adding * @returns {mat3} out */ function multiplyScalarAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; out[3] = a[3] + b[3] * scale; out[4] = a[4] + b[4] * scale; out[5] = a[5] + b[5] * scale; out[6] = a[6] + b[6] * scale; out[7] = a[7] + b[7] * scale; out[8] = a[8] + b[8] * scale; return out; } /** * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) * * @param {mat3} a The first matrix. * @param {mat3} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8]; } /** * Returns whether or not the matrices have approximately the same elements in the same position. * * @param {mat3} a The first matrix. * @param {mat3} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7], a8 = a[8]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7], b8 = b[8]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a8), Math.abs(b8)); } /** * Alias for {@link mat3.multiply} * @function */ var mul = multiply; /** * Alias for {@link mat3.subtract} * @function */ var sub = subtract; /***/ }), /* 3 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; /* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["translate"] = translate; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; /* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; /* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; /* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; /* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; /* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; /* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; /* harmony export (immutable) */ __webpack_exports__["fromXRotation"] = fromXRotation; /* harmony export (immutable) */ __webpack_exports__["fromYRotation"] = fromYRotation; /* harmony export (immutable) */ __webpack_exports__["fromZRotation"] = fromZRotation; /* harmony export (immutable) */ __webpack_exports__["fromRotationTranslation"] = fromRotationTranslation; /* harmony export (immutable) */ __webpack_exports__["fromQuat2"] = fromQuat2; /* harmony export (immutable) */ __webpack_exports__["getTranslation"] = getTranslation; /* harmony export (immutable) */ __webpack_exports__["getScaling"] = getScaling; /* harmony export (immutable) */ __webpack_exports__["getRotation"] = getRotation; /* harmony export (immutable) */ __webpack_exports__["fromRotationTranslationScale"] = fromRotationTranslationScale; /* harmony export (immutable) */ __webpack_exports__["fromRotationTranslationScaleOrigin"] = fromRotationTranslationScaleOrigin; /* harmony export (immutable) */ __webpack_exports__["fromQuat"] = fromQuat; /* harmony export (immutable) */ __webpack_exports__["frustum"] = frustum; /* harmony export (immutable) */ __webpack_exports__["perspective"] = perspective; /* harmony export (immutable) */ __webpack_exports__["perspectiveFromFieldOfView"] = perspectiveFromFieldOfView; /* harmony export (immutable) */ __webpack_exports__["ortho"] = ortho; /* harmony export (immutable) */ __webpack_exports__["lookAt"] = lookAt; /* harmony export (immutable) */ __webpack_exports__["targetTo"] = targetTo; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["frob"] = frob; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; /* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 4x4 Matrix
Format: column-major, when typed out it looks like row-major
The matrices are being post multiplied. * @module mat4 */ /** * Creates a new identity mat4 * * @returns {mat4} a new 4x4 matrix */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](16); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; } out[0] = 1; out[5] = 1; out[10] = 1; out[15] = 1; return out; } /** * Creates a new mat4 initialized with values from an existing matrix * * @param {mat4} a matrix to clone * @returns {mat4} a new 4x4 matrix */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](16); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } /** * Copy the values from one mat4 to another * * @param {mat4} out the receiving matrix * @param {mat4} a the source matrix * @returns {mat4} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } /** * Create a new mat4 with the given values * * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m02 Component in column 0, row 2 position (index 2) * @param {Number} m03 Component in column 0, row 3 position (index 3) * @param {Number} m10 Component in column 1, row 0 position (index 4) * @param {Number} m11 Component in column 1, row 1 position (index 5) * @param {Number} m12 Component in column 1, row 2 position (index 6) * @param {Number} m13 Component in column 1, row 3 position (index 7) * @param {Number} m20 Component in column 2, row 0 position (index 8) * @param {Number} m21 Component in column 2, row 1 position (index 9) * @param {Number} m22 Component in column 2, row 2 position (index 10) * @param {Number} m23 Component in column 2, row 3 position (index 11) * @param {Number} m30 Component in column 3, row 0 position (index 12) * @param {Number} m31 Component in column 3, row 1 position (index 13) * @param {Number} m32 Component in column 3, row 2 position (index 14) * @param {Number} m33 Component in column 3, row 3 position (index 15) * @returns {mat4} A new mat4 */ function fromValues(m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](16); out[0] = m00; out[1] = m01; out[2] = m02; out[3] = m03; out[4] = m10; out[5] = m11; out[6] = m12; out[7] = m13; out[8] = m20; out[9] = m21; out[10] = m22; out[11] = m23; out[12] = m30; out[13] = m31; out[14] = m32; out[15] = m33; return out; } /** * Set the components of a mat4 to the given values * * @param {mat4} out the receiving matrix * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m02 Component in column 0, row 2 position (index 2) * @param {Number} m03 Component in column 0, row 3 position (index 3) * @param {Number} m10 Component in column 1, row 0 position (index 4) * @param {Number} m11 Component in column 1, row 1 position (index 5) * @param {Number} m12 Component in column 1, row 2 position (index 6) * @param {Number} m13 Component in column 1, row 3 position (index 7) * @param {Number} m20 Component in column 2, row 0 position (index 8) * @param {Number} m21 Component in column 2, row 1 position (index 9) * @param {Number} m22 Component in column 2, row 2 position (index 10) * @param {Number} m23 Component in column 2, row 3 position (index 11) * @param {Number} m30 Component in column 3, row 0 position (index 12) * @param {Number} m31 Component in column 3, row 1 position (index 13) * @param {Number} m32 Component in column 3, row 2 position (index 14) * @param {Number} m33 Component in column 3, row 3 position (index 15) * @returns {mat4} out */ function set(out, m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33) { out[0] = m00; out[1] = m01; out[2] = m02; out[3] = m03; out[4] = m10; out[5] = m11; out[6] = m12; out[7] = m13; out[8] = m20; out[9] = m21; out[10] = m22; out[11] = m23; out[12] = m30; out[13] = m31; out[14] = m32; out[15] = m33; return out; } /** * Set a mat4 to the identity matrix * * @param {mat4} out the receiving matrix * @returns {mat4} out */ function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Transpose the values of a mat4 * * @param {mat4} out the receiving matrix * @param {mat4} a the source matrix * @returns {mat4} out */ function transpose(out, a) { // If we are transposing ourselves we can skip a few steps but have to cache some values if (out === a) { var a01 = a[1], a02 = a[2], a03 = a[3]; var a12 = a[6], a13 = a[7]; var a23 = a[11]; out[1] = a[4]; out[2] = a[8]; out[3] = a[12]; out[4] = a01; out[6] = a[9]; out[7] = a[13]; out[8] = a02; out[9] = a12; out[11] = a[14]; out[12] = a03; out[13] = a13; out[14] = a23; } else { out[0] = a[0]; out[1] = a[4]; out[2] = a[8]; out[3] = a[12]; out[4] = a[1]; out[5] = a[5]; out[6] = a[9]; out[7] = a[13]; out[8] = a[2]; out[9] = a[6]; out[10] = a[10]; out[11] = a[14]; out[12] = a[3]; out[13] = a[7]; out[14] = a[11]; out[15] = a[15]; } return out; } /** * Inverts a mat4 * * @param {mat4} out the receiving matrix * @param {mat4} a the source matrix * @returns {mat4} out */ function invert(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b00 = a00 * a11 - a01 * a10; var b01 = a00 * a12 - a02 * a10; var b02 = a00 * a13 - a03 * a10; var b03 = a01 * a12 - a02 * a11; var b04 = a01 * a13 - a03 * a11; var b05 = a02 * a13 - a03 * a12; var b06 = a20 * a31 - a21 * a30; var b07 = a20 * a32 - a22 * a30; var b08 = a20 * a33 - a23 * a30; var b09 = a21 * a32 - a22 * a31; var b10 = a21 * a33 - a23 * a31; var b11 = a22 * a33 - a23 * a32; // Calculate the determinant var 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; } /** * Calculates the adjugate of a mat4 * * @param {mat4} out the receiving matrix * @param {mat4} a the source matrix * @returns {mat4} out */ function adjoint(out, a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; out[0] = a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22); out[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22)); out[2] = a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12); out[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12)); out[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22)); out[5] = a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22); out[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12)); out[7] = a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12); out[8] = a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21); out[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21)); out[10] = a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11); out[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11)); out[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21)); out[13] = a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21); out[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11)); out[15] = a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11); return out; } /** * Calculates the determinant of a mat4 * * @param {mat4} a the source matrix * @returns {Number} determinant of a */ function determinant(a) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; var b00 = a00 * a11 - a01 * a10; var b01 = a00 * a12 - a02 * a10; var b02 = a00 * a13 - a03 * a10; var b03 = a01 * a12 - a02 * a11; var b04 = a01 * a13 - a03 * a11; var b05 = a02 * a13 - a03 * a12; var b06 = a20 * a31 - a21 * a30; var b07 = a20 * a32 - a22 * a30; var b08 = a20 * a33 - a23 * a30; var b09 = a21 * a32 - a22 * a31; var b10 = a21 * a33 - a23 * a31; var b11 = a22 * a33 - a23 * a32; // Calculate the determinant return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06; } /** * Multiplies two mat4s * * @param {mat4} out the receiving matrix * @param {mat4} a the first operand * @param {mat4} b the second operand * @returns {mat4} out */ function multiply(out, a, b) { var a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3]; var a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7]; var a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11]; var a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15]; // Cache only the current line of the second matrix var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[1] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[2] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[3] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[4];b1 = b[5];b2 = b[6];b3 = b[7]; out[4] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[5] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[6] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[7] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[8];b1 = b[9];b2 = b[10];b3 = b[11]; out[8] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[9] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[10] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[11] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; b0 = b[12];b1 = b[13];b2 = b[14];b3 = b[15]; out[12] = b0 * a00 + b1 * a10 + b2 * a20 + b3 * a30; out[13] = b0 * a01 + b1 * a11 + b2 * a21 + b3 * a31; out[14] = b0 * a02 + b1 * a12 + b2 * a22 + b3 * a32; out[15] = b0 * a03 + b1 * a13 + b2 * a23 + b3 * a33; return out; } /** * Translate a mat4 by the given vector * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to translate * @param {vec3} v vector to translate by * @returns {mat4} out */ function translate(out, a, v) { var x = v[0], y = v[1], z = v[2]; var a00 = void 0, a01 = void 0, a02 = void 0, a03 = void 0; var a10 = void 0, a11 = void 0, a12 = void 0, a13 = void 0; var a20 = void 0, a21 = void 0, a22 = void 0, a23 = void 0; 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; } /** * Scales the mat4 by the dimensions in the given vec3 not using vectorization * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to scale * @param {vec3} v the vec3 to scale the matrix by * @returns {mat4} out **/ function scale(out, a, v) { var x = v[0], y = v[1], z = v[2]; out[0] = a[0] * x; out[1] = a[1] * x; out[2] = a[2] * x; out[3] = a[3] * x; out[4] = a[4] * y; out[5] = a[5] * y; out[6] = a[6] * y; out[7] = a[7] * y; out[8] = a[8] * z; out[9] = a[9] * z; out[10] = a[10] * z; out[11] = a[11] * z; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; return out; } /** * Rotates a mat4 by the given angle around the given axis * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @param {vec3} axis the axis to rotate around * @returns {mat4} out */ function rotate(out, a, rad, axis) { var x = axis[0], y = axis[1], z = axis[2]; var len = Math.sqrt(x * x + y * y + z * z); var s = void 0, c = void 0, t = void 0; var a00 = void 0, a01 = void 0, a02 = void 0, a03 = void 0; var a10 = void 0, a11 = void 0, a12 = void 0, a13 = void 0; var a20 = void 0, a21 = void 0, a22 = void 0, a23 = void 0; var b00 = void 0, b01 = void 0, b02 = void 0; var b10 = void 0, b11 = void 0, b12 = void 0; var b20 = void 0, b21 = void 0, b22 = void 0; if (len < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { return null; } len = 1 / len; x *= len; y *= len; z *= len; s = Math.sin(rad); c = Math.cos(rad); t = 1 - c; 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]; // Construct the elements of the rotation matrix b00 = x * x * t + c;b01 = y * x * t + z * s;b02 = z * x * t - y * s; b10 = x * y * t - z * s;b11 = y * y * t + c;b12 = z * y * t + x * s; b20 = x * z * t + y * s;b21 = y * z * t - x * s;b22 = z * z * t + c; // Perform rotation-specific matrix multiplication out[0] = a00 * b00 + a10 * b01 + a20 * b02; out[1] = a01 * b00 + a11 * b01 + a21 * b02; out[2] = a02 * b00 + a12 * b01 + a22 * b02; out[3] = a03 * b00 + a13 * b01 + a23 * b02; out[4] = a00 * b10 + a10 * b11 + a20 * b12; out[5] = a01 * b10 + a11 * b11 + a21 * b12; out[6] = a02 * b10 + a12 * b11 + a22 * b12; out[7] = a03 * b10 + a13 * b11 + a23 * b12; out[8] = a00 * b20 + a10 * b21 + a20 * b22; out[9] = a01 * b20 + a11 * b21 + a21 * b22; out[10] = a02 * b20 + a12 * b21 + a22 * b22; out[11] = a03 * b20 + a13 * b21 + a23 * b22; if (a !== out) { // If the source and destination differ, copy the unchanged last row out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } return out; } /** * Rotates a matrix by the given angle around the X axis * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function rotateX(out, a, rad) { var s = Math.sin(rad); var c = Math.cos(rad); var a10 = a[4]; var a11 = a[5]; var a12 = a[6]; var a13 = a[7]; var a20 = a[8]; var a21 = a[9]; var a22 = a[10]; var a23 = a[11]; if (a !== out) { // If the source and destination differ, copy the unchanged rows out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } // Perform axis-specific matrix multiplication out[4] = a10 * c + a20 * s; out[5] = a11 * c + a21 * s; out[6] = a12 * c + a22 * s; out[7] = a13 * c + a23 * s; out[8] = a20 * c - a10 * s; out[9] = a21 * c - a11 * s; out[10] = a22 * c - a12 * s; out[11] = a23 * c - a13 * s; return out; } /** * Rotates a matrix by the given angle around the Y axis * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function rotateY(out, a, rad) { var s = Math.sin(rad); var c = Math.cos(rad); var a00 = a[0]; var a01 = a[1]; var a02 = a[2]; var a03 = a[3]; var a20 = a[8]; var a21 = a[9]; var a22 = a[10]; var a23 = a[11]; if (a !== out) { // If the source and destination differ, copy the unchanged rows out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } // Perform axis-specific matrix multiplication out[0] = a00 * c - a20 * s; out[1] = a01 * c - a21 * s; out[2] = a02 * c - a22 * s; out[3] = a03 * c - a23 * s; out[8] = a00 * s + a20 * c; out[9] = a01 * s + a21 * c; out[10] = a02 * s + a22 * c; out[11] = a03 * s + a23 * c; return out; } /** * Rotates a matrix by the given angle around the Z axis * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function rotateZ(out, a, rad) { var s = Math.sin(rad); var c = Math.cos(rad); var a00 = a[0]; var a01 = a[1]; var a02 = a[2]; var a03 = a[3]; var a10 = a[4]; var a11 = a[5]; var a12 = a[6]; var a13 = a[7]; if (a !== out) { // If the source and destination differ, copy the unchanged last row out[8] = a[8]; out[9] = a[9]; out[10] = a[10]; out[11] = a[11]; out[12] = a[12]; out[13] = a[13]; out[14] = a[14]; out[15] = a[15]; } // Perform axis-specific matrix multiplication out[0] = a00 * c + a10 * s; out[1] = a01 * c + a11 * s; out[2] = a02 * c + a12 * s; out[3] = a03 * c + a13 * s; out[4] = a10 * c - a00 * s; out[5] = a11 * c - a01 * s; out[6] = a12 * c - a02 * s; out[7] = a13 * c - a03 * s; return out; } /** * Creates a matrix from a vector translation * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.translate(dest, dest, vec); * * @param {mat4} out mat4 receiving operation result * @param {vec3} v Translation vector * @returns {mat4} out */ function fromTranslation(out, v) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = v[0]; out[13] = v[1]; out[14] = v[2]; out[15] = 1; return out; } /** * Creates a matrix from a vector scaling * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.scale(dest, dest, vec); * * @param {mat4} out mat4 receiving operation result * @param {vec3} v Scaling vector * @returns {mat4} out */ function fromScaling(out, v) { out[0] = v[0]; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = v[1]; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = v[2]; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Creates a matrix from a given angle around a given axis * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.rotate(dest, dest, rad, axis); * * @param {mat4} out mat4 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @param {vec3} axis the axis to rotate around * @returns {mat4} out */ function fromRotation(out, rad, axis) { var x = axis[0], y = axis[1], z = axis[2]; var len = Math.sqrt(x * x + y * y + z * z); var s = void 0, c = void 0, t = void 0; if (len < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { return null; } len = 1 / len; x *= len; y *= len; z *= len; s = Math.sin(rad); c = Math.cos(rad); t = 1 - c; // Perform rotation-specific matrix multiplication out[0] = x * x * t + c; out[1] = y * x * t + z * s; out[2] = z * x * t - y * s; out[3] = 0; out[4] = x * y * t - z * s; out[5] = y * y * t + c; out[6] = z * y * t + x * s; out[7] = 0; out[8] = x * z * t + y * s; out[9] = y * z * t - x * s; out[10] = z * z * t + c; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Creates a matrix from the given angle around the X axis * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.rotateX(dest, dest, rad); * * @param {mat4} out mat4 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function fromXRotation(out, rad) { var s = Math.sin(rad); var c = Math.cos(rad); // Perform axis-specific matrix multiplication out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = c; out[6] = s; out[7] = 0; out[8] = 0; out[9] = -s; out[10] = c; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Creates a matrix from the given angle around the Y axis * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.rotateY(dest, dest, rad); * * @param {mat4} out mat4 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function fromYRotation(out, rad) { var s = Math.sin(rad); var c = Math.cos(rad); // Perform axis-specific matrix multiplication out[0] = c; out[1] = 0; out[2] = -s; out[3] = 0; out[4] = 0; out[5] = 1; out[6] = 0; out[7] = 0; out[8] = s; out[9] = 0; out[10] = c; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Creates a matrix from the given angle around the Z axis * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.rotateZ(dest, dest, rad); * * @param {mat4} out mat4 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat4} out */ function fromZRotation(out, rad) { var s = Math.sin(rad); var c = Math.cos(rad); // Perform axis-specific matrix multiplication out[0] = c; out[1] = s; out[2] = 0; out[3] = 0; out[4] = -s; out[5] = c; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[10] = 1; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Creates a matrix from a quaternion rotation and vector translation * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.translate(dest, vec); * let quatMat = mat4.create(); * quat4.toMat4(quat, quatMat); * mat4.multiply(dest, quatMat); * * @param {mat4} out mat4 receiving operation result * @param {quat4} q Rotation quaternion * @param {vec3} v Translation vector * @returns {mat4} out */ function fromRotationTranslation(out, q, v) { // Quaternion math var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var xy = x * y2; var xz = x * z2; var yy = y * y2; var yz = y * z2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var 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; } /** * Creates a new mat4 from a dual quat. * * @param {mat4} out Matrix * @param {quat2} a Dual Quaternion * @returns {mat4} mat4 receiving operation result */ function fromQuat2(out, a) { var translation = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](3); var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7]; var magnitude = bx * bx + by * by + bz * bz + bw * bw; //Only scale if it makes sense if (magnitude > 0) { translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2 / magnitude; translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2 / magnitude; translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2 / magnitude; } else { translation[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; translation[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; translation[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; } fromRotationTranslation(out, a, translation); return out; } /** * Returns the translation vector component of a transformation * matrix. If a matrix is built with fromRotationTranslation, * the returned vector will be the same as the translation vector * originally supplied. * @param {vec3} out Vector to receive translation component * @param {mat4} mat Matrix to be decomposed (input) * @return {vec3} out */ function getTranslation(out, mat) { out[0] = mat[12]; out[1] = mat[13]; out[2] = mat[14]; return out; } /** * Returns the scaling factor component of a transformation * matrix. If a matrix is built with fromRotationTranslationScale * with a normalized Quaternion paramter, the returned vector will be * the same as the scaling vector * originally supplied. * @param {vec3} out Vector to receive scaling factor component * @param {mat4} mat Matrix to be decomposed (input) * @return {vec3} out */ function getScaling(out, mat) { var m11 = mat[0]; var m12 = mat[1]; var m13 = mat[2]; var m21 = mat[4]; var m22 = mat[5]; var m23 = mat[6]; var m31 = mat[8]; var m32 = mat[9]; var m33 = mat[10]; out[0] = Math.sqrt(m11 * m11 + m12 * m12 + m13 * m13); out[1] = Math.sqrt(m21 * m21 + m22 * m22 + m23 * m23); out[2] = Math.sqrt(m31 * m31 + m32 * m32 + m33 * m33); return out; } /** * Returns a quaternion representing the rotational component * of a transformation matrix. If a matrix is built with * fromRotationTranslation, the returned quaternion will be the * same as the quaternion originally supplied. * @param {quat} out Quaternion to receive the rotation component * @param {mat4} mat Matrix to be decomposed (input) * @return {quat} out */ function getRotation(out, mat) { // Algorithm taken from http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm var trace = mat[0] + mat[5] + mat[10]; var S = 0; if (trace > 0) { S = Math.sqrt(trace + 1.0) * 2; out[3] = 0.25 * S; out[0] = (mat[6] - mat[9]) / S; out[1] = (mat[8] - mat[2]) / S; out[2] = (mat[1] - mat[4]) / S; } else if (mat[0] > mat[5] && mat[0] > mat[10]) { S = Math.sqrt(1.0 + mat[0] - mat[5] - mat[10]) * 2; out[3] = (mat[6] - mat[9]) / S; out[0] = 0.25 * S; out[1] = (mat[1] + mat[4]) / S; out[2] = (mat[8] + mat[2]) / S; } else if (mat[5] > mat[10]) { S = Math.sqrt(1.0 + mat[5] - mat[0] - mat[10]) * 2; out[3] = (mat[8] - mat[2]) / S; out[0] = (mat[1] + mat[4]) / S; out[1] = 0.25 * S; out[2] = (mat[6] + mat[9]) / S; } else { S = Math.sqrt(1.0 + mat[10] - mat[0] - mat[5]) * 2; out[3] = (mat[1] - mat[4]) / S; out[0] = (mat[8] + mat[2]) / S; out[1] = (mat[6] + mat[9]) / S; out[2] = 0.25 * S; } return out; } /** * Creates a matrix from a quaternion rotation, vector translation and vector scale * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.translate(dest, vec); * let quatMat = mat4.create(); * quat4.toMat4(quat, quatMat); * mat4.multiply(dest, quatMat); * mat4.scale(dest, scale) * * @param {mat4} out mat4 receiving operation result * @param {quat4} q Rotation quaternion * @param {vec3} v Translation vector * @param {vec3} s Scaling vector * @returns {mat4} out */ function fromRotationTranslationScale(out, q, v, s) { // Quaternion math var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var xy = x * y2; var xz = x * z2; var yy = y * y2; var yz = y * z2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var wz = w * z2; var sx = s[0]; var sy = s[1]; var sz = s[2]; out[0] = (1 - (yy + zz)) * sx; out[1] = (xy + wz) * sx; out[2] = (xz - wy) * sx; out[3] = 0; out[4] = (xy - wz) * sy; out[5] = (1 - (xx + zz)) * sy; out[6] = (yz + wx) * sy; out[7] = 0; out[8] = (xz + wy) * sz; out[9] = (yz - wx) * sz; out[10] = (1 - (xx + yy)) * sz; out[11] = 0; out[12] = v[0]; out[13] = v[1]; out[14] = v[2]; out[15] = 1; return out; } /** * Creates a matrix from a quaternion rotation, vector translation and vector scale, rotating and scaling around the given origin * This is equivalent to (but much faster than): * * mat4.identity(dest); * mat4.translate(dest, vec); * mat4.translate(dest, origin); * let quatMat = mat4.create(); * quat4.toMat4(quat, quatMat); * mat4.multiply(dest, quatMat); * mat4.scale(dest, scale) * mat4.translate(dest, negativeOrigin); * * @param {mat4} out mat4 receiving operation result * @param {quat4} q Rotation quaternion * @param {vec3} v Translation vector * @param {vec3} s Scaling vector * @param {vec3} o The origin vector around which to scale and rotate * @returns {mat4} out */ function fromRotationTranslationScaleOrigin(out, q, v, s, o) { // Quaternion math var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var xy = x * y2; var xz = x * z2; var yy = y * y2; var yz = y * z2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var wz = w * z2; var sx = s[0]; var sy = s[1]; var sz = s[2]; var ox = o[0]; var oy = o[1]; var oz = o[2]; var out0 = (1 - (yy + zz)) * sx; var out1 = (xy + wz) * sx; var out2 = (xz - wy) * sx; var out4 = (xy - wz) * sy; var out5 = (1 - (xx + zz)) * sy; var out6 = (yz + wx) * sy; var out8 = (xz + wy) * sz; var out9 = (yz - wx) * sz; var out10 = (1 - (xx + yy)) * sz; out[0] = out0; out[1] = out1; out[2] = out2; out[3] = 0; out[4] = out4; out[5] = out5; out[6] = out6; out[7] = 0; out[8] = out8; out[9] = out9; out[10] = out10; out[11] = 0; out[12] = v[0] + ox - (out0 * ox + out4 * oy + out8 * oz); out[13] = v[1] + oy - (out1 * ox + out5 * oy + out9 * oz); out[14] = v[2] + oz - (out2 * ox + out6 * oy + out10 * oz); out[15] = 1; return out; } /** * Calculates a 4x4 matrix from the given quaternion * * @param {mat4} out mat4 receiving operation result * @param {quat} q Quaternion to create matrix from * * @returns {mat4} out */ function fromQuat(out, q) { var x = q[0], y = q[1], z = q[2], w = q[3]; var x2 = x + x; var y2 = y + y; var z2 = z + z; var xx = x * x2; var yx = y * x2; var yy = y * y2; var zx = z * x2; var zy = z * y2; var zz = z * z2; var wx = w * x2; var wy = w * y2; var wz = w * z2; out[0] = 1 - yy - zz; out[1] = yx + wz; out[2] = zx - wy; out[3] = 0; out[4] = yx - wz; out[5] = 1 - xx - zz; out[6] = zy + wx; out[7] = 0; out[8] = zx + wy; out[9] = zy - wx; out[10] = 1 - xx - yy; out[11] = 0; out[12] = 0; out[13] = 0; out[14] = 0; out[15] = 1; return out; } /** * Generates a frustum matrix with the given bounds * * @param {mat4} out mat4 frustum matrix will be written into * @param {Number} left Left bound of the frustum * @param {Number} right Right bound of the frustum * @param {Number} bottom Bottom bound of the frustum * @param {Number} top Top bound of the frustum * @param {Number} near Near bound of the frustum * @param {Number} far Far bound of the frustum * @returns {mat4} out */ function frustum(out, left, right, bottom, top, near, far) { var rl = 1 / (right - left); var tb = 1 / (top - bottom); var nf = 1 / (near - far); out[0] = near * 2 * rl; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = near * 2 * tb; out[6] = 0; out[7] = 0; out[8] = (right + left) * rl; out[9] = (top + bottom) * tb; out[10] = (far + near) * nf; out[11] = -1; out[12] = 0; out[13] = 0; out[14] = far * near * 2 * nf; out[15] = 0; return out; } /** * Generates a perspective projection matrix with the given bounds. * Passing null/undefined/no value for far will generate infinite projection matrix. * * @param {mat4} out mat4 frustum matrix will be written into * @param {number} fovy Vertical field of view in radians * @param {number} aspect Aspect ratio. typically viewport width/height * @param {number} near Near bound of the frustum * @param {number} far Far bound of the frustum, can be null or Infinity * @returns {mat4} out */ function perspective(out, fovy, aspect, near, far) { var f = 1.0 / Math.tan(fovy / 2), nf = void 0; out[0] = f / aspect; out[1] = 0; out[2] = 0; out[3] = 0; out[4] = 0; out[5] = f; out[6] = 0; out[7] = 0; out[8] = 0; out[9] = 0; out[11] = -1; out[12] = 0; out[13] = 0; out[15] = 0; if (far != null && far !== Infinity) { nf = 1 / (near - far); out[10] = (far + near) * nf; out[14] = 2 * far * near * nf; } else { out[10] = -1; out[14] = -2 * near; } return out; } /** * Generates a perspective projection matrix with the given field of view. * This is primarily useful for generating projection matrices to be used * with the still experiemental WebVR API. * * @param {mat4} out mat4 frustum matrix will be written into * @param {Object} fov Object containing the following values: upDegrees, downDegrees, leftDegrees, rightDegrees * @param {number} near Near bound of the frustum * @param {number} far Far bound of the frustum * @returns {mat4} out */ function perspectiveFromFieldOfView(out, fov, near, far) { var upTan = Math.tan(fov.upDegrees * Math.PI / 180.0); var downTan = Math.tan(fov.downDegrees * Math.PI / 180.0); var leftTan = Math.tan(fov.leftDegrees * Math.PI / 180.0); var rightTan = Math.tan(fov.rightDegrees * Math.PI / 180.0); var xScale = 2.0 / (leftTan + rightTan); var 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; } /** * Generates a orthogonal projection matrix with the given bounds * * @param {mat4} out mat4 frustum matrix will be written into * @param {number} left Left bound of the frustum * @param {number} right Right bound of the frustum * @param {number} bottom Bottom bound of the frustum * @param {number} top Top bound of the frustum * @param {number} near Near bound of the frustum * @param {number} far Far bound of the frustum * @returns {mat4} out */ function ortho(out, left, right, bottom, top, near, far) { var lr = 1 / (left - right); var bt = 1 / (bottom - top); var 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; } /** * Generates a look-at matrix with the given eye position, focal point, and up axis. * If you want a matrix that actually makes an object look at another object, you should use targetTo instead. * * @param {mat4} out mat4 frustum matrix will be written into * @param {vec3} eye Position of the viewer * @param {vec3} center Point the viewer is looking at * @param {vec3} up vec3 pointing up * @returns {mat4} out */ function lookAt(out, eye, center, up) { var x0 = void 0, x1 = void 0, x2 = void 0, y0 = void 0, y1 = void 0, y2 = void 0, z0 = void 0, z1 = void 0, z2 = void 0, len = void 0; var eyex = eye[0]; var eyey = eye[1]; var eyez = eye[2]; var upx = up[0]; var upy = up[1]; var upz = up[2]; var centerx = center[0]; var centery = center[1]; var centerz = center[2]; if (Math.abs(eyex - centerx) < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] && Math.abs(eyey - centery) < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] && Math.abs(eyez - centerz) < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { return identity(out); } z0 = eyex - centerx; z1 = eyey - centery; z2 = eyez - centerz; len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2); z0 *= len; z1 *= len; z2 *= len; x0 = upy * z2 - upz * z1; x1 = upz * z0 - upx * z2; x2 = upx * z1 - upy * z0; len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2); if (!len) { x0 = 0; x1 = 0; x2 = 0; } else { len = 1 / len; x0 *= len; x1 *= len; x2 *= len; } y0 = z1 * x2 - z2 * x1; y1 = z2 * x0 - z0 * x2; y2 = z0 * x1 - z1 * x0; len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2); if (!len) { y0 = 0; y1 = 0; y2 = 0; } else { len = 1 / len; y0 *= len; y1 *= len; y2 *= len; } out[0] = x0; out[1] = y0; out[2] = z0; out[3] = 0; out[4] = x1; out[5] = y1; out[6] = z1; out[7] = 0; out[8] = x2; out[9] = y2; out[10] = z2; out[11] = 0; out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez); out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez); out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez); out[15] = 1; return out; } /** * Generates a matrix that makes something look at something else. * * @param {mat4} out mat4 frustum matrix will be written into * @param {vec3} eye Position of the viewer * @param {vec3} center Point the viewer is looking at * @param {vec3} up vec3 pointing up * @returns {mat4} out */ function targetTo(out, eye, target, up) { var eyex = eye[0], eyey = eye[1], eyez = eye[2], upx = up[0], upy = up[1], upz = up[2]; var z0 = eyex - target[0], z1 = eyey - target[1], z2 = eyez - target[2]; var len = z0 * z0 + z1 * z1 + z2 * z2; if (len > 0) { len = 1 / Math.sqrt(len); z0 *= len; z1 *= len; z2 *= len; } var x0 = upy * z2 - upz * z1, x1 = upz * z0 - upx * z2, x2 = upx * z1 - upy * z0; len = x0 * x0 + x1 * x1 + x2 * x2; if (len > 0) { len = 1 / Math.sqrt(len); x0 *= len; x1 *= len; x2 *= len; } out[0] = x0; out[1] = x1; out[2] = x2; out[3] = 0; out[4] = z1 * x2 - z2 * x1; out[5] = z2 * x0 - z0 * x2; out[6] = z0 * x1 - z1 * x0; out[7] = 0; out[8] = z0; out[9] = z1; out[10] = z2; out[11] = 0; out[12] = eyex; out[13] = eyey; out[14] = eyez; out[15] = 1; return out; }; /** * Returns a string representation of a mat4 * * @param {mat4} a matrix to represent as a string * @returns {String} string representation of the matrix */ function str(a) { return 'mat4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' + a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' + a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')'; } /** * Returns Frobenius norm of a mat4 * * @param {mat4} a the matrix to calculate Frobenius norm of * @returns {Number} Frobenius norm */ function frob(a) { return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + Math.pow(a[6], 2) + Math.pow(a[7], 2) + Math.pow(a[8], 2) + Math.pow(a[9], 2) + Math.pow(a[10], 2) + Math.pow(a[11], 2) + Math.pow(a[12], 2) + Math.pow(a[13], 2) + Math.pow(a[14], 2) + Math.pow(a[15], 2)); } /** * Adds two mat4's * * @param {mat4} out the receiving matrix * @param {mat4} a the first operand * @param {mat4} b the second operand * @returns {mat4} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; out[6] = a[6] + b[6]; out[7] = a[7] + b[7]; out[8] = a[8] + b[8]; out[9] = a[9] + b[9]; out[10] = a[10] + b[10]; out[11] = a[11] + b[11]; out[12] = a[12] + b[12]; out[13] = a[13] + b[13]; out[14] = a[14] + b[14]; out[15] = a[15] + b[15]; return out; } /** * Subtracts matrix b from matrix a * * @param {mat4} out the receiving matrix * @param {mat4} a the first operand * @param {mat4} b the second operand * @returns {mat4} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; out[4] = a[4] - b[4]; out[5] = a[5] - b[5]; out[6] = a[6] - b[6]; out[7] = a[7] - b[7]; out[8] = a[8] - b[8]; out[9] = a[9] - b[9]; out[10] = a[10] - b[10]; out[11] = a[11] - b[11]; out[12] = a[12] - b[12]; out[13] = a[13] - b[13]; out[14] = a[14] - b[14]; out[15] = a[15] - b[15]; return out; } /** * Multiply each element of the matrix by a scalar. * * @param {mat4} out the receiving matrix * @param {mat4} a the matrix to scale * @param {Number} b amount to scale the matrix's elements by * @returns {mat4} out */ function multiplyScalar(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; out[4] = a[4] * b; out[5] = a[5] * b; out[6] = a[6] * b; out[7] = a[7] * b; out[8] = a[8] * b; out[9] = a[9] * b; out[10] = a[10] * b; out[11] = a[11] * b; out[12] = a[12] * b; out[13] = a[13] * b; out[14] = a[14] * b; out[15] = a[15] * b; return out; } /** * Adds two mat4's after multiplying each element of the second operand by a scalar value. * * @param {mat4} out the receiving vector * @param {mat4} a the first operand * @param {mat4} b the second operand * @param {Number} scale the amount to scale b's elements by before adding * @returns {mat4} out */ function multiplyScalarAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; out[3] = a[3] + b[3] * scale; out[4] = a[4] + b[4] * scale; out[5] = a[5] + b[5] * scale; out[6] = a[6] + b[6] * scale; out[7] = a[7] + b[7] * scale; out[8] = a[8] + b[8] * scale; out[9] = a[9] + b[9] * scale; out[10] = a[10] + b[10] * scale; out[11] = a[11] + b[11] * scale; out[12] = a[12] + b[12] * scale; out[13] = a[13] + b[13] * scale; out[14] = a[14] + b[14] * scale; out[15] = a[15] + b[15] * scale; return out; } /** * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) * * @param {mat4} a The first matrix. * @param {mat4} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7] && a[8] === b[8] && a[9] === b[9] && a[10] === b[10] && a[11] === b[11] && a[12] === b[12] && a[13] === b[13] && a[14] === b[14] && a[15] === b[15]; } /** * Returns whether or not the matrices have approximately the same elements in the same position. * * @param {mat4} a The first matrix. * @param {mat4} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7]; var a8 = a[8], a9 = a[9], a10 = a[10], a11 = a[11]; var a12 = a[12], a13 = a[13], a14 = a[14], a15 = a[15]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; var b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7]; var b8 = b[8], b9 = b[9], b10 = b[10], b11 = b[11]; var b12 = b[12], b13 = b[13], b14 = b[14], b15 = b[15]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a7), Math.abs(b7)) && Math.abs(a8 - b8) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a8), Math.abs(b8)) && Math.abs(a9 - b9) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a9), Math.abs(b9)) && Math.abs(a10 - b10) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a10), Math.abs(b10)) && Math.abs(a11 - b11) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a11), Math.abs(b11)) && Math.abs(a12 - b12) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a12), Math.abs(b12)) && Math.abs(a13 - b13) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a13), Math.abs(b13)) && Math.abs(a14 - b14) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a14), Math.abs(b14)) && Math.abs(a15 - b15) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a15), Math.abs(b15)); } /** * Alias for {@link mat4.multiply} * @function */ var mul = multiply; /** * Alias for {@link mat4.subtract} * @function */ var sub = subtract; /***/ }), /* 4 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["setAxisAngle"] = setAxisAngle; /* harmony export (immutable) */ __webpack_exports__["getAxisAngle"] = getAxisAngle; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; /* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; /* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; /* harmony export (immutable) */ __webpack_exports__["calculateW"] = calculateW; /* harmony export (immutable) */ __webpack_exports__["slerp"] = slerp; /* harmony export (immutable) */ __webpack_exports__["random"] = random; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["conjugate"] = conjugate; /* harmony export (immutable) */ __webpack_exports__["fromMat3"] = fromMat3; /* harmony export (immutable) */ __webpack_exports__["fromEuler"] = fromEuler; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "clone", function() { return clone; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fromValues", function() { return fromValues; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "copy", function() { return copy; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "set", function() { return set; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "add", function() { return add; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "scale", function() { return scale; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "lerp", function() { return lerp; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "normalize", function() { return normalize; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "exactEquals", function() { return exactEquals; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "equals", function() { return equals; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "rotationTo", function() { return rotationTo; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqlerp", function() { return sqlerp; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setAxes", function() { return setAxes; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__mat3_js__ = __webpack_require__(2); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__vec3_js__ = __webpack_require__(5); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_3__vec4_js__ = __webpack_require__(6); /** * Quaternion * @module quat */ /** * Creates a new identity quat * * @returns {quat} a new quaternion */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } out[3] = 1; return out; } /** * Set a quat to the identity quaternion * * @param {quat} out the receiving quaternion * @returns {quat} out */ function identity(out) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1; return out; } /** * Sets a quat from the given angle and rotation axis, * then returns it. * * @param {quat} out the receiving quaternion * @param {vec3} axis the axis around which to rotate * @param {Number} rad the angle in radians * @returns {quat} out **/ function setAxisAngle(out, axis, rad) { rad = rad * 0.5; var s = Math.sin(rad); out[0] = s * axis[0]; out[1] = s * axis[1]; out[2] = s * axis[2]; out[3] = Math.cos(rad); return out; } /** * Gets the rotation axis and angle for a given * quaternion. If a quaternion is created with * setAxisAngle, this method will return the same * values as providied in the original parameter list * OR functionally equivalent values. * Example: The quaternion formed by axis [0, 0, 1] and * angle -90 is the same as the quaternion formed by * [0, 0, 1] and 270. This method favors the latter. * @param {vec3} out_axis Vector receiving the axis of rotation * @param {quat} q Quaternion to be decomposed * @return {Number} Angle, in radians, of the rotation */ function getAxisAngle(out_axis, q) { var rad = Math.acos(q[3]) * 2.0; var s = Math.sin(rad / 2.0); if (s > __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { out_axis[0] = q[0] / s; out_axis[1] = q[1] / s; out_axis[2] = q[2] / s; } else { // If s is zero, return any axis (no rotation - axis does not matter) out_axis[0] = 1; out_axis[1] = 0; out_axis[2] = 0; } return rad; } /** * Multiplies two quat's * * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand * @returns {quat} out */ function multiply(out, a, b) { var ax = a[0], ay = a[1], az = a[2], aw = a[3]; var bx = b[0], by = b[1], bz = b[2], bw = b[3]; out[0] = ax * bw + aw * bx + ay * bz - az * by; out[1] = ay * bw + aw * by + az * bx - ax * bz; out[2] = az * bw + aw * bz + ax * by - ay * bx; out[3] = aw * bw - ax * bx - ay * by - az * bz; return out; } /** * Rotates a quaternion by the given angle about the X axis * * @param {quat} out quat receiving operation result * @param {quat} a quat to rotate * @param {number} rad angle (in radians) to rotate * @returns {quat} out */ function rotateX(out, a, rad) { rad *= 0.5; var ax = a[0], ay = a[1], az = a[2], aw = a[3]; var bx = Math.sin(rad), bw = Math.cos(rad); out[0] = ax * bw + aw * bx; out[1] = ay * bw + az * bx; out[2] = az * bw - ay * bx; out[3] = aw * bw - ax * bx; return out; } /** * Rotates a quaternion by the given angle about the Y axis * * @param {quat} out quat receiving operation result * @param {quat} a quat to rotate * @param {number} rad angle (in radians) to rotate * @returns {quat} out */ function rotateY(out, a, rad) { rad *= 0.5; var ax = a[0], ay = a[1], az = a[2], aw = a[3]; var by = Math.sin(rad), bw = Math.cos(rad); out[0] = ax * bw - az * by; out[1] = ay * bw + aw * by; out[2] = az * bw + ax * by; out[3] = aw * bw - ay * by; return out; } /** * Rotates a quaternion by the given angle about the Z axis * * @param {quat} out quat receiving operation result * @param {quat} a quat to rotate * @param {number} rad angle (in radians) to rotate * @returns {quat} out */ function rotateZ(out, a, rad) { rad *= 0.5; var ax = a[0], ay = a[1], az = a[2], aw = a[3]; var bz = Math.sin(rad), bw = Math.cos(rad); out[0] = ax * bw + ay * bz; out[1] = ay * bw - ax * bz; out[2] = az * bw + aw * bz; out[3] = aw * bw - az * bz; return out; } /** * Calculates the W component of a quat from the X, Y, and Z components. * Assumes that quaternion is 1 unit in length. * Any existing W component will be ignored. * * @param {quat} out the receiving quaternion * @param {quat} a quat to calculate W component of * @returns {quat} out */ function calculateW(out, a) { var x = a[0], y = a[1], z = a[2]; out[0] = x; out[1] = y; out[2] = z; out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); return out; } /** * Performs a spherical linear interpolation between two quat * * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out */ function slerp(out, a, b, t) { // benchmarks: // http://jsperf.com/quaternion-slerp-implementations var ax = a[0], ay = a[1], az = a[2], aw = a[3]; var bx = b[0], by = b[1], bz = b[2], bw = b[3]; var omega = void 0, cosom = void 0, sinom = void 0, scale0 = void 0, scale1 = void 0; // calc cosine cosom = ax * bx + ay * by + az * bz + aw * bw; // adjust signs (if necessary) if (cosom < 0.0) { cosom = -cosom; bx = -bx; by = -by; bz = -bz; bw = -bw; } // calculate coefficients if (1.0 - cosom > __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { // standard case (slerp) omega = Math.acos(cosom); sinom = Math.sin(omega); scale0 = Math.sin((1.0 - t) * omega) / sinom; scale1 = Math.sin(t * omega) / sinom; } else { // "from" and "to" quaternions are very close // ... so we can do a linear interpolation scale0 = 1.0 - t; scale1 = t; } // calculate final values out[0] = scale0 * ax + scale1 * bx; out[1] = scale0 * ay + scale1 * by; out[2] = scale0 * az + scale1 * bz; out[3] = scale0 * aw + scale1 * bw; return out; } /** * Generates a random quaternion * * @param {quat} out the receiving quaternion * @returns {quat} out */ function random(out) { // Implementation of http://planning.cs.uiuc.edu/node198.html // TODO: Calling random 3 times is probably not the fastest solution var u1 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"](); var u2 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"](); var u3 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"](); var sqrt1MinusU1 = Math.sqrt(1 - u1); var sqrtU1 = Math.sqrt(u1); out[0] = sqrt1MinusU1 * Math.sin(2.0 * Math.PI * u2); out[1] = sqrt1MinusU1 * Math.cos(2.0 * Math.PI * u2); out[2] = sqrtU1 * Math.sin(2.0 * Math.PI * u3); out[3] = sqrtU1 * Math.cos(2.0 * Math.PI * u3); return out; } /** * Calculates the inverse of a quat * * @param {quat} out the receiving quaternion * @param {quat} a quat to calculate inverse of * @returns {quat} out */ function invert(out, a) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var dot = a0 * a0 + a1 * a1 + a2 * a2 + a3 * a3; var invDot = dot ? 1.0 / dot : 0; // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 out[0] = -a0 * invDot; out[1] = -a1 * invDot; out[2] = -a2 * invDot; out[3] = a3 * invDot; return out; } /** * Calculates the conjugate of a quat * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. * * @param {quat} out the receiving quaternion * @param {quat} a quat to calculate conjugate of * @returns {quat} out */ function conjugate(out, a) { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; out[3] = a[3]; return out; } /** * Creates a quaternion from the given 3x3 rotation matrix. * * NOTE: The resultant quaternion is not normalized, so you should be sure * to renormalize the quaternion yourself where necessary. * * @param {quat} out the receiving quaternion * @param {mat3} m rotation matrix * @returns {quat} out * @function */ function fromMat3(out, m) { // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes // article "Quaternion Calculus and Fast Animation". var fTrace = m[0] + m[4] + m[8]; var fRoot = void 0; if (fTrace > 0.0) { // |w| > 1/2, may as well choose w > 1/2 fRoot = Math.sqrt(fTrace + 1.0); // 2w out[3] = 0.5 * fRoot; fRoot = 0.5 / fRoot; // 1/(4w) out[0] = (m[5] - m[7]) * fRoot; out[1] = (m[6] - m[2]) * fRoot; out[2] = (m[1] - m[3]) * fRoot; } else { // |w| <= 1/2 var i = 0; if (m[4] > m[0]) i = 1; if (m[8] > m[i * 3 + i]) i = 2; var j = (i + 1) % 3; var k = (i + 2) % 3; fRoot = Math.sqrt(m[i * 3 + i] - m[j * 3 + j] - m[k * 3 + k] + 1.0); out[i] = 0.5 * fRoot; fRoot = 0.5 / fRoot; out[3] = (m[j * 3 + k] - m[k * 3 + j]) * fRoot; out[j] = (m[j * 3 + i] + m[i * 3 + j]) * fRoot; out[k] = (m[k * 3 + i] + m[i * 3 + k]) * fRoot; } return out; } /** * Creates a quaternion from the given euler angle x, y, z. * * @param {quat} out the receiving quaternion * @param {x} Angle to rotate around X axis in degrees. * @param {y} Angle to rotate around Y axis in degrees. * @param {z} Angle to rotate around Z axis in degrees. * @returns {quat} out * @function */ function fromEuler(out, x, y, z) { var halfToRad = 0.5 * Math.PI / 180.0; x *= halfToRad; y *= halfToRad; z *= halfToRad; var sx = Math.sin(x); var cx = Math.cos(x); var sy = Math.sin(y); var cy = Math.cos(y); var sz = Math.sin(z); var cz = Math.cos(z); out[0] = sx * cy * cz - cx * sy * sz; out[1] = cx * sy * cz + sx * cy * sz; out[2] = cx * cy * sz - sx * sy * cz; out[3] = cx * cy * cz + sx * sy * sz; return out; } /** * Returns a string representation of a quatenion * * @param {quat} a vector to represent as a string * @returns {String} string representation of the vector */ function str(a) { return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; } /** * Creates a new quat initialized with values from an existing quaternion * * @param {quat} a quaternion to clone * @returns {quat} a new quaternion * @function */ var clone = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["clone"]; /** * Creates a new quat initialized with the given values * * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @param {Number} w W component * @returns {quat} a new quaternion * @function */ var fromValues = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["fromValues"]; /** * Copy the values from one quat to another * * @param {quat} out the receiving quaternion * @param {quat} a the source quaternion * @returns {quat} out * @function */ var copy = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["copy"]; /** * Set the components of a quat to the given values * * @param {quat} out the receiving quaternion * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @param {Number} w W component * @returns {quat} out * @function */ var set = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["set"]; /** * Adds two quat's * * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand * @returns {quat} out * @function */ var add = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["add"]; /** * Alias for {@link quat.multiply} * @function */ var mul = multiply; /** * Scales a quat by a scalar number * * @param {quat} out the receiving vector * @param {quat} a the vector to scale * @param {Number} b amount to scale the vector by * @returns {quat} out * @function */ var scale = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["scale"]; /** * Calculates the dot product of two quat's * * @param {quat} a the first operand * @param {quat} b the second operand * @returns {Number} dot product of a and b * @function */ var dot = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["dot"]; /** * Performs a linear interpolation between two quat's * * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out * @function */ var lerp = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["lerp"]; /** * Calculates the length of a quat * * @param {quat} a vector to calculate length of * @returns {Number} length of a */ var length = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["length"]; /** * Alias for {@link quat.length} * @function */ var len = length; /** * Calculates the squared length of a quat * * @param {quat} a vector to calculate squared length of * @returns {Number} squared length of a * @function */ var squaredLength = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["squaredLength"]; /** * Alias for {@link quat.squaredLength} * @function */ var sqrLen = squaredLength; /** * Normalize a quat * * @param {quat} out the receiving quaternion * @param {quat} a quaternion to normalize * @returns {quat} out * @function */ var normalize = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["normalize"]; /** * Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===) * * @param {quat} a The first quaternion. * @param {quat} b The second quaternion. * @returns {Boolean} True if the vectors are equal, false otherwise. */ var exactEquals = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["exactEquals"]; /** * Returns whether or not the quaternions have approximately the same elements in the same position. * * @param {quat} a The first vector. * @param {quat} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ var equals = __WEBPACK_IMPORTED_MODULE_3__vec4_js__["equals"]; /** * Sets a quaternion to represent the shortest rotation from one * vector to another. * * Both vectors are assumed to be unit length. * * @param {quat} out the receiving quaternion. * @param {vec3} a the initial vector * @param {vec3} b the destination vector * @returns {quat} out */ var rotationTo = function () { var tmpvec3 = __WEBPACK_IMPORTED_MODULE_2__vec3_js__["create"](); var xUnitVec3 = __WEBPACK_IMPORTED_MODULE_2__vec3_js__["fromValues"](1, 0, 0); var yUnitVec3 = __WEBPACK_IMPORTED_MODULE_2__vec3_js__["fromValues"](0, 1, 0); return function (out, a, b) { var dot = __WEBPACK_IMPORTED_MODULE_2__vec3_js__["dot"](a, b); if (dot < -0.999999) { __WEBPACK_IMPORTED_MODULE_2__vec3_js__["cross"](tmpvec3, xUnitVec3, a); if (__WEBPACK_IMPORTED_MODULE_2__vec3_js__["len"](tmpvec3) < 0.000001) __WEBPACK_IMPORTED_MODULE_2__vec3_js__["cross"](tmpvec3, yUnitVec3, a); __WEBPACK_IMPORTED_MODULE_2__vec3_js__["normalize"](tmpvec3, tmpvec3); setAxisAngle(out, tmpvec3, Math.PI); return out; } else if (dot > 0.999999) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1; return out; } else { __WEBPACK_IMPORTED_MODULE_2__vec3_js__["cross"](tmpvec3, a, b); out[0] = tmpvec3[0]; out[1] = tmpvec3[1]; out[2] = tmpvec3[2]; out[3] = 1 + dot; return normalize(out, out); } }; }(); /** * Performs a spherical linear interpolation with two control points * * @param {quat} out the receiving quaternion * @param {quat} a the first operand * @param {quat} b the second operand * @param {quat} c the third operand * @param {quat} d the fourth operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat} out */ var sqlerp = function () { var temp1 = create(); var temp2 = create(); return function (out, a, b, c, d, t) { slerp(temp1, a, d, t); slerp(temp2, b, c, t); slerp(out, temp1, temp2, 2 * t * (1 - t)); return out; }; }(); /** * Sets the specified quaternion with values corresponding to the given * axes. Each axis is a vec3 and is expected to be unit length and * perpendicular to all other specified axes. * * @param {vec3} view the vector representing the viewing direction * @param {vec3} right the vector representing the local "right" direction * @param {vec3} up the vector representing the local "up" direction * @returns {quat} out */ var setAxes = function () { var matr = __WEBPACK_IMPORTED_MODULE_1__mat3_js__["create"](); return function (out, view, right, up) { matr[0] = right[0]; matr[3] = right[1]; matr[6] = right[2]; matr[1] = up[0]; matr[4] = up[1]; matr[7] = up[2]; matr[2] = -view[0]; matr[5] = -view[1]; matr[8] = -view[2]; return normalize(out, fromMat3(out, matr)); }; }(); /***/ }), /* 5 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["length"] = length; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["divide"] = divide; /* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; /* harmony export (immutable) */ __webpack_exports__["floor"] = floor; /* harmony export (immutable) */ __webpack_exports__["min"] = min; /* harmony export (immutable) */ __webpack_exports__["max"] = max; /* harmony export (immutable) */ __webpack_exports__["round"] = round; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; /* harmony export (immutable) */ __webpack_exports__["distance"] = distance; /* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; /* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; /* harmony export (immutable) */ __webpack_exports__["negate"] = negate; /* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; /* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; /* harmony export (immutable) */ __webpack_exports__["dot"] = dot; /* harmony export (immutable) */ __webpack_exports__["cross"] = cross; /* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; /* harmony export (immutable) */ __webpack_exports__["hermite"] = hermite; /* harmony export (immutable) */ __webpack_exports__["bezier"] = bezier; /* harmony export (immutable) */ __webpack_exports__["random"] = random; /* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; /* harmony export (immutable) */ __webpack_exports__["transformMat3"] = transformMat3; /* harmony export (immutable) */ __webpack_exports__["transformQuat"] = transformQuat; /* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; /* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; /* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; /* harmony export (immutable) */ __webpack_exports__["angle"] = angle; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 3 Dimensional Vector * @module vec3 */ /** * Creates a new, empty vec3 * * @returns {vec3} a new 3D vector */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](3); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; } return out; } /** * Creates a new vec3 initialized with values from an existing vector * * @param {vec3} a vector to clone * @returns {vec3} a new 3D vector */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](3); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } /** * Calculates the length of a vec3 * * @param {vec3} a vector to calculate length of * @returns {Number} length of a */ function length(a) { var x = a[0]; var y = a[1]; var z = a[2]; return Math.sqrt(x * x + y * y + z * z); } /** * Creates a new vec3 initialized with the given values * * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @returns {vec3} a new 3D vector */ function fromValues(x, y, z) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](3); out[0] = x; out[1] = y; out[2] = z; return out; } /** * Copy the values from one vec3 to another * * @param {vec3} out the receiving vector * @param {vec3} a the source vector * @returns {vec3} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; return out; } /** * Set the components of a vec3 to the given values * * @param {vec3} out the receiving vector * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @returns {vec3} out */ function set(out, x, y, z) { out[0] = x; out[1] = y; out[2] = z; return out; } /** * Adds two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; return out; } /** * Subtracts vector b from vector a * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; return out; } /** * Multiplies two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function multiply(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; out[2] = a[2] * b[2]; return out; } /** * Divides two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function divide(out, a, b) { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; out[2] = a[2] / b[2]; return out; } /** * Math.ceil the components of a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to ceil * @returns {vec3} out */ function ceil(out, a) { out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); out[2] = Math.ceil(a[2]); return out; } /** * Math.floor the components of a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to floor * @returns {vec3} out */ function floor(out, a) { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); out[2] = Math.floor(a[2]); return out; } /** * Returns the minimum of two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function min(out, a, b) { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); out[2] = Math.min(a[2], b[2]); return out; } /** * Returns the maximum of two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function max(out, a, b) { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); out[2] = Math.max(a[2], b[2]); return out; } /** * Math.round the components of a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to round * @returns {vec3} out */ function round(out, a) { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); out[2] = Math.round(a[2]); return out; } /** * Scales a vec3 by a scalar number * * @param {vec3} out the receiving vector * @param {vec3} a the vector to scale * @param {Number} b amount to scale the vector by * @returns {vec3} out */ function scale(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; return out; } /** * Adds two vec3's after scaling the second operand by a scalar value * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @param {Number} scale the amount to scale b by before adding * @returns {vec3} out */ function scaleAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; return out; } /** * Calculates the euclidian distance between two vec3's * * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {Number} distance between a and b */ function distance(a, b) { var x = b[0] - a[0]; var y = b[1] - a[1]; var z = b[2] - a[2]; return Math.sqrt(x * x + y * y + z * z); } /** * Calculates the squared euclidian distance between two vec3's * * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {Number} squared distance between a and b */ function squaredDistance(a, b) { var x = b[0] - a[0]; var y = b[1] - a[1]; var z = b[2] - a[2]; return x * x + y * y + z * z; } /** * Calculates the squared length of a vec3 * * @param {vec3} a vector to calculate squared length of * @returns {Number} squared length of a */ function squaredLength(a) { var x = a[0]; var y = a[1]; var z = a[2]; return x * x + y * y + z * z; } /** * Negates the components of a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to negate * @returns {vec3} out */ function negate(out, a) { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; return out; } /** * Returns the inverse of the components of a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to invert * @returns {vec3} out */ function inverse(out, a) { out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; out[2] = 1.0 / a[2]; return out; } /** * Normalize a vec3 * * @param {vec3} out the receiving vector * @param {vec3} a vector to normalize * @returns {vec3} out */ function normalize(out, a) { var x = a[0]; var y = a[1]; var z = a[2]; var len = x * x + y * y + z * z; if (len > 0) { //TODO: evaluate use of glm_invsqrt here? len = 1 / Math.sqrt(len); out[0] = a[0] * len; out[1] = a[1] * len; out[2] = a[2] * len; } return out; } /** * Calculates the dot product of two vec3's * * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {Number} dot product of a and b */ function dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; } /** * Computes the cross product of two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @returns {vec3} out */ function cross(out, a, b) { var ax = a[0], ay = a[1], az = a[2]; var bx = b[0], by = b[1], bz = b[2]; out[0] = ay * bz - az * by; out[1] = az * bx - ax * bz; out[2] = ax * by - ay * bx; return out; } /** * Performs a linear interpolation between two vec3's * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function lerp(out, a, b, t) { var ax = a[0]; var ay = a[1]; var az = a[2]; out[0] = ax + t * (b[0] - ax); out[1] = ay + t * (b[1] - ay); out[2] = az + t * (b[2] - az); return out; } /** * Performs a hermite interpolation with two control points * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @param {vec3} c the third operand * @param {vec3} d the fourth operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function hermite(out, a, b, c, d, t) { var factorTimes2 = t * t; var factor1 = factorTimes2 * (2 * t - 3) + 1; var factor2 = factorTimes2 * (t - 2) + t; var factor3 = factorTimes2 * (t - 1); var factor4 = factorTimes2 * (3 - 2 * t); out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; return out; } /** * Performs a bezier interpolation with two control points * * @param {vec3} out the receiving vector * @param {vec3} a the first operand * @param {vec3} b the second operand * @param {vec3} c the third operand * @param {vec3} d the fourth operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec3} out */ function bezier(out, a, b, c, d, t) { var inverseFactor = 1 - t; var inverseFactorTimesTwo = inverseFactor * inverseFactor; var factorTimes2 = t * t; var factor1 = inverseFactorTimesTwo * inverseFactor; var factor2 = 3 * t * inverseFactorTimesTwo; var factor3 = 3 * factorTimes2 * inverseFactor; var factor4 = factorTimes2 * t; out[0] = a[0] * factor1 + b[0] * factor2 + c[0] * factor3 + d[0] * factor4; out[1] = a[1] * factor1 + b[1] * factor2 + c[1] * factor3 + d[1] * factor4; out[2] = a[2] * factor1 + b[2] * factor2 + c[2] * factor3 + d[2] * factor4; return out; } /** * Generates a random vector with the given scale * * @param {vec3} out the receiving vector * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned * @returns {vec3} out */ function random(out, scale) { scale = scale || 1.0; var r = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2.0 * Math.PI; var z = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2.0 - 1.0; var zScale = Math.sqrt(1.0 - z * z) * scale; out[0] = Math.cos(r) * zScale; out[1] = Math.sin(r) * zScale; out[2] = z * scale; return out; } /** * Transforms the vec3 with a mat4. * 4th vector component is implicitly '1' * * @param {vec3} out the receiving vector * @param {vec3} a the vector to transform * @param {mat4} m matrix to transform with * @returns {vec3} out */ function transformMat4(out, a, m) { var x = a[0], y = a[1], z = a[2]; var w = m[3] * x + m[7] * y + m[11] * z + m[15]; w = w || 1.0; out[0] = (m[0] * x + m[4] * y + m[8] * z + m[12]) / w; out[1] = (m[1] * x + m[5] * y + m[9] * z + m[13]) / w; out[2] = (m[2] * x + m[6] * y + m[10] * z + m[14]) / w; return out; } /** * Transforms the vec3 with a mat3. * * @param {vec3} out the receiving vector * @param {vec3} a the vector to transform * @param {mat3} m the 3x3 matrix to transform with * @returns {vec3} out */ function transformMat3(out, a, m) { var x = a[0], y = a[1], z = a[2]; out[0] = x * m[0] + y * m[3] + z * m[6]; out[1] = x * m[1] + y * m[4] + z * m[7]; out[2] = x * m[2] + y * m[5] + z * m[8]; return out; } /** * Transforms the vec3 with a quat * Can also be used for dual quaternions. (Multiply it with the real part) * * @param {vec3} out the receiving vector * @param {vec3} a the vector to transform * @param {quat} q quaternion to transform with * @returns {vec3} out */ function transformQuat(out, a, q) { // benchmarks: https://jsperf.com/quaternion-transform-vec3-implementations-fixed var qx = q[0], qy = q[1], qz = q[2], qw = q[3]; var x = a[0], y = a[1], z = a[2]; // var qvec = [qx, qy, qz]; // var uv = vec3.cross([], qvec, a); var uvx = qy * z - qz * y, uvy = qz * x - qx * z, uvz = qx * y - qy * x; // var uuv = vec3.cross([], qvec, uv); var uuvx = qy * uvz - qz * uvy, uuvy = qz * uvx - qx * uvz, uuvz = qx * uvy - qy * uvx; // vec3.scale(uv, uv, 2 * w); var w2 = qw * 2; uvx *= w2; uvy *= w2; uvz *= w2; // vec3.scale(uuv, uuv, 2); uuvx *= 2; uuvy *= 2; uuvz *= 2; // return vec3.add(out, a, vec3.add(out, uv, uuv)); out[0] = x + uvx + uuvx; out[1] = y + uvy + uuvy; out[2] = z + uvz + uuvz; return out; } /** * Rotate a 3D vector around the x-axis * @param {vec3} out The receiving vec3 * @param {vec3} a The vec3 point to rotate * @param {vec3} b The origin of the rotation * @param {Number} c The angle of rotation * @returns {vec3} out */ function rotateX(out, a, b, c) { var p = [], r = []; //Translate point to the origin p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; //perform rotation r[0] = p[0]; r[1] = p[1] * Math.cos(c) - p[2] * Math.sin(c); r[2] = p[1] * Math.sin(c) + p[2] * Math.cos(c); //translate to correct position out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } /** * Rotate a 3D vector around the y-axis * @param {vec3} out The receiving vec3 * @param {vec3} a The vec3 point to rotate * @param {vec3} b The origin of the rotation * @param {Number} c The angle of rotation * @returns {vec3} out */ function rotateY(out, a, b, c) { var p = [], r = []; //Translate point to the origin p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; //perform rotation r[0] = p[2] * Math.sin(c) + p[0] * Math.cos(c); r[1] = p[1]; r[2] = p[2] * Math.cos(c) - p[0] * Math.sin(c); //translate to correct position out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } /** * Rotate a 3D vector around the z-axis * @param {vec3} out The receiving vec3 * @param {vec3} a The vec3 point to rotate * @param {vec3} b The origin of the rotation * @param {Number} c The angle of rotation * @returns {vec3} out */ function rotateZ(out, a, b, c) { var p = [], r = []; //Translate point to the origin p[0] = a[0] - b[0]; p[1] = a[1] - b[1]; p[2] = a[2] - b[2]; //perform rotation r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c); r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c); r[2] = p[2]; //translate to correct position out[0] = r[0] + b[0]; out[1] = r[1] + b[1]; out[2] = r[2] + b[2]; return out; } /** * Get the angle between two 3D vectors * @param {vec3} a The first operand * @param {vec3} b The second operand * @returns {Number} The angle in radians */ function angle(a, b) { var tempA = fromValues(a[0], a[1], a[2]); var tempB = fromValues(b[0], b[1], b[2]); normalize(tempA, tempA); normalize(tempB, tempB); var cosine = dot(tempA, tempB); if (cosine > 1.0) { return 0; } else if (cosine < -1.0) { return Math.PI; } else { return Math.acos(cosine); } } /** * Returns a string representation of a vector * * @param {vec3} a vector to represent as a string * @returns {String} string representation of the vector */ function str(a) { return 'vec3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ')'; } /** * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) * * @param {vec3} a The first vector. * @param {vec3} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2]; } /** * Returns whether or not the vectors have approximately the same elements in the same position. * * @param {vec3} a The first vector. * @param {vec3} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2]; var b0 = b[0], b1 = b[1], b2 = b[2]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)); } /** * Alias for {@link vec3.subtract} * @function */ var sub = subtract; /** * Alias for {@link vec3.multiply} * @function */ var mul = multiply; /** * Alias for {@link vec3.divide} * @function */ var div = divide; /** * Alias for {@link vec3.distance} * @function */ var dist = distance; /** * Alias for {@link vec3.squaredDistance} * @function */ var sqrDist = squaredDistance; /** * Alias for {@link vec3.length} * @function */ var len = length; /** * Alias for {@link vec3.squaredLength} * @function */ var sqrLen = squaredLength; /** * Perform some operation over an array of vec3s. * * @param {Array} a the array of vectors to iterate over * @param {Number} stride Number of elements between the start of each vec3. If 0 assumes tightly packed * @param {Number} offset Number of elements to skip at the beginning of the array * @param {Number} count Number of vec3s to iterate over. If 0 iterates over entire array * @param {Function} fn Function to call for each vector in the array * @param {Object} [arg] additional argument to pass to fn * @returns {Array} a * @function */ var forEach = function () { var vec = create(); return function (a, stride, offset, count, fn, arg) { var i = void 0, l = void 0; if (!stride) { stride = 3; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2]; fn(vec, vec, arg); a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2]; } return a; }; }(); /***/ }), /* 6 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["divide"] = divide; /* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; /* harmony export (immutable) */ __webpack_exports__["floor"] = floor; /* harmony export (immutable) */ __webpack_exports__["min"] = min; /* harmony export (immutable) */ __webpack_exports__["max"] = max; /* harmony export (immutable) */ __webpack_exports__["round"] = round; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; /* harmony export (immutable) */ __webpack_exports__["distance"] = distance; /* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; /* harmony export (immutable) */ __webpack_exports__["length"] = length; /* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; /* harmony export (immutable) */ __webpack_exports__["negate"] = negate; /* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; /* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; /* harmony export (immutable) */ __webpack_exports__["dot"] = dot; /* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; /* harmony export (immutable) */ __webpack_exports__["random"] = random; /* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; /* harmony export (immutable) */ __webpack_exports__["transformQuat"] = transformQuat; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 4 Dimensional Vector * @module vec4 */ /** * Creates a new, empty vec4 * * @returns {vec4} a new 4D vector */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 0; } return out; } /** * Creates a new vec4 initialized with values from an existing vector * * @param {vec4} a vector to clone * @returns {vec4} a new 4D vector */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } /** * Creates a new vec4 initialized with the given values * * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @param {Number} w W component * @returns {vec4} a new 4D vector */ function fromValues(x, y, z, w) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); out[0] = x; out[1] = y; out[2] = z; out[3] = w; return out; } /** * Copy the values from one vec4 to another * * @param {vec4} out the receiving vector * @param {vec4} a the source vector * @returns {vec4} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } /** * Set the components of a vec4 to the given values * * @param {vec4} out the receiving vector * @param {Number} x X component * @param {Number} y Y component * @param {Number} z Z component * @param {Number} w W component * @returns {vec4} out */ function set(out, x, y, z, w) { out[0] = x; out[1] = y; out[2] = z; out[3] = w; return out; } /** * Adds two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; return out; } /** * Subtracts vector b from vector a * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; return out; } /** * Multiplies two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function multiply(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; out[2] = a[2] * b[2]; out[3] = a[3] * b[3]; return out; } /** * Divides two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function divide(out, a, b) { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; out[2] = a[2] / b[2]; out[3] = a[3] / b[3]; return out; } /** * Math.ceil the components of a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to ceil * @returns {vec4} out */ function ceil(out, a) { out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); out[2] = Math.ceil(a[2]); out[3] = Math.ceil(a[3]); return out; } /** * Math.floor the components of a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to floor * @returns {vec4} out */ function floor(out, a) { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); out[2] = Math.floor(a[2]); out[3] = Math.floor(a[3]); return out; } /** * Returns the minimum of two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function min(out, a, b) { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); out[2] = Math.min(a[2], b[2]); out[3] = Math.min(a[3], b[3]); return out; } /** * Returns the maximum of two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {vec4} out */ function max(out, a, b) { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); out[2] = Math.max(a[2], b[2]); out[3] = Math.max(a[3], b[3]); return out; } /** * Math.round the components of a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to round * @returns {vec4} out */ function round(out, a) { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); out[2] = Math.round(a[2]); out[3] = Math.round(a[3]); return out; } /** * Scales a vec4 by a scalar number * * @param {vec4} out the receiving vector * @param {vec4} a the vector to scale * @param {Number} b amount to scale the vector by * @returns {vec4} out */ function scale(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; return out; } /** * Adds two vec4's after scaling the second operand by a scalar value * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @param {Number} scale the amount to scale b by before adding * @returns {vec4} out */ function scaleAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; out[3] = a[3] + b[3] * scale; return out; } /** * Calculates the euclidian distance between two vec4's * * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {Number} distance between a and b */ function distance(a, b) { var x = b[0] - a[0]; var y = b[1] - a[1]; var z = b[2] - a[2]; var w = b[3] - a[3]; return Math.sqrt(x * x + y * y + z * z + w * w); } /** * Calculates the squared euclidian distance between two vec4's * * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {Number} squared distance between a and b */ function squaredDistance(a, b) { var x = b[0] - a[0]; var y = b[1] - a[1]; var z = b[2] - a[2]; var w = b[3] - a[3]; return x * x + y * y + z * z + w * w; } /** * Calculates the length of a vec4 * * @param {vec4} a vector to calculate length of * @returns {Number} length of a */ function length(a) { var x = a[0]; var y = a[1]; var z = a[2]; var w = a[3]; return Math.sqrt(x * x + y * y + z * z + w * w); } /** * Calculates the squared length of a vec4 * * @param {vec4} a vector to calculate squared length of * @returns {Number} squared length of a */ function squaredLength(a) { var x = a[0]; var y = a[1]; var z = a[2]; var w = a[3]; return x * x + y * y + z * z + w * w; } /** * Negates the components of a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to negate * @returns {vec4} out */ function negate(out, a) { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; out[3] = -a[3]; return out; } /** * Returns the inverse of the components of a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to invert * @returns {vec4} out */ function inverse(out, a) { out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; out[2] = 1.0 / a[2]; out[3] = 1.0 / a[3]; return out; } /** * Normalize a vec4 * * @param {vec4} out the receiving vector * @param {vec4} a vector to normalize * @returns {vec4} out */ function normalize(out, a) { var x = a[0]; var y = a[1]; var z = a[2]; var w = a[3]; var len = x * x + y * y + z * z + w * w; if (len > 0) { len = 1 / Math.sqrt(len); out[0] = x * len; out[1] = y * len; out[2] = z * len; out[3] = w * len; } return out; } /** * Calculates the dot product of two vec4's * * @param {vec4} a the first operand * @param {vec4} b the second operand * @returns {Number} dot product of a and b */ function dot(a, b) { return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]; } /** * Performs a linear interpolation between two vec4's * * @param {vec4} out the receiving vector * @param {vec4} a the first operand * @param {vec4} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec4} out */ function lerp(out, a, b, t) { var ax = a[0]; var ay = a[1]; var az = a[2]; var aw = a[3]; out[0] = ax + t * (b[0] - ax); out[1] = ay + t * (b[1] - ay); out[2] = az + t * (b[2] - az); out[3] = aw + t * (b[3] - aw); return out; } /** * Generates a random vector with the given scale * * @param {vec4} out the receiving vector * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned * @returns {vec4} out */ function random(out, scale) { scale = scale || 1.0; // Marsaglia, George. Choosing a Point from the Surface of a // Sphere. Ann. Math. Statist. 43 (1972), no. 2, 645--646. // http://projecteuclid.org/euclid.aoms/1177692644; var v1, v2, v3, v4; var s1, s2; do { v1 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2 - 1; v2 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2 - 1; s1 = v1 * v1 + v2 * v2; } while (s1 >= 1); do { v3 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2 - 1; v4 = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2 - 1; s2 = v3 * v3 + v4 * v4; } while (s2 >= 1); var d = Math.sqrt((1 - s1) / s2); out[0] = scale * v1; out[1] = scale * v2; out[2] = scale * v3 * d; out[3] = scale * v4 * d; return out; } /** * Transforms the vec4 with a mat4. * * @param {vec4} out the receiving vector * @param {vec4} a the vector to transform * @param {mat4} m matrix to transform with * @returns {vec4} out */ function transformMat4(out, a, m) { var x = a[0], y = a[1], z = a[2], w = a[3]; out[0] = m[0] * x + m[4] * y + m[8] * z + m[12] * w; out[1] = m[1] * x + m[5] * y + m[9] * z + m[13] * w; out[2] = m[2] * x + m[6] * y + m[10] * z + m[14] * w; out[3] = m[3] * x + m[7] * y + m[11] * z + m[15] * w; return out; } /** * Transforms the vec4 with a quat * * @param {vec4} out the receiving vector * @param {vec4} a the vector to transform * @param {quat} q quaternion to transform with * @returns {vec4} out */ function transformQuat(out, a, q) { var x = a[0], y = a[1], z = a[2]; var qx = q[0], qy = q[1], qz = q[2], qw = q[3]; // calculate quat * vec 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; // calculate result * inverse quat out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy; out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz; out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx; out[3] = a[3]; return out; } /** * Returns a string representation of a vector * * @param {vec4} a vector to represent as a string * @returns {String} string representation of the vector */ function str(a) { return 'vec4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; } /** * Returns whether or not the vectors have exactly the same elements in the same position (when compared with ===) * * @param {vec4} a The first vector. * @param {vec4} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; } /** * Returns whether or not the vectors have approximately the same elements in the same position. * * @param {vec4} a The first vector. * @param {vec4} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)); } /** * Alias for {@link vec4.subtract} * @function */ var sub = subtract; /** * Alias for {@link vec4.multiply} * @function */ var mul = multiply; /** * Alias for {@link vec4.divide} * @function */ var div = divide; /** * Alias for {@link vec4.distance} * @function */ var dist = distance; /** * Alias for {@link vec4.squaredDistance} * @function */ var sqrDist = squaredDistance; /** * Alias for {@link vec4.length} * @function */ var len = length; /** * Alias for {@link vec4.squaredLength} * @function */ var sqrLen = squaredLength; /** * Perform some operation over an array of vec4s. * * @param {Array} a the array of vectors to iterate over * @param {Number} stride Number of elements between the start of each vec4. If 0 assumes tightly packed * @param {Number} offset Number of elements to skip at the beginning of the array * @param {Number} count Number of vec4s to iterate over. If 0 iterates over entire array * @param {Function} fn Function to call for each vector in the array * @param {Object} [arg] additional argument to pass to fn * @returns {Array} a * @function */ var forEach = function () { var vec = create(); return function (a, stride, offset, count, fn, arg) { var i = void 0, l = void 0; if (!stride) { stride = 4; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i];vec[1] = a[i + 1];vec[2] = a[i + 2];vec[3] = a[i + 3]; fn(vec, vec, arg); a[i] = vec[0];a[i + 1] = vec[1];a[i + 2] = vec[2];a[i + 3] = vec[3]; } return a; }; }(); /***/ }), /* 7 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_gl_matrix__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__css_style_css__ = __webpack_require__(13); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__css_style_css___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_1__css_style_css__); var MinimalGLTFLoader = __webpack_require__(12); // require('./lib/minimal-gltf-loader.js'); // utils var Utils = Utils || {}; (function () { 'use strict'; Utils.getShaderSource = function(id) { return document.getElementById(id).textContent.replace(/^\s+|\s+$/g, ''); }; function createShader(gl, source, type) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } Utils.createProgram = function(gl, vertexShaderSource, fragmentShaderSource) { var program = gl.createProgram(); var vshader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER); var fshader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER); gl.attachShader(program, vshader); gl.deleteShader(vshader); gl.attachShader(program, fshader); gl.deleteShader(fshader); gl.linkProgram(program); var log = gl.getProgramInfoLog(program); if (log) { console.log(log); } log = gl.getShaderInfoLog(vshader); if (log) { console.log(log); } log = gl.getShaderInfoLog(fshader); if (log) { console.log(log); } return program; }; var loadImage = Utils.loadImage = function(url, onload) { var img = new Image(); img.crossOrigin = "Anonymous"; img.src = url; // img.onload = function() { // onload(img); // }; img.onload = onload; return img; }; Utils.loadImages = function(urls, onload) { var imgs = []; var imgsToLoad = urls.length; function onImgLoad() { if (--imgsToLoad <= 0) { onload(imgs); } } for (var i = 0; i < imgsToLoad; ++i) { imgs.push(loadImage(urls[i], onImgLoad)); } }; })(); (function() { 'use strict'; // var selectedGltfSampleModel = 'Drone'; var selectedGltfSampleModel = 'DamagedHelmet'; var drawBoundingBox = false; var boundingBoxType = 'obb'; var curAnimationId = 0; var playAllAnimationTogether = false; var animationSelectionList = document.getElementById("animations"); animationSelectionList.addEventListener("change", function() { curAnimationId = this.selectedIndex; }); document.getElementById("gltf-model").addEventListener("change", function() { // selectedGltfSampleModel = this.value; var uri = this.value; // if (selectedGltfSampleModel == 'Drone') { // uri = 'https://raw.githubusercontent.com/shrekshao/minimal-gltf-loader/store-drone-model/glTFs/glTF_version_2/buster_drone/scene.gltf'; // } else { // uri = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/' // + selectedGltfSampleModel // + '/glTF/' // + selectedGltfSampleModel // + '.gltf'; // } glTFLoader.loadGLTF(uri, function(glTF) { // var scene = scenes[0]; scenes = []; // TODO: delete gl resources // scene = null; setupScene(glTF); }); }); document.getElementById("bbox-toggle").addEventListener("change", function() { drawBoundingBox = this.checked; }); document.getElementById("play-all-animations").addEventListener("change", function() { playAllAnimationTogether = this.checked; }); document.getElementById("bbox-type").addEventListener("change", function() { boundingBoxType = this.value; }); var canvas = document.createElement('canvas'); // canvas.width = Math.min(window.innerWidth, window.innerHeight); // canvas.height = canvas.width; canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var gl = canvas.getContext( 'webgl2', { antialias: true } ); var isWebGL2 = !!gl; if(!isWebGL2) { document.getElementById('info').innerHTML = 'WebGL 2 is not available. See How to get a WebGL 2 implementation'; return; } canvas.oncontextmenu = function (e) { e.preventDefault(); }; // Scene object for runtime renderer var Scene = function(glTFScene, glTF, id) { this.glTFScene = glTFScene; this.glTF = glTF; this.id = id; // runtime renderer context this.rootTransform = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); // @temp, assume every node is in current scene this.nodeMatrix = new Array(glTF.nodes.length); var i, len; for(i = 0, len = this.nodeMatrix.length; i < len; i++) { this.nodeMatrix[i] = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); } // TODO: runtime joint matrix }; var BOUNDING_BOX = { vertexData: new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0 ]), vertexArray: gl.createVertexArray(), vertexBuffer: gl.createBuffer(), program: Utils.createProgram(gl, __webpack_require__(18), __webpack_require__(19)), positionLocation: 0, uniformMvpLocation: 0, draw: (function() { var MVP = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); return (function(bbox, nodeTransform, V, P) { // gl.useProgram(this.program); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(MVP, nodeTransform, bbox.transform); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(MVP, V, MVP); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(MVP, P, MVP); gl.uniformMatrix4fv(this.uniformMvpLocation, false, MVP); // gl.bindVertexArray(this.vertexArray); gl.drawArrays(gl.LINES, 0, 24); // gl.bindVertexArray(null); }); })() }; var defaultSampler = gl.createSampler(); gl.samplerParameteri(defaultSampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); gl.samplerParameteri(defaultSampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_T, gl.REPEAT); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_R, gl.REPEAT); // gl.samplerParameterf(defaultSampler, gl.TEXTURE_MIN_LOD, -1000.0); // gl.samplerParameterf(defaultSampler, gl.TEXTURE_MAX_LOD, 1000.0); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_COMPARE_MODE, gl.NONE); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); BOUNDING_BOX.uniformMvpLocation = gl.getUniformLocation(BOUNDING_BOX.program, "u_MVP"); gl.bindVertexArray(BOUNDING_BOX.vertexArray); gl.bindBuffer(gl.ARRAY_BUFFER, BOUNDING_BOX.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, BOUNDING_BOX.vertexData, gl.STATIC_DRAW); gl.vertexAttribPointer(BOUNDING_BOX.positionLocation, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(BOUNDING_BOX.positionLocation); gl.bindVertexArray(null); var BRDF_LUT = { texture: null, textureIndex: 29, createTexture: function (img) { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D( gl.TEXTURE_2D, // assumed 0, // Level of details gl.RG16F, // Format gl.RG, // gl.RGBA, // Format // gl.RGBA, // gl.UNSIGNED_BYTE, // Size of each channel gl.FLOAT, img ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 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.bindTexture(gl.TEXTURE_2D, null); } } // Environment maps var CUBE_MAP = { textureIndex: 31, texture: null, // IBL textureIBLDiffuseIndex: 30, textureIBLDiffuse: null, // loading asset -------------------- // TODO: use webpack to pack these uris: [ '../textures/environment/px.jpg', '../textures/environment/nx.jpg', '../textures/environment/py.jpg', '../textures/environment/ny.jpg', '../textures/environment/pz.jpg', '../textures/environment/nz.jpg', // ibl diffuse '../textures/environment/diffuse/bakedDiffuse_01.jpg', '../textures/environment/diffuse/bakedDiffuse_02.jpg', '../textures/environment/diffuse/bakedDiffuse_03.jpg', '../textures/environment/diffuse/bakedDiffuse_04.jpg', '../textures/environment/diffuse/bakedDiffuse_05.jpg', '../textures/environment/diffuse/bakedDiffuse_06.jpg', // '../textures/papermill/environment_right_0.jpg', // '../textures/papermill/environment_left_0.jpg', // '../textures/papermill/environment_top_0.jpg', // '../textures/papermill/environment_bottom_0.jpg', // '../textures/papermill/environment_front_0.jpg', // '../textures/papermill/environment_back_0.jpg', // '../textures/papermill/diffuse/diffuse_right_0.jpg', // '../textures/papermill/diffuse/diffuse_left_0.jpg', // '../textures/papermill/diffuse/diffuse_top_0.jpg', // '../textures/papermill/diffuse/diffuse_bottom_0.jpg', // '../textures/papermill/diffuse/diffuse_front_0.jpg', // '../textures/papermill/diffuse/diffuse_back_0.jpg', // @tmp, ugly, load brdfLUT here '../textures/brdfLUT.png' ], images: null, loadAll: function() { Utils.loadImages(this.uris, this.onloadAll.bind(this)); }, onloadAll: function(imgs) { this.images = imgs; console.log('all cube maps loaded'); this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); for (var i = 0; i < 6; i++) { gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.images[i] ); } gl.generateMipmap(gl.TEXTURE_CUBE_MAP); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); this.textureIBLDiffuse = gl.createTexture(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.textureIBLDiffuse); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); for (var i = 0; i < 6; i++) { gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.images[i + 6] ); } gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); // @tmp BRDF_LUT.createTexture(this.images[this.images.length - 1]); if (this.finishLoadingCallback) { this.finishLoadingCallback(); } }, finishLoadingCallback: null, // runtime stuffs ------------------------- vertexData: new Float32Array([ -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ]), vertexArray: gl.createVertexArray(), vertexBuffer: gl.createBuffer(), program: Utils.createProgram(gl, __webpack_require__(20), __webpack_require__(21)), positionLocation: 0, uniformMvpLocation: 0, uniformEnvironmentLocation: 0, draw: (function() { var MVP = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); return (function(V, P) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].copy(MVP, V); MVP[12] = 0.0; MVP[13] = 0.0; MVP[14] = 0.0; MVP[15] = 1.0; __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(MVP, P, MVP); gl.useProgram(this.program); gl.activeTexture(gl.TEXTURE0 + this.textureIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture); gl.uniformMatrix4fv(this.uniformMvpLocation, false, MVP); gl.uniform1i(this.uniformEnvironmentLocation, this.textureIndex); gl.bindVertexArray(this.vertexArray); gl.drawArrays(gl.TRIANGLES, 0, 36); gl.bindVertexArray(null); }); })() }; CUBE_MAP.uniformMvpLocation = gl.getUniformLocation(CUBE_MAP.program, "u_MVP"); CUBE_MAP.uniformEnvironmentLocation = gl.getUniformLocation(CUBE_MAP.program, "u_environment"); gl.bindVertexArray(CUBE_MAP.vertexArray); gl.bindBuffer(gl.ARRAY_BUFFER, CUBE_MAP.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, CUBE_MAP.vertexData, gl.STATIC_DRAW); gl.vertexAttribPointer(CUBE_MAP.positionLocation, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(CUBE_MAP.positionLocation); gl.bindVertexArray(null); var Shader_Static = { shaderVersionLine: '#version 300 es\n', bitMasks: { // vertex shader HAS_SKIN: 1, SKIN_VEC8: 2, // fragment shader HAS_BASECOLORMAP: 4, HAS_NORMALMAP: 8, HAS_METALROUGHNESSMAP: 16, HAS_OCCLUSIONMAP: 32, HAS_EMISSIVEMAP: 64 }, vsMasterCode: __webpack_require__(22), fsMasterCode: __webpack_require__(23), programObjects: {} // < flags, Shader Object > }; var Shader = function() { this.flags = 0; this.programObject = null; }; Shader.prototype.hasSkin = function() { return this.flags & Shader_Static.bitMasks.HAS_SKIN; }; Shader.prototype.hasBaseColorMap = function() { return this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP; }; Shader.prototype.hasNormalMap = function() { return this.flags & Shader_Static.bitMasks.HAS_NORMALMAP; }; Shader.prototype.hasMetalRoughnessMap = function() { return this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP; }; Shader.prototype.hasOcclusionMap = function() { return this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP; }; Shader.prototype.hasEmissiveMap = function() { return this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP; }; Shader.prototype.defineMacro = function(macro) { if (Shader_Static.bitMasks[macro] !== undefined) { this.flags = Shader_Static.bitMasks[macro] | this.flags; } else { console.log('WARNING: ' + macro + ' is not a valid macro'); } }; Shader.prototype.compile = function() { var existingProgramObject = Shader_Static.programObjects[this.flags]; if (existingProgramObject) { this.programObject = existingProgramObject; return; } // new program var vsDefine = ''; var fsDefine = ''; // define macros if (this.flags & Shader_Static.bitMasks.HAS_SKIN) { vsDefine += '#define HAS_SKIN\n'; } if (this.flags & Shader_Static.bitMasks.SKIN_VEC8) { vsDefine += '#define SKIN_VEC8\n'; } if (this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP) { fsDefine += '#define HAS_BASECOLORMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_NORMALMAP) { fsDefine += '#define HAS_NORMALMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP) { fsDefine += '#define HAS_METALROUGHNESSMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP) { fsDefine += '#define HAS_OCCLUSIONMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP) { fsDefine += '#define HAS_EMISSIVEMAP\n'; } // concat var vertexShaderSource = Shader_Static.shaderVersionLine + vsDefine + Shader_Static.vsMasterCode; var fragmentShaderSource = Shader_Static.shaderVersionLine + fsDefine + Shader_Static.fsMasterCode; // compile var program = Utils.createProgram(gl, vertexShaderSource, fragmentShaderSource); this.programObject = { program: program, uniformLocations: {}, uniformBlockIndices: {} }; // uniform block id if (this.flags & Shader_Static.bitMasks.HAS_SKIN) { this.programObject.uniformBlockIndices.JointMatrix = gl.getUniformBlockIndex(program, "JointMatrix"); } // uniform locations var us = this.programObject.uniformLocations; us.MVP = gl.getUniformLocation(program, 'u_MVP'); us.MVNormal = gl.getUniformLocation(program, 'u_MVNormal'); us.MV = gl.getUniformLocation(program, 'u_MV'); us.baseColorFactor = gl.getUniformLocation(program, 'u_baseColorFactor'); us.metallicFactor = gl.getUniformLocation(program, 'u_metallicFactor'); us.roughnessFactor = gl.getUniformLocation(program, 'u_roughnessFactor'); if (this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP) { us.baseColorTexture = gl.getUniformLocation(program, 'u_baseColorTexture'); } if (this.flags & Shader_Static.bitMasks.HAS_NORMALMAP) { us.normalTexture = gl.getUniformLocation(program, 'u_normalTexture'); us.normalTextureScale = gl.getUniformLocation(program, 'u_normalTextureScale'); } if (this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP) { us.metallicRoughnessTexture = gl.getUniformLocation(program, 'u_metallicRoughnessTexture'); } if (this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP) { us.occlusionTexture = gl.getUniformLocation(program, 'u_occlusionTexture'); us.occlusionStrength = gl.getUniformLocation(program, 'u_occlusionStrength'); } if (this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP) { us.emissiveTexture = gl.getUniformLocation(program, 'u_emissiveTexture'); us.emissiveFactor = gl.getUniformLocation(program, 'u_emissiveFactor'); } us.diffuseEnvSampler = gl.getUniformLocation(program, 'u_DiffuseEnvSampler'); us.specularEnvSampler = gl.getUniformLocation(program, 'u_SpecularEnvSampler'); us.brdfLUT = gl.getUniformLocation(program, 'u_brdfLUT'); // set static uniform values in cubemap gl.useProgram(program); gl.uniform1i(us.brdfLUT, BRDF_LUT.textureIndex); gl.uniform1i(us.specularEnvSampler, CUBE_MAP.textureIndex); gl.uniform1i(us.diffuseEnvSampler, CUBE_MAP.textureIBLDiffuseIndex); gl.useProgram(null); Shader_Static.programObjects[this.flags] = this.programObject; }; // -- Initialize vertex array var POSITION_LOCATION = 0; // set with GLSL layout qualifier var NORMAL_LOCATION = 1; // set with GLSL layout qualifier var TEXCOORD_0_LOCATION = 2; // set with GLSL layout qualifier var JOINTS_0_LOCATION = 3; // set with GLSL layout qualifier var JOINTS_1_LOCATION = 5; // set with GLSL layout qualifier var WEIGHTS_0_LOCATION = 4; // set with GLSL layout qualifier var WEIGHTS_1_LOCATION = 6; // set with GLSL layout qualifier // -- Mouse Behaviour var isDisplayRotation = true; var s = 1; var eulerX = 0; var eulerY = 0; // var s = 1; // var t = -100; var translate = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); // var t = -5; var modelMatrix = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var mouseDown = false; var mouseButtonId = 0; var lastMouseY = 0; var lastMouseX = 0; var identityQ = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["quat"].create(); window.onmousedown = function(event) { mouseDown = true; mouseButtonId = event.which; lastMouseY = event.clientY; lastMouseX = event.clientX; if (mouseButtonId === 1) { isDisplayRotation = false; } }; window.onmouseup = function(event) { mouseDown = false; isDisplayRotation = true; }; window.onmousemove = function(event) { if(!mouseDown) { return; } var newY = event.clientY; var newX = event.clientX; var deltaY = newY - lastMouseY; var deltaX = newX - lastMouseX; // s *= (1 + deltaY / 1000); switch(mouseButtonId) { case 1: // left: rotation eulerX += -deltaY * 0.01; eulerY += deltaX * 0.01; break; case 3: // right translate[0] += deltaX * 0.001; translate[1] += -deltaY * 0.001; break; } lastMouseY = newY; lastMouseX = newX; }; window.onwheel = function(event) { translate[2] += -event.deltaY * 0.001; // translate[2] *= 1 + (-event.deltaY * 0.01); }; // 2.0 // var gltfUrl = '../glTFs/glTF_version_2/Duck/glTF/Duck.gltf'; var gltfUrl = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf'; var glTFLoader = new MinimalGLTFLoader.glTFLoader(gl); var glTFModelCount = 1; var scenes = []; gl.enable(gl.CULL_FACE); gl.cullFace(gl.BACK); gl.frontFace(gl.CCW); var isFaceCulling = true; function setupScene(glTF, replaceScene) { var i, len; // update animation list for(i = animationSelectionList.options.length - 1 ; i >= 0 ; i--) { animationSelectionList.remove(i); } if (glTF.animations) { var option; for (i = 0, len = glTF.animations.length; i < len; i++) { option = document.createElement("option"); option.text = glTF.animations[i].name || i; animationSelectionList.add(option); } } curAnimationId = 0; // ---------------- var curGltfScene = glTF.scenes[glTF.defaultScene]; var sceneDeltaTranslate = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(curGltfScene.boundingBox.transform[0] * 1.2, 0, 0); var tmpVec3Translate = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var newGltfRuntimeScene; if (!replaceScene) { newGltfRuntimeScene = new Scene(curGltfScene, glTF, scenes.length); scenes.push(newGltfRuntimeScene); } else { newGltfRuntimeScene = scenes[replaceScene.id] = new Scene(curGltfScene, glTF, replaceScene.id); } // for (i = 0, len = glTFModelCount; i < len; i++) { // scenes.push(new Scene(curGltfScene, glTF)); // // vec3.scale(tmpVec3Translate, sceneDeltaTranslate, i); // // mat4.fromTranslation(scenes[i].rootTransform, tmpVec3Translate); // } if (scenes.length === 1) { // first model, adjust camera __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].identity(modelMatrix); // center s = 1.0 / Math.max( curGltfScene.boundingBox.transform[0], Math.max(curGltfScene.boundingBox.transform[5], curGltfScene.boundingBox.transform[10]) ); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].getTranslation(translate, curGltfScene.boundingBox.transform); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(translate, translate, -1); translate[0] += - 0.5 * curGltfScene.boundingBox.transform[0]; translate[1] += - 0.5 * curGltfScene.boundingBox.transform[5]; translate[2] += - 0.5 * curGltfScene.boundingBox.transform[10]; s *= 0.5; modelMatrix[0] = s; modelMatrix[5] = s; modelMatrix[10] = s; __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].translate(modelMatrix, modelMatrix, translate); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].set(translate, 0, 0, -1.5); s = 1; } // var in loop var mesh; var primitive; var vertexBuffer; var indexBuffer; var vertexArray; var nid, lenNodes; var mid, lenMeshes; var attribute; var material; var image, texture, sampler; var accessor, bufferView; var animation, animationSampler, channel; var skin; // create buffers for (i = 0, len = glTF.bufferViews.length; i < len; i++) { bufferView = glTF.bufferViews[i]; bufferView.createBuffer(gl); bufferView.bindData(gl); } // create textures if (glTF.textures) { for (i = 0, len = glTF.textures.length; i < len; i++) { texture = glTF.textures[i]; texture.createTexture(gl); } } // create samplers if (glTF.samplers) { for (i = 0, len = glTF.samplers.length; i < len; i++) { sampler = glTF.samplers[i]; sampler.createSampler(gl); } } if (glTF.skins) { // gl.useProgram(programSkinBaseColor.program); // gl.uniformBlockBinding(programSkinBaseColor.program, programSkinBaseColor.uniformBlockIndexJointMatrix, 0); // gl.useProgram(null); for (i = 0, len = glTF.skins.length; i < len; i++) { skin = glTF.skins[i]; skin.jointMatrixUniformBuffer = gl.createBuffer(); // gl.bindBufferBase(gl.UNIFORM_BUFFER, i, skin.jointMatrixUniformBuffer); gl.bindBufferBase(gl.UNIFORM_BUFFER, skin.uniformBlockID, skin.jointMatrixUniformBuffer); gl.bindBuffer(gl.UNIFORM_BUFFER, skin.jointMatrixUniformBuffer); gl.bufferData(gl.UNIFORM_BUFFER, skin.jointMatrixUnidormBufferData, gl.DYNAMIC_DRAW); gl.bufferSubData(gl.UNIFORM_BUFFER, 0, skin.jointMatrixUnidormBufferData); gl.bindBuffer(gl.UNIFORM_BUFFER, null); } } function setupAttribuite(attrib, location) { if (attrib !== undefined) { // var accessor = glTF.accessors[ attrib ]; var accessor = attrib; var bufferView = accessor.bufferView; if (bufferView.target === null) { // console.log('WARNING: the bufferview of this accessor should have a target, or it should represent non buffer data (like animation)'); gl.bindBuffer(gl.ARRAY_BUFFER, bufferView.buffer); gl.bufferData(gl.ARRAY_BUFFER, bufferView.data, gl.STATIC_DRAW); } else { gl.bindBuffer(bufferView.target, bufferView.buffer); } accessor.prepareVertexAttrib(location, gl); return true; } return false; } // create vaos & materials shader source setup for (mid = 0, lenMeshes = glTF.meshes.length; mid < lenMeshes; mid++) { mesh = glTF.meshes[mid]; // vertexArrayMaps[mid] = []; for (i = 0, len = mesh.primitives.length; i < len; ++i) { primitive = mesh.primitives[i]; primitive.shader = new Shader(); // WebGL2: create vertexArray primitive.vertexArray = vertexArray = gl.createVertexArray(); gl.bindVertexArray(vertexArray); setupAttribuite(primitive.attributes.POSITION, POSITION_LOCATION); setupAttribuite(primitive.attributes.NORMAL, NORMAL_LOCATION); // @tmp, should consider together with material setupAttribuite(primitive.attributes.TEXCOORD_0, TEXCOORD_0_LOCATION); if ( setupAttribuite(primitive.attributes.JOINTS_0, JOINTS_0_LOCATION) && setupAttribuite(primitive.attributes.WEIGHTS_0, WEIGHTS_0_LOCATION) ) { // assume these two attributes always appear together primitive.shader.defineMacro('HAS_SKIN'); } if ( setupAttribuite(primitive.attributes.JOINTS_1, JOINTS_1_LOCATION) && setupAttribuite(primitive.attributes.WEIGHTS_1, WEIGHTS_1_LOCATION) ) { // assume these two attributes always appear together primitive.shader.defineMacro('SKIN_VEC8'); } // indices ( assume use indices ) if (primitive.indices !== null) { accessor = glTF.accessors[ primitive.indices ]; bufferView = accessor.bufferView; if (bufferView.target === null) { // console.log('WARNING: the bufferview of this accessor should have a target, or it should represent non buffer data (like animation)'); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferView.buffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferView.data, gl.STATIC_DRAW); } else { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferView.buffer); } } gl.bindVertexArray(null); gl.bindBuffer(gl.ARRAY_BUFFER, null); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); // material shader setup material = primitive.material; if (material) { if (material.pbrMetallicRoughness.baseColorTexture) { primitive.shader.defineMacro('HAS_BASECOLORMAP'); } if (material.pbrMetallicRoughness.metallicRoughnessTexture) { primitive.shader.defineMacro('HAS_METALROUGHNESSMAP'); } if (material.normalTexture) { primitive.shader.defineMacro('HAS_NORMALMAP'); } if (material.occlusionTexture) { primitive.shader.defineMacro('HAS_OCCLUSIONMAP'); } if (material.emissiveTexture) { primitive.shader.defineMacro('HAS_EMISSIVEMAP'); } } primitive.shader.compile(); } } return newGltfRuntimeScene; } // -- Render preparation gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); var Renderer = Renderer || {}; var program = null; // current program object (function() { 'use strict'; var scale = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var r = 0.0; var rotationSpeedY= 0.01; // var rotationSpeedY= 0.0; var perspective = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].perspective(perspective, 0.785, canvas.width / canvas.height, 0.01, 100); var modelView = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var localMV = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var localMVP = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var localMVNormal = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var VP = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var hasIndices = true; var hasSkin = false; var uniformBlockID; // same for uniform block binding id var curScene; function activeAndBindTexture(uniformLocation, textureInfo) { gl.uniform1i(uniformLocation, textureInfo.index); gl.activeTexture(gl.TEXTURE0 + textureInfo.index); var texture = curScene.glTF.textures[ textureInfo.index ]; gl.bindTexture(gl.TEXTURE_2D, texture.texture); var sampler; if (texture.sampler) { sampler = texture.sampler.sampler; } else { sampler = defaultSampler; } gl.bindSampler(textureInfo.index, sampler); } var defaultColor = [1.0, 1.0, 1.0, 1.0]; var drawPrimitive = Renderer.drawPrimitive = function(primitive, matrix) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].multiply(localMV, modelView, matrix); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].multiply(localMVP, perspective, localMV); // mat4.multiply(localMVP, VP, matrix); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].invert(localMVNormal, localMV); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].transpose(localMVNormal, localMVNormal); var texture, sampler; var baseColor = defaultColor; var shader = primitive.shader; var material = primitive.material; if (material !== null) { var pbrMetallicRoughness = material.pbrMetallicRoughness; baseColor = pbrMetallicRoughness.baseColorFactor; if (primitive.material.doubleSided === isFaceCulling) { isFaceCulling = !primitive.material.doubleSided; if (isFaceCulling) { gl.enable(gl.CULL_FACE); } else { gl.disable(gl.CULL_FACE); } } } if (program != primitive.shader.programObject) { program = primitive.shader.programObject; gl.useProgram(program.program); } if (material) { // base color texture if (shader.hasBaseColorMap()) { activeAndBindTexture(program.uniformLocations.baseColorTexture, pbrMetallicRoughness.baseColorTexture); } // normal texture if (shader.hasNormalMap()) { activeAndBindTexture(program.uniformLocations.normalTexture, material.normalTexture); gl.uniform1f(program.uniformLocations.normalTextureScale, material.normalTexture.scale); } // metallic roughness texture if (shader.hasMetalRoughnessMap()) { activeAndBindTexture(program.uniformLocations.metallicRoughnessTexture, pbrMetallicRoughness.metallicRoughnessTexture); } gl.uniform1f(program.uniformLocations.metallicFactor, pbrMetallicRoughness.metallicFactor); gl.uniform1f(program.uniformLocations.roughnessFactor, pbrMetallicRoughness.roughnessFactor); // occlusion texture if (shader.hasOcclusionMap()) { activeAndBindTexture(program.uniformLocations.occlusionTexture, material.occlusionTexture); gl.uniform1f(program.uniformLocations.occlusionStrength, material.occlusionTexture.strength); } // emissive texture if (shader.hasEmissiveMap()) { activeAndBindTexture(program.uniformLocations.emissiveTexture, material.emissiveTexture); gl.uniform3fv(program.uniformLocations.emissiveFactor, material.emissiveFactor); } } // TODO: skin JointMatrix uniform block if (shader.hasSkin()) { gl.uniformBlockBinding(program.program, program.uniformBlockIndices.JointMatrix, uniformBlockID); } gl.activeTexture(gl.TEXTURE0 + BRDF_LUT.textureIndex); gl.bindTexture(gl.TEXTURE_2D, BRDF_LUT.texture); // console.log( (gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toString(16) ); gl.activeTexture(gl.TEXTURE0 + CUBE_MAP.textureIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, CUBE_MAP.texture); gl.activeTexture(gl.TEXTURE0 + CUBE_MAP.textureIBLDiffuseIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, CUBE_MAP.textureIBLDiffuse); gl.uniform4fv(program.uniformLocations.baseColorFactor, baseColor); gl.uniformMatrix4fv(program.uniformLocations.MV, false, localMV); gl.uniformMatrix4fv(program.uniformLocations.MVP, false, localMVP); gl.uniformMatrix4fv(program.uniformLocations.MVNormal, false, localMVNormal); gl.bindVertexArray(primitive.vertexArray); if (primitive.indices !== null) { gl.drawElements(primitive.mode, primitive.indicesLength, primitive.indicesComponentType, primitive.indicesOffset); } else { gl.drawArrays(primitive.mode, primitive.drawArraysOffset, primitive.drawArraysCount); } gl.bindVertexArray(null); } var tmpMat4 = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); var inverseTransformMat4 = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); // @todo: // in a real engine, it is better to simply parse the node tree stucture // to compute transform matrices, // then sort node array by material and render use a for loop // to minimize context switch var drawNode = Renderer.drawNode = function (node, nodeID, nodeMatrix, parentModelMatrix) { var matrix = nodeMatrix[nodeID]; if (parentModelMatrix !== undefined) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(matrix, parentModelMatrix, node.matrix); } else { // from scene root, parent is identity __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].copy(matrix, node.matrix); } // mat4.mul(matrix, parentModelMatrix, node.matrix); hasSkin = false; if (node.skin !== null) { // mesh node with skin hasSkin = true; var skin = node.skin; uniformBlockID = skin.uniformBlockID; var joints = node.skin.joints; var jointNode; __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].invert(inverseTransformMat4, matrix); // @tmp: assume joint nodes are always in the front of the scene node list // so that their matrices are ready to use for (i = 0, len = joints.length; i < len; i++) { jointNode = joints[i]; __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(tmpMat4, nodeMatrix[jointNode.nodeID], skin.inverseBindMatrix[i]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(tmpMat4, inverseTransformMat4, tmpMat4); // if (skin.skeleton !== null) { // mat4.mul(tmpMat4, inverseSkeletonRootMat4, tmpMat4); // } skin.jointMatrixUnidormBufferData.set(tmpMat4, i * 16); } gl.bindBuffer(gl.UNIFORM_BUFFER, skin.jointMatrixUniformBuffer); gl.bufferSubData(gl.UNIFORM_BUFFER, 0, skin.jointMatrixUnidormBufferData, 0, skin.jointMatrixUnidormBufferData.length); } var i, len; // draw cur node's mesh if (node.mesh !== null) { // drawMesh(glTF.meshes[node.mesh], matrix); // var mesh = glTF.meshes[node.mesh]; var mesh = node.mesh; for (i = 0, len = mesh.primitives.length; i < len; i++) { // draw primitive drawPrimitive(mesh.primitives[i], matrix); } // BOUNDING_BOX.draw(mesh.boundingBox, matrix, modelView, perspective); // gl.useProgram(program); } if (node.skin !== null) { gl.bindBuffer(gl.UNIFORM_BUFFER, null); } // draw children var childNodeID; for (i = 0, len = node.children.length; i < len; i++) { // childNodeID = node.children[i]; // drawNode(glTF.nodes[childNodeID], childNodeID, matrix); drawNode(node.children[i], node.children[i].nodeID, nodeMatrix, matrix); } } function applyAnimation(animation, glTF) { var j, lenj; var channel, animationSampler, node; for (j = 0, lenj = animation.samplers.length; j < lenj; j++) { animation.samplers[j].getValue(timeParameter); } for (j = 0, lenj = animation.channels.length; j < lenj; j++) { channel = animation.channels[j]; animationSampler = channel.sampler; node = glTF.nodes[channel.target.nodeID]; switch (channel.target.path) { case 'rotation': __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].copy(node.rotation, animationSampler.curValue); break; case 'translation': __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].copy(node.translation, animationSampler.curValue); break; case 'scale': __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].copy(node.scale, animationSampler.curValue); break; } node.updateMatrixFromTRS(); } } var drawScene = Renderer.drawScene = function (scene) { // animation var animation; var i, len; var glTF = scene.glTF; if (glTF.animations) { if (playAllAnimationTogether) { for (i = 0, len = glTF.animations.length; i < len; i++) { animation = glTF.animations[i]; applyAnimation(animation, glTF); } } else { animation = glTF.animations[curAnimationId]; applyAnimation(animation, glTF); } } for (var i = 0, len = scene.glTFScene.nodes.length; i < len; i++) { drawNode( scene.glTFScene.nodes[i], scene.glTFScene.nodes[i].nodeID, scene.nodeMatrix, scene.rootTransform ); } } var drawSceneBBox = Renderer.drawSceneBBox = function (glTF, scene, bboxType) { var node, mesh, bbox; // @temp: assume all nodes are in cur scene // @potential fix: can label each node's scene at the setup var i, len; for (i = 0, len = scene.nodeMatrix.length; i < len; i++) { node = glTF.nodes[i]; if (bboxType == 'bvh') { // bvh __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, scene.rootTransform, node.bvh.transform); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, VP, localMVP); gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); gl.drawArrays(gl.LINES, 0, 24); } else if (node.mesh !== null) { // mesh = glTF.meshes[node.mesh]; mesh = node.mesh; if (bboxType == 'aabb') { // aabb __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, scene.rootTransform, node.aabb.transform); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, VP, localMVP); } else { // obb (assume object node is static) __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, scene.nodeMatrix[i], mesh.boundingBox.transform); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(localMVP, VP, localMVP); } gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); gl.drawArrays(gl.LINES, 0, 24); } } // // scene bounding box // mat4.mul(localMVP, scene.rootTransform, scene.glTFScene.boundingBox.transform); // mat4.mul(localMVP, VP, localMVP); // gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); // gl.drawArrays(gl.LINES, 0, 24); } var timeStampZero = performance.now(); var timeParameter = 0; // -- Render loop // function render() { var render = Renderer.render = function(timestamp) { var i, len; var j, lenj; var node; gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].set(scale, s, s, s); // mat4.identity(modelView); // mat4.translate(modelView, modelView, translate); // mat4.scale(modelView, modelView, scale); // mat4.fromRotationTranslationScale(modelView, identityQ, translate, scale); // mat4.mul(modelView, modelView, modelMatrix); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].identity(modelView); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].translate(modelView, modelView, translate); if (isDisplayRotation) { r += rotationSpeedY; } __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].rotateX(modelView, modelView, eulerX); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].rotateY(modelView, modelView, r); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].scale(modelView, modelView, scale); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(modelView, modelView, modelMatrix); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].rotateY(modelView, modelView, eulerY); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(VP, perspective, modelView); for (i = 0, len = scenes.length; i < len; i++) { curScene = scenes[i]; drawScene(scenes[i]); } if (drawBoundingBox) { gl.useProgram(BOUNDING_BOX.program); gl.bindVertexArray(BOUNDING_BOX.vertexArray); for (i = 0, len = scenes.length; i < len; i++) { drawSceneBBox(scenes[i].glTF, scenes[i], boundingBoxType); } gl.bindVertexArray(null); } // cube map CUBE_MAP.draw(modelView, perspective); program = null; timeParameter = (timestamp - timeStampZero) * 0.001; requestAnimationFrame(render); } })(); CUBE_MAP.finishLoadingCallback = function() { glTFLoader.loadGLTF(gltfUrl, function(glTF) { setupScene(glTF); Renderer.render(); }); }; CUBE_MAP.loadAll(); })(); /***/ }), /* 8 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["transpose"] = transpose; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["adjoint"] = adjoint; /* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; /* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["frob"] = frob; /* harmony export (immutable) */ __webpack_exports__["LDU"] = LDU; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; /* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 2x2 Matrix * @module mat2 */ /** * Creates a new identity mat2 * * @returns {mat2} a new 2x2 matrix */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[1] = 0; out[2] = 0; } out[0] = 1; out[3] = 1; return out; } /** * Creates a new mat2 initialized with values from an existing matrix * * @param {mat2} a matrix to clone * @returns {mat2} a new 2x2 matrix */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } /** * Copy the values from one mat2 to another * * @param {mat2} out the receiving matrix * @param {mat2} a the source matrix * @returns {mat2} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; return out; } /** * Set a mat2 to the identity matrix * * @param {mat2} out the receiving matrix * @returns {mat2} out */ function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 1; return out; } /** * Create a new mat2 with the given values * * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m10 Component in column 1, row 0 position (index 2) * @param {Number} m11 Component in column 1, row 1 position (index 3) * @returns {mat2} out A new 2x2 matrix */ function fromValues(m00, m01, m10, m11) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](4); out[0] = m00; out[1] = m01; out[2] = m10; out[3] = m11; return out; } /** * Set the components of a mat2 to the given values * * @param {mat2} out the receiving matrix * @param {Number} m00 Component in column 0, row 0 position (index 0) * @param {Number} m01 Component in column 0, row 1 position (index 1) * @param {Number} m10 Component in column 1, row 0 position (index 2) * @param {Number} m11 Component in column 1, row 1 position (index 3) * @returns {mat2} out */ function set(out, m00, m01, m10, m11) { out[0] = m00; out[1] = m01; out[2] = m10; out[3] = m11; return out; } /** * Transpose the values of a mat2 * * @param {mat2} out the receiving matrix * @param {mat2} a the source matrix * @returns {mat2} out */ function transpose(out, a) { // If we are transposing ourselves we can skip a few steps but have to cache // some values if (out === a) { var a1 = a[1]; out[1] = a[2]; out[2] = a1; } else { out[0] = a[0]; out[1] = a[2]; out[2] = a[1]; out[3] = a[3]; } return out; } /** * Inverts a mat2 * * @param {mat2} out the receiving matrix * @param {mat2} a the source matrix * @returns {mat2} out */ function invert(out, a) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; // Calculate the determinant var det = a0 * a3 - a2 * a1; if (!det) { return null; } det = 1.0 / det; out[0] = a3 * det; out[1] = -a1 * det; out[2] = -a2 * det; out[3] = a0 * det; return out; } /** * Calculates the adjugate of a mat2 * * @param {mat2} out the receiving matrix * @param {mat2} a the source matrix * @returns {mat2} out */ function adjoint(out, a) { // Caching this value is nessecary if out == a var a0 = a[0]; out[0] = a[3]; out[1] = -a[1]; out[2] = -a[2]; out[3] = a0; return out; } /** * Calculates the determinant of a mat2 * * @param {mat2} a the source matrix * @returns {Number} determinant of a */ function determinant(a) { return a[0] * a[3] - a[2] * a[1]; } /** * Multiplies two mat2's * * @param {mat2} out the receiving matrix * @param {mat2} a the first operand * @param {mat2} b the second operand * @returns {mat2} out */ function multiply(out, a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; out[0] = a0 * b0 + a2 * b1; out[1] = a1 * b0 + a3 * b1; out[2] = a0 * b2 + a2 * b3; out[3] = a1 * b2 + a3 * b3; return out; } /** * Rotates a mat2 by the given angle * * @param {mat2} out the receiving matrix * @param {mat2} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat2} out */ function rotate(out, a, rad) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var s = Math.sin(rad); var c = Math.cos(rad); out[0] = a0 * c + a2 * s; out[1] = a1 * c + a3 * s; out[2] = a0 * -s + a2 * c; out[3] = a1 * -s + a3 * c; return out; } /** * Scales the mat2 by the dimensions in the given vec2 * * @param {mat2} out the receiving matrix * @param {mat2} a the matrix to rotate * @param {vec2} v the vec2 to scale the matrix by * @returns {mat2} out **/ function scale(out, a, v) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var v0 = v[0], v1 = v[1]; out[0] = a0 * v0; out[1] = a1 * v0; out[2] = a2 * v1; out[3] = a3 * v1; return out; } /** * Creates a matrix from a given angle * This is equivalent to (but much faster than): * * mat2.identity(dest); * mat2.rotate(dest, dest, rad); * * @param {mat2} out mat2 receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat2} out */ function fromRotation(out, rad) { var s = Math.sin(rad); var c = Math.cos(rad); out[0] = c; out[1] = s; out[2] = -s; out[3] = c; return out; } /** * Creates a matrix from a vector scaling * This is equivalent to (but much faster than): * * mat2.identity(dest); * mat2.scale(dest, dest, vec); * * @param {mat2} out mat2 receiving operation result * @param {vec2} v Scaling vector * @returns {mat2} out */ function fromScaling(out, v) { out[0] = v[0]; out[1] = 0; out[2] = 0; out[3] = v[1]; return out; } /** * Returns a string representation of a mat2 * * @param {mat2} a matrix to represent as a string * @returns {String} string representation of the matrix */ function str(a) { return 'mat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; } /** * Returns Frobenius norm of a mat2 * * @param {mat2} a the matrix to calculate Frobenius norm of * @returns {Number} Frobenius norm */ function frob(a) { return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2)); } /** * Returns L, D and U matrices (Lower triangular, Diagonal and Upper triangular) by factorizing the input matrix * @param {mat2} L the lower triangular matrix * @param {mat2} D the diagonal matrix * @param {mat2} U the upper triangular matrix * @param {mat2} a the input matrix to factorize */ function LDU(L, D, U, a) { L[2] = a[2] / a[0]; U[0] = a[0]; U[1] = a[1]; U[3] = a[3] - L[2] * U[1]; return [L, D, U]; } /** * Adds two mat2's * * @param {mat2} out the receiving matrix * @param {mat2} a the first operand * @param {mat2} b the second operand * @returns {mat2} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; return out; } /** * Subtracts matrix b from matrix a * * @param {mat2} out the receiving matrix * @param {mat2} a the first operand * @param {mat2} b the second operand * @returns {mat2} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; return out; } /** * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) * * @param {mat2} a The first matrix. * @param {mat2} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3]; } /** * Returns whether or not the matrices have approximately the same elements in the same position. * * @param {mat2} a The first matrix. * @param {mat2} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)); } /** * Multiply each element of the matrix by a scalar. * * @param {mat2} out the receiving matrix * @param {mat2} a the matrix to scale * @param {Number} b amount to scale the matrix's elements by * @returns {mat2} out */ function multiplyScalar(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; return out; } /** * Adds two mat2's after multiplying each element of the second operand by a scalar value. * * @param {mat2} out the receiving vector * @param {mat2} a the first operand * @param {mat2} b the second operand * @param {Number} scale the amount to scale b's elements by before adding * @returns {mat2} out */ function multiplyScalarAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; out[3] = a[3] + b[3] * scale; return out; } /** * Alias for {@link mat2.multiply} * @function */ var mul = multiply; /** * Alias for {@link mat2.subtract} * @function */ var sub = subtract; /***/ }), /* 9 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["determinant"] = determinant; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["translate"] = translate; /* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; /* harmony export (immutable) */ __webpack_exports__["fromScaling"] = fromScaling; /* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["frob"] = frob; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiplyScalar"] = multiplyScalar; /* harmony export (immutable) */ __webpack_exports__["multiplyScalarAndAdd"] = multiplyScalarAndAdd; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 2x3 Matrix * @module mat2d * * @description * A mat2d contains six elements defined as: *
 * [a, c, tx,
 *  b, d, ty]
 * 
* This is a short form for the 3x3 matrix: *
 * [a, c, tx,
 *  b, d, ty,
 *  0, 0, 1]
 * 
* The last row is ignored so the array is shorter and operations are faster. */ /** * Creates a new identity mat2d * * @returns {mat2d} a new 2x3 matrix */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](6); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[1] = 0; out[2] = 0; out[4] = 0; out[5] = 0; } out[0] = 1; out[3] = 1; return out; } /** * Creates a new mat2d initialized with values from an existing matrix * * @param {mat2d} a matrix to clone * @returns {mat2d} a new 2x3 matrix */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](6); out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; return out; } /** * Copy the values from one mat2d to another * * @param {mat2d} out the receiving matrix * @param {mat2d} a the source matrix * @returns {mat2d} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; return out; } /** * Set a mat2d to the identity matrix * * @param {mat2d} out the receiving matrix * @returns {mat2d} out */ function identity(out) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 1; out[4] = 0; out[5] = 0; return out; } /** * Create a new mat2d with the given values * * @param {Number} a Component A (index 0) * @param {Number} b Component B (index 1) * @param {Number} c Component C (index 2) * @param {Number} d Component D (index 3) * @param {Number} tx Component TX (index 4) * @param {Number} ty Component TY (index 5) * @returns {mat2d} A new mat2d */ function fromValues(a, b, c, d, tx, ty) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](6); out[0] = a; out[1] = b; out[2] = c; out[3] = d; out[4] = tx; out[5] = ty; return out; } /** * Set the components of a mat2d to the given values * * @param {mat2d} out the receiving matrix * @param {Number} a Component A (index 0) * @param {Number} b Component B (index 1) * @param {Number} c Component C (index 2) * @param {Number} d Component D (index 3) * @param {Number} tx Component TX (index 4) * @param {Number} ty Component TY (index 5) * @returns {mat2d} out */ function set(out, a, b, c, d, tx, ty) { out[0] = a; out[1] = b; out[2] = c; out[3] = d; out[4] = tx; out[5] = ty; return out; } /** * Inverts a mat2d * * @param {mat2d} out the receiving matrix * @param {mat2d} a the source matrix * @returns {mat2d} out */ function invert(out, a) { var aa = a[0], ab = a[1], ac = a[2], ad = a[3]; var atx = a[4], aty = a[5]; var det = aa * ad - ab * ac; if (!det) { return null; } det = 1.0 / det; out[0] = ad * det; out[1] = -ab * det; out[2] = -ac * det; out[3] = aa * det; out[4] = (ac * aty - ad * atx) * det; out[5] = (ab * atx - aa * aty) * det; return out; } /** * Calculates the determinant of a mat2d * * @param {mat2d} a the source matrix * @returns {Number} determinant of a */ function determinant(a) { return a[0] * a[3] - a[1] * a[2]; } /** * Multiplies two mat2d's * * @param {mat2d} out the receiving matrix * @param {mat2d} a the first operand * @param {mat2d} b the second operand * @returns {mat2d} out */ function multiply(out, a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; out[0] = a0 * b0 + a2 * b1; out[1] = a1 * b0 + a3 * b1; out[2] = a0 * b2 + a2 * b3; out[3] = a1 * b2 + a3 * b3; out[4] = a0 * b4 + a2 * b5 + a4; out[5] = a1 * b4 + a3 * b5 + a5; return out; } /** * Rotates a mat2d by the given angle * * @param {mat2d} out the receiving matrix * @param {mat2d} a the matrix to rotate * @param {Number} rad the angle to rotate the matrix by * @returns {mat2d} out */ function rotate(out, a, rad) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; var s = Math.sin(rad); var c = Math.cos(rad); out[0] = a0 * c + a2 * s; out[1] = a1 * c + a3 * s; out[2] = a0 * -s + a2 * c; out[3] = a1 * -s + a3 * c; out[4] = a4; out[5] = a5; return out; } /** * Scales the mat2d by the dimensions in the given vec2 * * @param {mat2d} out the receiving matrix * @param {mat2d} a the matrix to translate * @param {vec2} v the vec2 to scale the matrix by * @returns {mat2d} out **/ function scale(out, a, v) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; var v0 = v[0], v1 = v[1]; out[0] = a0 * v0; out[1] = a1 * v0; out[2] = a2 * v1; out[3] = a3 * v1; out[4] = a4; out[5] = a5; return out; } /** * Translates the mat2d by the dimensions in the given vec2 * * @param {mat2d} out the receiving matrix * @param {mat2d} a the matrix to translate * @param {vec2} v the vec2 to translate the matrix by * @returns {mat2d} out **/ function translate(out, a, v) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; var v0 = v[0], v1 = v[1]; out[0] = a0; out[1] = a1; out[2] = a2; out[3] = a3; out[4] = a0 * v0 + a2 * v1 + a4; out[5] = a1 * v0 + a3 * v1 + a5; return out; } /** * Creates a matrix from a given angle * This is equivalent to (but much faster than): * * mat2d.identity(dest); * mat2d.rotate(dest, dest, rad); * * @param {mat2d} out mat2d receiving operation result * @param {Number} rad the angle to rotate the matrix by * @returns {mat2d} out */ function fromRotation(out, rad) { var s = Math.sin(rad), c = Math.cos(rad); out[0] = c; out[1] = s; out[2] = -s; out[3] = c; out[4] = 0; out[5] = 0; return out; } /** * Creates a matrix from a vector scaling * This is equivalent to (but much faster than): * * mat2d.identity(dest); * mat2d.scale(dest, dest, vec); * * @param {mat2d} out mat2d receiving operation result * @param {vec2} v Scaling vector * @returns {mat2d} out */ function fromScaling(out, v) { out[0] = v[0]; out[1] = 0; out[2] = 0; out[3] = v[1]; out[4] = 0; out[5] = 0; return out; } /** * Creates a matrix from a vector translation * This is equivalent to (but much faster than): * * mat2d.identity(dest); * mat2d.translate(dest, dest, vec); * * @param {mat2d} out mat2d receiving operation result * @param {vec2} v Translation vector * @returns {mat2d} out */ function fromTranslation(out, v) { out[0] = 1; out[1] = 0; out[2] = 0; out[3] = 1; out[4] = v[0]; out[5] = v[1]; return out; } /** * Returns a string representation of a mat2d * * @param {mat2d} a matrix to represent as a string * @returns {String} string representation of the matrix */ function str(a) { return 'mat2d(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ')'; } /** * Returns Frobenius norm of a mat2d * * @param {mat2d} a the matrix to calculate Frobenius norm of * @returns {Number} Frobenius norm */ function frob(a) { return Math.sqrt(Math.pow(a[0], 2) + Math.pow(a[1], 2) + Math.pow(a[2], 2) + Math.pow(a[3], 2) + Math.pow(a[4], 2) + Math.pow(a[5], 2) + 1); } /** * Adds two mat2d's * * @param {mat2d} out the receiving matrix * @param {mat2d} a the first operand * @param {mat2d} b the second operand * @returns {mat2d} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; return out; } /** * Subtracts matrix b from matrix a * * @param {mat2d} out the receiving matrix * @param {mat2d} a the first operand * @param {mat2d} b the second operand * @returns {mat2d} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; out[2] = a[2] - b[2]; out[3] = a[3] - b[3]; out[4] = a[4] - b[4]; out[5] = a[5] - b[5]; return out; } /** * Multiply each element of the matrix by a scalar. * * @param {mat2d} out the receiving matrix * @param {mat2d} a the matrix to scale * @param {Number} b amount to scale the matrix's elements by * @returns {mat2d} out */ function multiplyScalar(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; out[4] = a[4] * b; out[5] = a[5] * b; return out; } /** * Adds two mat2d's after multiplying each element of the second operand by a scalar value. * * @param {mat2d} out the receiving vector * @param {mat2d} a the first operand * @param {mat2d} b the second operand * @param {Number} scale the amount to scale b's elements by before adding * @returns {mat2d} out */ function multiplyScalarAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; out[2] = a[2] + b[2] * scale; out[3] = a[3] + b[3] * scale; out[4] = a[4] + b[4] * scale; out[5] = a[5] + b[5] * scale; return out; } /** * Returns whether or not the matrices have exactly the same elements in the same position (when compared with ===) * * @param {mat2d} a The first matrix. * @param {mat2d} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; } /** * Returns whether or not the matrices have approximately the same elements in the same position. * * @param {mat2d} a The first matrix. * @param {mat2d} b The second matrix. * @returns {Boolean} True if the matrices are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a5), Math.abs(b5)); } /** * Alias for {@link mat2d.multiply} * @function */ var mul = multiply; /** * Alias for {@link mat2d.subtract} * @function */ var sub = subtract; /***/ }), /* 10 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["fromRotationTranslationValues"] = fromRotationTranslationValues; /* harmony export (immutable) */ __webpack_exports__["fromRotationTranslation"] = fromRotationTranslation; /* harmony export (immutable) */ __webpack_exports__["fromTranslation"] = fromTranslation; /* harmony export (immutable) */ __webpack_exports__["fromRotation"] = fromRotation; /* harmony export (immutable) */ __webpack_exports__["fromMat4"] = fromMat4; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["identity"] = identity; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "getReal", function() { return getReal; }); /* harmony export (immutable) */ __webpack_exports__["getDual"] = getDual; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "setReal", function() { return setReal; }); /* harmony export (immutable) */ __webpack_exports__["setDual"] = setDual; /* harmony export (immutable) */ __webpack_exports__["getTranslation"] = getTranslation; /* harmony export (immutable) */ __webpack_exports__["translate"] = translate; /* harmony export (immutable) */ __webpack_exports__["rotateX"] = rotateX; /* harmony export (immutable) */ __webpack_exports__["rotateY"] = rotateY; /* harmony export (immutable) */ __webpack_exports__["rotateZ"] = rotateZ; /* harmony export (immutable) */ __webpack_exports__["rotateByQuatAppend"] = rotateByQuatAppend; /* harmony export (immutable) */ __webpack_exports__["rotateByQuatPrepend"] = rotateByQuatPrepend; /* harmony export (immutable) */ __webpack_exports__["rotateAroundAxis"] = rotateAroundAxis; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dot", function() { return dot; }); /* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; /* harmony export (immutable) */ __webpack_exports__["invert"] = invert; /* harmony export (immutable) */ __webpack_exports__["conjugate"] = conjugate; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "length", function() { return length; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "squaredLength", function() { return squaredLength; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__quat_js__ = __webpack_require__(4); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__mat4_js__ = __webpack_require__(3); /** * Dual Quaternion
* Format: [real, dual]
* Quaternion format: XYZW
* Make sure to have normalized dual quaternions, otherwise the functions may not work as intended.
* @module quat2 */ /** * Creates a new identity dual quat * * @returns {quat2} a new dual quaternion [real -> rotation, dual -> translation] */ function create() { var dq = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](8); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { dq[0] = 0; dq[1] = 0; dq[2] = 0; dq[4] = 0; dq[5] = 0; dq[6] = 0; dq[7] = 0; } dq[3] = 1; return dq; } /** * Creates a new quat initialized with values from an existing quaternion * * @param {quat2} a dual quaternion to clone * @returns {quat2} new dual quaternion * @function */ function clone(a) { var dq = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](8); dq[0] = a[0]; dq[1] = a[1]; dq[2] = a[2]; dq[3] = a[3]; dq[4] = a[4]; dq[5] = a[5]; dq[6] = a[6]; dq[7] = a[7]; return dq; } /** * Creates a new dual quat initialized with the given values * * @param {Number} x1 X component * @param {Number} y1 Y component * @param {Number} z1 Z component * @param {Number} w1 W component * @param {Number} x2 X component * @param {Number} y2 Y component * @param {Number} z2 Z component * @param {Number} w2 W component * @returns {quat2} new dual quaternion * @function */ function fromValues(x1, y1, z1, w1, x2, y2, z2, w2) { var dq = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](8); dq[0] = x1; dq[1] = y1; dq[2] = z1; dq[3] = w1; dq[4] = x2; dq[5] = y2; dq[6] = z2; dq[7] = w2; return dq; } /** * Creates a new dual quat from the given values (quat and translation) * * @param {Number} x1 X component * @param {Number} y1 Y component * @param {Number} z1 Z component * @param {Number} w1 W component * @param {Number} x2 X component (translation) * @param {Number} y2 Y component (translation) * @param {Number} z2 Z component (translation) * @returns {quat2} new dual quaternion * @function */ function fromRotationTranslationValues(x1, y1, z1, w1, x2, y2, z2) { var dq = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](8); dq[0] = x1; dq[1] = y1; dq[2] = z1; dq[3] = w1; var ax = x2 * 0.5, ay = y2 * 0.5, az = z2 * 0.5; dq[4] = ax * w1 + ay * z1 - az * y1; dq[5] = ay * w1 + az * x1 - ax * z1; dq[6] = az * w1 + ax * y1 - ay * x1; dq[7] = -ax * x1 - ay * y1 - az * z1; return dq; } /** * Creates a dual quat from a quaternion and a translation * * @param {quat2} dual quaternion receiving operation result * @param {quat} q quaternion * @param {vec3} t tranlation vector * @returns {quat2} dual quaternion receiving operation result * @function */ function fromRotationTranslation(out, q, t) { var ax = t[0] * 0.5, ay = t[1] * 0.5, az = t[2] * 0.5, bx = q[0], by = q[1], bz = q[2], bw = q[3]; out[0] = bx; out[1] = by; out[2] = bz; out[3] = bw; out[4] = ax * bw + ay * bz - az * by; out[5] = ay * bw + az * bx - ax * bz; out[6] = az * bw + ax * by - ay * bx; out[7] = -ax * bx - ay * by - az * bz; return out; } /** * Creates a dual quat from a translation * * @param {quat2} dual quaternion receiving operation result * @param {vec3} t translation vector * @returns {quat2} dual quaternion receiving operation result * @function */ function fromTranslation(out, t) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1; out[4] = t[0] * 0.5; out[5] = t[1] * 0.5; out[6] = t[2] * 0.5; out[7] = 0; return out; } /** * Creates a dual quat from a quaternion * * @param {quat2} dual quaternion receiving operation result * @param {quat} q the quaternion * @returns {quat2} dual quaternion receiving operation result * @function */ function fromRotation(out, q) { out[0] = q[0]; out[1] = q[1]; out[2] = q[2]; out[3] = q[3]; out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 0; return out; } /** * Creates a new dual quat from a matrix (4x4) * * @param {quat2} out the dual quaternion * @param {mat4} a the matrix * @returns {quat2} dual quat receiving operation result * @function */ function fromMat4(out, a) { //TODO Optimize this var outer = __WEBPACK_IMPORTED_MODULE_1__quat_js__["create"](); __WEBPACK_IMPORTED_MODULE_2__mat4_js__["getRotation"](outer, a); var t = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](3); __WEBPACK_IMPORTED_MODULE_2__mat4_js__["getTranslation"](t, a); fromRotationTranslation(out, outer, t); return out; } /** * Copy the values from one dual quat to another * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the source dual quaternion * @returns {quat2} out * @function */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; out[2] = a[2]; out[3] = a[3]; out[4] = a[4]; out[5] = a[5]; out[6] = a[6]; out[7] = a[7]; return out; } /** * Set a dual quat to the identity dual quaternion * * @param {quat2} out the receiving quaternion * @returns {quat2} out */ function identity(out) { out[0] = 0; out[1] = 0; out[2] = 0; out[3] = 1; out[4] = 0; out[5] = 0; out[6] = 0; out[7] = 0; return out; } /** * Set the components of a dual quat to the given values * * @param {quat2} out the receiving quaternion * @param {Number} x1 X component * @param {Number} y1 Y component * @param {Number} z1 Z component * @param {Number} w1 W component * @param {Number} x2 X component * @param {Number} y2 Y component * @param {Number} z2 Z component * @param {Number} w2 W component * @returns {quat2} out * @function */ function set(out, x1, y1, z1, w1, x2, y2, z2, w2) { out[0] = x1; out[1] = y1; out[2] = z1; out[3] = w1; out[4] = x2; out[5] = y2; out[6] = z2; out[7] = w2; return out; } /** * Gets the real part of a dual quat * @param {quat} out real part * @param {quat2} a Dual Quaternion * @return {quat} real part */ var getReal = __WEBPACK_IMPORTED_MODULE_1__quat_js__["copy"]; /** * Gets the dual part of a dual quat * @param {quat} out dual part * @param {quat2} a Dual Quaternion * @return {quat} dual part */ function getDual(out, a) { out[0] = a[4]; out[1] = a[5]; out[2] = a[6]; out[3] = a[7]; return out; } /** * Set the real component of a dual quat to the given quaternion * * @param {quat2} out the receiving quaternion * @param {quat} q a quaternion representing the real part * @returns {quat2} out * @function */ var setReal = __WEBPACK_IMPORTED_MODULE_1__quat_js__["copy"]; /** * Set the dual component of a dual quat to the given quaternion * * @param {quat2} out the receiving quaternion * @param {quat} q a quaternion representing the dual part * @returns {quat2} out * @function */ function setDual(out, q) { out[4] = q[0]; out[5] = q[1]; out[6] = q[2]; out[7] = q[3]; return out; } /** * Gets the translation of a normalized dual quat * @param {vec3} out translation * @param {quat2} a Dual Quaternion to be decomposed * @return {vec3} translation */ function getTranslation(out, a) { var ax = a[4], ay = a[5], az = a[6], aw = a[7], bx = -a[0], by = -a[1], bz = -a[2], bw = a[3]; out[0] = (ax * bw + aw * bx + ay * bz - az * by) * 2; out[1] = (ay * bw + aw * by + az * bx - ax * bz) * 2; out[2] = (az * bw + aw * bz + ax * by - ay * bx) * 2; return out; } /** * Translates a dual quat by the given vector * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to translate * @param {vec3} v vector to translate by * @returns {quat2} out */ function translate(out, a, v) { var ax1 = a[0], ay1 = a[1], az1 = a[2], aw1 = a[3], bx1 = v[0] * 0.5, by1 = v[1] * 0.5, bz1 = v[2] * 0.5, ax2 = a[4], ay2 = a[5], az2 = a[6], aw2 = a[7]; out[0] = ax1; out[1] = ay1; out[2] = az1; out[3] = aw1; out[4] = aw1 * bx1 + ay1 * bz1 - az1 * by1 + ax2; out[5] = aw1 * by1 + az1 * bx1 - ax1 * bz1 + ay2; out[6] = aw1 * bz1 + ax1 * by1 - ay1 * bx1 + az2; out[7] = -ax1 * bx1 - ay1 * by1 - az1 * bz1 + aw2; return out; } /** * Rotates a dual quat around the X axis * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to rotate * @param {number} rad how far should the rotation be * @returns {quat2} out */ function rotateX(out, a, rad) { var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7], ax1 = ax * bw + aw * bx + ay * bz - az * by, ay1 = ay * bw + aw * by + az * bx - ax * bz, az1 = az * bw + aw * bz + ax * by - ay * bx, aw1 = aw * bw - ax * bx - ay * by - az * bz; __WEBPACK_IMPORTED_MODULE_1__quat_js__["rotateX"](out, a, rad); bx = out[0]; by = out[1]; bz = out[2]; bw = out[3]; out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; return out; } /** * Rotates a dual quat around the Y axis * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to rotate * @param {number} rad how far should the rotation be * @returns {quat2} out */ function rotateY(out, a, rad) { var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7], ax1 = ax * bw + aw * bx + ay * bz - az * by, ay1 = ay * bw + aw * by + az * bx - ax * bz, az1 = az * bw + aw * bz + ax * by - ay * bx, aw1 = aw * bw - ax * bx - ay * by - az * bz; __WEBPACK_IMPORTED_MODULE_1__quat_js__["rotateY"](out, a, rad); bx = out[0]; by = out[1]; bz = out[2]; bw = out[3]; out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; return out; } /** * Rotates a dual quat around the Z axis * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to rotate * @param {number} rad how far should the rotation be * @returns {quat2} out */ function rotateZ(out, a, rad) { var bx = -a[0], by = -a[1], bz = -a[2], bw = a[3], ax = a[4], ay = a[5], az = a[6], aw = a[7], ax1 = ax * bw + aw * bx + ay * bz - az * by, ay1 = ay * bw + aw * by + az * bx - ax * bz, az1 = az * bw + aw * bz + ax * by - ay * bx, aw1 = aw * bw - ax * bx - ay * by - az * bz; __WEBPACK_IMPORTED_MODULE_1__quat_js__["rotateZ"](out, a, rad); bx = out[0]; by = out[1]; bz = out[2]; bw = out[3]; out[4] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; out[5] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; out[6] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; out[7] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; return out; } /** * Rotates a dual quat by a given quaternion (a * q) * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to rotate * @param {quat} q quaternion to rotate by * @returns {quat2} out */ function rotateByQuatAppend(out, a, q) { var qx = q[0], qy = q[1], qz = q[2], qw = q[3], ax = a[0], ay = a[1], az = a[2], aw = a[3]; out[0] = ax * qw + aw * qx + ay * qz - az * qy; out[1] = ay * qw + aw * qy + az * qx - ax * qz; out[2] = az * qw + aw * qz + ax * qy - ay * qx; out[3] = aw * qw - ax * qx - ay * qy - az * qz; ax = a[4]; ay = a[5]; az = a[6]; aw = a[7]; out[4] = ax * qw + aw * qx + ay * qz - az * qy; out[5] = ay * qw + aw * qy + az * qx - ax * qz; out[6] = az * qw + aw * qz + ax * qy - ay * qx; out[7] = aw * qw - ax * qx - ay * qy - az * qz; return out; } /** * Rotates a dual quat by a given quaternion (q * a) * * @param {quat2} out the receiving dual quaternion * @param {quat} q quaternion to rotate by * @param {quat2} a the dual quaternion to rotate * @returns {quat2} out */ function rotateByQuatPrepend(out, q, a) { var qx = q[0], qy = q[1], qz = q[2], qw = q[3], bx = a[0], by = a[1], bz = a[2], bw = a[3]; out[0] = qx * bw + qw * bx + qy * bz - qz * by; out[1] = qy * bw + qw * by + qz * bx - qx * bz; out[2] = qz * bw + qw * bz + qx * by - qy * bx; out[3] = qw * bw - qx * bx - qy * by - qz * bz; bx = a[4]; by = a[5]; bz = a[6]; bw = a[7]; out[4] = qx * bw + qw * bx + qy * bz - qz * by; out[5] = qy * bw + qw * by + qz * bx - qx * bz; out[6] = qz * bw + qw * bz + qx * by - qy * bx; out[7] = qw * bw - qx * bx - qy * by - qz * bz; return out; } /** * Rotates a dual quat around a given axis. Does the normalisation automatically * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the dual quaternion to rotate * @param {vec3} axis the axis to rotate around * @param {Number} rad how far the rotation should be * @returns {quat2} out */ function rotateAroundAxis(out, a, axis, rad) { //Special case for rad = 0 if (Math.abs(rad) < __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"]) { return copy(out, a); } var axisLength = Math.sqrt(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]); rad = rad * 0.5; var s = Math.sin(rad); var bx = s * axis[0] / axisLength; var by = s * axis[1] / axisLength; var bz = s * axis[2] / axisLength; var bw = Math.cos(rad); var ax1 = a[0], ay1 = a[1], az1 = a[2], aw1 = a[3]; out[0] = ax1 * bw + aw1 * bx + ay1 * bz - az1 * by; out[1] = ay1 * bw + aw1 * by + az1 * bx - ax1 * bz; out[2] = az1 * bw + aw1 * bz + ax1 * by - ay1 * bx; out[3] = aw1 * bw - ax1 * bx - ay1 * by - az1 * bz; var ax = a[4], ay = a[5], az = a[6], aw = a[7]; out[4] = ax * bw + aw * bx + ay * bz - az * by; out[5] = ay * bw + aw * by + az * bx - ax * bz; out[6] = az * bw + aw * bz + ax * by - ay * bx; out[7] = aw * bw - ax * bx - ay * by - az * bz; return out; } /** * Adds two dual quat's * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the first operand * @param {quat2} b the second operand * @returns {quat2} out * @function */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; out[2] = a[2] + b[2]; out[3] = a[3] + b[3]; out[4] = a[4] + b[4]; out[5] = a[5] + b[5]; out[6] = a[6] + b[6]; out[7] = a[7] + b[7]; return out; } /** * Multiplies two dual quat's * * @param {quat2} out the receiving dual quaternion * @param {quat2} a the first operand * @param {quat2} b the second operand * @returns {quat2} out */ function multiply(out, a, b) { var ax0 = a[0], ay0 = a[1], az0 = a[2], aw0 = a[3], bx1 = b[4], by1 = b[5], bz1 = b[6], bw1 = b[7], ax1 = a[4], ay1 = a[5], az1 = a[6], aw1 = a[7], bx0 = b[0], by0 = b[1], bz0 = b[2], bw0 = b[3]; out[0] = ax0 * bw0 + aw0 * bx0 + ay0 * bz0 - az0 * by0; out[1] = ay0 * bw0 + aw0 * by0 + az0 * bx0 - ax0 * bz0; out[2] = az0 * bw0 + aw0 * bz0 + ax0 * by0 - ay0 * bx0; out[3] = aw0 * bw0 - ax0 * bx0 - ay0 * by0 - az0 * bz0; out[4] = ax0 * bw1 + aw0 * bx1 + ay0 * bz1 - az0 * by1 + ax1 * bw0 + aw1 * bx0 + ay1 * bz0 - az1 * by0; out[5] = ay0 * bw1 + aw0 * by1 + az0 * bx1 - ax0 * bz1 + ay1 * bw0 + aw1 * by0 + az1 * bx0 - ax1 * bz0; out[6] = az0 * bw1 + aw0 * bz1 + ax0 * by1 - ay0 * bx1 + az1 * bw0 + aw1 * bz0 + ax1 * by0 - ay1 * bx0; out[7] = aw0 * bw1 - ax0 * bx1 - ay0 * by1 - az0 * bz1 + aw1 * bw0 - ax1 * bx0 - ay1 * by0 - az1 * bz0; return out; } /** * Alias for {@link quat2.multiply} * @function */ var mul = multiply; /** * Scales a dual quat by a scalar number * * @param {quat2} out the receiving dual quat * @param {quat2} a the dual quat to scale * @param {Number} b amount to scale the dual quat by * @returns {quat2} out * @function */ function scale(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; out[2] = a[2] * b; out[3] = a[3] * b; out[4] = a[4] * b; out[5] = a[5] * b; out[6] = a[6] * b; out[7] = a[7] * b; return out; } /** * Calculates the dot product of two dual quat's (The dot product of the real parts) * * @param {quat2} a the first operand * @param {quat2} b the second operand * @returns {Number} dot product of a and b * @function */ var dot = __WEBPACK_IMPORTED_MODULE_1__quat_js__["dot"]; /** * Performs a linear interpolation between two dual quats's * NOTE: The resulting dual quaternions won't always be normalized (The error is most noticeable when t = 0.5) * * @param {quat2} out the receiving dual quat * @param {quat2} a the first operand * @param {quat2} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {quat2} out */ function lerp(out, a, b, t) { var mt = 1 - t; if (dot(a, b) < 0) t = -t; out[0] = a[0] * mt + b[0] * t; out[1] = a[1] * mt + b[1] * t; out[2] = a[2] * mt + b[2] * t; out[3] = a[3] * mt + b[3] * t; out[4] = a[4] * mt + b[4] * t; out[5] = a[5] * mt + b[5] * t; out[6] = a[6] * mt + b[6] * t; out[7] = a[7] * mt + b[7] * t; return out; } /** * Calculates the inverse of a dual quat. If they are normalized, conjugate is cheaper * * @param {quat2} out the receiving dual quaternion * @param {quat2} a dual quat to calculate inverse of * @returns {quat2} out */ function invert(out, a) { var sqlen = squaredLength(a); out[0] = -a[0] / sqlen; out[1] = -a[1] / sqlen; out[2] = -a[2] / sqlen; out[3] = a[3] / sqlen; out[4] = -a[4] / sqlen; out[5] = -a[5] / sqlen; out[6] = -a[6] / sqlen; out[7] = a[7] / sqlen; return out; } /** * Calculates the conjugate of a dual quat * If the dual quaternion is normalized, this function is faster than quat2.inverse and produces the same result. * * @param {quat2} out the receiving quaternion * @param {quat2} a quat to calculate conjugate of * @returns {quat2} out */ function conjugate(out, a) { out[0] = -a[0]; out[1] = -a[1]; out[2] = -a[2]; out[3] = a[3]; out[4] = -a[4]; out[5] = -a[5]; out[6] = -a[6]; out[7] = a[7]; return out; } /** * Calculates the length of a dual quat * * @param {quat2} a dual quat to calculate length of * @returns {Number} length of a * @function */ var length = __WEBPACK_IMPORTED_MODULE_1__quat_js__["length"]; /** * Alias for {@link quat2.length} * @function */ var len = length; /** * Calculates the squared length of a dual quat * * @param {quat2} a dual quat to calculate squared length of * @returns {Number} squared length of a * @function */ var squaredLength = __WEBPACK_IMPORTED_MODULE_1__quat_js__["squaredLength"]; /** * Alias for {@link quat2.squaredLength} * @function */ var sqrLen = squaredLength; /** * Normalize a dual quat * * @param {quat2} out the receiving dual quaternion * @param {quat2} a dual quaternion to normalize * @returns {quat2} out * @function */ function normalize(out, a) { var magnitude = squaredLength(a); if (magnitude > 0) { magnitude = Math.sqrt(magnitude); var a0 = a[0] / magnitude; var a1 = a[1] / magnitude; var a2 = a[2] / magnitude; var a3 = a[3] / magnitude; var b0 = a[4]; var b1 = a[5]; var b2 = a[6]; var b3 = a[7]; var a_dot_b = a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3; out[0] = a0; out[1] = a1; out[2] = a2; out[3] = a3; out[4] = (b0 - a0 * a_dot_b) / magnitude; out[5] = (b1 - a1 * a_dot_b) / magnitude; out[6] = (b2 - a2 * a_dot_b) / magnitude; out[7] = (b3 - a3 * a_dot_b) / magnitude; } return out; } /** * Returns a string representation of a dual quatenion * * @param {quat2} a dual quaternion to represent as a string * @returns {String} string representation of the dual quat */ function str(a) { return 'quat2(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' + a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ')'; } /** * Returns whether or not the dual quaternions have exactly the same elements in the same position (when compared with ===) * * @param {quat2} a the first dual quaternion. * @param {quat2} b the second dual quaternion. * @returns {Boolean} true if the dual quaternions are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5] && a[6] === b[6] && a[7] === b[7]; } /** * Returns whether or not the dual quaternions have approximately the same elements in the same position. * * @param {quat2} a the first dual quat. * @param {quat2} b the second dual quat. * @returns {Boolean} true if the dual quats are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], a6 = a[6], a7 = a[7]; var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5], b6 = b[6], b7 = b[7]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a3), Math.abs(b3)) && Math.abs(a4 - b4) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a4), Math.abs(b4)) && Math.abs(a5 - b5) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a5), Math.abs(b5)) && Math.abs(a6 - b6) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a6), Math.abs(b6)) && Math.abs(a7 - b7) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a7), Math.abs(b7)); } /***/ }), /* 11 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (immutable) */ __webpack_exports__["create"] = create; /* harmony export (immutable) */ __webpack_exports__["clone"] = clone; /* harmony export (immutable) */ __webpack_exports__["fromValues"] = fromValues; /* harmony export (immutable) */ __webpack_exports__["copy"] = copy; /* harmony export (immutable) */ __webpack_exports__["set"] = set; /* harmony export (immutable) */ __webpack_exports__["add"] = add; /* harmony export (immutable) */ __webpack_exports__["subtract"] = subtract; /* harmony export (immutable) */ __webpack_exports__["multiply"] = multiply; /* harmony export (immutable) */ __webpack_exports__["divide"] = divide; /* harmony export (immutable) */ __webpack_exports__["ceil"] = ceil; /* harmony export (immutable) */ __webpack_exports__["floor"] = floor; /* harmony export (immutable) */ __webpack_exports__["min"] = min; /* harmony export (immutable) */ __webpack_exports__["max"] = max; /* harmony export (immutable) */ __webpack_exports__["round"] = round; /* harmony export (immutable) */ __webpack_exports__["scale"] = scale; /* harmony export (immutable) */ __webpack_exports__["scaleAndAdd"] = scaleAndAdd; /* harmony export (immutable) */ __webpack_exports__["distance"] = distance; /* harmony export (immutable) */ __webpack_exports__["squaredDistance"] = squaredDistance; /* harmony export (immutable) */ __webpack_exports__["length"] = length; /* harmony export (immutable) */ __webpack_exports__["squaredLength"] = squaredLength; /* harmony export (immutable) */ __webpack_exports__["negate"] = negate; /* harmony export (immutable) */ __webpack_exports__["inverse"] = inverse; /* harmony export (immutable) */ __webpack_exports__["normalize"] = normalize; /* harmony export (immutable) */ __webpack_exports__["dot"] = dot; /* harmony export (immutable) */ __webpack_exports__["cross"] = cross; /* harmony export (immutable) */ __webpack_exports__["lerp"] = lerp; /* harmony export (immutable) */ __webpack_exports__["random"] = random; /* harmony export (immutable) */ __webpack_exports__["transformMat2"] = transformMat2; /* harmony export (immutable) */ __webpack_exports__["transformMat2d"] = transformMat2d; /* harmony export (immutable) */ __webpack_exports__["transformMat3"] = transformMat3; /* harmony export (immutable) */ __webpack_exports__["transformMat4"] = transformMat4; /* harmony export (immutable) */ __webpack_exports__["rotate"] = rotate; /* harmony export (immutable) */ __webpack_exports__["angle"] = angle; /* harmony export (immutable) */ __webpack_exports__["str"] = str; /* harmony export (immutable) */ __webpack_exports__["exactEquals"] = exactEquals; /* harmony export (immutable) */ __webpack_exports__["equals"] = equals; /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "len", function() { return len; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sub", function() { return sub; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "mul", function() { return mul; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "div", function() { return div; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "dist", function() { return dist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrDist", function() { return sqrDist; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "sqrLen", function() { return sqrLen; }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "forEach", function() { return forEach; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__common_js__ = __webpack_require__(0); /** * 2 Dimensional Vector * @module vec2 */ /** * Creates a new, empty vec2 * * @returns {vec2} a new 2D vector */ function create() { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](2); if (__WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"] != Float32Array) { out[0] = 0; out[1] = 0; } return out; } /** * Creates a new vec2 initialized with values from an existing vector * * @param {vec2} a vector to clone * @returns {vec2} a new 2D vector */ function clone(a) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](2); out[0] = a[0]; out[1] = a[1]; return out; } /** * Creates a new vec2 initialized with the given values * * @param {Number} x X component * @param {Number} y Y component * @returns {vec2} a new 2D vector */ function fromValues(x, y) { var out = new __WEBPACK_IMPORTED_MODULE_0__common_js__["ARRAY_TYPE"](2); out[0] = x; out[1] = y; return out; } /** * Copy the values from one vec2 to another * * @param {vec2} out the receiving vector * @param {vec2} a the source vector * @returns {vec2} out */ function copy(out, a) { out[0] = a[0]; out[1] = a[1]; return out; } /** * Set the components of a vec2 to the given values * * @param {vec2} out the receiving vector * @param {Number} x X component * @param {Number} y Y component * @returns {vec2} out */ function set(out, x, y) { out[0] = x; out[1] = y; return out; } /** * Adds two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function add(out, a, b) { out[0] = a[0] + b[0]; out[1] = a[1] + b[1]; return out; } /** * Subtracts vector b from vector a * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function subtract(out, a, b) { out[0] = a[0] - b[0]; out[1] = a[1] - b[1]; return out; } /** * Multiplies two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function multiply(out, a, b) { out[0] = a[0] * b[0]; out[1] = a[1] * b[1]; return out; } /** * Divides two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function divide(out, a, b) { out[0] = a[0] / b[0]; out[1] = a[1] / b[1]; return out; } /** * Math.ceil the components of a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to ceil * @returns {vec2} out */ function ceil(out, a) { out[0] = Math.ceil(a[0]); out[1] = Math.ceil(a[1]); return out; } /** * Math.floor the components of a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to floor * @returns {vec2} out */ function floor(out, a) { out[0] = Math.floor(a[0]); out[1] = Math.floor(a[1]); return out; } /** * Returns the minimum of two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function min(out, a, b) { out[0] = Math.min(a[0], b[0]); out[1] = Math.min(a[1], b[1]); return out; } /** * Returns the maximum of two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec2} out */ function max(out, a, b) { out[0] = Math.max(a[0], b[0]); out[1] = Math.max(a[1], b[1]); return out; } /** * Math.round the components of a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to round * @returns {vec2} out */ function round(out, a) { out[0] = Math.round(a[0]); out[1] = Math.round(a[1]); return out; } /** * Scales a vec2 by a scalar number * * @param {vec2} out the receiving vector * @param {vec2} a the vector to scale * @param {Number} b amount to scale the vector by * @returns {vec2} out */ function scale(out, a, b) { out[0] = a[0] * b; out[1] = a[1] * b; return out; } /** * Adds two vec2's after scaling the second operand by a scalar value * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @param {Number} scale the amount to scale b by before adding * @returns {vec2} out */ function scaleAndAdd(out, a, b, scale) { out[0] = a[0] + b[0] * scale; out[1] = a[1] + b[1] * scale; return out; } /** * Calculates the euclidian distance between two vec2's * * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {Number} distance between a and b */ function distance(a, b) { var x = b[0] - a[0], y = b[1] - a[1]; return Math.sqrt(x * x + y * y); } /** * Calculates the squared euclidian distance between two vec2's * * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {Number} squared distance between a and b */ function squaredDistance(a, b) { var x = b[0] - a[0], y = b[1] - a[1]; return x * x + y * y; } /** * Calculates the length of a vec2 * * @param {vec2} a vector to calculate length of * @returns {Number} length of a */ function length(a) { var x = a[0], y = a[1]; return Math.sqrt(x * x + y * y); } /** * Calculates the squared length of a vec2 * * @param {vec2} a vector to calculate squared length of * @returns {Number} squared length of a */ function squaredLength(a) { var x = a[0], y = a[1]; return x * x + y * y; } /** * Negates the components of a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to negate * @returns {vec2} out */ function negate(out, a) { out[0] = -a[0]; out[1] = -a[1]; return out; } /** * Returns the inverse of the components of a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to invert * @returns {vec2} out */ function inverse(out, a) { out[0] = 1.0 / a[0]; out[1] = 1.0 / a[1]; return out; } /** * Normalize a vec2 * * @param {vec2} out the receiving vector * @param {vec2} a vector to normalize * @returns {vec2} out */ function normalize(out, a) { var x = a[0], y = a[1]; var len = x * x + y * y; if (len > 0) { //TODO: evaluate use of glm_invsqrt here? len = 1 / Math.sqrt(len); out[0] = a[0] * len; out[1] = a[1] * len; } return out; } /** * Calculates the dot product of two vec2's * * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {Number} dot product of a and b */ function dot(a, b) { return a[0] * b[0] + a[1] * b[1]; } /** * Computes the cross product of two vec2's * Note that the cross product must by definition produce a 3D vector * * @param {vec3} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @returns {vec3} out */ function cross(out, a, b) { var z = a[0] * b[1] - a[1] * b[0]; out[0] = out[1] = 0; out[2] = z; return out; } /** * Performs a linear interpolation between two vec2's * * @param {vec2} out the receiving vector * @param {vec2} a the first operand * @param {vec2} b the second operand * @param {Number} t interpolation amount, in the range [0-1], between the two inputs * @returns {vec2} out */ function lerp(out, a, b, t) { var ax = a[0], ay = a[1]; out[0] = ax + t * (b[0] - ax); out[1] = ay + t * (b[1] - ay); return out; } /** * Generates a random vector with the given scale * * @param {vec2} out the receiving vector * @param {Number} [scale] Length of the resulting vector. If ommitted, a unit vector will be returned * @returns {vec2} out */ function random(out, scale) { scale = scale || 1.0; var r = __WEBPACK_IMPORTED_MODULE_0__common_js__["RANDOM"]() * 2.0 * Math.PI; out[0] = Math.cos(r) * scale; out[1] = Math.sin(r) * scale; return out; } /** * Transforms the vec2 with a mat2 * * @param {vec2} out the receiving vector * @param {vec2} a the vector to transform * @param {mat2} m matrix to transform with * @returns {vec2} out */ function transformMat2(out, a, m) { var x = a[0], y = a[1]; out[0] = m[0] * x + m[2] * y; out[1] = m[1] * x + m[3] * y; return out; } /** * Transforms the vec2 with a mat2d * * @param {vec2} out the receiving vector * @param {vec2} a the vector to transform * @param {mat2d} m matrix to transform with * @returns {vec2} out */ function transformMat2d(out, a, m) { var x = a[0], y = a[1]; out[0] = m[0] * x + m[2] * y + m[4]; out[1] = m[1] * x + m[3] * y + m[5]; return out; } /** * Transforms the vec2 with a mat3 * 3rd vector component is implicitly '1' * * @param {vec2} out the receiving vector * @param {vec2} a the vector to transform * @param {mat3} m matrix to transform with * @returns {vec2} out */ function transformMat3(out, a, m) { var x = a[0], y = a[1]; out[0] = m[0] * x + m[3] * y + m[6]; out[1] = m[1] * x + m[4] * y + m[7]; return out; } /** * Transforms the vec2 with a mat4 * 3rd vector component is implicitly '0' * 4th vector component is implicitly '1' * * @param {vec2} out the receiving vector * @param {vec2} a the vector to transform * @param {mat4} m matrix to transform with * @returns {vec2} out */ function transformMat4(out, a, m) { var x = a[0]; var y = a[1]; out[0] = m[0] * x + m[4] * y + m[12]; out[1] = m[1] * x + m[5] * y + m[13]; return out; } /** * Rotate a 2D vector * @param {vec2} out The receiving vec2 * @param {vec2} a The vec2 point to rotate * @param {vec2} b The origin of the rotation * @param {Number} c The angle of rotation * @returns {vec2} out */ function rotate(out, a, b, c) { //Translate point to the origin var p0 = a[0] - b[0], p1 = a[1] - b[1], sinC = Math.sin(c), cosC = Math.cos(c); //perform rotation and translate to correct position out[0] = p0 * cosC - p1 * sinC + b[0]; out[1] = p0 * sinC + p1 * cosC + b[1]; return out; } /** * Get the angle between two 2D vectors * @param {vec2} a The first operand * @param {vec2} b The second operand * @returns {Number} The angle in radians */ function angle(a, b) { var x1 = a[0], y1 = a[1], x2 = b[0], y2 = b[1]; var len1 = x1 * x1 + y1 * y1; if (len1 > 0) { //TODO: evaluate use of glm_invsqrt here? len1 = 1 / Math.sqrt(len1); } var len2 = x2 * x2 + y2 * y2; if (len2 > 0) { //TODO: evaluate use of glm_invsqrt here? len2 = 1 / Math.sqrt(len2); } var cosine = (x1 * x2 + y1 * y2) * len1 * len2; if (cosine > 1.0) { return 0; } else if (cosine < -1.0) { return Math.PI; } else { return Math.acos(cosine); } } /** * Returns a string representation of a vector * * @param {vec2} a vector to represent as a string * @returns {String} string representation of the vector */ function str(a) { return 'vec2(' + a[0] + ', ' + a[1] + ')'; } /** * Returns whether or not the vectors exactly have the same elements in the same position (when compared with ===) * * @param {vec2} a The first vector. * @param {vec2} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function exactEquals(a, b) { return a[0] === b[0] && a[1] === b[1]; } /** * Returns whether or not the vectors have approximately the same elements in the same position. * * @param {vec2} a The first vector. * @param {vec2} b The second vector. * @returns {Boolean} True if the vectors are equal, false otherwise. */ function equals(a, b) { var a0 = a[0], a1 = a[1]; var b0 = b[0], b1 = b[1]; return Math.abs(a0 - b0) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= __WEBPACK_IMPORTED_MODULE_0__common_js__["EPSILON"] * Math.max(1.0, Math.abs(a1), Math.abs(b1)); } /** * Alias for {@link vec2.length} * @function */ var len = length; /** * Alias for {@link vec2.subtract} * @function */ var sub = subtract; /** * Alias for {@link vec2.multiply} * @function */ var mul = multiply; /** * Alias for {@link vec2.divide} * @function */ var div = divide; /** * Alias for {@link vec2.distance} * @function */ var dist = distance; /** * Alias for {@link vec2.squaredDistance} * @function */ var sqrDist = squaredDistance; /** * Alias for {@link vec2.squaredLength} * @function */ var sqrLen = squaredLength; /** * Perform some operation over an array of vec2s. * * @param {Array} a the array of vectors to iterate over * @param {Number} stride Number of elements between the start of each vec2. If 0 assumes tightly packed * @param {Number} offset Number of elements to skip at the beginning of the array * @param {Number} count Number of vec2s to iterate over. If 0 iterates over entire array * @param {Function} fn Function to call for each vector in the array * @param {Object} [arg] additional argument to pass to fn * @returns {Array} a * @function */ var forEach = function () { var vec = create(); return function (a, stride, offset, count, fn, arg) { var i = void 0, l = void 0; if (!stride) { stride = 2; } if (!offset) { offset = 0; } if (count) { l = Math.min(count * stride + offset, a.length); } else { l = a.length; } for (i = offset; i < l; i += stride) { vec[0] = a[i];vec[1] = a[i + 1]; fn(vec, vec, arg); a[i] = vec[0];a[i + 1] = vec[1]; } return a; }; }(); /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { (function webpackUniversalModuleDefinition(root, factory) { if(true) module.exports = factory(__webpack_require__(1)); else if(typeof define === 'function' && define.amd) define(["gl-matrix"], factory); else if(typeof exports === 'object') exports["MinimalGLTFLoader"] = factory(require("gl-matrix")); else root["MinimalGLTFLoader"] = factory(root[undefined]); })(this, function(__WEBPACK_EXTERNAL_MODULE_1__) { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __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; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 0); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "glTFLoader", function() { return glTFLoader; }); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_gl_matrix__ = __webpack_require__(1); /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0_gl_matrix___default = __webpack_require__.n(__WEBPACK_IMPORTED_MODULE_0_gl_matrix__); var MinimalGLTFLoader = MinimalGLTFLoader || {}; var globalUniformBlockID = 0; var curLoader = null; // @tmp, might be unsafe if loading multiple model at the same time var NUM_MAX_JOINTS = 65; // Data classes var Scene = MinimalGLTFLoader.Scene = function (gltf, s) { this.name = s.name !== undefined ? s.name : null; this.nodes = new Array(s.nodes.length); // root node object of this scene for (var i = 0, len = s.nodes.length; i < len; i++) { this.nodes[i] = gltf.nodes[s.nodes[i]]; } this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; this.boundingBox = null; }; /** * * @param {vec3} min * @param {vec3} max */ var BoundingBox = MinimalGLTFLoader.BoundingBox = function (min, max, isClone) { // this.min = min; // this.max = max; min = min || __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); max = max || __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY); if (isClone === undefined || isClone === true) { this.min = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].clone(min); this.max = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].clone(max); } else { this.min = min; this.max = max; } this.transform = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); }; BoundingBox.prototype.updateBoundingBox = function (bbox) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].min(this.min, this.min, bbox.min); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].max(this.max, this.max, bbox.max); }; BoundingBox.prototype.calculateTransform = function () { // transform from a unit cube whose min = (0, 0, 0) and max = (1, 1, 1) // scale this.transform[0] = this.max[0] - this.min[0]; this.transform[5] = this.max[1] - this.min[1]; this.transform[10] = this.max[2] - this.min[2]; // translate this.transform[12] = this.min[0]; this.transform[13] = this.min[1]; this.transform[14] = this.min[2]; }; BoundingBox.getAABBFromOBB = (function() { var transformRight = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var transformUp = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var transformBackward = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var tmpVec3a = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); var tmpVec3b = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); return (function (obb, matrix) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].set(transformRight, matrix[0], matrix[1], matrix[2]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].set(transformUp, matrix[4], matrix[5], matrix[6]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].set(transformBackward, matrix[8], matrix[9], matrix[10]); var min = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(matrix[12], matrix[13], matrix[14]); // init with matrix translation var max = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].clone(min); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3a, transformRight, obb.min[0]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3b, transformRight, obb.max[0]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].min(transformRight, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(min, min, transformRight); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].max(transformRight, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(max, max, transformRight); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3a, transformUp, obb.min[1]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3b, transformUp, obb.max[1]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].min(transformUp, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(min, min, transformUp); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].max(transformUp, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(max, max, transformUp); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3a, transformBackward, obb.min[2]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].scale(tmpVec3b, transformBackward, obb.max[2]); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].min(transformBackward, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(min, min, transformBackward); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].max(transformBackward, tmpVec3a, tmpVec3b); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].add(max, max, transformBackward); var bbox = new BoundingBox(min, max, false); bbox.calculateTransform(); return bbox; }); })(); var Accessor = MinimalGLTFLoader.Accessor = function (a, bufferViewObject) { this.bufferView = bufferViewObject; this.componentType = a.componentType; // required this.byteOffset = a.byteOffset !== undefined ? a.byteOffset : 0; this.byteStride = bufferViewObject.byteStride; this.normalized = a.normalized !== undefined ? a.normalized : false; this.count = a.count; // required this.type = a.type; // required this.size = Type2NumOfComponent[this.type]; this.min = a.min; // @tmp assume required for now (for bbox) this.max = a.max; // @tmp assume required for now (for bbox) this.extensions = a.extensions !== undefined ? a.extensions : null; this.extras = a.extras !== undefined ? a.extras : null; }; Accessor.prototype.prepareVertexAttrib = function(location, gl) { gl.vertexAttribPointer( location, this.size, this.componentType, this.normalized, this.byteStride, this.byteOffset ); gl.enableVertexAttribArray(location); }; var BufferView = MinimalGLTFLoader.BufferView = function(bf, bufferData) { this.byteLength = bf.byteLength; //required this.byteOffset = bf.byteOffset !== undefined ? bf.byteOffset : 0; this.byteStride = bf.byteStride !== undefined ? bf.byteStride : 0; this.target = bf.target !== undefined ? bf.target : null; this.data = bufferData.slice(this.byteOffset, this.byteOffset + this.byteLength); this.extensions = bf.extensions !== undefined ? bf.extensions : null; this.extras = bf.extras !== undefined ? bf.extras : null; // runtime stuffs ------------- this.buffer = null; // gl buffer }; BufferView.prototype.createBuffer = function(gl) { this.buffer = gl.createBuffer(); }; BufferView.prototype.bindData = function(gl) { if (this.target) { gl.bindBuffer(this.target, this.buffer); gl.bufferData(this.target, this.data, gl.STATIC_DRAW); gl.bindBuffer(this.target, null); return true; } return false; }; var Camera = MinimalGLTFLoader.Camera = function(c) { this.name = c.name !== undefined ? c.name : null; this.type = c.type; // required this.othographic = c.othographic === undefined ? null : c.othographic; // every attribute inside is required (excluding extensions) this.perspective = c.perspective === undefined ? null : { yfov: c.perspective.yfov, znear: c.perspective.znear, zfar: c.perspective.zfar !== undefined ? c.perspective.zfar : null, aspectRatio: c.perspective.aspectRatio !== undefined ? c.perspective.aspectRatio : null }; this.extensions = c.extensions !== undefined ? c.extensions : null; this.extras = c.extras !== undefined ? c.extras : null; }; var Node = MinimalGLTFLoader.Node = function (n, nodeID) { this.name = n.name !== undefined ? n.name : null; this.nodeID = nodeID; // TODO: camera this.camera = n.camera !== undefined ? n.camera : null; this.matrix = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); if (n.hasOwnProperty('matrix')) { for(var i = 0; i < 16; ++i) { this.matrix[i] = n.matrix[i]; } this.translation = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].getTranslation(this.translation, this.matrix); this.rotation = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["quat"].create(); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].getRotation(this.rotation, this.matrix); this.scale = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].create(); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].getScaling(this.scale, this.matrix); } else { // this.translation = null; // this.rotation = null; // this.scale = null; this.getTransformMatrixFromTRS(n.translation, n.rotation, n.scale); } this.children = n.children || []; // init as id, then hook up to node object later this.mesh = n.mesh !== undefined ? curLoader.glTF.meshes[n.mesh] : null; this.skin = n.skin !== undefined ? n.skin : null; // init as id, then hook up to skin object later if (n.extensions !== undefined) { if (n.extensions.gl_avatar !== undefined && curLoader.enableGLAvatar === true) { var linkedSkinID = curLoader.skeletonGltf.json.extensions.gl_avatar.skins[ n.extensions.gl_avatar.skin.name ]; var linkedSkin = curLoader.skeletonGltf.skins[linkedSkinID]; this.skin = new SkinLink(curLoader.glTF, linkedSkin, n.extensions.gl_avatar.skin.inverseBindMatrices); } } // TODO: morph targets weights this.weights = n.weights !== undefined ? n.weights : null; this.extensions = n.extensions !== undefined ? n.extensions : null; this.extras = n.extras !== undefined ? n.extras : null; // runtime stuffs-------------- this.aabb = null; // axis aligned bounding box, not need to apply node transform to aabb this.bvh = new BoundingBox(); }; Node.prototype.traverse = function(parent, executeFunc) { executeFunc(this, parent); for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traverse(this, executeFunc); } }; Node.prototype.traversePostOrder = function(parent, executeFunc) { for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traversePostOrder(this, executeFunc); } executeFunc(this, parent); }; Node.prototype.traverseTwoExecFun = function(parent, execFunPre, execFunPos) { execFunPre(this, parent); for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traverseTwoExecFun(this, execFunPre, execFunPos); } execFunPos(this, parent); }; var TRSMatrix = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); Node.prototype.getTransformMatrixFromTRS = function(translation, rotation, scale) { this.translation = translation !== undefined ? __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(translation[0], translation[1], translation[2]) : __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(0, 0, 0); this.rotation = rotation !== undefined ? __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].fromValues(rotation[0], rotation[1], rotation[2], rotation[3]) : __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].fromValues(0, 0, 0, 1); this.scale = scale !== undefined ? __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(scale[0], scale[1], scale[2]) : __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(1, 1, 1); this.updateMatrixFromTRS(); }; Node.prototype.updateMatrixFromTRS = function() { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].fromRotationTranslation(TRSMatrix, this.rotation, this.translation); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].scale(this.matrix, TRSMatrix, this.scale); }; var Mesh = MinimalGLTFLoader.Mesh = function (m, meshID) { this.meshID = meshID; this.name = m.name !== undefined ? m.name : null; this.primitives = []; // required // bounding box (runtime stuff) this.boundingBox = null; var p, primitive, accessor; for (var i = 0, len = m.primitives.length; i < len; ++i) { p = m.primitives[i]; primitive = new Primitive(curLoader.glTF, p); this.primitives.push(primitive); // bounding box related if (primitive.boundingBox) { if (!this.boundingBox) { this.boundingBox = new BoundingBox(); } this.boundingBox.updateBoundingBox(primitive.boundingBox); } } if (this.boundingBox) { this.boundingBox.calculateTransform(); } // TODO: weights for morph targets this.weights = m.weights !== undefined ? m.weights : null; this.extensions = m.extensions !== undefined ? m.extensions : null; this.extras = m.extras !== undefined ? m.extras : null; }; var Primitive = MinimalGLTFLoader.Primitive = function (gltf, p) { // , required // get hook up with accessor object in _postprocessing this.attributes = p.attributes; this.indices = p.indices !== undefined ? p.indices : null; // accessor id var attname; if (p.extensions !== undefined) { if (p.extensions.gl_avatar !== undefined && curLoader.enableGLAvatar === true) { if (p.extensions.gl_avatar.attributes) { for ( attname in p.extensions.gl_avatar.attributes ) { this.attributes[attname] = p.extensions.gl_avatar.attributes[attname]; } } } } if (this.indices !== null) { this.indicesComponentType = gltf.json.accessors[this.indices].componentType; this.indicesLength = gltf.json.accessors[this.indices].count; this.indicesOffset = (gltf.json.accessors[this.indices].byteOffset || 0); } else { // assume 'POSITION' is there this.drawArraysCount = gltf.json.accessors[this.attributes.POSITION].count; this.drawArraysOffset = (gltf.json.accessors[this.attributes.POSITION].byteOffset || 0); } // hook up accessor object for ( attname in this.attributes ) { this.attributes[attname] = gltf.accessors[ this.attributes[attname] ]; } this.material = p.material !== undefined ? gltf.materials[p.material] : null; this.mode = p.mode !== undefined ? p.mode : 4; // default: gl.TRIANGLES // morph related this.targets = p.targets; this.extensions = p.extensions !== undefined ? p.extensions : null; this.extras = p.extras !== undefined ? p.extras : null; // ----gl run time related this.vertexArray = null; //vao this.vertexBuffer = null; this.indexBuffer = null; this.shader = null; this.boundingBox = null; if (this.attributes.POSITION !== undefined) { var accessor = this.attributes.POSITION; if (accessor.max) { // @todo: handle cases where no min max are provided // assume vec3 if (accessor.type === 'VEC3') { this.boundingBox = new BoundingBox( __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(accessor.min[0], accessor.min[1], accessor.min[2]), __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].fromValues(accessor.max[0], accessor.max[1], accessor.max[2]), false ); this.boundingBox.calculateTransform(); } } } }; var Texture = MinimalGLTFLoader.Texture = function (t) { this.name = t.name !== undefined ? t.name : null; this.sampler = t.sampler !== undefined ? curLoader.glTF.samplers[t.sampler] : null; this.source = t.source !== undefined ? curLoader.glTF.images[t.source] : null; this.extensions = t.extensions !== undefined ? t.extensions : null; this.extras = t.extras !== undefined ? t.extras : null; // runtime this.texture = null; }; Texture.prototype.createTexture = function(gl) { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D( gl.TEXTURE_2D, // assumed 0, // Level of details // gl.RGB, // Format // gl.RGB, gl.RGBA, // Format gl.RGBA, gl.UNSIGNED_BYTE, // Size of each channel this.source ); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); }; var Sampler = MinimalGLTFLoader.Sampler = function (s) { this.name = s.name !== undefined ? s.name : null; this.magFilter = s.magFilter !== undefined ? s.magFilter : null; this.minFilter = s.minFilter !== undefined ? s.minFilter : null; this.wrapS = s.wrapS !== undefined ? s.wrapS : 10497; this.wrapT = s.wrapT !== undefined ? s.wrapT : 10497; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; this.sampler = null; }; Sampler.prototype.createSampler = function(gl) { this.sampler = gl.createSampler(); if (this.minFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, this.minFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); } if (this.magFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, this.magFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR); } gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_S, this.wrapS); gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_T, this.wrapT); }; // Sampler.prototype.bindSampler = function(i, gl) { // gl.bindSampler(i, this.sampler); // } var TextureInfo = MinimalGLTFLoader.TextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var PbrMetallicRoughness = MinimalGLTFLoader.PbrMetallicRoughness = function (json) { this.baseColorFactor = json.baseColorFactor !== undefined ? json.baseColorFactor : [1, 1, 1, 1]; this.baseColorTexture = json.baseColorTexture !== undefined ? new TextureInfo(json.baseColorTexture): null; this.metallicFactor = json.metallicFactor !== undefined ? json.metallicFactor : 1 ; this.roughnessFactor = json.roughnessFactor !== undefined ? json.roughnessFactor : 1 ; this.metallicRoughnessTexture = json.metallicRoughnessTexture !== undefined ? new TextureInfo(json.metallicRoughnessTexture): null; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var NormalTextureInfo = MinimalGLTFLoader.NormalTextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.scale = json.scale !== undefined ? json.scale : 1 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var OcclusionTextureInfo = MinimalGLTFLoader.OcclusionTextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.strength = json.strength !== undefined ? json.strength : 1 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var Material = MinimalGLTFLoader.Material = function (m) { this.name = m.name !== undefined ? m.name : null; this.pbrMetallicRoughness = m.pbrMetallicRoughness !== undefined ? new PbrMetallicRoughness( m.pbrMetallicRoughness ) : new PbrMetallicRoughness({ baseColorFactor: [1, 1, 1, 1], metallicFactor: 1, metallicRoughnessTexture: 1 }); // this.normalTexture = m.normalTexture !== undefined ? m.normalTexture : null; this.normalTexture = m.normalTexture !== undefined ? new NormalTextureInfo(m.normalTexture) : null; this.occlusionTexture = m.occlusionTexture !== undefined ? new OcclusionTextureInfo(m.occlusionTexture) : null; this.emissiveTexture = m.emissiveTexture !== undefined ? new TextureInfo(m.emissiveTexture) : null; this.emissiveFactor = m.emissiveFactor !== undefined ? m.emissiveFactor : [0, 0, 0]; this.alphaMode = m.alphaMode !== undefined ? m.alphaMode : "OPAQUE"; this.alphaCutoff = m.alphaCutoff !== undefined ? m.alphaCutoff : 0.5; this.doubleSided = m.doubleSided || false; this.extensions = m.extensions !== undefined ? m.extensions : null; this.extras = m.extras !== undefined ? m.extras : null; }; var Skin = MinimalGLTFLoader.Skin = function (gltf, s, skinID) { this.name = s.name !== undefined ? s.name : null; this.skinID = skinID; this.joints = new Array(s.joints.length); // required var i, len; for (i = 0, len = this.joints.length; i < len; i++) { this.joints[i] = gltf.nodes[s.joints[i]]; } this.skeleton = s.skeleton !== undefined ? gltf.nodes[s.skeleton] : null; this.inverseBindMatrices = s.inverseBindMatrices !== undefined ? gltf.accessors[s.inverseBindMatrices] : null; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; // @tmp: runtime stuff should be taken care of renderer // since glTF model should only store info // runtime can have multiple instances of this glTF models this.uniformBlockID = globalUniformBlockID++; if (this.inverseBindMatrices) { // should be a mat4 this.inverseBindMatricesData = _getAccessorData(this.inverseBindMatrices); // this.inverseBindMatricesMat4 = mat4.fromValues(this.inverseBindMatricesData); this.inverseBindMatrix = []; // for calculation this.jointMatrixUniformBuffer = null; // this.jointMatrixUnidormBufferData = _arrayBuffer2TypedArray( // this.inverseBindMatricesData, // 0, // this.inverseBindMatricesData.length, // this.inverseBindMatrices.componentType // ); // for copy to UBO // @tmp: fixed length to coordinate with shader, for copy to UBO this.jointMatrixUnidormBufferData = new Float32Array(NUM_MAX_JOINTS * 16); for (i = 0, len = this.inverseBindMatricesData.length; i < len; i += 16) { this.inverseBindMatrix.push(__WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15] )); } } }; var SkinLink = MinimalGLTFLoader.SkinLink = function (gltf, linkedSkin, inverseBindMatricesAccessorID) { this.isLink = true; if (!gltf.skins) { gltf.skins = []; } gltf.skins.push(this); this.name = linkedSkin.name; // this.skinID = linkedSkin.skinID; // use this for uniformblock id // this.skinID = gltf.skins.length - 1; // this.skinID = curLoader.skeletonGltf.skins.length + gltf.skins.length - 1; this.skinID = gltf.skins.length - 1; this.joints = linkedSkin.joints; this.skeleton = linkedSkin.skeleton; this.inverseBindMatrices = inverseBindMatricesAccessorID !== undefined ? gltf.accessors[inverseBindMatricesAccessorID] : null; // @tmp: runtime stuff should be taken care of renderer // since glTF model should only store info // runtime can have multiple instances of this glTF models this.uniformBlockID = globalUniformBlockID++; if (this.inverseBindMatrices) { // should be a mat4 this.inverseBindMatricesData = _getAccessorData(this.inverseBindMatrices); // this.inverseBindMatricesMat4 = mat4.fromValues(this.inverseBindMatricesData); this.inverseBindMatrix = []; // for calculation this.jointMatrixUniformBuffer = null; // this.jointMatrixUnidormBufferData = _arrayBuffer2TypedArray( // this.inverseBindMatricesData, // 0, // this.inverseBindMatricesData.length, // this.inverseBindMatrices.componentType // ); // for copy to UBO // @tmp: fixed length to coordinate with shader, for copy to UBO this.jointMatrixUnidormBufferData = new Float32Array(NUM_MAX_JOINTS * 16); for (var i = 0, len = this.inverseBindMatricesData.length; i < len; i += 16) { this.inverseBindMatrix.push(__WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15] )); } } }; // animation has no potential plan for progressive rendering I guess // so everything happens after all buffers are loaded var Target = MinimalGLTFLoader.Target = function (t) { this.nodeID = t.node !== undefined ? t.node : null ; //id, to be hooked up to object later this.path = t.path; //required, string this.extensions = t.extensions !== undefined ? t.extensions : null; this.extras = t.extras !== undefined ? t.extras : null; }; var Channel = MinimalGLTFLoader.Channel = function (c, animation) { this.sampler = animation.samplers[c.sampler]; //required this.target = new Target(c.target); //required this.extensions = c.extensions !== undefined ? c.extensions : null; this.extras = c.extras !== undefined ? c.extras : null; }; var AnimationSampler = MinimalGLTFLoader.AnimationSampler = function (gltf, s) { this.input = gltf.accessors[s.input]; //required, accessor object this.output = gltf.accessors[s.output]; //required, accessor object this.inputTypedArray = _getAccessorData(this.input); this.outputTypedArray = _getAccessorData(this.output); // "LINEAR" // "STEP" // "CATMULLROMSPLINE" // "CUBICSPLINE" this.interpolation = s.interpolation !== undefined ? s.interpolation : 'LINEAR' ; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; // ------- extra runtime info ----------- // runtime status thing this.curIdx = 0; // this.curValue = 0; this.curValue = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].create(); this.endT = this.inputTypedArray[this.inputTypedArray.length - 1]; this.inputMax = this.endT - this.inputTypedArray[0]; }; var animationOutputValueVec4a = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].create(); var animationOutputValueVec4b = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].create(); AnimationSampler.prototype.getValue = function (t) { if (t > this.endT) { t -= this.inputMax * Math.ceil((t - this.endT) / this.inputMax); this.curIdx = 0; } var len = this.inputTypedArray.length; while (this.curIdx <= len - 2 && t >= this.inputTypedArray[this.curIdx + 1]) { this.curIdx++; } if (this.curIdx >= len - 1) { // loop t -= this.inputMax; this.curIdx = 0; } // @tmp: assume no stride var count = Type2NumOfComponent[this.output.type]; var v4lerp = count === 4 ? __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["quat"].slerp: __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec4"].lerp; var i = this.curIdx; var o = i * count; var on = o + count; var u = Math.max( 0, t - this.inputTypedArray[i] ) / (this.inputTypedArray[i+1] - this.inputTypedArray[i]); for (var j = 0; j < count; j++ ) { animationOutputValueVec4a[j] = this.outputTypedArray[o + j]; animationOutputValueVec4b[j] = this.outputTypedArray[on + j]; } switch(this.interpolation) { case 'LINEAR': v4lerp(this.curValue, animationOutputValueVec4a, animationOutputValueVec4b, u); break; default: break; } }; var Animation = MinimalGLTFLoader.Animation = function (gltf, a) { this.name = a.name !== undefined ? a.name : null; var i, len; this.samplers = []; // required, array of animation sampler for (i = 0, len = a.samplers.length; i < len; i++) { this.samplers[i] = new AnimationSampler(gltf, a.samplers[i]); } this.channels = []; //required, array of channel for (i = 0, len = a.channels.length; i < len; i++) { this.channels[i] = new Channel(a.channels[i], this); } this.extensions = a.extensions !== undefined ? a.extensions : null; this.extras = a.extras !== undefined ? a.extras : null; }; /** * */ var glTFModel = MinimalGLTFLoader.glTFModel = function (gltf) { this.json = gltf; this.defaultScene = gltf.scene !== undefined ? gltf.scene : 0; this.version = Number(gltf.asset.version); if (gltf.accessors) { this.accessors = new Array(gltf.accessors.length); } if (gltf.bufferViews) { this.bufferViews = new Array(gltf.bufferViews.length); } if (gltf.scenes) { this.scenes = new Array(gltf.scenes.length); // store Scene object } if (gltf.nodes) { this.nodes = new Array(gltf.nodes.length); // store Node object } if (gltf.meshes) { this.meshes = new Array(gltf.meshes.length); // store mesh object } if (gltf.materials) { this.materials = new Array(gltf.materials.length); // store material object } if (gltf.textures) { this.textures = new Array(gltf.textures.length); } if (gltf.samplers) { this.samplers = new Array(gltf.samplers.length); } if (gltf.images) { this.images = new Array(gltf.images.length); } if (gltf.skins) { this.skins = new Array(gltf.skins.length); } if (gltf.animations) { this.animations = new Array(gltf.animations.length); } if (gltf.cameras) { this.cameras = new Array(gltf.cameras.length); } this.extensions = gltf.extensions !== undefined ? gltf.extensions : null; this.extras = gltf.extras !== undefined ? gltf.extras : null; }; var gl; var glTFLoader = MinimalGLTFLoader.glTFLoader = function (glContext) { gl = glContext !== undefined ? glContext : null; this._init(); this.glTF = null; this.enableGLAvatar = false; this.linkSkeletonGltf = null; }; glTFLoader.prototype._init = function() { this._loadDone = false; this._bufferRequested = 0; this._bufferLoaded = 0; this._buffers = []; this._bufferTasks = {}; this._shaderRequested = 0; this._shaderLoaded = 0; this._imageRequested = 0; this._imageLoaded = 0; this._pendingTasks = 0; this._finishedPendingTasks = 0; this.onload = null; curLoader = this; }; glTFLoader.prototype._checkComplete = function () { if (this._bufferRequested == this._bufferLoaded && // this._shaderRequested == this._shaderLoaded && this._imageRequested == this._imageLoaded // && other resources finish loading ) { this._loadDone = true; } if (this._loadDone && this._pendingTasks == this._finishedPendingTasks) { this._postprocess(); this.onload(this.glTF); } }; glTFLoader.prototype.loadGLTF_GL_Avatar_Skin = function (uri, skeletonGltf, callback) { this.enableGLAvatar = true; this.skeletonGltf = skeletonGltf; this.loadGLTF(uri, callback); }; /** * load a glTF model * * @param {String} uri uri of the .glTF file. Other resources (bins, images) are assumed to be in the same base path * @param {Function} callback the onload callback function */ glTFLoader.prototype.loadGLTF = function (uri, callback) { this._init(); this.onload = callback || function(glTF) { console.log('glTF model loaded.'); console.log(glTF); }; this.baseUri = _getBaseUri(uri); var loader = this; _loadJSON(uri, function (response) { // Parse JSON string into object var json = JSON.parse(response); loader.glTF = new glTFModel(json); var bid; var loadArrayBufferCallback = function (resource) { loader._buffers[bid] = resource; loader._bufferLoaded++; if (loader._bufferTasks[bid]) { var i,len; for (i = 0, len = loader._bufferTasks[bid].length; i < len; ++i) { (loader._bufferTasks[bid][i])(resource); } } loader._checkComplete(); }; // Launch loading resources task: buffers, etc. if (json.buffers) { for (bid in json.buffers) { loader._bufferRequested++; _loadArrayBuffer(loader.baseUri + json.buffers[bid].uri, loadArrayBufferCallback); } } // load images var loadImageCallback = function (img, iid) { loader._imageLoaded++; loader.glTF.images[iid] = img; loader._checkComplete(); }; var iid; if (json.images) { for (iid in json.images) { loader._imageRequested++; _loadImage(loader.baseUri + json.images[iid].uri, iid, loadImageCallback); } } loader._checkComplete(); }); }; glTFLoader.prototype._postprocess = function () { // if there's no plan for progressive loading (streaming) // than simply everything should be placed here // console.log('finish loading all assets, do a second pass postprocess'); curLoader = this; var i, leni, j, lenj; var scene, s; var node; var mesh, primitive, accessor; // cameras if (this.glTF.cameras) { for (i = 0, leni = this.glTF.cameras.length; i < leni; i++) { this.glTF.cameras[i] = new Camera(this.glTF.json.cameras[i]); } } // bufferviews if (this.glTF.bufferViews) { for (i = 0, leni = this.glTF.bufferViews.length; i < leni; i++) { this.glTF.bufferViews[i] = new BufferView(this.glTF.json.bufferViews[i], this._buffers[ this.glTF.json.bufferViews[i].buffer ]); } } // accessors if (this.glTF.accessors) { for (i = 0, leni = this.glTF.accessors.length; i < leni; i++) { this.glTF.accessors[i] = new Accessor(this.glTF.json.accessors[i], this.glTF.bufferViews[ this.glTF.json.accessors[i].bufferView ]); } } // load all materials if (this.glTF.materials) { for (i = 0, leni = this.glTF.materials.length; i < leni; i++) { this.glTF.materials[i] = new Material(this.glTF.json.materials[i]); } } // load all samplers if (this.glTF.samplers) { for (i = 0, leni = this.glTF.samplers.length; i < leni; i++) { this.glTF.samplers[i] = new Sampler(this.glTF.json.samplers[i]); } } // load all textures if (this.glTF.textures) { for (i = 0, leni = this.glTF.textures.length; i < leni; i++) { this.glTF.textures[i] = new Texture(this.glTF.json.textures[i]); } } // mesh for (i = 0, leni = this.glTF.meshes.length; i < leni; i++) { this.glTF.meshes[i] = new Mesh(this.glTF.json.meshes[i], i); } // node for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { this.glTF.nodes[i] = new Node(this.glTF.json.nodes[i], i); } // node: hook up children for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { node = this.glTF.nodes[i]; for (j = 0, lenj = node.children.length; j < lenj; j++) { node.children[j] = this.glTF.nodes[ node.children[j] ]; } } // scene Bounding box var nodeMatrix = new Array(this.glTF.nodes.length); for(i = 0, leni = nodeMatrix.length; i < leni; i++) { nodeMatrix[i] = __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].create(); } function execUpdateTransform(n, parent) { var tmpMat4 = nodeMatrix[n.nodeID]; if (parent !== null) { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].mul(tmpMat4, nodeMatrix[parent.nodeID], n.matrix); } else { __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["mat4"].copy(tmpMat4, n.matrix); } } function execUpdateBBox(n, parent){ var tmpMat4 = nodeMatrix[n.nodeID]; var parentBVH; if (parent !== null) { parentBVH = parent.bvh; } else { parentBVH = scene.boundingBox; } if (n.mesh) { mesh = n.mesh; if (mesh.boundingBox) { n.aabb = BoundingBox.getAABBFromOBB(mesh.boundingBox, tmpMat4); if (n.children.length === 0) { // n.bvh = n.aabb; __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].copy(n.bvh.min, n.aabb.min); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].copy(n.bvh.max, n.aabb.max); } } } __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].min(parentBVH.min, parentBVH.min, n.bvh.min); __WEBPACK_IMPORTED_MODULE_0_gl_matrix__["vec3"].max(parentBVH.max, parentBVH.max, n.bvh.max); } for (i = 0, leni = this.glTF.scenes.length; i < leni; i++) { scene = this.glTF.scenes[i] = new Scene(this.glTF, this.glTF.json.scenes[i]); scene.boundingBox = new BoundingBox(); for (j = 0, lenj = scene.nodes.length; j < lenj; j++) { node = scene.nodes[j]; // node.traverse(null, execUpdateBBox); node.traverseTwoExecFun(null, execUpdateTransform, execUpdateBBox); } scene.boundingBox.calculateTransform(); } for (j = 0, lenj = this.glTF.nodes.length; j < lenj; j++) { node = this.glTF.nodes[j]; if (node.bvh !== null) { node.bvh.calculateTransform(); } } // load animations (when all accessors are loaded correctly) if (this.glTF.animations) { for (i = 0, leni = this.glTF.animations.length; i < leni; i++) { this.glTF.animations[i] = new Animation(this.glTF, this.glTF.json.animations[i]); } } var joints; // if (this.glTF.skins) { if (this.glTF.json.skins) { for (i = 0, leni = this.glTF.skins.length; i < leni; i++) { this.glTF.skins[i] = new Skin(this.glTF, this.glTF.json.skins[i], i); joints = this.glTF.skins[i].joints; for (j = 0, lenj = joints.length; j < lenj; j++) { // this.glTF.nodes[ joints[j] ].jointID = j; joints[j].jointID = j; } } } for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { node = this.glTF.nodes[i]; if (node.skin !== null) { if (typeof node.skin == 'number') { // usual skin, hook up node.skin = this.glTF.skins[ node.skin ]; } else { // assume gl_avatar is in use // do nothing } } } }; // TODO: get from gl context var ComponentType2ByteSize = { 5120: 1, // BYTE 5121: 1, // UNSIGNED_BYTE 5122: 2, // SHORT 5123: 2, // UNSIGNED_SHORT 5126: 4 // FLOAT }; var Type2NumOfComponent = { 'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT2': 4, 'MAT3': 9, 'MAT4': 16 }; // ------ Scope limited private util functions--------------- // for animation use function _arrayBuffer2TypedArray(buffer, byteOffset, countOfComponentType, componentType) { switch(componentType) { // @todo: finish case 5122: return new Int16Array(buffer, byteOffset, countOfComponentType); case 5123: return new Uint16Array(buffer, byteOffset, countOfComponentType); case 5124: return new Int32Array(buffer, byteOffset, countOfComponentType); case 5125: return new Uint32Array(buffer, byteOffset, countOfComponentType); case 5126: return new Float32Array(buffer, byteOffset, countOfComponentType); default: return null; } } function _getAccessorData(accessor) { return _arrayBuffer2TypedArray( accessor.bufferView.data, accessor.byteOffset, accessor.count * Type2NumOfComponent[accessor.type], accessor.componentType ); } function _getBaseUri(uri) { // https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Core/getBaseUri.js var basePath = ''; var i = uri.lastIndexOf('/'); if(i !== -1) { basePath = uri.substring(0, i + 1); } return basePath; } function _loadJSON(src, callback) { // native json loading technique from @KryptoniteDove: // http://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript var xobj = new XMLHttpRequest(); xobj.overrideMimeType("application/json"); xobj.open('GET', src, true); xobj.onreadystatechange = function () { if (xobj.readyState == 4 && // Request finished, response ready xobj.status == "200") { // Status OK callback(xobj.responseText, this); } }; xobj.send(null); } function _loadArrayBuffer(url, callback) { var xobj = new XMLHttpRequest(); xobj.responseType = 'arraybuffer'; xobj.open('GET', url, true); xobj.onreadystatechange = function () { if (xobj.readyState == 4 && // Request finished, response ready xobj.status == "200") { // Status OK var arrayBuffer = xobj.response; if (arrayBuffer && callback) { callback(arrayBuffer); } } }; xobj.send(null); } function _loadImage(url, iid, onload) { var img = new Image(); img.crossOrigin = "Anonymous"; img.src = url; img.onload = function() { onload(img, iid); }; } // export { MinimalGLTFLoader }; /***/ }), /* 1 */ /***/ (function(module, exports) { module.exports = __WEBPACK_EXTERNAL_MODULE_1__; /***/ }) /******/ ]); }); /***/ }), /* 13 */ /***/ (function(module, exports, __webpack_require__) { // style-loader: Adds some css to the DOM by adding a
Occlusion culling with hierarchy demo

https://developer.nvidia.com/gpugems/GPUGems2/gpugems2_chapter06.html

Draw Bounding Box:
Bounding Box type:
================================================ FILE: examples/style.css ================================================ body { color: #cccccc; font-family: Monospace; font-size: 13px; text-align: center; background-color: #050505; margin: 0px; overflow: hidden; } #info { position: absolute; top: 0px; width: 100%; padding: 5px; } #description { position: absolute; top: 20px; width: 100%; padding: 5px; } .float { float: left; top: 10px; } a { color: #0080ff; } ================================================ FILE: examples/utility.js ================================================ (function () { 'use strict'; window.getShaderSource = function(id) { return document.getElementById(id).textContent.replace(/^\s+|\s+$/g, ''); }; function createShader(gl, source, type) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } window.createProgram = function(gl, vertexShaderSource, fragmentShaderSource) { var program = gl.createProgram(); var vshader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER); var fshader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER); gl.attachShader(program, vshader); gl.deleteShader(vshader); gl.attachShader(program, fshader); gl.deleteShader(fshader); gl.linkProgram(program); var log = gl.getProgramInfoLog(program); if (log) { console.log(log); } log = gl.getShaderInfoLog(vshader); if (log) { console.log(log); } log = gl.getShaderInfoLog(fshader); if (log) { console.log(log); } return program; }; window.loadImage = function(url, onload) { var img = new Image(); img.src = url; img.onload = function() { onload(img); }; return img; }; window.loadImages = function(urls, onload) { var imgs = []; var imgsToLoad = urls.length; function onImgLoad() { if (--imgsToLoad <= 0) { onload(imgs); } } for (var i = 0; i < imgsToLoad; ++i) { imgs.push(loadImage(urls[i], onImgLoad)); } }; window.loadObj = function(url, onload) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'text'; xhr.onload = function(e) { var mesh = new OBJ.Mesh(this.response); onload(mesh); }; xhr.send(); }; })(); ================================================ FILE: examples/webgl2-renderer-old.html ================================================ WebGL 2 Renderer Example
WebGL 2 Renderer Example

An example viewer of the model loaded by Minimal-glTF-Loader

Draw Bounding Box:
Bounding Box type:
================================================ FILE: examples/webgl2-renderer.html ================================================ Minimal-glTF-Loader renderer example
Minimal-glTF-Loader renderer example WebGL 2 Renderer Example

An example viewer of the model loaded by Minimal-glTF-Loader

glTF Models:
Animations:
Play All Animations:
Draw Bounding Box:
Bounding Box type:
================================================ FILE: examples/webpack.config.js ================================================ var path = require('path'); var webpack = require('webpack'); // var HtmlWebpackPlugin = require('html-webpack-plugin'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); module.exports = { entry: { app: './src/index.js' }, resolve: { alias: { // Lib: path.resolve(__dirname, 'demo/lib/'), // Shaders: path.resolve(__dirname, 'demo/lib/src/shaders') } }, output: { filename: '[name].js', path: path.resolve(__dirname, '../build'), }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|jpg|gif)$/, use: [ 'file-loader' ] }, { test: /\.(glsl|vs|fs)$/, use: [ 'shader-loader' ] } ], // loaders: [ // { // test: /\.glsl$/, // loader: "webpack-glsl" // }, // ] }, plugins: [ // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false, // drop_console: false, // } // }) // new UglifyJSPlugin() // new HtmlWebpackPlugin({ // title: "glAvatar demo" // }) ], devServer: { contentBase: path.join(__dirname, "demo"), port: 7777 } }; ================================================ FILE: gulpfile.js ================================================ (function(){ 'use strict'; var jshint = require('gulp-jshint'); var uglify = require('gulp-uglify'); var rename = require("gulp-rename"); var gulp = require('gulp'); var jsHintFiles = [ '**/*.js', '**/*.html', '!node_modules/**', '!src/third-party/**', '!build/**' ]; // gulp.task('default', function() { // // place code for your default task here // }); gulp.task('default', ['jsHint']); gulp.task('jsHint', function() { return gulp.src(jsHintFiles) .pipe(jshint.extract('auto')) .pipe(jshint()) .pipe(jshint.reporter('jshint-stylish')) .pipe(jshint.reporter('fail')); }); gulp.task('jsHint-watch', function() { gulp.watch(jsHintFiles).on('change', function(event) { gulp.src(event.path) .pipe(jshint.extract('auto')) .pipe(jshint()) .pipe(jshint.reporter('jshint-stylish')); }); }); gulp.task('compress', function() { return gulp.src('src/minimal-gltf-loader.js') .pipe(uglify()) .pipe(rename({suffix: '.min'})) .pipe(gulp.dest('build')); }); })(); ================================================ FILE: package.json ================================================ { "name": "minimal-gltf-loader", "version": "0.1.0", "description": "A minimal JavaScript glTF Loader without need of 3D engines like Three.js.", "main": "build/minimal-gltf-loader.js", "directories": { "example": "examples" }, "scripts": { "test": "gulp jsHint", "build-examples": "webpack --config examples/webpack.config.js", "build-examples-watch": "webpack --config examples/webpack.config.js --watch", "build": "webpack", "build-watch": "webpack --watch", "dev-server": "node_modules/.bin/webpack-dev-server" }, "repository": { "type": "git", "url": "git+https://github.com/shrekshao/minimal-gltf-loader.git" }, "keywords": [ "glTF", "WebGL" ], "author": "shrekshao", "license": "MIT", "bugs": { "url": "https://github.com/shrekshao/minimal-gltf-loader/issues" }, "homepage": "https://github.com/shrekshao/minimal-gltf-loader#readme", "devDependencies": { "css-loader": "^0.28.7", "file-loader": "^0.11.2", "gulp": "^3.9.1", "gulp-jshint": "^2.0.1", "gulp-rename": "^1.2.2", "gulp-uglify": "^1.5.3", "jshint": "^2.9.2", "jshint-stylish": "^2.2.0", "shader-loader": "^1.3.1", "style-loader": "^0.18.2", "webpack": "^3.5.6", "webpack-glsl-loader": "^1.0.1" }, "dependencies": { "gl-matrix": "^3.4.3" } } ================================================ FILE: src/glTFLoader.ts ================================================ import { vec3, mat4, quat } from "gl-matrix" type GLTFID = number; enum MeshPrimitiveType { POINTS = 0, LINES = 1, LINE_LOOP = 2, LINE_STRIP = 3, TRIANGLES = 4, TRIANGLE_STRIP = 5, TRIANGLE_FAN = 6 } enum AccessorComponentType { GL_BYTE = 5120, GL_UNSIGNED_BYTE = 5121, GL_SHORT = 5122, GL_UNSIGNED_SHORT = 5123, GL_INT = 5124, GL_UNSIGNED_INT = 5125, GL_FLOAT = 5126 }; enum AccessorSparseIndicesComponentType { GL_UNSIGNED_BYTE = 5121, GL_UNSIGNED_SHORT = 5123, GL_UNSIGNED_INT = 5125 } enum BufferViewTarget { ARRAY_BUFFER = 34962, ELEMENT_ARRAY_BUFFER = 34963 } enum SamplerMagnificationFilter { NEAREST = 9728, LINEAR = 9729 } enum SamplerMinificationFilter { NEAREST = 9728, LINEAR = 9729, NEAREST_MIPMAP_NEAREST = 9984, LINEAR_MIPMAP_NEAREST = 9985, NEAREST_MIPMAP_LINEAR = 9986, LINEAR_MIPMAP_LINEAR = 9987 } enum SamplerWrappingMode { CLAMP_TO_EDGE = 33071, MIRRORED_REPEAT = 33648, REPEAT = 10497 } interface AssetBase { copyright ?: string; generator ?: string; version : string; minVersion ?: string; extensions ?: any; extras ?: any; } interface SceneBase { nodes : GLTFID[]; name ?: string; extensions ?: any; extras ?: any; } interface NodeBase { camera ?: GLTFID; children ?: GLTFID[]; skin ?: GLTFID; matrix : mat4; mesh ?: GLTFID; translation ?: vec3; rotation ?: quat; scale ?: vec3; weights ?: number[]; name ?: string; extensions ?: any; extras ?: any; } interface MeshBase { primitives : MeshPrimitiveBase[]; weights ?: number[]; name ?: string; extensions ?: any; extras ?: any; } interface MeshPrimitiveBase { attributes : {POSITION ?: GLTFID, NORMAL ?: GLTFID, TEXCOORD_0 ?: GLTFID}; indices ?: GLTFID; material ?: GLTFID; mode ?: MeshPrimitiveType; targets ?: {POSITION ?: GLTFID, NORMAL ?: GLTFID, TANGENT ?: GLTFID}[]; extensions ?: any; extras ?: any; } interface AccessorBase { bufferView ?: GLTFID; byteOffset ?: number; componentType : AccessorComponentType; normalized ?: boolean; count : number; type : "SCALAR" | "VEC2" | "VEC3" | "VEC4" | "MAT2" | "MAT3" | "MAT4"; max ?: number[]; min ?: number[]; sparse ?: AccessorSparseBase; name ?: string; extensions ?: any; extras ?: any; } interface AccessorSparseBase { count : number; indices : AccessorSparseIndicesBase; values : AccessorSparseValuesBase; extensions ?: any; extras ?: any; } interface AccessorSparseIndicesBase { bufferView : GLTFID; byteOffset ?: number; componentType : AccessorSparseIndicesComponentType; extensions ?: any; extras ?: any; } interface AccessorSparseValuesBase { bufferView : GLTFID; byteOffset ?: number; extensions ?: any; extras ?: any; } interface BufferViewBase { buffer : GLTFID; byteOffset ?: number; byteLength : number; byteStride ?: number; target ?: BufferViewTarget; name ?: string; extensions ?: any; extras ?: any; } interface BufferBase { uri ?: string; byteLength : number; name ?: string; extensions ?: any; extras ?: any; } interface AnimationBase { channels : AnimationChannelBase[]; samplers : AnimationSamplerBase[]; name ?: string; extensions ?: any; extras ?: any; } interface AnimationChannelBase { sampler : GLTFID; target : AnimationChannelTargetBase; extensions ?: any; extras ?: any; } interface AnimationChannelTargetBase{ node ?: GLTFID; path : "translation" | "rotation" | "scale" | "weights"; extensions ?: any; extras ?: any; } interface AnimationSamplerBase { input : GLTFID; interpolation ?: "LINEAR" | "STEP" | "CUBICSPLINE"; output : GLTFID; extensions ?: any; extras ?: any; } interface CameraBase{ orthographic ?: CameraOrthographicBase; perspective ?: CameraPerspectiveBase; type : "perspective" | "orthographic"; name ?: string; extensions ?: any; extras ?: any; } interface CameraOrthographicBase { xmag : number; ymag : number; zfar : number; znear : number; extensions ?: any; extras ?: any; } interface CameraPerspectiveBase { aspectRatio ?: number; yfov : number; zfar ?: number; znear : number; extensions ?: any; extras ?: any; } interface TextureBase { sampler ?: GLTFID; source ?: GLTFID; name ?: string; extensions ?: any; extras ?: any; } interface ImageBase { uri ?: string; mimeType ?: "image/jpeg" | "image/png"; bufferView ?: GLTFID; name ?: string; extensions ?: any; extras ?: any; } interface SamplerBase { magFilter : SamplerMagnificationFilter; minFilter : SamplerMinificationFilter; wrapS : SamplerWrappingMode; wrapT : SamplerWrappingMode; name ?: string; extensions ?: any; extras ?: any; } interface MaterialBase { name ?: string; extensions ?: any; extras ?: any; pbrMetallicRoughness ?: MaterialPbrMetallicRoughnessBase; normalTexture ?: MaterialNormalTextureInfoBase; occlusionTexture ?: MaterialOcclusionTextureInfoBase; emissiveTexture ?: TextureInfoBase; emissiveFactor ?: number[]; alphaMode ?: "OPAQUE" | "MASK" | "BLEND"; alphaCutoff ?: number; doubleSided ?: boolean; } interface MaterialPbrMetallicRoughnessBase { baseColorFactor : number[]; baseColorTexture : TextureInfoBase; metallicFactor : number; roughnessFactor : number; metallicRoughnessTexture : TextureInfoBase; extensions ?: any; extras ?: any; } interface MaterialNormalTextureInfoBase { index ?: any; texCoord ?: any; scale ?: number; extensions ?: any; extras ?: any; } interface MaterialOcclusionTextureInfoBase { index ?: any; texCoord ?: any; strength ?: number; extensions ?: any; extras ?: any; } interface TextureInfoBase { index : GLTFID; texCoord ?: number; extensions ?: any; extras ?: any; } interface SkinBase { inverseBindMatrices ?: GLTFID; skeleton ?: GLTFID; joints : GLTFID[]; name ?: string; extensions ?: any; extras ?: any; } interface GLTFBase { asset : AssetBase; scenes ?: SceneBase[]; scene ?: GLTFID; nodes ?: NodeBase[]; meshes ?: MeshBase[]; accessors ?: AccessorBase[]; bufferViews ?: BufferViewBase[]; buffers ?: BufferBase[]; animations ?: AnimationBase[]; cameras ?: CameraBase[]; textures ?: TextureBase[]; images ?: ImageBase[]; samplers ?: SamplerBase[]; materials ?: MaterialBase[]; skins ?: SkinBase[]; extensions ?: any; extensionsRequired ?: string[]; extensionsUsed ?: string[]; extras ?: any; } interface BoundingBoxBase { min : vec3; max : vec3; transform : mat4; } class Scene { nodes : Node[]; name : string; extensions : any; extras : any; boundingBox : BoundingBox; constructor (sceneBase: SceneBase, gltf: GLTF) { const length = sceneBase.nodes.length; this.nodes = []; for (let i = 0; i < length; i++) { this.nodes.push(gltf.nodes[sceneBase.nodes[i]]); } this.name = (sceneBase.name !== undefined) ? sceneBase.name : null; this.extensions = (sceneBase.extensions !== undefined) ? sceneBase.extensions : null; this.extras = (sceneBase.extras !== undefined) ? sceneBase.extras : null; this.boundingBox = null; }; }; export class BoundingBox { min : vec3; max : vec3; transform : mat4; constructor(min?: vec3, max?: vec3, isClone?: boolean) { min = min || vec3.fromValues(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); max = max || vec3.fromValues(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY); if (isClone === undefined || isClone === true) { this.min = vec3.clone(min); this.max = vec3.clone(max); } else { this.min = min; this.max = max; } this.transform = mat4.create(); }; updateBoundingBox(boundingBoxBase: BoundingBoxBase): void { vec3.min(this.min, this.min, boundingBoxBase.min); vec3.max(this.max, this.max, boundingBoxBase.max); }; calculateTransform(): void { // transform from a unit cube whose min = (0, 0, 0) and max = (1, 1, 1) // scale this.transform[0] = this.max[0] - this.min[0]; this.transform[5] = this.max[1] - this.min[1]; this.transform[10] = this.max[2] - this.min[2]; // translate this.transform[12] = this.min[0]; this.transform[13] = this.min[1]; this.transform[14] = this.min[2]; }; } class Accessor { bufferView : BufferView; byteOffset : number; componentType : AccessorComponentType; normalized : boolean; count : number; type : "SCALAR" | "VEC2" | "VEC3" | "VEC4" | "MAT2" | "MAT3" | "MAT4"; max : number[]; min : number[]; sparse : AccessorSparseBase; name : string; extensions : any; extras : any; constructor(accessorBase: AccessorBase, bufferView: BufferView) { this.bufferView = bufferView; this.byteOffset = (accessorBase.byteOffset !== undefined) ? accessorBase.byteOffset : 0; this.componentType = accessorBase.componentType; this.normalized = (accessorBase.normalized !== undefined) ? accessorBase.normalized : false; this.count = accessorBase.count; this.type = accessorBase.type; this.max = accessorBase.max; this.min = accessorBase.min; this.sparse = (accessorBase.sparse !== undefined) ? accessorBase.sparse : null; this.name = (accessorBase.name !== undefined) ? accessorBase.name : null; this.extensions = (accessorBase.extensions !== undefined) ? accessorBase.extensions : null; this.extras = (accessorBase.extras !== undefined) ? accessorBase.extras : null; } prepareVertexAttribute(gl: WebGL2RenderingContext, location: number): void { gl.vertexAttribPointer( location, glTFLoaderBasic.accessorTypeToNumComponents(this.type), this.componentType, this.normalized, this.bufferView.byteStride, this.byteOffset ) gl.enableVertexAttribArray(location) } } class BufferView { buffer : WebGLBuffer; byteOffset : number; byteLength : number; byteStride : number; target : BufferViewTarget; name : string; extensions : any; extras : any; data : ArrayBuffer; constructor(bufferViewBase: BufferViewBase, bufferData: ArrayBuffer) { this.buffer = null; this.byteOffset = (bufferViewBase.byteOffset !== undefined) ? bufferViewBase.byteOffset : 0; this.byteLength = bufferViewBase.byteLength; this.byteStride = (bufferViewBase.byteStride !== undefined) ? bufferViewBase.byteStride : 0; this.target = (bufferViewBase.target !== undefined) ? bufferViewBase.target : 0; this.name = (bufferViewBase.name !== undefined) ? bufferViewBase.name : null; this.extensions = (bufferViewBase.extensions !== undefined) ? bufferViewBase.extensions : null; this.extras = (bufferViewBase.extras !== undefined) ? bufferViewBase.extras : null; this.data = bufferData.slice(this.byteOffset, this.byteOffset + this.byteLength); } createBuffer(gl: WebGL2RenderingContext): void { this.buffer = gl.createBuffer() } bindData(gl:WebGL2RenderingContext): void { const target = this.target || BufferViewTarget.ARRAY_BUFFER gl.bindBuffer(target, this.buffer); gl.bufferData(target, this.data, gl.STATIC_DRAW); gl.bindBuffer(target, null); } } class Camera { orthographic : CameraOrthographicBase; perspective : CameraPerspectiveBase; type : "perspective" | "orthographic"; name : string; extensions : any; extras : any; constructor(cameraBase: CameraBase) { this.orthographic = (cameraBase.orthographic !== undefined) ? cameraBase.orthographic: null; this.perspective = (cameraBase.perspective !== undefined) ? cameraBase.perspective : null; this.type = cameraBase.type; this.name = (cameraBase.name !== undefined) ? cameraBase.name : null; this.extensions = (cameraBase.extensions !== undefined) ? cameraBase.extensions : null; this.extras = (cameraBase.extras !== undefined) ? cameraBase.extras : null; } } export class Node { camera : GLTFID; children : Node[]; skin : Skin; translation : vec3; rotation : quat; scale : vec3; matrix : mat4; mesh : Mesh; weights : number[]; name : string; extensions : any; extras : any; nodeID : GLTFID; childrenID : GLTFID[]; parent : Node; skinLink : SkinLink; modelMatrix : mat4; worldMatrix : mat4; aabb : BoundingBox; bvh : BoundingBox; constructor(nodeBase: NodeBase, nodeID: GLTFID, currentLoader: GLTFLoader) { this.camera = (nodeBase.camera !== undefined) ? nodeBase.camera : null; this.children = []; this.skin = null; this.translation = (nodeBase.translation !== undefined) ? nodeBase.translation : vec3.create(); this.rotation = (nodeBase.rotation !== undefined) ? nodeBase.rotation : quat.create(); this.scale = (nodeBase.scale !== undefined) ? nodeBase.scale : vec3.fromValues(1.0, 1.0, 1.0); this.matrix = (nodeBase.matrix !== undefined) ? mat4.clone(nodeBase.matrix) : mat4.fromRotationTranslationScale(mat4.create(), this.rotation, this.translation, this.scale); this.mesh = (nodeBase.mesh !== undefined) ? currentLoader.glTF.meshes[nodeBase.mesh] : null; this.weights = (nodeBase.weights !== undefined) ? nodeBase.weights : null; this.name = (nodeBase.name !== undefined) ? nodeBase.name : null; this.extensions = (nodeBase.extensions !== undefined) ? nodeBase.extensions : null; this.extras = (nodeBase.extras !== undefined) ? nodeBase.extras : null; this.nodeID = nodeID; this.childrenID = (nodeBase.children !== undefined) ? nodeBase.children : []; this.parent = null; this.modelMatrix = mat4.clone(this.matrix); this.worldMatrix = mat4.clone(this.matrix); if (nodeBase.extensions !== undefined) { if (nodeBase.extensions.gl_avatar !== undefined && currentLoader.enableGLAvatar === true) { const linkedSkinID : number = currentLoader._glTF.extensions.gl_avatar.skins[nodeBase.extensions.gl_avatar.skin.name]; const linkedSkin : Skin = currentLoader.skeletonGLTF.skins[linkedSkinID]; this.skinLink = new SkinLink(linkedSkin, currentLoader.glTF, nodeBase.extensions.gl_avatar.skin.inverseBindMatrices); } else { this.skinLink = null; } } this.aabb = null; this.bvh = new BoundingBox(); }; traverse(traverseFunction: Function, parent?: Node): void { parent = (parent === undefined) ? null : parent; traverseFunction(this, parent); for (let i = 0, len = this.children.length; i < len; i++) { this.children[i].traverse(traverseFunction, this); } }; traversePostOrder(traverseFunction: Function, parent: Node): void { parent = (parent === undefined) ? null : parent; for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traversePostOrder(traverseFunction, this); } traverseFunction(this, parent); }; traverseTwoFunction(traverseFunctionPreOrder: Function, traverseFunctionPostOrder: Function, parent?: Node): void { parent = (parent === undefined) ? null : parent; traverseFunctionPreOrder(this, parent); for (let i = 0, len = this.children.length; i < len; i++) { this.children[i].traverseTwoFunction(traverseFunctionPreOrder, traverseFunctionPostOrder, this); } traverseFunctionPostOrder(this, parent); }; } class Mesh { primitives : MeshPrimitive[]; weights : number[]; name : string; extensions : any; extras : any; boundingBox : BoundingBox; meshID : number; constructor(meshBase: MeshBase, meshID: number, currentLoader: GLTFLoader) { this.primitives = []; this.weights = (meshBase.weights !== undefined) ? meshBase.weights : null; this.name = (meshBase.name !== undefined) ? meshBase.name : null; this.extensions = (meshBase.extensions !== undefined) ? meshBase.extensions : null; this.extras = (meshBase.extras !== undefined) ? meshBase.extras : null; this.boundingBox = null; let primitiveBase : MeshPrimitiveBase, primitive : MeshPrimitive; for (let i = 0; i < meshBase.primitives.length; i++) { primitiveBase = meshBase.primitives[i]; primitive = new MeshPrimitive(primitiveBase, currentLoader.glTF, currentLoader); this.primitives.push(primitive); if (primitive.boundingBox) { if (!this.boundingBox) { this.boundingBox = new BoundingBox() } this.boundingBox.updateBoundingBox(primitive.boundingBox); } } if (this.boundingBox) { this.boundingBox.calculateTransform(); } this.meshID = meshID; } } export class MeshPrimitive { attributesID : {POSITION ?: GLTFID , NORMAL ?: GLTFID, TEXCOORD_0 ?: GLTFID}; attributes : {POSITION ?: Accessor , NORMAL ?: Accessor, TEXCOORD_0 ?: Accessor}; indicesID : GLTFID; indices : Accessor; material : Material; mode : MeshPrimitiveType; targetsID : {POSITION ?: GLTFID, NORMAL ?: GLTFID, TANGENT ?: GLTFID}[]; targets : {POSITION ?: Accessor, NORMAL ?: Accessor, TANGENT ?: Accessor}[]; extensions : any; extras : any; drawIndices : Accessor; vertexArray : ArrayBuffer; vertexBuffer : ArrayBuffer; shader : WebGLShader; boundingBox : BoundingBox; constructor(primitiveBase: MeshPrimitiveBase, gltf: GLTF, currentLoader: GLTFLoader) { this.attributesID = primitiveBase.attributes; if (primitiveBase.extensions !== undefined) { if (primitiveBase.extensions.gl_avatar !== undefined && currentLoader.enableGLAvatar === true) { if (primitiveBase.extensions.gl_avatar.attributes) { for (let attributeName in primitiveBase.extensions.gl_avatar.attributes) { this.attributesID[attributeName] = primitiveBase.extensions.gl_avatar.attributeName[attributeName]; } } } } this.attributes = {POSITION : null , NORMAL : null, TEXCOORD_0 : null}; for (let attributeName in this.attributesID) { this.attributes[attributeName] = gltf.accessors[this.attributesID[attributeName]]; } if (this.attributes.POSITION !== undefined) { let accessor = this.attributes.POSITION; if (accessor.max) { if (accessor.type === "VEC3") { this.boundingBox = new BoundingBox( vec3.fromValues(accessor.min[0], accessor.min[1], accessor.min[2]), vec3.fromValues(accessor.max[0], accessor.max[1], accessor.max[2]), false ); this.boundingBox.calculateTransform(); } } } this.indicesID = (primitiveBase.indices !== undefined) ? primitiveBase.indices : null; if (this.indicesID !== null) { this.indices = gltf.accessors[this.indicesID]; } else { this.drawIndices = gltf.accessors[this.attributesID.POSITION]; } this.material = (primitiveBase.material !== undefined) ? gltf.materials[primitiveBase.material] : null; this.mode = (primitiveBase.mode !== undefined) ? primitiveBase.mode : MeshPrimitiveType.TRIANGLES; this.targetsID = (primitiveBase.targets !== undefined) ? primitiveBase.targets : null; for (let targetID in this.targetsID) { const currentTarget = {POSITION : null , NORMAL : null, TEXCOORD_0 : null}; // for (let attributeName in targetID) { // this.targets // } } this.extensions = (primitiveBase.extensions !== undefined) ? primitiveBase.extensions : null; this.extras = (primitiveBase.extras !== undefined) ? primitiveBase.extras : null; this.vertexArray = null; this.vertexBuffer = null; this.shader = null; } } class Texture { sampler : Sampler; source : ImageBitmap | ImageData | HTMLImageElement; name : string; extensions : any; extras : any; texture : WebGLTexture; constructor(textureBase: TextureBase, currentLoader: GLTFLoader) { this.sampler = (textureBase.sampler !== undefined) ? currentLoader.glTF.samplers[textureBase.sampler] : null; this.source = (textureBase.sampler !== undefined) ? currentLoader.glTF.images[textureBase.source] : null; this.name = (textureBase.name !== undefined) ? textureBase.name : null; this.extensions = (textureBase.extensions !== undefined) ? textureBase.extensions : null; this.extras = (textureBase.extras !== undefined) ? textureBase.extras : null; this.texture = null; } createTexture(gl: WebGL2RenderingContext): void { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D( gl.TEXTURE_2D, // assumed 0, // Level of details gl.RGBA, // Internalformat gl.RGBA, // Format gl.UNSIGNED_BYTE, // Size of each channel this.source ); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); } } class Sampler { magFilter : SamplerMagnificationFilter; minFilter : SamplerMinificationFilter; wrapS : SamplerWrappingMode; wrapT : SamplerWrappingMode; name : string; extensions : any; extras : any; // FIXME: // 当前版本typescipt不支持接口WebGLSampler 等待升级 // sampler : WebGLSampler; sampler : any; constructor(samplerBase: SamplerBase) { this.magFilter = (samplerBase.magFilter !== undefined) ? samplerBase.magFilter : null; this.minFilter = (samplerBase.minFilter !== undefined) ? samplerBase.minFilter : null; this.wrapS = (samplerBase.wrapS !== undefined) ? samplerBase.wrapS : SamplerWrappingMode.REPEAT; this.wrapT = (samplerBase.wrapT !== undefined) ? samplerBase.wrapT : SamplerWrappingMode.REPEAT; this.name = (samplerBase.name !== undefined) ? samplerBase.name : null; this.extensions = (samplerBase.extensions !== undefined) ? samplerBase.extensions : null; this.extras = (samplerBase.extras !== undefined) ? samplerBase.extras : null; this.sampler = null; } createSampler(gl: WebGL2RenderingContext) { this.sampler = gl.createSampler(); if (this.minFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, this.minFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); } if (this.magFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, this.magFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR); } gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_S, this.wrapS); gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_T, this.wrapT); } } class TextureInfo { index : GLTFID; texCoord : number; extensions : any; extras : any; constructor(textureInfoBase: TextureInfoBase) { this.index = textureInfoBase.index; this.texCoord = (textureInfoBase.texCoord !== undefined) ? textureInfoBase.texCoord : 0 ; this.extensions = (textureInfoBase.extensions !== undefined) ? textureInfoBase.extensions : null; this.extras = (textureInfoBase.extras !== undefined) ? textureInfoBase.extras : null; } } class Material { name : string; extensions : any; extras : any; pbrMetallicRoughness : MaterialPbrMetallicRoughness; normalTexture : MaterialNormalTextureInfo; occlusionTexture : MaterialOcclusionTextureInfo; emissiveTexture : TextureInfo; emissiveFactor : number[]; alphaMode : "OPAQUE" | "MASK" | "BLEND"; alphaCutoff : number; doubleSided : boolean; constructor(materialBase: MaterialBase) { this.name = (materialBase.name !== undefined) ? materialBase.name : null; this.extensions = (materialBase.extensions !== undefined) ? materialBase.extensions : null; this.extras = (materialBase.extras !== undefined) ? materialBase.extras : null; this.pbrMetallicRoughness = (materialBase.pbrMetallicRoughness !== undefined) ? new MaterialPbrMetallicRoughness(materialBase.pbrMetallicRoughness) : new MaterialPbrMetallicRoughness({ baseColorFactor : [1, 1, 1, 1], baseColorTexture : null, metallicFactor : 1, roughnessFactor : 1, metallicRoughnessTexture : null, }); this.normalTexture = (materialBase.normalTexture !== undefined) ? new MaterialNormalTextureInfo(materialBase.normalTexture) : null; this.occlusionTexture = (materialBase.occlusionTexture !== undefined) ? new MaterialOcclusionTextureInfo(materialBase.occlusionTexture) : null; this.emissiveTexture = (materialBase.emissiveTexture !== undefined) ? new TextureInfo(materialBase.emissiveTexture) : null; this.emissiveFactor = (materialBase.emissiveFactor !== undefined) ? materialBase.emissiveFactor : [0, 0, 0]; this.alphaMode = (materialBase.alphaMode !== undefined) ? materialBase.alphaMode : "OPAQUE"; this.alphaCutoff = (materialBase.alphaCutoff !== undefined) ? materialBase.alphaCutoff : 0.5; this.doubleSided = !!materialBase.doubleSided; } } class MaterialPbrMetallicRoughness { baseColorFactor : number[]; baseColorTexture : TextureInfoBase; metallicFactor : number; roughnessFactor : number; metallicRoughnessTexture : TextureInfoBase; extensions : any; extras : any; constructor(materialPbrMetallicRoughnessBase: MaterialPbrMetallicRoughnessBase) { this.baseColorFactor = (materialPbrMetallicRoughnessBase.baseColorFactor !== undefined) ? materialPbrMetallicRoughnessBase.baseColorFactor : [1, 1, 1, 1]; this.baseColorTexture = (materialPbrMetallicRoughnessBase.baseColorTexture !== undefined) ? new TextureInfo(materialPbrMetallicRoughnessBase.baseColorTexture): null; this.metallicFactor = (materialPbrMetallicRoughnessBase.metallicFactor !== undefined) ? materialPbrMetallicRoughnessBase.metallicFactor : 1; this.roughnessFactor = (materialPbrMetallicRoughnessBase.roughnessFactor !== undefined) ? materialPbrMetallicRoughnessBase.roughnessFactor : 1; this.metallicRoughnessTexture = (materialPbrMetallicRoughnessBase.metallicRoughnessTexture !== undefined) ? new TextureInfo(materialPbrMetallicRoughnessBase.metallicRoughnessTexture): null; this.extensions = (materialPbrMetallicRoughnessBase.extensions !== undefined) ? materialPbrMetallicRoughnessBase.extensions : null; this.extras = (materialPbrMetallicRoughnessBase.extras !== undefined) ? materialPbrMetallicRoughnessBase.extras : null; } } class MaterialNormalTextureInfo { index : any; texCoord : any; scale : number; extensions : any; extras : any; constructor(materialNormalTextureInfoBase: MaterialNormalTextureInfoBase) { this.index = (materialNormalTextureInfoBase.index !== undefined) ? materialNormalTextureInfoBase.index : 0; this.texCoord = (materialNormalTextureInfoBase.texCoord !== undefined) ? materialNormalTextureInfoBase.texCoord : 0; this.scale = (materialNormalTextureInfoBase.scale !== undefined) ? materialNormalTextureInfoBase.scale : 1; this.extensions = (materialNormalTextureInfoBase.extensions !== undefined) ? materialNormalTextureInfoBase.extensions : null; this.extras = (materialNormalTextureInfoBase.extras !== undefined) ? materialNormalTextureInfoBase.extras : null; } } class MaterialOcclusionTextureInfo { index : any; texCoord : any; strength : number; extensions : any; extras : any; constructor(materialOcclusionTextureInfoBase: MaterialOcclusionTextureInfoBase) { this.index = (materialOcclusionTextureInfoBase.index !== undefined) ? materialOcclusionTextureInfoBase.index : 0; this.texCoord = (materialOcclusionTextureInfoBase.texCoord !== undefined) ? materialOcclusionTextureInfoBase.texCoord : 0; this.strength = (materialOcclusionTextureInfoBase.strength !== undefined) ? materialOcclusionTextureInfoBase.strength : 1; this.extensions = (materialOcclusionTextureInfoBase.extensions !== undefined) ? materialOcclusionTextureInfoBase.extensions : null; this.extras = (materialOcclusionTextureInfoBase.extras !== undefined) ? materialOcclusionTextureInfoBase.extras : null; } } class Skin { inverseBindMatrices : Accessor; skeleton : Node; joints : Node[]; name : string; extensions : any; extras : any; isLink : boolean; inverseBindMatricesData : Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array; inverseBindMatrix : mat4[]; constructor(skinBase: SkinBase, gltf: GLTF) { this.inverseBindMatrices = (skinBase.inverseBindMatrices !== undefined) ? gltf.accessors[skinBase.inverseBindMatrices] : null; this.skeleton = (skinBase.skeleton !== undefined) ? gltf.nodes[skinBase.skeleton] : null; this.joints = []; for (let i = 0; i < skinBase.joints.length; i++) { this.joints.push(gltf.nodes[skinBase.joints[i]]); } this.name = (skinBase.name !== undefined) ? skinBase.name : null; this.extensions = (skinBase.extensions !== undefined) ? skinBase.extensions : null; this.extras = (skinBase.extras !== undefined) ? skinBase.extras : null; this.isLink = false; if (this.inverseBindMatrices) { this.inverseBindMatricesData = glTFLoaderBasic.getAccessorData(this.inverseBindMatrices); this.inverseBindMatrix = []; for(let i = 0; i < this.inverseBindMatricesData.length; i += 16) { this.inverseBindMatrix.push( mat4.fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15], ) ); } } } } class SkinLink { inverseBindMatrices : Accessor; skeleton : Node; joints : Node[]; name : string; extensions : any; extras : any; isLink : boolean inverseBindMatricesData : Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array; inverseBindMatrix : mat4[]; constructor(linkedSkin: Skin, gltf: GLTF, inverseBindMatricesAccessorID?: number) { if (!gltf.skins) { gltf.skins = []; } gltf.skins.push(this); this.inverseBindMatrices = (inverseBindMatricesAccessorID !== undefined) ? gltf.accessors[inverseBindMatricesAccessorID] : null; this.skeleton = linkedSkin.skeleton; this.joints = linkedSkin.joints; this.name = linkedSkin.name; this.extensions = linkedSkin.extensions; this.extras = linkedSkin.extras; this.isLink = true; if (this.inverseBindMatrices) { this.inverseBindMatricesData = glTFLoaderBasic.getAccessorData(this.inverseBindMatrices); this.inverseBindMatrix = []; for(let i = 0; i < this.inverseBindMatricesData.length; i += 16) { this.inverseBindMatrix.push( mat4.fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15], ) ); } } } } export class Animation { samplers : AnimationSampler[]; channels : AnimationChannel[]; name : string; extensions : any; extras : any; constructor(animationBase: AnimationBase, gltf: GLTF) { this.samplers = []; for (let i = 0; i < animationBase.samplers.length; i++) { this.samplers.push(new AnimationSampler(animationBase.samplers[i], gltf)); } this.channels = []; for (let i = 0; i < animationBase.channels.length; i++) { this.channels.push(new AnimationChannel(animationBase.channels[i], this)); } this.name = (animationBase.name !== undefined) ? animationBase.name : null; this.extensions = (animationBase.extensions !== undefined) ? animationBase.extensions : null; this.extras = (animationBase.extras !== undefined) ? animationBase.extras : null; } } export class AnimationChannel { sampler : AnimationSampler; target : AnimationChannelTarget; extensions : any; extras : any; constructor(animationChannelBase: AnimationChannelBase, animation: Animation) { this.sampler = animation.samplers[animationChannelBase.sampler]; this.target = new AnimationChannelTarget(animationChannelBase.target); this.extensions = (animationChannelBase.extensions !== undefined) ? animationChannelBase.extensions : null; this.extras = (animationChannelBase.extras !== undefined) ? animationChannelBase.extras : null; } } class AnimationChannelTarget { node : Node; path : "translation" | "rotation" | "scale" | "weights"; extensions : any; extras : any; nodeID : GLTFID; constructor(animationChannelTargetBase: AnimationChannelTargetBase) { //id, to be hooked up to object later this.nodeID = animationChannelTargetBase.node; this.path = animationChannelTargetBase.path; this.extensions = (animationChannelTargetBase.extensions !== undefined) ? animationChannelTargetBase.extensions : null; this.extras = (animationChannelTargetBase.extras !== undefined) ? animationChannelTargetBase.extras : null; } } export class AnimationSampler { input : Accessor; interpolation : "LINEAR" | "STEP" | "CUBICSPLINE"; output : Accessor; extensions : any; extras : any; keyFrameIndices : Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array; keyFrameRaw : Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array; keyFrames : {src: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array, dst: Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array}; currentIndex : number; startTime : number; endTime : number; duration : number; constructor(animationSamplerBase: AnimationSamplerBase, gltf: GLTF) { this.input = gltf.accessors[animationSamplerBase.input]; this.interpolation = (animationSamplerBase.interpolation !== undefined) ? animationSamplerBase.interpolation : "LINEAR"; this.output = gltf.accessors[animationSamplerBase.output]; this.extensions = (animationSamplerBase.extensions !== undefined) ? animationSamplerBase.extensions : null; this.extras = (animationSamplerBase.extras !== undefined) ? animationSamplerBase.extras : null; this.keyFrameIndices = glTFLoaderBasic.getAccessorData(this.input); this.keyFrameRaw = glTFLoaderBasic.getAccessorData(this.output); this.keyFrames = {src: null, dst: null}; this.currentIndex = 0; this.startTime = this.keyFrameIndices[0]; this.endTime = this.keyFrameIndices[this.keyFrameIndices.length - 1]; this.duration = this.endTime - this.startTime; } updateKeyFrames(time: number): void { while (this.currentIndex < this.keyFrameIndices.length - 2 && time >= this.keyFrameIndices[this.currentIndex + 1]) { this.currentIndex++; } const byteLength = glTFLoaderBasic.accessorTypeToNumComponents(this.output.type); this.keyFrames.src = this.keyFrameRaw.slice(this.currentIndex * byteLength, (this.currentIndex + 1) * byteLength); this.keyFrames.dst = this.keyFrameRaw.slice((this.currentIndex + 1) * byteLength, (this.currentIndex + 2) * byteLength); if (time >= this.endTime) { this.currentIndex = 0; } } } export class GLTF { asset : AssetBase; scene ?: Scene; scenes ?: Scene[]; nodes ?: Node[]; meshes ?: Mesh[]; accessors ?: Accessor[]; bufferViews ?: BufferView[]; buffers ?: ArrayBuffer[]; animations ?: Animation[]; cameras ?: Camera[]; textures ?: Texture[]; images ?: (ImageBitmap | ImageData | HTMLImageElement)[]; samplers ?: Sampler[]; materials ?: Material[]; skins ?: (Skin | SkinLink)[]; extensions ?: any; extensionsUsed ?: string[]; extensionsRequired ?: string[]; extras ?: any; constructor(glTFBase: GLTFBase) { this.asset = glTFBase.asset; this.scene = null; this.scenes = (glTFBase.scenes !== undefined) ? [] : null; this.nodes = (glTFBase.nodes !== undefined) ? [] : null; this.meshes = (glTFBase.meshes !== undefined) ? [] : null; this.accessors = (glTFBase.accessors !== undefined) ? [] : null; this.bufferViews = (glTFBase.bufferViews !== undefined) ? [] : null; this.buffers = (glTFBase.buffers !== undefined) ? [] : null; this.animations = (glTFBase.animations !== undefined) ? [] : null; this.cameras = (glTFBase.cameras !== undefined) ? [] : null; this.textures = (glTFBase.textures !== undefined) ? [] : null; this.images = (glTFBase.images !== undefined) ? [] : null; this.samplers = (glTFBase.samplers !== undefined) ? [] : null; this.materials = (glTFBase.materials !== undefined) ? [] : null; this.skins = (glTFBase.skins !== undefined) ? [] : null; this.extensions = (glTFBase.extensions !== undefined) ? glTFBase.extensions : null; this.extensionsUsed = (glTFBase.extensionsUsed !== undefined) ? glTFBase.extensionsUsed : null; this.extensionsRequired = (glTFBase.extensionsRequired !== undefined) ? glTFBase.extensionsRequired : null; this.extras = (glTFBase.extras !== undefined) ? glTFBase.extras : null; } } export class GLTFLoader { _glTF : GLTFBase; glTF : GLTF; baseUri : string; enableGLAvatar : boolean; skeletonGLTF : GLTF; gl : WebGL2RenderingContext; constructor(gl: WebGL2RenderingContext) { this.glTF = null; this.enableGLAvatar = false; this.skeletonGLTF = null; this.gl = gl; } /** * Get base URL from the given URL * @param {url} string The original URL * @returns {string} The base URL */ public getBaseUri(uri: string): string { // https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Core/getBaseUri.js let basePath: string = ""; if (uri.lastIndexOf('/') !== -1) { basePath = uri.substring(0, uri.lastIndexOf('/') + 1); } return basePath; } /** * infer attribute target for BufferView whether ARRAY_BUFFER or ELEMENT_ARRAY_BUFFER * @param {glTF} GLTF The glTF need to be inferred * @returns {void} */ private inferBufferViewTarget(): void { this._glTF.meshes.forEach((mesh: MeshBase) => { mesh.primitives.forEach((primitive: MeshPrimitiveBase) => { // set bufferView.target for POSITION, NORMAL, and TEXCOORD_0 for (const [attributeName, accessorIndex] of Object.entries(primitive.attributes)) { if (attributeName === "POSITION" || attributeName === "NORMAL" || attributeName === "TEXCOORD_0") { this._glTF.bufferViews[this._glTF.accessors[accessorIndex].bufferView].target = BufferViewTarget.ARRAY_BUFFER } } if (primitive.indices !== undefined) { const bufferView = this._glTF.bufferViews[this._glTF.accessors[primitive.indices].bufferView]; if (bufferView.target !== undefined) { if (bufferView.target !== BufferViewTarget.ELEMENT_ARRAY_BUFFER) console.warn("BufferView " + primitive.indices + " should have a target equal to ELEMENT_ARRAY_BUFFER"); } else { bufferView.target = BufferViewTarget.ELEMENT_ARRAY_BUFFER; } } }) }) } private postProcess():void { this.inferBufferViewTarget(); // 挂载 BufferView if (this._glTF.bufferViews !== undefined) { for (let i = 0; i < this._glTF.bufferViews.length; i++) { const bufferView = new BufferView(this._glTF.bufferViews[i], this.glTF.buffers[this._glTF.bufferViews[i].buffer]); bufferView.createBuffer(this.gl); bufferView.bindData(this.gl); this.glTF.bufferViews.push(bufferView); } } // 挂载 Accessor if (this._glTF.accessors !== undefined) { for (let i = 0; i < this._glTF.accessors.length; i++) { this.glTF.accessors.push(new Accessor(this._glTF.accessors[i], this.glTF.bufferViews[this._glTF.accessors[i].bufferView])); } } // 挂载 Camera if (this._glTF.cameras !== undefined) { for (let i = 0; i < this._glTF.cameras.length; i++) { this.glTF.cameras.push(new Camera(this._glTF.cameras[i])) } } // 挂载 Material if (this._glTF.materials !== undefined) { for (let i = 0; i < this._glTF.materials.length; i++) { this.glTF.materials.push(new Material(this._glTF.materials[i])); } } // 挂载 Sampler if (this._glTF.samplers !== undefined) { for (let i = 0; i < this._glTF.samplers.length; i++) { this.glTF.samplers.push(new Sampler(this._glTF.samplers[i])); } } // 挂载 Texture if (this._glTF.textures !== undefined) { for (let i = 0; i < this._glTF.textures.length; i++) { this.glTF.textures.push(new Texture(this._glTF.textures[i], this)); this.glTF.textures[i].createTexture(this.gl); } } // 挂载 Mesh if (this._glTF.meshes !== undefined) { for (let i = 0; i < this._glTF.meshes.length; i++) { this.glTF.meshes.push(new Mesh(this._glTF.meshes[i], i, this)); } } // 挂载 Node if (this._glTF.nodes !== undefined) { for (let i = 0; i < this._glTF.nodes.length; i++) { this.glTF.nodes.push(new Node(this._glTF.nodes[i], i, this)); } // 为每个 Node 挂载 Node.children this.glTF.nodes.forEach(currentNode => { for (let i = 0; i < currentNode.childrenID.length; i++) { currentNode.children[i] = this.glTF.nodes[currentNode.childrenID[i]]; currentNode.children[i].parent = currentNode; } }); // 挂载 Scene if (this._glTF.scenes !== undefined) { for (let i = 0; i < this._glTF.scenes.length; i++) { this.glTF.scenes[i] = new Scene(this._glTF.scenes[i], this.glTF); this.glTF.scenes[i].boundingBox = new BoundingBox(); const nodeMatrices : mat4[] = new Array(this.glTF.nodes.length); for (let j = 0; j < this.glTF.scenes[i].nodes.length; j++) { this.glTF.scenes[i].nodes[j].traverseTwoFunction( (node: Node, parent: Node) => { if (parent !== null) { mat4.multiply(nodeMatrices[node.nodeID], nodeMatrices[parent.nodeID], node.modelMatrix) } else { nodeMatrices[node.nodeID] = mat4.clone(node.modelMatrix); } }, (node: Node, parent: Node) => { if (node.mesh) { node.worldMatrix = mat4.clone(nodeMatrices[node.nodeID]); if (node.mesh.boundingBox) { node.aabb = getAABBFromOBB(node.mesh.boundingBox, nodeMatrices[node.nodeID]); if (node.children.length === 0) { node.bvh.min = vec3.clone(node.aabb.min); node.bvh.max = vec3.clone(node.aabb.max); } } } if (parent !== null) { parent.bvh.min = vec3.min(parent.bvh.min, parent.bvh.min, node.bvh.min); parent.bvh.max = vec3.max(parent.bvh.max, parent.bvh.max, node.bvh.max); } else { vec3.min(this.glTF.scenes[i].boundingBox.min, this.glTF.scenes[i].boundingBox.min, node.bvh.min); vec3.max(this.glTF.scenes[i].boundingBox.max, this.glTF.scenes[i].boundingBox.max, node.bvh.max); } } ) } this.glTF.scenes[i].boundingBox.calculateTransform(); } if (this._glTF.scene !== undefined) { this.glTF.scene = this.glTF.scenes[this._glTF.scene]; } else { this.glTF.scene = this.glTF.scenes[0]; } } for (let i = 0; i < this.glTF.nodes.length; i++) { if (this.glTF.nodes[i].bvh !== null) { this.glTF.nodes[i].bvh.calculateTransform(); } } } // 挂载 Animation if (this._glTF.animations) { for (let i = 0; i < this._glTF.animations.length; i++) { this.glTF.animations.push(new Animation(this._glTF.animations[i], this.glTF)); this.glTF.animations[i].channels.forEach((channel) => { channel.target.node = this.glTF.nodes[channel.target.nodeID]; }) } } // 挂载 Skin if (this._glTF.skins) { for (let i = 0; i < this._glTF.skins.length; i++) { this.glTF.skins.push(new Skin(this._glTF.skins[i], this.glTF)); } for (let i = 0; i < this.glTF.nodes.length; i++) { if (this.glTF.nodes[i].skin !== null) { if (typeof this._glTF.nodes[this.glTF.nodes[i].nodeID].skin) { // usual skin, hook up this.glTF.nodes[i].skin = this.glTF.skins[this._glTF.nodes[this.glTF.nodes[i].nodeID].skin]; } else { // assume gl_avatar is in use then do nothing } } } } } public async loadGLTF(uri: string): Promise { this.baseUri = this.getBaseUri(uri); try { const glTFBase : GLTFBase = await fetch(new Request(uri)).then((response: Response) => { if (response.ok) { console.log(response) return response.json(); } throw Error("LoadingError: Error occured in loading glTF JSON."); }); this._glTF = glTFBase; this.glTF = new GLTF(glTFBase); } catch (error) { console.error(error); } const loadBuffer : Promise = new Promise(async (resolve) => { if (this._glTF.buffers) { const bufferPromises : Promise[] = []; for (const bufferInfo of this._glTF.buffers) { try { bufferPromises.push(fetch (new Request(this.baseUri + bufferInfo.uri) ).then((response: Response) => { if (response.ok) { return response.arrayBuffer(); } throw Error("LoadingError: Error occured in loading buffers."); })); } catch (error) { console.error(error); } } for (const [bufferID, buffer] of bufferPromises.entries()) { this.glTF.buffers[bufferID] = await buffer; console.log(`image ${bufferID} complete`); } } resolve(true); }); const loadImage : Promise = new Promise(async (resolve) => { if (this._glTF.images) { const imagePromises : Promise[] = []; for (const imageInfo of this._glTF.images) { try { imagePromises.push(fetch (new Request(this.baseUri + imageInfo.uri) ).then((response: Response) => { if (response.ok) { return response.blob(); } throw Error("LoadingError: Error occured in loading images."); }).then((imageBlob: Blob) => { return createImageBitmap(imageBlob); })); } catch (error) { console.error(error); } } for (const [imageID, image] of imagePromises.entries()) { this.glTF.images[imageID] = await image; console.log(`image ${imageID} complete`); } } resolve(true); }); await loadBuffer; await loadImage; this.postProcess(); return this.glTF; } } export module glTFLoaderBasic { /** * Common utilities * @module loaderBasic */ /** * Get the count of components from the given accessor * @param {type} string The type of the given accessor * @returns {number} The count of components */ export function accessorTypeToNumComponents(type : string): number { const accessorMap = new Map([ ["SCALAR", 1], ["VEC2", 2], ["VEC3", 3], ["VEC4", 4], ["MAT2", 4], ["MAT3", 9], ["MAT4", 16] ]); if (accessorMap.has(type)) { return accessorMap.get(type); } throw new Error(`NOKEY ERROR: no numComponents for accessorType ${type}`); } /** * Get the typed array of the given accessor's component * @param {type} string The component type of the given accessor * @returns {typedArrayConstructor} The constructor of the component's typed array */ export function glTypeToTypedArray(type: AccessorComponentType) { const typeMap = new Map([ [5120, Int8Array], // gl.BYTE [5121, Uint8Array], // gl.UNSIGNED_BYTE [5122, Int16Array], // gl.SHORT [5123, Uint16Array], // gl.UNSIGNED_SHORT [5124, Int32Array], // gl.INT [5125, Uint32Array], // gl.UNSIGNED_INT [5126, Float32Array] // gl.FLOAT ]); if (typeMap.has(type)) { return typeMap.get(type); } throw new Error(`NOKEY ERROR: no typedArray for glType ${type}`); } /** * Get the typed array of the given accessor's component * @param {type} string The component type of the given accessor * @returns {typedArrayConstructor} The constructor of the component's typed array */ export function getAccessorData(accessor: Accessor): Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array { const typedArray = glTFLoaderBasic.glTypeToTypedArray(accessor.componentType); return new typedArray( accessor.bufferView.data, accessor.byteOffset, accessor.count * glTFLoaderBasic.accessorTypeToNumComponents(accessor.type) ); } } // get Axis-Aligned Bounding Boxes from Oriented Bounding Boxes function getAABBFromOBB(obb: BoundingBox, matrix: mat4): BoundingBox{ let transformRight : vec3 = vec3.fromValues(matrix[0], matrix[1], matrix[2]); let transformUp : vec3 = vec3.fromValues(matrix[4], matrix[5], matrix[6]); let transformBackward : vec3 = vec3.fromValues(matrix[8], matrix[9], matrix[10]); let tmpVec3a : vec3 = vec3.create(); let tmpVec3b : vec3 = vec3.create(); let min = vec3.fromValues(matrix[12], matrix[13], matrix[14]); // init with matrix translation let max = vec3.clone(min); vec3.scale(tmpVec3a, transformRight, obb.min[0]); vec3.scale(tmpVec3b, transformRight, obb.max[0]); vec3.min(transformRight, tmpVec3a, tmpVec3b); vec3.add(min, min, transformRight); vec3.max(transformRight, tmpVec3a, tmpVec3b); vec3.add(max, max, transformRight); tmpVec3a = vec3.scale(tmpVec3a, transformUp, obb.min[1]); tmpVec3b = vec3.scale(tmpVec3b, transformUp, obb.max[1]); vec3.min(transformUp, tmpVec3a, tmpVec3b); vec3.add(min, min, transformUp); vec3.max(transformUp, tmpVec3a, tmpVec3b); vec3.add(max, max, transformUp); tmpVec3a = vec3.scale(tmpVec3a, transformBackward, obb.min[2]); tmpVec3b = vec3.scale(tmpVec3b, transformBackward, obb.max[2]); vec3.min(transformBackward, tmpVec3a, tmpVec3b); vec3.add(min, min, transformBackward); vec3.max(transformBackward, tmpVec3a, tmpVec3b); vec3.add(max, max, transformBackward); let axisAlignedBoundingBox = new BoundingBox(min, max, false); axisAlignedBoundingBox.calculateTransform(); return axisAlignedBoundingBox; } ================================================ FILE: src/index.js ================================================ import {vec3, vec4, quat, mat4} from 'gl-matrix'; var MinimalGLTFLoader = require('../build/minimal-gltf-loader.js'); // require('./lib/minimal-gltf-loader.js'); import '../css/style.css'; // utils var Utils = Utils || {}; (function () { 'use strict'; Utils.getShaderSource = function(id) { return document.getElementById(id).textContent.replace(/^\s+|\s+$/g, ''); }; function createShader(gl, source, type) { var shader = gl.createShader(type); gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } Utils.createProgram = function(gl, vertexShaderSource, fragmentShaderSource) { var program = gl.createProgram(); var vshader = createShader(gl, vertexShaderSource, gl.VERTEX_SHADER); var fshader = createShader(gl, fragmentShaderSource, gl.FRAGMENT_SHADER); gl.attachShader(program, vshader); gl.deleteShader(vshader); gl.attachShader(program, fshader); gl.deleteShader(fshader); gl.linkProgram(program); var log = gl.getProgramInfoLog(program); if (log) { console.log(log); } log = gl.getShaderInfoLog(vshader); if (log) { console.log(log); } log = gl.getShaderInfoLog(fshader); if (log) { console.log(log); } return program; }; var loadImage = Utils.loadImage = function(url, onload) { var img = new Image(); img.crossOrigin = "Anonymous"; img.src = url; // img.onload = function() { // onload(img); // }; img.onload = onload; return img; }; Utils.loadImages = function(urls, onload) { var imgs = []; var imgsToLoad = urls.length; function onImgLoad() { if (--imgsToLoad <= 0) { onload(imgs); } } for (var i = 0; i < imgsToLoad; ++i) { imgs.push(loadImage(urls[i], onImgLoad)); } }; })(); (function() { 'use strict'; // var selectedGltfSampleModel = 'Drone'; var selectedGltfSampleModel = 'DamagedHelmet'; var drawBoundingBox = false; var boundingBoxType = 'obb'; var curAnimationId = 0; var playAllAnimationTogether = false; var animationSelectionList = document.getElementById("animations"); animationSelectionList.addEventListener("change", function() { curAnimationId = this.selectedIndex; }); document.getElementById("gltf-model").addEventListener("change", function() { // selectedGltfSampleModel = this.value; var uri = this.value; // if (selectedGltfSampleModel == 'Drone') { // uri = 'https://raw.githubusercontent.com/shrekshao/minimal-gltf-loader/store-drone-model/glTFs/glTF_version_2/buster_drone/scene.gltf'; // } else { // uri = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/' // + selectedGltfSampleModel // + '/glTF/' // + selectedGltfSampleModel // + '.gltf'; // } glTFLoader.loadGLTF(uri, function(glTF) { // var scene = scenes[0]; scenes = []; // TODO: delete gl resources // scene = null; setupScene(glTF); }); }); document.getElementById("bbox-toggle").addEventListener("change", function() { drawBoundingBox = this.checked; }); document.getElementById("play-all-animations").addEventListener("change", function() { playAllAnimationTogether = this.checked; }); document.getElementById("bbox-type").addEventListener("change", function() { boundingBoxType = this.value; }); var canvas = document.createElement('canvas'); // canvas.width = Math.min(window.innerWidth, window.innerHeight); // canvas.height = canvas.width; canvas.width = window.innerWidth; canvas.height = window.innerHeight; document.body.appendChild(canvas); var gl = canvas.getContext( 'webgl2', { antialias: true } ); var isWebGL2 = !!gl; if(!isWebGL2) { document.getElementById('info').innerHTML = 'WebGL 2 is not available. See How to get a WebGL 2 implementation'; return; } canvas.oncontextmenu = function (e) { e.preventDefault(); }; // Scene object for runtime renderer var Scene = function(glTFScene, glTF, id) { this.glTFScene = glTFScene; this.glTF = glTF; this.id = id; // runtime renderer context this.rootTransform = mat4.create(); // @temp, assume every node is in current scene this.nodeMatrix = new Array(glTF.nodes.length); var i, len; for(i = 0, len = this.nodeMatrix.length; i < len; i++) { this.nodeMatrix[i] = mat4.create(); } // TODO: runtime joint matrix }; var BOUNDING_BOX = { vertexData: new Float32Array([ 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0 ]), vertexArray: gl.createVertexArray(), vertexBuffer: gl.createBuffer(), program: Utils.createProgram(gl, require('./shaders/vs-bbox.glsl'), require('./shaders/fs-bbox.glsl')), positionLocation: 0, uniformMvpLocation: 0, draw: (function() { var MVP = mat4.create(); return (function(bbox, nodeTransform, V, P) { // gl.useProgram(this.program); mat4.mul(MVP, nodeTransform, bbox.transform); mat4.mul(MVP, V, MVP); mat4.mul(MVP, P, MVP); gl.uniformMatrix4fv(this.uniformMvpLocation, false, MVP); // gl.bindVertexArray(this.vertexArray); gl.drawArrays(gl.LINES, 0, 24); // gl.bindVertexArray(null); }); })() }; var defaultSampler = gl.createSampler(); gl.samplerParameteri(defaultSampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); gl.samplerParameteri(defaultSampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_S, gl.REPEAT); gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_T, gl.REPEAT); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_WRAP_R, gl.REPEAT); // gl.samplerParameterf(defaultSampler, gl.TEXTURE_MIN_LOD, -1000.0); // gl.samplerParameterf(defaultSampler, gl.TEXTURE_MAX_LOD, 1000.0); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_COMPARE_MODE, gl.NONE); // gl.samplerParameteri(defaultSampler, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); BOUNDING_BOX.uniformMvpLocation = gl.getUniformLocation(BOUNDING_BOX.program, "u_MVP"); gl.bindVertexArray(BOUNDING_BOX.vertexArray); gl.bindBuffer(gl.ARRAY_BUFFER, BOUNDING_BOX.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, BOUNDING_BOX.vertexData, gl.STATIC_DRAW); gl.vertexAttribPointer(BOUNDING_BOX.positionLocation, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(BOUNDING_BOX.positionLocation); gl.bindVertexArray(null); var BRDF_LUT = { texture: null, textureIndex: 29, createTexture: function (img) { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D( gl.TEXTURE_2D, // assumed 0, // Level of details gl.RG16F, // Format gl.RG, // gl.RGBA, // Format // gl.RGBA, // gl.UNSIGNED_BYTE, // Size of each channel gl.FLOAT, img ); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 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.bindTexture(gl.TEXTURE_2D, null); } } // Environment maps var CUBE_MAP = { textureIndex: 31, texture: null, // IBL textureIBLDiffuseIndex: 30, textureIBLDiffuse: null, // loading asset -------------------- // TODO: use webpack to pack these uris: [ '../textures/environment/px.jpg', '../textures/environment/nx.jpg', '../textures/environment/py.jpg', '../textures/environment/ny.jpg', '../textures/environment/pz.jpg', '../textures/environment/nz.jpg', // ibl diffuse '../textures/environment/diffuse/bakedDiffuse_01.jpg', '../textures/environment/diffuse/bakedDiffuse_02.jpg', '../textures/environment/diffuse/bakedDiffuse_03.jpg', '../textures/environment/diffuse/bakedDiffuse_04.jpg', '../textures/environment/diffuse/bakedDiffuse_05.jpg', '../textures/environment/diffuse/bakedDiffuse_06.jpg', // '../textures/papermill/environment_right_0.jpg', // '../textures/papermill/environment_left_0.jpg', // '../textures/papermill/environment_top_0.jpg', // '../textures/papermill/environment_bottom_0.jpg', // '../textures/papermill/environment_front_0.jpg', // '../textures/papermill/environment_back_0.jpg', // '../textures/papermill/diffuse/diffuse_right_0.jpg', // '../textures/papermill/diffuse/diffuse_left_0.jpg', // '../textures/papermill/diffuse/diffuse_top_0.jpg', // '../textures/papermill/diffuse/diffuse_bottom_0.jpg', // '../textures/papermill/diffuse/diffuse_front_0.jpg', // '../textures/papermill/diffuse/diffuse_back_0.jpg', // @tmp, ugly, load brdfLUT here '../textures/brdfLUT.png' ], images: null, loadAll: function() { Utils.loadImages(this.uris, this.onloadAll.bind(this)); }, onloadAll: function(imgs) { this.images = imgs; console.log('all cube maps loaded'); this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); for (var i = 0; i < 6; i++) { gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.images[i] ); } gl.generateMipmap(gl.TEXTURE_CUBE_MAP); gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); this.textureIBLDiffuse = gl.createTexture(); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.textureIBLDiffuse); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_MODE, gl.NONE); gl.texParameteri(gl.TEXTURE_CUBE_MAP, gl.TEXTURE_COMPARE_FUNC, gl.LEQUAL); for (var i = 0; i < 6; i++) { gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.images[i + 6] ); } gl.bindTexture(gl.TEXTURE_CUBE_MAP, null); // @tmp BRDF_LUT.createTexture(this.images[this.images.length - 1]); if (this.finishLoadingCallback) { this.finishLoadingCallback(); } }, finishLoadingCallback: null, // runtime stuffs ------------------------- vertexData: new Float32Array([ -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, 1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, -1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0 ]), vertexArray: gl.createVertexArray(), vertexBuffer: gl.createBuffer(), program: Utils.createProgram(gl, require('./shaders/vs-cube-map.glsl'), require('./shaders/fs-cube-map.glsl')), positionLocation: 0, uniformMvpLocation: 0, uniformEnvironmentLocation: 0, draw: (function() { var MVP = mat4.create(); return (function(V, P) { mat4.copy(MVP, V); MVP[12] = 0.0; MVP[13] = 0.0; MVP[14] = 0.0; MVP[15] = 1.0; mat4.mul(MVP, P, MVP); gl.useProgram(this.program); gl.activeTexture(gl.TEXTURE0 + this.textureIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.texture); gl.uniformMatrix4fv(this.uniformMvpLocation, false, MVP); gl.uniform1i(this.uniformEnvironmentLocation, this.textureIndex); gl.bindVertexArray(this.vertexArray); gl.drawArrays(gl.TRIANGLES, 0, 36); gl.bindVertexArray(null); }); })() }; CUBE_MAP.uniformMvpLocation = gl.getUniformLocation(CUBE_MAP.program, "u_MVP"); CUBE_MAP.uniformEnvironmentLocation = gl.getUniformLocation(CUBE_MAP.program, "u_environment"); gl.bindVertexArray(CUBE_MAP.vertexArray); gl.bindBuffer(gl.ARRAY_BUFFER, CUBE_MAP.vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, CUBE_MAP.vertexData, gl.STATIC_DRAW); gl.vertexAttribPointer(CUBE_MAP.positionLocation, 3, gl.FLOAT, false, 0, 0); gl.enableVertexAttribArray(CUBE_MAP.positionLocation); gl.bindVertexArray(null); var Shader_Static = { shaderVersionLine: '#version 300 es\n', bitMasks: { // vertex shader HAS_SKIN: 1, SKIN_VEC8: 2, // fragment shader HAS_BASECOLORMAP: 4, HAS_NORMALMAP: 8, HAS_METALROUGHNESSMAP: 16, HAS_OCCLUSIONMAP: 32, HAS_EMISSIVEMAP: 64 }, vsMasterCode: require('./shaders/vs-pbr-master.glsl'), fsMasterCode: require('./shaders/fs-pbr-master.glsl'), programObjects: {} // < flags, Shader Object > }; var Shader = function() { this.flags = 0; this.programObject = null; }; Shader.prototype.hasSkin = function() { return this.flags & Shader_Static.bitMasks.HAS_SKIN; }; Shader.prototype.hasBaseColorMap = function() { return this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP; }; Shader.prototype.hasNormalMap = function() { return this.flags & Shader_Static.bitMasks.HAS_NORMALMAP; }; Shader.prototype.hasMetalRoughnessMap = function() { return this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP; }; Shader.prototype.hasOcclusionMap = function() { return this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP; }; Shader.prototype.hasEmissiveMap = function() { return this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP; }; Shader.prototype.defineMacro = function(macro) { if (Shader_Static.bitMasks[macro] !== undefined) { this.flags = Shader_Static.bitMasks[macro] | this.flags; } else { console.log('WARNING: ' + macro + ' is not a valid macro'); } }; Shader.prototype.compile = function() { var existingProgramObject = Shader_Static.programObjects[this.flags]; if (existingProgramObject) { this.programObject = existingProgramObject; return; } // new program var vsDefine = ''; var fsDefine = ''; // define macros if (this.flags & Shader_Static.bitMasks.HAS_SKIN) { vsDefine += '#define HAS_SKIN\n'; } if (this.flags & Shader_Static.bitMasks.SKIN_VEC8) { vsDefine += '#define SKIN_VEC8\n'; } if (this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP) { fsDefine += '#define HAS_BASECOLORMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_NORMALMAP) { fsDefine += '#define HAS_NORMALMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP) { fsDefine += '#define HAS_METALROUGHNESSMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP) { fsDefine += '#define HAS_OCCLUSIONMAP\n'; } if (this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP) { fsDefine += '#define HAS_EMISSIVEMAP\n'; } // concat var vertexShaderSource = Shader_Static.shaderVersionLine + vsDefine + Shader_Static.vsMasterCode; var fragmentShaderSource = Shader_Static.shaderVersionLine + fsDefine + Shader_Static.fsMasterCode; // compile var program = Utils.createProgram(gl, vertexShaderSource, fragmentShaderSource); this.programObject = { program: program, uniformLocations: {}, uniformBlockIndices: {} }; // uniform block id if (this.flags & Shader_Static.bitMasks.HAS_SKIN) { this.programObject.uniformBlockIndices.JointMatrix = gl.getUniformBlockIndex(program, "JointMatrix"); } // uniform locations var us = this.programObject.uniformLocations; us.MVP = gl.getUniformLocation(program, 'u_MVP'); us.MVNormal = gl.getUniformLocation(program, 'u_MVNormal'); us.MV = gl.getUniformLocation(program, 'u_MV'); us.baseColorFactor = gl.getUniformLocation(program, 'u_baseColorFactor'); us.metallicFactor = gl.getUniformLocation(program, 'u_metallicFactor'); us.roughnessFactor = gl.getUniformLocation(program, 'u_roughnessFactor'); if (this.flags & Shader_Static.bitMasks.HAS_BASECOLORMAP) { us.baseColorTexture = gl.getUniformLocation(program, 'u_baseColorTexture'); } if (this.flags & Shader_Static.bitMasks.HAS_NORMALMAP) { us.normalTexture = gl.getUniformLocation(program, 'u_normalTexture'); us.normalTextureScale = gl.getUniformLocation(program, 'u_normalTextureScale'); } if (this.flags & Shader_Static.bitMasks.HAS_METALROUGHNESSMAP) { us.metallicRoughnessTexture = gl.getUniformLocation(program, 'u_metallicRoughnessTexture'); } if (this.flags & Shader_Static.bitMasks.HAS_OCCLUSIONMAP) { us.occlusionTexture = gl.getUniformLocation(program, 'u_occlusionTexture'); us.occlusionStrength = gl.getUniformLocation(program, 'u_occlusionStrength'); } if (this.flags & Shader_Static.bitMasks.HAS_EMISSIVEMAP) { us.emissiveTexture = gl.getUniformLocation(program, 'u_emissiveTexture'); us.emissiveFactor = gl.getUniformLocation(program, 'u_emissiveFactor'); } us.diffuseEnvSampler = gl.getUniformLocation(program, 'u_DiffuseEnvSampler'); us.specularEnvSampler = gl.getUniformLocation(program, 'u_SpecularEnvSampler'); us.brdfLUT = gl.getUniformLocation(program, 'u_brdfLUT'); // set static uniform values in cubemap gl.useProgram(program); gl.uniform1i(us.brdfLUT, BRDF_LUT.textureIndex); gl.uniform1i(us.specularEnvSampler, CUBE_MAP.textureIndex); gl.uniform1i(us.diffuseEnvSampler, CUBE_MAP.textureIBLDiffuseIndex); gl.useProgram(null); Shader_Static.programObjects[this.flags] = this.programObject; }; // -- Initialize vertex array var POSITION_LOCATION = 0; // set with GLSL layout qualifier var NORMAL_LOCATION = 1; // set with GLSL layout qualifier var TEXCOORD_0_LOCATION = 2; // set with GLSL layout qualifier var JOINTS_0_LOCATION = 3; // set with GLSL layout qualifier var JOINTS_1_LOCATION = 5; // set with GLSL layout qualifier var WEIGHTS_0_LOCATION = 4; // set with GLSL layout qualifier var WEIGHTS_1_LOCATION = 6; // set with GLSL layout qualifier // -- Mouse Behaviour var isDisplayRotation = true; var s = 1; var eulerX = 0; var eulerY = 0; // var s = 1; // var t = -100; var translate = vec3.create(); // var t = -5; var modelMatrix = mat4.create(); var mouseDown = false; var mouseButtonId = 0; var lastMouseY = 0; var lastMouseX = 0; var identityQ = quat.create(); window.onmousedown = function(event) { mouseDown = true; mouseButtonId = event.which; lastMouseY = event.clientY; lastMouseX = event.clientX; if (mouseButtonId === 1) { isDisplayRotation = false; } }; window.onmouseup = function(event) { mouseDown = false; isDisplayRotation = true; }; window.onmousemove = function(event) { if(!mouseDown) { return; } var newY = event.clientY; var newX = event.clientX; var deltaY = newY - lastMouseY; var deltaX = newX - lastMouseX; // s *= (1 + deltaY / 1000); switch(mouseButtonId) { case 1: // left: rotation eulerX += -deltaY * 0.01; eulerY += deltaX * 0.01; break; case 3: // right translate[0] += deltaX * 0.001; translate[1] += -deltaY * 0.001; break; } lastMouseY = newY; lastMouseX = newX; }; window.onwheel = function(event) { translate[2] += -event.deltaY * 0.001; // translate[2] *= 1 + (-event.deltaY * 0.01); }; // 2.0 // var gltfUrl = '../glTFs/glTF_version_2/Duck/glTF/Duck.gltf'; var gltfUrl = 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Models/master/2.0/DamagedHelmet/glTF/DamagedHelmet.gltf'; var glTFLoader = new MinimalGLTFLoader.glTFLoader(gl); var glTFModelCount = 1; var scenes = []; gl.enable(gl.CULL_FACE); gl.cullFace(gl.BACK); gl.frontFace(gl.CCW); var isFaceCulling = true; function setupScene(glTF, replaceScene) { var i, len; // update animation list for(i = animationSelectionList.options.length - 1 ; i >= 0 ; i--) { animationSelectionList.remove(i); } if (glTF.animations) { var option; for (i = 0, len = glTF.animations.length; i < len; i++) { option = document.createElement("option"); option.text = glTF.animations[i].name || i; animationSelectionList.add(option); } } curAnimationId = 0; // ---------------- var curGltfScene = glTF.scenes[glTF.defaultScene]; var sceneDeltaTranslate = vec3.fromValues(curGltfScene.boundingBox.transform[0] * 1.2, 0, 0); var tmpVec3Translate = vec3.create(); var newGltfRuntimeScene; if (!replaceScene) { newGltfRuntimeScene = new Scene(curGltfScene, glTF, scenes.length); scenes.push(newGltfRuntimeScene); } else { newGltfRuntimeScene = scenes[replaceScene.id] = new Scene(curGltfScene, glTF, replaceScene.id); } // for (i = 0, len = glTFModelCount; i < len; i++) { // scenes.push(new Scene(curGltfScene, glTF)); // // vec3.scale(tmpVec3Translate, sceneDeltaTranslate, i); // // mat4.fromTranslation(scenes[i].rootTransform, tmpVec3Translate); // } if (scenes.length === 1) { // first model, adjust camera mat4.identity(modelMatrix); // center s = 1.0 / Math.max( curGltfScene.boundingBox.transform[0], Math.max(curGltfScene.boundingBox.transform[5], curGltfScene.boundingBox.transform[10]) ); mat4.getTranslation(translate, curGltfScene.boundingBox.transform); vec3.scale(translate, translate, -1); translate[0] += - 0.5 * curGltfScene.boundingBox.transform[0]; translate[1] += - 0.5 * curGltfScene.boundingBox.transform[5]; translate[2] += - 0.5 * curGltfScene.boundingBox.transform[10]; s *= 0.5; modelMatrix[0] = s; modelMatrix[5] = s; modelMatrix[10] = s; mat4.translate(modelMatrix, modelMatrix, translate); vec3.set(translate, 0, 0, -1.5); s = 1; } // var in loop var mesh; var primitive; var vertexBuffer; var indexBuffer; var vertexArray; var nid, lenNodes; var mid, lenMeshes; var attribute; var material; var image, texture, sampler; var accessor, bufferView; var animation, animationSampler, channel; var skin; // create buffers for (i = 0, len = glTF.bufferViews.length; i < len; i++) { bufferView = glTF.bufferViews[i]; bufferView.createBuffer(gl); bufferView.bindData(gl); } // create textures if (glTF.textures) { for (i = 0, len = glTF.textures.length; i < len; i++) { texture = glTF.textures[i]; texture.createTexture(gl); } } // create samplers if (glTF.samplers) { for (i = 0, len = glTF.samplers.length; i < len; i++) { sampler = glTF.samplers[i]; sampler.createSampler(gl); } } if (glTF.skins) { // gl.useProgram(programSkinBaseColor.program); // gl.uniformBlockBinding(programSkinBaseColor.program, programSkinBaseColor.uniformBlockIndexJointMatrix, 0); // gl.useProgram(null); for (i = 0, len = glTF.skins.length; i < len; i++) { skin = glTF.skins[i]; skin.jointMatrixUniformBuffer = gl.createBuffer(); // gl.bindBufferBase(gl.UNIFORM_BUFFER, i, skin.jointMatrixUniformBuffer); gl.bindBufferBase(gl.UNIFORM_BUFFER, skin.uniformBlockID, skin.jointMatrixUniformBuffer); gl.bindBuffer(gl.UNIFORM_BUFFER, skin.jointMatrixUniformBuffer); gl.bufferData(gl.UNIFORM_BUFFER, skin.jointMatrixUnidormBufferData, gl.DYNAMIC_DRAW); gl.bufferSubData(gl.UNIFORM_BUFFER, 0, skin.jointMatrixUnidormBufferData); gl.bindBuffer(gl.UNIFORM_BUFFER, null); } } function setupAttribuite(attrib, location) { if (attrib !== undefined) { // var accessor = glTF.accessors[ attrib ]; var accessor = attrib; var bufferView = accessor.bufferView; if (bufferView.target === null) { // console.log('WARNING: the bufferview of this accessor should have a target, or it should represent non buffer data (like animation)'); gl.bindBuffer(gl.ARRAY_BUFFER, bufferView.buffer); gl.bufferData(gl.ARRAY_BUFFER, bufferView.data, gl.STATIC_DRAW); } else { gl.bindBuffer(bufferView.target, bufferView.buffer); } accessor.prepareVertexAttrib(location, gl); return true; } return false; } // create vaos & materials shader source setup for (mid = 0, lenMeshes = glTF.meshes.length; mid < lenMeshes; mid++) { mesh = glTF.meshes[mid]; // vertexArrayMaps[mid] = []; for (i = 0, len = mesh.primitives.length; i < len; ++i) { primitive = mesh.primitives[i]; primitive.shader = new Shader(); // WebGL2: create vertexArray primitive.vertexArray = vertexArray = gl.createVertexArray(); gl.bindVertexArray(vertexArray); setupAttribuite(primitive.attributes.POSITION, POSITION_LOCATION); setupAttribuite(primitive.attributes.NORMAL, NORMAL_LOCATION); // @tmp, should consider together with material setupAttribuite(primitive.attributes.TEXCOORD_0, TEXCOORD_0_LOCATION); if ( setupAttribuite(primitive.attributes.JOINTS_0, JOINTS_0_LOCATION) && setupAttribuite(primitive.attributes.WEIGHTS_0, WEIGHTS_0_LOCATION) ) { // assume these two attributes always appear together primitive.shader.defineMacro('HAS_SKIN'); } if ( setupAttribuite(primitive.attributes.JOINTS_1, JOINTS_1_LOCATION) && setupAttribuite(primitive.attributes.WEIGHTS_1, WEIGHTS_1_LOCATION) ) { // assume these two attributes always appear together primitive.shader.defineMacro('SKIN_VEC8'); } // indices ( assume use indices ) if (primitive.indices !== null) { accessor = glTF.accessors[ primitive.indices ]; bufferView = accessor.bufferView; if (bufferView.target === null) { // console.log('WARNING: the bufferview of this accessor should have a target, or it should represent non buffer data (like animation)'); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferView.buffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, bufferView.data, gl.STATIC_DRAW); } else { gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, bufferView.buffer); } } gl.bindVertexArray(null); gl.bindBuffer(gl.ARRAY_BUFFER, null); gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null); // material shader setup material = primitive.material; if (material) { if (material.pbrMetallicRoughness.baseColorTexture) { primitive.shader.defineMacro('HAS_BASECOLORMAP'); } if (material.pbrMetallicRoughness.metallicRoughnessTexture) { primitive.shader.defineMacro('HAS_METALROUGHNESSMAP'); } if (material.normalTexture) { primitive.shader.defineMacro('HAS_NORMALMAP'); } if (material.occlusionTexture) { primitive.shader.defineMacro('HAS_OCCLUSIONMAP'); } if (material.emissiveTexture) { primitive.shader.defineMacro('HAS_EMISSIVEMAP'); } } primitive.shader.compile(); } } return newGltfRuntimeScene; } // -- Render preparation gl.enable(gl.DEPTH_TEST); gl.depthFunc(gl.LEQUAL); var Renderer = Renderer || {}; var program = null; // current program object (function() { 'use strict'; var scale = vec3.create(); var r = 0.0; var rotationSpeedY= 0.01; // var rotationSpeedY= 0.0; var perspective = mat4.create(); mat4.perspective(perspective, 0.785, canvas.width / canvas.height, 0.01, 100); var modelView = mat4.create(); var localMV = mat4.create(); var localMVP = mat4.create(); var localMVNormal = mat4.create(); var VP = mat4.create(); var hasIndices = true; var hasSkin = false; var uniformBlockID; // same for uniform block binding id var curScene; function activeAndBindTexture(uniformLocation, textureInfo) { gl.uniform1i(uniformLocation, textureInfo.index); gl.activeTexture(gl.TEXTURE0 + textureInfo.index); var texture = curScene.glTF.textures[ textureInfo.index ]; gl.bindTexture(gl.TEXTURE_2D, texture.texture); var sampler; if (texture.sampler) { sampler = texture.sampler.sampler; } else { sampler = defaultSampler; } gl.bindSampler(textureInfo.index, sampler); } var defaultColor = [1.0, 1.0, 1.0, 1.0]; var drawPrimitive = Renderer.drawPrimitive = function(primitive, matrix) { mat4.multiply(localMV, modelView, matrix); mat4.multiply(localMVP, perspective, localMV); // mat4.multiply(localMVP, VP, matrix); mat4.invert(localMVNormal, localMV); mat4.transpose(localMVNormal, localMVNormal); var texture, sampler; var baseColor = defaultColor; var shader = primitive.shader; var material = primitive.material; if (material !== null) { var pbrMetallicRoughness = material.pbrMetallicRoughness; baseColor = pbrMetallicRoughness.baseColorFactor; if (primitive.material.doubleSided === isFaceCulling) { isFaceCulling = !primitive.material.doubleSided; if (isFaceCulling) { gl.enable(gl.CULL_FACE); } else { gl.disable(gl.CULL_FACE); } } } if (program != primitive.shader.programObject) { program = primitive.shader.programObject; gl.useProgram(program.program); } if (material) { // base color texture if (shader.hasBaseColorMap()) { activeAndBindTexture(program.uniformLocations.baseColorTexture, pbrMetallicRoughness.baseColorTexture); } // normal texture if (shader.hasNormalMap()) { activeAndBindTexture(program.uniformLocations.normalTexture, material.normalTexture); gl.uniform1f(program.uniformLocations.normalTextureScale, material.normalTexture.scale); } // metallic roughness texture if (shader.hasMetalRoughnessMap()) { activeAndBindTexture(program.uniformLocations.metallicRoughnessTexture, pbrMetallicRoughness.metallicRoughnessTexture); } gl.uniform1f(program.uniformLocations.metallicFactor, pbrMetallicRoughness.metallicFactor); gl.uniform1f(program.uniformLocations.roughnessFactor, pbrMetallicRoughness.roughnessFactor); // occlusion texture if (shader.hasOcclusionMap()) { activeAndBindTexture(program.uniformLocations.occlusionTexture, material.occlusionTexture); gl.uniform1f(program.uniformLocations.occlusionStrength, material.occlusionTexture.strength); } // emissive texture if (shader.hasEmissiveMap()) { activeAndBindTexture(program.uniformLocations.emissiveTexture, material.emissiveTexture); gl.uniform3fv(program.uniformLocations.emissiveFactor, material.emissiveFactor); } } // TODO: skin JointMatrix uniform block if (shader.hasSkin()) { gl.uniformBlockBinding(program.program, program.uniformBlockIndices.JointMatrix, uniformBlockID); } gl.activeTexture(gl.TEXTURE0 + BRDF_LUT.textureIndex); gl.bindTexture(gl.TEXTURE_2D, BRDF_LUT.texture); // console.log( (gl.getTexParameter(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S)).toString(16) ); gl.activeTexture(gl.TEXTURE0 + CUBE_MAP.textureIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, CUBE_MAP.texture); gl.activeTexture(gl.TEXTURE0 + CUBE_MAP.textureIBLDiffuseIndex); gl.bindTexture(gl.TEXTURE_CUBE_MAP, CUBE_MAP.textureIBLDiffuse); gl.uniform4fv(program.uniformLocations.baseColorFactor, baseColor); gl.uniformMatrix4fv(program.uniformLocations.MV, false, localMV); gl.uniformMatrix4fv(program.uniformLocations.MVP, false, localMVP); gl.uniformMatrix4fv(program.uniformLocations.MVNormal, false, localMVNormal); gl.bindVertexArray(primitive.vertexArray); if (primitive.indices !== null) { gl.drawElements(primitive.mode, primitive.indicesLength, primitive.indicesComponentType, primitive.indicesOffset); } else { gl.drawArrays(primitive.mode, primitive.drawArraysOffset, primitive.drawArraysCount); } gl.bindVertexArray(null); } var tmpMat4 = mat4.create(); var inverseTransformMat4 = mat4.create(); // @todo: // in a real engine, it is better to simply parse the node tree stucture // to compute transform matrices, // then sort node array by material and render use a for loop // to minimize context switch var drawNode = Renderer.drawNode = function (node, nodeID, nodeMatrix, parentModelMatrix) { var matrix = nodeMatrix[nodeID]; if (parentModelMatrix !== undefined) { mat4.mul(matrix, parentModelMatrix, node.matrix); } else { // from scene root, parent is identity mat4.copy(matrix, node.matrix); } // mat4.mul(matrix, parentModelMatrix, node.matrix); hasSkin = false; if (node.skin !== null) { // mesh node with skin hasSkin = true; var skin = node.skin; uniformBlockID = skin.uniformBlockID; var joints = node.skin.joints; var jointNode; mat4.invert(inverseTransformMat4, matrix); // @tmp: assume joint nodes are always in the front of the scene node list // so that their matrices are ready to use for (i = 0, len = joints.length; i < len; i++) { jointNode = joints[i]; mat4.mul(tmpMat4, nodeMatrix[jointNode.nodeID], skin.inverseBindMatrix[i]); mat4.mul(tmpMat4, inverseTransformMat4, tmpMat4); // if (skin.skeleton !== null) { // mat4.mul(tmpMat4, inverseSkeletonRootMat4, tmpMat4); // } skin.jointMatrixUnidormBufferData.set(tmpMat4, i * 16); } gl.bindBuffer(gl.UNIFORM_BUFFER, skin.jointMatrixUniformBuffer); gl.bufferSubData(gl.UNIFORM_BUFFER, 0, skin.jointMatrixUnidormBufferData, 0, skin.jointMatrixUnidormBufferData.length); } var i, len; // draw cur node's mesh if (node.mesh !== null) { // drawMesh(glTF.meshes[node.mesh], matrix); // var mesh = glTF.meshes[node.mesh]; var mesh = node.mesh; for (i = 0, len = mesh.primitives.length; i < len; i++) { // draw primitive drawPrimitive(mesh.primitives[i], matrix); } // BOUNDING_BOX.draw(mesh.boundingBox, matrix, modelView, perspective); // gl.useProgram(program); } if (node.skin !== null) { gl.bindBuffer(gl.UNIFORM_BUFFER, null); } // draw children var childNodeID; for (i = 0, len = node.children.length; i < len; i++) { // childNodeID = node.children[i]; // drawNode(glTF.nodes[childNodeID], childNodeID, matrix); drawNode(node.children[i], node.children[i].nodeID, nodeMatrix, matrix); } } function applyAnimation(animation, glTF) { var j, lenj; var channel, animationSampler, node; for (j = 0, lenj = animation.samplers.length; j < lenj; j++) { animation.samplers[j].getValue(timeParameter); } for (j = 0, lenj = animation.channels.length; j < lenj; j++) { channel = animation.channels[j]; animationSampler = channel.sampler; node = glTF.nodes[channel.target.nodeID]; switch (channel.target.path) { case 'rotation': vec4.copy(node.rotation, animationSampler.curValue); break; case 'translation': vec3.copy(node.translation, animationSampler.curValue); break; case 'scale': vec3.copy(node.scale, animationSampler.curValue); break; } node.updateMatrixFromTRS(); } } var drawScene = Renderer.drawScene = function (scene) { // animation var animation; var i, len; var glTF = scene.glTF; if (glTF.animations) { if (playAllAnimationTogether) { for (i = 0, len = glTF.animations.length; i < len; i++) { animation = glTF.animations[i]; applyAnimation(animation, glTF); } } else { animation = glTF.animations[curAnimationId]; applyAnimation(animation, glTF); } } for (var i = 0, len = scene.glTFScene.nodes.length; i < len; i++) { drawNode( scene.glTFScene.nodes[i], scene.glTFScene.nodes[i].nodeID, scene.nodeMatrix, scene.rootTransform ); } } var drawSceneBBox = Renderer.drawSceneBBox = function (glTF, scene, bboxType) { var node, mesh, bbox; // @temp: assume all nodes are in cur scene // @potential fix: can label each node's scene at the setup var i, len; for (i = 0, len = scene.nodeMatrix.length; i < len; i++) { node = glTF.nodes[i]; if (bboxType == 'bvh') { // bvh mat4.mul(localMVP, scene.rootTransform, node.bvh.transform); mat4.mul(localMVP, VP, localMVP); gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); gl.drawArrays(gl.LINES, 0, 24); } else if (node.mesh !== null) { // mesh = glTF.meshes[node.mesh]; mesh = node.mesh; if (bboxType == 'aabb') { // aabb mat4.mul(localMVP, scene.rootTransform, node.aabb.transform); mat4.mul(localMVP, VP, localMVP); } else { // obb (assume object node is static) mat4.mul(localMVP, scene.nodeMatrix[i], mesh.boundingBox.transform); mat4.mul(localMVP, VP, localMVP); } gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); gl.drawArrays(gl.LINES, 0, 24); } } // // scene bounding box // mat4.mul(localMVP, scene.rootTransform, scene.glTFScene.boundingBox.transform); // mat4.mul(localMVP, VP, localMVP); // gl.uniformMatrix4fv(BOUNDING_BOX.uniformMvpLocation, false, localMVP); // gl.drawArrays(gl.LINES, 0, 24); } var timeStampZero = performance.now(); var timeParameter = 0; // -- Render loop // function render() { var render = Renderer.render = function(timestamp) { var i, len; var j, lenj; var node; gl.clearColor(0.0, 0.0, 0.0, 1.0); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); vec3.set(scale, s, s, s); // mat4.identity(modelView); // mat4.translate(modelView, modelView, translate); // mat4.scale(modelView, modelView, scale); // mat4.fromRotationTranslationScale(modelView, identityQ, translate, scale); // mat4.mul(modelView, modelView, modelMatrix); mat4.identity(modelView); mat4.translate(modelView, modelView, translate); if (isDisplayRotation) { r += rotationSpeedY; } mat4.rotateX(modelView, modelView, eulerX); mat4.rotateY(modelView, modelView, r); mat4.scale(modelView, modelView, scale); mat4.mul(modelView, modelView, modelMatrix); mat4.rotateY(modelView, modelView, eulerY); mat4.mul(VP, perspective, modelView); for (i = 0, len = scenes.length; i < len; i++) { curScene = scenes[i]; drawScene(scenes[i]); } if (drawBoundingBox) { gl.useProgram(BOUNDING_BOX.program); gl.bindVertexArray(BOUNDING_BOX.vertexArray); for (i = 0, len = scenes.length; i < len; i++) { drawSceneBBox(scenes[i].glTF, scenes[i], boundingBoxType); } gl.bindVertexArray(null); } // cube map CUBE_MAP.draw(modelView, perspective); program = null; timeParameter = (timestamp - timeStampZero) * 0.001; requestAnimationFrame(render); } })(); CUBE_MAP.finishLoadingCallback = function() { glTFLoader.loadGLTF(gltfUrl, function(glTF) { setupScene(glTF); Renderer.render(); }); }; CUBE_MAP.loadAll(); })(); ================================================ FILE: src/minimal-gltf-loader.js ================================================ import {vec3, vec4, quat, mat4} from 'gl-matrix'; var MinimalGLTFLoader = MinimalGLTFLoader || {}; var globalUniformBlockID = 0; var curLoader = null; // @tmp, might be unsafe if loading multiple model at the same time var NUM_MAX_JOINTS = 65; // Data classes var Scene = MinimalGLTFLoader.Scene = function (gltf, s) { this.name = s.name !== undefined ? s.name : null; this.nodes = new Array(s.nodes.length); // root node object of this scene for (var i = 0, len = s.nodes.length; i < len; i++) { this.nodes[i] = gltf.nodes[s.nodes[i]]; } this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; this.boundingBox = null; }; /** * * @param {vec3} min * @param {vec3} max */ var BoundingBox = MinimalGLTFLoader.BoundingBox = function (min, max, isClone) { // this.min = min; // this.max = max; min = min || vec3.fromValues(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY); max = max || vec3.fromValues(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY); if (isClone === undefined || isClone === true) { this.min = vec3.clone(min); this.max = vec3.clone(max); } else { this.min = min; this.max = max; } this.transform = mat4.create(); }; BoundingBox.prototype.updateBoundingBox = function (bbox) { vec3.min(this.min, this.min, bbox.min); vec3.max(this.max, this.max, bbox.max); }; BoundingBox.prototype.calculateTransform = function () { // transform from a unit cube whose min = (0, 0, 0) and max = (1, 1, 1) // scale this.transform[0] = this.max[0] - this.min[0]; this.transform[5] = this.max[1] - this.min[1]; this.transform[10] = this.max[2] - this.min[2]; // translate this.transform[12] = this.min[0]; this.transform[13] = this.min[1]; this.transform[14] = this.min[2]; }; BoundingBox.getAABBFromOBB = (function() { var transformRight = vec3.create(); var transformUp = vec3.create(); var transformBackward = vec3.create(); var tmpVec3a = vec3.create(); var tmpVec3b = vec3.create(); return (function (obb, matrix) { vec3.set(transformRight, matrix[0], matrix[1], matrix[2]); vec3.set(transformUp, matrix[4], matrix[5], matrix[6]); vec3.set(transformBackward, matrix[8], matrix[9], matrix[10]); var min = vec3.fromValues(matrix[12], matrix[13], matrix[14]); // init with matrix translation var max = vec3.clone(min); vec3.scale(tmpVec3a, transformRight, obb.min[0]); vec3.scale(tmpVec3b, transformRight, obb.max[0]); vec3.min(transformRight, tmpVec3a, tmpVec3b); vec3.add(min, min, transformRight); vec3.max(transformRight, tmpVec3a, tmpVec3b); vec3.add(max, max, transformRight); vec3.scale(tmpVec3a, transformUp, obb.min[1]); vec3.scale(tmpVec3b, transformUp, obb.max[1]); vec3.min(transformUp, tmpVec3a, tmpVec3b); vec3.add(min, min, transformUp); vec3.max(transformUp, tmpVec3a, tmpVec3b); vec3.add(max, max, transformUp); vec3.scale(tmpVec3a, transformBackward, obb.min[2]); vec3.scale(tmpVec3b, transformBackward, obb.max[2]); vec3.min(transformBackward, tmpVec3a, tmpVec3b); vec3.add(min, min, transformBackward); vec3.max(transformBackward, tmpVec3a, tmpVec3b); vec3.add(max, max, transformBackward); var bbox = new BoundingBox(min, max, false); bbox.calculateTransform(); return bbox; }); })(); var Accessor = MinimalGLTFLoader.Accessor = function (a, bufferViewObject) { this.bufferView = bufferViewObject; this.componentType = a.componentType; // required this.byteOffset = a.byteOffset !== undefined ? a.byteOffset : 0; this.byteStride = bufferViewObject.byteStride; this.normalized = a.normalized !== undefined ? a.normalized : false; this.count = a.count; // required this.type = a.type; // required this.size = Type2NumOfComponent[this.type]; this.min = a.min; // @tmp assume required for now (for bbox) this.max = a.max; // @tmp assume required for now (for bbox) this.extensions = a.extensions !== undefined ? a.extensions : null; this.extras = a.extras !== undefined ? a.extras : null; }; Accessor.prototype.prepareVertexAttrib = function(location, gl) { gl.vertexAttribPointer( location, this.size, this.componentType, this.normalized, this.byteStride, this.byteOffset ); gl.enableVertexAttribArray(location); }; var BufferView = MinimalGLTFLoader.BufferView = function(bf, bufferData) { this.byteLength = bf.byteLength; //required this.byteOffset = bf.byteOffset !== undefined ? bf.byteOffset : 0; this.byteStride = bf.byteStride !== undefined ? bf.byteStride : 0; this.target = bf.target !== undefined ? bf.target : null; this.data = bufferData.slice(this.byteOffset, this.byteOffset + this.byteLength); this.extensions = bf.extensions !== undefined ? bf.extensions : null; this.extras = bf.extras !== undefined ? bf.extras : null; // runtime stuffs ------------- this.buffer = null; // gl buffer }; BufferView.prototype.createBuffer = function(gl) { this.buffer = gl.createBuffer(); }; BufferView.prototype.bindData = function(gl) { if (this.target) { gl.bindBuffer(this.target, this.buffer); gl.bufferData(this.target, this.data, gl.STATIC_DRAW); gl.bindBuffer(this.target, null); return true; } return false; }; var Camera = MinimalGLTFLoader.Camera = function(c) { this.name = c.name !== undefined ? c.name : null; this.type = c.type; // required this.othographic = c.othographic === undefined ? null : c.othographic; // every attribute inside is required (excluding extensions) this.perspective = c.perspective === undefined ? null : { yfov: c.perspective.yfov, znear: c.perspective.znear, zfar: c.perspective.zfar !== undefined ? c.perspective.zfar : null, aspectRatio: c.perspective.aspectRatio !== undefined ? c.perspective.aspectRatio : null }; this.extensions = c.extensions !== undefined ? c.extensions : null; this.extras = c.extras !== undefined ? c.extras : null; }; var Node = MinimalGLTFLoader.Node = function (n, nodeID) { this.name = n.name !== undefined ? n.name : null; this.nodeID = nodeID; // TODO: camera this.camera = n.camera !== undefined ? n.camera : null; this.matrix = mat4.create(); if (n.hasOwnProperty('matrix')) { for(var i = 0; i < 16; ++i) { this.matrix[i] = n.matrix[i]; } this.translation = vec3.create(); mat4.getTranslation(this.translation, this.matrix); this.rotation = quat.create(); mat4.getRotation(this.rotation, this.matrix); this.scale = vec3.create(); mat4.getScaling(this.scale, this.matrix); } else { // this.translation = null; // this.rotation = null; // this.scale = null; this.getTransformMatrixFromTRS(n.translation, n.rotation, n.scale); } this.children = n.children || []; // init as id, then hook up to node object later this.mesh = n.mesh !== undefined ? curLoader.glTF.meshes[n.mesh] : null; this.skin = n.skin !== undefined ? n.skin : null; // init as id, then hook up to skin object later if (n.extensions !== undefined) { if (n.extensions.gl_avatar !== undefined && curLoader.enableGLAvatar === true) { var linkedSkinID = curLoader.skeletonGltf.json.extensions.gl_avatar.skins[ n.extensions.gl_avatar.skin.name ]; var linkedSkin = curLoader.skeletonGltf.skins[linkedSkinID]; this.skin = new SkinLink(curLoader.glTF, linkedSkin, n.extensions.gl_avatar.skin.inverseBindMatrices); } } // TODO: morph targets weights this.weights = n.weights !== undefined ? n.weights : null; this.extensions = n.extensions !== undefined ? n.extensions : null; this.extras = n.extras !== undefined ? n.extras : null; // runtime stuffs-------------- this.aabb = null; // axis aligned bounding box, not need to apply node transform to aabb this.bvh = new BoundingBox(); }; Node.prototype.traverse = function(parent, executeFunc) { executeFunc(this, parent); for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traverse(this, executeFunc); } }; Node.prototype.traversePostOrder = function(parent, executeFunc) { for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traversePostOrder(this, executeFunc); } executeFunc(this, parent); }; Node.prototype.traverseTwoExecFun = function(parent, execFunPre, execFunPos) { execFunPre(this, parent); for (var i = 0, len = this.children.length; i < len; i++) { this.children[i].traverseTwoExecFun(this, execFunPre, execFunPos); } execFunPos(this, parent); }; var TRSMatrix = mat4.create(); Node.prototype.getTransformMatrixFromTRS = function(translation, rotation, scale) { this.translation = translation !== undefined ? vec3.fromValues(translation[0], translation[1], translation[2]) : vec3.fromValues(0, 0, 0); this.rotation = rotation !== undefined ? vec4.fromValues(rotation[0], rotation[1], rotation[2], rotation[3]) : vec4.fromValues(0, 0, 0, 1); this.scale = scale !== undefined ? vec3.fromValues(scale[0], scale[1], scale[2]) : vec3.fromValues(1, 1, 1); this.updateMatrixFromTRS(); }; Node.prototype.updateMatrixFromTRS = function() { mat4.fromRotationTranslation(TRSMatrix, this.rotation, this.translation); mat4.scale(this.matrix, TRSMatrix, this.scale); }; var Mesh = MinimalGLTFLoader.Mesh = function (m, meshID) { this.meshID = meshID; this.name = m.name !== undefined ? m.name : null; this.primitives = []; // required // bounding box (runtime stuff) this.boundingBox = null; var p, primitive, accessor; for (var i = 0, len = m.primitives.length; i < len; ++i) { p = m.primitives[i]; primitive = new Primitive(curLoader.glTF, p); this.primitives.push(primitive); // bounding box related if (primitive.boundingBox) { if (!this.boundingBox) { this.boundingBox = new BoundingBox(); } this.boundingBox.updateBoundingBox(primitive.boundingBox); } } if (this.boundingBox) { this.boundingBox.calculateTransform(); } // TODO: weights for morph targets this.weights = m.weights !== undefined ? m.weights : null; this.extensions = m.extensions !== undefined ? m.extensions : null; this.extras = m.extras !== undefined ? m.extras : null; }; var Primitive = MinimalGLTFLoader.Primitive = function (gltf, p) { // , required // get hook up with accessor object in _postprocessing this.attributes = p.attributes; this.indices = p.indices !== undefined ? p.indices : null; // accessor id var attname; if (p.extensions !== undefined) { if (p.extensions.gl_avatar !== undefined && curLoader.enableGLAvatar === true) { if (p.extensions.gl_avatar.attributes) { for ( attname in p.extensions.gl_avatar.attributes ) { this.attributes[attname] = p.extensions.gl_avatar.attributes[attname]; } } } } if (this.indices !== null) { this.indicesComponentType = gltf.json.accessors[this.indices].componentType; this.indicesLength = gltf.json.accessors[this.indices].count; this.indicesOffset = (gltf.json.accessors[this.indices].byteOffset || 0); } else { // assume 'POSITION' is there this.drawArraysCount = gltf.json.accessors[this.attributes.POSITION].count; this.drawArraysOffset = (gltf.json.accessors[this.attributes.POSITION].byteOffset || 0); } // hook up accessor object for ( attname in this.attributes ) { this.attributes[attname] = gltf.accessors[ this.attributes[attname] ]; } this.material = p.material !== undefined ? gltf.materials[p.material] : null; this.mode = p.mode !== undefined ? p.mode : 4; // default: gl.TRIANGLES // morph related this.targets = p.targets; this.extensions = p.extensions !== undefined ? p.extensions : null; this.extras = p.extras !== undefined ? p.extras : null; // ----gl run time related this.vertexArray = null; //vao this.vertexBuffer = null; this.indexBuffer = null; this.shader = null; this.boundingBox = null; if (this.attributes.POSITION !== undefined) { var accessor = this.attributes.POSITION; if (accessor.max) { // @todo: handle cases where no min max are provided // assume vec3 if (accessor.type === 'VEC3') { this.boundingBox = new BoundingBox( vec3.fromValues(accessor.min[0], accessor.min[1], accessor.min[2]), vec3.fromValues(accessor.max[0], accessor.max[1], accessor.max[2]), false ); this.boundingBox.calculateTransform(); } } } }; var Texture = MinimalGLTFLoader.Texture = function (t) { this.name = t.name !== undefined ? t.name : null; this.sampler = t.sampler !== undefined ? curLoader.glTF.samplers[t.sampler] : null; this.source = t.source !== undefined ? curLoader.glTF.images[t.source] : null; this.extensions = t.extensions !== undefined ? t.extensions : null; this.extras = t.extras !== undefined ? t.extras : null; // runtime this.texture = null; }; Texture.prototype.createTexture = function(gl) { this.texture = gl.createTexture(); gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D( gl.TEXTURE_2D, // assumed 0, // Level of details // gl.RGB, // Format // gl.RGB, gl.RGBA, // Format gl.RGBA, gl.UNSIGNED_BYTE, // Size of each channel this.source ); gl.generateMipmap(gl.TEXTURE_2D); gl.bindTexture(gl.TEXTURE_2D, null); }; var Sampler = MinimalGLTFLoader.Sampler = function (s) { this.name = s.name !== undefined ? s.name : null; this.magFilter = s.magFilter !== undefined ? s.magFilter : null; this.minFilter = s.minFilter !== undefined ? s.minFilter : null; this.wrapS = s.wrapS !== undefined ? s.wrapS : 10497; this.wrapT = s.wrapT !== undefined ? s.wrapT : 10497; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; this.sampler = null; }; Sampler.prototype.createSampler = function(gl) { this.sampler = gl.createSampler(); if (this.minFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, this.minFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MIN_FILTER, gl.NEAREST_MIPMAP_LINEAR); } if (this.magFilter) { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, this.magFilter); } else { gl.samplerParameteri(this.sampler, gl.TEXTURE_MAG_FILTER, gl.LINEAR); } gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_S, this.wrapS); gl.samplerParameteri(this.sampler, gl.TEXTURE_WRAP_T, this.wrapT); }; // Sampler.prototype.bindSampler = function(i, gl) { // gl.bindSampler(i, this.sampler); // } var TextureInfo = MinimalGLTFLoader.TextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var PbrMetallicRoughness = MinimalGLTFLoader.PbrMetallicRoughness = function (json) { this.baseColorFactor = json.baseColorFactor !== undefined ? json.baseColorFactor : [1, 1, 1, 1]; this.baseColorTexture = json.baseColorTexture !== undefined ? new TextureInfo(json.baseColorTexture): null; this.metallicFactor = json.metallicFactor !== undefined ? json.metallicFactor : 1 ; this.roughnessFactor = json.roughnessFactor !== undefined ? json.roughnessFactor : 1 ; this.metallicRoughnessTexture = json.metallicRoughnessTexture !== undefined ? new TextureInfo(json.metallicRoughnessTexture): null; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var NormalTextureInfo = MinimalGLTFLoader.NormalTextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.scale = json.scale !== undefined ? json.scale : 1 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var OcclusionTextureInfo = MinimalGLTFLoader.OcclusionTextureInfo = function (json) { this.index = json.index; this.texCoord = json.texCoord !== undefined ? json.texCoord : 0 ; this.strength = json.strength !== undefined ? json.strength : 1 ; this.extensions = json.extensions !== undefined ? json.extensions : null; this.extras = json.extras !== undefined ? json.extras : null; }; var Material = MinimalGLTFLoader.Material = function (m) { this.name = m.name !== undefined ? m.name : null; this.pbrMetallicRoughness = m.pbrMetallicRoughness !== undefined ? new PbrMetallicRoughness( m.pbrMetallicRoughness ) : new PbrMetallicRoughness({ baseColorFactor: [1, 1, 1, 1], metallicFactor: 1, metallicRoughnessTexture: 1 }); // this.normalTexture = m.normalTexture !== undefined ? m.normalTexture : null; this.normalTexture = m.normalTexture !== undefined ? new NormalTextureInfo(m.normalTexture) : null; this.occlusionTexture = m.occlusionTexture !== undefined ? new OcclusionTextureInfo(m.occlusionTexture) : null; this.emissiveTexture = m.emissiveTexture !== undefined ? new TextureInfo(m.emissiveTexture) : null; this.emissiveFactor = m.emissiveFactor !== undefined ? m.emissiveFactor : [0, 0, 0]; this.alphaMode = m.alphaMode !== undefined ? m.alphaMode : "OPAQUE"; this.alphaCutoff = m.alphaCutoff !== undefined ? m.alphaCutoff : 0.5; this.doubleSided = m.doubleSided || false; this.extensions = m.extensions !== undefined ? m.extensions : null; this.extras = m.extras !== undefined ? m.extras : null; }; var Skin = MinimalGLTFLoader.Skin = function (gltf, s, skinID) { this.name = s.name !== undefined ? s.name : null; this.skinID = skinID; this.joints = new Array(s.joints.length); // required var i, len; for (i = 0, len = this.joints.length; i < len; i++) { this.joints[i] = gltf.nodes[s.joints[i]]; } this.skeleton = s.skeleton !== undefined ? gltf.nodes[s.skeleton] : null; this.inverseBindMatrices = s.inverseBindMatrices !== undefined ? gltf.accessors[s.inverseBindMatrices] : null; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; // @tmp: runtime stuff should be taken care of renderer // since glTF model should only store info // runtime can have multiple instances of this glTF models this.uniformBlockID = globalUniformBlockID++; if (this.inverseBindMatrices) { // should be a mat4 this.inverseBindMatricesData = _getAccessorData(this.inverseBindMatrices); // this.inverseBindMatricesMat4 = mat4.fromValues(this.inverseBindMatricesData); this.inverseBindMatrix = []; // for calculation this.jointMatrixUniformBuffer = null; // this.jointMatrixUnidormBufferData = _arrayBuffer2TypedArray( // this.inverseBindMatricesData, // 0, // this.inverseBindMatricesData.length, // this.inverseBindMatrices.componentType // ); // for copy to UBO // @tmp: fixed length to coordinate with shader, for copy to UBO this.jointMatrixUnidormBufferData = new Float32Array(NUM_MAX_JOINTS * 16); for (i = 0, len = this.inverseBindMatricesData.length; i < len; i += 16) { this.inverseBindMatrix.push(mat4.fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15] )); } } }; var SkinLink = MinimalGLTFLoader.SkinLink = function (gltf, linkedSkin, inverseBindMatricesAccessorID) { this.isLink = true; if (!gltf.skins) { gltf.skins = []; } gltf.skins.push(this); this.name = linkedSkin.name; // this.skinID = linkedSkin.skinID; // use this for uniformblock id // this.skinID = gltf.skins.length - 1; // this.skinID = curLoader.skeletonGltf.skins.length + gltf.skins.length - 1; this.skinID = gltf.skins.length - 1; this.joints = linkedSkin.joints; this.skeleton = linkedSkin.skeleton; this.inverseBindMatrices = inverseBindMatricesAccessorID !== undefined ? gltf.accessors[inverseBindMatricesAccessorID] : null; // @tmp: runtime stuff should be taken care of renderer // since glTF model should only store info // runtime can have multiple instances of this glTF models this.uniformBlockID = globalUniformBlockID++; if (this.inverseBindMatrices) { // should be a mat4 this.inverseBindMatricesData = _getAccessorData(this.inverseBindMatrices); // this.inverseBindMatricesMat4 = mat4.fromValues(this.inverseBindMatricesData); this.inverseBindMatrix = []; // for calculation this.jointMatrixUniformBuffer = null; // this.jointMatrixUnidormBufferData = _arrayBuffer2TypedArray( // this.inverseBindMatricesData, // 0, // this.inverseBindMatricesData.length, // this.inverseBindMatrices.componentType // ); // for copy to UBO // @tmp: fixed length to coordinate with shader, for copy to UBO this.jointMatrixUnidormBufferData = new Float32Array(NUM_MAX_JOINTS * 16); for (var i = 0, len = this.inverseBindMatricesData.length; i < len; i += 16) { this.inverseBindMatrix.push(mat4.fromValues( this.inverseBindMatricesData[i], this.inverseBindMatricesData[i + 1], this.inverseBindMatricesData[i + 2], this.inverseBindMatricesData[i + 3], this.inverseBindMatricesData[i + 4], this.inverseBindMatricesData[i + 5], this.inverseBindMatricesData[i + 6], this.inverseBindMatricesData[i + 7], this.inverseBindMatricesData[i + 8], this.inverseBindMatricesData[i + 9], this.inverseBindMatricesData[i + 10], this.inverseBindMatricesData[i + 11], this.inverseBindMatricesData[i + 12], this.inverseBindMatricesData[i + 13], this.inverseBindMatricesData[i + 14], this.inverseBindMatricesData[i + 15] )); } } }; // animation has no potential plan for progressive rendering I guess // so everything happens after all buffers are loaded var Target = MinimalGLTFLoader.Target = function (t) { this.nodeID = t.node !== undefined ? t.node : null ; //id, to be hooked up to object later this.path = t.path; //required, string this.extensions = t.extensions !== undefined ? t.extensions : null; this.extras = t.extras !== undefined ? t.extras : null; }; var Channel = MinimalGLTFLoader.Channel = function (c, animation) { this.sampler = animation.samplers[c.sampler]; //required this.target = new Target(c.target); //required this.extensions = c.extensions !== undefined ? c.extensions : null; this.extras = c.extras !== undefined ? c.extras : null; }; var AnimationSampler = MinimalGLTFLoader.AnimationSampler = function (gltf, s) { this.input = gltf.accessors[s.input]; //required, accessor object this.output = gltf.accessors[s.output]; //required, accessor object this.inputTypedArray = _getAccessorData(this.input); this.outputTypedArray = _getAccessorData(this.output); // "LINEAR" // "STEP" // "CATMULLROMSPLINE" // "CUBICSPLINE" this.interpolation = s.interpolation !== undefined ? s.interpolation : 'LINEAR' ; this.extensions = s.extensions !== undefined ? s.extensions : null; this.extras = s.extras !== undefined ? s.extras : null; // ------- extra runtime info ----------- // runtime status thing this.curIdx = 0; // this.curValue = 0; this.curValue = vec4.create(); this.endT = this.inputTypedArray[this.inputTypedArray.length - 1]; this.inputMax = this.endT - this.inputTypedArray[0]; }; var animationOutputValueVec4a = vec4.create(); var animationOutputValueVec4b = vec4.create(); AnimationSampler.prototype.getValue = function (t) { if (t > this.endT) { t -= this.inputMax * Math.ceil((t - this.endT) / this.inputMax); this.curIdx = 0; } var len = this.inputTypedArray.length; while (this.curIdx <= len - 2 && t >= this.inputTypedArray[this.curIdx + 1]) { this.curIdx++; } if (this.curIdx >= len - 1) { // loop t -= this.inputMax; this.curIdx = 0; } // @tmp: assume no stride var count = Type2NumOfComponent[this.output.type]; var v4lerp = count === 4 ? quat.slerp: vec4.lerp; var i = this.curIdx; var o = i * count; var on = o + count; var u = Math.max( 0, t - this.inputTypedArray[i] ) / (this.inputTypedArray[i+1] - this.inputTypedArray[i]); for (var j = 0; j < count; j++ ) { animationOutputValueVec4a[j] = this.outputTypedArray[o + j]; animationOutputValueVec4b[j] = this.outputTypedArray[on + j]; } switch(this.interpolation) { case 'LINEAR': v4lerp(this.curValue, animationOutputValueVec4a, animationOutputValueVec4b, u); break; default: break; } }; var Animation = MinimalGLTFLoader.Animation = function (gltf, a) { this.name = a.name !== undefined ? a.name : null; var i, len; this.samplers = []; // required, array of animation sampler for (i = 0, len = a.samplers.length; i < len; i++) { this.samplers[i] = new AnimationSampler(gltf, a.samplers[i]); } this.channels = []; //required, array of channel for (i = 0, len = a.channels.length; i < len; i++) { this.channels[i] = new Channel(a.channels[i], this); } this.extensions = a.extensions !== undefined ? a.extensions : null; this.extras = a.extras !== undefined ? a.extras : null; }; /** * */ var glTFModel = MinimalGLTFLoader.glTFModel = function (gltf) { this.json = gltf; this.defaultScene = gltf.scene !== undefined ? gltf.scene : 0; this.version = Number(gltf.asset.version); if (gltf.accessors) { this.accessors = new Array(gltf.accessors.length); } if (gltf.bufferViews) { this.bufferViews = new Array(gltf.bufferViews.length); } if (gltf.scenes) { this.scenes = new Array(gltf.scenes.length); // store Scene object } if (gltf.nodes) { this.nodes = new Array(gltf.nodes.length); // store Node object } if (gltf.meshes) { this.meshes = new Array(gltf.meshes.length); // store mesh object } if (gltf.materials) { this.materials = new Array(gltf.materials.length); // store material object } if (gltf.textures) { this.textures = new Array(gltf.textures.length); } if (gltf.samplers) { this.samplers = new Array(gltf.samplers.length); } if (gltf.images) { this.images = new Array(gltf.images.length); } if (gltf.skins) { this.skins = new Array(gltf.skins.length); } if (gltf.animations) { this.animations = new Array(gltf.animations.length); } if (gltf.cameras) { this.cameras = new Array(gltf.cameras.length); } this.extensions = gltf.extensions !== undefined ? gltf.extensions : null; this.extras = gltf.extras !== undefined ? gltf.extras : null; }; var gl; var glTFLoader = MinimalGLTFLoader.glTFLoader = function (glContext) { gl = glContext !== undefined ? glContext : null; this._init(); this.glTF = null; this.enableGLAvatar = false; this.linkSkeletonGltf = null; }; glTFLoader.prototype._init = function() { this._loadDone = false; this._bufferRequested = 0; this._bufferLoaded = 0; this._buffers = []; this._bufferTasks = {}; this._shaderRequested = 0; this._shaderLoaded = 0; this._imageRequested = 0; this._imageLoaded = 0; this._pendingTasks = 0; this._finishedPendingTasks = 0; this.onload = null; curLoader = this; }; glTFLoader.prototype._checkComplete = function () { if (this._bufferRequested == this._bufferLoaded && // this._shaderRequested == this._shaderLoaded && this._imageRequested == this._imageLoaded // && other resources finish loading ) { this._loadDone = true; } if (this._loadDone && this._pendingTasks == this._finishedPendingTasks) { this._postprocess(); this.onload(this.glTF); } }; glTFLoader.prototype.loadGLTF_GL_Avatar_Skin = function (uri, skeletonGltf, callback) { this.enableGLAvatar = true; this.skeletonGltf = skeletonGltf; this.loadGLTF(uri, callback); }; /** * load a glTF model * * @param {String} uri uri of the .glTF file. Other resources (bins, images) are assumed to be in the same base path * @param {Function} callback the onload callback function */ glTFLoader.prototype.loadGLTF = function (uri, callback) { this._init(); this.onload = callback || function(glTF) { console.log('glTF model loaded.'); console.log(glTF); }; this.baseUri = _getBaseUri(uri); var loader = this; _loadJSON(uri, function (response) { // Parse JSON string into object var json = JSON.parse(response); loader.glTF = new glTFModel(json); var bid; var loadArrayBufferCallback = function (resource) { loader._buffers[bid] = resource; loader._bufferLoaded++; if (loader._bufferTasks[bid]) { var i,len; for (i = 0, len = loader._bufferTasks[bid].length; i < len; ++i) { (loader._bufferTasks[bid][i])(resource); } } loader._checkComplete(); }; // Launch loading resources task: buffers, etc. if (json.buffers) { for (bid in json.buffers) { loader._bufferRequested++; _loadArrayBuffer(loader.baseUri + json.buffers[bid].uri, loadArrayBufferCallback); } } // load images var loadImageCallback = function (img, iid) { loader._imageLoaded++; loader.glTF.images[iid] = img; loader._checkComplete(); }; var iid; if (json.images) { for (iid in json.images) { loader._imageRequested++; _loadImage(loader.baseUri + json.images[iid].uri, iid, loadImageCallback); } } loader._checkComplete(); }); }; glTFLoader.prototype._postprocess = function () { // if there's no plan for progressive loading (streaming) // than simply everything should be placed here // console.log('finish loading all assets, do a second pass postprocess'); curLoader = this; var i, leni, j, lenj; var scene, s; var node; var mesh, primitive, accessor; // cameras if (this.glTF.cameras) { for (i = 0, leni = this.glTF.cameras.length; i < leni; i++) { this.glTF.cameras[i] = new Camera(this.glTF.json.cameras[i]); } } // bufferviews if (this.glTF.bufferViews) { for (i = 0, leni = this.glTF.bufferViews.length; i < leni; i++) { this.glTF.bufferViews[i] = new BufferView(this.glTF.json.bufferViews[i], this._buffers[ this.glTF.json.bufferViews[i].buffer ]); } } // accessors if (this.glTF.accessors) { for (i = 0, leni = this.glTF.accessors.length; i < leni; i++) { this.glTF.accessors[i] = new Accessor(this.glTF.json.accessors[i], this.glTF.bufferViews[ this.glTF.json.accessors[i].bufferView ]); } } // load all materials if (this.glTF.materials) { for (i = 0, leni = this.glTF.materials.length; i < leni; i++) { this.glTF.materials[i] = new Material(this.glTF.json.materials[i]); } } // load all samplers if (this.glTF.samplers) { for (i = 0, leni = this.glTF.samplers.length; i < leni; i++) { this.glTF.samplers[i] = new Sampler(this.glTF.json.samplers[i]); } } // load all textures if (this.glTF.textures) { for (i = 0, leni = this.glTF.textures.length; i < leni; i++) { this.glTF.textures[i] = new Texture(this.glTF.json.textures[i]); } } // mesh for (i = 0, leni = this.glTF.meshes.length; i < leni; i++) { this.glTF.meshes[i] = new Mesh(this.glTF.json.meshes[i], i); } // node for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { this.glTF.nodes[i] = new Node(this.glTF.json.nodes[i], i); } // node: hook up children for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { node = this.glTF.nodes[i]; for (j = 0, lenj = node.children.length; j < lenj; j++) { node.children[j] = this.glTF.nodes[ node.children[j] ]; } } // scene Bounding box var nodeMatrix = new Array(this.glTF.nodes.length); for(i = 0, leni = nodeMatrix.length; i < leni; i++) { nodeMatrix[i] = mat4.create(); } function execUpdateTransform(n, parent) { var tmpMat4 = nodeMatrix[n.nodeID]; if (parent !== null) { mat4.mul(tmpMat4, nodeMatrix[parent.nodeID], n.matrix); } else { mat4.copy(tmpMat4, n.matrix); } } function execUpdateBBox(n, parent){ var tmpMat4 = nodeMatrix[n.nodeID]; var parentBVH; if (parent !== null) { parentBVH = parent.bvh; } else { parentBVH = scene.boundingBox; } if (n.mesh) { mesh = n.mesh; if (mesh.boundingBox) { n.aabb = BoundingBox.getAABBFromOBB(mesh.boundingBox, tmpMat4); if (n.children.length === 0) { // n.bvh = n.aabb; vec3.copy(n.bvh.min, n.aabb.min); vec3.copy(n.bvh.max, n.aabb.max); } } } vec3.min(parentBVH.min, parentBVH.min, n.bvh.min); vec3.max(parentBVH.max, parentBVH.max, n.bvh.max); } for (i = 0, leni = this.glTF.scenes.length; i < leni; i++) { scene = this.glTF.scenes[i] = new Scene(this.glTF, this.glTF.json.scenes[i]); scene.boundingBox = new BoundingBox(); for (j = 0, lenj = scene.nodes.length; j < lenj; j++) { node = scene.nodes[j]; // node.traverse(null, execUpdateBBox); node.traverseTwoExecFun(null, execUpdateTransform, execUpdateBBox); } scene.boundingBox.calculateTransform(); } for (j = 0, lenj = this.glTF.nodes.length; j < lenj; j++) { node = this.glTF.nodes[j]; if (node.bvh !== null) { node.bvh.calculateTransform(); } } // load animations (when all accessors are loaded correctly) if (this.glTF.animations) { for (i = 0, leni = this.glTF.animations.length; i < leni; i++) { this.glTF.animations[i] = new Animation(this.glTF, this.glTF.json.animations[i]); } } var joints; // if (this.glTF.skins) { if (this.glTF.json.skins) { for (i = 0, leni = this.glTF.skins.length; i < leni; i++) { this.glTF.skins[i] = new Skin(this.glTF, this.glTF.json.skins[i], i); joints = this.glTF.skins[i].joints; for (j = 0, lenj = joints.length; j < lenj; j++) { // this.glTF.nodes[ joints[j] ].jointID = j; joints[j].jointID = j; } } } for (i = 0, leni = this.glTF.nodes.length; i < leni; i++) { node = this.glTF.nodes[i]; if (node.skin !== null) { if (typeof node.skin == 'number') { // usual skin, hook up node.skin = this.glTF.skins[ node.skin ]; } else { // assume gl_avatar is in use // do nothing } } } }; // TODO: get from gl context var ComponentType2ByteSize = { 5120: 1, // BYTE 5121: 1, // UNSIGNED_BYTE 5122: 2, // SHORT 5123: 2, // UNSIGNED_SHORT 5126: 4 // FLOAT }; var Type2NumOfComponent = { 'SCALAR': 1, 'VEC2': 2, 'VEC3': 3, 'VEC4': 4, 'MAT2': 4, 'MAT3': 9, 'MAT4': 16 }; // ------ Scope limited private util functions--------------- // for animation use function _arrayBuffer2TypedArray(buffer, byteOffset, countOfComponentType, componentType) { switch(componentType) { // @todo: finish case 5122: return new Int16Array(buffer, byteOffset, countOfComponentType); case 5123: return new Uint16Array(buffer, byteOffset, countOfComponentType); case 5124: return new Int32Array(buffer, byteOffset, countOfComponentType); case 5125: return new Uint32Array(buffer, byteOffset, countOfComponentType); case 5126: return new Float32Array(buffer, byteOffset, countOfComponentType); default: return null; } } function _getAccessorData(accessor) { return _arrayBuffer2TypedArray( accessor.bufferView.data, accessor.byteOffset, accessor.count * Type2NumOfComponent[accessor.type], accessor.componentType ); } function _getBaseUri(uri) { // https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Core/getBaseUri.js var basePath = ''; var i = uri.lastIndexOf('/'); if(i !== -1) { basePath = uri.substring(0, i + 1); } return basePath; } function _loadJSON(src, callback) { // native json loading technique from @KryptoniteDove: // http://codepen.io/KryptoniteDove/post/load-json-file-locally-using-pure-javascript var xobj = new XMLHttpRequest(); xobj.overrideMimeType("application/json"); xobj.open('GET', src, true); xobj.onreadystatechange = function () { if (xobj.readyState == 4 && // Request finished, response ready xobj.status == "200") { // Status OK callback(xobj.responseText, this); } }; xobj.send(null); } function _loadArrayBuffer(url, callback) { var xobj = new XMLHttpRequest(); xobj.responseType = 'arraybuffer'; xobj.open('GET', url, true); xobj.onreadystatechange = function () { if (xobj.readyState == 4 && // Request finished, response ready xobj.status == "200") { // Status OK var arrayBuffer = xobj.response; if (arrayBuffer && callback) { callback(arrayBuffer); } } }; xobj.send(null); } function _loadImage(url, iid, onload) { var img = new Image(); img.crossOrigin = "Anonymous"; img.src = url; img.onload = function() { onload(img, iid); }; } // export { MinimalGLTFLoader }; export { glTFLoader }; ================================================ FILE: src/shaders/fs-bbox.glsl ================================================ #version 300 es #define FRAG_COLOR_LOCATION 0 precision highp float; precision highp int; layout(location = FRAG_COLOR_LOCATION) out vec4 color; void main() { color = vec4(1.0, 0.0, 0.0, 1.0); } ================================================ FILE: src/shaders/fs-cube-map.glsl ================================================ #version 300 es precision highp float; precision highp int; uniform samplerCube u_environment; in vec3 texcoord; out vec4 color; void main() { color = texture(u_environment, texcoord); } ================================================ FILE: src/shaders/fs-pbr-master.glsl ================================================ #define FRAG_COLOR_LOCATION 0 // reference: https://github.com/KhronosGroup/glTF-WebGL-PBR/blob/master/shaders/pbr-frag.glsl precision highp float; precision highp int; // IBL uniform samplerCube u_DiffuseEnvSampler; uniform samplerCube u_SpecularEnvSampler; uniform sampler2D u_brdfLUT; // Metallic-roughness material // base color uniform vec4 u_baseColorFactor; #ifdef HAS_BASECOLORMAP uniform sampler2D u_baseColorTexture; #endif // normal map #ifdef HAS_NORMALMAP uniform sampler2D u_normalTexture; uniform float u_normalTextureScale; #endif // emmisve map #ifdef HAS_EMISSIVEMAP uniform sampler2D u_emissiveTexture; uniform vec3 u_emissiveFactor; #endif // metal roughness #ifdef HAS_METALROUGHNESSMAP uniform sampler2D u_metallicRoughnessTexture; #endif uniform float u_metallicFactor; uniform float u_roughnessFactor; // occlusion texture #ifdef HAS_OCCLUSIONMAP uniform sampler2D u_occlusionTexture; uniform float u_occlusionStrength; #endif in vec3 v_position; in vec3 v_normal; in vec2 v_uv; layout(location = FRAG_COLOR_LOCATION) out vec4 frag_color; struct PBRInfo { float NdotL; // cos angle between normal and light direction float NdotV; // cos angle between normal and view direction float NdotH; // cos angle between normal and half vector float LdotH; // cos angle between light direction and half vector float VdotH; // cos angle between view direction and half vector float perceptualRoughness; // roughness value, as authored by the model creator (input to shader) float metalness; // metallic value at the surface vec3 reflectance0; // full reflectance color (normal incidence angle) vec3 reflectance90; // reflectance color at grazing angle float alphaRoughness; // roughness mapped to a more linear change in the roughness (proposed by [2]) vec3 diffuseColor; // color contribution from diffuse lighting vec3 specularColor; // color contribution from specular lighting }; // vec3 applyNormalMap(vec3 geomnor, vec3 normap) { // normap = normap * 2.0 - 1.0; // vec3 up = normalize(vec3(0.01, 1, 0.01)); // vec3 surftan = normalize(cross(geomnor, up)); // vec3 surfbinor = cross(geomnor, surftan); // return normap.y * surftan * u_normalTextureScale + normap.x * surfbinor * u_normalTextureScale + normap.z * geomnor; // } const float M_PI = 3.141592653589793; const float c_MinRoughness = 0.04; // vec3 getNormal() // { // #ifdef HAS_NORMALMAP // #ifdef HAS_TANGENTS // vec3 n = texture(u_normalTexture, v_uv).rgb; // n = normalize(v_TBN * (2.0 * n - 1.0) - vec3(u_normalTextureScale, u_normalTextureScale, 1.0)); // #else // vec3 n = applyNormalMap( v_normal, texture(u_normalTexture, v_uv).rgb ); // #endif // #else // vec3 n = v_normal; // #endif // return n; // #endif // } // Find the normal for this fragment, pulling either from a predefined normal map // or from the interpolated mesh normal and tangent attributes. vec3 getNormal() { // #ifdef HAS_NORMALMAP // vec3 n = applyNormalMap( v_normal, texture(u_normalTexture, v_uv).rgb ); // #else // vec3 n = v_normal; // #endif // return n; // Retrieve the tangent space matrix // #ifndef HAS_TANGENTS vec3 pos_dx = dFdx(v_position); vec3 pos_dy = dFdy(v_position); vec3 tex_dx = dFdx(vec3(v_uv, 0.0)); vec3 tex_dy = dFdy(vec3(v_uv, 0.0)); vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); vec3 ng = v_normal; // #ifdef HAS_NORMALS // vec3 ng = normalize(v_normal); // #else // vec3 ng = cross(pos_dx, pos_dy); // #endif t = normalize(t - ng * dot(ng, t)); vec3 b = normalize(cross(ng, t)); mat3 tbn = mat3(t, b, ng); // #else // HAS_TANGENTS // mat3 tbn = v_TBN; // #endif // TODO: TANGENTS #ifdef HAS_NORMALMAP vec3 n = texture(u_normalTexture, v_uv).rgb; n = normalize(tbn * ((2.0 * n - 1.0) * vec3(u_normalTextureScale, u_normalTextureScale, 1.0))); #else vec3 n = tbn[2].xyz; #endif return n; } vec3 getIBLContribution(PBRInfo pbrInputs, vec3 n, vec3 reflection) { // float mipCount = 9.0; // resolution of 512x512 // float mipCount = 10.0; // resolution of 1024x1024 float mipCount = 10.0; // resolution of 256x256 float lod = (pbrInputs.perceptualRoughness * mipCount); // retrieve a scale and bias to F0. See [1], Figure 3 vec3 brdf = texture(u_brdfLUT, vec2(pbrInputs.NdotV, 1.0 - pbrInputs.perceptualRoughness)).rgb; vec3 diffuseLight = texture(u_DiffuseEnvSampler, n).rgb; // #ifdef USE_TEX_LOD vec3 specularLight = texture(u_SpecularEnvSampler, reflection, lod).rgb; // #else // vec3 specularLight = texture(u_SpecularEnvSampler, reflection).rgb; // #endif vec3 diffuse = diffuseLight * pbrInputs.diffuseColor; vec3 specular = specularLight * (pbrInputs.specularColor * brdf.x + brdf.y); // // For presentation, this allows us to disable IBL terms // diffuse *= u_ScaleIBLAmbient.x; // specular *= u_ScaleIBLAmbient.y; return diffuse + specular; } // Basic Lambertian diffuse // Implementation from Lambert's Photometria https://archive.org/details/lambertsphotome00lambgoog // See also [1], Equation 1 vec3 diffuse(PBRInfo pbrInputs) { return pbrInputs.diffuseColor / M_PI; } // The following equation models the Fresnel reflectance term of the spec equation (aka F()) // Implementation of fresnel from [4], Equation 15 vec3 specularReflection(PBRInfo pbrInputs) { return pbrInputs.reflectance0 + (pbrInputs.reflectance90 - pbrInputs.reflectance0) * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); } // This calculates the specular geometric attenuation (aka G()), // where rougher material will reflect less light back to the viewer. // This implementation is based on [1] Equation 4, and we adopt their modifications to // alphaRoughness as input as originally proposed in [2]. float geometricOcclusion(PBRInfo pbrInputs) { float NdotL = pbrInputs.NdotL; float NdotV = pbrInputs.NdotV; float r = pbrInputs.alphaRoughness; float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); return attenuationL * attenuationV; } // The following equation(s) model the distribution of microfacet normals across the area being drawn (aka D()) // Implementation from "Average Irregularity Representation of a Roughened Surface for Ray Reflection" by T. S. Trowbridge, and K. P. Reitz // Follows the distribution function recommended in the SIGGRAPH 2013 course notes from EPIC Games [1], Equation 3. float microfacetDistribution(PBRInfo pbrInputs) { float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; return roughnessSq / (M_PI * f * f); } void main() { float perceptualRoughness = u_roughnessFactor; float metallic = u_metallicFactor; #ifdef HAS_METALROUGHNESSMAP // Roughness is stored in the 'g' channel, metallic is stored in the 'b' channel. // This layout intentionally reserves the 'r' channel for (optional) occlusion map data vec4 mrSample = texture(u_metallicRoughnessTexture, v_uv); perceptualRoughness = mrSample.g * perceptualRoughness; metallic = mrSample.b * metallic; #endif perceptualRoughness = clamp(perceptualRoughness, c_MinRoughness, 1.0); metallic = clamp(metallic, 0.0, 1.0); // Roughness is authored as perceptual roughness; as is convention, // convert to material roughness by squaring the perceptual roughness [2]. float alphaRoughness = perceptualRoughness * perceptualRoughness; // The albedo may be defined from a base texture or a flat color #ifdef HAS_BASECOLORMAP vec4 baseColor = texture(u_baseColorTexture, v_uv) * u_baseColorFactor; #else vec4 baseColor = u_baseColorFactor; #endif vec3 f0 = vec3(0.04); vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0); diffuseColor *= 1.0 - metallic; vec3 specularColor = mix(f0, baseColor.rgb, metallic); // Compute reflectance. float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); // For typical incident reflectance range (between 4% to 100%) set the grazing reflectance to 100% for typical fresnel effect. // For very low reflectance range on highly diffuse objects (below 4%), incrementally reduce grazing reflecance to 0%. float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); vec3 specularEnvironmentR0 = specularColor.rgb; vec3 specularEnvironmentR90 = vec3(1.0, 1.0, 1.0) * reflectance90; vec3 n = getNormal(); // normal at surface point // vec3 v = vec3( 0.0, 0.0, 1.0 ); // Vector from surface point to camera vec3 v = normalize(-v_position); // Vector from surface point to camera // vec3 l = normalize(u_LightDirection); // Vector from surface point to light vec3 l = normalize(vec3( 1.0, 1.0, 1.0 )); // Vector from surface point to light // vec3 l = vec3( 0.0, 0.0, 1.0 ); // Vector from surface point to light vec3 h = normalize(l+v); // Half vector between both l and v vec3 reflection = -normalize(reflect(v, n)); float NdotL = clamp(dot(n, l), 0.001, 1.0); float NdotV = abs(dot(n, v)) + 0.001; float NdotH = clamp(dot(n, h), 0.0, 1.0); float LdotH = clamp(dot(l, h), 0.0, 1.0); float VdotH = clamp(dot(v, h), 0.0, 1.0); PBRInfo pbrInputs = PBRInfo( NdotL, NdotV, NdotH, LdotH, VdotH, perceptualRoughness, metallic, specularEnvironmentR0, specularEnvironmentR90, alphaRoughness, diffuseColor, specularColor ); // Calculate the shading terms for the microfacet specular shading model vec3 F = specularReflection(pbrInputs); float G = geometricOcclusion(pbrInputs); float D = microfacetDistribution(pbrInputs); // Calculation of analytical lighting contribution vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); vec3 specContrib = max(vec3(0.0), F * G * D / (4.0 * NdotL * NdotV)); // vec3 color = NdotL * u_LightColor * (diffuseContrib + specContrib); vec3 color = NdotL * (diffuseContrib + specContrib); // assume light color vec3(1, 1, 1) // Calculate lighting contribution from image based lighting source (IBL) // #ifdef USE_IBL color += getIBLContribution(pbrInputs, n, reflection); // #endif // Apply optional PBR terms for additional (optional) shading #ifdef HAS_OCCLUSIONMAP float ao = texture(u_occlusionTexture, v_uv).r; color = mix(color, color * ao, u_occlusionStrength); #endif #ifdef HAS_EMISSIVEMAP vec3 emissive = texture(u_emissiveTexture, v_uv).rgb * u_emissiveFactor; color += emissive; #endif // // This section uses mix to override final color for reference app visualization // // of various parameters in the lighting equation. // color = mix(color, F, u_ScaleFGDSpec.x); // color = mix(color, vec3(G), u_ScaleFGDSpec.y); // color = mix(color, vec3(D), u_ScaleFGDSpec.z); // color = mix(color, specContrib, u_ScaleFGDSpec.w); // color = mix(color, diffuseContrib, u_ScaleDiffBaseMR.x); // color = mix(color, baseColor.rgb, u_ScaleDiffBaseMR.y); // color = mix(color, vec3(metallic), u_ScaleDiffBaseMR.z); // color = mix(color, vec3(perceptualRoughness), u_ScaleDiffBaseMR.w); frag_color = vec4(color, baseColor.a); } ================================================ FILE: src/shaders/vs-bbox.glsl ================================================ #version 300 es #define POSITION_LOCATION 0 precision highp float; precision highp int; uniform mat4 u_MVP; layout(location = POSITION_LOCATION) in vec3 position; void main() { gl_Position = u_MVP * vec4(position, 1.0) ; } ================================================ FILE: src/shaders/vs-cube-map.glsl ================================================ #version 300 es precision highp float; precision highp int; uniform mat4 u_MVP; layout(location = 0) in vec3 position; out vec3 texcoord; void main() { vec4 pos = u_MVP * vec4(position, 1.0); gl_Position = pos.xyww; texcoord = position; } ================================================ FILE: src/shaders/vs-pbr-master.glsl ================================================ #define POSITION_LOCATION 0 #define NORMAL_LOCATION 1 #define TEXCOORD_0_LOCATION 2 #define JOINTS_0_LOCATION 3 #define JOINTS_1_LOCATION 5 #define WEIGHTS_0_LOCATION 4 #define WEIGHTS_1_LOCATION 6 #define TANGENT_LOCATION 7 precision highp float; precision highp int; uniform mat4 u_MVP; uniform mat4 u_MV; uniform mat4 u_MVNormal; #ifdef HAS_SKIN uniform JointMatrix { mat4 matrix[65]; } u_jointMatrix; #endif layout(location = POSITION_LOCATION) in vec3 position; layout(location = NORMAL_LOCATION) in vec3 normal; layout(location = TEXCOORD_0_LOCATION) in vec2 uv; #ifdef HAS_SKIN layout(location = JOINTS_0_LOCATION) in vec4 joint0; layout(location = WEIGHTS_0_LOCATION) in vec4 weight0; #ifdef SKIN_VEC8 layout(location = JOINTS_1_LOCATION) in vec4 joint1; layout(location = WEIGHTS_1_LOCATION) in vec4 weight1; #endif #endif // #ifdef HAS_TANGENTS // layout(location = TANGENT_LOCATION) in vec4 tangent; // out vec3 v_tangentW; // out vec3 v_bitangentW; // #endif out vec3 v_position; out vec3 v_normal; out vec2 v_uv; void main() { #ifdef HAS_SKIN mat4 skinMatrix = weight0.x * u_jointMatrix.matrix[int(joint0.x)] + weight0.y * u_jointMatrix.matrix[int(joint0.y)] + weight0.z * u_jointMatrix.matrix[int(joint0.z)] + weight0.w * u_jointMatrix.matrix[int(joint0.w)]; #ifdef SKIN_VEC8 skinMatrix += weight1.x * u_jointMatrix.matrix[int(joint1.x)] + weight1.y * u_jointMatrix.matrix[int(joint1.y)] + weight1.z * u_jointMatrix.matrix[int(joint1.z)] + weight1.w * u_jointMatrix.matrix[int(joint1.w)]; #endif #endif v_uv = uv; #ifdef HAS_SKIN v_normal = normalize(( u_MVNormal * transpose(inverse(skinMatrix)) * vec4(normal, 0)).xyz); vec4 pos = u_MV * skinMatrix * vec4(position, 1.0); gl_Position = u_MVP * skinMatrix * vec4(position, 1.0); #else v_normal = normalize((u_MVNormal * vec4(normal, 0)).xyz); vec4 pos = u_MV * vec4(position, 1.0); gl_Position = u_MVP * vec4(position, 1.0); #endif v_position = vec3(pos.xyz) / pos.w; } ================================================ FILE: third-party-license/glMatrix ================================================ Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. 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. ================================================ FILE: webpack.config.js ================================================ var path = require('path'); var webpack = require('webpack'); // var HtmlWebpackPlugin = require('html-webpack-plugin'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); module.exports = { entry: { lib: './src/minimal-gltf-loader.js' }, resolve: { alias: { // Lib: path.resolve(__dirname, 'demo/lib/'), // Shaders: path.resolve(__dirname, 'demo/lib/src/shaders') } }, output: { filename: 'minimal-gltf-loader.js', path: path.resolve(__dirname, 'build'), library: 'MinimalGLTFLoader', libraryTarget: 'umd' }, externals: { 'gl-matrix': { commonjs: 'gl-matrix', commonjs2: 'gl-matrix', amd: 'gl-matrix' } }, module: { // rules: [ // ] // loaders: [ // { // test: /\.glsl$/, // loader: "webpack-glsl" // }, // ] }, plugins: [ // new webpack.optimize.UglifyJsPlugin({ // compress: { // warnings: false, // drop_console: false, // } // }) // new UglifyJSPlugin() // new HtmlWebpackPlugin({ // title: "glAvatar demo" // }) ], devServer: { contentBase: path.join(__dirname, "demo"), port: 7777 } };