Compare commits

...

101 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 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 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 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 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 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 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 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 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 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 from igghera/master
Update webpack-cli version
2018-12-06 16:55:21 -05:00
Andrea Gherardi c212317b72 Update webpack-cli version
Fixes 
2018-12-06 10:28:59 +01:00
Paul Graffam 7381928803
Merge pull request from lucaskuzma/camera-fix
Update camera.js
2018-10-24 11:15:33 -04:00
Paul Graffam 8eaf3a8b49
Merge pull request from rtpHarry/patch-2
fixes  - clarify animation mixer comment
2018-10-09 11:02:56 -04:00
Matthew Harris ba8478fbe5
fixes - 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 from rtpHarry/patch-1
Add clarification for a comment
2018-06-27 12:21:39 -04:00
Paul Graffam 481b33053c
Merge pull request 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 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 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
70 changed files with 26917 additions and 2227 deletions

1
.babelrc Normal file
View File

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

116
.eslintrc
View File

@ -1,60 +1,60 @@
{
"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"
}
"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,18 +1,29 @@
# 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
* src/css - Contains all SCSS files, that are compiled to `src/public/assets/css`
* src/js - All the Three.js app files, with `app.js` as entry point. Compiled to `src/public/assets/js` with webpack
* src/js/app/components - Three.js components that get initialized in `main.js`
* src/js/app/helpers - Classes that provide ideas on how to set up and work with defaults
* src/js/app/managers - Manage complex tasks such as GUI or input
* src/js/app/model - Classes that set up the model object
* src/js/data - Any data to be imported into app
* src/js/utils - Various helpers and vendor classes
* src/public - Used by webpack-dev-server to serve content and is copied over to build folder with build command. Place external vendor files here.
```
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:
@ -27,30 +38,28 @@ 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. Only reloads automatically upon save of js files.
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 folder and then 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 build folder and lints `src/js`
* clean - Cleans build folder
* lint - Runs lint on `src/js` folder and uses `.eslintrc` file in root as linting rules
* webpack-server - Create webpack-dev-server with hot-module-replacement
* webpack-watch - Run webpack in dev environment with watch
* dev:sass - Run node-sass on `src/css` folder and output to `src/public` and watch for changes
* dev:js - Run webpack in dev environment without watch
* build:dir - Copy files and folders from `src/public` to `build`
* build:sass - Run node-sass on `src/css` and output compressed css to `build` folder
* build:js - Run webpack in production environment
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
Scrollwheel zooms in and out
* 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

(image error) 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

(image error) Size: 636 KiB

After

(image error) 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{-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}body{overflow:hidden}.main{position:relative;width:100%;height:100vh}#loading{position:absolute;top:calc(50% - 8px);left:calc(50% - 35px)}

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>
<section id="appContainer" class="main">
<div id="loading">Loading...</div>
</section>
<script src="./assets/js/rStats.js"></script>
<script src="./assets/js/rStats.extras.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,42 +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",
"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/",
"webpack-server": "set NODE_ENV=0&& webpack-dev-server --progress --colors --hot --inline --open",
"webpack-watch": "set NODE_ENV=0&& webpack --progress --colors --watch --cache",
"dev:sass": "node-sass -w -r src/css/ -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"
"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": "^4.0.5",
"three": "0.81.2",
"tween.js": "16.3.0"
"@tweenjs/tween.js": "^18.6.4",
"es6-promise": "^4.2.8",
"three": "^0.126.1"
},
"devDependencies": {
"babel-core": "^6.17.0",
"babel-loader": "^6.2.5",
"babel-preset-es2015": "^6.16.0",
"copyfiles": "^1.0.0",
"eslint": "^3.7.1",
"node-sass": "^3.10.1",
"npm-run-all": "^3.0.0",
"rimraf": "^2.5.4",
"webpack": "^1.13.2",
"webpack-dev-middleware": "^1.8.3",
"webpack-dev-server": "^1.16.2"
},
"engines": {
"node": "6.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'),
],
};

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,8 +2,11 @@ import Config from './data/config';
import Detector from './utils/detector';
import Main from './app/main';
// Styles
import './../css/app.scss';
// Check environment and set the Config helper
if(__ENV__ == 'dev') {
if(__ENV__ === 'dev') {
console.log('----- RUNNING IN DEV ENVIRONMENT! -----');
Config.isDev = true;

View File

@ -2,7 +2,7 @@ import * as THREE from 'three';
export default class Animation {
constructor(obj, clip) {
// Object with animations
// Scene that the clip will be applied to
this.obj = obj;
// Initialize animation mixer

View File

@ -20,8 +20,8 @@ export default class Camera {
}
updateSize(renderer) {
// Multiply by dpr in case it is retina device
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,7 +1,6 @@
import * as THREE from 'three';
import Material from './material';
import Config from '../../data/config';
// This helper class can be used to create and then place geometry in the scene
@ -12,13 +11,13 @@ 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') {
if(type === 'sphere') {
return (radius, widthSegments = 32, heightSegments = 32) => {
this.geo = new THREE.SphereGeometry(radius, widthSegments, heightSegments);
};

View File

@ -38,9 +38,10 @@ export default class Light {
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;
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);
@ -55,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

@ -1,7 +1,5 @@
import * as THREE from 'three';
import Config from '../../data/config';
// USe this class as a helper to set up some default materials
export default class Material {
constructor(color) {

View File

@ -24,7 +24,7 @@ export default class Renderer {
this.threeRenderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Get anisotropy for textures
Config.maxAnisotropy = this.threeRenderer.getMaxAnisotropy();
Config.maxAnisotropy = this.threeRenderer.capabilities.getMaxAnisotropy();
// Initial size update set to canvas container
this.updateSize();

View File

@ -1,24 +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) {
const wireframe = new THREE.WireframeGeometry(mesh.geometry);
const wireLine = new THREE.LineSegments(wireframe);
wireLine.material.depthTest = false;
wireLine.material.opacity = 0.25;
wireLine.material.transparent = true;
mesh.add(wireLine);
this.mesh = mesh;
this.scene = scene;
const edges = new THREE.EdgesGeometry(mesh.geometry);
const edgesLine = new THREE.LineSegments(edges);
edgesLine.material.depthTest = false;
edgesLine.material.opacity = 0.25;
edgesLine.material.transparent = true;
mesh.add(edgesLine);
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;
scene.add(new THREE.BoxHelper(mesh));
scene.add(new THREE.FaceNormalsHelper(mesh, 2));
scene.add(new THREE.VertexNormalsHelper(mesh, 2));
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,6 +1,6 @@
// Global imports -
import * as THREE from 'three';
import TWEEN from 'tween.js';
import TWEEN from '@tweenjs/tween.js';
// Local imports -
// Components
@ -8,9 +8,11 @@ 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 Geometry from './helpers/geometry';
import Stats from './helpers/stats';
import MeshHelper from './helpers/meshHelper';
// Model
import Texture from './model/texture';
@ -24,10 +26,6 @@ import DatGUI from './managers/datGUI';
import Config from './../data/config';
// -- End of imports
// Local vars for rStats
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) {
@ -46,51 +44,32 @@ export default class Main {
Config.dpr = window.devicePixelRatio;
}
// Main renderer instantiation
// Main renderer constructor
this.renderer = new Renderer(this.scene, container);
// Components instantiation
// Components instantiations
this.camera = new Camera(this.renderer.threeRenderer);
this.controls = new Controls(this.camera.threeCamera, container);
this.light = new Light(this.scene);
// 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));
// Create and place geo in scene
this.geometry = new Geometry(this.scene);
this.geometry.make('plane')(150, 150, 10, 10);
this.geometry.place([0, -20, 0], [Math.PI/2, 0, 0]);
this.geometry.place([0, -20, 0], [Math.PI / 2, 0, 0]);
// Set up rStats if dev environment
if(Config.isDev) {
bS = new BrowserStats();
glS = new glStats();
tS = new threeStats(this.renderer.threeRenderer);
if(Config.isDev && Config.isShowingStats) {
this.stats = new Stats(this.renderer);
this.stats.setUp();
}
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 gui
if (Config.isDev) {
this.gui = new DatGUI(this)
}
// Instantiate texture class
@ -102,7 +81,7 @@ export default class Main {
// Textures loaded, load model
this.model = new Model(this.scene, this.manager, this.texture.textures);
this.model.load();
this.model.load(Config.models[Config.model.selected].type);
// onProgress callback
this.manager.onProgress = (item, loaded, total) => {
@ -116,7 +95,10 @@ export default class Main {
// Add dat.GUI controls if dev
if(Config.isDev) {
new DatGUI(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
@ -131,34 +113,22 @@ export default class Main {
render() {
// Render rStats if Dev
if(Config.isDev) {
rS('frame').start();
glS.start();
rS('rAF').tick();
rS('FPS').frame();
rS('render').start();
if(Config.isDev && Config.isShowingStats) {
Stats.start();
}
// Call render function and pass in created scene and camera
this.renderer.render(this.scene, this.camera.threeCamera);
// rStats has finished determining render call now
if(Config.isDev) {
rS('render').end(); // render finished
rS('frame').end(); // frame finished
// Local rStats update
rS('rStats').start();
rS().update();
rS('rStats').end();
if(Config.isDev && Config.isShowingStats) {
Stats.end();
}
// Delta time is sometimes needed for certain updates
//const delta = this.clock.getDelta();
// Call any vendor or module updates here
// Call any vendor or module frame updates here
TWEEN.update();
this.controls.threeControls.update();

View File

@ -2,18 +2,27 @@ import Config from '../../data/config';
// Manages all dat.GUI interactions
export default class DatGUI {
constructor(main, mesh) {
const gui = new dat.GUI();
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 */
const cameraFolder = gui.addFolder('Camera');
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;
@ -38,13 +47,13 @@ export default class DatGUI {
});
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);
});
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(() => {
this.controls.enableRotate = true;
@ -52,7 +61,7 @@ export default class DatGUI {
/* Controls */
const controlsFolder = gui.addFolder('Controls');
const controlsFolder = this.gui.addFolder('Controls');
controlsFolder.add(Config.controls, 'autoRotate').name('Auto Rotate').onChange((value) => {
this.controls.autoRotate = value;
});
@ -66,8 +75,29 @@ export default class DatGUI {
});
/* 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 */
const 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;
@ -83,7 +113,7 @@ export default class DatGUI {
/* Lights */
// Ambient Light
const 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;
});
@ -93,7 +123,7 @@ export default class DatGUI {
// Directional Light
const 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;
});
@ -138,7 +168,7 @@ export default class DatGUI {
});
// Shadow Map
const 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;
});
@ -232,7 +262,7 @@ export default class DatGUI {
// Point Light
const 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;
});
@ -287,7 +317,7 @@ export default class DatGUI {
// Hemi Light
const 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;
});
@ -334,4 +364,9 @@ export default class DatGUI {
this.controls.enableRotate = true;
});
}
unload() {
this.gui.destroy();
this.gui = new dat.GUI();
}
}

View File

@ -1,8 +1,9 @@
import * as THREE from 'three';
import Material from '../helpers/material';
import MeshHelper from '../helpers/meshHelper';
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
@ -10,40 +11,91 @@ export default class Model {
constructor(scene, manager, textures) {
this.scene = scene;
this.textures = textures;
this.manager = manager;
// Manager is passed in to loader to determine when loading done in main
this.loader = new THREE.ObjectLoader(manager);
this.obj = null;
this.ref = null;
}
load() {
// Load model with ObjectLoader
this.loader.load(Config.model.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;
load(type) {
// Manager is passed in to loader to determine when loading done in main
// Set to cast and receive shadow if enabled
if(Config.shadow.enabled) {
child.receiveShadow = true;
child.castShadow = true;
}
}
});
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;
// Add mesh helper if Dev
if(Config.isDev && Config.mesh.enableHelper) {
new MeshHelper(this.scene, obj);
}
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;
}
});
}
// Set prop to obj
this.obj = obj;
this.obj = mesh;
obj.scale.multiplyScalar(Config.model.scale);
this.scene.add(obj);
}, Helpers.logProgress(), Helpers.logError());
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

@ -1,8 +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,
@ -13,17 +14,30 @@ export default {
easing: TWEEN.Easing.Quadratic.InOut,
duration: 500,
model: {
path: './assets/models/Teapot.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/',
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: {
@ -65,7 +79,7 @@ export default {
}
},
ambientLight: {
enabled: false,
enabled: true,
color: 0x141414
},
directionalLight: {

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

@ -8,7 +8,7 @@ export default class Helpers {
const context = scope || this;
const now = +new Date,
args = arguments;
args = arguments;
if(last && now < last + threshhold) {
clearTimeout(deferTimer);

View File

@ -14,16 +14,16 @@ 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);

File diff suppressed because it is too large Load Diff

View File

@ -1,76 +0,0 @@
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; }
body {
overflow: hidden; }
.main {
position: relative;
width: 100%;
height: 100vh; }
#loading {
position: absolute;
top: calc(50% - 8px);
left: calc(50% - 35px); }

View File

@ -1,86 +0,0 @@
.alarm {
color: #b70000;
text-shadow: 0 0 0 #b70000,
0 0 1px #ffffff,
0 0 1px #ffffff,
0 0 2px #ffffff,
0 0 2px #ffffff,
0 0 3px #ffffff,
0 0 3px #ffffff,
0 0 4px #ffffff,
0 0 4px #ffffff;
}
.rs-base {
position: absolute;
top: 0;
left: 0;
z-index: 10000;
overflow: hidden;
padding: 10px;
width: 350px;
background-color: #222222;
font-size: 10px;
font-family: 'Roboto Condensed', tahoma, sans-serif;
line-height: 1.2em;
}
.rs-base h1 {
margin: 0;
margin-bottom: 5px;
padding: 0;
color: #ffffff;
font-size: 1.4em;
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 {
margin: 0;
padding: 0;
width: 120px;
text-align: right;
}
.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;
top: 0;
left: 0;
}
.rs-base div.rs-counter-value {
position: absolute;
top: 0;
left: 90px;
width: 30px;
height: 1em;
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,265 +0,0 @@
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
};
}

View File

@ -1,453 +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;
}

Binary file not shown.

Binary file not shown.

After

(image error) 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"
}
]
}

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

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>
<section id="appContainer" class="main">
<div id="loading">Loading...</div>
</section>
<body>
<section id="appContainer" class="main">
<div id="loading">Loading...</div>
</section>
<script src="./assets/js/rStats.js"></script>
<script src="./assets/js/rStats.extras.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

@ -116,9 +116,9 @@ window.threeStats = function ( renderer ) {
'renderer.info.render.calls': {
caption: 'Calls'
},
'renderer.info.render.faces': {
caption: 'Faces',
over: 1000
'renderer.info.render.triangles': {
caption: 'Triangles',
over: 5000
},
'renderer.info.render.points': {
caption: 'Points'
@ -133,21 +133,18 @@ window.threeStats = function ( renderer ) {
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' ]
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.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 );
_rS( 'renderer.info.render.triangles' ).set( renderer.info.render.triangles );
// _rS( 'renderer.info.render.points' ).set( renderer.info.render.points );
}
function _start () {}

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 );
}*/
}

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,84 +1,172 @@
// Global imports
var webpack = require('webpack'),
path = require('path');
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');
// Paths
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');
const entry = './src/js/app.js';
const includePath = path.join(__dirname, 'src/js');
const nodeModulesPath = path.join(__dirname, 'node_modules');
// Environment
var PROD = JSON.parse(process.env.NODE_ENV || 0);
let outputPath = path.join(__dirname, 'src/public/js');
let publicPath = '/js/';
// Dev environment
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)
})
];
// Production environment
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
]
}
]
},
plugins: plugins
};