Compare commits

...

129 Commits

Author SHA1 Message Date
Ray Elliott b56aa0d016 do not open browser when runnig devServer 2021-06-10 18:44:01 +01:00
Ray Elliott eb715144b3 update readme 2021-06-10 18:35:46 +01:00
Ray Elliott 480161d9a5 update readme 2021-06-10 18:31:43 +01:00
Ray Elliott 31e603e295 replace node-sass with sass 2021-06-10 18:24:46 +01:00
Paul Graffam f3bca60420 Updated lock 2021-04-05 11:45:04 -04:00
Paul Graffam e91115b0cf Updated version 2021-04-05 11:43:35 -04:00
Paul Graffam 975b1f4f66 Set public path to work in dev and prod 2021-04-05 11:41:56 -04:00
Paul Graffam 889093011e
Merge pull request #39 from designbyjosh/fix-dev-server
Fixed publicPath for dev server
2021-04-05 11:37:28 -04:00
Josh Atkins ee3341c6b3 Fixed publicPath for dev server 2021-04-03 16:00:59 +01:00
Paul Graffam b52ad3e7b9 Updated version 2021-03-24 19:18:35 -04:00
Paul Graffam 47f740e3ca Merge branch 'master' of github.com:paulmg/ThreeJS-Webpack-ES6-Boilerplate
# Conflicts:
#	package-lock.json
2021-03-24 19:13:34 -04:00
Paul Graffam 752ecf63b0 Added check for isDev 2021-03-24 19:12:41 -04:00
Paul Graffam 599bf0b1d0 Reran build and dev commands 2021-03-24 19:12:29 -04:00
Paul Graffam 0d11abb1aa Fixed webpack options 2021-03-24 19:11:21 -04:00
Paul Graffam 96c95a8649 Updated package lock 2021-03-24 19:09:47 -04:00
Paul Graffam 26c84115ba Updated packages, fixed scripts 2021-03-24 19:09:33 -04:00
Paul Graffam ef7369228d
Merge pull request #33 from paulmg/dependabot/npm_and_yarn/ini-1.3.7
Bump ini from 1.3.5 to 1.3.7
2020-12-14 11:40:06 -05:00
dependabot[bot] c46d33c57c
Bump ini from 1.3.5 to 1.3.7
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7.
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot[bot] <support@github.com>
2020-12-10 18:48:46 +00:00
Paul Graffam d59f59613f
Merge pull request #31 from paulmg/dependabot/npm_and_yarn/lodash-4.17.19
Bump lodash from 4.17.15 to 4.17.19
2020-07-16 11:49:00 -04:00
dependabot[bot] b0ff6b41ef
Bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-16 04:31:52 +00:00
Paul Graffam 41569ab1b6 Updated build and public files 2020-07-06 17:29:40 -04:00
Paul Graffam 5b0425c02d Replaced ugilfyjs with terser 2020-07-06 17:29:24 -04:00
Paul Graffam 6374273055 Set up gltf loading, set up switching, fixed imports, fixed helpers, added model gui 2020-07-06 17:29:08 -04:00
Paul Graffam 548da33664 Updated stats 2020-07-06 17:27:49 -04:00
Paul Graffam f3502290c4 Fixed deprecation 2020-07-06 17:27:24 -04:00
Paul Graffam 529f28f781 Cleaned up 2020-07-06 17:27:09 -04:00
Paul Graffam 76a7367be6 Added geometry utils 2020-07-06 17:24:24 -04:00
Paul Graffam a73b163e4e Added gltf loader 2020-07-06 17:24:10 -04:00
Paul Graffam 8303fd1810 Added vertex helper, fixed up mesh helper 2020-07-06 17:23:59 -04:00
Paul Graffam 8bf324c925 Old files 2020-07-06 17:23:33 -04:00
Paul Graffam 5e70d3d69a Moved to components 2020-07-06 17:23:21 -04:00
Paul Graffam ae1ec73418 Updated packages, replaced deprecated ones 2020-07-06 17:22:59 -04:00
Paul Graffam 40dc533d59 Added gltf duck files 2020-07-06 17:22:18 -04:00
Paul Graffam afb4645347 Updated packages and re-ran build 2020-03-17 18:37:47 -04:00
Paul Graffam 5c22d5fc87
Bumped node-sass to 4.13 2020-03-17 18:23:02 -04:00
Paul Graffam c67efe561e
Merge pull request #22 from paulmg/dependabot/npm_and_yarn/mixin-deep-1.3.2
Bump mixin-deep from 1.3.1 to 1.3.2
2020-03-11 11:19:50 -04:00
dependabot[bot] d6bacd84c6
Bump mixin-deep from 1.3.1 to 1.3.2
Bumps [mixin-deep](https://github.com/jonschlinkert/mixin-deep) from 1.3.1 to 1.3.2.
- [Release notes](https://github.com/jonschlinkert/mixin-deep/releases)
- [Commits](https://github.com/jonschlinkert/mixin-deep/compare/1.3.1...1.3.2)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-11 15:19:32 +00:00
Paul Graffam 680e6fe694
Merge pull request #21 from paulmg/dependabot/npm_and_yarn/lodash.mergewith-4.6.2
Bump lodash.mergewith from 4.6.1 to 4.6.2
2020-03-11 11:19:18 -04:00
Paul Graffam 212b0bc0e0
Merge pull request #24 from paulmg/dependabot/npm_and_yarn/lodash-4.17.15
Bump lodash from 4.17.10 to 4.17.15
2020-03-11 11:18:38 -04:00
Paul Graffam 42a8b791a7
Merge pull request #23 from paulmg/dependabot/npm_and_yarn/js-yaml-3.13.1
Bump js-yaml from 3.12.1 to 3.13.1
2020-03-11 11:18:25 -04:00
dependabot[bot] e0a43e34a2
Bump lodash from 4.17.10 to 4.17.15
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.10 to 4.17.15.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.10...4.17.15)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-11 15:18:06 +00:00
dependabot[bot] 9abdd90a41
Bump lodash.mergewith from 4.6.1 to 4.6.2
Bumps [lodash.mergewith](https://github.com/lodash/lodash) from 4.6.1 to 4.6.2.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/commits)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-11 15:18:05 +00:00
dependabot[bot] d10f28c122
Bump js-yaml from 3.12.1 to 3.13.1
Bumps [js-yaml](https://github.com/nodeca/js-yaml) from 3.12.1 to 3.13.1.
- [Release notes](https://github.com/nodeca/js-yaml/releases)
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/3.12.1...3.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-11 15:18:04 +00:00
Paul Graffam 1beda54b11
Merge pull request #25 from paulmg/dependabot/npm_and_yarn/eslint-utils-1.4.3
Bump eslint-utils from 1.3.1 to 1.4.3
2020-03-11 11:17:16 -04:00
Paul Graffam dd9d7a30f8
Merge pull request #26 from paulmg/dependabot/npm_and_yarn/fstream-1.0.12
Bump fstream from 1.0.11 to 1.0.12
2020-03-11 11:17:04 -04:00
dependabot[bot] 024051b576
Bump fstream from 1.0.11 to 1.0.12
Bumps [fstream](https://github.com/npm/fstream) from 1.0.11 to 1.0.12.
- [Release notes](https://github.com/npm/fstream/releases)
- [Commits](https://github.com/npm/fstream/compare/v1.0.11...v1.0.12)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-10 00:40:05 +00:00
dependabot[bot] 2401bfad23
Bump eslint-utils from 1.3.1 to 1.4.3
Bumps [eslint-utils](https://github.com/mysticatea/eslint-utils) from 1.3.1 to 1.4.3.
- [Release notes](https://github.com/mysticatea/eslint-utils/releases)
- [Commits](https://github.com/mysticatea/eslint-utils/compare/v1.3.1...v1.4.3)

Signed-off-by: dependabot[bot] <support@github.com>
2020-03-10 00:40:03 +00:00
Paul Graffam 80d504370c
Create nodejs.yml 2020-03-09 20:39:15 -04:00
Paul Graffam a04eb38f03
Update README.md
Fixed alignment
2019-02-05 16:47:12 -05:00
Paul Graffam cb8f17be3e Clarified some portions, updated sections related to assets refactoring 2019-01-29 17:19:43 -05:00
Paul Graffam 49e4c939e6 Updated readme 2019-01-29 16:56:28 -05:00
Paul Graffam e8177659ac Added minimization, set up css extract plugin, added style chunking, fixed paths 2019-01-29 16:56:13 -05:00
Paul Graffam 11dd93aff6 Added postcss autoprefixing 2019-01-29 16:55:27 -05:00
Paul Graffam 37ffe49cdc Added template logic 2019-01-29 16:55:18 -05:00
Paul Graffam a4f88fee78 Import styles into project 2019-01-29 16:55:05 -05:00
Paul Graffam 0ba07b1dec Re-built 2019-01-29 16:54:53 -05:00
Paul Graffam c25969dd94 Fixed pathing to css 2019-01-29 16:54:39 -05:00
Paul Graffam 5b806289ce Remove old files 2019-01-29 16:54:20 -05:00
Paul Graffam 98ced74b80 Refactored public dirs 2019-01-29 16:54:10 -05:00
Paul Graffam ea9380baa5 Added new packages, updated scripts 2019-01-29 16:52:45 -05:00
Paul Graffam 672881cd86 Updated webpack config: added chunking, fixed environment variables 2019-01-24 18:07:59 -05:00
Paul Graffam 3a83436ef2 Remove old files 2019-01-24 17:59:07 -05:00
Paul Graffam fa214fd967 Enabled ambient light 2019-01-24 17:58:53 -05:00
Paul Graffam 26a7239c91 Updated dat.gui 2019-01-24 17:58:40 -05:00
Paul Graffam 8628734c6a New generated chunk files 2019-01-24 17:58:29 -05:00
Paul Graffam d6fb7d1a71 Moved index.html to html dir, new generated index.html 2019-01-24 17:57:57 -05:00
Paul Graffam 1228774174 Added new packages for chunking and webpack sass, fixed up scripts 2019-01-24 17:57:17 -05:00
Paul Graffam 3018c6f5bd Reformat parameters 2019-01-23 17:26:49 -05:00
Paul Graffam 052e101e1c Updated model to correct json 2019-01-23 17:26:17 -05:00
Paul Graffam 85f1f2474d Set to correct new babel preset 2019-01-23 17:24:08 -05:00
Paul Graffam ad74138a7c Updated packages to lates 2019-01-23 17:23:50 -05:00
Paul Graffam 432cb4a5cf
Merge pull request #19 from igghera/master
Update webpack-cli version
2018-12-06 16:55:21 -05:00
Andrea Gherardi c212317b72 Update webpack-cli version
Fixes #17
2018-12-06 10:28:59 +01:00
Paul Graffam 7381928803
Merge pull request #18 from lucaskuzma/camera-fix
Update camera.js
2018-10-24 11:15:33 -04:00
Paul Graffam 8eaf3a8b49
Merge pull request #16 from rtpHarry/patch-2
fixes #15 - clarify animation mixer comment
2018-10-09 11:02:56 -04:00
Matthew Harris ba8478fbe5
fixes #15 - clarify animation mixer comment 2018-10-06 17:33:35 +07:00
lucaskuzma 44808a4974
Update camera.js
No need to involve pixel ratio here.
2018-09-18 09:22:26 +02:00
Paul Graffam 337e21226b
Merge pull request #10 from rtpHarry/patch-1
Add clarification for a comment
2018-06-27 12:21:39 -04:00
Paul Graffam 481b33053c
Merge pull request #11 from rtpHarry/patch-2
Add url to readme.md
2018-06-27 12:20:19 -04:00
Matthew Harris 952e4701e2
Add url to readme.md 2018-06-27 09:46:49 +07:00
Matthew Harris 97f5358f95
Add clarification for a comment
I removed this as it looked pointless, only to realise it was because it was for using outside of the class
2018-06-27 09:45:34 +07:00
Paul Graffam a8e2a24c43
Updated readme with project tree 2018-06-21 11:05:55 -04:00
Paul Graffam 4bf4b32e81 Rebuilt 2018-05-13 23:56:49 -04:00
Paul Graffam d918863297 Updated dependencies, fixed build script 2018-05-13 23:56:41 -04:00
Paul Graffam 7a86dd1991
Merge pull request #8 from weiserhei/patch-3
add argument `event` to onKeyChange function calls
2018-05-13 20:49:30 -04:00
weiserhei 3ca1bce253
add argument `event` to onKeyChange function calls
because otherwise its undefined
2018-05-11 22:33:04 +02:00
Paul Graffam c3027370e5
Merge pull request #5 from weiserhei/patch-1
Quoting buildpath / globstars
2018-05-07 16:26:55 -04:00
weiserhei 8c7c808e16
Quoting globstars
Problem I ran into:
`npm run build` only created the build/public/assets/css/app.css file, nothing else was copied.
No Error showed up in Terminal. 
Solution:
After reading the `copyfiles`-module readme I discovered you may have to put the path in quotation marks. Doing so fixed it and copied the whole public folders like its supposed to.
2018-05-07 17:57:17 +02:00
Paul Graffam 87745300ac Merge branch 'master' of github.com:paulmg/ThreeJS-Webpack-ES6-Boilerplate 2018-02-25 19:34:09 -05:00
Paul Graffam f1a3628d6e Added progress flag 2018-02-25 19:33:12 -05:00
Paul Graffam 094c6f4db0 Rebuilt project 2018-02-25 19:33:02 -05:00
Paul Graffam 58e3b39fce Set to triple equals 2018-02-25 19:31:59 -05:00
Paul Graffam cbfe38ac59 Migrated webpack config to 4.0 version, restructured, added more options 2018-02-25 19:31:45 -05:00
Paul Graffam e183f91dee Updated vendor files to latest 2018-02-25 19:30:59 -05:00
Paul Graffam de7032afe8 Cleanup 2018-02-25 19:30:17 -05:00
Paul Graffam 4ef5184b16 Refactored rStats to its own module, added config option for displaying stats 2018-02-25 19:30:01 -05:00
Paul Graffam 4b584783d7 Set to triple equals 2018-02-25 19:27:55 -05:00
Paul Graffam 0cf0430a5d Created babel config file 2018-02-25 19:27:36 -05:00
Paul Graffam 6639ee11d0 Updated all dependencies, updated scripts, removed watch from dev call 2018-02-25 19:27:09 -05:00
Paul Graffam 7be7436321
Adding license 2018-01-28 20:54:09 -05:00
Paul Graffam 219d333ad9 Set bottom section to list 2016-10-07 15:08:15 -04:00
Paul Graffam 65bcb08089 Updated readme with new info 2016-10-07 14:56:18 -04:00
Paul Graffam f78d23b52f Rebuilt files 2016-10-07 14:56:00 -04:00
Paul Graffam 6474293117 Updated public files 2016-10-07 14:55:46 -04:00
Paul Graffam ee7369d79b Added more comments 2016-10-07 14:55:31 -04:00
Paul Graffam c2f4f1741b Passed in color to material constructor 2016-10-07 14:55:13 -04:00
Paul Graffam 2837909a17 Added sphere, updated to use Material class 2016-10-07 14:54:45 -04:00
Paul Graffam 29a2f7393d Style updates 2016-10-07 14:54:20 -04:00
Paul Graffam a21f06e3ea Refactored gui functions to static helper functions 2016-10-07 14:53:11 -04:00
Paul Graffam 3737462bd5 Commented and updated 2016-10-07 04:42:23 -04:00
Paul Graffam ac06ae8cbd Set to use Helper static methods, commented and updated 2016-10-07 04:41:27 -04:00
Paul Graffam 0b556be6bc Updated config values 2016-10-07 04:40:50 -04:00
Paul Graffam f2087cab2d Minor cleanup 2016-10-07 04:40:29 -04:00
Paul Graffam a2f26b057b Added base and loading files, updated styles 2016-10-07 04:39:35 -04:00
Paul Graffam 24ff7899c3 Added static classes to log progress and errors 2016-10-07 04:38:54 -04:00
Paul Graffam 43c3e43984 Renamed to meshHelper to avoid confusion with other helpers 2016-10-07 04:38:28 -04:00
Paul Graffam 3b691178b0 Added new rStats extras file path 2016-10-07 04:37:29 -04:00
Paul Graffam 2f150b614c Updated rStats 2016-10-07 04:37:03 -04:00
Paul Graffam 6064df572e Updated eslint rules, set to warning to continue npm execution 2016-10-06 23:17:10 -04:00
Paul Graffam fe7b6a3e41 Comments, removed unused code 2016-10-06 23:16:25 -04:00
Paul Graffam 9bc1583877 Fixed Three.js import, updated file imports, commented code 2016-10-06 23:15:00 -04:00
Paul Graffam 93156a8174 Refactored app js into folders, fixed three.js import for new version, minor changes after lint pass 2016-10-06 23:14:07 -04:00
Paul Graffam 2fba979793 Set paths to local 2016-10-06 23:11:58 -04:00
Paul Graffam 17188d80c1 Refactored styles to folders 2016-10-06 23:11:22 -04:00
Paul Graffam 988d718b5a Cleaned up and updated vars to ES6 2016-10-06 23:10:05 -04:00
Paul Graffam 7b4318dc86 Set paths to local, added loading div 2016-10-06 23:09:07 -04:00
Paul Graffam 102f5ef9e9 Updated packages and node, set Three and Tween to working versions, updated scripts 2016-10-06 23:07:17 -04:00
Paul Graffam 604b496d5e Delete old model json file 2016-10-06 23:04:14 -04:00
Paul Graffam a6737ae8b1 Renamed to Teapot.json for naming consistency 2016-10-06 23:03:24 -04:00
82 changed files with 27614 additions and 3225 deletions

1
.babelrc Normal file
View File

@ -0,0 +1 @@
{ "presets": ["@babel/preset-env"] }

View File

@ -1,22 +1,60 @@
{
"rules": {
"quotes": [
2,
"single"
],
"semi": [
2,
"always"
],
"no-unused-vars" : 2,
"no-undef" : 2
},
"env": {
"es6": true,
"browser": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
}
"rules": {
"no-cond-assign": 1,
"no-console": 1,
"no-constant-condition": 1,
"no-control-regex": 1,
"no-debugger": 1,
"no-dupe-args": 1,
"no-dupe-keys": 1,
"no-duplicate-case": 1,
"no-empty-character-class": 1,
"no-empty": 1,
"no-ex-assign": 1,
"no-extra-boolean-cast": 1,
"no-extra-semi": 1,
"no-func-assign": 1,
"no-inner-declarations": 1,
"no-invalid-regexp": 1,
"no-irregular-whitespace": 1,
"no-negated-in-lhs": 1,
"no-obj-calls": 1,
"no-regex-spaces": 1,
"no-sparse-arrays": 1,
"no-unreachable": 1,
"use-isnan": 1,
"valid-typeof": 1,
"no-alert": 1,
"no-else-return": 1,
"no-eval": 1,
"no-extra-bind": 1,
"no-fallthrough": 1,
"no-octal": 1,
"no-proto": 1,
"no-redeclare": [1, {"builtinGlobals": true}],
"no-useless-call": 1,
"no-delete-var": 1,
"no-undef-init": 1,
"no-undef": 1,
"no-unused-vars": 1,
"camelcase": 1,
"eol-last": 1,
"indent": [1, 2, {"SwitchCase": 1}],
"no-array-constructor": 1,
"no-continue": 1,
"no-lonely-if": 1,
"no-mixed-spaces-and-tabs": 1,
"no-new-object": 1,
"no-const-assign": 1,
"prefer-const": 1,
"prefer-spread": 1
},
"env": {
"es6": true,
"browser": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
}
}

31
.github/workflows/nodejs.yml vendored Normal file
View File

@ -0,0 +1,31 @@
# This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
name: Node.js CI
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [10.x, 12.x]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v1
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm run build --if-present
- run: npm test
env:
CI: true

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Paul Graffam
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.

View File

@ -1,22 +1,65 @@
# Three.js Webpack ES6 Boilerplate
[GitHub - paulmg/ThreeJS-Webpack-ES6-Boilerplate/](https://github.com/paulmg/ThreeJS-Webpack-ES6-Boilerplate/)
A basic boilerplate for a Three.js project including the use of Webpack and ES6 syntax via Babel.
## This Fork
* Replace `node-sass` with `sass`.
* Do not open browser when running `devServer`.
## Project Structure
```
build - Directory for built and compressed files from the npm build script
src - Directory for all dev files
├── css - Contains all SCSS files, that are compiled to `src/public/css`
├── js - All the Three.js app files, with `app.js` as entry point. Compiled to `src/public/js` with webpack
│ ├── app
│ │ ├── components - Three.js components that get initialized in `main.js`
│ │ ├── helpers - Classes that provide ideas on how to set up and work with defaults
│ │ ├── managers - Manage complex tasks such as GUI or input
│ │ └── model - Classes that set up the model object
│ ├── data - Any data to be imported into app
│ └── utils - Various helpers and vendor classes
└── public - Used by webpack-dev-server to serve content. Webpack builds local dev files here.
└── assets - Is copied over to build folder with build command. Place external asset files here.
```
## Getting started
Install dependencies:
```
npm install
```
Then
Then run dev script:
```
npm run dev
```
Spins up a webpack dev server at localhost:8080 and keeps track of all js and sass changes to files and reloads upon save.
Spins up a webpack dev server at localhost:8080 and keeps track of all js and sass changes to files.
## Build
```
npm run build
```
Cleans existing build folder while linting js and copies over the public folder from src. Then sets environment to production and compiles js and css into build.
Cleans existing build folder while linting js folder and copies over the public assets folder from src. Then sets environment to production and compiles js and css into build.
## Other NPM Scripts
You can run any of these individually if you'd like with the `npm run` command:
* `prebuild` - Cleans up build folder and lints `src/js`
* `clean` - Cleans build folder
* `lint` - Runs lint on the `src/js` folder and uses the `.eslintrc` file in root for linting rules
* `webpack-server` - Start up a webpack-dev-server with hot-module-replacement
* `webpack-watch` - Run webpack in dev environment with watch
* `dev:js` - Run webpack in dev environment without watch
* `build:dir` - Copy files and folders from `src/public` to `build`
* `build:js` - Run webpack in production environment
## Input Controls
* Press H to hide dat.GUI
* Arrow controls will pan
* Mouse left click will rotate/right click will pan
* Scroll wheel zooms in and out

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,219 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
2,
1
],
"matrix": [
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"matrix": [
-0.7289686799049377,
0.0,
-0.6845470666885376,
0.0,
-0.4252049028873444,
0.7836934328079224,
0.4527972936630249,
0.0,
0.5364750623703003,
0.6211478114128113,
-0.571287989616394,
0.0,
400.1130065917969,
463.2640075683594,
-431.0780334472656,
1.0
],
"camera": 0
},
{
"mesh": 0
}
],
"cameras": [
{
"perspective": {
"aspectRatio": 1.5,
"yfov": 0.6605925559997559,
"zfar": 10000.0,
"znear": 1.0
},
"type": "perspective"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "LOD3spShape"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 12636,
"max": [
2398
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 2399,
"max": [
0.9995989799499512,
0.999580979347229,
0.9984359741210938
],
"min": [
-0.9990839958190918,
-1.0,
-0.9998319745063782
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 28788,
"componentType": 5126,
"count": 2399,
"max": [
96.17990112304688,
163.97000122070313,
53.92519760131836
],
"min": [
-69.29850006103516,
9.929369926452637,
-61.32819747924805
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 2399,
"max": [
0.9833459854125976,
0.9800369739532472
],
"min": [
0.026409000158309938,
0.01996302604675293
],
"type": "VEC2"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicFactor": 0.0
},
"emissiveFactor": [
0.0,
0.0,
0.0
],
"name": "blinn3-fx"
}
],
"textures": [
{
"sampler": 0,
"source": 0
}
],
"images": [
{
"uri": "DuckCM.png"
}
],
"samplers": [
{
"magFilter": 9729,
"minFilter": 9986,
"wrapS": 10497,
"wrapT": 10497
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 76768,
"byteLength": 25272,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 57576,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 57576,
"byteLength": 19192,
"byteStride": 8,
"target": 34962
}
],
"buffers": [
{
"byteLength": 102040,
"uri": "Duck0.bin"
}
]
}

View File

Before

Width:  |  Height:  |  Size: 636 KiB

After

Width:  |  Height:  |  Size: 636 KiB

1
build/css/main.css Normal file
View File

@ -0,0 +1 @@
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0;font:16px/1 sans-serif;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}blockquote,figure,h1,h2,h3,h4,ol,p,ul{margin:0;padding:0}li,main{display:block}h1,h2,h3,h4{font-size:inherit}strong{font-weight:700}a,button{color:inherit;transition:.3s}a{text-decoration:none}button{overflow:visible;border:0;font:inherit;-webkit-font-smoothing:inherit;letter-spacing:inherit;background:none;cursor:pointer}::-moz-focus-inner{padding:0;border:0}:focus{outline:0}img{max-width:100%;height:auto;border:0}body{overflow:hidden}.main{position:relative;width:100%;height:100vh}#loading{position:absolute;top:calc(50% - 8px);left:calc(50% - 35px)}

1
build/index.html Normal file
View File

@ -0,0 +1 @@
<!doctype html><html lang="en"><head><meta charset="UTF-8"><title>Three.js Webpack ES6 Boilerplate</title><script defer="defer" src="js/runtime.bundle.js"></script><script defer="defer" src="js/vendors.bundle.js"></script><script defer="defer" src="js/main.bundle.js"></script><link href="js/../css/main.css" rel="stylesheet"></head><body><section id="appContainer" class="main"><div id="loading">Loading...</div></section></body></html>

1
build/js/main.bundle.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(()=>{"use strict";var e,r={},t={};function o(e){var n=t[e];if(void 0!==n)return n.exports;var l=t[e]={exports:{}};return r[e].call(l.exports,l,l.exports,o),l.exports}o.m=r,e=[],o.O=(r,t,n,l)=>{if(!t){var a=1/0;for(s=0;s<e.length;s++){for(var[t,n,l]=e[s],i=!0,u=0;u<t.length;u++)(!1&l||a>=l)&&Object.keys(o.O).every((e=>o.O[e](t[u])))?t.splice(u--,1):(i=!1,l<a&&(a=l));i&&(e.splice(s--,1),r=n())}return r}l=l||0;for(var s=e.length;s>0&&e[s-1][2]>l;s--)e[s]=e[s-1];e[s]=[t,n,l]},o.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return o.d(r,{a:r}),r},o.d=(e,r)=>{for(var t in r)o.o(r,t)&&!o.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),o.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},(()=>{var e={666:0};o.O.j=r=>0===e[r];var r=(r,t)=>{var n,l,[a,i,u]=t,s=0;for(n in i)o.o(i,n)&&(o.m[n]=i[n]);for(u&&u(o),r&&r(t);s<a.length;s++)l=a[s],o.o(e,l)&&e[l]&&e[l][0](),e[a[s]]=0;o.O()},t=self.webpackChunkthreejs_es6_webpack_boilerplate=self.webpackChunkthreejs_es6_webpack_boilerplate||[];t.forEach(r.bind(null,0)),t.push=r.bind(null,t.push.bind(t))})(),o.O()})();

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,7 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
* @version v4.2.8+1e68dce6
*/

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.main{width:100%;height:100vh}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,19 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js Webpack ES6 Boilerplate</title>
<link rel="stylesheet" type="text/css" href="/assets/css/app.css">
</head>
<body>
<div class="content">
<div id="appContainer" class="main">
</div>
</div>
<script src="/assets/js/rStats.js"></script>
<script src="/assets/js/dat.gui.min.js"></script>
<script src="/assets/js/app.js"></script>
</body>
</html>

21459
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +1,49 @@
{
"name": "threejs-es6-webpack-boilerplate",
"version": "1.0.0",
"version": "1.6.1",
"description": "Boilerplate for Three.js projects set up with Babel for ES6 and compiled with webpack",
"author": "Paul Graffam",
"main": "app.js",
"engines": {
"node": ">=10.0"
},
"scripts": {
"dev": "run-p dev:sass webpack-server webpack-watch",
"build": "run-s prebuild build:dir build:js build:sass",
"prebuild": "run-p clean lint",
"dev": "run-s dev:js webpack-server",
"build": "run-s build:dir build:js",
"prebuild": "run-s clean lint",
"clean": "rimraf build",
"lint": "eslint src/js/; exit 0",
"webpack-server": "set NODE_ENV=0&& webpack-dev-server --hot --inline --open",
"webpack-watch": "set NODE_ENV=0&& webpack --progress --colors --watch --cache",
"dev:sass": "node-sass -w src/css/app.scss -o src/public/assets/css/",
"dev:js": "set NODE_ENV=0&& webpack",
"build:dir": "copyfiles -u 1 src/public/**/* build/",
"build:sass": "node-sass --output-style compressed src/css/ -o build/public/assets/css/",
"build:js": "set NODE_ENV=1&& webpack"
"lint": "eslint src/js/",
"webpack-server": "webpack serve --env NODE_ENV=dev --progress --color --open --hot",
"webpack-watch": "webpack --env NODE_ENV=dev --progress --color --watch --hot",
"dev:js": "webpack --env NODE_ENV=dev",
"build:dir": "copyfiles -a -u 2 src/public/assets/**/*.* build/",
"build:js": "webpack --env NODE_ENV=prod --progress --color"
},
"dependencies": {
"es6-promise": "^3.2.1",
"normalize.css": "^4.2.0",
"three": "^0.79.0",
"tween.js": "16.2.0"
"@tweenjs/tween.js": "^18.6.4",
"es6-promise": "^4.2.8",
"three": "^0.126.1"
},
"devDependencies": {
"babel-core": "^6.13.2",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.13.2",
"copyfiles": "^1.0.0",
"eslint": "^3.4.0",
"file-loader": "^0.9.0",
"node-sass": "^3.8.0",
"npm-run-all": "^3.0.0",
"rimraf": "^2.5.4",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.6.1",
"webpack-dev-server": "^1.15.0"
},
"engines": {
"node": "5.0.0"
"@babel/core": "^7.13.10",
"@babel/preset-env": "^7.13.12",
"autoprefixer": "^10.2.5",
"babel-loader": "^8.2.2",
"copyfiles": "^2.4.1",
"css-loader": "^5.2.0",
"eslint": "^7.22.0",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.3.9",
"sass": "^1.34.1",
"npm-run-all": "^4.1.5",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^5.2.0",
"rimraf": "^3.0.2",
"sass-loader": "^11.0.1",
"style-loader": "^2.0.0",
"terser-webpack-plugin": "^5.1.1",
"webpack": "^5.28.0",
"webpack-cli": "^4.5.0",
"webpack-dev-server": "^4.0.0-beta.1"
}
}

5
postcss.config.js Normal file
View File

@ -0,0 +1,5 @@
module.exports = {
plugins: [
require('autoprefixer'),
],
};

View File

@ -1,585 +1,9 @@
/* ==========================================================================
Normalize.scss settings
========================================================================== */
/**
* Includes legacy browser support IE6/7
*
* Set to false if you want to drop support for IE6 and IE7
*/
// Utils
@import './utils/normalize';
$legacy_browser_support: false !default;
// App
@import './app/base';
@import './app/main';
/* Base
========================================================================== */
/**
* 1. Set default font family to sans-serif.
* 2. Prevent iOS and IE text size adjust after device orientation change,
* without disabling user zoom.
* 3. Corrects text resizing oddly in IE 6/7 when body `font-size` is set using
* `em` units.
*/
html {
font-family: sans-serif; /* 1 */
-ms-text-size-adjust: 100%; /* 2 */
-webkit-text-size-adjust: 100%; /* 2 */
@if $legacy_browser_support {
*font-size: 100%; /* 3 */
}
}
/**
* Remove default margin.
*/
body {
margin: 0;
}
/* HTML5 display definitions
========================================================================== */
/**
* Correct `block` display not defined for any HTML5 element in IE 8/9.
* Correct `block` display not defined for `details` or `summary` in IE 10/11
* and Firefox.
* Correct `block` display not defined for `main` in IE 11.
*/
article,
aside,
details,
figcaption,
figure,
footer,
header,
hgroup,
main,
menu,
nav,
section,
summary {
display: block;
}
/**
* 1. Correct `inline-block` display not defined in IE 6/7/8/9 and Firefox 3.
* 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
*/
audio,
canvas,
progress,
video {
display: inline-block; /* 1 */
vertical-align: baseline; /* 2 */
@if $legacy_browser_support {
*display: inline;
*zoom: 1;
}
}
/**
* Prevents modern browsers from displaying `audio` without controls.
* Remove excess height in iOS 5 devices.
*/
audio:not([controls]) {
display: none;
height: 0;
}
/**
* Address `[hidden]` styling not present in IE 8/9/10.
* Hide the `template` element in IE 8/9/10/11, Safari, and Firefox < 22.
*/
[hidden],
template {
display: none;
}
/* Links
========================================================================== */
/**
* Remove the gray background color from active links in IE 10.
*/
a {
background-color: transparent;
}
/**
* Improve readability of focused elements when they are also in an
* active/hover state.
*/
a {
&:active, &:hover {
outline: 0;
};
}
/* Text-level semantics
========================================================================== */
/**
* Address styling not present in IE 8/9/10/11, Safari, and Chrome.
*/
abbr[title] {
border-bottom: 1px dotted;
}
/**
* Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
*/
b,
strong {
font-weight: bold;
}
@if $legacy_browser_support {
blockquote {
margin: 1em 40px;
}
}
/**
* Address styling not present in Safari and Chrome.
*/
dfn {
font-style: italic;
}
/**
* Address variable `h1` font-size and margin within `section` and `article`
* contexts in Firefox 4+, Safari, and Chrome.
*/
h1 {
font-size: 2em;
margin: 0.67em 0;
}
@if $legacy_browser_support {
h2 {
font-size: 1.5em;
margin: 0.83em 0;
}
h3 {
font-size: 1.17em;
margin: 1em 0;
}
h4 {
font-size: 1em;
margin: 1.33em 0;
}
h5 {
font-size: 0.83em;
margin: 1.67em 0;
}
h6 {
font-size: 0.67em;
margin: 2.33em 0;
}
}
/**
* Addresses styling not present in IE 8/9.
*/
mark {
background: #ff0;
color: #000;
}
@if $legacy_browser_support {
/**
* Addresses margins set differently in IE 6/7.
*/
p,
pre {
*margin: 1em 0;
}
/*
* Addresses CSS quotes not supported in IE 6/7.
*/
q {
*quotes: none;
}
/*
* Addresses `quotes` property not supported in Safari 4.
*/
q:before,
q:after {
content: '';
content: none;
}
}
/**
* Address inconsistent and variable font size in all browsers.
*/
small {
font-size: 80%;
}
/**
* Prevent `sub` and `sup` affecting `line-height` in all browsers.
*/
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sup {
top: -0.5em;
}
sub {
bottom: -0.25em;
}
@if $legacy_browser_support {
/* ==========================================================================
Lists
========================================================================== */
/*
* Addresses margins set differently in IE 6/7.
*/
dl,
menu,
ol,
ul {
*margin: 1em 0;
}
dd {
*margin: 0 0 0 40px;
}
/*
* Addresses paddings set differently in IE 6/7.
*/
menu,
ol,
ul {
*padding: 0 0 0 40px;
}
/*
* Corrects list images handled incorrectly in IE 7.
*/
nav ul,
nav ol {
*list-style: none;
*list-style-image: none;
}
}
/* Embedded content
========================================================================== */
/**
* 1. Remove border when inside `a` element in IE 8/9/10.
* 2. Improves image quality when scaled in IE 7.
*/
img {
border: 0;
@if $legacy_browser_support {
*-ms-interpolation-mode: bicubic; /* 2 */
}
}
/**
* Correct overflow not hidden in IE 9/10/11.
*/
svg:not(:root) {
overflow: hidden;
}
/* Grouping content
========================================================================== */
/**
* Address margin not present in IE 8/9 and Safari.
*/
figure {
margin: 1em 40px;
}
/**
* Address differences between Firefox and other browsers.
*/
hr {
box-sizing: content-box;
height: 0;
}
/**
* Contain overflow in all browsers.
*/
pre {
overflow: auto;
}
/**
* Address odd `em`-unit font size rendering in all browsers.
* Correct font family set oddly in IE 6, Safari 4/5, and Chrome.
*/
code,
kbd,
pre,
samp {
font-family: monospace, monospace;
@if $legacy_browser_support {
_font-family: 'courier new', monospace;
}
font-size: 1em;
}
/* Forms
========================================================================== */
/**
* Known limitation: by default, Chrome and Safari on OS X allow very limited
* styling of `select`, unless a `border` property is set.
*/
/**
* 1. Correct color not being inherited.
* Known issue: affects color of disabled elements.
* 2. Correct font properties not being inherited.
* 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
* 4. Improves appearance and consistency in all browsers.
*/
button,
input,
optgroup,
select,
textarea {
color: inherit; /* 1 */
font: inherit; /* 2 */
margin: 0; /* 3 */
@if $legacy_browser_support {
vertical-align: baseline; /* 3 */
*vertical-align: middle; /* 3 */
}
}
/**
* Address `overflow` set to `hidden` in IE 8/9/10/11.
*/
button {
overflow: visible;
}
/**
* Address inconsistent `text-transform` inheritance for `button` and `select`.
* All other form control elements do not inherit `text-transform` values.
* Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
* Correct `select` style inheritance in Firefox.
*/
button,
select {
text-transform: none;
}
/**
* 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
* and `video` controls.
* 2. Correct inability to style clickable `input` types in iOS.
* 3. Improve usability and consistency of cursor style between image-type
* `input` and others.
* 4. Removes inner spacing in IE 7 without affecting normal text inputs.
* Known issue: inner spacing remains in IE 6.
*/
button,
html input[type="button"], /* 1 */
input[type="reset"],
input[type="submit"] {
-webkit-appearance: button; /* 2 */
cursor: pointer; /* 3 */
@if $legacy_browser_support {
*overflow: visible; /* 4 */
}
}
/**
* Re-set default cursor for disabled elements.
*/
button[disabled],
html input[disabled] {
cursor: default;
}
/**
* Remove inner padding and border in Firefox 4+.
*/
button::-moz-focus-inner,
input::-moz-focus-inner {
border: 0;
padding: 0;
}
/**
* Address Firefox 4+ setting `line-height` on `input` using `!important` in
* the UA stylesheet.
*/
input {
line-height: normal;
}
/**
* 1. Address box sizing set to `content-box` in IE 8/9/10.
* 2. Remove excess padding in IE 8/9/10.
* Known issue: excess padding remains in IE 6.
*/
input[type="checkbox"],
input[type="radio"] {
box-sizing: border-box; /* 1 */
padding: 0; /* 2 */
@if $legacy_browser_support {
*height: 13px; /* 3 */
*width: 13px; /* 3 */
}
}
/**
* Fix the cursor style for Chrome's increment/decrement buttons. For certain
* `font-size` values of the `input`, it causes the cursor style of the
* decrement button to change from `default` to `text`.
*/
input[type="number"]::-webkit-inner-spin-button,
input[type="number"]::-webkit-outer-spin-button {
height: auto;
}
/**
* 1. Address `appearance` set to `searchfield` in Safari and Chrome.
* 2. Address `box-sizing` set to `border-box` in Safari and Chrome.
*/
input[type="search"] {
-webkit-appearance: textfield; /* 1 */
box-sizing: content-box; /* 2 */
}
/**
* Remove inner padding and search cancel button in Safari and Chrome on OS X.
* Safari (but not Chrome) clips the cancel button when the search input has
* padding (and `textfield` appearance).
*/
input[type="search"]::-webkit-search-cancel-button,
input[type="search"]::-webkit-search-decoration {
-webkit-appearance: none;
}
/**
* Define consistent border, margin, and padding.
*/
fieldset {
border: 1px solid #c0c0c0;
margin: 0 2px;
padding: 0.35em 0.625em 0.75em;
}
/**
* 1. Correct `color` not being inherited in IE 8/9/10/11.
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
* 3. Corrects text not wrapping in Firefox 3.
* 4. Corrects alignment displayed oddly in IE 6/7.
*/
legend {
border: 0; /* 1 */
padding: 0; /* 2 */
@if $legacy_browser_support {
white-space: normal; /* 3 */
*margin-left: -7px; /* 4 */
}
}
/**
* Remove default vertical scrollbar in IE 8/9/10/11.
*/
textarea {
overflow: auto;
}
/**
* Don't inherit the `font-weight` (applied by a rule above).
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
*/
optgroup {
font-weight: bold;
}
/* Tables
========================================================================== */
/**
* Remove most spacing between table cells.
*/
table {
border-collapse: collapse;
border-spacing: 0;
}
td,
th {
padding: 0;
}
.main {
width: 100%;
height: 100vh;
}
// Components
@import './components/loading';

3
src/css/app/_base.scss Normal file
View File

@ -0,0 +1,3 @@
body {
overflow: hidden;
}

View File

@ -1,4 +1,5 @@
.main {
position: relative;
width: 100%;
height: 100vh;
}

View File

@ -0,0 +1,5 @@
#loading {
position: absolute;
top: calc(50% - 8px);
left: calc(50% - 35px);
}

View File

@ -0,0 +1,64 @@
html {
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
font: 16px/1 sans-serif;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
}
h1,
h2,
h3,
h4,
p,
blockquote,
figure,
ol,
ul {
margin: 0;
padding: 0;
}
main,
li {
display: block;
}
h1,
h2,
h3,
h4 {
font-size: inherit;
}
strong {
font-weight: bold;
}
a,
button {
color: inherit;
transition: .3s;
}
a {
text-decoration: none;
}
button {
overflow: visible;
border: 0;
font: inherit;
-webkit-font-smoothing: inherit;
letter-spacing: inherit;
background: none;
cursor: pointer;
}
::-moz-focus-inner {
padding: 0;
border: 0;
}
:focus {
outline: 0;
}
img {
max-width: 100%;
height: auto;
border: 0;
}

19
src/html/index.html Normal file
View File

@ -0,0 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<section id="appContainer" class="main">
<div id="loading">Loading...</div>
</section>
<% if (htmlWebpackPlugin.options.env === 'dev') { %>
<script src="js/rStats.js"></script>
<script src="js/rStats.extras.js"></script>
<script src="js/dat.gui.min.js"></script>
<% } %>
</body>
</html>

View File

@ -2,14 +2,18 @@ import Config from './data/config';
import Detector from './utils/detector';
import Main from './app/main';
// verify environment.
if(__ENV__ == 'dev') {
// Styles
import './../css/app.scss';
// Check environment and set the Config helper
if(__ENV__ === 'dev') {
console.log('----- RUNNING IN DEV ENVIRONMENT! -----');
Config.isDev = true;
}
function init() {
// Check for webGL capabilities
if(!Detector.webgl) {
Detector.addGetWebGLMessage();
} else {
@ -18,4 +22,4 @@ function init() {
}
}
window.onload = init;
init();

View File

@ -1,11 +1,14 @@
import THREE from 'three';
import * as THREE from 'three';
export default class Animation {
constructor(obj, clip) {
// Scene that the clip will be applied to
this.obj = obj;
// Initialize animation mixer
this.mixer = new THREE.AnimationMixer(this.obj);
// Simple animation player
this.playClip(clip);
}
@ -15,6 +18,7 @@ export default class Animation {
this.action.play();
}
// Call update in loop
update(delta) {
if(this.mixer) {
this.mixer.update(delta);

View File

@ -1,23 +1,29 @@
import THREE from 'three';
import * as THREE from 'three';
import Config from './../data/config';
import Config from '../../data/config';
// Class that creates and updates the main camera
export default class Camera {
constructor(renderer) {
const width = renderer.domElement.width;
const height = renderer.domElement.height;
// Create and position a Perspective Camera
this.threeCamera = new THREE.PerspectiveCamera(Config.camera.fov, width / height, Config.camera.near, Config.camera.far);
this.threeCamera.position.set(Config.camera.posX, Config.camera.posY, Config.camera.posZ);
// Initial sizing
this.updateSize(renderer);
// listeners
// Listeners
window.addEventListener('resize', () => this.updateSize(renderer), false);
}
updateSize(renderer) {
this.threeCamera.aspect = (renderer.domElement.width * Config.dpr) / (renderer.domElement.height * Config.dpr);
// Update camera aspect ratio with window aspect ratio
this.threeCamera.aspect = renderer.domElement.width / renderer.domElement.height;
// Always call updateProjectionMatrix on camera change
this.threeCamera.updateProjectionMatrix();
}
}

View File

@ -1,10 +1,12 @@
import THREE from 'three';
import * as THREE from 'three';
import OrbitControls from '../utils/orbitControls';
import Config from './../data/config';
import OrbitControls from '../../utils/orbitControls';
import Config from '../../data/config';
// Controls based on orbit controls
export default class Controls {
constructor(camera, container) {
// Orbit controls first needs to pass in THREE to constructor
const orbitControls = new OrbitControls(THREE);
this.threeControls = new orbitControls(camera, container);

View File

@ -1,7 +1,9 @@
import THREE from 'three';
import * as THREE from 'three';
import Config from '../data/config';
import Material from './material';
import Config from '../../data/config';
// This helper class can be used to create and then place geometry in the scene
export default class Geometry {
constructor(scene) {
this.scene = scene;
@ -9,23 +11,29 @@ export default class Geometry {
}
make(type) {
if(type == 'plane') {
if(type === 'plane') {
return (width, height, widthSegments = 1, heightSegments = 1) => {
this.geo = new THREE.PlaneGeometry(width, height, widthSegments, heightSegments);
}
};
}
if(type === 'sphere') {
return (radius, widthSegments = 32, heightSegments = 32) => {
this.geo = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
};
}
}
place(position, rotation) {
const material = new THREE.MeshStandardMaterial({ color: 0xCCCCCC, side: THREE.DoubleSide });
const material = new Material(0xeeeeee).standard;
const mesh = new THREE.Mesh(this.geo, material);
// Use ES6 spread to set position and rotation from passed in array
mesh.position.set(...position);
mesh.rotation.set(...rotation);
if(Config.shadow.enabled) {
mesh.receiveShadow = true;
mesh.castShadow = true;
}
this.scene.add(mesh);

View File

@ -1,7 +1,8 @@
import THREE from 'three';
import * as THREE from 'three';
import Config from './../data/config';
import Config from '../../data/config';
// Sets up and places all lights in scene
export default class Light {
constructor(scene) {
this.scene = scene;
@ -10,21 +11,21 @@ export default class Light {
}
init() {
// ambient
// Ambient
this.ambientLight = new THREE.AmbientLight(Config.ambientLight.color);
this.ambientLight.visible = Config.ambientLight.enabled;
// point light
// Point light
this.pointLight = new THREE.PointLight(Config.pointLight.color, Config.pointLight.intensity, Config.pointLight.distance);
this.pointLight.position.set(Config.pointLight.x, Config.pointLight.y, Config.pointLight.z);
this.pointLight.visible = Config.pointLight.enabled;
// directional light
// Directional light
this.directionalLight = new THREE.DirectionalLight(Config.directionalLight.color, Config.directionalLight.intensity);
this.directionalLight.position.set(Config.directionalLight.x, Config.directionalLight.y, Config.directionalLight.z);
this.directionalLight.visible = Config.directionalLight.enabled;
// shadow map
// Shadow map
this.directionalLight.castShadow = Config.shadow.enabled;
this.directionalLight.shadow.bias = Config.shadow.bias;
this.directionalLight.shadow.camera.near = Config.shadow.near;
@ -36,11 +37,12 @@ export default class Light {
this.directionalLight.shadow.mapSize.width = Config.shadow.mapWidth;
this.directionalLight.shadow.mapSize.height = Config.shadow.mapHeight;
// shadow camera helper
this.directionalLightHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);
this.directionalLightHelper.visible = Config.shadow.helperEnabled;
// hemisphere light
// Shadow camera helper
if(Config.isDev) {
this.directionalLightHelper = new THREE.CameraHelper(this.directionalLight.shadow.camera);
this.directionalLightHelper.visible = Config.shadow.helperEnabled;
}
// Hemisphere light
this.hemiLight = new THREE.HemisphereLight(Config.hemiLight.color, Config.hemiLight.groundColor, Config.hemiLight.intensity);
this.hemiLight.position.set(Config.hemiLight.x, Config.hemiLight.y, Config.hemiLight.z);
this.hemiLight.visible = Config.hemiLight.enabled;
@ -54,7 +56,9 @@ export default class Light {
case 'directional':
this.scene.add(this.directionalLight);
this.scene.add(this.directionalLightHelper);
if(Config.isDev) {
this.scene.add(this.directionalLightHelper);
}
break;
case 'point':

View File

@ -0,0 +1,22 @@
import * as THREE from 'three';
// USe this class as a helper to set up some default materials
export default class Material {
constructor(color) {
this.basic = new THREE.MeshBasicMaterial({
color,
side: THREE.DoubleSide
});
this.standard = new THREE.MeshStandardMaterial({
color,
shading: THREE.FlatShading,
roughness: 1,
metalness: 0,
side: THREE.DoubleSide
});
this.wire = new THREE.MeshBasicMaterial({wireframe: true});
}
}

View File

@ -1,32 +1,32 @@
import THREE from 'three';
import * as THREE from 'three';
import Config from './../data/config';
import Config from '../../data/config';
// Main webGL renderer class
export default class Renderer {
constructor(container, scene) {
this.container = container;
constructor(scene, container) {
// Properties
this.scene = scene;
this.container = container;
// Create WebGL renderer and set its antialias
this.threeRenderer = new THREE.WebGLRenderer({antialias: true});
//this.renderer.setClearColor(0x000000, 0);
// Set clear color to fog to enable fog or to hex color for no fog
this.threeRenderer.setClearColor(scene.fog.color);
this.threeRenderer.setPixelRatio(window.devicePixelRatio);
this.threeRenderer.setPixelRatio(window.devicePixelRatio); // For retina
// Appends canvas
container.appendChild(this.threeRenderer.domElement);
this.threeRenderer.gammaInput = true;
this.threeRenderer.gammaOutput = true;
// shadow
// Shadow map options
this.threeRenderer.shadowMap.enabled = true;
this.threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
this.threeRenderer.shadowMapSoft = true;
this.threeRenderer.autoClear = false;
Config.maxAnisotropy = this.threeRenderer.getMaxAnisotropy();
// Get anisotropy for textures
Config.maxAnisotropy = this.threeRenderer.capabilities.getMaxAnisotropy();
// Initial size update set to canvas container
this.updateSize();
// Listeners
@ -39,6 +39,7 @@ export default class Renderer {
}
render(scene, camera) {
// Renders scene to canvas target
this.threeRenderer.render(scene, camera);
}
}

View File

@ -1,23 +0,0 @@
import THREE from 'three';
export default class Helper {
constructor(scene, mesh) {
let wireframe = new THREE.WireframeGeometry(mesh.geometry);
let wireLine = new THREE.LineSegments(wireframe);
wireLine.material.depthTest = false;
wireLine.material.opacity = 0.25;
wireLine.material.transparent = true;
mesh.add(wireLine);
let edges = new THREE.EdgesGeometry(mesh.geometry);
let edgesLine = new THREE.LineSegments(edges);
edgesLine.material.depthTest = false;
edgesLine.material.opacity = 0.25;
edgesLine.material.transparent = true;
mesh.add(edgesLine);
scene.add(new THREE.BoxHelper(mesh));
scene.add(new THREE.FaceNormalsHelper(mesh, 2));
scene.add(new THREE.VertexNormalsHelper(mesh, 2));
}
}

View File

@ -0,0 +1,41 @@
import * as THREE from 'three';
import { VertexNormalsHelper } from './vertexNormalsHelper';
// Simple mesh helper that shows edges, wireframes, and face and vertex normals
export default class MeshHelper {
constructor(scene, mesh) {
this.mesh = mesh;
this.scene = scene;
const wireframe = new THREE.WireframeGeometry(this.mesh.geometry);
this.wireLine = new THREE.LineSegments(wireframe);
this.wireLine.material.depthTest = false;
this.wireLine.material.opacity = 0.25;
this.wireLine.material.transparent = true;
const edges = new THREE.EdgesGeometry(this.mesh.geometry);
this.edgesLine = new THREE.LineSegments(edges);
this.edgesLine.material.depthTest = false;
this.edgesLine.material.opacity = 0.25;
this.edgesLine.material.transparent = true;
this.vertexHelper = new VertexNormalsHelper(this.mesh, 2);
this.boxHelper = new THREE.BoxHelper(this.mesh);
}
enable() {
this.mesh.add(this.wireLine);
this.mesh.add(this.edgesLine);
this.scene.add(this.vertexHelper);
this.scene.add(this.boxHelper);
}
disable() {
this.mesh.remove(this.wireLine);
this.mesh.remove(this.edgesLine);
this.scene.remove(this.vertexHelper);
this.scene.remove(this.boxHelper);
}
}

View File

@ -0,0 +1,55 @@
// Local vars for rStats
let rS, bS, glS, tS;
export default class Stats {
constructor(renderer) {
this.renderer = renderer;
}
setUp() {
bS = new BrowserStats();
glS = new glStats();
tS = new threeStats(this.renderer.threeRenderer);
rS = new rStats({
CSSPath: './css/',
userTimingAPI: true,
values: {
frame: { caption: 'Total frame time (ms)', over: 16, average: true, avgMs: 100 },
fps: { caption: 'Framerate (FPS)', below: 30 },
calls: { caption: 'Calls (three.js)', over: 3000 },
raf: { caption: 'Time since last rAF (ms)', average: true, avgMs: 100 },
rstats: { caption: 'rStats update (ms)', average: true, avgMs: 100 },
texture: { caption: 'GenTex', average: true, avgMs: 100 }
},
groups: [
{ caption: 'Framerate', values: ['fps', 'raf'] },
{ caption: 'Frame Budget', values: ['frame', 'texture', 'setup', 'render'] }
],
fractions: [
{ base: 'frame', steps: ['texture', 'setup', 'render'] }
],
plugins: [bS, tS]
});
}
static start() {
rS('frame').start();
glS.start();
rS('rAF').tick();
rS('FPS').frame();
rS('render').start();
}
static end() {
rS('render').end(); // render finished
rS('frame').end(); // frame finished
// Local rStats update
rS('rStats').start();
rS().update();
rS('rStats').end();
}
}

View File

@ -0,0 +1,124 @@
/**
* @author mrdoob / http://mrdoob.com/
* @author WestLangley / http://github.com/WestLangley
*/
import {
BufferGeometry,
Float32BufferAttribute,
LineSegments,
LineBasicMaterial,
Matrix3,
Vector3,
} from 'three';
const _v1 = new Vector3();
const _v2 = new Vector3();
const _normalMatrix = new Matrix3();
const _keys = ['a', 'b', 'c'];
function VertexNormalsHelper(object, size, hex) {
this.object = object;
this.size = size !== undefined ? size : 0.1;
const color = hex !== undefined ? hex : 0xff0000;
//
let nNormals = 0;
const objGeometry = this.object.geometry;
if (objGeometry && objGeometry.isGeometry) {
nNormals = objGeometry.faces.length * 3;
} else if (objGeometry && objGeometry.isBufferGeometry) {
nNormals = objGeometry.attributes.normal.count;
}
//
const geometry = new BufferGeometry();
const positions = new Float32BufferAttribute(nNormals * 2 * 3, 3);
geometry.setAttribute('position', positions);
LineSegments.call(this, geometry, new LineBasicMaterial({ color: color, toneMapped: false }));
this.type = 'VertexNormalsHelper';
//
this.matrixAutoUpdate = false;
this.update();
}
VertexNormalsHelper.prototype = Object.create(LineSegments.prototype);
VertexNormalsHelper.prototype.constructor = VertexNormalsHelper;
VertexNormalsHelper.prototype.update = function () {
let idx;
this.object.updateMatrixWorld(true);
_normalMatrix.getNormalMatrix(this.object.matrixWorld);
const matrixWorld = this.object.matrixWorld;
const position = this.geometry.attributes.position;
//
const objGeometry = this.object.geometry;
if (objGeometry && objGeometry.isGeometry) {
const vertices = objGeometry.vertices;
const faces = objGeometry.faces;
idx = 0;
for (let i = 0, l = faces.length; i < l; i++) {
const face = faces[i];
for (let j = 0, jl = face.vertexNormals.length; j < jl; j++) {
const vertex = vertices[face[_keys[j]]];
const normal = face.vertexNormals[j];
_v1.copy(vertex).applyMatrix4(matrixWorld);
_v2.copy(normal).applyMatrix3(_normalMatrix).normalize().multiplyScalar(this.size).add(_v1);
position.setXYZ(idx, _v1.x, _v1.y, _v1.z);
idx = idx + 1;
position.setXYZ(idx, _v2.x, _v2.y, _v2.z);
idx = idx + 1;
}
}
} else if (objGeometry && objGeometry.isBufferGeometry) {
const objPos = objGeometry.attributes.position;
const objNorm = objGeometry.attributes.normal;
idx = 0;
// for simplicity, ignore index and drawcalls, and render every normal
for (var j = 0, jl = objPos.count; j < jl; j++) {
_v1.set(objPos.getX(j), objPos.getY(j), objPos.getZ(j)).applyMatrix4(matrixWorld);
_v2.set(objNorm.getX(j), objNorm.getY(j), objNorm.getZ(j));
_v2.applyMatrix3(_normalMatrix).normalize().multiplyScalar(this.size).add(_v1);
position.setXYZ(idx, _v1.x, _v1.y, _v1.z);
idx = idx + 1;
position.setXYZ(idx, _v2.x, _v2.y, _v2.z);
idx = idx + 1;
}
}
position.needsUpdate = true;
};
export { VertexNormalsHelper };

File diff suppressed because it is too large Load Diff

View File

@ -1,147 +1,138 @@
// global imports
import THREE from 'three';
import TWEEN from 'tween.js';
// Global imports -
import * as THREE from 'three';
import TWEEN from '@tweenjs/tween.js';
// local imports
import Renderer from './renderer';
import Camera from './camera';
import Light from './light';
import Controls from './controls';
import Geometry from './geometry';
import Texture from './texture';
import Model from './model';
import Interaction from './interaction';
import GUI from './gui';
// Local imports -
// Components
import Renderer from './components/renderer';
import Camera from './components/camera';
import Light from './components/light';
import Controls from './components/controls';
import Geometry from './components/geometry';
// Helpers
import Stats from './helpers/stats';
import MeshHelper from './helpers/meshHelper';
// Model
import Texture from './model/texture';
import Model from './model/model';
// Managers
import Interaction from './managers/interaction';
import DatGUI from './managers/datGUI';
// data
import Config from './../data/config';
// -- End of imports
// stats
let rS, bS, glS, tS;
// This class instantiates and ties all of the components together, starts the loading process and renders the main loop
export default class Main {
constructor(container) {
// Set container property to container element
this.container = container;
// Start Three clock
this.clock = new THREE.Clock();
// Main scene
// Main scene creation
this.scene = new THREE.Scene();
this.scene.fog = new THREE.FogExp2(Config.fog.color, Config.fog.near);
// Get Device Pixel Ratio first
// Get Device Pixel Ratio first for retina
if(window.devicePixelRatio) {
Config.dpr = window.devicePixelRatio;
}
// Main renderer
this.renderer = new Renderer(container, this.scene);
// Main renderer constructor
this.renderer = new Renderer(this.scene, container);
// Components
// Components instantiations
this.camera = new Camera(this.renderer.threeRenderer);
this.controls = new Controls(this.camera.threeCamera, this.container);
this.controls = new Controls(this.camera.threeCamera, container);
this.light = new Light(this.scene);
// Place lights
// Create and place lights in scene
const lights = ['ambient', 'directional', 'point', 'hemi'];
for(let i = 0; i < lights.length; i++) {
this.light.place(lights[i]);
}
lights.forEach((light) => this.light.place(light));
// Place geo
// Create and place geo in scene
this.geometry = new Geometry(this.scene);
this.geometry.make('plane')(100, 100, 10, 10);
this.geometry.place([0, -20, 0], [Math.PI/2, 0, 0]);
this.geometry.make('plane')(150, 150, 10, 10);
this.geometry.place([0, -20, 0], [Math.PI / 2, 0, 0]);
// Set up stats if dev
if(Config.isDev) {
bS = new BrowserStats();
glS = new glStats();
tS = new threeStats(this.renderer.threeRenderer);
rS = new rStats({
CSSPath: '/assets/css/',
userTimingAPI: true,
values: {
frame: { caption: 'Total frame time (ms)', over: 16, average: true, avgMs: 100 },
fps: { caption: 'Framerate (FPS)', below: 30 },
calls: { caption: 'Calls (three.js)', over: 3000 },
raf: { caption: 'Time since last rAF (ms)', average: true, avgMs: 100 },
rstats: { caption: 'rStats update (ms)', average: true, avgMs: 100 },
texture: { caption: 'GenTex', average: true, avgMs: 100 }
},
groups: [
{ caption: 'Framerate', values: [ 'fps', 'raf' ] },
{ caption: 'Frame Budget', values: [ 'frame', 'texture', 'setup', 'render' ] }
],
fractions: [
{ base: 'frame', steps: [ 'texture', 'setup', 'render' ] }
],
plugins: [bS, tS, glS]
});
// Set up rStats if dev environment
if(Config.isDev && Config.isShowingStats) {
this.stats = new Stats(this.renderer);
this.stats.setUp();
}
// Set up gui
if (Config.isDev) {
this.gui = new DatGUI(this)
}
// Instantiate texture class
this.texture = new Texture();
// Start loading the textures
// Start loading the textures and then go on to load the model after the texture Promises have resolved
this.texture.load().then(() => {
this.manager = new THREE.LoadingManager();
// Textures loaded, load main model
this.model = new Model(this.scene, this.manager, this.texture.textures);
this.model.load();
// onProgress
// Textures loaded, load model
this.model = new Model(this.scene, this.manager, this.texture.textures);
this.model.load(Config.models[Config.model.selected].type);
// onProgress callback
this.manager.onProgress = (item, loaded, total) => {
console.log(`${item}: ${loaded} ${total}`);
};
// All loaders done
// All loaders done now
this.manager.onLoad = () => {
// Set up interaction with app
// Set up interaction manager with the app now that the model is finished loading
new Interaction(this.renderer.threeRenderer, this.scene, this.camera.threeCamera, this.controls.threeControls);
// Add dat.GUI controls if dev
if(Config.isDev) {
new GUI(this, this.model.obj);
this.meshHelper = new MeshHelper(this.scene, this.model.obj);
if (Config.mesh.enableHelper) this.meshHelper.enable();
this.gui.load(this, this.model.obj);
}
// Everything is now fully loaded
Config.isLoaded = true;
this.container.querySelector('#loading').style.display = 'none';
};
});
// Start render which does not wait for model fully loaded
this.render();
}
render() {
const delta = this.clock.getDelta();
if(Config.isDev) {
rS('frame').start();
glS.start();
rS('rAF').tick();
rS('FPS').frame();
rS('render').start();
// Render rStats if Dev
if(Config.isDev && Config.isShowingStats) {
Stats.start();
}
// Clear renderer
this.renderer.threeRenderer.clear();
// Call render function and pass in created scene and camera
this.renderer.render(this.scene, this.camera.threeCamera);
if(Config.isDev) {
rS('render').end();
rS('frame').end();
rS('rStats').start();
rS().update();
rS('rStats').end();
// rStats has finished determining render call now
if(Config.isDev && Config.isShowingStats) {
Stats.end();
}
// Updates
// Delta time is sometimes needed for certain updates
//const delta = this.clock.getDelta();
// Call any vendor or module frame updates here
TWEEN.update();
this.controls.threeControls.update();
// raf
requestAnimationFrame(this.render.bind(this));
// RAF
requestAnimationFrame(this.render.bind(this)); // Bind the main class instead of window object
}
}

View File

@ -1,72 +1,103 @@
import Config from './../data/config';
import Config from '../../data/config';
export default class GUI {
constructor(main, mesh) {
let gui = new dat.GUI();
// Manages all dat.GUI interactions
export default class DatGUI {
constructor(main) {
this.gui = new dat.GUI();
this.camera = main.camera.threeCamera;
this.controls = main.controls.threeControls;
this.light = main.light;
this.scene = main.scene;
this.model = null;
this.meshHelper = null;
}
load(main, mesh) {
/* Global */
//gui.close();
//this.gui.close();
this.model = main.model;
this.meshHelper = main.meshHelper;
/* Camera */
let cameraFolder = gui.addFolder('Camera');
let cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV');
const cameraFolder = this.gui.addFolder('Camera');
const cameraFOVGui = cameraFolder.add(Config.camera, 'fov', 0, 180).name('Camera FOV');
cameraFOVGui.onChange((value) => {
this.controls.enableRotate = false;
this.camera.fov = value;
});
cameraFOVGui.onFinishChange((value) => {
cameraFOVGui.onFinishChange(() => {
this.camera.updateProjectionMatrix();
this.controls.enableRotate = true;
});
let cameraAspectGui = cameraFolder.add(Config.camera, 'aspect', 0, 4).name('Camera Aspect');
const cameraAspectGui = cameraFolder.add(Config.camera, 'aspect', 0, 4).name('Camera Aspect');
cameraAspectGui.onChange((value) => {
this.controls.enableRotate = false;
this.camera.aspect = value;
});
cameraAspectGui.onFinishChange((value) => {
cameraAspectGui.onFinishChange(() => {
this.camera.updateProjectionMatrix();
this.controls.enableRotate = true;
});
let cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color');
const cameraFogColorGui = cameraFolder.addColor(Config.fog, 'color').name('Fog Color');
cameraFogColorGui.onChange((value) => {
main.scene.fog.color.setHex(value);
this.scene.fog.color.setHex(value);
});
let cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near');
const cameraFogNearGui = cameraFolder.add(Config.fog, 'near', 0.000, 0.010).name('Fog Near');
cameraFogNearGui.onChange((value) => {
this.controls.enableRotate = false;
main.scene.fog.density = value;
this.scene.fog.density = value;
});
cameraFogNearGui.onFinishChange((value) => {
cameraFogNearGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
/* Controls */
let controlsFolder = gui.addFolder('Controls');
const controlsFolder = this.gui.addFolder('Controls');
controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => {
this.controls.autoRotate = value;
});
let controlsAutoRotateSpeedGui = controlsFolder.add(Config.controls, 'autoRotateSpeed', -1, 1).name('Rotation Speed');
const controlsAutoRotateSpeedGui = controlsFolder.add(Config.controls, 'autoRotateSpeed', -1, 1).name('Rotation Speed');
controlsAutoRotateSpeedGui.onChange((value) => {
this.controls.enableRotate = false;
this.controls.autoRotateSpeed = value;
});
controlsAutoRotateSpeedGui.onFinishChange((value) => {
controlsAutoRotateSpeedGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
/* Model */
const modelFolder = this.gui.addFolder('Model');
modelFolder.add(Config.model, 'type', [...Config.model.initialTypes]).name('Select Model').onChange((value) => {
if (value) {
if (Config.mesh.enableHelper)
this.meshHelper.disable();
Config.model.selected = Config.model.initialTypes.indexOf(value);
this.unload();
this.model.unload();
this.model.load(value);
}
});
/* Mesh */
let meshFolder = gui.addFolder('Mesh');
const meshFolder = this.gui.addFolder('Mesh');
meshFolder.add(Config.mesh, 'enableHelper', true).name('Enable Helpers').onChange((value) => {
if(value) {
this.meshHelper.enable();
} else {
this.meshHelper.disable();
}
});
meshFolder.add(Config.mesh, 'translucent', true).name('Translucent').onChange((value) => {
if(value) {
mesh.material.transparent = true;
@ -82,7 +113,7 @@ export default class GUI {
/* Lights */
// Ambient Light
let ambientLightFolder = gui.addFolder('Ambient Light');
const ambientLightFolder = this.gui.addFolder('Ambient Light');
ambientLightFolder.add(Config.ambientLight, 'enabled').name('Enabled').onChange((value) => {
this.light.ambientLight.visible = value;
});
@ -92,137 +123,137 @@ export default class GUI {
// Directional Light
let directionalLightFolder = gui.addFolder('Directional Light');
const directionalLightFolder = this.gui.addFolder('Directional Light');
directionalLightFolder.add(Config.directionalLight, 'enabled').name('Enabled').onChange((value) => {
this.light.directionalLight.visible = value;
});
directionalLightFolder.addColor(Config.directionalLight, 'color').name('Color').onChange((value) => {
this.light.directionalLight.color.setHex(value);
});
let directionalLightIntensityGui = directionalLightFolder.add(Config.directionalLight, 'intensity', 0, 2).name('Intensity');
const directionalLightIntensityGui = directionalLightFolder.add(Config.directionalLight, 'intensity', 0, 2).name('Intensity');
directionalLightIntensityGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.intensity = value;
});
directionalLightIntensityGui.onFinishChange((value) => {
directionalLightIntensityGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let directionalLightPositionXGui = directionalLightFolder.add(Config.directionalLight, 'x', -1000, 1000).name('Position X');
const directionalLightPositionXGui = directionalLightFolder.add(Config.directionalLight, 'x', -1000, 1000).name('Position X');
directionalLightPositionXGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.position.x = value;
});
directionalLightPositionXGui.onFinishChange((value) => {
directionalLightPositionXGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let directionalLightPositionYGui = directionalLightFolder.add(Config.directionalLight, 'y', -1000, 1000).name('Position Y');
const directionalLightPositionYGui = directionalLightFolder.add(Config.directionalLight, 'y', -1000, 1000).name('Position Y');
directionalLightPositionYGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.position.y = value;
});
directionalLightPositionYGui.onFinishChange((value) => {
directionalLightPositionYGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let directionalLightPositionZGui = directionalLightFolder.add(Config.directionalLight, 'z', -1000, 1000).name('Position Z');
const directionalLightPositionZGui = directionalLightFolder.add(Config.directionalLight, 'z', -1000, 1000).name('Position Z');
directionalLightPositionZGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.position.z = value;
});
directionalLightPositionZGui.onFinishChange((value) => {
directionalLightPositionZGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
// Shadow Map
let shadowFolder = gui.addFolder('Shadow Map');
const shadowFolder = this.gui.addFolder('Shadow Map');
shadowFolder.add(Config.shadow, 'enabled').name('Enabled').onChange((value) => {
this.light.directionalLight.castShadow = value;
});
shadowFolder.add(Config.shadow, 'helperEnabled').name('Helper Enabled').onChange((value) => {
this.light.directionalLightHelper.visible = value;
});
let shadowNearGui = shadowFolder.add(Config.shadow, 'near', 0, 100).name('Near');
const shadowNearGui = shadowFolder.add(Config.shadow, 'near', 0, 400).name('Near');
shadowNearGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.near = value;
});
shadowNearGui.onFinishChange((value) => {
shadowNearGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowFarGui = shadowFolder.add(Config.shadow, 'far', 0, 1200).name('Far');
const shadowFarGui = shadowFolder.add(Config.shadow, 'far', 0, 1200).name('Far');
shadowFarGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.far = value;
});
shadowFarGui.onFinishChange((value) => {
shadowFarGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowTopGui = shadowFolder.add(Config.shadow, 'top', -400, 400).name('Top');
const shadowTopGui = shadowFolder.add(Config.shadow, 'top', -400, 400).name('Top');
shadowTopGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.top = value;
});
shadowTopGui.onFinishChange((value) => {
shadowTopGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowRightGui = shadowFolder.add(Config.shadow, 'right', -400, 400).name('Right');
const shadowRightGui = shadowFolder.add(Config.shadow, 'right', -400, 400).name('Right');
shadowRightGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.right = value;
});
shadowRightGui.onFinishChange((value) => {
shadowRightGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowBottomGui = shadowFolder.add(Config.shadow, 'bottom', -400, 400).name('Bottom');
const shadowBottomGui = shadowFolder.add(Config.shadow, 'bottom', -400, 400).name('Bottom');
shadowBottomGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.bottom = value;
});
shadowBottomGui.onFinishChange((value) => {
shadowBottomGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowLeftGui = shadowFolder.add(Config.shadow, 'left', -400, 400).name('Left');
const shadowLeftGui = shadowFolder.add(Config.shadow, 'left', -400, 400).name('Left');
shadowLeftGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.camera.left = value;
});
shadowLeftGui.onFinishChange((value) => {
shadowLeftGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
this.light.directionalLightHelper.update();
});
let shadowBiasGui = shadowFolder.add(Config.shadow, 'bias', -0.000010, 1).name('Bias');
const shadowBiasGui = shadowFolder.add(Config.shadow, 'bias', -0.000010, 1).name('Bias');
shadowBiasGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.directionalLight.shadow.bias = value;
});
shadowBiasGui.onFinishChange((value) => {
shadowBiasGui.onFinishChange(() => {
this.controls.enableRotate = true;
this.light.directionalLight.shadow.map.dispose();
this.light.directionalLight.shadow.map = null;
@ -231,62 +262,62 @@ export default class GUI {
// Point Light
let pointLightFolder = gui.addFolder('Point Light');
const pointLightFolder = this.gui.addFolder('Point Light');
pointLightFolder.add(Config.pointLight, 'enabled').name('Enabled').onChange((value) => {
this.light.pointLight.visible = value;
});
pointLightFolder.addColor(Config.pointLight, 'color').name('Color').onChange((value) => {
this.light.pointLight.color.setHex(value);
});
let pointLightIntensityGui = pointLightFolder.add(Config.pointLight, 'intensity', 0, 2).name('Intensity');
const pointLightIntensityGui = pointLightFolder.add(Config.pointLight, 'intensity', 0, 2).name('Intensity');
pointLightIntensityGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.pointLight.intensity = value;
});
pointLightIntensityGui.onFinishChange((value) => {
pointLightIntensityGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let pointLightDistanceGui = pointLightFolder.add(Config.pointLight, 'distance', 0, 1000).name('Distance');
const pointLightDistanceGui = pointLightFolder.add(Config.pointLight, 'distance', 0, 1000).name('Distance');
pointLightDistanceGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.pointLight.distance = value;
});
pointLightDistanceGui.onFinishChange((value) => {
pointLightDistanceGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let pointLightPositionXGui = pointLightFolder.add(Config.pointLight, 'x', -1000, 1000).name('Position X');
const pointLightPositionXGui = pointLightFolder.add(Config.pointLight, 'x', -1000, 1000).name('Position X');
pointLightPositionXGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.pointLight.position.x = value;
});
pointLightPositionXGui.onFinishChange((value) => {
pointLightPositionXGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let pointLightPositionYGui = pointLightFolder.add(Config.pointLight, 'y', -1000, 1000).name('Position Y');
const pointLightPositionYGui = pointLightFolder.add(Config.pointLight, 'y', -1000, 1000).name('Position Y');
pointLightPositionYGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.pointLight.position.y = value;
});
pointLightPositionYGui.onFinishChange((value) => {
pointLightPositionYGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let pointLightPositionZGui = pointLightFolder.add(Config.pointLight, 'z', -1000, 1000).name('Position Z');
const pointLightPositionZGui = pointLightFolder.add(Config.pointLight, 'z', -1000, 1000).name('Position Z');
pointLightPositionZGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.pointLight.position.z = value;
});
pointLightPositionZGui.onFinishChange((value) => {
pointLightPositionZGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
// Hemi Light
let hemiLightFolder = gui.addFolder('Hemi Light');
const hemiLightFolder = this.gui.addFolder('Hemi Light');
hemiLightFolder.add(Config.hemiLight, 'enabled').name('Enabled').onChange((value) => {
this.light.hemiLight.visible = value;
});
@ -296,74 +327,46 @@ export default class GUI {
hemiLightFolder.addColor(Config.hemiLight, 'groundColor').name('ground Color').onChange((value) => {
this.light.hemiLight.groundColor.setHex(value);
});
let hemiLightIntensityGui = hemiLightFolder.add(Config.hemiLight, 'intensity', 0, 2).name('Intensity');
const hemiLightIntensityGui = hemiLightFolder.add(Config.hemiLight, 'intensity', 0, 2).name('Intensity');
hemiLightIntensityGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.hemiLight.intensity = value;
});
hemiLightIntensityGui.onFinishChange((value) => {
hemiLightIntensityGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let hemiLightPositionXGui = hemiLightFolder.add(Config.hemiLight, 'x', -1000, 1000).name('Position X');
const hemiLightPositionXGui = hemiLightFolder.add(Config.hemiLight, 'x', -1000, 1000).name('Position X');
hemiLightPositionXGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.hemiLight.position.x = value;
});
hemiLightPositionXGui.onFinishChange((value) => {
hemiLightPositionXGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let hemiLightPositionYGui = hemiLightFolder.add(Config.hemiLight, 'y', -500, 1000).name('Position Y');
const hemiLightPositionYGui = hemiLightFolder.add(Config.hemiLight, 'y', -500, 1000).name('Position Y');
hemiLightPositionYGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.hemiLight.position.y = value;
});
hemiLightPositionYGui.onFinishChange((value) => {
hemiLightPositionYGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
let hemiLightPositionZGui = hemiLightFolder.add(Config.hemiLight, 'z', -1000, 1000).name('Position Z');
const hemiLightPositionZGui = hemiLightFolder.add(Config.hemiLight, 'z', -1000, 1000).name('Position Z');
hemiLightPositionZGui.onChange((value) => {
this.controls.enableRotate = false;
this.light.hemiLight.position.z = value;
});
hemiLightPositionZGui.onFinishChange((value) => {
hemiLightPositionZGui.onFinishChange(() => {
this.controls.enableRotate = true;
});
}
handleColorChange(color) {
return (value) => {
if(typeof value === 'string') {
value = value.replace('#', '0x');
}
color.setHex(value);
};
}
needsUpdate(material, geometry) {
return function() {
material.shading = +material.shading; //Ensure number
material.vertexColors = +material.vertexColors; //Ensure number
material.side = +material.side; //Ensure number
material.needsUpdate = true;
geometry.verticesNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
};
}
updateTexture(material, materialKey, textures) {
return function(key) {
material[materialKey] = textures[key];
material.needsUpdate = true;
};
}
update() {
this.needsUpdate(mesh.material, mesh.geometry);
unload() {
this.gui.destroy();
this.gui = new dat.GUI();
}
}

View File

@ -1,54 +1,61 @@
import THREE from 'three';
import Keyboard from './../utils/keyboard';
import Helpers from './../utils/helpers';
import Config from './../data/config';
import Keyboard from '../../utils/keyboard';
import Helpers from '../../utils/helpers';
import Config from '../../data/config';
// Manages all input interactions
export default class Interaction {
constructor(renderer, scene, camera, controls) {
// Properties
this.renderer = renderer;
this.scene = scene;
this.camera = camera;
this.controls = controls;
this.timeout = null;
// Instantiate keyboard helper
this.keyboard = new Keyboard();
// listeners
// mouse events
this.renderer.domElement.addEventListener('mouseup', (event) => this.onMouseUp(event), false);
// Listeners
// Mouse events
this.renderer.domElement.addEventListener('mousemove', (event) => Helpers.throttle(this.onMouseMove(event), 250), false);
this.renderer.domElement.addEventListener('mouseenter', (event) => this.onMouseEnter(event), false);
this.renderer.domElement.addEventListener('mouseleave', (event) => this.onMouseLeave(event), false);
this.renderer.domElement.addEventListener('mouseover', (event) => this.onMouseOver(event), false);
// keyboard events
// Keyboard events
this.keyboard.domElement.addEventListener('keydown', (event) => {
// Only once
if(event.repeat) {
return;
}
if(this.keyboard.eventMatches(event, 'escape')) {
console.log('Escape pressed');
}
});
}
onMouseEnter(event) {
event.preventDefault();
}
onMouseOver(event) {
event.preventDefault();
Config.isMouseOver = true;
}
onMouseLeave(event) {
event.preventDefault();
Config.isMouseOver = false;
}
onMouseMove(event) {
event.preventDefault();
}
onMouseUp(event) {
event.preventDefault();
clearTimeout(this.timeout);
this.timeout = setTimeout(function() {
Config.isMouseMoving = false;
}, 200);
Config.isMouseMoving = true;
}
}

View File

@ -1,24 +0,0 @@
import THREE from 'three';
import Config from './../data/config';
export default class Material {
constructor() {
this.emissive = new THREE.MeshBasicMaterial({
color: 0xeeeeee,
side: THREE.DoubleSide,
fog: false
});
this.standard = new THREE.MeshStandardMaterial({
shading: THREE.FlatShading,
roughness: 1,
metalness: 0,
side: THREE.DoubleSide,
fog: false
});
this.wire = new THREE.MeshBasicMaterial({wireframe: true});
}
}

View File

@ -1,57 +0,0 @@
import THREE from 'three';
import Material from './material';
import Helper from './helper';
import Config from './../data/config';
export default class Model {
constructor(scene, manager, textures) {
this.scene = scene;
this.textures = textures;
this.loader = new THREE.ObjectLoader(manager);
this.obj = null;
}
load() {
// load a resource
this.loader.load(Config.model.path, (obj) => {
obj.traverse((child) => {
if(child instanceof THREE.Mesh) {
let material = new Material().standard;
material.map = this.textures.UV;
child.material = material;
if(Config.shadow.enabled) {
child.receiveShadow = true;
child.castShadow = true;
}
}
});
if(Config.isDev && Config.mesh.enableHelper) {
new Helper(this.scene, obj);
}
// set prop to obj
this.obj = obj;
obj.scale.multiplyScalar(Config.model.scale);
// add object to scene
this.scene.add(obj);
}, Model.onProgress, Model.onError);
}
static onProgress(xhr) {
if(xhr.lengthComputable) {
let percentComplete = xhr.loaded / xhr.total * 100;
console.log(Math.round(percentComplete, 2) + '% downloaded');
}
};
static onError(xhr) {
console.error(xhr);
};
}

101
src/js/app/model/model.js Normal file
View File

@ -0,0 +1,101 @@
import * as THREE from 'three';
import Material from '../components/material';
import Helpers from '../../utils/helpers';
import { BufferGeometryUtils } from '../../utils/bufferGeometryUtils';
import { GLTFLoader } from '../loaders/GLTFLoader';
import Config from '../../data/config';
// Loads in a single object from the config file
export default class Model {
constructor(scene, manager, textures) {
this.scene = scene;
this.textures = textures;
this.manager = manager;
this.obj = null;
this.ref = null;
}
load(type) {
// Manager is passed in to loader to determine when loading done in main
switch (type) {
case 'gltf':
// Load model with selected loader
new GLTFLoader(this.manager).load(
Config.models[Config.model.selected].path,
(gltf) => {
const scene = gltf.scene;
let mesh;
if (Config.shadow.enabled) {
scene.traverse(function(node) {
if (node.isMesh || node.isLight) node.castShadow = true;
if (node.isMesh) {
node.material.wireframe = Config.mesh.wireframe;
mesh = node;
}
});
}
this.obj = mesh;
BufferGeometryUtils.computeTangents(mesh.geometry);
var group = new THREE.Group();
group.scale.multiplyScalar(0.25);
this.scene.add( group );
this.ref = group;
// To make sure that the matrixWorld is up to date for the boxhelpers
group.updateMatrixWorld(true);
group.add(mesh);
// Add to scene
this.scene.add(scene);
},
Helpers.logProgress(),
Helpers.logError()
);
break;
case 'object':
// Load model with ObjectLoader
new THREE.ObjectLoader(this.manager).load(
Config.models[Config.model.selected].path,
obj => {
obj.traverse(child => {
if(child instanceof THREE.Mesh) {
// Create material for mesh and set its map to texture by name from preloaded textures
const material = new Material(0xffffff).standard;
material.map = this.textures.UV;
child.material = material;
// Set to cast and receive shadow if enabled
if(Config.shadow.enabled) {
child.receiveShadow = true;
child.castShadow = true;
}
}
});
// Set prop to obj so it can be accessed from outside the class
this.obj = obj;
this.ref = obj;
obj.scale.multiplyScalar(Config.models[Config.model.selected].scale);
this.scene.add(obj);
},
Helpers.logProgress(),
Helpers.logError()
);
break;
}
}
unload() {
this.scene.remove(this.ref);
}
}

View File

@ -0,0 +1,55 @@
import * as THREE from 'three';
// Promise polyfill for IE
import { Promise } from 'es6-promise';
import Helpers from '../../utils/helpers';
import Config from '../../data/config';
// This class preloads all textures in the imageFiles array in the Config via ES6 Promises.
// Once all textures are done loading the model itself will be loaded after the Promise .then() callback.
// Using promises to preload textures prevents issues when applying textures to materials
// before the textures have loaded.
export default class Texture {
constructor() {
// Prop that will contain all loaded textures
this.textures = {};
}
load() {
const loader = new THREE.TextureLoader();
const maxAnisotropy = Config.maxAnisotropy;
const imageFiles = Config.texture.imageFiles;
const promiseArray = [];
loader.setPath(Config.texture.path);
imageFiles.forEach(imageFile => {
// Add an individual Promise for each image in array
promiseArray.push(new Promise((resolve, reject) => {
// Each Promise will attempt to load the image file
loader.load(imageFile.image,
// This gets called on load with the loaded texture
texture => {
texture.anisotropy = maxAnisotropy;
// Resolve Promise with object of texture if it is instance of THREE.Texture
const modelOBJ = {};
modelOBJ[imageFile.name] = texture;
if(modelOBJ[imageFile.name] instanceof THREE.Texture)
resolve(modelOBJ);
},
Helpers.logProgress(),
xhr => reject(new Error(xhr + 'An error occurred loading while loading ' + imageFile.image))
)
}));
});
// Iterate through all Promises in array and return another Promise when all have resolved or console log reason when any reject
return Promise.all(promiseArray).then(textures => {
// Set the textures prop object to have name be the resolved texture
for(let i = 0; i < textures.length; i++) {
this.textures[Object.keys(textures[i])[0]] = textures[i][Object.keys(textures[i])[0]];
}
}, reason => console.log(reason));
}
}

View File

@ -1,48 +0,0 @@
import THREE from 'three';
import { Promise } from 'es6-promise';
import Config from './../data/config';
export default class Texture {
constructor() {
this.textures = {};
}
load() {
const loader = new THREE.TextureLoader();
const maxAnisotropy = Config.maxAnisotropy;
const imageFiles = Config.texture.imageFiles;
let promiseArray = [];
loader.setPath(Config.texture.path);
imageFiles.forEach((imageFile) => {
promiseArray.push(new Promise((resolve, reject) => {
loader.load(imageFile.image,
function(texture) {
texture.anisotropy = maxAnisotropy;
var modelOBJ = {};
modelOBJ[imageFile.name] = texture;
if(modelOBJ[imageFile.name] instanceof THREE.Texture)
resolve(modelOBJ);
},
function(xhr) {
console.log(( xhr.loaded / xhr.total * 100 ) + '% loaded');
},
function(xhr) {
reject(new Error(xhr + 'An error occurred loading while loading ' + imageFile.image));
}
)
}));
});
return Promise.all(promiseArray).then((textures) => {
for(var i = 0; i < textures.length; i++) {
this.textures[Object.keys(textures[i])[0]] = textures[i][Object.keys(textures[i])[0]];
}
});
}
}

View File

@ -1,7 +1,9 @@
import TWEEN from 'tween.js';
import TWEEN from '@tweenjs/tween.js';
// This object contains the state of the app
export default {
isDev: false,
isShowingStats: true,
isLoaded: false,
isTweening: false,
isRotating: true,
@ -12,17 +14,30 @@ export default {
easing: TWEEN.Easing.Quadratic.InOut,
duration: 500,
model: {
path: '/assets/models/teapot-claraio.json',
scale: 20
selected: 0,
initialTypes: ['gltf', 'object'],
type: 'gltf'
},
models: [
{
path: './assets/models/duck.gltf',
scale: 20,
type: 'gltf'
},
{
path: './assets/models/Teapot.json',
scale: 20,
type: 'object'
}
],
texture: {
path: '/assets/textures/',
path: './assets/textures/',
imageFiles: [
{name: 'UV', image: 'UV_Grid_Sm.jpg'}
{ name: 'UV', image: 'UV_Grid_Sm.jpg' }
]
},
mesh: {
enableHelper: false,
enableHelper: true,
wireframe: false,
translucent: false,
material: {
@ -64,7 +79,7 @@ export default {
}
},
ambientLight: {
enabled: false,
enabled: true,
color: 0x141414
},
directionalLight: {
@ -78,15 +93,15 @@ export default {
shadow: {
enabled: true,
helperEnabled: true,
bias: -0.00025,
mapWidth: 1024,
mapHeight: 1024,
near: 200,
bias: 0,
mapWidth: 2048,
mapHeight: 2048,
near: 250,
far: 400,
top: 150,
right: 150,
bottom: -150,
left: -150
top: 100,
right: 100,
bottom: -100,
left: -100
},
pointLight: {
enabled: true,
@ -101,9 +116,9 @@ export default {
enabled: true,
color: 0xc8c8c8,
groundColor: 0xffffff,
intensity: 0.3,
x: -275,
y: 145,
intensity: 0.55,
x: 0,
y: 0,
z: 0
}
};

View File

@ -0,0 +1,702 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
import {
BufferAttribute,
BufferGeometry,
InterleavedBuffer,
InterleavedBufferAttribute,
TriangleFanDrawMode,
TriangleStripDrawMode,
TrianglesDrawMode,
Vector2,
Vector3,
} from 'three';
var BufferGeometryUtils = {
computeTangents: function (geometry) {
var index = geometry.index;
var attributes = geometry.attributes;
// based on http://www.terathon.com/code/tangent.html
// (per vertex tangents)
if (
index === null ||
attributes.position === undefined ||
attributes.normal === undefined ||
attributes.uv === undefined
) {
console.error(
'THREE.BufferGeometryUtils: .computeTangents() failed. Missing required attributes (index, position, normal or uv)'
);
return;
}
var indices = index.array;
var positions = attributes.position.array;
var normals = attributes.normal.array;
var uvs = attributes.uv.array;
var nVertices = positions.length / 3;
if (attributes.tangent === undefined) {
geometry.setAttribute('tangent', new BufferAttribute(new Float32Array(4 * nVertices), 4));
}
var tangents = attributes.tangent.array;
var tan1 = [],
tan2 = [];
for (var i = 0; i < nVertices; i++) {
tan1[i] = new Vector3();
tan2[i] = new Vector3();
}
var vA = new Vector3(),
vB = new Vector3(),
vC = new Vector3(),
uvA = new Vector2(),
uvB = new Vector2(),
uvC = new Vector2(),
sdir = new Vector3(),
tdir = new Vector3();
function handleTriangle(a, b, c) {
vA.fromArray(positions, a * 3);
vB.fromArray(positions, b * 3);
vC.fromArray(positions, c * 3);
uvA.fromArray(uvs, a * 2);
uvB.fromArray(uvs, b * 2);
uvC.fromArray(uvs, c * 2);
vB.sub(vA);
vC.sub(vA);
uvB.sub(uvA);
uvC.sub(uvA);
var r = 1.0 / (uvB.x * uvC.y - uvC.x * uvB.y);
// silently ignore degenerate uv triangles having coincident or colinear vertices
if (!isFinite(r)) return;
sdir.copy(vB).multiplyScalar(uvC.y).addScaledVector(vC, -uvB.y).multiplyScalar(r);
tdir.copy(vC).multiplyScalar(uvB.x).addScaledVector(vB, -uvC.x).multiplyScalar(r);
tan1[a].add(sdir);
tan1[b].add(sdir);
tan1[c].add(sdir);
tan2[a].add(tdir);
tan2[b].add(tdir);
tan2[c].add(tdir);
}
var groups = geometry.groups;
if (groups.length === 0) {
groups = [
{
start: 0,
count: indices.length,
},
];
}
for (var i = 0, il = groups.length; i < il; ++i) {
var group = groups[i];
var start = group.start;
var count = group.count;
for (var j = start, jl = start + count; j < jl; j += 3) {
handleTriangle(indices[j + 0], indices[j + 1], indices[j + 2]);
}
}
var tmp = new Vector3(),
tmp2 = new Vector3();
var n = new Vector3(),
n2 = new Vector3();
var w, t, test;
function handleVertex(v) {
n.fromArray(normals, v * 3);
n2.copy(n);
t = tan1[v];
// Gram-Schmidt orthogonalize
tmp.copy(t);
tmp.sub(n.multiplyScalar(n.dot(t))).normalize();
// Calculate handedness
tmp2.crossVectors(n2, t);
test = tmp2.dot(tan2[v]);
w = test < 0.0 ? -1.0 : 1.0;
tangents[v * 4] = tmp.x;
tangents[v * 4 + 1] = tmp.y;
tangents[v * 4 + 2] = tmp.z;
tangents[v * 4 + 3] = w;
}
for (var i = 0, il = groups.length; i < il; ++i) {
var group = groups[i];
var start = group.start;
var count = group.count;
for (var j = start, jl = start + count; j < jl; j += 3) {
handleVertex(indices[j + 0]);
handleVertex(indices[j + 1]);
handleVertex(indices[j + 2]);
}
}
},
/**
* @param {Array<BufferGeometry>} geometries
* @param {Boolean} useGroups
* @return {BufferGeometry}
*/
mergeBufferGeometries: function (geometries, useGroups) {
var isIndexed = geometries[0].index !== null;
var attributesUsed = new Set(Object.keys(geometries[0].attributes));
var morphAttributesUsed = new Set(Object.keys(geometries[0].morphAttributes));
var attributes = {};
var morphAttributes = {};
var morphTargetsRelative = geometries[0].morphTargetsRelative;
var mergedGeometry = new BufferGeometry();
var offset = 0;
for (var i = 0; i < geometries.length; ++i) {
var geometry = geometries[i];
var attributesCount = 0;
// ensure that all geometries are indexed, or none
if (isIndexed !== (geometry.index !== null)) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.'
);
return null;
}
// gather attributes, exit early if they're different
for (var name in geometry.attributes) {
if (!attributesUsed.has(name)) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. All geometries must have compatible attributes; make sure "' +
name +
'" attribute exists among all geometries, or in none of them.'
);
return null;
}
if (attributes[name] === undefined) attributes[name] = [];
attributes[name].push(geometry.attributes[name]);
attributesCount++;
}
// ensure geometries have the same number of attributes
if (attributesCount !== attributesUsed.size) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. Make sure all geometries have the same number of attributes.'
);
return null;
}
// gather morph attributes, exit early if they're different
if (morphTargetsRelative !== geometry.morphTargetsRelative) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. .morphTargetsRelative must be consistent throughout all geometries.'
);
return null;
}
for (var name in geometry.morphAttributes) {
if (!morphAttributesUsed.has(name)) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. .morphAttributes must be consistent throughout all geometries.'
);
return null;
}
if (morphAttributes[name] === undefined) morphAttributes[name] = [];
morphAttributes[name].push(geometry.morphAttributes[name]);
}
// gather .userData
mergedGeometry.userData.mergedUserData = mergedGeometry.userData.mergedUserData || [];
mergedGeometry.userData.mergedUserData.push(geometry.userData);
if (useGroups) {
var count;
if (isIndexed) {
count = geometry.index.count;
} else if (geometry.attributes.position !== undefined) {
count = geometry.attributes.position.count;
} else {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed with geometry at index ' +
i +
'. The geometry must have either an index or a position attribute'
);
return null;
}
mergedGeometry.addGroup(offset, count, i);
offset += count;
}
}
// merge indices
if (isIndexed) {
var indexOffset = 0;
var mergedIndex = [];
for (var i = 0; i < geometries.length; ++i) {
var index = geometries[i].index;
for (var j = 0; j < index.count; ++j) {
mergedIndex.push(index.getX(j) + indexOffset);
}
indexOffset += geometries[i].attributes.position.count;
}
mergedGeometry.setIndex(mergedIndex);
}
// merge attributes
for (var name in attributes) {
var mergedAttribute = this.mergeBufferAttributes(attributes[name]);
if (!mergedAttribute) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the ' +
name +
' attribute.'
);
return null;
}
mergedGeometry.setAttribute(name, mergedAttribute);
}
// merge morph attributes
for (var name in morphAttributes) {
var numMorphTargets = morphAttributes[name][0].length;
if (numMorphTargets === 0) break;
mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
mergedGeometry.morphAttributes[name] = [];
for (var i = 0; i < numMorphTargets; ++i) {
var morphAttributesToMerge = [];
for (var j = 0; j < morphAttributes[name].length; ++j) {
morphAttributesToMerge.push(morphAttributes[name][j][i]);
}
var mergedMorphAttribute = this.mergeBufferAttributes(morphAttributesToMerge);
if (!mergedMorphAttribute) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferGeometries() failed while trying to merge the ' +
name +
' morphAttribute.'
);
return null;
}
mergedGeometry.morphAttributes[name].push(mergedMorphAttribute);
}
}
return mergedGeometry;
},
/**
* @param {Array<BufferAttribute>} attributes
* @return {BufferAttribute}
*/
mergeBufferAttributes: function (attributes) {
var TypedArray;
var itemSize;
var normalized;
var arrayLength = 0;
for (var i = 0; i < attributes.length; ++i) {
var attribute = attributes[i];
if (attribute.isInterleavedBufferAttribute) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. InterleavedBufferAttributes are not supported.'
);
return null;
}
if (TypedArray === undefined) TypedArray = attribute.array.constructor;
if (TypedArray !== attribute.array.constructor) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes.'
);
return null;
}
if (itemSize === undefined) itemSize = attribute.itemSize;
if (itemSize !== attribute.itemSize) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes.'
);
return null;
}
if (normalized === undefined) normalized = attribute.normalized;
if (normalized !== attribute.normalized) {
console.error(
'THREE.BufferGeometryUtils: .mergeBufferAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes.'
);
return null;
}
arrayLength += attribute.array.length;
}
var array = new TypedArray(arrayLength);
var offset = 0;
for (var i = 0; i < attributes.length; ++i) {
array.set(attributes[i].array, offset);
offset += attributes[i].array.length;
}
return new BufferAttribute(array, itemSize, normalized);
},
/**
* @param {Array<BufferAttribute>} attributes
* @return {Array<InterleavedBufferAttribute>}
*/
interleaveAttributes: function (attributes) {
// Interleaves the provided attributes into an InterleavedBuffer and returns
// a set of InterleavedBufferAttributes for each attribute
var TypedArray;
var arrayLength = 0;
var stride = 0;
// calculate the the length and type of the interleavedBuffer
for (var i = 0, l = attributes.length; i < l; ++i) {
var attribute = attributes[i];
if (TypedArray === undefined) TypedArray = attribute.array.constructor;
if (TypedArray !== attribute.array.constructor) {
console.error('AttributeBuffers of different types cannot be interleaved');
return null;
}
arrayLength += attribute.array.length;
stride += attribute.itemSize;
}
// Create the set of buffer attributes
var interleavedBuffer = new InterleavedBuffer(new TypedArray(arrayLength), stride);
var offset = 0;
var res = [];
var getters = ['getX', 'getY', 'getZ', 'getW'];
var setters = ['setX', 'setY', 'setZ', 'setW'];
for (var j = 0, l = attributes.length; j < l; j++) {
var attribute = attributes[j];
var itemSize = attribute.itemSize;
var count = attribute.count;
var iba = new InterleavedBufferAttribute(
interleavedBuffer,
itemSize,
offset,
attribute.normalized
);
res.push(iba);
offset += itemSize;
// Move the data for each attribute into the new interleavedBuffer
// at the appropriate offset
for (var c = 0; c < count; c++) {
for (var k = 0; k < itemSize; k++) {
iba[setters[k]](c, attribute[getters[k]](c));
}
}
}
return res;
},
/**
* @param {Array<BufferGeometry>} geometry
* @return {number}
*/
estimateBytesUsed: function (geometry) {
// Return the estimated memory used by this geometry in bytes
// Calculate using itemSize, count, and BYTES_PER_ELEMENT to account
// for InterleavedBufferAttributes.
var mem = 0;
for (var name in geometry.attributes) {
var attr = geometry.getAttribute(name);
mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
}
var indices = geometry.getIndex();
mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
return mem;
},
/**
* @param {BufferGeometry} geometry
* @param {number} tolerance
* @return {BufferGeometry>}
*/
mergeVertices: function (geometry, tolerance = 1e-4) {
tolerance = Math.max(tolerance, Number.EPSILON);
// Generate an index buffer if the geometry doesn't have one, or optimize it
// if it's already available.
var hashToIndex = {};
var indices = geometry.getIndex();
var positions = geometry.getAttribute('position');
var vertexCount = indices ? indices.count : positions.count;
// next value for triangle indices
var nextIndex = 0;
// attributes and new attribute arrays
var attributeNames = Object.keys(geometry.attributes);
var attrArrays = {};
var morphAttrsArrays = {};
var newIndices = [];
var getters = ['getX', 'getY', 'getZ', 'getW'];
// initialize the arrays
for (var i = 0, l = attributeNames.length; i < l; i++) {
var name = attributeNames[i];
attrArrays[name] = [];
var morphAttr = geometry.morphAttributes[name];
if (morphAttr) {
morphAttrsArrays[name] = new Array(morphAttr.length).fill().map(() => []);
}
}
// convert the error tolerance to an amount of decimal places to truncate to
var decimalShift = Math.log10(1 / tolerance);
var shiftMultiplier = Math.pow(10, decimalShift);
for (var i = 0; i < vertexCount; i++) {
var index = indices ? indices.getX(i) : i;
// Generate a hash for the vertex attributes at the current index 'i'
var hash = '';
for (var j = 0, l = attributeNames.length; j < l; j++) {
var name = attributeNames[j];
var attribute = geometry.getAttribute(name);
var itemSize = attribute.itemSize;
for (var k = 0; k < itemSize; k++) {
// double tilde truncates the decimal value
hash += `${~~(attribute[getters[k]](index) * shiftMultiplier)},`;
}
}
// Add another reference to the vertex if it's already
// used by another index
if (hash in hashToIndex) {
newIndices.push(hashToIndex[hash]);
} else {
// copy data to the new index in the attribute arrays
for (var j = 0, l = attributeNames.length; j < l; j++) {
var name = attributeNames[j];
var attribute = geometry.getAttribute(name);
var morphAttr = geometry.morphAttributes[name];
var itemSize = attribute.itemSize;
var newarray = attrArrays[name];
var newMorphArrays = morphAttrsArrays[name];
for (var k = 0; k < itemSize; k++) {
var getterFunc = getters[k];
newarray.push(attribute[getterFunc](index));
if (morphAttr) {
for (var m = 0, ml = morphAttr.length; m < ml; m++) {
newMorphArrays[m].push(morphAttr[m][getterFunc](index));
}
}
}
}
hashToIndex[hash] = nextIndex;
newIndices.push(nextIndex);
nextIndex++;
}
}
// Generate typed arrays from new attribute arrays and update
// the attributeBuffers
const result = geometry.clone();
for (var i = 0, l = attributeNames.length; i < l; i++) {
var name = attributeNames[i];
var oldAttribute = geometry.getAttribute(name);
var buffer = new oldAttribute.array.constructor(attrArrays[name]);
var attribute = new BufferAttribute(buffer, oldAttribute.itemSize, oldAttribute.normalized);
result.setAttribute(name, attribute);
// Update the attribute arrays
if (name in morphAttrsArrays) {
for (var j = 0; j < morphAttrsArrays[name].length; j++) {
var oldMorphAttribute = geometry.morphAttributes[name][j];
var buffer = new oldMorphAttribute.array.constructor(morphAttrsArrays[name][j]);
var morphAttribute = new BufferAttribute(
buffer,
oldMorphAttribute.itemSize,
oldMorphAttribute.normalized
);
result.morphAttributes[name][j] = morphAttribute;
}
}
}
// indices
result.setIndex(newIndices);
return result;
},
/**
* @param {BufferGeometry} geometry
* @param {number} drawMode
* @return {BufferGeometry>}
*/
toTrianglesDrawMode: function (geometry, drawMode) {
if (drawMode === TrianglesDrawMode) {
console.warn(
'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.'
);
return geometry;
}
if (drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode) {
var index = geometry.getIndex();
// generate index if not present
if (index === null) {
var indices = [];
var position = geometry.getAttribute('position');
if (position !== undefined) {
for (var i = 0; i < position.count; i++) {
indices.push(i);
}
geometry.setIndex(indices);
index = geometry.getIndex();
} else {
console.error(
'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.'
);
return geometry;
}
}
//
var numberOfTriangles = index.count - 2;
var newIndices = [];
if (drawMode === TriangleFanDrawMode) {
// gl.TRIANGLE_FAN
for (var i = 1; i <= numberOfTriangles; i++) {
newIndices.push(index.getX(0));
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
}
} else {
// gl.TRIANGLE_STRIP
for (var i = 0; i < numberOfTriangles; i++) {
if (i % 2 === 0) {
newIndices.push(index.getX(i));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i + 2));
} else {
newIndices.push(index.getX(i + 2));
newIndices.push(index.getX(i + 1));
newIndices.push(index.getX(i));
}
}
}
if (newIndices.length / 3 !== numberOfTriangles) {
console.error(
'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unable to generate correct amount of triangles.'
);
}
// build final geometry
var newGeometry = geometry.clone();
newGeometry.setIndex(newIndices);
newGeometry.clearGroups();
return newGeometry;
}
console.error('THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:', drawMode);
return geometry;
},
};
export { BufferGeometryUtils };

View File

@ -4,26 +4,21 @@
*/
export default {
canvas: !!window.CanvasRenderingContext2D,
webgl: (function() {
try {
var canvas = document.createElement('canvas');
return !!( window.WebGLRenderingContext && ( canvas.getContext('webgl') || canvas.getContext('experimental-webgl') ) );
return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
} catch(e) {
return false;
}
})(),
workers: !!window.Worker,
fileapi: window.File && window.FileReader && window.FileList && window.Blob,
getWebGLErrorMessage: function() {
var element = document.createElement('div');
element.id = 'webgl-error-message';
element.style.fontFamily = 'monospace';
@ -37,7 +32,6 @@ export default {
element.style.margin = '5em auto 0';
if(!this.webgl) {
element.innerHTML = window.WebGLRenderingContext ? [
'Your graphics card does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000000">WebGL</a>.<br />',
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000000">here</a>.'
@ -45,15 +39,12 @@ export default {
'Your browser does not seem to support <a href="http://khronos.org/webgl/wiki/Getting_a_WebGL_Implementation" style="color:#000000">WebGL</a>.<br/>',
'Find out how to get it <a href="http://get.webgl.org/" style="color:#000000">here</a>.'
].join('\n');
}
return element;
},
addGetWebGLMessage: function(parameters) {
var parent, id, element;
parameters = parameters || {};
@ -65,7 +56,5 @@ export default {
element.id = id;
parent.appendChild(element);
}
};

View File

@ -1,16 +1,16 @@
// Provides simple static functions that are used multiple times in the app
export default class Helpers {
static throttle(fn, threshhold, scope) {
threshhold || (threshhold = 250);
var last, deferTimer;
let last, deferTimer;
return function() {
var context = scope || this;
const context = scope || this;
var now = +new Date,
args = arguments;
const now = +new Date,
args = arguments;
if(last && now < last + threshhold) {
// hold on to it
clearTimeout(deferTimer);
deferTimer = setTimeout(function() {
last = now;
@ -23,4 +23,53 @@ export default class Helpers {
}
};
}
static logProgress() {
return function(xhr) {
if(xhr.lengthComputable) {
const percentComplete = xhr.loaded / xhr.total * 100;
console.log(Math.round(percentComplete, 2) + '% downloaded');
}
}
}
static logError() {
return function(xhr) {
console.error(xhr);
}
}
static handleColorChange(color) {
return (value) => {
if(typeof value === 'string') {
value = value.replace('#', '0x');
}
color.setHex(value);
};
}
static update(mesh) {
this.needsUpdate(mesh.material, mesh.geometry);
}
static needsUpdate(material, geometry) {
return function() {
material.shading = +material.shading; //Ensure number
material.vertexColors = +material.vertexColors; //Ensure number
material.side = +material.side; //Ensure number
material.needsUpdate = true;
geometry.verticesNeedUpdate = true;
geometry.normalsNeedUpdate = true;
geometry.colorsNeedUpdate = true;
};
}
static updateTexture(material, materialKey, textures) {
return function(key) {
material[materialKey] = textures[key];
material.needsUpdate = true;
};
}
}

View File

@ -4,8 +4,6 @@ const ALIAS = {
'right' : 39,
'down' : 40,
'space' : 32,
'pageup' : 33,
'pagedown': 34,
'tab' : 9,
'escape' : 27
};
@ -16,23 +14,23 @@ export default class Keyboard {
this.keyCodes = {};
// bind keyEvents
this.domElement.addEventListener('keydown', () => this.onKeyChange(event), false);
this.domElement.addEventListener('keyup', () => this.onKeyChange(event), false);
this.domElement.addEventListener('keydown', (event) => this.onKeyChange(event), false);
this.domElement.addEventListener('keyup', (event) => this.onKeyChange(event), false);
// bind window blur
window.addEventListener('blur', () => this.onBlur, false);
}
destroy() {
this.domElement.removeEventListener('keydown', () => this.onKeyChange(event), false);
this.domElement.removeEventListener('keyup', () => this.onKeyChange(event), false);
this.domElement.removeEventListener('keydown', (event) => this.onKeyChange(event), false);
this.domElement.removeEventListener('keyup', (event) => this.onKeyChange(event), false);
// unbind window blur event
window.removeEventListener('blur', () => this.onBlur, false);
}
onBlur() {
for(let prop in this.keyCodes)
for(const prop in this.keyCodes)
this.keyCodes[prop] = false;
}
@ -41,14 +39,14 @@ export default class Keyboard {
//console.log('onKeyChange', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)
// update this.keyCodes
let keyCode = event.keyCode;
const keyCode = event.keyCode;
this.keyCodes[keyCode] = event.type === 'keydown';
}
pressed(keyDesc) {
let keys = keyDesc.split('+');
const keys = keyDesc.split('+');
for(let i = 0; i < keys.length; i++) {
let key = keys[i];
const key = keys[i];
let pressed = false;
if(Object.keys(ALIAS).indexOf(key) != -1) {
pressed = this.keyCodes[ALIAS[key]];
@ -63,24 +61,24 @@ export default class Keyboard {
}
eventMatches(event, keyDesc) {
let aliases = ALIAS;
let aliasKeys = Object.keys(aliases);
let keys = keyDesc.split('+');
const aliases = ALIAS;
const aliasKeys = Object.keys(aliases);
const keys = keyDesc.split('+');
// log to debug
// console.log('eventMatches', event, event.keyCode, event.shiftKey, event.ctrlKey, event.altKey, event.metaKey)
for(let i = 0; i < keys.length; i++) {
let key = keys[i];
const key = keys[i];
let pressed = false;
if(key === 'shift') {
pressed = (event.shiftKey ? true : false);
pressed = event.shiftKey ? true : false;
} else if(key === 'ctrl') {
pressed = (event.ctrlKey ? true : false);
pressed = event.ctrlKey ? true : false;
} else if(key === 'alt') {
pressed = (event.altKey ? true : false);
pressed = event.altKey ? true : false;
} else if(key === 'meta') {
pressed = (event.metaKey ? true : false);
pressed = event.metaKey ? true : false;
} else if(aliasKeys.indexOf(key) !== -1) {
pressed = (event.keyCode === aliases[key]);
pressed = event.keyCode === aliases[key];
} else if(event.keyCode === key.toUpperCase().charCodeAt(0)) {
pressed = true;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,73 +0,0 @@
.rs-base{
position: absolute;
z-index: 10000;
padding: 10px;
background-color: #222;
font-size: 10px;
line-height: 1.2em;
width: 350px;
font-family: 'Roboto Condensed', tahoma, sans-serif;
left: 0;
top: 0;
overflow: hidden;
}
.rs-base h1{
margin: 0;
padding: 0;
font-size: 1.4em;
color: #fff;
margin-bottom: 5px;
cursor: pointer;
}
.rs-base div.rs-group{
margin-bottom: 10px;
}
.rs-base div.rs-group.hidden{
display: none;
}
.rs-base div.rs-fraction{
position: relative;
margin-bottom: 5px;
}
.rs-base div.rs-fraction p{
width: 120px;
text-align: right;
margin: 0;
padding: 0;
}
.rs-base div.rs-legend{
position: absolute;
line-height: 1em;
}
.rs-base div.rs-counter-base{
position: relative;
margin: 2px 0;
height: 1em;
}
.rs-base span.rs-counter-id{
position: absolute;
left: 0;
top: 0;
}
.rs-base div.rs-counter-value{
position: absolute;
left: 90px;
width: 30px;
height: 1em;
top: 0;
text-align: right;
}
.rs-base canvas.rs-canvas{
position: absolute;
right: 0;
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,719 +0,0 @@
// performance.now() polyfill from https://gist.github.com/paulirish/5438650
'use strict';
( function () {
// prepare base perf object
if ( typeof window.performance === 'undefined' ) {
window.performance = {};
}
if ( !window.performance.now ) {
var nowOffset = Date.now();
if ( performance.timing && performance.timing.navigationStart ) {
nowOffset = performance.timing.navigationStart;
}
window.performance.now = function now () {
return Date.now() - nowOffset;
};
}
if( !window.performance.mark ) {
window.performance.mark = function(){}
}
if( !window.performance.measure ) {
window.performance.measure = function(){}
}
} )();
window.rStats = function rStats ( settings ) {
function iterateKeys ( array, callback ) {
var keys = Object.keys( array );
for ( var j = 0, l = keys.length; j < l; j++ ) {
callback( keys[ j ] );
}
}
function importCSS ( url ) {
var element = document.createElement( 'link' );
element.href = url;
element.rel = 'stylesheet';
element.type = 'text/css';
document.getElementsByTagName( 'head' )[ 0 ].appendChild( element );
}
var _settings = settings || {};
var _colours = _settings.colours || [ '#850700', '#c74900', '#fcb300', '#284280', '#4c7c0c' ];
var _cssFont = 'https://fonts.googleapis.com/css?family=Roboto+Condensed:400,700,300';
var _cssRStats = ( _settings.CSSPath ? _settings.CSSPath : '' ) + 'rStats.css';
var _css = _settings.css || [ _cssFont, _cssRStats ];
_css.forEach(function (uri) {
importCSS( uri );
});
if ( !_settings.values ) _settings.values = {};
var _base, _div, _elHeight = 10, _elWidth = 200;
var _perfCounters = {};
function Graph ( _dom, _id, _defArg ) {
var _def = _defArg || {};
var _canvas = document.createElement( 'canvas' ),
_ctx = _canvas.getContext( '2d' ),
_max = 0,
_current = 0;
var c = _def.color ? _def.color : '#666666';
var _dotCanvas = document.createElement( 'canvas' ),
_dotCtx = _dotCanvas.getContext( '2d' );
_dotCanvas.width = 1;
_dotCanvas.height = 2 * _elHeight;
_dotCtx.fillStyle = '#444444';
_dotCtx.fillRect( 0, 0, 1, 2 * _elHeight );
_dotCtx.fillStyle = c;
_dotCtx.fillRect( 0, _elHeight, 1, _elHeight );
_dotCtx.fillStyle = '#ffffff';
_dotCtx.globalAlpha = 0.5;
_dotCtx.fillRect( 0, _elHeight, 1, 1 );
_dotCtx.globalAlpha = 1;
var _alarmCanvas = document.createElement( 'canvas' ),
_alarmCtx = _alarmCanvas.getContext( '2d' );
_alarmCanvas.width = 1;
_alarmCanvas.height = 2 * _elHeight;
_alarmCtx.fillStyle = '#444444';
_alarmCtx.fillRect( 0, 0, 1, 2 * _elHeight );
_alarmCtx.fillStyle = '#b70000';
_alarmCtx.fillRect( 0, _elHeight, 1, _elHeight );
_alarmCtx.globalAlpha = 0.5;
_alarmCtx.fillStyle = '#ffffff';
_alarmCtx.fillRect( 0, _elHeight, 1, 1 );
_alarmCtx.globalAlpha = 1;
function _init () {
_canvas.width = _elWidth;
_canvas.height = _elHeight;
_canvas.style.width = _canvas.width + 'px';
_canvas.style.height = _canvas.height + 'px';
_canvas.className = 'rs-canvas';
_dom.appendChild( _canvas );
_ctx.fillStyle = '#444444';
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
}
function _draw ( v, alarm ) {
_current += ( v - _current ) * 0.1;
_max *= 0.99;
if ( _current > _max ) _max = _current;
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
if ( alarm ) {
_ctx.drawImage( _alarmCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
} else {
_ctx.drawImage( _dotCanvas, _canvas.width - 1, _canvas.height - _current * _canvas.height / _max - _elHeight );
}
}
_init();
return {
draw: _draw
};
}
function StackGraph ( _dom, _num ) {
var _canvas = document.createElement( 'canvas' ),
_ctx = _canvas.getContext( '2d' );
function _init () {
_canvas.width = _elWidth;
_canvas.height = _elHeight * _num;
_canvas.style.width = _canvas.width + 'px';
_canvas.style.height = _canvas.height + 'px';
_canvas.className = 'rs-canvas';
_dom.appendChild( _canvas );
_ctx.fillStyle = '#444444';
_ctx.fillRect( 0, 0, _canvas.width, _canvas.height );
}
function _draw ( v ) {
_ctx.drawImage( _canvas, 1, 0, _canvas.width - 1, _canvas.height, 0, 0, _canvas.width - 1, _canvas.height );
var th = 0;
iterateKeys( v, function ( j ) {
var h = v[ j ] * _canvas.height;
_ctx.fillStyle = _colours[ j ];
_ctx.fillRect( _canvas.width - 1, th, 1, h );
th += h;
} );
}
_init();
return {
draw: _draw
};
}
function PerfCounter ( id, group ) {
var _id = id,
_time,
_value = 0,
_total = 0,
_averageValue = 0,
_accumValue = 0,
_accumStart = performance.now(),
_accumSamples = 0,
_dom = document.createElement( 'div' ),
_spanId = document.createElement( 'span' ),
_spanValue = document.createElement( 'div' ),
_spanValueText = document.createTextNode( '' ),
_def = _settings ? _settings.values[ _id.toLowerCase() ] : null,
_graph = new Graph( _dom, _id, _def ),
_started = false;
_dom.className = 'rs-counter-base';
_spanId.className = 'rs-counter-id';
_spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;
_spanValue.className = 'rs-counter-value';
_spanValue.appendChild( _spanValueText );
_dom.appendChild( _spanId );
_dom.appendChild( _spanValue );
if ( group ) group.div.appendChild( _dom );
else _div.appendChild( _dom );
_time = performance.now();
function _average ( v ) {
if ( _def && _def.average ) {
_accumValue += v;
_accumSamples++;
var t = performance.now();
if ( t - _accumStart >= ( _def.avgMs || 1000 ) ) {
_averageValue = _accumValue / _accumSamples;
_accumValue = 0;
_accumStart = t;
_accumSamples = 0;
}
}
}
function _start () {
_time = performance.now();
if( _settings.userTimingAPI ) performance.mark( _id + '-start' );
_started = true;
}
function _end () {
_value = performance.now() - _time;
if( _settings.userTimingAPI ) {
performance.mark( _id + '-end' );
if( _started ) {
performance.measure( _id, _id + '-start', _id + '-end' );
}
}
_average( _value );
}
function _tick () {
_end();
_start();
}
function _draw () {
var v = ( _def && _def.average ) ? _averageValue : _value;
_spanValueText.nodeValue = Math.round( v * 100 ) / 100;
var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );
_graph.draw( _value, a );
_dom.style.color = a ? '#b70000' : '#ffffff';
}
function _frame () {
var t = performance.now();
var e = t - _time;
_total++;
if ( e > 1000 ) {
if ( _def && _def.interpolate === false ) {
_value = _total;
} else {
_value = _total * 1000 / e;
}
_total = 0;
_time = t;
_average( _value );
}
}
function _set ( v ) {
_value = v;
_average( _value );
}
return {
set: _set,
start: _start,
tick: _tick,
end: _end,
frame: _frame,
value: function () {
return _value;
},
draw: _draw
};
}
function sample () {
var _value = 0;
function _set ( v ) {
_value = v;
}
return {
set: _set,
value: function () {
return _value;
}
};
}
function _perf ( idArg ) {
var id = idArg.toLowerCase();
if ( id === undefined ) id = 'default';
if ( _perfCounters[ id ] ) return _perfCounters[ id ];
var group = null;
if ( _settings && _settings.groups ) {
iterateKeys( _settings.groups, function ( j ) {
var g = _settings.groups[ parseInt( j, 10 ) ];
if ( !group && g.values.indexOf( id.toLowerCase() ) !== -1 ) {
group = g;
}
} );
}
var p = new PerfCounter( id, group );
_perfCounters[ id ] = p;
return p;
}
function _init () {
if ( _settings.plugins ) {
if ( !_settings.values ) _settings.values = {};
if ( !_settings.groups ) _settings.groups = [];
if ( !_settings.fractions ) _settings.fractions = [];
for ( var j = 0; j < _settings.plugins.length; j++ ) {
_settings.plugins[ j ].attach( _perf );
iterateKeys( _settings.plugins[ j ].values, function ( k ) {
_settings.values[ k ] = _settings.plugins[ j ].values[ k ];
} );
_settings.groups = _settings.groups.concat( _settings.plugins[ j ].groups );
_settings.fractions = _settings.fractions.concat( _settings.plugins[ j ].fractions );
}
} else {
_settings.plugins = {};
}
_base = document.createElement( 'div' );
_base.className = 'rs-base';
_div = document.createElement( 'div' );
_div.className = 'rs-container';
_div.style.height = 'auto';
_base.appendChild( _div );
document.body.appendChild( _base );
if ( !_settings ) return;
if ( _settings.groups ) {
iterateKeys( _settings.groups, function ( j ) {
var g = _settings.groups[ parseInt( j, 10 ) ];
var div = document.createElement( 'div' );
div.className = 'rs-group';
g.div = div;
var h1 = document.createElement( 'h1' );
h1.textContent = g.caption;
h1.addEventListener( 'click', function ( e ) {
this.classList.toggle( 'hidden' );
e.preventDefault();
}.bind( div ) );
_div.appendChild( h1 );
_div.appendChild( div );
} );
}
if ( _settings.fractions ) {
iterateKeys( _settings.fractions, function ( j ) {
var f = _settings.fractions[ parseInt( j, 10 ) ];
var div = document.createElement( 'div' );
div.className = 'rs-fraction';
var legend = document.createElement( 'div' );
legend.className = 'rs-legend';
var h = 0;
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
var p = document.createElement( 'p' );
p.textContent = _settings.fractions[ j ].steps[ k ];
p.style.color = _colours[ h ];
legend.appendChild( p );
h++;
} );
div.appendChild( legend );
div.style.height = h * _elHeight + 'px';
f.div = div;
var graph = new StackGraph( div, h );
f.graph = graph;
_div.appendChild( div );
} );
}
}
function _update () {
iterateKeys( _settings.plugins, function ( j ) {
_settings.plugins[ j ].update();
} );
iterateKeys( _perfCounters, function ( j ) {
_perfCounters[ j ].draw();
} );
if ( _settings && _settings.fractions ) {
iterateKeys( _settings.fractions, function ( j ) {
var f = _settings.fractions[ parseInt( j, 10 ) ];
var v = [];
var base = _perfCounters[ f.base.toLowerCase() ];
if ( base ) {
base = base.value();
iterateKeys( _settings.fractions[ j ].steps, function ( k ) {
var s = _settings.fractions[ j ].steps[ parseInt( k, 10 ) ].toLowerCase();
var val = _perfCounters[ s ];
if ( val ) {
v.push( val.value() / base );
}
} );
}
f.graph.draw( v );
} );
}
/*if( _height != _div.clientHeight ) {
_height = _div.clientHeight;
_base.style.height = _height + 2 * _elHeight + 'px';
console.log( _base.clientHeight );
}*/
}
_init();
return function ( id ) {
if ( id ) return _perf( id );
return {
element: _base,
update: _update
};
};
}
if (typeof module === 'object') {
module.exports = window.rStats;
}
window.glStats = function () {
var _rS = null;
var _totalDrawArraysCalls = 0,
_totalDrawElementsCalls = 0,
_totalUseProgramCalls = 0,
_totalFaces = 0,
_totalVertices = 0,
_totalPoints = 0,
_totalBindTexures = 0;
function _h ( f, c ) {
return function () {
c.apply( this, arguments );
f.apply( this, arguments );
};
}
WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
_totalDrawArraysCalls++;
if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
else _totalVertices += arguments[ 2 ];
} );
WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
_totalDrawElementsCalls++;
_totalFaces += arguments[ 1 ] / 3;
_totalVertices += arguments[ 1 ];
} );
WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
_totalUseProgramCalls++;
} );
WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
_totalBindTexures++;
} );
var _values = {
allcalls: {
over: 3000,
caption: 'Calls (hook)'
},
drawelements: {
caption: 'drawElements (hook)'
},
drawarrays: {
caption: 'drawArrays (hook)'
}
};
var _groups = [ {
caption: 'WebGL',
values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
} ];
var _fractions = [ {
base: 'allcalls',
steps: [ 'drawelements', 'drawarrays' ]
} ];
function _update () {
_rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
_rS( 'drawElements' ).set( _totalDrawElementsCalls );
_rS( 'drawArrays' ).set( _totalDrawArraysCalls );
_rS( 'bindTexture' ).set( _totalBindTexures );
_rS( 'useProgram' ).set( _totalUseProgramCalls );
_rS( 'glfaces' ).set( _totalFaces );
_rS( 'glvertices' ).set( _totalVertices );
_rS( 'glpoints' ).set( _totalPoints );
}
function _start () {
_totalDrawArraysCalls = 0;
_totalDrawElementsCalls = 0;
_totalUseProgramCalls = 0;
_totalFaces = 0;
_totalVertices = 0;
_totalPoints = 0;
_totalBindTexures = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
window.threeStats = function ( renderer ) {
var _rS = null;
var _values = {
'renderer.info.memory.geometries': {
caption: 'Geometries'
},
'renderer.info.memory.textures': {
caption: 'Textures'
},
'renderer.info.programs': {
caption: 'Programs'
},
'renderer.info.render.calls': {
caption: 'Calls'
},
'renderer.info.render.faces': {
caption: 'Faces',
over: 1000
},
'renderer.info.render.points': {
caption: 'Points'
},
'renderer.info.render.vertices': {
caption: 'Vertices'
}
};
var _groups = [ {
caption: 'Three.js - Memory',
values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
}, {
caption: 'Three.js - Render',
values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]
} ];
var _fractions = [];
function _update () {
_rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
//_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
_rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
_rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
_rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );
_rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
_rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );
}
function _start () {}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
/*
* From https://github.com/paulirish/memory-stats.js
*/
window.BrowserStats = function () {
var _rS = null;
var _usedJSHeapSize = 0,
_totalJSHeapSize = 0;
var memory = {
usedJSHeapSize: 0,
totalJSHeapSize: 0
};
if ( window.performance && performance.memory )
memory = performance.memory;
if ( memory.totalJSHeapSize === 0 ) {
console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
}
var _values = {
memory: {
caption: 'Used Memory',
average: true,
avgMs: 1000,
over: 22
},
total: {
caption: 'Total Memory'
}
};
var _groups = [ {
caption: 'Browser',
values: [ 'memory', 'total' ]
} ];
var _fractions = [ {
base: 'total',
steps: [ 'memory' ]
} ];
var log1024 = Math.log( 1024 );
function _size ( v ) {
var precision = 100; //Math.pow(10, 2);
var i = Math.floor( Math.log( v ) / log1024 );
if( v === 0 ) i = 1;
return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
}
function _update () {
_usedJSHeapSize = _size( memory.usedJSHeapSize );
_totalJSHeapSize = _size( memory.totalJSHeapSize );
_rS( 'memory' ).set( _usedJSHeapSize );
_rS( 'total' ).set( _totalJSHeapSize );
}
function _start () {
_usedJSHeapSize = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
if (typeof module === 'object') {
module.exports = {
glStats: window.glStats,
threeStats: window.threeStats,
BrowserStats: window.BrowserStats
};
}

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,219 @@
{
"asset": {
"generator": "COLLADA2GLTF",
"version": "2.0"
},
"scene": 0,
"scenes": [
{
"nodes": [
0
]
}
],
"nodes": [
{
"children": [
2,
1
],
"matrix": [
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
0.009999999776482582,
0.0,
0.0,
0.0,
0.0,
1.0
]
},
{
"matrix": [
-0.7289686799049377,
0.0,
-0.6845470666885376,
0.0,
-0.4252049028873444,
0.7836934328079224,
0.4527972936630249,
0.0,
0.5364750623703003,
0.6211478114128113,
-0.571287989616394,
0.0,
400.1130065917969,
463.2640075683594,
-431.0780334472656,
1.0
],
"camera": 0
},
{
"mesh": 0
}
],
"cameras": [
{
"perspective": {
"aspectRatio": 1.5,
"yfov": 0.6605925559997559,
"zfar": 10000.0,
"znear": 1.0
},
"type": "perspective"
}
],
"meshes": [
{
"primitives": [
{
"attributes": {
"NORMAL": 1,
"POSITION": 2,
"TEXCOORD_0": 3
},
"indices": 0,
"mode": 4,
"material": 0
}
],
"name": "LOD3spShape"
}
],
"accessors": [
{
"bufferView": 0,
"byteOffset": 0,
"componentType": 5123,
"count": 12636,
"max": [
2398
],
"min": [
0
],
"type": "SCALAR"
},
{
"bufferView": 1,
"byteOffset": 0,
"componentType": 5126,
"count": 2399,
"max": [
0.9995989799499512,
0.999580979347229,
0.9984359741210938
],
"min": [
-0.9990839958190918,
-1.0,
-0.9998319745063782
],
"type": "VEC3"
},
{
"bufferView": 1,
"byteOffset": 28788,
"componentType": 5126,
"count": 2399,
"max": [
96.17990112304688,
163.97000122070313,
53.92519760131836
],
"min": [
-69.29850006103516,
9.929369926452637,
-61.32819747924805
],
"type": "VEC3"
},
{
"bufferView": 2,
"byteOffset": 0,
"componentType": 5126,
"count": 2399,
"max": [
0.9833459854125976,
0.9800369739532472
],
"min": [
0.026409000158309938,
0.01996302604675293
],
"type": "VEC2"
}
],
"materials": [
{
"pbrMetallicRoughness": {
"baseColorTexture": {
"index": 0
},
"metallicFactor": 0.0
},
"emissiveFactor": [
0.0,
0.0,
0.0
],
"name": "blinn3-fx"
}
],
"textures": [
{
"sampler": 0,
"source": 0
}
],
"images": [
{
"uri": "DuckCM.png"
}
],
"samplers": [
{
"magFilter": 9729,
"minFilter": 9986,
"wrapS": 10497,
"wrapT": 10497
}
],
"bufferViews": [
{
"buffer": 0,
"byteOffset": 76768,
"byteLength": 25272,
"target": 34963
},
{
"buffer": 0,
"byteOffset": 0,
"byteLength": 57576,
"byteStride": 12,
"target": 34962
},
{
"buffer": 0,
"byteOffset": 57576,
"byteLength": 19192,
"byteStride": 8,
"target": 34962
}
],
"buffers": [
{
"byteLength": 102040,
"uri": "Duck0.bin"
}
]
}

File diff suppressed because one or more lines are too long

1
src/public/css/main.css Normal file
View File

@ -0,0 +1 @@
html{-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0;font:16px/1 sans-serif;-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased}blockquote,figure,h1,h2,h3,h4,ol,p,ul{margin:0;padding:0}li,main{display:block}h1,h2,h3,h4{font-size:inherit}strong{font-weight:700}a,button{color:inherit;transition:.3s}a{text-decoration:none}button{overflow:visible;border:0;font:inherit;-webkit-font-smoothing:inherit;letter-spacing:inherit;background:none;cursor:pointer}::-moz-focus-inner{padding:0;border:0}:focus{outline:0}img{max-width:100%;height:auto;border:0}body{overflow:hidden}.main{position:relative;width:100%;height:100vh}#loading{position:absolute;top:calc(50% - 8px);left:calc(50% - 35px)}

View File

@ -0,0 +1 @@
{"version":3,"sources":["webpack://threejs-es6-webpack-boilerplate/./src/css/utils/_normalize.scss","webpack://threejs-es6-webpack-boilerplate/./src/css/app/_base.scss","webpack://threejs-es6-webpack-boilerplate/./src/css/app/_main.scss","webpack://threejs-es6-webpack-boilerplate/./src/css/components/_loading.scss"],"names":[],"mappings":"AAAA;EACE,0BAA0B;EAC1B,8BAA8B;;AAEhC;EACE,SAAS;EACT,uBAAuB;EACvB,kCAAkC;EAClC,mCAAmC;;AAErC;;;;;;;;;EASE,SAAS;EACT,UAAU;;AAEZ;;EAEE,cAAc;;AAEhB;;;;EAIE,kBAAkB;;AAEpB;EACE,iBAAiB;;AAEnB;;EAEE,cAAc;EACd,eAAe;;AAEjB;EACE,qBAAqB;;AAEvB;EACE,iBAAiB;EACjB,SAAS;EACT,aAAa;EACb,+BAA+B;EAC/B,uBAAuB;EACvB,gBAAgB;EAChB,eAAe;;AAEjB;EACE,UAAU;EACV,SAAS;;AAEX;EACE,UAAU;;AAEZ;EACE,eAAe;EACf,YAAY;EACZ,SAAS;;AC9DX;EACE,gBAAgB;;ACDlB;EACE,kBAAkB;EAClB,WAAW;EACX,aAAa;;ACHf;EACE,kBAAkB;EAClB,oBAAoB;EACpB,sBAAsB","file":"../css/main.css","sourcesContent":["html {\r\n -ms-text-size-adjust: 100%;\r\n -webkit-text-size-adjust: 100%;\r\n}\r\nbody {\r\n margin: 0;\r\n font: 16px/1 sans-serif;\r\n -moz-osx-font-smoothing: grayscale;\r\n -webkit-font-smoothing: antialiased;\r\n}\r\nh1,\r\nh2,\r\nh3,\r\nh4,\r\np,\r\nblockquote,\r\nfigure,\r\nol,\r\nul {\r\n margin: 0;\r\n padding: 0;\r\n}\r\nmain,\r\nli {\r\n display: block;\r\n}\r\nh1,\r\nh2,\r\nh3,\r\nh4 {\r\n font-size: inherit;\r\n}\r\nstrong {\r\n font-weight: bold;\r\n}\r\na,\r\nbutton {\r\n color: inherit;\r\n transition: .3s;\r\n}\r\na {\r\n text-decoration: none;\r\n}\r\nbutton {\r\n overflow: visible;\r\n border: 0;\r\n font: inherit;\r\n -webkit-font-smoothing: inherit;\r\n letter-spacing: inherit;\r\n background: none;\r\n cursor: pointer;\r\n}\r\n::-moz-focus-inner {\r\n padding: 0;\r\n border: 0;\r\n}\r\n:focus {\r\n outline: 0;\r\n}\r\nimg {\r\n max-width: 100%;\r\n height: auto;\r\n border: 0;\r\n}\r\n","body {\r\n overflow: hidden;\r\n}\r\n",".main {\r\n position: relative;\r\n width: 100%;\r\n height: 100vh;\r\n}\r\n","#loading {\r\n position: absolute;\r\n top: calc(50% - 8px);\r\n left: calc(50% - 35px);\r\n}\r\n"],"sourceRoot":""}

View File

@ -1,3 +1,16 @@
.alarm{
color: #b70000;
text-shadow: 0 0 0 #b70000,
0 0 1px #fff,
0 0 1px #fff,
0 0 2px #fff,
0 0 2px #fff,
0 0 3px #fff,
0 0 3px #fff,
0 0 4px #fff,
0 0 4px #fff;
}
.rs-base{
position: absolute;
z-index: 10000;
@ -50,6 +63,7 @@
position: relative;
margin: 2px 0;
height: 1em;
color: white;
}
.rs-base span.rs-counter-id{

View File

@ -1,19 +1,19 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Three.js Webpack ES6 Boilerplate</title>
<head>
<meta charset="UTF-8">
<title>Three.js Webpack ES6 Boilerplate</title>
<script defer src="/js/runtime.bundle.js"></script><script defer src="/js/vendors.bundle.js"></script><script defer src="/js/main.bundle.js"></script><link href="/js/../css/main.css" rel="stylesheet"></head>
<link rel="stylesheet" type="text/css" href="/assets/css/app.css">
</head>
<body>
<div class="content">
<div id="appContainer" class="main">
</div>
</div>
<body>
<section id="appContainer" class="main">
<div id="loading">Loading...</div>
</section>
<script src="/assets/js/rStats.js"></script>
<script src="/assets/js/dat.gui.min.js"></script>
<script src="/assets/js/app.js"></script>
</body>
<script src="js/rStats.js"></script>
<script src="js/rStats.extras.js"></script>
<script src="js/dat.gui.min.js"></script>
</body>
</html>

13
src/public/js/dat.gui.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,147 @@
/*! ../../data/config */
/*! ../../utils/bufferGeometryUtils */
/*! ../../utils/helpers */
/*! ../../utils/keyboard */
/*! ../../utils/orbitControls */
/*! ../components/material */
/*! ../loaders/GLTFLoader */
/*! ./../css/app.scss */
/*! ./../data/config */
/*! ./app/main */
/*! ./components/camera */
/*! ./components/controls */
/*! ./components/geometry */
/*! ./components/light */
/*! ./components/renderer */
/*! ./data/config */
/*! ./helpers/meshHelper */
/*! ./helpers/stats */
/*! ./managers/datGUI */
/*! ./managers/interaction */
/*! ./material */
/*! ./model/model */
/*! ./model/texture */
/*! ./utils/detector */
/*! ./vertexNormalsHelper */
/*! @tweenjs/tween.js */
/*! es6-promise */
/*! three */
/*!***********************!*\
!*** ./src/js/app.js ***!
\***********************/
/*!**************************!*\
!*** ./src/css/app.scss ***!
\**************************/
/*!****************************!*\
!*** ./src/js/app/main.js ***!
\****************************/
/*!*******************************!*\
!*** ./src/js/data/config.js ***!
\*******************************/
/*!*********************************!*\
!*** ./src/js/utils/helpers.js ***!
\*********************************/
/*!**********************************!*\
!*** ./src/js/utils/detector.js ***!
\**********************************/
/*!**********************************!*\
!*** ./src/js/utils/keyboard.js ***!
\**********************************/
/*!***********************************!*\
!*** ./src/js/app/model/model.js ***!
\***********************************/
/*!*************************************!*\
!*** ./src/js/app/helpers/stats.js ***!
\*************************************/
/*!*************************************!*\
!*** ./src/js/app/model/texture.js ***!
\*************************************/
/*!***************************************!*\
!*** ./src/js/app/managers/datGUI.js ***!
\***************************************/
/*!***************************************!*\
!*** ./src/js/utils/orbitControls.js ***!
\***************************************/
/*!****************************************!*\
!*** ./src/js/app/components/light.js ***!
\****************************************/
/*!*****************************************!*\
!*** ./src/js/app/components/camera.js ***!
\*****************************************/
/*!******************************************!*\
!*** ./src/js/app/helpers/meshHelper.js ***!
\******************************************/
/*!******************************************!*\
!*** ./src/js/app/loaders/GLTFLoader.js ***!
\******************************************/
/*!*******************************************!*\
!*** ./src/js/app/components/controls.js ***!
\*******************************************/
/*!*******************************************!*\
!*** ./src/js/app/components/geometry.js ***!
\*******************************************/
/*!*******************************************!*\
!*** ./src/js/app/components/material.js ***!
\*******************************************/
/*!*******************************************!*\
!*** ./src/js/app/components/renderer.js ***!
\*******************************************/
/*!********************************************!*\
!*** ./src/js/app/managers/interaction.js ***!
\********************************************/
/*!*********************************************!*\
!*** ./src/js/utils/bufferGeometryUtils.js ***!
\*********************************************/
/*!***************************************************!*\
!*** ./src/js/app/helpers/vertexNormalsHelper.js ***!
\***************************************************/

View File

@ -0,0 +1,262 @@
window.glStats = function () {
var _rS = null;
var _totalDrawArraysCalls = 0,
_totalDrawElementsCalls = 0,
_totalUseProgramCalls = 0,
_totalFaces = 0,
_totalVertices = 0,
_totalPoints = 0,
_totalBindTexures = 0;
function _h ( f, c ) {
return function () {
c.apply( this, arguments );
f.apply( this, arguments );
};
}
WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
_totalDrawArraysCalls++;
if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
else _totalVertices += arguments[ 2 ];
} );
WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
_totalDrawElementsCalls++;
_totalFaces += arguments[ 1 ] / 3;
_totalVertices += arguments[ 1 ];
} );
WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
_totalUseProgramCalls++;
} );
WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
_totalBindTexures++;
} );
var _values = {
allcalls: {
over: 3000,
caption: 'Calls (hook)'
},
drawelements: {
caption: 'drawElements (hook)'
},
drawarrays: {
caption: 'drawArrays (hook)'
}
};
var _groups = [ {
caption: 'WebGL',
values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
} ];
var _fractions = [ {
base: 'allcalls',
steps: [ 'drawelements', 'drawarrays' ]
} ];
function _update () {
_rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
_rS( 'drawElements' ).set( _totalDrawElementsCalls );
_rS( 'drawArrays' ).set( _totalDrawArraysCalls );
_rS( 'bindTexture' ).set( _totalBindTexures );
_rS( 'useProgram' ).set( _totalUseProgramCalls );
_rS( 'glfaces' ).set( _totalFaces );
_rS( 'glvertices' ).set( _totalVertices );
_rS( 'glpoints' ).set( _totalPoints );
}
function _start () {
_totalDrawArraysCalls = 0;
_totalDrawElementsCalls = 0;
_totalUseProgramCalls = 0;
_totalFaces = 0;
_totalVertices = 0;
_totalPoints = 0;
_totalBindTexures = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
window.threeStats = function ( renderer ) {
var _rS = null;
var _values = {
'renderer.info.memory.geometries': {
caption: 'Geometries'
},
'renderer.info.memory.textures': {
caption: 'Textures'
},
'renderer.info.programs': {
caption: 'Programs'
},
'renderer.info.render.calls': {
caption: 'Calls'
},
'renderer.info.render.triangles': {
caption: 'Triangles',
over: 5000
},
'renderer.info.render.points': {
caption: 'Points'
},
'renderer.info.render.vertices': {
caption: 'Vertices'
}
};
var _groups = [ {
caption: 'Three.js - Memory',
values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
}, {
caption: 'Three.js - Render',
values: [ 'renderer.info.render.calls', 'renderer.info.render.triangles', 'renderer.info.render.points' ]
} ];
var _fractions = [];
function _update () {
_rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
//_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
_rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
_rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
_rS( 'renderer.info.render.triangles' ).set( renderer.info.render.triangles );
// _rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
}
function _start () {}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
/*
* From https://github.com/paulirish/memory-stats.js
*/
window.BrowserStats = function () {
var _rS = null;
var _usedJSHeapSize = 0,
_totalJSHeapSize = 0;
var memory = {
usedJSHeapSize: 0,
totalJSHeapSize: 0
};
if ( window.performance && performance.memory )
memory = performance.memory;
if ( memory.totalJSHeapSize === 0 ) {
console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
}
var _values = {
memory: {
caption: 'Used Memory',
average: true,
avgMs: 1000,
over: 22
},
total: {
caption: 'Total Memory'
}
};
var _groups = [ {
caption: 'Browser',
values: [ 'memory', 'total' ]
} ];
var _fractions = [ {
base: 'total',
steps: [ 'memory' ]
} ];
var log1024 = Math.log( 1024 );
function _size ( v ) {
var precision = 100; //Math.pow(10, 2);
var i = Math.floor( Math.log( v ) / log1024 );
if( v === 0 ) i = 1;
return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
}
function _update () {
_usedJSHeapSize = _size( memory.usedJSHeapSize );
_totalJSHeapSize = _size( memory.totalJSHeapSize );
_rS( 'memory' ).set( _usedJSHeapSize );
_rS( 'total' ).set( _totalJSHeapSize );
}
function _start () {
_usedJSHeapSize = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
if (typeof module === 'object') {
module.exports = {
glStats: window.glStats,
threeStats: window.threeStats,
BrowserStats: window.BrowserStats
};
}

View File

@ -32,6 +32,32 @@
} )();
/**
* @class rStats
* @param {rStats~Settings} [settings] Settings for the rStats instance.
*/
/**
* @typedef {Object} rStats~Settings
* @property {Array.<String>} [colours] An array of CSS colour values.
* @property {String} [CSSPath=''] Base URL where rStats.css is located.
* @property {Array.<String>} [css] URLs of CSS or font files to import.
* @property {Object.<String, rStats~CounterProperties>} [values] Properties to use for each counter.
* @property {Array.<Object>} [groups] Define groups of counters.
* @property {Array.<Object>} [fractions] Define stacked counters.
* @property {Array.<Object>} [plugins] Additional plugins.
*/
/**
* @typedef {Object} rStats~CounterProperties
* @property {String} [caption] Caption for this counter.
* @property {Boolean} [average=false] Whether the values should be averaged.
* @property {Number} [avgMs=1000] Duration for which the values should be averaged.
* @property {Number} [below] Value below which the graph should be highlighted.
* @property {Number} [over] Value over which the graph should be highlighted.
* @property {Boolean} [interpolate=true] Whether framerate should be interpolated.
*/
window.rStats = function rStats ( settings ) {
function iterateKeys ( array, callback ) {
@ -194,8 +220,6 @@ window.rStats = function rStats ( settings ) {
_graph = new Graph( _dom, _id, _def ),
_started = false;
_dom.className = 'rs-counter-base';
_spanId.className = 'rs-counter-id';
_spanId.textContent = ( _def && _def.caption ) ? _def.caption : _id;
@ -250,7 +274,8 @@ window.rStats = function rStats ( settings ) {
_spanValueText.nodeValue = Math.round( v * 100 ) / 100;
var a = ( _def && ( ( _def.below && _value < _def.below ) || ( _def.over && _value > _def.over ) ) );
_graph.draw( _value, a );
_dom.style.color = a ? '#b70000' : '#ffffff';
_dom.className = a ? 'rs-counter-base alarm' : 'rs-counter-base';
}
function _frame () {
@ -429,10 +454,10 @@ window.rStats = function rStats ( settings ) {
}
/*if( _height != _div.clientHeight ) {
_height = _div.clientHeight;
_base.style.height = _height + 2 * _elHeight + 'px';
console.log( _base.clientHeight );
}*/
_height = _div.clientHeight;
_base.style.height = _height + 2 * _elHeight + 'px';
console.log( _base.clientHeight );
}*/
}
@ -451,269 +476,3 @@ window.rStats = function rStats ( settings ) {
if (typeof module === 'object') {
module.exports = window.rStats;
}
window.glStats = function () {
var _rS = null;
var _totalDrawArraysCalls = 0,
_totalDrawElementsCalls = 0,
_totalUseProgramCalls = 0,
_totalFaces = 0,
_totalVertices = 0,
_totalPoints = 0,
_totalBindTexures = 0;
function _h ( f, c ) {
return function () {
c.apply( this, arguments );
f.apply( this, arguments );
};
}
WebGLRenderingContext.prototype.drawArrays = _h( WebGLRenderingContext.prototype.drawArrays, function () {
_totalDrawArraysCalls++;
if ( arguments[ 0 ] == this.POINTS ) _totalPoints += arguments[ 2 ];
else _totalVertices += arguments[ 2 ];
} );
WebGLRenderingContext.prototype.drawElements = _h( WebGLRenderingContext.prototype.drawElements, function () {
_totalDrawElementsCalls++;
_totalFaces += arguments[ 1 ] / 3;
_totalVertices += arguments[ 1 ];
} );
WebGLRenderingContext.prototype.useProgram = _h( WebGLRenderingContext.prototype.useProgram, function () {
_totalUseProgramCalls++;
} );
WebGLRenderingContext.prototype.bindTexture = _h( WebGLRenderingContext.prototype.bindTexture, function () {
_totalBindTexures++;
} );
var _values = {
allcalls: {
over: 3000,
caption: 'Calls (hook)'
},
drawelements: {
caption: 'drawElements (hook)'
},
drawarrays: {
caption: 'drawArrays (hook)'
}
};
var _groups = [ {
caption: 'WebGL',
values: [ 'allcalls', 'drawelements', 'drawarrays', 'useprogram', 'bindtexture', 'glfaces', 'glvertices', 'glpoints' ]
} ];
var _fractions = [ {
base: 'allcalls',
steps: [ 'drawelements', 'drawarrays' ]
} ];
function _update () {
_rS( 'allcalls' ).set( _totalDrawArraysCalls + _totalDrawElementsCalls );
_rS( 'drawElements' ).set( _totalDrawElementsCalls );
_rS( 'drawArrays' ).set( _totalDrawArraysCalls );
_rS( 'bindTexture' ).set( _totalBindTexures );
_rS( 'useProgram' ).set( _totalUseProgramCalls );
_rS( 'glfaces' ).set( _totalFaces );
_rS( 'glvertices' ).set( _totalVertices );
_rS( 'glpoints' ).set( _totalPoints );
}
function _start () {
_totalDrawArraysCalls = 0;
_totalDrawElementsCalls = 0;
_totalUseProgramCalls = 0;
_totalFaces = 0;
_totalVertices = 0;
_totalPoints = 0;
_totalBindTexures = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
window.threeStats = function ( renderer ) {
var _rS = null;
var _values = {
'renderer.info.memory.geometries': {
caption: 'Geometries'
},
'renderer.info.memory.textures': {
caption: 'Textures'
},
'renderer.info.programs': {
caption: 'Programs'
},
'renderer.info.render.calls': {
caption: 'Calls'
},
'renderer.info.render.faces': {
caption: 'Faces',
over: 1000
},
'renderer.info.render.points': {
caption: 'Points'
},
'renderer.info.render.vertices': {
caption: 'Vertices'
}
};
var _groups = [ {
caption: 'Three.js - Memory',
values: [ 'renderer.info.memory.geometries', 'renderer.info.programs', 'renderer.info.memory.textures' ]
}, {
caption: 'Three.js - Render',
values: [ 'renderer.info.render.calls', 'renderer.info.render.faces', 'renderer.info.render.points', 'renderer.info.render.vertices' ]
} ];
var _fractions = [];
function _update () {
_rS( 'renderer.info.memory.geometries' ).set( renderer.info.memory.geometries );
//_rS( 'renderer.info.programs' ).set( renderer.info.programs.length );
_rS( 'renderer.info.memory.textures' ).set( renderer.info.memory.textures );
_rS( 'renderer.info.render.calls' ).set( renderer.info.render.calls );
_rS( 'renderer.info.render.faces' ).set( renderer.info.render.faces );
_rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
_rS( 'renderer.info.render.vertices' ).set( renderer.info.render.vertices );
}
function _start () {}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
/*
* From https://github.com/paulirish/memory-stats.js
*/
window.BrowserStats = function () {
var _rS = null;
var _usedJSHeapSize = 0,
_totalJSHeapSize = 0;
var memory = {
usedJSHeapSize: 0,
totalJSHeapSize: 0
};
if ( window.performance && performance.memory )
memory = performance.memory;
if ( memory.totalJSHeapSize === 0 ) {
console.warn( 'totalJSHeapSize === 0... performance.memory is only available in Chrome .' );
}
var _values = {
memory: {
caption: 'Used Memory',
average: true,
avgMs: 1000,
over: 22
},
total: {
caption: 'Total Memory'
}
};
var _groups = [ {
caption: 'Browser',
values: [ 'memory', 'total' ]
} ];
var _fractions = [ {
base: 'total',
steps: [ 'memory' ]
} ];
var log1024 = Math.log( 1024 );
function _size ( v ) {
var precision = 100; //Math.pow(10, 2);
var i = Math.floor( Math.log( v ) / log1024 );
if( v === 0 ) i = 1;
return Math.round( v * precision / Math.pow( 1024, i ) ) / precision; // + ' ' + sizes[i];
}
function _update () {
_usedJSHeapSize = _size( memory.usedJSHeapSize );
_totalJSHeapSize = _size( memory.totalJSHeapSize );
_rS( 'memory' ).set( _usedJSHeapSize );
_rS( 'total' ).set( _totalJSHeapSize );
}
function _start () {
_usedJSHeapSize = 0;
}
function _end () {}
function _attach ( r ) {
_rS = r;
}
return {
update: _update,
start: _start,
end: _end,
attach: _attach,
values: _values,
groups: _groups,
fractions: _fractions
};
};
if (typeof module === 'object') {
module.exports = {
glStats: window.glStats,
threeStats: window.threeStats,
BrowserStats: window.BrowserStats
};
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,19 @@
/*!
* @overview es6-promise - a tiny implementation of Promises/A+.
* @copyright Copyright (c) 2014 Yehuda Katz, Tom Dale, Stefan Penner and contributors (Conversion to ES6 API by Jake Archibald)
* @license Licensed under MIT license
* See https://raw.githubusercontent.com/stefanpenner/es6-promise/master/LICENSE
* @version v4.2.8+1e68dce6
*/
/*!**************************************************!*\
!*** ./node_modules/three/build/three.module.js ***!
\**************************************************/
/*!******************************************************!*\
!*** ./node_modules/es6-promise/dist/es6-promise.js ***!
\******************************************************/
/*!**********************************************************!*\
!*** ./node_modules/@tweenjs/tween.js/dist/tween.esm.js ***!
\**********************************************************/

View File

@ -1,95 +1,172 @@
var webpack = require('webpack'),
path = require('path');
// Global imports
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
var entry = './src/js/app.js',
includePath = path.join(__dirname, 'src/js'),
nodeModulesPath = path.join(__dirname, 'node_modules'),
outputPath = path.join(__dirname, 'src/public/assets/js');
// Paths
const entry = './src/js/app.js';
const includePath = path.join(__dirname, 'src/js');
const nodeModulesPath = path.join(__dirname, 'node_modules');
var PROD = JSON.parse(process.env.NODE_ENV || 0);
let outputPath = path.join(__dirname, 'src/public/js');
let publicPath = '/js/';
var env = 'dev',
time = Date.now(),
devtool = 'eval',
debug = true,
plugins = [
new webpack.NoErrorsPlugin(),
new webpack.DefinePlugin({
__ENV__: JSON.stringify(env),
___BUILD_TIME___: time
})
];
module.exports = env => {
// Dev environment
let devtool = 'inline-source-map';
let mode = 'development';
let stats = 'minimal';
let plugins = [
new webpack.DefinePlugin({
__ENV__: JSON.stringify(env.NODE_ENV)
})
];
if(PROD) {
env = 'prod';
devtool = 'hidden-source-map';
debug = false;
outputPath = __dirname + '/build/public/assets/js';
// Prod environment
if (env.NODE_ENV === 'prod') {
devtool = 'hidden-source-map';
mode = 'production';
stats = 'none';
outputPath = `${__dirname}/build/js`;
publicPath = 'js/';
}
uglifyOptions = {
sourceMap: false,
mangle: true,
compress: {
drop_console: true
},
console.log('Webpack build -');
console.log(` - ENV: ${env.NODE_ENV}`);
console.log(` - outputPath ${outputPath}`);
console.log(` - includePath ${includePath}`);
console.log(` - nodeModulesPath: ${nodeModulesPath}`);
return {
// Here the application starts executing
// and webpack starts bundling
entry: [
entry
],
// options related to how webpack emits results
output: {
comments: false
// the target directory for all output files
// must be an absolute path (use the Node.js path module)
path: outputPath,
// the url to the output directory resolved relative to the HTML page
publicPath,
// the filename template for entry chunks
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
},
// Webpack 4 mode helper
mode,
// configuration regarding modules
module: {
// rules for modules (configure loaders, parser options, etc.)
rules: [
{
// these are matching conditions, each accepting a regular expression or string
// test and include have the same behavior, both must be matched
// exclude must not be matched (takes preference over test and include)
// Best practices:
// - Use RegExp only in test and for filename matching
// - Use arrays of absolute paths in include and exclude
// - Try to avoid exclude and prefer include
test: /\.js?$/,
// the loader which should be applied, it'll be resolved relative to the context
// -loader suffix is no longer optional in webpack2 for clarity reasons
// see webpack 1 upgrade guide
use: {
loader: 'babel-loader',
},
include: includePath,
exclude: nodeModulesPath,
},
{
test: /\.(s*)css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
// you can specify a publicPath here
// by default it use publicPath in webpackOptions.output
publicPath: 'css'
}
},
'css-loader',
'postcss-loader',
'sass-loader',
],
}
]
},
// options for resolving module requests
// (does not apply to resolving to loaders)
resolve: {
// directories where to look for modules,
modules: [
'node_modules',
path.resolve(__dirname, 'src')
],
// extensions that are used
extensions: ['.js', '.json'],
},
performance: {
hints: 'warning'
},
// lets you precisely control what bundle information gets displayed
stats,
// enhance debugging by adding meta info for the browser devtools
// source-map most detailed at the expense of build speed.
devtool,
devServer: {
static: 'src/public',
open: false,
},
plugins: plugins.concat(
new HtmlWebpackPlugin({
title: 'Three.js Webpack ES6 Boilerplate',
template: path.join(__dirname, 'src/html/index.html'),
filename: '../index.html',
env: env.NODE_ENV,
}),
new MiniCssExtractPlugin({
filename: '../css/[name].css',
chunkFilename: '../css/[id].css'
})
),
optimization: {
minimize: true,
minimizer: [
new TerserPlugin(),
new OptimizeCSSAssetsPlugin()
],
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\\/]node_modules[\\\/]/,
name: 'vendors',
chunks: 'all'
},
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
}
};
plugins.push(new webpack.optimize.UglifyJsPlugin(uglifyOptions));
}
console.log('Webpack build - ENV: ' + env + ' V: ' + time);
console.log(' - outputPath ', outputPath);
console.log(' - includePath ', includePath);
console.log(' - nodeModulesPath ', nodeModulesPath);
module.exports = {
stats: {
colors: true
},
debug: debug,
devtool: devtool,
devServer: {
contentBase: 'src/public'
},
entry: [
entry
],
output: {
path: outputPath,
publicPath: 'assets/js',
filename: 'app.js'
},
module: {
loaders: [
{
test: /\.js?$/,
loader: 'babel-loader',
query: {
presets: ['es2015']
},
include: [
includePath, nodeModulesPath
]
}
]
},
sassLoader: {
outputStyle: 'compressed',
outFile: __dirname + '/src/public/assets/css'
},
plugins: plugins,
resolve: {
alias: {}
}
};