├── .gitignore ├── bundler ├── webpack.common.js ├── webpack.dev.js └── webpack.prod.js ├── package-lock.json ├── package.json ├── readme.md ├── report.20210312.220522.3600.0.001.json ├── resources ├── brushes.psb ├── world.blend └── world.blend1 ├── src ├── index.html ├── index.js ├── javascript │ ├── Application.js │ ├── BrushParticles.js │ ├── Camera │ │ ├── DebugCamera.js │ │ ├── DefaultCamera.js │ │ └── index.js │ ├── Controls.js │ ├── Fullscreen.js │ ├── Materials │ │ └── PointsPhysicalMaterial.js │ ├── Passes │ │ └── FinalPass.js │ ├── Physics.js │ ├── Renderer.js │ ├── Resources.js │ ├── Utils │ │ ├── EventEmitter.js │ │ ├── Loader.js │ │ ├── Sizes.js │ │ ├── Stats.js │ │ └── Time.js │ ├── World.js │ ├── assets.js │ └── shaders │ │ ├── final │ │ ├── fragment.glsl │ │ └── vertex.glsl │ │ ├── pointsPhysical │ │ ├── fragment.glsl │ │ └── vertex.glsl │ │ └── standardBase │ │ ├── fragment.glsl │ │ └── vertex.glsl └── style │ └── main.css └── static ├── .gitkeep ├── textures ├── brushes │ ├── brush1.png │ ├── brush2.png │ ├── brush3.png │ └── brush4.png ├── door │ ├── alpha.jpg │ ├── ambientOcclusion.jpg │ ├── color.jpg │ ├── height.jpg │ ├── metalness.jpg │ ├── normal.jpg │ └── roughness.jpg └── environmentMaps │ ├── 0 │ ├── nx.jpg │ ├── ny.jpg │ ├── nz.jpg │ ├── px.jpg │ ├── py.jpg │ └── pz.jpg │ ├── 1 │ ├── nx.jpg │ ├── ny.jpg │ ├── nz.jpg │ ├── px.jpg │ ├── py.jpg │ └── pz.jpg │ ├── 2 │ ├── nx.jpg │ ├── ny.jpg │ ├── nz.jpg │ ├── px.jpg │ ├── py.jpg │ └── pz.jpg │ └── 3 │ ├── nx.jpg │ ├── ny.jpg │ ├── nz.jpg │ ├── px.jpg │ ├── py.jpg │ └── pz.jpg └── world.glb /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | .cache 5 | 6 | # Editor directories and files 7 | .idea 8 | .vscode 9 | *.suo 10 | *.ntvs* 11 | *.njsproj 12 | *.sln 13 | *.sw? 14 | -------------------------------------------------------------------------------- /bundler/webpack.common.js: -------------------------------------------------------------------------------- 1 | const CopyWebpackPlugin = require('copy-webpack-plugin') 2 | const HtmlWebpackPlugin = require('html-webpack-plugin') 3 | const MiniCSSExtractPlugin = require('mini-css-extract-plugin') 4 | const path = require('path') 5 | 6 | module.exports = { 7 | entry: path.resolve(__dirname, '../src/index.js'), 8 | output: 9 | { 10 | filename: 'bundle.[contenthash].js', 11 | path: path.resolve(__dirname, '../dist') 12 | }, 13 | devtool: 'source-map', 14 | plugins: 15 | [ 16 | new CopyWebpackPlugin({ 17 | patterns: [ 18 | { from: path.resolve(__dirname, '../static') } 19 | ] 20 | }), 21 | new HtmlWebpackPlugin({ 22 | template: path.resolve(__dirname, '../src/index.html'), 23 | minify: true 24 | }), 25 | new MiniCSSExtractPlugin() 26 | ], 27 | module: 28 | { 29 | rules: 30 | [ 31 | // HTML 32 | { 33 | test: /\.(html)$/, 34 | use: ['html-loader'] 35 | }, 36 | 37 | // JS 38 | { 39 | test: /\.js$/, 40 | exclude: /node_modules/, 41 | use: 42 | [ 43 | 'babel-loader' 44 | ] 45 | }, 46 | 47 | // CSS 48 | { 49 | test: /\.css$/, 50 | use: 51 | [ 52 | MiniCSSExtractPlugin.loader, 53 | 'css-loader' 54 | ] 55 | }, 56 | 57 | // Images 58 | { 59 | test: /\.(jpg|png|gif|svg)$/, 60 | use: 61 | [ 62 | { 63 | loader: 'file-loader', 64 | options: 65 | { 66 | outputPath: 'assets/images/' 67 | } 68 | } 69 | ] 70 | }, 71 | 72 | // Fonts 73 | { 74 | test: /\.(ttf|eot|woff|woff2)$/, 75 | use: 76 | [ 77 | { 78 | loader: 'file-loader', 79 | options: 80 | { 81 | outputPath: 'assets/fonts/' 82 | } 83 | } 84 | ] 85 | }, 86 | 87 | // Shaders 88 | { 89 | test: /\.(glsl|vs|fs|vert|frag)$/, 90 | exclude: /node_modules/, 91 | use: [ 92 | 'raw-loader' 93 | ] 94 | } 95 | ] 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /bundler/webpack.dev.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge') 2 | const commonConfiguration = require('./webpack.common.js') 3 | const ip = require('internal-ip') 4 | const portFinderSync = require('portfinder-sync') 5 | 6 | const infoColor = (_message) => 7 | { 8 | return `\u001b[1m\u001b[34m${_message}\u001b[39m\u001b[22m` 9 | } 10 | 11 | module.exports = merge( 12 | commonConfiguration, 13 | { 14 | mode: 'development', 15 | devServer: 16 | { 17 | host: '0.0.0.0', 18 | port: portFinderSync.getPort(8080), 19 | contentBase: './dist', 20 | watchContentBase: true, 21 | open: true, 22 | https: false, 23 | useLocalIp: true, 24 | disableHostCheck: true, 25 | overlay: true, 26 | noInfo: true, 27 | after: function(app, server, compiler) 28 | { 29 | const port = server.options.port 30 | const https = server.options.https ? 's' : '' 31 | const localIp = ip.v4.sync() 32 | const domain1 = `http${https}://${localIp}:${port}` 33 | const domain2 = `http${https}://localhost:${port}` 34 | 35 | console.log(`Project running at:\n - ${infoColor(domain1)}\n - ${infoColor(domain2)}`) 36 | } 37 | } 38 | } 39 | ) 40 | -------------------------------------------------------------------------------- /bundler/webpack.prod.js: -------------------------------------------------------------------------------- 1 | const { merge } = require('webpack-merge') 2 | const commonConfiguration = require('./webpack.common.js') 3 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 4 | 5 | module.exports = merge( 6 | commonConfiguration, 7 | { 8 | mode: 'production', 9 | plugins: 10 | [ 11 | new CleanWebpackPlugin() 12 | ] 13 | } 14 | ) 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "scripts": { 3 | "build": "webpack --config ./bundler/webpack.prod.js", 4 | "dev": "webpack serve --config ./bundler/webpack.dev.js" 5 | }, 6 | "dependencies": { 7 | "@babel/core": "^7.12.10", 8 | "@babel/preset-env": "^7.12.11", 9 | "babel-loader": "^8.2.2", 10 | "clean-webpack-plugin": "^3.0.0", 11 | "copy-webpack-plugin": "^7.0.0", 12 | "css-loader": "^5.0.1", 13 | "dat.gui": "^0.7.7", 14 | "file-loader": "^6.2.0", 15 | "gsap": "^3.6.0", 16 | "guify": "^0.12.0", 17 | "html-loader": "^1.3.2", 18 | "html-webpack-plugin": "^5.0.0-alpha.7", 19 | "matter-js": "^0.16.1", 20 | "mini-css-extract-plugin": "^1.3.5", 21 | "ola": "^1.1.1", 22 | "poly-decomp": "^0.3.0", 23 | "portfinder-sync": "0.0.2", 24 | "raw-loader": "^4.0.2", 25 | "stats.js": "^0.17.0", 26 | "style-loader": "^2.0.0", 27 | "three": "^0.125.1", 28 | "webpack": "^5.18.0", 29 | "webpack-cli": "^4.4.0", 30 | "webpack-dev-server": "^3.11.2", 31 | "webpack-merge": "^5.7.3", 32 | "alea": "^1.0.0" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Three.js - Points Physical Material 2 | 3 | ## Setup 4 | Download [Node.js](https://nodejs.org/en/download/). 5 | Run this followed commands: 6 | 7 | ``` bash 8 | # Install dependencies (only the first time) 9 | npm install 10 | 11 | # Run the local server at localhost:8080 12 | npm run dev 13 | 14 | # Build for production in the dist/ directory 15 | npm run build 16 | ``` 17 | -------------------------------------------------------------------------------- /report.20210312.220522.3600.0.001.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "header": { 4 | "reportVersion": 1, 5 | "event": "Allocation failed - JavaScript heap out of memory", 6 | "trigger": "FatalError", 7 | "filename": "report.20210312.220522.3600.0.001.json", 8 | "dumpEventTime": "2021-03-12T22:05:22Z", 9 | "dumpEventTimeStamp": "1615583122526", 10 | "processId": 3600, 11 | "cwd": "/Users/brunosimon/Projects/threejs-points-physical-material", 12 | "commandLine": [ 13 | "node", 14 | "/Users/brunosimon/Projects/threejs-points-physical-material/node_modules/.bin/webpack", 15 | "serve", 16 | "--config", 17 | "./bundler/webpack.dev.js" 18 | ], 19 | "nodejsVersion": "v12.14.1", 20 | "wordSize": 64, 21 | "arch": "x64", 22 | "platform": "darwin", 23 | "componentVersions": { 24 | "node": "12.14.1", 25 | "v8": "7.7.299.13-node.16", 26 | "uv": "1.33.1", 27 | "zlib": "1.2.11", 28 | "brotli": "1.0.7", 29 | "ares": "1.15.0", 30 | "modules": "72", 31 | "nghttp2": "1.40.0", 32 | "napi": "5", 33 | "llhttp": "2.0.1", 34 | "http_parser": "2.8.0", 35 | "openssl": "1.1.1d", 36 | "cldr": "35.1", 37 | "icu": "64.2", 38 | "tz": "2019c", 39 | "unicode": "12.1" 40 | }, 41 | "release": { 42 | "name": "node", 43 | "lts": "Erbium", 44 | "headersUrl": "https://nodejs.org/download/release/v12.14.1/node-v12.14.1-headers.tar.gz", 45 | "sourceUrl": "https://nodejs.org/download/release/v12.14.1/node-v12.14.1.tar.gz" 46 | }, 47 | "osName": "Darwin", 48 | "osRelease": "20.2.0", 49 | "osVersion": "Darwin Kernel Version 20.2.0: Wed Dec 2 20:39:59 PST 2020; root:xnu-7195.60.75~1/RELEASE_X86_64", 50 | "osMachine": "x86_64", 51 | "cpus": [ 52 | { 53 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 54 | "speed": 2300, 55 | "user": 7674660, 56 | "nice": 0, 57 | "sys": 4214560, 58 | "idle": 34529550, 59 | "irq": 0 60 | }, 61 | { 62 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 63 | "speed": 2300, 64 | "user": 134450, 65 | "nice": 0, 66 | "sys": 143850, 67 | "idle": 46140050, 68 | "irq": 0 69 | }, 70 | { 71 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 72 | "speed": 2300, 73 | "user": 6611000, 74 | "nice": 0, 75 | "sys": 3231110, 76 | "idle": 36576250, 77 | "irq": 0 78 | }, 79 | { 80 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 81 | "speed": 2300, 82 | "user": 128600, 83 | "nice": 0, 84 | "sys": 117260, 85 | "idle": 46172490, 86 | "irq": 0 87 | }, 88 | { 89 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 90 | "speed": 2300, 91 | "user": 4968060, 92 | "nice": 0, 93 | "sys": 2388060, 94 | "idle": 39062230, 95 | "irq": 0 96 | }, 97 | { 98 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 99 | "speed": 2300, 100 | "user": 130780, 101 | "nice": 0, 102 | "sys": 101300, 103 | "idle": 46186280, 104 | "irq": 0 105 | }, 106 | { 107 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 108 | "speed": 2300, 109 | "user": 4221820, 110 | "nice": 0, 111 | "sys": 1994100, 112 | "idle": 40202440, 113 | "irq": 0 114 | }, 115 | { 116 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 117 | "speed": 2300, 118 | "user": 131890, 119 | "nice": 0, 120 | "sys": 86490, 121 | "idle": 46199960, 122 | "irq": 0 123 | }, 124 | { 125 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 126 | "speed": 2300, 127 | "user": 3162750, 128 | "nice": 0, 129 | "sys": 1443060, 130 | "idle": 41812550, 131 | "irq": 0 132 | }, 133 | { 134 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 135 | "speed": 2300, 136 | "user": 131540, 137 | "nice": 0, 138 | "sys": 74790, 139 | "idle": 46212020, 140 | "irq": 0 141 | }, 142 | { 143 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 144 | "speed": 2300, 145 | "user": 2734340, 146 | "nice": 0, 147 | "sys": 1145740, 148 | "idle": 42538280, 149 | "irq": 0 150 | }, 151 | { 152 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 153 | "speed": 2300, 154 | "user": 131050, 155 | "nice": 0, 156 | "sys": 63740, 157 | "idle": 46223560, 158 | "irq": 0 159 | }, 160 | { 161 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 162 | "speed": 2300, 163 | "user": 2214550, 164 | "nice": 0, 165 | "sys": 861130, 166 | "idle": 43342680, 167 | "irq": 0 168 | }, 169 | { 170 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 171 | "speed": 2300, 172 | "user": 127980, 173 | "nice": 0, 174 | "sys": 54340, 175 | "idle": 46236030, 176 | "irq": 0 177 | }, 178 | { 179 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 180 | "speed": 2300, 181 | "user": 1750320, 182 | "nice": 0, 183 | "sys": 600200, 184 | "idle": 44067830, 185 | "irq": 0 186 | }, 187 | { 188 | "model": "Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz", 189 | "speed": 2300, 190 | "user": 124990, 191 | "nice": 0, 192 | "sys": 47700, 193 | "idle": 46245660, 194 | "irq": 0 195 | } 196 | ], 197 | "networkInterfaces": [ 198 | { 199 | "name": "lo0", 200 | "internal": true, 201 | "mac": "00:00:00:00:00:00", 202 | "address": "127.0.0.1", 203 | "netmask": "255.0.0.0", 204 | "family": "IPv4" 205 | }, 206 | { 207 | "name": "lo0", 208 | "internal": true, 209 | "mac": "00:00:00:00:00:00", 210 | "address": "::1", 211 | "netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", 212 | "family": "IPv6", 213 | "scopeid": 0 214 | }, 215 | { 216 | "name": "lo0", 217 | "internal": true, 218 | "mac": "00:00:00:00:00:00", 219 | "address": "fe80::1", 220 | "netmask": "ffff:ffff:ffff:ffff::", 221 | "family": "IPv6", 222 | "scopeid": 1 223 | }, 224 | { 225 | "name": "en5", 226 | "internal": false, 227 | "mac": "ac:de:48:00:11:22", 228 | "address": "fe80::aede:48ff:fe00:1122", 229 | "netmask": "ffff:ffff:ffff:ffff::", 230 | "family": "IPv6", 231 | "scopeid": 4 232 | }, 233 | { 234 | "name": "en0", 235 | "internal": false, 236 | "mac": "f8:ff:c2:59:53:ea", 237 | "address": "fe80::cba:638f:a03:4d21", 238 | "netmask": "ffff:ffff:ffff:ffff::", 239 | "family": "IPv6", 240 | "scopeid": 6 241 | }, 242 | { 243 | "name": "en0", 244 | "internal": false, 245 | "mac": "f8:ff:c2:59:53:ea", 246 | "address": "192.168.1.11", 247 | "netmask": "255.255.255.0", 248 | "family": "IPv4" 249 | }, 250 | { 251 | "name": "en0", 252 | "internal": false, 253 | "mac": "f8:ff:c2:59:53:ea", 254 | "address": "2a01:cb04:558:1300:1cd1:d2d5:cfa8:40ae", 255 | "netmask": "ffff:ffff:ffff:ffff::", 256 | "family": "IPv6", 257 | "scopeid": 0 258 | }, 259 | { 260 | "name": "en0", 261 | "internal": false, 262 | "mac": "f8:ff:c2:59:53:ea", 263 | "address": "2a01:cb04:558:1300:d9fe:7450:cfeb:5052", 264 | "netmask": "ffff:ffff:ffff:ffff::", 265 | "family": "IPv6", 266 | "scopeid": 0 267 | }, 268 | { 269 | "name": "awdl0", 270 | "internal": false, 271 | "mac": "fa:f4:0e:18:b4:d3", 272 | "address": "fe80::f8f4:eff:fe18:b4d3", 273 | "netmask": "ffff:ffff:ffff:ffff::", 274 | "family": "IPv6", 275 | "scopeid": 12 276 | }, 277 | { 278 | "name": "llw0", 279 | "internal": false, 280 | "mac": "fa:f4:0e:18:b4:d3", 281 | "address": "fe80::f8f4:eff:fe18:b4d3", 282 | "netmask": "ffff:ffff:ffff:ffff::", 283 | "family": "IPv6", 284 | "scopeid": 13 285 | }, 286 | { 287 | "name": "utun0", 288 | "internal": false, 289 | "mac": "00:00:00:00:00:00", 290 | "address": "fe80::49ec:32cd:45b0:54db", 291 | "netmask": "ffff:ffff:ffff:ffff::", 292 | "family": "IPv6", 293 | "scopeid": 14 294 | }, 295 | { 296 | "name": "utun1", 297 | "internal": false, 298 | "mac": "00:00:00:00:00:00", 299 | "address": "fe80::7f10:3a29:dd01:2db3", 300 | "netmask": "ffff:ffff:ffff:ffff::", 301 | "family": "IPv6", 302 | "scopeid": 15 303 | } 304 | ], 305 | "host": "MBP-de-Bruno.home" 306 | }, 307 | "javascriptStack": { 308 | "message": "No stack.", 309 | "stack": [ 310 | "Unavailable." 311 | ] 312 | }, 313 | "nativeStack": [ 314 | { 315 | "pc": "0x000000010014e0ce", 316 | "symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::__1::basic_string, std::__1::allocator > const&, v8::Local) [/usr/local/bin/node]" 317 | }, 318 | { 319 | "pc": "0x000000010007f391", 320 | "symbol": "node::OnFatalError(char const*, char const*) [/usr/local/bin/node]" 321 | }, 322 | { 323 | "pc": "0x0000000100176887", 324 | "symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]" 325 | }, 326 | { 327 | "pc": "0x0000000100176823", 328 | "symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/usr/local/bin/node]" 329 | }, 330 | { 331 | "pc": "0x00000001002fa9d5", 332 | "symbol": "v8::internal::Heap::FatalProcessOutOfMemory(char const*) [/usr/local/bin/node]" 333 | }, 334 | { 335 | "pc": "0x00000001002fc0a4", 336 | "symbol": "v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/usr/local/bin/node]" 337 | }, 338 | { 339 | "pc": "0x00000001002f8f77", 340 | "symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/usr/local/bin/node]" 341 | }, 342 | { 343 | "pc": "0x00000001002f6f5d", 344 | "symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/usr/local/bin/node]" 345 | }, 346 | { 347 | "pc": "0x0000000100302674", 348 | "symbol": "v8::internal::Heap::AllocateRawWithLightRetry(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/usr/local/bin/node]" 349 | }, 350 | { 351 | "pc": "0x00000001003026ef", 352 | "symbol": "v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/usr/local/bin/node]" 353 | }, 354 | { 355 | "pc": "0x00000001002cf2e7", 356 | "symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType) [/usr/local/bin/node]" 357 | }, 358 | { 359 | "pc": "0x00000001005f8935", 360 | "symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/usr/local/bin/node]" 361 | }, 362 | { 363 | "pc": "0x00000001009311f9", 364 | "symbol": "Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit [/usr/local/bin/node]" 365 | } 366 | ], 367 | "javascriptHeap": { 368 | "totalMemory": 2151460864, 369 | "totalCommittedMemory": 2149940160, 370 | "usedMemory": 2142758464, 371 | "availableMemory": 51879968, 372 | "memoryLimit": 2197815296, 373 | "heapSpaces": { 374 | "read_only_space": { 375 | "memorySize": 262144, 376 | "committedMemory": 32568, 377 | "capacity": 261872, 378 | "used": 32296, 379 | "available": 229576 380 | }, 381 | "new_space": { 382 | "memorySize": 2097152, 383 | "committedMemory": 1052248, 384 | "capacity": 1047488, 385 | "used": 2648, 386 | "available": 1044840 387 | }, 388 | "old_space": { 389 | "memorySize": 339324928, 390 | "committedMemory": 339111216, 391 | "capacity": 338666488, 392 | "used": 335462856, 393 | "available": 3203632 394 | }, 395 | "code_space": { 396 | "memorySize": 1736704, 397 | "committedMemory": 1704608, 398 | "capacity": 1383232, 399 | "used": 1383232, 400 | "available": 0 401 | }, 402 | "map_space": { 403 | "memorySize": 2887680, 404 | "committedMemory": 2887264, 405 | "capacity": 2174560, 406 | "used": 2174560, 407 | "available": 0 408 | }, 409 | "large_object_space": { 410 | "memorySize": 1804529664, 411 | "committedMemory": 1804529664, 412 | "capacity": 1803152216, 413 | "used": 1803152216, 414 | "available": 0 415 | }, 416 | "code_large_object_space": { 417 | "memorySize": 622592, 418 | "committedMemory": 622592, 419 | "capacity": 550656, 420 | "used": 550656, 421 | "available": 0 422 | }, 423 | "new_large_object_space": { 424 | "memorySize": 0, 425 | "committedMemory": 0, 426 | "capacity": 1047488, 427 | "used": 0, 428 | "available": 1047488 429 | } 430 | } 431 | }, 432 | "resourceUsage": { 433 | "userCpuSeconds": 230.644, 434 | "kernelCpuSeconds": 28.7443, 435 | "cpuConsumptionPercent": 0.903888, 436 | "maxRss": 770162294784, 437 | "pageFaults": { 438 | "IORequired": 449, 439 | "IONotRequired": 7059795 440 | }, 441 | "fsActivity": { 442 | "reads": 0, 443 | "writes": 0 444 | } 445 | }, 446 | "libuv": [ 447 | ], 448 | "environmentVariables": { 449 | "npm_config_save_dev": "", 450 | "npm_config_legacy_bundling": "", 451 | "npm_config_dry_run": "", 452 | "npm_package_dependencies_webpack_dev_server": "^3.11.2", 453 | "npm_config_viewer": "man", 454 | "npm_config_only": "", 455 | "npm_config_commit_hooks": "true", 456 | "npm_config_browser": "", 457 | "npm_package_gitHead": "75697130608986b33a8906ad715b6b2dffe4be30", 458 | "npm_package_dependencies_webpack_cli": "^4.4.0", 459 | "npm_config_also": "", 460 | "npm_config_sign_git_commit": "", 461 | "npm_config_rollback": "true", 462 | "TERM_PROGRAM": "vscode", 463 | "NODE": "/usr/local/bin/node", 464 | "npm_config_usage": "", 465 | "npm_config_audit": "true", 466 | "INIT_CWD": "/Users/brunosimon/Projects/threejs-points-physical-material", 467 | "npm_config_globalignorefile": "/usr/local/etc/npmignore", 468 | "TERM": "xterm-256color", 469 | "SHELL": "/bin/zsh", 470 | "npm_config_shell": "/bin/zsh", 471 | "npm_config_maxsockets": "50", 472 | "npm_config_init_author_url": "", 473 | "npm_config_shrinkwrap": "true", 474 | "npm_config_parseable": "", 475 | "npm_config_metrics_registry": "https://registry.npmjs.org/", 476 | "TMPDIR": "/var/folders/07/y0vg59j518n7s23pkv2zlgd00000gn/T/", 477 | "npm_config_timing": "", 478 | "npm_config_init_license": "ISC", 479 | "npm_config_if_present": "", 480 | "TERM_PROGRAM_VERSION": "1.54.1", 481 | "npm_package_scripts_dev": "webpack serve --config ./bundler/webpack.dev.js", 482 | "npm_config_sign_git_tag": "", 483 | "npm_config_init_author_email": "", 484 | "npm_config_cache_max": "Infinity", 485 | "ORIGINAL_XDG_CURRENT_DESKTOP": "undefined", 486 | "npm_config_preid": "", 487 | "npm_config_long": "", 488 | "npm_config_local_address": "", 489 | "npm_config_git_tag_version": "true", 490 | "npm_config_cert": "", 491 | "npm_config_registry": "https://registry.npmjs.org/", 492 | "npm_config_noproxy": "", 493 | "npm_config_fetch_retries": "2", 494 | "npm_package_dependencies_style_loader": "^2.0.0", 495 | "npm_package_dependencies__babel_preset_env": "^7.12.11", 496 | "npm_package_dependencies_babel_loader": "^8.2.2", 497 | "npm_config_versions": "", 498 | "npm_config_message": "%s", 499 | "npm_config_key": "", 500 | "npm_package_readmeFilename": "readme.md", 501 | "npm_package_description": "## Setup Download [Node.js](https://nodejs.org/en/download/). Run this followed commands:", 502 | "USER": "brunosimon", 503 | "npm_package_dependencies_poly_decomp": "^0.3.0", 504 | "COMMAND_MODE": "unix2003", 505 | "npm_config_globalconfig": "/usr/local/etc/npmrc", 506 | "npm_package_dependencies_stats_js": "^0.17.0", 507 | "npm_package_dependencies_dat_gui": "^0.7.7", 508 | "npm_config_prefer_online": "", 509 | "npm_config_logs_max": "10", 510 | "npm_config_always_auth": "", 511 | "SSH_AUTH_SOCK": "/private/tmp/com.apple.launchd.Qp4T9pmIMO/Listeners", 512 | "npm_package_dependencies_webpack_merge": "^5.7.3", 513 | "npm_package_dependencies_file_loader": "^6.2.0", 514 | "__CF_USER_TEXT_ENCODING": "0x1F5:0x0:0x1", 515 | "npm_execpath": "/usr/local/lib/node_modules/npm/bin/npm-cli.js", 516 | "npm_config_global_style": "", 517 | "npm_config_cache_lock_retries": "10", 518 | "npm_package_dependencies_mini_css_extract_plugin": "^1.3.5", 519 | "npm_config_update_notifier": "true", 520 | "npm_config_cafile": "", 521 | "npm_package_dependencies_raw_loader": "^4.0.2", 522 | "npm_config_heading": "npm", 523 | "npm_config_audit_level": "low", 524 | "npm_config_searchlimit": "20", 525 | "npm_config_read_only": "", 526 | "npm_config_offline": "", 527 | "npm_config_fetch_retry_mintimeout": "10000", 528 | "npm_package_dependencies_css_loader": "^5.0.1", 529 | "npm_config_json": "", 530 | "npm_config_access": "", 531 | "npm_config_argv": "{\"remain\":[],\"cooked\":[\"run\",\"dev\"],\"original\":[\"run\",\"dev\"]}", 532 | "npm_package_dependencies_guify": "^0.12.0", 533 | "PATH": "/usr/local/lib/node_modules/npm/node_modules/npm-lifecycle/node-gyp-bin:/Users/brunosimon/Projects/threejs-points-physical-material/node_modules/.bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin", 534 | "npm_config_allow_same_version": "", 535 | "npm_package_dependencies_webpack": "^5.18.0", 536 | "npm_package_dependencies__babel_core": "^7.12.10", 537 | "npm_config_https_proxy": "", 538 | "npm_config_engine_strict": "", 539 | "npm_config_description": "true", 540 | "_": "/Users/brunosimon/Projects/threejs-points-physical-material/node_modules/.bin/webpack", 541 | "LaunchInstanceID": "3DF7D1E1-138D-4F93-81B8-B83DF7DD41D7", 542 | "npm_config_userconfig": "/Users/brunosimon/.npmrc", 543 | "npm_config_init_module": "/Users/brunosimon/.npm-init.js", 544 | "npm_package_dependencies_matter_js": "^0.16.1", 545 | "__CFBundleIdentifier": "com.microsoft.VSCode", 546 | "npm_config_cidr": "", 547 | "PWD": "/Users/brunosimon/Projects/threejs-points-physical-material", 548 | "npm_config_user": "", 549 | "npm_config_node_version": "12.14.1", 550 | "npm_lifecycle_event": "dev", 551 | "npm_config_save": "true", 552 | "npm_config_ignore_prepublish": "", 553 | "npm_config_editor": "vi", 554 | "npm_config_auth_type": "legacy", 555 | "npm_package_name": "", 556 | "npm_package_dependencies_alea": "^1.0.0", 557 | "LANG": "fr_FR.UTF-8", 558 | "npm_config_tag": "latest", 559 | "npm_config_script_shell": "", 560 | "npm_config_progress": "true", 561 | "npm_config_global": "", 562 | "npm_config_before": "", 563 | "npm_package_dependencies_clean_webpack_plugin": "^3.0.0", 564 | "npm_package_scripts_build": "webpack --config ./bundler/webpack.prod.js", 565 | "npm_config_searchstaleness": "900", 566 | "npm_config_optional": "true", 567 | "npm_config_ham_it_up": "", 568 | "XPC_FLAGS": "0x0", 569 | "npm_config_save_prod": "", 570 | "npm_config_force": "", 571 | "npm_config_bin_links": "true", 572 | "npm_config_searchopts": "", 573 | "npm_config_node_gyp": "/usr/local/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js", 574 | "npm_config_depth": "Infinity", 575 | "npm_config_sso_poll_frequency": "500", 576 | "npm_config_rebuild_bundle": "true", 577 | "npm_package_version": "", 578 | "XPC_SERVICE_NAME": "0", 579 | "npm_config_unicode": "true", 580 | "SHLVL": "2", 581 | "HOME": "/Users/brunosimon", 582 | "npm_config_fetch_retry_maxtimeout": "60000", 583 | "VSCODE_GIT_ASKPASS_MAIN": "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass-main.js", 584 | "npm_config_tag_version_prefix": "v", 585 | "npm_config_strict_ssl": "true", 586 | "npm_config_sso_type": "oauth", 587 | "npm_config_scripts_prepend_node_path": "warn-only", 588 | "npm_config_save_prefix": "^", 589 | "npm_config_loglevel": "notice", 590 | "npm_config_ca": "", 591 | "npm_package_dependencies_three": "^0.125.1", 592 | "npm_config_save_exact": "", 593 | "npm_config_group": "20", 594 | "npm_config_fetch_retry_factor": "10", 595 | "npm_config_dev": "", 596 | "npm_package_dependencies_gsap": "^3.6.0", 597 | "npm_package_dependencies_copy_webpack_plugin": "^7.0.0", 598 | "npm_config_version": "", 599 | "npm_config_prefer_offline": "", 600 | "npm_config_cache_lock_stale": "60000", 601 | "npm_config_otp": "", 602 | "npm_config_cache_min": "10", 603 | "npm_config_searchexclude": "", 604 | "npm_config_cache": "/Users/brunosimon/.npm", 605 | "LOGNAME": "brunosimon", 606 | "npm_lifecycle_script": "webpack serve --config ./bundler/webpack.dev.js", 607 | "npm_config_color": "true", 608 | "npm_package_dependencies_html_webpack_plugin": "^5.0.0-alpha.7", 609 | "npm_config_proxy": "", 610 | "npm_config_package_lock": "true", 611 | "npm_package_dependencies_ola": "^1.1.1", 612 | "VSCODE_GIT_IPC_HANDLE": "/var/folders/07/y0vg59j518n7s23pkv2zlgd00000gn/T/vscode-git-ff4ec54cf7.sock", 613 | "npm_config_package_lock_only": "", 614 | "npm_config_fund": "true", 615 | "npm_package_dependencies_portfinder_sync": "0.0.2", 616 | "npm_config_save_optional": "", 617 | "npm_config_ignore_scripts": "", 618 | "npm_config_user_agent": "npm/6.13.4 node/v12.14.1 darwin x64", 619 | "npm_config_cache_lock_wait": "10000", 620 | "VSCODE_GIT_ASKPASS_NODE": "/Applications/Visual Studio Code.app/Contents/Frameworks/Code Helper (Renderer).app/Contents/MacOS/Code Helper (Renderer)", 621 | "GIT_ASKPASS": "/Applications/Visual Studio Code.app/Contents/Resources/app/extensions/git/dist/askpass.sh", 622 | "npm_config_production": "", 623 | "npm_config_send_metrics": "", 624 | "npm_config_save_bundle": "", 625 | "npm_config_umask": "0022", 626 | "npm_config_node_options": "", 627 | "npm_config_init_version": "1.0.0", 628 | "npm_package_dependencies_html_loader": "^1.3.2", 629 | "npm_config_init_author_name": "", 630 | "npm_config_git": "git", 631 | "npm_config_scope": "", 632 | "SECURITYSESSIONID": "186aa", 633 | "npm_config_unsafe_perm": "true", 634 | "npm_config_tmp": "/var/folders/07/y0vg59j518n7s23pkv2zlgd00000gn/T", 635 | "npm_config_onload_script": "", 636 | "npm_node_execpath": "/usr/local/bin/node", 637 | "npm_config_prefix": "/usr/local", 638 | "npm_config_link": "", 639 | "npm_config_format_package_lock": "true", 640 | "COLORTERM": "truecolor", 641 | "WEBPACK_DEV_SERVER": "true" 642 | }, 643 | "userLimits": { 644 | "core_file_size_blocks": { 645 | "soft": 0, 646 | "hard": "unlimited" 647 | }, 648 | "data_seg_size_kbytes": { 649 | "soft": "unlimited", 650 | "hard": "unlimited" 651 | }, 652 | "file_size_blocks": { 653 | "soft": "unlimited", 654 | "hard": "unlimited" 655 | }, 656 | "max_locked_memory_bytes": { 657 | "soft": "unlimited", 658 | "hard": "unlimited" 659 | }, 660 | "max_memory_size_kbytes": { 661 | "soft": "unlimited", 662 | "hard": "unlimited" 663 | }, 664 | "open_files": { 665 | "soft": 1048575, 666 | "hard": "unlimited" 667 | }, 668 | "stack_size_bytes": { 669 | "soft": 8388608, 670 | "hard": 67104768 671 | }, 672 | "cpu_time_seconds": { 673 | "soft": "unlimited", 674 | "hard": "unlimited" 675 | }, 676 | "max_user_processes": { 677 | "soft": 2784, 678 | "hard": 4176 679 | }, 680 | "virtual_memory_kbytes": { 681 | "soft": "unlimited", 682 | "hard": "unlimited" 683 | } 684 | }, 685 | "sharedObjects": [ 686 | "/usr/local/bin/node", 687 | "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation", 688 | "/usr/lib/libSystem.B.dylib", 689 | "/usr/lib/libc++.1.dylib", 690 | "/usr/lib/libobjc.A.dylib", 691 | "/usr/lib/liboah.dylib", 692 | "/usr/lib/libfakelink.dylib", 693 | "/usr/lib/libicucore.A.dylib", 694 | "/System/Library/PrivateFrameworks/SoftLinking.framework/Versions/A/SoftLinking", 695 | "/usr/lib/libc++abi.dylib", 696 | "/usr/lib/system/libcache.dylib", 697 | "/usr/lib/system/libcommonCrypto.dylib", 698 | "/usr/lib/system/libcompiler_rt.dylib", 699 | "/usr/lib/system/libcopyfile.dylib", 700 | "/usr/lib/system/libcorecrypto.dylib", 701 | "/usr/lib/system/libdispatch.dylib", 702 | "/usr/lib/system/libdyld.dylib", 703 | "/usr/lib/system/libkeymgr.dylib", 704 | "/usr/lib/system/liblaunch.dylib", 705 | "/usr/lib/system/libmacho.dylib", 706 | "/usr/lib/system/libquarantine.dylib", 707 | "/usr/lib/system/libremovefile.dylib", 708 | "/usr/lib/system/libsystem_asl.dylib", 709 | "/usr/lib/system/libsystem_blocks.dylib", 710 | "/usr/lib/system/libsystem_c.dylib", 711 | "/usr/lib/system/libsystem_collections.dylib", 712 | "/usr/lib/system/libsystem_configuration.dylib", 713 | "/usr/lib/system/libsystem_containermanager.dylib", 714 | "/usr/lib/system/libsystem_coreservices.dylib", 715 | "/usr/lib/system/libsystem_darwin.dylib", 716 | "/usr/lib/system/libsystem_dnssd.dylib", 717 | "/usr/lib/system/libsystem_featureflags.dylib", 718 | "/usr/lib/system/libsystem_info.dylib", 719 | "/usr/lib/system/libsystem_m.dylib", 720 | "/usr/lib/system/libsystem_malloc.dylib", 721 | "/usr/lib/system/libsystem_networkextension.dylib", 722 | "/usr/lib/system/libsystem_notify.dylib", 723 | "/usr/lib/system/libsystem_product_info_filter.dylib", 724 | "/usr/lib/system/libsystem_sandbox.dylib", 725 | "/usr/lib/system/libsystem_secinit.dylib", 726 | "/usr/lib/system/libsystem_kernel.dylib", 727 | "/usr/lib/system/libsystem_platform.dylib", 728 | "/usr/lib/system/libsystem_pthread.dylib", 729 | "/usr/lib/system/libsystem_symptoms.dylib", 730 | "/usr/lib/system/libsystem_trace.dylib", 731 | "/usr/lib/system/libunwind.dylib", 732 | "/usr/lib/system/libxpc.dylib", 733 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/ApplicationServices", 734 | "/System/Library/Frameworks/CoreGraphics.framework/Versions/A/CoreGraphics", 735 | "/System/Library/Frameworks/CoreText.framework/Versions/A/CoreText", 736 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/ImageIO", 737 | "/System/Library/Frameworks/ColorSync.framework/Versions/A/ColorSync", 738 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/ATS", 739 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ColorSyncLegacy.framework/Versions/A/ColorSyncLegacy", 740 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/CoreServices", 741 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/HIServices.framework/Versions/A/HIServices", 742 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/LangAnalysis.framework/Versions/A/LangAnalysis", 743 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/PrintCore.framework/Versions/A/PrintCore", 744 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/QD.framework/Versions/A/QD", 745 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/SpeechSynthesis.framework/Versions/A/SpeechSynthesis", 746 | "/System/Library/PrivateFrameworks/SkyLight.framework/Versions/A/SkyLight", 747 | "/System/Library/PrivateFrameworks/FontServices.framework/libFontParser.dylib", 748 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Accelerate", 749 | "/System/Library/Frameworks/IOSurface.framework/Versions/A/IOSurface", 750 | "/usr/lib/libxml2.2.dylib", 751 | "/System/Library/Frameworks/CFNetwork.framework/Versions/A/CFNetwork", 752 | "/usr/lib/libz.1.dylib", 753 | "/System/Library/Frameworks/Foundation.framework/Versions/C/Foundation", 754 | "/System/Library/PrivateFrameworks/RunningBoardServices.framework/Versions/A/RunningBoardServices", 755 | "/usr/lib/libMobileGestalt.dylib", 756 | "/System/Library/PrivateFrameworks/WatchdogClient.framework/Versions/A/WatchdogClient", 757 | "/usr/lib/libcompression.dylib", 758 | "/usr/lib/libDiagnosticMessagesClient.dylib", 759 | "/System/Library/Frameworks/SystemConfiguration.framework/Versions/A/SystemConfiguration", 760 | "/System/Library/Frameworks/CoreDisplay.framework/Versions/A/CoreDisplay", 761 | "/System/Library/Frameworks/CoreMedia.framework/Versions/A/CoreMedia", 762 | "/System/Library/PrivateFrameworks/IOAccelerator.framework/Versions/A/IOAccelerator", 763 | "/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit", 764 | "/System/Library/Frameworks/Metal.framework/Versions/A/Metal", 765 | "/System/Library/Frameworks/CoreVideo.framework/Versions/A/CoreVideo", 766 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/MetalPerformanceShaders", 767 | "/System/Library/PrivateFrameworks/MultitouchSupport.framework/Versions/A/MultitouchSupport", 768 | "/System/Library/Frameworks/Security.framework/Versions/A/Security", 769 | "/System/Library/Frameworks/QuartzCore.framework/Versions/A/QuartzCore", 770 | "/usr/lib/libbsm.0.dylib", 771 | "/System/Library/PrivateFrameworks/CoreAnalytics.framework/Versions/A/CoreAnalytics", 772 | "/System/Library/Frameworks/VideoToolbox.framework/Versions/A/VideoToolbox", 773 | "/System/Library/PrivateFrameworks/BaseBoard.framework/Versions/A/BaseBoard", 774 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/FSEvents.framework/Versions/A/FSEvents", 775 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/Versions/A/CarbonCore", 776 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/Metadata.framework/Versions/A/Metadata", 777 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/OSServices.framework/Versions/A/OSServices", 778 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SearchKit.framework/Versions/A/SearchKit", 779 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/AE.framework/Versions/A/AE", 780 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/LaunchServices", 781 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/DictionaryServices.framework/Versions/A/DictionaryServices", 782 | "/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/SharedFileList.framework/Versions/A/SharedFileList", 783 | "/usr/lib/libapple_nghttp2.dylib", 784 | "/usr/lib/libnetwork.dylib", 785 | "/usr/lib/libsqlite3.dylib", 786 | "/usr/lib/libenergytrace.dylib", 787 | "/usr/lib/system/libkxld.dylib", 788 | "/System/Library/PrivateFrameworks/AppleFSCompression.framework/Versions/A/AppleFSCompression", 789 | "/usr/lib/libcoretls.dylib", 790 | "/usr/lib/libcoretls_cfhelpers.dylib", 791 | "/usr/lib/libpam.2.dylib", 792 | "/usr/lib/libxar.1.dylib", 793 | "/System/Library/PrivateFrameworks/CoreAutoLayout.framework/Versions/A/CoreAutoLayout", 794 | "/System/Library/Frameworks/DiskArbitration.framework/Versions/A/DiskArbitration", 795 | "/usr/lib/libarchive.2.dylib", 796 | "/usr/lib/liblangid.dylib", 797 | "/usr/lib/libCRFSuite.dylib", 798 | "/usr/lib/libpcap.A.dylib", 799 | "/usr/lib/libdns_services.dylib", 800 | "/usr/lib/liblzma.5.dylib", 801 | "/usr/lib/libbz2.1.0.dylib", 802 | "/usr/lib/libiconv.2.dylib", 803 | "/usr/lib/libcharset.1.dylib", 804 | "/System/Library/PrivateFrameworks/AppleSystemInfo.framework/Versions/A/AppleSystemInfo", 805 | "/System/Library/PrivateFrameworks/IOMobileFramebuffer.framework/Versions/A/IOMobileFramebuffer", 806 | "/usr/lib/libCheckFix.dylib", 807 | "/System/Library/PrivateFrameworks/TCC.framework/Versions/A/TCC", 808 | "/System/Library/PrivateFrameworks/CoreNLP.framework/Versions/A/CoreNLP", 809 | "/System/Library/PrivateFrameworks/MetadataUtilities.framework/Versions/A/MetadataUtilities", 810 | "/usr/lib/libmecabra.dylib", 811 | "/System/Library/Frameworks/MLCompute.framework/Versions/A/MLCompute", 812 | "/usr/lib/libmecab.dylib", 813 | "/usr/lib/libgermantok.dylib", 814 | "/usr/lib/libThaiTokenizer.dylib", 815 | "/usr/lib/libChineseTokenizer.dylib", 816 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vImage.framework/Versions/A/vImage", 817 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/vecLib", 818 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvMisc.dylib", 819 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libvDSP.dylib", 820 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib", 821 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib", 822 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLinearAlgebra.dylib", 823 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparseBLAS.dylib", 824 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libQuadrature.dylib", 825 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBNNS.dylib", 826 | "/System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libSparse.dylib", 827 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSCore.framework/Versions/A/MPSCore", 828 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSImage.framework/Versions/A/MPSImage", 829 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNeuralNetwork.framework/Versions/A/MPSNeuralNetwork", 830 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSMatrix.framework/Versions/A/MPSMatrix", 831 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSRayIntersector.framework/Versions/A/MPSRayIntersector", 832 | "/System/Library/Frameworks/MetalPerformanceShaders.framework/Versions/A/Frameworks/MPSNDArray.framework/Versions/A/MPSNDArray", 833 | "/System/Library/PrivateFrameworks/MetalTools.framework/Versions/A/MetalTools", 834 | "/System/Library/PrivateFrameworks/AggregateDictionary.framework/Versions/A/AggregateDictionary", 835 | "/System/Library/PrivateFrameworks/AppleSauce.framework/Versions/A/AppleSauce", 836 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreFSCache.dylib", 837 | "/System/Library/PrivateFrameworks/LanguageModeling.framework/Versions/A/LanguageModeling", 838 | "/System/Library/PrivateFrameworks/CoreEmoji.framework/Versions/A/CoreEmoji", 839 | "/System/Library/PrivateFrameworks/LinguisticData.framework/Versions/A/LinguisticData", 840 | "/System/Library/PrivateFrameworks/Lexicon.framework/Versions/A/Lexicon", 841 | "/usr/lib/libcmph.dylib", 842 | "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/Frameworks/CFOpenDirectory.framework/Versions/A/CFOpenDirectory", 843 | "/System/Library/Frameworks/OpenDirectory.framework/Versions/A/OpenDirectory", 844 | "/System/Library/PrivateFrameworks/APFS.framework/Versions/A/APFS", 845 | "/System/Library/Frameworks/SecurityFoundation.framework/Versions/A/SecurityFoundation", 846 | "/usr/lib/libutil.dylib", 847 | "/usr/lib/libapp_launch_measurement.dylib", 848 | "/System/Library/PrivateFrameworks/CoreServicesStore.framework/Versions/A/CoreServicesStore", 849 | "/System/Library/Frameworks/ServiceManagement.framework/Versions/A/ServiceManagement", 850 | "/usr/lib/libxslt.1.dylib", 851 | "/System/Library/PrivateFrameworks/BackgroundTaskManagement.framework/Versions/A/BackgroundTaskManagement", 852 | "/System/Library/PrivateFrameworks/PersistentConnection.framework/Versions/A/PersistentConnection", 853 | "/System/Library/PrivateFrameworks/ProtocolBuffer.framework/Versions/A/ProtocolBuffer", 854 | "/System/Library/PrivateFrameworks/CommonUtilities.framework/Versions/A/CommonUtilities", 855 | "/System/Library/PrivateFrameworks/Bom.framework/Versions/A/Bom", 856 | "/usr/lib/libate.dylib", 857 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libRadiance.dylib", 858 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJPEG.dylib", 859 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libPng.dylib", 860 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libTIFF.dylib", 861 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libGIF.dylib", 862 | "/System/Library/Frameworks/ImageIO.framework/Versions/A/Resources/libJP2.dylib", 863 | "/usr/lib/libexpat.1.dylib", 864 | "/System/Library/PrivateFrameworks/AppleJPEG.framework/Versions/A/AppleJPEG", 865 | "/System/Library/PrivateFrameworks/GPUWrangler.framework/Versions/A/GPUWrangler", 866 | "/System/Library/PrivateFrameworks/IOPresentment.framework/Versions/A/IOPresentment", 867 | "/System/Library/PrivateFrameworks/DSExternalDisplay.framework/Versions/A/DSExternalDisplay", 868 | "/System/Library/PrivateFrameworks/CMCaptureCore.framework/Versions/A/CMCaptureCore", 869 | "/usr/lib/libspindump.dylib", 870 | "/System/Library/Frameworks/CoreAudio.framework/Versions/A/CoreAudio", 871 | "/System/Library/PrivateFrameworks/AppServerSupport.framework/Versions/A/AppServerSupport", 872 | "/System/Library/PrivateFrameworks/perfdata.framework/Versions/A/perfdata", 873 | "/System/Library/PrivateFrameworks/AssertionServices.framework/Versions/A/AssertionServices", 874 | "/System/Library/PrivateFrameworks/AudioToolboxCore.framework/Versions/A/AudioToolboxCore", 875 | "/System/Library/PrivateFrameworks/caulk.framework/Versions/A/caulk", 876 | "/System/Library/PrivateFrameworks/SystemPolicy.framework/Versions/A/SystemPolicy", 877 | "/usr/lib/libIOReport.dylib", 878 | "/usr/lib/libSMC.dylib", 879 | "/usr/lib/libAudioToolboxUtility.dylib", 880 | "/usr/lib/libmis.dylib", 881 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/OpenGL", 882 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib", 883 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGFXShared.dylib", 884 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib", 885 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLImage.dylib", 886 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCVMSPluginSupport.dylib", 887 | "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libCoreVMClient.dylib", 888 | "/System/Library/Frameworks/CoreImage.framework/Versions/A/CoreImage", 889 | "/System/Library/Frameworks/OpenCL.framework/Versions/A/OpenCL", 890 | "/System/Library/PrivateFrameworks/GraphVisualizer.framework/Versions/A/GraphVisualizer", 891 | "/System/Library/PrivateFrameworks/FaceCore.framework/Versions/A/FaceCore", 892 | "/System/Library/PrivateFrameworks/OTSVG.framework/Versions/A/OTSVG", 893 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATS.framework/Versions/A/Resources/libFontRegistry.dylib", 894 | "/System/Library/PrivateFrameworks/FontServices.framework/libhvf.dylib", 895 | "/System/Library/PrivateFrameworks/AppleVA.framework/Versions/A/AppleVA", 896 | "/System/Library/Frameworks/ApplicationServices.framework/Versions/A/Frameworks/ATSUI.framework/Versions/A/ATSUI", 897 | "/usr/lib/libcups.2.dylib", 898 | "/System/Library/PrivateFrameworks/NetAuth.framework/Versions/A/NetAuth", 899 | "/System/Library/Frameworks/Kerberos.framework/Versions/A/Kerberos", 900 | "/System/Library/Frameworks/GSS.framework/Versions/A/GSS", 901 | "/usr/lib/libresolv.9.dylib", 902 | "/System/Library/PrivateFrameworks/Heimdal.framework/Versions/A/Heimdal", 903 | "/System/Library/Frameworks/Kerberos.framework/Versions/A/Libraries/libHeimdalProxy.dylib", 904 | "/System/Library/Frameworks/Network.framework/Versions/A/Network", 905 | "/usr/lib/libheimdal-asn1.dylib", 906 | "/System/Library/PrivateFrameworks/CommonAuth.framework/Versions/A/CommonAuth", 907 | "/System/Library/PrivateFrameworks/login.framework/Versions/A/Frameworks/loginsupport.framework/Versions/A/loginsupport", 908 | "/System/Library/Frameworks/AudioToolbox.framework/Versions/A/AudioToolbox", 909 | "/System/Library/PrivateFrameworks/AudioSession.framework/Versions/A/AudioSession", 910 | "/usr/lib/libAudioStatistics.dylib", 911 | "/System/Library/PrivateFrameworks/MediaExperience.framework/Versions/A/MediaExperience", 912 | "/System/Library/PrivateFrameworks/AudioSession.framework/libSessionUtility.dylib", 913 | "/usr/lib/libperfcheck.dylib", 914 | "/System/Library/PrivateFrameworks/AudioResourceArbitration.framework/Versions/A/AudioResourceArbitration", 915 | "/System/Library/Frameworks/CoreData.framework/Versions/A/CoreData", 916 | "/Users/brunosimon/Projects/threejs-points-physical-material/node_modules/fsevents/build/Release/fse.node" 917 | ] 918 | } -------------------------------------------------------------------------------- /resources/brushes.psb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/resources/brushes.psb -------------------------------------------------------------------------------- /resources/world.blend: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/resources/world.blend -------------------------------------------------------------------------------- /resources/world.blend1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/resources/world.blend1 -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Three.js - PointsPhysicalMaterial 7 | 8 | 9 |
10 | 11 |
12 | 13 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './style/main.css' 2 | import Application from './javascript/Application.js' 3 | 4 | const application = new Application({ 5 | targetElement: document.querySelector('.experience') 6 | }) 7 | 8 | -------------------------------------------------------------------------------- /src/javascript/Application.js: -------------------------------------------------------------------------------- 1 | import Guify from 'guify' 2 | import * as THREE from 'three' 3 | 4 | import EventEmitter from './Utils/EventEmitter.js' 5 | import Time from './Utils/Time.js' 6 | import Sizes from './Utils/Sizes.js' 7 | import Stats from './Utils/Stats.js' 8 | 9 | import Camera from './Camera/index.js' 10 | import Renderer from './Renderer.js' 11 | import Physics from './Physics.js' 12 | import Controls from './Controls.js' 13 | import World from './World.js' 14 | import Fullscreen from './Fullscreen.js' 15 | import Resources from './Resources.js' 16 | import assets from './assets.js' 17 | 18 | export default class Application 19 | { 20 | /** 21 | * Constructor 22 | */ 23 | constructor(_options = {}) 24 | { 25 | window.application = this 26 | 27 | this.targetElement = _options.targetElement 28 | 29 | if(!this.targetElement) 30 | { 31 | console.warn('Missing \'targetElement\' property') 32 | return 33 | } 34 | 35 | this.time = new Time() 36 | this.sizes = new Sizes() 37 | 38 | this.setConfig() 39 | this.setDebug() 40 | this.setStats() 41 | this.setResources() 42 | this.setScene() 43 | this.setCamera() 44 | this.setRenderer() 45 | this.setPhysics() 46 | this.setFullscreen() 47 | this.setControls() 48 | 49 | this.time.on('tick', () => 50 | { 51 | this.update() 52 | }) 53 | } 54 | 55 | /** 56 | * Set config 57 | */ 58 | setConfig() 59 | { 60 | this.config = {} 61 | 62 | // Debug 63 | this.config.debug = window.location.hash === '#debug' 64 | 65 | // Pixel ratio 66 | this.config.pixelRatio = Math.min(Math.max(window.devicePixelRatio, 1), 1.5) 67 | 68 | // Width and height 69 | const boundings = this.targetElement.getBoundingClientRect() 70 | this.config.width = boundings.width 71 | this.config.height = boundings.height 72 | this.config.heightRatio = this.config.height / this.sizes.viewport.height 73 | 74 | this.sizes.on('resize', () => 75 | { 76 | const boundings = this.targetElement.getBoundingClientRect() 77 | this.config.width = boundings.width 78 | this.config.height = boundings.height 79 | this.config.heightRatio = this.config.height / this.sizes.viewport.height 80 | }) 81 | 82 | // Touch 83 | this.config.touch = false 84 | 85 | window.addEventListener('touchstart', () => 86 | { 87 | this.config.touch = true 88 | }, { once: true }) 89 | } 90 | 91 | /** 92 | * Set debug 93 | */ 94 | setDebug() 95 | { 96 | if(this.config.debug) 97 | { 98 | this.debug = new Guify({ 99 | title: 'Brush Particles', 100 | theme: 'dark', // dark, light, yorha, or theme object 101 | align: 'right', // left, right 102 | width: 500, 103 | barMode: 'none', // none, overlay, above, offset 104 | panelMode: 'inner', 105 | opacity: 1, 106 | open: true 107 | }) 108 | } 109 | } 110 | 111 | /** 112 | * Set stats 113 | */ 114 | setStats() 115 | { 116 | this.stats = new Stats(true) 117 | } 118 | 119 | /** 120 | * Set resources 121 | */ 122 | setResources() 123 | { 124 | this.resources = new Resources(assets) 125 | 126 | this.resources.on('progress', (_group, _resource, _data) => 127 | { 128 | }) 129 | 130 | this.resources.on('groupEnd', (_group) => 131 | { 132 | }) 133 | 134 | this.resources.on('end', (_group) => 135 | { 136 | this.setWorld() 137 | }) 138 | } 139 | 140 | /** 141 | * Set scene 142 | */ 143 | setScene() 144 | { 145 | this.scene = new THREE.Scene() 146 | } 147 | 148 | /** 149 | * Set camera 150 | */ 151 | setCamera() 152 | { 153 | this.camera = new Camera({ 154 | interactionTarget: this.targetElement 155 | }) 156 | 157 | this.scene.add(this.camera.instance) 158 | } 159 | 160 | /** 161 | * Set renderer 162 | */ 163 | setRenderer() 164 | { 165 | this.renderer = new Renderer() 166 | 167 | this.targetElement.appendChild(this.renderer.instance.domElement) 168 | } 169 | 170 | /** 171 | * Set physics 172 | */ 173 | setPhysics() 174 | { 175 | this.physics = new Physics() 176 | } 177 | 178 | /** 179 | * Set fullscreen 180 | */ 181 | setFullscreen() 182 | { 183 | this.fullscreen = new Fullscreen() 184 | } 185 | 186 | /** 187 | * Set controls 188 | */ 189 | setControls() 190 | { 191 | this.controls = new Controls({ 192 | interactionTarget: this.targetElement 193 | }) 194 | } 195 | 196 | /** 197 | * Set levels 198 | */ 199 | setWorld() 200 | { 201 | this.world = new World() 202 | } 203 | 204 | /** 205 | * Update 206 | */ 207 | update() 208 | { 209 | this.stats.update() 210 | this.camera.update() 211 | this.physics.update() 212 | this.controls.update() 213 | if(this.world) 214 | { 215 | this.world.update() 216 | } 217 | this.renderer.update() 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/javascript/BrushParticles.js: -------------------------------------------------------------------------------- 1 | export default class BrushParticles 2 | { 3 | constructor() 4 | { 5 | console.log('ok') 6 | } 7 | 8 | update() 9 | { 10 | } 11 | } -------------------------------------------------------------------------------- /src/javascript/Camera/DebugCamera.js: -------------------------------------------------------------------------------- 1 | import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' 2 | 3 | export default class DebugCamera 4 | { 5 | constructor(_options) 6 | { 7 | this.time = _options.time 8 | this.baseInstance = _options.baseInstance 9 | this.interactionTarget = _options.interactionTarget 10 | 11 | this.active = false 12 | this.instance = this.baseInstance.clone() 13 | 14 | this.orbitControls = new OrbitControls(this.instance, this.interactionTarget) 15 | this.orbitControls.enabled = this.active 16 | this.orbitControls.screenSpacePanning = true 17 | this.orbitControls.enableKeys = false 18 | this.orbitControls.zoomSpeed = 0.25 19 | this.orbitControls.enableDamping = true 20 | this.orbitControls.update() 21 | } 22 | 23 | update() 24 | { 25 | if(!this.active) 26 | { 27 | return 28 | } 29 | 30 | this.orbitControls.update() 31 | } 32 | 33 | activate() 34 | { 35 | this.active = true 36 | this.orbitControls.enabled = true 37 | } 38 | 39 | deactivate() 40 | { 41 | this.active = false 42 | this.orbitControls.enabled = false 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/javascript/Camera/DefaultCamera.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | 3 | export default class DefaultCamera 4 | { 5 | constructor(_options) 6 | { 7 | this.time = _options.time 8 | this.baseInstance = _options.baseInstance 9 | 10 | this.active = false 11 | 12 | this.instance = this.baseInstance.clone() 13 | this.instance.position.set(0, 1.68, 2) 14 | this.instance.lookAt(new THREE.Vector3(0, 1.55, 0)) 15 | this.instance.rotation.order = 'YXZ' 16 | } 17 | 18 | activate() 19 | { 20 | this.active = true 21 | } 22 | 23 | deactivate() 24 | { 25 | this.active = false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/javascript/Camera/index.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import DefaultCamera from './DefaultCamera.js' 3 | import DebugCamera from './DebugCamera.js' 4 | 5 | export default class Camera 6 | { 7 | constructor(_options) 8 | { 9 | // Options 10 | this.application = window.application 11 | this.config = this.application.config 12 | this.debug = this.application.debug 13 | this.time = this.application.time 14 | this.sizes = this.application.sizes 15 | this.interactionTarget = _options.interactionTarget 16 | 17 | // Set up 18 | this.mode = 'debugCamera' 19 | 20 | // if(!this.debug) 21 | // { 22 | // this.mode = 'debugCamera' 23 | // } 24 | 25 | // Debug 26 | if(this.debug) 27 | { 28 | this.debug.Register({ 29 | type: 'folder', 30 | label: 'camera', 31 | open: true 32 | }) 33 | 34 | this.debug.Register({ 35 | folder: 'camera', 36 | type: 'select', 37 | label: 'mode', 38 | object: this, 39 | property: 'mode', 40 | options: ['defaultCamera', 'debugCamera'], 41 | onChange: () => 42 | { 43 | if(this.mode === 'defaultCamera') 44 | { 45 | this.defaultCamera.activate() 46 | this.debugCamera.deactivate() 47 | } 48 | else 49 | { 50 | this.defaultCamera.deactivate() 51 | this.debugCamera.activate() 52 | } 53 | } 54 | }) 55 | 56 | this.debug.Register({ 57 | folder: 'camera', 58 | type: 'button', 59 | label: 'points', 60 | object: this, 61 | action: () => 62 | { 63 | this.instance.layers.enable(0) 64 | this.instance.layers.disable(1) 65 | } 66 | }) 67 | 68 | this.debug.Register({ 69 | folder: 'camera', 70 | type: 'button', 71 | label: 'meshes', 72 | object: this, 73 | action: () => 74 | { 75 | this.instance.layers.enable(1) 76 | this.instance.layers.disable(0) 77 | } 78 | }) 79 | } 80 | 81 | this.setInstance() 82 | this.setDefaultCamera() 83 | this.setDebugCamera() 84 | 85 | this[this.mode].activate() 86 | } 87 | 88 | setInstance() 89 | { 90 | // Set up 91 | this.instance = new THREE.PerspectiveCamera(55, this.config.width / this.config.height, 0.1, 150) 92 | 93 | this.instance.position.set(0, 0, 5) 94 | 95 | // Resize event 96 | this.sizes.on('resize', () => 97 | { 98 | this.instance.aspect = this.config.width / this.config.height 99 | this.instance.updateProjectionMatrix() 100 | }) 101 | } 102 | 103 | setDefaultCamera() 104 | { 105 | // Set up 106 | this.defaultCamera = new DefaultCamera({ 107 | time: this.time, 108 | baseInstance: this.instance, 109 | interactionTarget: this.interactionTarget 110 | }) 111 | } 112 | 113 | setDebugCamera() 114 | { 115 | this.debugCamera = new DebugCamera({ 116 | time: this.time, 117 | baseInstance: this.instance, 118 | interactionTarget: this.interactionTarget 119 | }) 120 | 121 | if(this.mode === 'debugCamera') 122 | { 123 | this.debugCamera.activate() 124 | } 125 | } 126 | 127 | update() 128 | { 129 | this.debugCamera.update() 130 | 131 | this.instance.position.copy(this[this.mode].instance.position) 132 | this.instance.quaternion.copy(this[this.mode].instance.quaternion) 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/javascript/Controls.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import Ola from 'ola' 3 | 4 | export default class Controls 5 | { 6 | constructor(_options) 7 | { 8 | this.application = window.application 9 | this.debug = this.application.debug 10 | this.time = this.application.time 11 | this.interactionTarget = _options.interactionTarget 12 | this.physics = this.application.physics 13 | this.camera = this.application.camera 14 | 15 | // Debug 16 | if(this.debug) 17 | { 18 | this.debug.Register({ 19 | type: 'folder', 20 | label: 'controls', 21 | open: false 22 | }) 23 | } 24 | 25 | this.setPlayer() 26 | this.setDrag() 27 | this.setKeyboard() 28 | this.setWriggle() 29 | } 30 | 31 | setPlayer() 32 | { 33 | this.player = {} 34 | 35 | this.player.rotation = {} 36 | this.player.rotation.target = new THREE.Vector2(0, Math.PI * 0.5) 37 | this.player.rotation.value = this.player.rotation.target.clone() 38 | this.player.rotation.easing = 0.003 39 | 40 | this.player.eyeSight = {} 41 | this.player.eyeSight.standing = 1.65 42 | this.player.eyeSight.crouching = 1 43 | this.player.eyeSight.value = Ola({ y: this.player.eyeSight.standing }, 300) 44 | } 45 | 46 | setDrag() 47 | { 48 | this.drag = {} 49 | this.drag.previous = new THREE.Vector2() 50 | this.drag.current = new THREE.Vector2() 51 | this.drag.delta = new THREE.Vector2() 52 | this.drag.sensitivity = 0.002 53 | 54 | this.interactionTarget.style.cursor = 'grab' 55 | 56 | this.drag.mouseDown = (_event) => 57 | { 58 | this.drag.current.x = _event.clientX 59 | this.drag.current.y = _event.clientY 60 | 61 | this.interactionTarget.style.cursor = 'grabbing' 62 | 63 | this.wriggle.strength.set({ value: 0 }, 1000) 64 | 65 | window.addEventListener('mouseup', this.drag.mouseUp) 66 | window.addEventListener('mousemove', this.drag.mouseMove) 67 | } 68 | 69 | this.drag.mouseUp = () => 70 | { 71 | this.interactionTarget.style.cursor = 'grab' 72 | 73 | this.wriggle.strength.set({ value: 1 }, 4000) 74 | 75 | window.removeEventListener('mouseup', this.drag.mouseUp) 76 | window.removeEventListener('mousemove', this.drag.mouseMove) 77 | } 78 | 79 | this.drag.mouseMove = (_event) => 80 | { 81 | this.drag.previous.copy(this.drag.current) 82 | this.drag.current.x = _event.clientX 83 | this.drag.current.y = _event.clientY 84 | 85 | this.drag.delta.x = this.drag.current.x - this.drag.previous.x 86 | this.drag.delta.y = this.drag.current.y - this.drag.previous.y 87 | 88 | // Update player 89 | this.player.rotation.target.y -= this.drag.delta.x * this.drag.sensitivity 90 | this.player.rotation.target.x -= this.drag.delta.y * this.drag.sensitivity 91 | 92 | this.player.rotation.target.x = Math.min(Math.max(this.player.rotation.target.x, - Math.PI * 0.5), Math.PI * 0.5) 93 | } 94 | 95 | this.interactionTarget.addEventListener('mousedown', this.drag.mouseDown) 96 | } 97 | 98 | setKeyboard() 99 | { 100 | this.keyboard = {} 101 | this.keyboard.up = false 102 | this.keyboard.right = false 103 | this.keyboard.down = false 104 | this.keyboard.left = false 105 | this.keyboard.running = false 106 | 107 | window.addEventListener('keydown', (_event) => 108 | { 109 | if(_event.code === 'KeyW' || _event.code === 'ArrowUp') 110 | { 111 | this.keyboard.up = true 112 | } 113 | else if(_event.code === 'KeyD' || _event.code === 'ArrowRight') 114 | { 115 | this.keyboard.right = true 116 | } 117 | else if(_event.code === 'KeyS' || _event.code === 'ArrowDown') 118 | { 119 | this.keyboard.down = true 120 | } 121 | else if(_event.code === 'KeyA' || _event.code === 'ArrowLeft') 122 | { 123 | this.keyboard.left = true 124 | } 125 | else if(_event.code === 'ShiftLeft' || _event.code === 'ShiftRight') 126 | { 127 | this.keyboard.running = true 128 | } 129 | else if(_event.code === 'ControlLeft' || _event.code === 'KeyC') 130 | { 131 | this.player.eyeSight.value.set({ y: this.player.eyeSight.crouching }) 132 | } 133 | }) 134 | 135 | window.addEventListener('keyup', (_event) => 136 | { 137 | if(_event.code === 'KeyW' || _event.code === 'ArrowUp') 138 | { 139 | this.keyboard.up = false 140 | } 141 | else if(_event.code === 'KeyD' || _event.code === 'ArrowRight') 142 | { 143 | this.keyboard.right = false 144 | } 145 | else if(_event.code === 'KeyS' || _event.code === 'ArrowDown') 146 | { 147 | this.keyboard.down = false 148 | } 149 | else if(_event.code === 'KeyA' || _event.code === 'ArrowLeft') 150 | { 151 | this.keyboard.left = false 152 | } 153 | else if(_event.code === 'ShiftLeft' || _event.code === 'ShiftRight') 154 | { 155 | this.keyboard.running = false 156 | } 157 | else if(_event.code === 'ControlLeft' || _event.code === 'KeyC') 158 | { 159 | this.player.eyeSight.value.set({ y: this.player.eyeSight.standing }) 160 | } 161 | }) 162 | } 163 | 164 | setWriggle() 165 | { 166 | this.wriggle = {} 167 | this.wriggle.amplitude = 0.4 168 | this.wriggle.strength = Ola({ value: 1 }, 2000) 169 | this.wriggle.xFrequency = 0.0006123 170 | this.wriggle.yFrequency = 0.0005 171 | this.wriggle.x = 0 172 | this.wriggle.y = 0 173 | 174 | if(this.debug) 175 | { 176 | this.debug.Register({ 177 | folder: 'controls', 178 | type: 'range', 179 | label: 'wriggleAmplitude', 180 | min: 0, 181 | max: 3, 182 | object: this.wriggle, 183 | property: 'amplitude' 184 | }) 185 | 186 | this.debug.Register({ 187 | folder: 'controls', 188 | type: 'range', 189 | label: 'wriggleXFrequency', 190 | min: 0, 191 | max: 0.01, 192 | step: 0.0001, 193 | object: this.wriggle, 194 | property: 'xFrequency' 195 | }) 196 | 197 | this.debug.Register({ 198 | folder: 'controls', 199 | type: 'range', 200 | label: 'wriggleYFrequency', 201 | min: 0, 202 | max: 0.01, 203 | step: 0.0001, 204 | object: this.wriggle, 205 | property: 'yFrequency' 206 | }) 207 | } 208 | } 209 | 210 | update() 211 | { 212 | // Wriggle 213 | this.wriggle.y = Math.sin(this.time.elapsed * this.wriggle.yFrequency * 1) 214 | this.wriggle.y *= Math.sin(this.time.elapsed * this.wriggle.yFrequency * 0.5) / 3 215 | this.wriggle.y *= Math.sin(this.time.elapsed * this.wriggle.yFrequency * 0.25) / 3 216 | this.wriggle.y *= this.wriggle.amplitude * this.wriggle.strength.value 217 | 218 | this.wriggle.x = Math.sin(this.time.elapsed * this.wriggle.xFrequency * 1) 219 | this.wriggle.x *= Math.sin(this.time.elapsed * this.wriggle.xFrequency * 0.5) / 3 220 | this.wriggle.x *= Math.sin(this.time.elapsed * this.wriggle.xFrequency * 0.25) / 3 221 | this.wriggle.x *= this.wriggle.amplitude * this.wriggle.strength.value 222 | 223 | // Update rotation 224 | this.player.rotation.value.lerp(this.player.rotation.target, this.player.rotation.easing * this.time.delta) 225 | 226 | // Update camera rotation 227 | this.camera.defaultCamera.instance.rotation.x = this.player.rotation.value.x + this.wriggle.x 228 | this.camera.defaultCamera.instance.rotation.y = this.player.rotation.value.y - Math.PI * 0.5 + this.wriggle.y 229 | 230 | // Update physics 231 | const baseAngle = this.player.rotation.value.y 232 | const direction = new THREE.Vector2() 233 | 234 | if(this.keyboard.right) 235 | { 236 | direction.x = 1 237 | } 238 | if(this.keyboard.left) 239 | { 240 | direction.x = - 1 241 | } 242 | if(this.keyboard.up) 243 | { 244 | direction.y = 1 245 | } 246 | if(this.keyboard.down) 247 | { 248 | direction.y = - 1 249 | } 250 | 251 | if(direction.length()) 252 | { 253 | this.physics.moveToAngle(baseAngle + direction.angle(), this.keyboard.running) 254 | } 255 | 256 | // Update camera position 257 | this.camera.defaultCamera.instance.position.x = this.physics.player.body.position.x / this.physics.scale 258 | this.camera.defaultCamera.instance.position.z = this.physics.player.body.position.y / this.physics.scale 259 | this.camera.defaultCamera.instance.position.y = this.player.eyeSight.value.y 260 | } 261 | } 262 | -------------------------------------------------------------------------------- /src/javascript/Fullscreen.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './Utils/EventEmitter' 2 | 3 | export default class Fullscreen extends EventEmitter 4 | { 5 | constructor(_options) 6 | { 7 | super() 8 | 9 | // Options 10 | this.application = window.application 11 | this.targetElement = this.application.targetElement 12 | 13 | // Set up 14 | this.fullscreenActive = false 15 | this.pointerLockActive = false 16 | 17 | // Mouse event 18 | this.targetElement.addEventListener('dblclick', () => 19 | { 20 | this.toggle() 21 | }) 22 | 23 | // Keyboard event 24 | window.addEventListener('keydown', (_event) => 25 | { 26 | if(_event.code === 'KeyF') 27 | { 28 | this.toggle() 29 | } 30 | }) 31 | 32 | // Fullscreen change 33 | document.addEventListener('fullscreenchange', () => 34 | { 35 | this.fullscreenActive = document.fullscreen 36 | 37 | // Wait a little and test if pointer lock worked 38 | window.setTimeout(() => 39 | { 40 | if(this.fullscreenActive && !this.pointerLockActive) 41 | { 42 | this.targetElement.requestPointerLock() 43 | } 44 | if(!this.fullscreenActive && this.pointerLockActive) 45 | { 46 | this.targetElement.exitPointerLock() 47 | } 48 | }, 500) 49 | }) 50 | 51 | // Pointer lock change 52 | document.addEventListener('pointerlockchange', () => 53 | { 54 | this.pointerLockActive = !!document.pointerLockElement 55 | }) 56 | } 57 | 58 | toggle() 59 | { 60 | if(this.fullscreenActive) 61 | { 62 | this.deactivate() 63 | } 64 | else 65 | { 66 | this.activate() 67 | } 68 | } 69 | 70 | activate() 71 | { 72 | this.fullscreenActive = true 73 | 74 | this.targetElement.requestFullscreen() 75 | this.targetElement.requestPointerLock() 76 | 77 | this.trigger('activate') 78 | } 79 | 80 | deactivate() 81 | { 82 | this.fullscreenActive = false 83 | 84 | document.exitFullscreen() 85 | document.exitPointerLock() 86 | 87 | this.trigger('deactivate') 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/javascript/Materials/PointsPhysicalMaterial.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import shaderFragment from '../shaders/pointsPhysical/fragment.glsl' 3 | import shaderVertex from '../shaders/pointsPhysical/vertex.glsl' 4 | 5 | /** 6 | * TODO: 7 | * - Handle bump map 8 | * - Handle emissive map 9 | * - Handle vertex color 10 | */ 11 | 12 | export default function(_parameters = {}) 13 | { 14 | // Base uniforms 15 | const uniforms = THREE.UniformsUtils.merge([ 16 | THREE.ShaderLib[ 'standard'].uniforms, 17 | { 18 | uSize: { value: null } 19 | } 20 | ]) 21 | 22 | // Extensions 23 | const extensions = { 24 | derivatives: true, 25 | fragDepth: false, 26 | drawBuffers: false, 27 | shaderTextureLOD: true 28 | } 29 | 30 | // Defines 31 | const defines = { 32 | PHYSICAL: '', 33 | // USE_COLOR: '' 34 | // USE_BUMPMAP: '', 35 | // USE_EMISSIVEMAP: '', 36 | } 37 | 38 | // Fill uniforms and defines depending on parameters 39 | if(_parameters.usePoints) 40 | { 41 | defines.USE_POINTS = '' 42 | } 43 | 44 | if(_parameters.size) 45 | { 46 | uniforms.uSize.value = _parameters.size 47 | } 48 | 49 | if(_parameters.map) 50 | { 51 | uniforms.map.value = _parameters.map 52 | defines.USE_MAP = '' 53 | defines.USE_UV = '' 54 | } 55 | 56 | if(_parameters.alphaMap) 57 | { 58 | uniforms.alphaMap.value = _parameters.alphaMap 59 | defines.USE_ALPHAMAP = '' 60 | defines.USE_UV = '' 61 | } 62 | 63 | if(_parameters.aoMap) 64 | { 65 | uniforms.aoMap.value = _parameters.aoMap 66 | defines.USE_AOMAP = '' 67 | defines.USE_UV = '' 68 | } 69 | 70 | if(_parameters.displacementMap) 71 | { 72 | uniforms.displacementMap.value = _parameters.displacementMap 73 | defines.USE_DISPLACEMENTMAP = '' 74 | defines.USE_UV = '' 75 | } 76 | 77 | if(_parameters.normalMap) 78 | { 79 | uniforms.normalMap.value = _parameters.normalMap 80 | defines.USE_NORMALMAP = '' 81 | defines.USE_UV = '' 82 | defines.TANGENTSPACE_NORMALMAP = '' 83 | // defines.OBJECTSPACE_NORMALMAP = '' // ??? 84 | } 85 | 86 | if(_parameters.metalnessMap) 87 | { 88 | uniforms.metalnessMap.value = _parameters.metalnessMap 89 | defines.USE_METALNESSMAP = '' 90 | defines.USE_UV = '' 91 | } 92 | 93 | if(_parameters.roughnessMap) 94 | { 95 | uniforms.roughnessMap.value = _parameters.roughnessMap 96 | defines.USE_ROUGHNESSMAP = '' 97 | defines.USE_UV = '' 98 | } 99 | 100 | if(_parameters.envMap) 101 | { 102 | uniforms.envMapIntensity.value = _parameters.envMapIntensity 103 | uniforms.envMap.value = _parameters.envMap 104 | uniforms.maxMipLevel.value = 11 // ??? 105 | defines.USE_ENVMAP = '' 106 | defines.ENVMAP_TYPE_CUBE = '' 107 | // defines.ENVMAP_TYPE_CUBE_UV = '' 108 | 109 | // defines.ENVMAP_MODE_REFLECTION = '' // ??? 110 | // defines.ENVMAP_MODE_REFRACTION = '' // ??? 111 | // defines.ENVMAP_BLENDING_MULTIPLY = '' // ??? 112 | // defines.ENVMAP_BLENDING_MIX = '' // ??? 113 | // defines.ENVMAP_BLENDING_ADD = '' // ??? 114 | } 115 | 116 | // defines.USE_SHADOWMAP = '' 117 | 118 | if(_parameters.fogColor) 119 | { 120 | uniforms.fogColor.value = _parameters.fogColor 121 | uniforms.fogNear.value = _parameters.fogNear 122 | uniforms.fogFar.value = _parameters.fogFar 123 | uniforms.fogDensity.value = _parameters.fogDensity 124 | 125 | defines.USE_FOG = '' 126 | 127 | if(_parameters.fogDensity) 128 | { 129 | defines.FOG_EXP2 = '' 130 | } 131 | } 132 | 133 | if(_parameters.color) 134 | { 135 | uniforms.diffuse.value = _parameters.color 136 | } 137 | 138 | uniforms.roughness.value = _parameters.roughness 139 | uniforms.metalness.value = _parameters.metalness 140 | 141 | // Custom uniforms 142 | uniforms.uBrushTexture = { value: _parameters.brushTexture } 143 | 144 | // Create material 145 | const material = new THREE.ShaderMaterial({ 146 | wireframe: false, 147 | transparent: true, 148 | depthTest: true, 149 | depthWrite: true, 150 | alphaTest: 0.1, 151 | uniforms, 152 | extensions, 153 | defines, 154 | lights: true, 155 | vertexShader: shaderVertex, 156 | fragmentShader: shaderFragment 157 | }) 158 | 159 | // Update properties (needed for prefixed shader code) 160 | if(_parameters.map) 161 | { 162 | material.map = _parameters.map 163 | } 164 | if(_parameters.envMap) 165 | { 166 | material.envMap = _parameters.envMap 167 | } 168 | 169 | return material 170 | } 171 | -------------------------------------------------------------------------------- /src/javascript/Passes/FinalPass.js: -------------------------------------------------------------------------------- 1 | import shaderFragment from '../shaders/final/fragment.glsl' 2 | import shaderVertex from '../shaders/final/vertex.glsl' 3 | 4 | export default { 5 | uniforms: 6 | { 7 | tDiffuse: { type: 't', value: null }, 8 | uTime: { type: 'f', value: null }, 9 | uNoiseMultiplier: { type: 'f', value: null }, 10 | uRGBOffsetMultiplier: { type: 'f', value: null }, 11 | uRGBOffsetOffset: { type: 'f', value: null }, 12 | uRGBOffsetPower: { type: 'f', value: null }, 13 | uOverlayColor: { type: 'v3', value: null }, 14 | uOverlayAlpha: { type: 'f', value: null } 15 | }, 16 | vertexShader: shaderVertex, 17 | fragmentShader: shaderFragment 18 | } 19 | -------------------------------------------------------------------------------- /src/javascript/Physics.js: -------------------------------------------------------------------------------- 1 | import { Engine, Render, World, Bodies, Body, Vector } from 'matter-js' 2 | 3 | export default class Physics 4 | { 5 | constructor(_options) 6 | { 7 | this.application = window.application 8 | this.debug = this.application.debug 9 | this.time = this.application.time 10 | 11 | // Debug 12 | if(this.debug) 13 | { 14 | this.debug.Register({ 15 | type: 'folder', 16 | label: 'physics', 17 | open: false 18 | }) 19 | } 20 | 21 | // Set up 22 | this.staticBodies = [] 23 | this.scale = 100 24 | this.renderDistance = 2000 25 | this.renderSize = 600 26 | this.visible = false 27 | 28 | this.setEnvironment() 29 | this.setPlayer() 30 | this.setRender() 31 | 32 | // Debug 33 | if(this.debug) 34 | { 35 | this.debug.Register({ 36 | folder: 'physics', 37 | type: 'checkbox', 38 | label: 'visible', 39 | object: this, 40 | property: 'visible', 41 | onChange: () => 42 | { 43 | if(this.visible) 44 | { 45 | this.render.element.appendChild(this.render.canvas) 46 | } 47 | else 48 | { 49 | this.render.element.removeChild(this.render.canvas) 50 | } 51 | } 52 | }) 53 | } 54 | } 55 | 56 | setForLevel(_level) 57 | { 58 | for(const _shapeSource of _level.collisionSource) 59 | { 60 | let body = null 61 | 62 | switch(_shapeSource.type) 63 | { 64 | case 'rectangle': 65 | body = Bodies.rectangle( 66 | _shapeSource.position.x * this.scale, 67 | - _shapeSource.position.y * this.scale, 68 | _shapeSource.size.x * this.scale, 69 | _shapeSource.size.y * this.scale 70 | ) 71 | 72 | // Rotate 73 | Body.rotate(body, - _shapeSource.rotation) 74 | 75 | break 76 | 77 | case 'circle': 78 | body = Bodies.circle( 79 | _shapeSource.position.x * this.scale, 80 | - _shapeSource.position.y * this.scale, 81 | _shapeSource.radius * this.scale 82 | ) 83 | break 84 | } 85 | 86 | if(body) 87 | { 88 | body.render.fillStyle = '#ff2c65' 89 | 90 | // Set as static 91 | Body.setStatic(body, true) 92 | 93 | // Add and save 94 | World.add(this.world, body) 95 | this.staticBodies.push(body) 96 | } 97 | else 98 | { 99 | console.warn(`Shape source of type "${_shapeSource.type}" doesn't exist`, _shapeSource) 100 | } 101 | } 102 | } 103 | 104 | setEnvironment() 105 | { 106 | // Engine 107 | this.engine = Engine.create() 108 | 109 | // World 110 | this.world = this.engine.world 111 | this.world.gravity.y = 0 112 | } 113 | 114 | setPlayer() 115 | { 116 | this.player = {} 117 | this.player.baseSpeed = 0.015 118 | this.player.runninSpeed = this.player.baseSpeed * 3 119 | this.player.body = Bodies.circle(0, 0, 0.5 * this.scale) 120 | this.player.body.mass = 25 121 | this.player.body.frictionAir = 0.1 122 | this.player.body.render.fillStyle = '#60efff' 123 | 124 | if(this.debug) 125 | { 126 | this.debug.Register({ 127 | folder: 'physics', 128 | type: 'range', 129 | min: 0, 130 | max: 100, 131 | step: 0.1, 132 | label: 'playerMass', 133 | object: this.player.body, 134 | property: 'mass' 135 | }) 136 | 137 | this.debug.Register({ 138 | folder: 'physics', 139 | type: 'range', 140 | min: 0, 141 | max: 0.2, 142 | step: 0.001, 143 | label: 'playerBaseSpeed', 144 | object: this.player, 145 | property: 'baseSpeed' 146 | }) 147 | 148 | this.debug.Register({ 149 | folder: 'physics', 150 | type: 'range', 151 | min: 0, 152 | max: 0.2, 153 | step: 0.001, 154 | label: 'playerRunninSpeed', 155 | object: this.player, 156 | property: 'runninSpeed' 157 | }) 158 | 159 | this.debug.Register({ 160 | folder: 'physics', 161 | type: 'range', 162 | min: 0, 163 | max: 1, 164 | step: 0.001, 165 | label: 'playerFrictionAir', 166 | object: this.player.body, 167 | property: 'frictionAir' 168 | }) 169 | } 170 | 171 | World.add(this.world, this.player.body) 172 | } 173 | 174 | setRender() 175 | { 176 | // Render 177 | this.render = Render.create({ 178 | element: document.body, 179 | engine: this.engine, 180 | options: 181 | { 182 | wireframes: false 183 | } 184 | }) 185 | 186 | if(!this.visible) 187 | { 188 | this.render.element.removeChild(this.render.canvas) 189 | } 190 | 191 | this.render.canvas.style.position = 'fixed' 192 | this.render.canvas.style.top = 0 193 | this.render.canvas.style.left = 0 194 | 195 | this.render.options.hasBounds = true 196 | this.render.options.width = this.renderSize 197 | this.render.options.height = this.renderSize 198 | this.render.bounds.min.x = - this.renderDistance 199 | this.render.bounds.max.x = this.renderDistance 200 | this.render.bounds.min.y = - this.renderDistance 201 | this.render.bounds.max.y = this.renderDistance 202 | 203 | this.render.canvas.width = this.renderSize 204 | this.render.canvas.height = this.renderSize 205 | } 206 | 207 | moveToAngle(_angle, _running) 208 | { 209 | const speed = _running ? this.player.runninSpeed : this.player.baseSpeed 210 | Body.applyForce(this.player.body, this.player.body.position, Vector.create(Math.sin(_angle) * speed, Math.cos(_angle) * speed)) 211 | } 212 | 213 | update() 214 | { 215 | Engine.update(this.engine, this.time.delta, 1) 216 | 217 | if(this.visible) 218 | { 219 | this.render.bounds.min.x = this.player.body.position.x - this.renderDistance 220 | this.render.bounds.max.x = this.player.body.position.x + this.renderDistance 221 | this.render.bounds.min.y = this.player.body.position.y - this.renderDistance 222 | this.render.bounds.max.y = this.player.body.position.y + this.renderDistance 223 | 224 | Render.world(this.render) 225 | } 226 | } 227 | } 228 | -------------------------------------------------------------------------------- /src/javascript/Renderer.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer.js' 3 | import { ShaderPass } from 'three/examples/jsm/postprocessing/ShaderPass.js' 4 | import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass.js' 5 | import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass.js' 6 | 7 | import FinalPass from './Passes/FinalPass.js' 8 | 9 | export default class Renderer 10 | { 11 | constructor(_options = {}) 12 | { 13 | this.application = window.application 14 | this.config = this.application.config 15 | this.debug = this.application.debug 16 | this.stats = this.application.stats 17 | this.time = this.application.time 18 | this.sizes = this.application.sizes 19 | this.scene = this.application.scene 20 | this.camera = this.application.camera 21 | 22 | this.step = 0 23 | 24 | window.setTimeout(() => 25 | { 26 | this.step = 1 27 | }, 5000) 28 | 29 | // Debug 30 | if(this.debug) 31 | { 32 | this.debug.Register({ 33 | type: 'folder', 34 | label: 'renderer', 35 | open: false 36 | }) 37 | } 38 | 39 | this.setInstance() 40 | this.setPostProcess() 41 | } 42 | 43 | setInstance() 44 | { 45 | this.clearColor = '#0f0914' 46 | 47 | // Renderer 48 | this.instance = new THREE.WebGLRenderer({ 49 | alpha: true, 50 | antialias: true 51 | }) 52 | this.instance.domElement.style.position = 'absolute' 53 | this.instance.domElement.style.top = 0 54 | this.instance.domElement.style.left = 0 55 | this.instance.domElement.style.width = '100%' 56 | this.instance.domElement.style.height = '100%' 57 | 58 | // this.instance.setClearColor(0x414141, 1) 59 | this.instance.setClearColor(this.clearColor, 1) 60 | this.instance.setPixelRatio(this.config.pixelRatio) 61 | 62 | this.instance.setSize(this.config.width, this.config.height) 63 | 64 | this.instance.physicallyCorrectLights = true 65 | this.instance.gammaOutPut = true 66 | this.instance.outputEncoding = THREE.sRGBEncoding 67 | // this.instance.autoClear = false 68 | 69 | this.instance.shadowMap.enabled = true 70 | 71 | // Add stats panel 72 | this.stats.setRenderPanel(this.instance.getContext()) 73 | 74 | // Resize event 75 | this.sizes.on('resize', () => 76 | { 77 | this.instance.setSize(this.config.width, this.config.height) 78 | }) 79 | 80 | // Debug 81 | if(this.debug) 82 | { 83 | this.debug.Register({ 84 | type: 'color', 85 | folder: 'renderer', 86 | label: 'clearColor', 87 | object: this, 88 | property: 'clearColor', 89 | format: 'hex', 90 | onChange: () => 91 | { 92 | this.instance.setClearColor(this.clearColor, 1) 93 | } 94 | }) 95 | } 96 | 97 | } 98 | 99 | setPostProcess() 100 | { 101 | this.postProcess = {} 102 | 103 | /** 104 | * Render pass 105 | */ 106 | this.postProcess.renderPass = new RenderPass(this.scene, this.camera.instance) 107 | 108 | /** 109 | * Bloom pass 110 | */ 111 | this.postProcess.bloomPass = new UnrealBloomPass(new THREE.Vector2(this.config.width, this.config.height), 1.5, 0.4, 0.85) 112 | this.postProcess.bloomPass.threshold = 0 113 | this.postProcess.bloomPass.strength = 1 114 | this.postProcess.bloomPass.radius = 0 115 | 116 | if(this.debug) 117 | { 118 | this.debug.Register({ 119 | folder: 'renderer', 120 | type: 'range', 121 | label: 'unrealBloomThreshold', 122 | min: 0, 123 | max: 1, 124 | object: this.postProcess.bloomPass, 125 | property: 'threshold' 126 | }) 127 | this.debug.Register({ 128 | folder: 'renderer', 129 | type: 'range', 130 | label: 'unrealBloomStrength', 131 | min: 0, 132 | max: 3, 133 | object: this.postProcess.bloomPass, 134 | property: 'strength' 135 | }) 136 | this.debug.Register({ 137 | folder: 'renderer', 138 | type: 'range', 139 | label: 'unrealBloomRadius', 140 | min: 0, 141 | max: 1, 142 | object: this.postProcess.bloomPass, 143 | property: 'radius' 144 | }) 145 | } 146 | 147 | /** 148 | * Final pass 149 | */ 150 | this.postProcess.finalPass = new ShaderPass(FinalPass) 151 | this.postProcess.finalPass.animated = true 152 | this.postProcess.finalPass.material.uniforms.uTime.value = 0 153 | this.postProcess.finalPass.material.uniforms.uNoiseMultiplier.value = 0.05 154 | this.postProcess.finalPass.material.uniforms.uRGBOffsetMultiplier.value = 0.3 155 | this.postProcess.finalPass.material.uniforms.uRGBOffsetOffset.value = 0.1 156 | this.postProcess.finalPass.material.uniforms.uRGBOffsetPower.value = 2 157 | this.postProcess.finalPass.material.uniforms.uOverlayColor.value = new THREE.Color('#000d08') 158 | this.postProcess.finalPass.material.uniforms.uOverlayAlpha.value = 1 159 | 160 | if(this.debug) 161 | { 162 | this.debug.Register({ 163 | folder: 'renderer', 164 | type: 'range', 165 | label: 'noiseMultiplier', 166 | min: 0, 167 | max: 1, 168 | object: this.postProcess.finalPass.material.uniforms.uNoiseMultiplier, 169 | property: 'value' 170 | }) 171 | this.debug.Register({ 172 | folder: 'renderer', 173 | type: 'checkbox', 174 | label: 'noiseAnimated', 175 | object: this.postProcess.finalPass, 176 | property: 'animated' 177 | }) 178 | // this.debug.Register({ 179 | // folder: 'renderer', 180 | // type: 'range', 181 | // label: 'RGBOffsetMultiplier', 182 | // min: 0, 183 | // max: 1, 184 | // object: this.postProcess.finalPass.material.uniforms.uRGBOffsetMultiplier, 185 | // property: 'value' 186 | // }) 187 | // this.debug.Register({ 188 | // folder: 'renderer', 189 | // type: 'range', 190 | // label: 'RGBOffsetOffset', 191 | // min: 0, 192 | // max: 1, 193 | // object: this.postProcess.finalPass.material.uniforms.uRGBOffsetOffset, 194 | // property: 'value' 195 | // }) 196 | // this.debug.Register({ 197 | // folder: 'renderer', 198 | // type: 'range', 199 | // label: 'RGBOffsetPower', 200 | // min: 0, 201 | // max: 5, 202 | // object: this.postProcess.finalPass.material.uniforms.uRGBOffsetPower, 203 | // property: 'value' 204 | // }) 205 | } 206 | 207 | /** 208 | * Effect composer 209 | */ 210 | this.postProcess.composer = new EffectComposer(this.instance) 211 | 212 | this.postProcess.composer.addPass(this.postProcess.renderPass) 213 | this.postProcess.composer.addPass(this.postProcess.bloomPass) 214 | // this.postProcess.composer.addPass(this.postProcess.finalPass) 215 | 216 | /** 217 | * Resize event 218 | */ 219 | this.sizes.on('resize', () => 220 | { 221 | this.instance.setSize(this.config.width, this.config.height) 222 | this.postProcess.composer.setSize(this.config.width, this.config.height) 223 | }) 224 | } 225 | 226 | update() 227 | { 228 | // Update passes 229 | if(this.postProcess.finalPass.animated) 230 | { 231 | this.postProcess.finalPass.material.uniforms.uTime.value = this.time.elapsed 232 | } 233 | 234 | // Do the render 235 | this.stats.beforeRender() 236 | this.instance.render(this.scene, this.camera.instance) 237 | this.stats.afterRender() 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /src/javascript/Resources.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import EventEmitter from './Utils/EventEmitter.js' 3 | import Loader from './Utils/Loader.js' 4 | 5 | export default class Resources extends EventEmitter 6 | { 7 | constructor(_assets) 8 | { 9 | super() 10 | 11 | // Items (will contain every resources) 12 | this.items = {} 13 | 14 | // Loader 15 | this.loader = new Loader({ renderer: this.renderer }) 16 | 17 | this.groups = {} 18 | this.groups.assets = _assets 19 | this.groups.loaded = [] 20 | this.groups.current = null 21 | this.loadNextGroup() 22 | 23 | // Loader file end event 24 | this.loader.on('fileEnd', (_resource, _data) => 25 | { 26 | let data = _data 27 | 28 | // Convert to texture 29 | if(_resource.type === 'texture') 30 | { 31 | data = new THREE.Texture(_data) 32 | data.encoding = THREE.sRGBEncoding 33 | data.needsUpdate = true 34 | } 35 | 36 | this.items[_resource.name] = data 37 | 38 | // Progress and event 39 | this.groups.current.loaded++ 40 | this.trigger('progress', [this.groups.current, _resource, data]) 41 | }) 42 | 43 | // Loader all end event 44 | this.loader.on('end', () => 45 | { 46 | this.groups.loaded.push(this.groups.current) 47 | 48 | // Trigger 49 | this.trigger('groupEnd', [this.groups.current]) 50 | 51 | if(this.groups.assets.length > 0) 52 | { 53 | this.loadNextGroup() 54 | } 55 | else 56 | { 57 | this.trigger('end') 58 | } 59 | }) 60 | } 61 | 62 | loadNextGroup() 63 | { 64 | this.groups.current = this.groups.assets.shift() 65 | this.groups.current.toLoad = this.groups.current.items.length 66 | this.groups.current.loaded = 0 67 | 68 | this.loader.load(this.groups.current.items) 69 | } 70 | 71 | createInstancedMeshes(_children, _groups) 72 | { 73 | // Groups 74 | const groups = [] 75 | 76 | for(const _group of _groups) 77 | { 78 | groups.push({ 79 | name: _group.name, 80 | regex: _group.regex, 81 | meshesGroups: [], 82 | instancedMeshes: [] 83 | }) 84 | } 85 | 86 | // Result 87 | const result = {} 88 | 89 | for(const _group of groups) 90 | { 91 | result[_group.name] = _group.instancedMeshes 92 | } 93 | 94 | return result 95 | } 96 | 97 | destroy() 98 | { 99 | for(const _itemKey in this.items) 100 | { 101 | const item = this.items[_itemKey] 102 | if(item instanceof THREE.Texture) 103 | { 104 | item.dispose() 105 | } 106 | } 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/javascript/Utils/EventEmitter.js: -------------------------------------------------------------------------------- 1 | export default class 2 | { 3 | /** 4 | * Constructor 5 | */ 6 | constructor() 7 | { 8 | this.callbacks = {} 9 | this.callbacks.base = {} 10 | } 11 | 12 | /** 13 | * On 14 | */ 15 | on(_names, callback) 16 | { 17 | const that = this 18 | 19 | // Errors 20 | if(typeof _names === 'undefined' || _names === '') 21 | { 22 | console.warn('wrong names') 23 | return false 24 | } 25 | 26 | if(typeof callback === 'undefined') 27 | { 28 | console.warn('wrong callback') 29 | return false 30 | } 31 | 32 | // Resolve names 33 | const names = this.resolveNames(_names) 34 | 35 | // Each name 36 | names.forEach(function(_name) 37 | { 38 | // Resolve name 39 | const name = that.resolveName(_name) 40 | 41 | // Create namespace if not exist 42 | if(!(that.callbacks[ name.namespace ] instanceof Object)) 43 | that.callbacks[ name.namespace ] = {} 44 | 45 | // Create callback if not exist 46 | if(!(that.callbacks[ name.namespace ][ name.value ] instanceof Array)) 47 | that.callbacks[ name.namespace ][ name.value ] = [] 48 | 49 | // Add callback 50 | that.callbacks[ name.namespace ][ name.value ].push(callback) 51 | }) 52 | 53 | return this 54 | } 55 | 56 | /** 57 | * Off 58 | */ 59 | off(_names) 60 | { 61 | const that = this 62 | 63 | // Errors 64 | if(typeof _names === 'undefined' || _names === '') 65 | { 66 | console.warn('wrong name') 67 | return false 68 | } 69 | 70 | // Resolve names 71 | const names = this.resolveNames(_names) 72 | 73 | // Each name 74 | names.forEach(function(_name) 75 | { 76 | // Resolve name 77 | const name = that.resolveName(_name) 78 | 79 | // Remove namespace 80 | if(name.namespace !== 'base' && name.value === '') 81 | { 82 | delete that.callbacks[ name.namespace ] 83 | } 84 | 85 | // Remove specific callback in namespace 86 | else 87 | { 88 | // Default 89 | if(name.namespace === 'base') 90 | { 91 | // Try to remove from each namespace 92 | for(const namespace in that.callbacks) 93 | { 94 | if(that.callbacks[ namespace ] instanceof Object && that.callbacks[ namespace ][ name.value ] instanceof Array) 95 | { 96 | delete that.callbacks[ namespace ][ name.value ] 97 | 98 | // Remove namespace if empty 99 | if(Object.keys(that.callbacks[ namespace ]).length === 0) 100 | delete that.callbacks[ namespace ] 101 | } 102 | } 103 | } 104 | 105 | // Specified namespace 106 | else if(that.callbacks[ name.namespace ] instanceof Object && that.callbacks[ name.namespace ][ name.value ] instanceof Array) 107 | { 108 | delete that.callbacks[ name.namespace ][ name.value ] 109 | 110 | // Remove namespace if empty 111 | if(Object.keys(that.callbacks[ name.namespace ]).length === 0) 112 | delete that.callbacks[ name.namespace ] 113 | } 114 | } 115 | }) 116 | 117 | return this 118 | } 119 | 120 | /** 121 | * Trigger 122 | */ 123 | trigger(_name, _args) 124 | { 125 | // Errors 126 | if(typeof _name === 'undefined' || _name === '') 127 | { 128 | console.warn('wrong name') 129 | return false 130 | } 131 | 132 | const that = this 133 | let finalResult = null 134 | let result = null 135 | 136 | // Default args 137 | const args = !(_args instanceof Array) ? [] : _args 138 | 139 | // Resolve names (should on have one event) 140 | let name = this.resolveNames(_name) 141 | 142 | // Resolve name 143 | name = this.resolveName(name[ 0 ]) 144 | 145 | // Default namespace 146 | if(name.namespace === 'base') 147 | { 148 | // Try to find callback in each namespace 149 | for(const namespace in that.callbacks) 150 | { 151 | if(that.callbacks[ namespace ] instanceof Object && that.callbacks[ namespace ][ name.value ] instanceof Array) 152 | { 153 | that.callbacks[ namespace ][ name.value ].forEach(function(callback) 154 | { 155 | result = callback.apply(that, args) 156 | 157 | if(typeof finalResult === 'undefined') 158 | { 159 | finalResult = result 160 | } 161 | }) 162 | } 163 | } 164 | } 165 | 166 | // Specified namespace 167 | else if(this.callbacks[ name.namespace ] instanceof Object) 168 | { 169 | if(name.value === '') 170 | { 171 | console.warn('wrong name') 172 | return this 173 | } 174 | 175 | that.callbacks[ name.namespace ][ name.value ].forEach(function(callback) 176 | { 177 | result = callback.apply(that, args) 178 | 179 | if(typeof finalResult === 'undefined') 180 | finalResult = result 181 | }) 182 | } 183 | 184 | return finalResult 185 | } 186 | 187 | /** 188 | * Resolve names 189 | */ 190 | resolveNames(_names) 191 | { 192 | let names = _names 193 | names = names.replace(/[^a-zA-Z0-9 ,/.]/g, '') 194 | names = names.replace(/[,/]+/g, ' ') 195 | names = names.split(' ') 196 | 197 | return names 198 | } 199 | 200 | /** 201 | * Resolve name 202 | */ 203 | resolveName(name) 204 | { 205 | const newName = {} 206 | const parts = name.split('.') 207 | 208 | newName.original = name 209 | newName.value = parts[ 0 ] 210 | newName.namespace = 'base' // Base namespace 211 | 212 | // Specified namespace 213 | if(parts.length > 1 && parts[ 1 ] !== '') 214 | { 215 | newName.namespace = parts[ 1 ] 216 | } 217 | 218 | return newName 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /src/javascript/Utils/Loader.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './EventEmitter.js' 2 | import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js' 3 | import { FBXLoader } from 'three/examples/jsm/loaders/FBXLoader.js' 4 | import { DRACOLoader } from 'three/examples/jsm/loaders/DRACOLoader.js' 5 | 6 | export default class Resources extends EventEmitter 7 | { 8 | /** 9 | * Constructor 10 | */ 11 | constructor() 12 | { 13 | super() 14 | 15 | this.setLoaders() 16 | 17 | this.toLoad = 0 18 | this.loaded = 0 19 | this.items = {} 20 | } 21 | 22 | /** 23 | * Set loaders 24 | */ 25 | setLoaders() 26 | { 27 | this.loaders = [] 28 | 29 | // Images 30 | this.loaders.push({ 31 | extensions: ['jpg', 'png'], 32 | action: (_resource) => 33 | { 34 | const image = new Image() 35 | 36 | image.addEventListener('load', () => 37 | { 38 | this.fileLoadEnd(_resource, image) 39 | }) 40 | 41 | image.addEventListener('error', () => 42 | { 43 | this.fileLoadEnd(_resource, image) 44 | }) 45 | 46 | image.src = _resource.source 47 | } 48 | }) 49 | 50 | // Draco 51 | const dracoLoader = new DRACOLoader() 52 | dracoLoader.setDecoderPath('draco/') 53 | dracoLoader.setDecoderConfig({ type: 'js' }) 54 | 55 | this.loaders.push({ 56 | extensions: ['drc'], 57 | action: (_resource) => 58 | { 59 | dracoLoader.load(_resource.source, (_data) => 60 | { 61 | this.fileLoadEnd(_resource, _data) 62 | 63 | DRACOLoader.releaseDecoderModule() 64 | }) 65 | } 66 | }) 67 | 68 | // GLTF 69 | const gltfLoader = new GLTFLoader() 70 | gltfLoader.setDRACOLoader(dracoLoader) 71 | 72 | this.loaders.push({ 73 | extensions: ['glb', 'gltf'], 74 | action: (_resource) => 75 | { 76 | gltfLoader.load(_resource.source, (_data) => 77 | { 78 | this.fileLoadEnd(_resource, _data) 79 | }) 80 | } 81 | }) 82 | 83 | // FBX 84 | const fbxLoader = new FBXLoader() 85 | 86 | this.loaders.push({ 87 | extensions: ['fbx'], 88 | action: (_resource) => 89 | { 90 | fbxLoader.load(_resource.source, (_data) => 91 | { 92 | this.fileLoadEnd(_resource, _data) 93 | }) 94 | } 95 | }) 96 | } 97 | 98 | /** 99 | * Load 100 | */ 101 | load(_resources = []) 102 | { 103 | for(const _resource of _resources) 104 | { 105 | this.toLoad++ 106 | const extensionMatch = _resource.source.match(/\.([a-z]+)$/) 107 | 108 | if(typeof extensionMatch[1] !== 'undefined') 109 | { 110 | const extension = extensionMatch[1] 111 | const loader = this.loaders.find((_loader) => _loader.extensions.find((_extension) => _extension === extension)) 112 | 113 | if(loader) 114 | { 115 | loader.action(_resource) 116 | } 117 | else 118 | { 119 | console.warn(`Cannot found loader for ${_resource}`) 120 | } 121 | } 122 | else 123 | { 124 | console.warn(`Cannot found extension of ${_resource}`) 125 | } 126 | } 127 | } 128 | 129 | /** 130 | * File load end 131 | */ 132 | fileLoadEnd(_resource, _data) 133 | { 134 | this.loaded++ 135 | this.items[_resource.name] = _data 136 | 137 | this.trigger('fileEnd', [_resource, _data]) 138 | 139 | if(this.loaded === this.toLoad) 140 | { 141 | this.trigger('end') 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /src/javascript/Utils/Sizes.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './EventEmitter.js' 2 | 3 | export default class Sizes extends EventEmitter 4 | { 5 | /** 6 | * Constructor 7 | */ 8 | constructor() 9 | { 10 | super() 11 | 12 | // Viewport size 13 | this.viewport = {} 14 | this.$sizeViewport = document.createElement('div') 15 | this.$sizeViewport.style.width = '100vw' 16 | this.$sizeViewport.style.height = '100vh' 17 | this.$sizeViewport.style.position = 'absolute' 18 | this.$sizeViewport.style.top = 0 19 | this.$sizeViewport.style.left = 0 20 | this.$sizeViewport.style.pointerEvents = 'none' 21 | 22 | // Resize event 23 | this.resize = this.resize.bind(this) 24 | window.addEventListener('resize', this.resize) 25 | 26 | this.resize() 27 | } 28 | 29 | /** 30 | * Resize 31 | */ 32 | resize() 33 | { 34 | document.body.appendChild(this.$sizeViewport) 35 | this.viewport.width = this.$sizeViewport.offsetWidth 36 | this.viewport.height = this.$sizeViewport.offsetHeight 37 | document.body.removeChild(this.$sizeViewport) 38 | 39 | this.width = window.innerWidth 40 | this.height = window.innerHeight 41 | 42 | this.trigger('resize') 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/javascript/Utils/Stats.js: -------------------------------------------------------------------------------- 1 | import StatsJs from 'stats.js' 2 | 3 | export default class Stats 4 | { 5 | constructor(_active) 6 | { 7 | this.instance = new StatsJs() 8 | this.instance.showPanel(3) 9 | 10 | this.active = false 11 | 12 | if(_active) 13 | { 14 | this.activate() 15 | } 16 | } 17 | 18 | activate() 19 | { 20 | this.active = true 21 | 22 | document.body.appendChild(this.instance.dom) 23 | } 24 | 25 | deactivate() 26 | { 27 | this.active = false 28 | 29 | document.body.removeChild(this.instance.dom) 30 | } 31 | 32 | setRenderPanel(_context) 33 | { 34 | this.render = {} 35 | this.render.context = _context 36 | this.render.extension = this.render.context.getExtension('EXT_disjoint_timer_query_webgl2') 37 | this.render.panel = this.instance.addPanel(new StatsJs.Panel('Render (ms)', '#f8f', '#212')) 38 | this.render.maxValue = 40 39 | } 40 | 41 | beforeRender() 42 | { 43 | // Setup 44 | this.queryCreated = false 45 | let queryResultAvailable = false 46 | 47 | // Test if query result available 48 | if(this.render.query) 49 | { 50 | queryResultAvailable = this.render.context.getQueryParameter(this.render.query, this.render.context.QUERY_RESULT_AVAILABLE) 51 | 52 | if(queryResultAvailable) 53 | { 54 | const elapsedNanos = this.render.context.getQueryParameter(this.render.query, this.render.context.QUERY_RESULT) 55 | const panelValue = Math.min(elapsedNanos / 1000 / 1000, this.render.maxValue) 56 | 57 | this.render.panel.update(panelValue, this.render.maxValue) 58 | } 59 | } 60 | 61 | // If query result available or no query yet 62 | if(queryResultAvailable || !this.render.query) 63 | { 64 | // Create new query 65 | this.queryCreated = true 66 | this.render.query = this.render.context.createQuery() 67 | this.render.context.beginQuery(this.render.extension.TIME_ELAPSED_EXT, this.render.query) 68 | } 69 | 70 | } 71 | 72 | afterRender() 73 | { 74 | // End the query (result will be available "later") 75 | if(this.queryCreated) 76 | { 77 | this.render.context.endQuery(this.render.extension.TIME_ELAPSED_EXT) 78 | } 79 | } 80 | 81 | update() 82 | { 83 | if(!this.active) 84 | { 85 | return 86 | } 87 | 88 | this.instance.update() 89 | } 90 | } -------------------------------------------------------------------------------- /src/javascript/Utils/Time.js: -------------------------------------------------------------------------------- 1 | import EventEmitter from './EventEmitter.js' 2 | 3 | export default class Time extends EventEmitter 4 | { 5 | /** 6 | * Constructor 7 | */ 8 | constructor() 9 | { 10 | super() 11 | 12 | this.start = Date.now() 13 | this.current = this.start 14 | this.elapsed = 0 15 | this.delta = 16 16 | 17 | this.tick = this.tick.bind(this) 18 | this.tick() 19 | } 20 | 21 | /** 22 | * Tick 23 | */ 24 | tick() 25 | { 26 | this.ticker = window.requestAnimationFrame(this.tick) 27 | 28 | const current = Date.now() 29 | 30 | this.delta = current - this.current 31 | this.elapsed = current - this.start 32 | this.current = current 33 | 34 | if(this.delta > 60) 35 | { 36 | this.delta = 60 37 | } 38 | 39 | this.trigger('tick') 40 | } 41 | 42 | /** 43 | * Stop 44 | */ 45 | stop() 46 | { 47 | window.cancelAnimationFrame(this.ticker) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/javascript/World.js: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three' 2 | import { BufferGeometryUtils } from 'three/examples/jsm/utils/BufferGeometryUtils.js' 3 | import PointsPhysicalMaterial from './Materials/PointsPhysicalMaterial.js' 4 | 5 | export default class World 6 | { 7 | constructor(_options) 8 | { 9 | this.application = window.application 10 | this.scene = this.application.scene 11 | this.debug = this.application.debug 12 | this.time = this.application.time 13 | this.resources = this.application.resources 14 | 15 | // Debug 16 | if(this.debug) 17 | { 18 | this.debug.Register({ 19 | type: 'folder', 20 | label: 'world', 21 | open: true 22 | }) 23 | } 24 | 25 | // const mesh = new THREE.Mesh( 26 | // new THREE.SphereGeometry(1, 32, 32), 27 | // new THREE.MeshStandardMaterial() 28 | // ) 29 | // this.scene.add(mesh) 30 | 31 | this.setEnvironmentMap() 32 | this.setLights() 33 | /** 34 | * Brush texture 35 | */ 36 | const textureLoader = new THREE.TextureLoader() 37 | this.brushTexture = textureLoader.load('/textures/brushes/brush3.png') 38 | 39 | this.setModel() 40 | } 41 | 42 | setEnvironmentMap() 43 | { 44 | const cubeTextureLoader = new THREE.CubeTextureLoader() 45 | 46 | this.environmentMap = cubeTextureLoader.load([ 47 | '/textures/environmentMaps/0/px.jpg', 48 | '/textures/environmentMaps/0/nx.jpg', 49 | '/textures/environmentMaps/0/py.jpg', 50 | '/textures/environmentMaps/0/ny.jpg', 51 | '/textures/environmentMaps/0/pz.jpg', 52 | '/textures/environmentMaps/0/nz.jpg' 53 | ]) 54 | 55 | this.environmentMap.encoding = THREE.sRGBEncoding 56 | } 57 | 58 | setLights() 59 | { 60 | this.lights = {} 61 | 62 | /** 63 | * Debug 64 | */ 65 | if(this.debug) 66 | { 67 | this.debug.Register({ 68 | type: 'folder', 69 | folder: 'world', 70 | label: 'lights', 71 | open: true 72 | }) 73 | } 74 | 75 | /** 76 | * Ambient light 77 | */ 78 | this.lights.ambientLight = {} 79 | this.lights.ambientLight.color = '#ff0000' 80 | this.lights.ambientLight.instance = new THREE.AmbientLight(this.lights.ambientLight.color, 0.2) 81 | this.lights.ambientLight.instance.layers.enableAll() 82 | this.scene.add(this.lights.ambientLight.instance) 83 | 84 | // Debug 85 | if(this.debug) 86 | { 87 | this.debug.Register({ 88 | folder: 'lights', 89 | type: 'range', 90 | label: 'ambientLightIntensity', 91 | min: 0, 92 | max: 1, 93 | object: this.lights.ambientLight.instance, 94 | property: 'intensity' 95 | }) 96 | 97 | this.debug.Register({ 98 | type: 'color', 99 | folder: 'lights', 100 | label: 'ambientLightColor', 101 | object: this.lights.ambientLight, 102 | property: 'color', 103 | format: 'hex', 104 | onChange: () => 105 | { 106 | this.lights.ambientLight.instance.color.set(this.lights.ambientLight.color) 107 | } 108 | }) 109 | } 110 | 111 | /** 112 | * Directional light 113 | */ 114 | this.lights.directionalLight = {} 115 | this.lights.directionalLight.color = '#ffffff' 116 | this.lights.directionalLight.instance = new THREE.DirectionalLight(this.lights.directionalLight.color, 5) 117 | this.lights.directionalLight.instance.position.x = 3 118 | this.lights.directionalLight.instance.position.y = 3 119 | this.lights.directionalLight.instance.position.z = 3 120 | this.lights.directionalLight.instance.castShadow = true 121 | this.lights.directionalLight.instance.shadow.mapSize.width = 512 122 | this.lights.directionalLight.instance.shadow.mapSize.height = 512 123 | this.lights.directionalLight.instance.shadow.camera.near = 0.5 124 | this.lights.directionalLight.instance.shadow.camera.far = 500 125 | this.lights.directionalLight.instance.shadow.bias = - 0.0001 126 | this.lights.directionalLight.instance.shadow.normalBias = - 0.0001 127 | this.lights.directionalLight.instance.layers.enableAll() 128 | this.scene.add(this.lights.directionalLight.instance) 129 | 130 | // // Helper 131 | // this.lights.directionalLightHelper = new THREE.CameraHelper(this.lights.directionalLight.instance.shadow.camera) 132 | // this.scene.add(this.lights.directionalLightHelper) 133 | 134 | // Debug 135 | if(this.debug) 136 | { 137 | this.debug.Register({ 138 | folder: 'lights', 139 | type: 'range', 140 | label: 'directionalLightIntensity', 141 | min: 0, 142 | max: 12, 143 | object: this.lights.directionalLight.instance, 144 | property: 'intensity' 145 | }) 146 | 147 | this.debug.Register({ 148 | type: 'color', 149 | folder: 'lights', 150 | label: 'directionalLightColor', 151 | object: this.lights.directionalLight, 152 | property: 'color', 153 | format: 'hex', 154 | onChange: () => 155 | { 156 | this.lights.directionalLight.instance.color.set(this.lights.directionalLight.color) 157 | } 158 | }) 159 | } 160 | } 161 | 162 | setModel() 163 | { 164 | this.model = {} 165 | this.model.resource = this.resources.items.worldModel.scene 166 | // this.scene.add(this.model.resource) 167 | 168 | const all = [] 169 | 170 | this.model.resource.traverse((_child) => 171 | { 172 | if(_child instanceof THREE.Mesh && _child.material instanceof THREE.MeshStandardMaterial) 173 | { 174 | // Geometry 175 | let geometry = BufferGeometryUtils.mergeVertices(_child.geometry) 176 | 177 | const verticesCount = geometry.attributes.position.count 178 | _child.geometry = geometry 179 | 180 | // for(let i = 0; i < verticesCount; i++) 181 | // { 182 | // geometry.attributes.position.array[i * 3 + 0] += (Math.random() - 0.5) * 0 183 | // geometry.attributes.position.array[i * 3 + 1] += (Math.random() - 0.5) * 0 184 | // geometry.attributes.position.array[i * 3 + 2] += (Math.random() - 0.5) * 0 185 | // } 186 | 187 | const uvRotation = new Float32Array(verticesCount) 188 | for(let i = 0; i < verticesCount; i++) 189 | { 190 | uvRotation[i] = Math.random() * Math.PI * 2 191 | } 192 | geometry.setAttribute('aUvRotation', new THREE.BufferAttribute(uvRotation, 1)) 193 | 194 | // Material 195 | const oldMaterial = _child.material 196 | const material = new PointsPhysicalMaterial({ 197 | size: 300, 198 | color: oldMaterial.color, 199 | roughness: oldMaterial.roughness, 200 | metalness: oldMaterial.metalness, 201 | envMap: this.environmentMap, 202 | envMapIntensity: oldMaterial.envMapIntensity, 203 | brushTexture: this.brushTexture, 204 | usePoints: true, 205 | // fogColor: new THREE.Color(0x0f0914), 206 | // fogDensity: 0 207 | }) 208 | 209 | // Points 210 | const points = new THREE.Points(geometry, material) 211 | points.castShadow = true 212 | points.receiveShadow = true 213 | points.position.copy(_child.position) 214 | points.scale.copy(_child.scale) 215 | points.quaternion.copy(_child.quaternion) 216 | points.layers.set(0) 217 | 218 | // Mesh 219 | _child.castShadow = true 220 | _child.receiveShadow = true 221 | _child.layers.set(1) 222 | 223 | // Add to the scene 224 | all.push(points) 225 | all.push(_child) 226 | } 227 | }) 228 | 229 | for(const _object of all) 230 | { 231 | this.scene.add(_object) 232 | } 233 | } 234 | 235 | mergeVertices(geometry, tolerance = 1e-4) 236 | { 237 | 238 | tolerance = Math.max( tolerance, Number.EPSILON ); 239 | 240 | // Generate an index buffer if the geometry doesn't have one, or optimize it 241 | // if it's already available. 242 | var hashToIndex = {}; 243 | var indices = geometry.getIndex(); 244 | var positions = geometry.getAttribute( 'position' ); 245 | var vertexCount = indices ? indices.count : positions.count; 246 | 247 | // next value for triangle indices 248 | var nextIndex = 0; 249 | 250 | // attributes and new attribute arrays 251 | var attributeNames = Object.keys( geometry.attributes ); 252 | var attrArrays = {}; 253 | var morphAttrsArrays = {}; 254 | var newIndices = []; 255 | var getters = [ 'getX', 'getY', 'getZ', 'getW' ]; 256 | 257 | // initialize the arrays 258 | for ( var i = 0, l = attributeNames.length; i < l; i ++ ) { 259 | 260 | var name = attributeNames[ i ]; 261 | 262 | attrArrays[ name ] = []; 263 | 264 | var morphAttr = geometry.morphAttributes[ name ]; 265 | if ( morphAttr ) { 266 | 267 | morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] ); 268 | 269 | } 270 | 271 | } 272 | 273 | // convert the error tolerance to an amount of decimal places to truncate to 274 | var decimalShift = Math.log10( 1 / tolerance ); 275 | var shiftMultiplier = Math.pow( 10, decimalShift ); 276 | console.log(attributeNames) 277 | for ( var i = 0; i < vertexCount; i ++ ) { 278 | 279 | var index = indices ? indices.getX( i ) : i; 280 | 281 | // Generate a hash for the vertex attributes at the current index 'i' 282 | var hash = ''; 283 | for ( var j = 0, l = attributeNames.length; j < l; j ++ ) { 284 | 285 | var name = attributeNames[ j ]; 286 | var attribute = geometry.getAttribute( name ); 287 | var itemSize = attribute.itemSize; 288 | 289 | for ( var k = 0; k < itemSize; k ++ ) { 290 | 291 | // double tilde truncates the decimal value 292 | hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier ) },`; 293 | 294 | } 295 | 296 | } 297 | console.log(hash) 298 | 299 | // Add another reference to the vertex if it's already 300 | // used by another index 301 | if ( hash in hashToIndex ) { 302 | 303 | newIndices.push( hashToIndex[ hash ] ); 304 | 305 | } else { 306 | 307 | // copy data to the new index in the attribute arrays 308 | for ( var j = 0, l = attributeNames.length; j < l; j ++ ) { 309 | 310 | var name = attributeNames[ j ]; 311 | var attribute = geometry.getAttribute( name ); 312 | var morphAttr = geometry.morphAttributes[ name ]; 313 | var itemSize = attribute.itemSize; 314 | var newarray = attrArrays[ name ]; 315 | var newMorphArrays = morphAttrsArrays[ name ]; 316 | 317 | for ( var k = 0; k < itemSize; k ++ ) { 318 | 319 | var getterFunc = getters[ k ]; 320 | newarray.push( attribute[ getterFunc ]( index ) ); 321 | 322 | if ( morphAttr ) { 323 | 324 | for ( var m = 0, ml = morphAttr.length; m < ml; m ++ ) { 325 | 326 | newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) ); 327 | 328 | } 329 | 330 | } 331 | 332 | } 333 | 334 | } 335 | 336 | hashToIndex[ hash ] = nextIndex; 337 | newIndices.push( nextIndex ); 338 | nextIndex ++; 339 | 340 | } 341 | 342 | } 343 | 344 | // Generate typed arrays from new attribute arrays and update 345 | // the attributeBuffers 346 | const result = geometry.clone(); 347 | for ( var i = 0, l = attributeNames.length; i < l; i ++ ) { 348 | 349 | var name = attributeNames[ i ]; 350 | var oldAttribute = geometry.getAttribute( name ); 351 | 352 | var buffer = new oldAttribute.array.constructor( attrArrays[ name ] ); 353 | var attribute = new THREE.BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized ); 354 | 355 | result.setAttribute( name, attribute ); 356 | 357 | // Update the attribute arrays 358 | if ( name in morphAttrsArrays ) { 359 | 360 | for ( var j = 0; j < morphAttrsArrays[ name ].length; j ++ ) { 361 | 362 | var oldMorphAttribute = geometry.morphAttributes[ name ][ j ]; 363 | 364 | var buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] ); 365 | var morphAttribute = new THREE.BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized ); 366 | result.morphAttributes[ name ][ j ] = morphAttribute; 367 | 368 | } 369 | 370 | } 371 | 372 | } 373 | 374 | // indices 375 | 376 | result.setIndex( newIndices ); 377 | 378 | return result; 379 | 380 | } 381 | 382 | update() 383 | { 384 | // this.lights.directionalLight.instance.position.x = Math.sin(this.time.elapsed / 1000) 385 | // this.lights.directionalLight.instance.position.z = Math.sin(this.time.elapsed / 1000 * 0.8) 386 | } 387 | } 388 | -------------------------------------------------------------------------------- /src/javascript/assets.js: -------------------------------------------------------------------------------- 1 | export default [ 2 | { 3 | name: 'all', 4 | data: {}, 5 | items: 6 | [ 7 | { name: 'worldModel', source: '/world.glb' } 8 | ] 9 | } 10 | ] -------------------------------------------------------------------------------- /src/javascript/shaders/final/fragment.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: random = require(../utils/random2d.glsl) 2 | 3 | uniform sampler2D tDiffuse; 4 | uniform float uNoiseMultiplier; 5 | uniform float uTime; 6 | uniform float uRGBOffsetMultiplier; 7 | uniform float uRGBOffsetOffset; 8 | uniform float uRGBOffsetPower; 9 | uniform vec3 uOverlayColor; 10 | uniform float uOverlayAlpha; 11 | 12 | varying vec2 vUv; 13 | 14 | void main() 15 | { 16 | vec4 diffuseColor = texture2D(tDiffuse, vUv); 17 | 18 | // RGB Offset 19 | float rgbOffsetStrength = pow(max(0.0, distance(vUv, vec2(0.5)) * uRGBOffsetMultiplier - uRGBOffsetOffset), uRGBOffsetPower); 20 | 21 | vec2 rUV = vUv + vec2(cos((3.14 * 2.0) / 3.0 + 1.0), sin((3.14 * 2.0) / 3.0 + 1.0)) * rgbOffsetStrength; 22 | vec2 gUV = vUv + vec2(cos(- (3.14 * 2.0) / 3.0 + 1.0), sin(- (3.14 * 2.0) / 3.0 + 1.0)) * rgbOffsetStrength; 23 | vec2 bUV = vUv + vec2(cos(0.0), sin(0.0)) * rgbOffsetStrength; 24 | 25 | vec4 diffuseColorR = texture2D(tDiffuse, rUV); 26 | vec4 diffuseColorG = texture2D(tDiffuse, gUV); 27 | vec4 diffuseColorB = texture2D(tDiffuse, bUV); 28 | vec3 finalColor = vec3(diffuseColorR.r, diffuseColorG.g, diffuseColorB.b); 29 | 30 | // Noise 31 | finalColor.r += (random(vUv + uTime * 0.00001) - 0.5) * uNoiseMultiplier; 32 | finalColor.g += (random(vUv + vec2(0.1) + uTime * 0.00001) - 0.5) * uNoiseMultiplier; 33 | finalColor.b += (random(vUv + vec2(0.1) + uTime * 0.00001) - 0.5) * uNoiseMultiplier; 34 | 35 | // Overlay 36 | finalColor.rgb = mix(finalColor.rgb, uOverlayColor, uOverlayAlpha); 37 | 38 | // gl_FragColor = vec4(vec3(rgbOffsetStrength), 1.0); 39 | gl_FragColor = vec4(finalColor, 1.0); 40 | } 41 | -------------------------------------------------------------------------------- /src/javascript/shaders/final/vertex.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() 4 | { 5 | vUv = uv; 6 | gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0); 7 | } 8 | -------------------------------------------------------------------------------- /src/javascript/shaders/pointsPhysical/fragment.glsl: -------------------------------------------------------------------------------- 1 | #define STANDARD 2 | 3 | #include 4 | 5 | varying vec4 vFinalColor; 6 | 7 | #ifdef USE_POINTS 8 | uniform sampler2D uBrushTexture; 9 | 10 | varying float vUvRotation; 11 | 12 | vec2 rotateUV(vec2 uv, float rotation) 13 | { 14 | float mid = 0.5; 15 | return vec2( 16 | cos(rotation) * (uv.x - mid) + sin(rotation) * (uv.y - mid) + mid, 17 | cos(rotation) * (uv.y - mid) - sin(rotation) * (uv.x - mid) + mid 18 | ); 19 | } 20 | #endif 21 | 22 | void main() { 23 | 24 | // Brush texture 25 | #ifdef USE_POINTS 26 | vec2 pointUv = rotateUV(gl_PointCoord, vUvRotation); 27 | float brushStrength = texture2D(uBrushTexture, pointUv).r; 28 | 29 | if(brushStrength < ALPHATEST) 30 | { 31 | discard; 32 | } 33 | #endif 34 | 35 | gl_FragColor = vFinalColor; 36 | 37 | #include 38 | #include 39 | #include 40 | #include 41 | } -------------------------------------------------------------------------------- /src/javascript/shaders/pointsPhysical/vertex.glsl: -------------------------------------------------------------------------------- 1 | #define STANDARD 2 | 3 | // ############################## 4 | // Fragment start 5 | // ############################## 6 | #ifdef PHYSICAL 7 | #define REFLECTIVITY 8 | #define CLEARCOAT 9 | #define TRANSMISSION 10 | #endif 11 | 12 | uniform vec3 diffuse; 13 | uniform vec3 emissive; 14 | uniform float roughness; 15 | uniform float metalness; 16 | uniform float opacity; 17 | 18 | #ifdef TRANSMISSION 19 | uniform float transmission; 20 | #endif 21 | 22 | #ifdef REFLECTIVITY 23 | uniform float reflectivity; 24 | #endif 25 | 26 | #ifdef CLEARCOAT 27 | uniform float clearcoat; 28 | uniform float clearcoatRoughness; 29 | #endif 30 | 31 | #ifdef USE_SHEEN 32 | uniform vec3 sheen; 33 | #endif 34 | // ############################## 35 | // Fragment end 36 | // ############################## 37 | 38 | #include 39 | 40 | // ############################## 41 | // Fragment start 42 | // ############################## 43 | #define gl_FragColor pc_fragColor 44 | #define gl_FragDepthEXT gl_FragDepth 45 | #define texture2D texture 46 | #define textureCube texture 47 | #define texture2DProj textureProj 48 | #define texture2DLodEXT textureLod 49 | #define texture2DProjLodEXT textureProjLod 50 | #define textureCubeLodEXT textureLod 51 | #define texture2DGradEXT textureGrad 52 | #define texture2DProjGradEXT textureProjGrad 53 | #define textureCubeGradEXT textureGrad 54 | precision highp float; 55 | precision highp int; 56 | #define HIGH_PRECISION 57 | #define SHADER_NAME ShaderMaterial 58 | #define PHYSICAL 59 | #define USE_POINTS 60 | #define USE_ENVMAP 61 | #define ENVMAP_TYPE_CUBE 62 | #define ALPHATEST 0.1 63 | #define GAMMA_FACTOR 2 64 | #define USE_ENVMAP 65 | #define ENVMAP_TYPE_CUBE 66 | #define ENVMAP_MODE_REFLECTION 67 | #define ENVMAP_BLENDING_NONE 68 | #define PHYSICALLY_CORRECT_LIGHTS 69 | #define TEXTURE_LOD_EXT 70 | 71 | #include 72 | 73 | vec4 envMapTexelToLinear( vec4 value ) { return sRGBToLinear( value ); } 74 | vec4 linearToOutputTexel( vec4 value ) { return LinearTosRGB( value ); } 75 | 76 | #include 77 | #include 78 | #include 79 | #include 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #ifdef USE_SHADOWMAP 91 | 92 | #if NUM_DIR_LIGHT_SHADOWS > 0 93 | 94 | uniform sampler2D directionalShadowMap[ NUM_DIR_LIGHT_SHADOWS ]; 95 | varying vec4 vDirectionalShadowCoord[ NUM_DIR_LIGHT_SHADOWS ]; 96 | uniform mat4 directionalShadowMatrix[ NUM_DIR_LIGHT_SHADOWS ]; 97 | 98 | struct DirectionalLightShadow { 99 | float shadowBias; 100 | float shadowNormalBias; 101 | float shadowRadius; 102 | vec2 shadowMapSize; 103 | }; 104 | 105 | uniform DirectionalLightShadow directionalLightShadows[ NUM_DIR_LIGHT_SHADOWS ]; 106 | 107 | #endif 108 | 109 | #if NUM_SPOT_LIGHT_SHADOWS > 0 110 | 111 | uniform sampler2D spotShadowMap[ NUM_SPOT_LIGHT_SHADOWS ]; 112 | varying vec4 vSpotShadowCoord[ NUM_SPOT_LIGHT_SHADOWS ]; 113 | uniform mat4 spotShadowMatrix[ NUM_SPOT_LIGHT_SHADOWS ]; 114 | 115 | struct SpotLightShadow { 116 | float shadowBias; 117 | float shadowNormalBias; 118 | float shadowRadius; 119 | vec2 shadowMapSize; 120 | }; 121 | 122 | uniform SpotLightShadow spotLightShadows[ NUM_SPOT_LIGHT_SHADOWS ]; 123 | 124 | #endif 125 | 126 | #if NUM_POINT_LIGHT_SHADOWS > 0 127 | 128 | uniform sampler2D pointShadowMap[ NUM_POINT_LIGHT_SHADOWS ]; 129 | varying vec4 vPointShadowCoord[ NUM_POINT_LIGHT_SHADOWS ]; 130 | uniform mat4 pointShadowMatrix[ NUM_POINT_LIGHT_SHADOWS ]; 131 | 132 | struct PointLightShadow { 133 | float shadowBias; 134 | float shadowNormalBias; 135 | float shadowRadius; 136 | vec2 shadowMapSize; 137 | float shadowCameraNear; 138 | float shadowCameraFar; 139 | }; 140 | 141 | uniform PointLightShadow pointLightShadows[ NUM_POINT_LIGHT_SHADOWS ]; 142 | 143 | #endif 144 | 145 | /* 146 | #if NUM_RECT_AREA_LIGHTS > 0 147 | 148 | // TODO (abelnation): create uniforms for area light shadows 149 | 150 | #endif 151 | */ 152 | 153 | float texture2DCompare( sampler2D depths, vec2 uv, float compare ) { 154 | 155 | return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) ); 156 | 157 | } 158 | 159 | vec2 texture2DDistribution( sampler2D shadow, vec2 uv ) { 160 | 161 | return unpackRGBATo2Half( texture2D( shadow, uv ) ); 162 | 163 | } 164 | 165 | float VSMShadow (sampler2D shadow, vec2 uv, float compare ){ 166 | 167 | float occlusion = 1.0; 168 | 169 | vec2 distribution = texture2DDistribution( shadow, uv ); 170 | 171 | float hard_shadow = step( compare , distribution.x ); // Hard Shadow 172 | 173 | if (hard_shadow != 1.0 ) { 174 | 175 | float distance = compare - distribution.x ; 176 | float variance = max( 0.00000, distribution.y * distribution.y ); 177 | float softness_probability = variance / (variance + distance * distance ); // Chebeyshevs inequality 178 | softness_probability = clamp( ( softness_probability - 0.3 ) / ( 0.95 - 0.3 ), 0.0, 1.0 ); // 0.3 reduces light bleed 179 | occlusion = clamp( max( hard_shadow, softness_probability ), 0.0, 1.0 ); 180 | 181 | } 182 | return occlusion; 183 | 184 | } 185 | 186 | float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) { 187 | 188 | float shadow = 1.0; 189 | 190 | shadowCoord.xyz /= shadowCoord.w; 191 | shadowCoord.z += shadowBias; 192 | 193 | // if ( something && something ) breaks ATI OpenGL shader compiler 194 | // if ( all( something, something ) ) using this instead 195 | 196 | bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 ); 197 | bool inFrustum = all( inFrustumVec ); 198 | 199 | bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 ); 200 | 201 | bool frustumTest = all( frustumTestVec ); 202 | 203 | if ( frustumTest ) { 204 | 205 | #if defined( SHADOWMAP_TYPE_PCF ) 206 | 207 | vec2 texelSize = vec2( 1.0 ) / shadowMapSize; 208 | 209 | float dx0 = - texelSize.x * shadowRadius; 210 | float dy0 = - texelSize.y * shadowRadius; 211 | float dx1 = + texelSize.x * shadowRadius; 212 | float dy1 = + texelSize.y * shadowRadius; 213 | float dx2 = dx0 / 2.0; 214 | float dy2 = dy0 / 2.0; 215 | float dx3 = dx1 / 2.0; 216 | float dy3 = dy1 / 2.0; 217 | 218 | shadow = ( 219 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) + 220 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) + 221 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) + 222 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy2 ), shadowCoord.z ) + 223 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy2 ), shadowCoord.z ) + 224 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy2 ), shadowCoord.z ) + 225 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) + 226 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, 0.0 ), shadowCoord.z ) + 227 | texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) + 228 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, 0.0 ), shadowCoord.z ) + 229 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) + 230 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx2, dy3 ), shadowCoord.z ) + 231 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy3 ), shadowCoord.z ) + 232 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx3, dy3 ), shadowCoord.z ) + 233 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) + 234 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) + 235 | texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z ) 236 | ) * ( 1.0 / 17.0 ); 237 | 238 | #elif defined( SHADOWMAP_TYPE_PCF_SOFT ) 239 | 240 | vec2 texelSize = vec2( 1.0 ) / shadowMapSize; 241 | float dx = texelSize.x; 242 | float dy = texelSize.y; 243 | 244 | vec2 uv = shadowCoord.xy; 245 | vec2 f = fract( uv * shadowMapSize + 0.5 ); 246 | uv -= f * texelSize; 247 | 248 | shadow = ( 249 | texture2DCompare( shadowMap, uv, shadowCoord.z ) + 250 | texture2DCompare( shadowMap, uv + vec2( dx, 0.0 ), shadowCoord.z ) + 251 | texture2DCompare( shadowMap, uv + vec2( 0.0, dy ), shadowCoord.z ) + 252 | texture2DCompare( shadowMap, uv + texelSize, shadowCoord.z ) + 253 | mix( texture2DCompare( shadowMap, uv + vec2( -dx, 0.0 ), shadowCoord.z ), 254 | texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 0.0 ), shadowCoord.z ), 255 | f.x ) + 256 | mix( texture2DCompare( shadowMap, uv + vec2( -dx, dy ), shadowCoord.z ), 257 | texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, dy ), shadowCoord.z ), 258 | f.x ) + 259 | mix( texture2DCompare( shadowMap, uv + vec2( 0.0, -dy ), shadowCoord.z ), 260 | texture2DCompare( shadowMap, uv + vec2( 0.0, 2.0 * dy ), shadowCoord.z ), 261 | f.y ) + 262 | mix( texture2DCompare( shadowMap, uv + vec2( dx, -dy ), shadowCoord.z ), 263 | texture2DCompare( shadowMap, uv + vec2( dx, 2.0 * dy ), shadowCoord.z ), 264 | f.y ) + 265 | mix( mix( texture2DCompare( shadowMap, uv + vec2( -dx, -dy ), shadowCoord.z ), 266 | texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, -dy ), shadowCoord.z ), 267 | f.x ), 268 | mix( texture2DCompare( shadowMap, uv + vec2( -dx, 2.0 * dy ), shadowCoord.z ), 269 | texture2DCompare( shadowMap, uv + vec2( 2.0 * dx, 2.0 * dy ), shadowCoord.z ), 270 | f.x ), 271 | f.y ) 272 | ) * ( 1.0 / 9.0 ); 273 | 274 | #elif defined( SHADOWMAP_TYPE_VSM ) 275 | 276 | shadow = VSMShadow( shadowMap, shadowCoord.xy, shadowCoord.z ); 277 | 278 | #else // no percentage-closer filtering: 279 | 280 | shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ); 281 | 282 | #endif 283 | 284 | } 285 | 286 | return shadow; 287 | 288 | } 289 | 290 | // cubeToUV() maps a 3D direction vector suitable for cube texture mapping to a 2D 291 | // vector suitable for 2D texture mapping. This code uses the following layout for the 292 | // 2D texture: 293 | // 294 | // xzXZ 295 | // y Y 296 | // 297 | // Y - Positive y direction 298 | // y - Negative y direction 299 | // X - Positive x direction 300 | // x - Negative x direction 301 | // Z - Positive z direction 302 | // z - Negative z direction 303 | // 304 | // Source and test bed: 305 | // https://gist.github.com/tschw/da10c43c467ce8afd0c4 306 | 307 | vec2 cubeToUV( vec3 v, float texelSizeY ) { 308 | 309 | // Number of texels to avoid at the edge of each square 310 | 311 | vec3 absV = abs( v ); 312 | 313 | // Intersect unit cube 314 | 315 | float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) ); 316 | absV *= scaleToCube; 317 | 318 | // Apply scale to avoid seams 319 | 320 | // two texels less per square (one texel will do for NEAREST) 321 | v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY ); 322 | 323 | // Unwrap 324 | 325 | // space: -1 ... 1 range for each square 326 | // 327 | // #X## dim := ( 4 , 2 ) 328 | // # # center := ( 1 , 1 ) 329 | 330 | vec2 planar = v.xy; 331 | 332 | float almostATexel = 1.5 * texelSizeY; 333 | float almostOne = 1.0 - almostATexel; 334 | 335 | if ( absV.z >= almostOne ) { 336 | 337 | if ( v.z > 0.0 ) 338 | planar.x = 4.0 - v.x; 339 | 340 | } else if ( absV.x >= almostOne ) { 341 | 342 | float signX = sign( v.x ); 343 | planar.x = v.z * signX + 2.0 * signX; 344 | 345 | } else if ( absV.y >= almostOne ) { 346 | 347 | float signY = sign( v.y ); 348 | planar.x = v.x + 2.0 * signY + 2.0; 349 | planar.y = v.z * signY - 2.0; 350 | 351 | } 352 | 353 | // Transform to UV space 354 | 355 | // scale := 0.5 / dim 356 | // translate := ( center + 0.5 ) / dim 357 | return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 ); 358 | 359 | } 360 | 361 | float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) { 362 | 363 | vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) ); 364 | 365 | // for point lights, the uniform @vShadowCoord is re-purposed to hold 366 | // the vector from the light to the world-space position of the fragment. 367 | vec3 lightToPosition = shadowCoord.xyz; 368 | 369 | // dp = normalized distance from light to fragment position 370 | float dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear ); // need to clamp? 371 | dp += shadowBias; 372 | 373 | // bd3D = base direction 3D 374 | vec3 bd3D = normalize( lightToPosition ); 375 | 376 | #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM ) 377 | 378 | vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y; 379 | 380 | return ( 381 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) + 382 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) + 383 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) + 384 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) + 385 | texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) + 386 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) + 387 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) + 388 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) + 389 | texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp ) 390 | ) * ( 1.0 / 9.0 ); 391 | 392 | #else // no percentage-closer filtering 393 | 394 | return texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ); 395 | 396 | #endif 397 | 398 | } 399 | 400 | #endif 401 | #include 402 | #include 403 | #include 404 | #include 405 | #include 406 | #include 407 | #include 408 | 409 | // ############################## 410 | // Fragment end 411 | // ############################## 412 | 413 | // varying vec3 vViewPosition; 414 | 415 | // #ifndef FLAT_SHADED 416 | 417 | // varying vec3 vNormal; 418 | 419 | // #ifdef USE_TANGENT 420 | 421 | // varying vec3 vTangent; 422 | // varying vec3 vBitangent; 423 | 424 | // #endif 425 | 426 | // #endif 427 | 428 | #include 429 | #include 430 | #include 431 | #include 432 | #include 433 | #include 434 | #include 435 | // #include 436 | #include 437 | #include 438 | 439 | // ############################## 440 | // Custom start 441 | // ############################## 442 | uniform float uSize; 443 | 444 | attribute float aUvRotation; 445 | 446 | varying vec4 vFinalColor; 447 | 448 | #ifdef USE_POINTS 449 | varying float vUvRotation; 450 | #endif 451 | // ############################## 452 | // Custom end 453 | // ############################## 454 | 455 | void main() { 456 | 457 | #include 458 | #include 459 | #include 460 | 461 | #include 462 | #include 463 | #include 464 | #include 465 | #include 466 | 467 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED 468 | 469 | vec3 vNormal = normalize( transformedNormal ); 470 | 471 | #ifdef USE_TANGENT 472 | 473 | vec3 vTangent = normalize( transformedTangent ); 474 | vec3 vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); 475 | 476 | #endif 477 | 478 | #endif 479 | 480 | #include 481 | #include 482 | #include 483 | #include 484 | #include 485 | #include 486 | #include 487 | 488 | vec3 vViewPosition = - mvPosition.xyz; 489 | 490 | #include 491 | #include 492 | #include 493 | 494 | // ############################## 495 | // Custom start 496 | // ############################## 497 | vec4 modelViewPosition = modelViewMatrix * vec4(position, 1.0); 498 | // gl_Position = projectionMatrix * modelViewPosition; 499 | 500 | #ifdef USE_POINTS 501 | gl_PointSize = uSize; 502 | gl_PointSize *= (1.0 / - modelViewPosition.z); 503 | 504 | vUvRotation = aUvRotation; 505 | #endif 506 | // ############################## 507 | // Custom end 508 | // ############################## 509 | 510 | // ############################## 511 | // Fragment start 512 | // ############################## 513 | 514 | #include 515 | 516 | vec4 diffuseColor = vec4( diffuse, opacity ); 517 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 518 | vec3 totalEmissiveRadiance = emissive; 519 | 520 | #ifdef TRANSMISSION 521 | float totalTransmission = transmission; 522 | #endif 523 | 524 | #include 525 | #include 526 | #include 527 | #include 528 | // #include 529 | #include 530 | #include 531 | #include 532 | #include 533 | #include 534 | #include 535 | #include 536 | #include 537 | 538 | // accumulation 539 | // Start custom implementation of 540 | PhysicalMaterial material; 541 | material.diffuseColor = diffuseColor.rgb * ( 1.0 - metalnessFactor ); 542 | 543 | // Custom TODO 544 | // vec3 dxy = max( abs( dFdx( geometryNormal ) ), abs( dFdy( geometryNormal ) ) ); 545 | // float geometryRoughness = max( max( geometryNormal.x, geometryNormal.y ), geometryNormal.z ); 546 | 547 | // Custom fix 548 | float geometryRoughness = 0.0; 549 | 550 | material.specularRoughness = max( roughnessFactor, 0.0525 );// 0.0525 corresponds to the base mip of a 256 cubemap. 551 | material.specularRoughness += geometryRoughness; 552 | material.specularRoughness = min( material.specularRoughness, 1.0 ); 553 | 554 | #ifdef REFLECTIVITY 555 | 556 | material.specularColor = mix( vec3( MAXIMUM_SPECULAR_COEFFICIENT * pow2( reflectivity ) ), diffuseColor.rgb, metalnessFactor ); 557 | 558 | #else 559 | 560 | material.specularColor = mix( vec3( DEFAULT_SPECULAR_COEFFICIENT ), diffuseColor.rgb, metalnessFactor ); 561 | 562 | #endif 563 | 564 | #ifdef CLEARCOAT 565 | 566 | material.clearcoat = clearcoat; 567 | material.clearcoatRoughness = clearcoatRoughness; 568 | 569 | #ifdef USE_CLEARCOATMAP 570 | 571 | material.clearcoat *= texture2D( clearcoatMap, vUv ).x; 572 | 573 | #endif 574 | 575 | #ifdef USE_CLEARCOAT_ROUGHNESSMAP 576 | 577 | material.clearcoatRoughness *= texture2D( clearcoatRoughnessMap, vUv ).y; 578 | 579 | #endif 580 | 581 | material.clearcoat = saturate( material.clearcoat ); // Burley clearcoat model 582 | material.clearcoatRoughness = max( material.clearcoatRoughness, 0.0525 ); 583 | material.clearcoatRoughness += geometryRoughness; 584 | material.clearcoatRoughness = min( material.clearcoatRoughness, 1.0 ); 585 | 586 | #endif 587 | 588 | #ifdef USE_SHEEN 589 | 590 | material.sheenColor = sheen; 591 | 592 | #endif 593 | // End custom implementation of 594 | 595 | #include 596 | #include 597 | #include 598 | 599 | // modulation 600 | #include 601 | 602 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 603 | 604 | // this is a stub for the transmission model 605 | #ifdef TRANSMISSION 606 | diffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness ); 607 | #endif 608 | 609 | vFinalColor = vec4( outgoingLight, diffuseColor.a ); 610 | 611 | // ############################## 612 | // Fragment end 613 | // ############################## 614 | } -------------------------------------------------------------------------------- /src/javascript/shaders/standardBase/fragment.glsl: -------------------------------------------------------------------------------- 1 | #define STANDARD 2 | 3 | #ifdef PHYSICAL 4 | #define REFLECTIVITY 5 | #define CLEARCOAT 6 | #define TRANSMISSION 7 | #endif 8 | 9 | uniform vec3 diffuse; 10 | uniform vec3 emissive; 11 | uniform float roughness; 12 | uniform float metalness; 13 | uniform float opacity; 14 | 15 | #ifdef TRANSMISSION 16 | uniform float transmission; 17 | #endif 18 | 19 | #ifdef REFLECTIVITY 20 | uniform float reflectivity; 21 | #endif 22 | 23 | #ifdef CLEARCOAT 24 | uniform float clearcoat; 25 | uniform float clearcoatRoughness; 26 | #endif 27 | 28 | #ifdef USE_SHEEN 29 | uniform vec3 sheen; 30 | #endif 31 | 32 | varying vec3 vViewPosition; 33 | 34 | #ifndef FLAT_SHADED 35 | 36 | varying vec3 vNormal; 37 | 38 | #ifdef USE_TANGENT 39 | 40 | varying vec3 vTangent; 41 | varying vec3 vBitangent; 42 | 43 | #endif 44 | 45 | #endif 46 | 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | #include 63 | #include 64 | #include 65 | #include 66 | #include 67 | #include 68 | #include 69 | #include 70 | #include 71 | #include 72 | #include 73 | #include 74 | 75 | void main() { 76 | 77 | #include 78 | 79 | vec4 diffuseColor = vec4( diffuse, opacity ); 80 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 81 | vec3 totalEmissiveRadiance = emissive; 82 | 83 | #ifdef TRANSMISSION 84 | float totalTransmission = transmission; 85 | #endif 86 | 87 | #include 88 | #include 89 | #include 90 | #include 91 | #include 92 | #include 93 | #include 94 | #include 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | 101 | // accumulation 102 | #include 103 | #include 104 | #include 105 | #include 106 | 107 | // modulation 108 | #include 109 | 110 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 111 | 112 | // this is a stub for the transmission model 113 | #ifdef TRANSMISSION 114 | diffuseColor.a *= mix( saturate( 1. - totalTransmission + linearToRelativeLuminance( reflectedLight.directSpecular + reflectedLight.indirectSpecular ) ), 1.0, metalness ); 115 | #endif 116 | 117 | gl_FragColor = vec4( outgoingLight, diffuseColor.a ); 118 | 119 | #include 120 | #include 121 | #include 122 | #include 123 | #include 124 | 125 | } -------------------------------------------------------------------------------- /src/javascript/shaders/standardBase/vertex.glsl: -------------------------------------------------------------------------------- 1 | #define STANDARD 2 | 3 | varying vec3 vViewPosition; 4 | 5 | #ifndef FLAT_SHADED 6 | 7 | varying vec3 vNormal; 8 | 9 | #ifdef USE_TANGENT 10 | 11 | varying vec3 vTangent; 12 | varying vec3 vBitangent; 13 | 14 | #endif 15 | 16 | #endif 17 | 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | void main() { 31 | 32 | #include 33 | #include 34 | #include 35 | 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | 42 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED 43 | 44 | vNormal = normalize( transformedNormal ); 45 | 46 | #ifdef USE_TANGENT 47 | 48 | vTangent = normalize( transformedTangent ); 49 | vBitangent = normalize( cross( vNormal, vTangent ) * tangent.w ); 50 | 51 | #endif 52 | 53 | #endif 54 | 55 | #include 56 | #include 57 | #include 58 | #include 59 | #include 60 | #include 61 | #include 62 | 63 | vViewPosition = - mvPosition.xyz; 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | } -------------------------------------------------------------------------------- /src/style/main.css: -------------------------------------------------------------------------------- 1 | * 2 | { 3 | margin: 0; 4 | padding: 0; 5 | } 6 | 7 | html, 8 | body 9 | { 10 | overflow: hidden; 11 | } 12 | 13 | .experience 14 | { 15 | position: fixed; 16 | top: 0; 17 | left: 0; 18 | width: 100%; 19 | height: 100%; 20 | } 21 | -------------------------------------------------------------------------------- /static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/.gitkeep -------------------------------------------------------------------------------- /static/textures/brushes/brush1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/brushes/brush1.png -------------------------------------------------------------------------------- /static/textures/brushes/brush2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/brushes/brush2.png -------------------------------------------------------------------------------- /static/textures/brushes/brush3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/brushes/brush3.png -------------------------------------------------------------------------------- /static/textures/brushes/brush4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/brushes/brush4.png -------------------------------------------------------------------------------- /static/textures/door/alpha.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/alpha.jpg -------------------------------------------------------------------------------- /static/textures/door/ambientOcclusion.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/ambientOcclusion.jpg -------------------------------------------------------------------------------- /static/textures/door/color.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/color.jpg -------------------------------------------------------------------------------- /static/textures/door/height.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/height.jpg -------------------------------------------------------------------------------- /static/textures/door/metalness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/metalness.jpg -------------------------------------------------------------------------------- /static/textures/door/normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/normal.jpg -------------------------------------------------------------------------------- /static/textures/door/roughness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/door/roughness.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/nx.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/ny.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/nz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/px.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/py.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/0/pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/0/pz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/nx.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/ny.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/nz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/px.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/py.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/1/pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/1/pz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/nx.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/ny.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/nz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/px.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/py.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/2/pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/2/pz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/nx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/nx.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/ny.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/ny.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/nz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/nz.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/px.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/px.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/py.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/py.jpg -------------------------------------------------------------------------------- /static/textures/environmentMaps/3/pz.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/textures/environmentMaps/3/pz.jpg -------------------------------------------------------------------------------- /static/world.glb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/brunosimon/threejs-points-physical-material/c5256771c4be92ae74ff008881ca3c83f2ac4765/static/world.glb --------------------------------------------------------------------------------