├── .gitignore ├── .npmignore ├── LICENSE.md ├── README.md ├── dist ├── css │ └── normalise.css ├── index.html └── js │ └── bundle.js ├── index.html ├── package.json └── src ├── App.js ├── glsl ├── basic_frag.glsl └── basic_vert.glsl ├── index.js └── post-processing ├── EffectComposer.js └── glsl ├── fxaa.glsl ├── gamma.glsl ├── screen_frag.glsl └── screen_vert.glsl /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | npm-debug.log 3 | .DS_Store 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2002-2016 Silvio Paganini 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ### Rapid Prototyping boilerplate 2 | 3 | Using ES6 and babelify transform 4 | 5 | #### Dependencies 6 | * babelify 7 | * budo 8 | * dat-gui 9 | * garnish 10 | * stats-js 11 | * three 12 | * three-orbit-controls 13 | * watchify 14 | 15 | ## Rapid proto command line tool 16 | 17 | [![NPM version][npm-image]][npm-url] 18 | [![Downloads][downloads-image]][npm-url] 19 | [![js-standard-style][standard-image]][standard-url] 20 | 21 | #### Install 22 | 23 | Need to install globally in order to have the command available everywhere. 24 | 25 | ```bash 26 | [sudo] npm -g install rapid-proto 27 | ``` 28 | 29 | ##### Full Documentation 30 | [https://github.com/silviopaganini/rapid-proto](https://github.com/silviopaganini/rapid-proto) 31 | 32 | ## Usage: 33 | ```bash 34 | rp nameOfThePrototype 35 | ``` 36 | 37 | Or just checkout the repo and start the server 38 | 39 | ``` 40 | git clone 41 | npm install 42 | npm start 43 | ``` 44 | 45 | ### credits 46 | [@mattdesl](https://github.com/mattdesl) 47 | 48 | [npm-image]: https://img.shields.io/npm/v/rapid-proto.svg?style=flat-square 49 | [npm-url]: https://npmjs.org/package/rapid-proto 50 | [downloads-image]: http://img.shields.io/npm/dm/rapid-proto.svg?style=flat-square 51 | [standard-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 52 | [standard-url]: https://github.com/feross/standard -------------------------------------------------------------------------------- /dist/css/normalise.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */ 2 | 3 | /** 4 | * 1. Set default font family to sans-serif. 5 | * 2. Prevent iOS text size adjust after orientation change, without disabling 6 | * user zoom. 7 | */ 8 | 9 | html { 10 | font-family: sans-serif; /* 1 */ 11 | -ms-text-size-adjust: 100%; /* 2 */ 12 | -webkit-text-size-adjust: 100%; /* 2 */ 13 | } 14 | 15 | /** 16 | * Remove default margin. 17 | */ 18 | 19 | body { 20 | margin: 0; 21 | } 22 | 23 | /* HTML5 display definitions 24 | ========================================================================== */ 25 | 26 | /** 27 | * Correct `block` display not defined for any HTML5 element in IE 8/9. 28 | * Correct `block` display not defined for `details` or `summary` in IE 10/11 29 | * and Firefox. 30 | * Correct `block` display not defined for `main` in IE 11. 31 | */ 32 | 33 | article, 34 | aside, 35 | details, 36 | figcaption, 37 | figure, 38 | footer, 39 | header, 40 | hgroup, 41 | main, 42 | menu, 43 | nav, 44 | section, 45 | summary { 46 | display: block; 47 | } 48 | 49 | /** 50 | * 1. Correct `inline-block` display not defined in IE 8/9. 51 | * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. 52 | */ 53 | 54 | audio, 55 | canvas, 56 | progress, 57 | video { 58 | display: inline-block; /* 1 */ 59 | vertical-align: baseline; /* 2 */ 60 | } 61 | 62 | /** 63 | * Prevent modern browsers from displaying `audio` without controls. 64 | * Remove excess height in iOS 5 devices. 65 | */ 66 | 67 | audio:not([controls]) { 68 | display: none; 69 | height: 0; 70 | } 71 | 72 | /** 73 | * Address `[hidden]` styling not present in IE 8/9/10. 74 | * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. 75 | */ 76 | 77 | [hidden], 78 | template { 79 | display: none; 80 | } 81 | 82 | /* Links 83 | ========================================================================== */ 84 | 85 | /** 86 | * Remove the gray background color from active links in IE 10. 87 | */ 88 | 89 | a { 90 | background-color: transparent; 91 | } 92 | 93 | /** 94 | * Improve readability when focused and also mouse hovered in all browsers. 95 | */ 96 | 97 | a:active, 98 | a:hover { 99 | outline: 0; 100 | } 101 | 102 | /* Text-level semantics 103 | ========================================================================== */ 104 | 105 | /** 106 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome. 107 | */ 108 | 109 | abbr[title] { 110 | border-bottom: 1px dotted; 111 | } 112 | 113 | /** 114 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. 115 | */ 116 | 117 | b, 118 | strong { 119 | font-weight: bold; 120 | } 121 | 122 | /** 123 | * Address styling not present in Safari and Chrome. 124 | */ 125 | 126 | dfn { 127 | font-style: italic; 128 | } 129 | 130 | /** 131 | * Address variable `h1` font-size and margin within `section` and `article` 132 | * contexts in Firefox 4+, Safari, and Chrome. 133 | */ 134 | 135 | h1 { 136 | font-size: 2em; 137 | margin: 0.67em 0; 138 | } 139 | 140 | /** 141 | * Address styling not present in IE 8/9. 142 | */ 143 | 144 | mark { 145 | background: #ff0; 146 | color: #000; 147 | } 148 | 149 | /** 150 | * Address inconsistent and variable font size in all browsers. 151 | */ 152 | 153 | small { 154 | font-size: 80%; 155 | } 156 | 157 | /** 158 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 159 | */ 160 | 161 | sub, 162 | sup { 163 | font-size: 75%; 164 | line-height: 0; 165 | position: relative; 166 | vertical-align: baseline; 167 | } 168 | 169 | sup { 170 | top: -0.5em; 171 | } 172 | 173 | sub { 174 | bottom: -0.25em; 175 | } 176 | 177 | /* Embedded content 178 | ========================================================================== */ 179 | 180 | /** 181 | * Remove border when inside `a` element in IE 8/9/10. 182 | */ 183 | 184 | img { 185 | border: 0; 186 | } 187 | 188 | /** 189 | * Correct overflow not hidden in IE 9/10/11. 190 | */ 191 | 192 | svg:not(:root) { 193 | overflow: hidden; 194 | } 195 | 196 | /* Grouping content 197 | ========================================================================== */ 198 | 199 | /** 200 | * Address margin not present in IE 8/9 and Safari. 201 | */ 202 | 203 | figure { 204 | margin: 1em 40px; 205 | } 206 | 207 | /** 208 | * Address differences between Firefox and other browsers. 209 | */ 210 | 211 | hr { 212 | -moz-box-sizing: content-box; 213 | box-sizing: content-box; 214 | height: 0; 215 | } 216 | 217 | /** 218 | * Contain overflow in all browsers. 219 | */ 220 | 221 | pre { 222 | overflow: auto; 223 | } 224 | 225 | /** 226 | * Address odd `em`-unit font size rendering in all browsers. 227 | */ 228 | 229 | code, 230 | kbd, 231 | pre, 232 | samp { 233 | font-family: monospace, monospace; 234 | font-size: 1em; 235 | } 236 | 237 | /* Forms 238 | ========================================================================== */ 239 | 240 | /** 241 | * Known limitation: by default, Chrome and Safari on OS X allow very limited 242 | * styling of `select`, unless a `border` property is set. 243 | */ 244 | 245 | /** 246 | * 1. Correct color not being inherited. 247 | * Known issue: affects color of disabled elements. 248 | * 2. Correct font properties not being inherited. 249 | * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. 250 | */ 251 | 252 | button, 253 | input, 254 | optgroup, 255 | select, 256 | textarea { 257 | color: inherit; /* 1 */ 258 | font: inherit; /* 2 */ 259 | margin: 0; /* 3 */ 260 | } 261 | 262 | /** 263 | * Address `overflow` set to `hidden` in IE 8/9/10/11. 264 | */ 265 | 266 | button { 267 | overflow: visible; 268 | } 269 | 270 | /** 271 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 272 | * All other form control elements do not inherit `text-transform` values. 273 | * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. 274 | * Correct `select` style inheritance in Firefox. 275 | */ 276 | 277 | button, 278 | select { 279 | text-transform: none; 280 | } 281 | 282 | /** 283 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 284 | * and `video` controls. 285 | * 2. Correct inability to style clickable `input` types in iOS. 286 | * 3. Improve usability and consistency of cursor style between image-type 287 | * `input` and others. 288 | */ 289 | 290 | button, 291 | html input[type="button"], /* 1 */ 292 | input[type="reset"], 293 | input[type="submit"] { 294 | -webkit-appearance: button; /* 2 */ 295 | cursor: pointer; /* 3 */ 296 | } 297 | 298 | /** 299 | * Re-set default cursor for disabled elements. 300 | */ 301 | 302 | button[disabled], 303 | html input[disabled] { 304 | cursor: default; 305 | } 306 | 307 | /** 308 | * Remove inner padding and border in Firefox 4+. 309 | */ 310 | 311 | button::-moz-focus-inner, 312 | input::-moz-focus-inner { 313 | border: 0; 314 | padding: 0; 315 | } 316 | 317 | /** 318 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 319 | * the UA stylesheet. 320 | */ 321 | 322 | input { 323 | line-height: normal; 324 | } 325 | 326 | /** 327 | * It's recommended that you don't attempt to style these elements. 328 | * Firefox's implementation doesn't respect box-sizing, padding, or width. 329 | * 330 | * 1. Address box sizing set to `content-box` in IE 8/9/10. 331 | * 2. Remove excess padding in IE 8/9/10. 332 | */ 333 | 334 | input[type="checkbox"], 335 | input[type="radio"] { 336 | box-sizing: border-box; /* 1 */ 337 | padding: 0; /* 2 */ 338 | } 339 | 340 | /** 341 | * Fix the cursor style for Chrome's increment/decrement buttons. For certain 342 | * `font-size` values of the `input`, it causes the cursor style of the 343 | * decrement button to change from `default` to `text`. 344 | */ 345 | 346 | input[type="number"]::-webkit-inner-spin-button, 347 | input[type="number"]::-webkit-outer-spin-button { 348 | height: auto; 349 | } 350 | 351 | /** 352 | * 1. Address `appearance` set to `searchfield` in Safari and Chrome. 353 | * 2. Address `box-sizing` set to `border-box` in Safari and Chrome 354 | * (include `-moz` to future-proof). 355 | */ 356 | 357 | input[type="search"] { 358 | -webkit-appearance: textfield; /* 1 */ 359 | -moz-box-sizing: content-box; 360 | -webkit-box-sizing: content-box; /* 2 */ 361 | box-sizing: content-box; 362 | } 363 | 364 | /** 365 | * Remove inner padding and search cancel button in Safari and Chrome on OS X. 366 | * Safari (but not Chrome) clips the cancel button when the search input has 367 | * padding (and `textfield` appearance). 368 | */ 369 | 370 | input[type="search"]::-webkit-search-cancel-button, 371 | input[type="search"]::-webkit-search-decoration { 372 | -webkit-appearance: none; 373 | } 374 | 375 | /** 376 | * Define consistent border, margin, and padding. 377 | */ 378 | 379 | fieldset { 380 | border: 1px solid #c0c0c0; 381 | margin: 0 2px; 382 | padding: 0.35em 0.625em 0.75em; 383 | } 384 | 385 | /** 386 | * 1. Correct `color` not being inherited in IE 8/9/10/11. 387 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 388 | */ 389 | 390 | legend { 391 | border: 0; /* 1 */ 392 | padding: 0; /* 2 */ 393 | } 394 | 395 | /** 396 | * Remove default vertical scrollbar in IE 8/9/10/11. 397 | */ 398 | 399 | textarea { 400 | overflow: auto; 401 | } 402 | 403 | /** 404 | * Don't inherit the `font-weight` (applied by a rule above). 405 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. 406 | */ 407 | 408 | optgroup { 409 | font-weight: bold; 410 | } 411 | 412 | /* Tables 413 | ========================================================================== */ 414 | 415 | /** 416 | * Remove most spacing between table cells. 417 | */ 418 | 419 | table { 420 | border-collapse: collapse; 421 | border-spacing: 0; 422 | } 423 | 424 | td, 425 | th { 426 | padding: 0; 427 | } 428 | 429 | /*! HTML5 Boilerplate v5.0.0 | MIT License | https://html5boilerplate.com/ */ 430 | 431 | /* 432 | * What follows is the result of much research on cross-browser styling. 433 | * Credit left inline and big thanks to Nicolas Gallagher, Jonathan Neal, 434 | * Kroc Camen, and the H5BP dev community and team. 435 | */ 436 | 437 | /* ========================================================================== 438 | Base styles: opinionated defaults 439 | ========================================================================== */ 440 | 441 | html { 442 | color: #222; 443 | font-size: 1em; 444 | line-height: 1.4; 445 | } 446 | 447 | /* 448 | * Remove text-shadow in selection highlight: 449 | * https://twitter.com/miketaylr/status/12228805301 450 | * 451 | * These selection rule sets have to be separate. 452 | * Customize the background color to match your design. 453 | */ 454 | 455 | ::-moz-selection { 456 | background: #b3d4fc; 457 | text-shadow: none; 458 | } 459 | 460 | ::selection { 461 | background: #b3d4fc; 462 | text-shadow: none; 463 | } 464 | 465 | /* 466 | * A better looking default horizontal rule 467 | */ 468 | 469 | hr { 470 | display: block; 471 | height: 1px; 472 | border: 0; 473 | border-top: 1px solid #ccc; 474 | margin: 1em 0; 475 | padding: 0; 476 | } 477 | 478 | /* 479 | * Remove the gap between audio, canvas, iframes, 480 | * images, videos and the bottom of their containers: 481 | * https://github.com/h5bp/html5-boilerplate/issues/440 482 | */ 483 | 484 | audio, 485 | canvas, 486 | iframe, 487 | img, 488 | svg, 489 | video { 490 | vertical-align: middle; 491 | } 492 | 493 | /* 494 | * Remove default fieldset styles. 495 | */ 496 | 497 | fieldset { 498 | border: 0; 499 | margin: 0; 500 | padding: 0; 501 | } 502 | 503 | /* 504 | * Allow only vertical resizing of textareas. 505 | */ 506 | 507 | textarea { 508 | resize: vertical; 509 | } 510 | 511 | /* ========================================================================== 512 | Browser Upgrade Prompt 513 | ========================================================================== */ 514 | 515 | .browserupgrade { 516 | margin: 0.2em 0; 517 | background: #ccc; 518 | color: #000; 519 | padding: 0.2em 0; 520 | } 521 | 522 | /* ========================================================================== 523 | Author's custom styles 524 | ========================================================================== */ 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | /* ========================================================================== 543 | Helper classes 544 | ========================================================================== */ 545 | 546 | /* 547 | * Hide visually and from screen readers: 548 | */ 549 | 550 | .hidden { 551 | display: none !important; 552 | } 553 | 554 | /* 555 | * Hide only visually, but have it available for screen readers: 556 | * http://snook.ca/archives/html_and_css/hiding-content-for-accessibility 557 | */ 558 | 559 | .visuallyhidden { 560 | border: 0; 561 | clip: rect(0 0 0 0); 562 | height: 1px; 563 | margin: -1px; 564 | overflow: hidden; 565 | padding: 0; 566 | position: absolute; 567 | width: 1px; 568 | } 569 | 570 | /* 571 | * Extends the .visuallyhidden class to allow the element 572 | * to be focusable when navigated to via the keyboard: 573 | * https://www.drupal.org/node/897638 574 | */ 575 | 576 | .visuallyhidden.focusable:active, 577 | .visuallyhidden.focusable:focus { 578 | clip: auto; 579 | height: auto; 580 | margin: 0; 581 | overflow: visible; 582 | position: static; 583 | width: auto; 584 | } 585 | 586 | /* 587 | * Hide visually and from screen readers, but maintain layout 588 | */ 589 | 590 | .invisible { 591 | visibility: hidden; 592 | } 593 | 594 | /* 595 | * Clearfix: contain floats 596 | * 597 | * For modern browsers 598 | * 1. The space content is one way to avoid an Opera bug when the 599 | * `contenteditable` attribute is included anywhere else in the document. 600 | * Otherwise it causes space to appear at the top and bottom of elements 601 | * that receive the `clearfix` class. 602 | * 2. The use of `table` rather than `block` is only necessary if using 603 | * `:before` to contain the top-margins of child elements. 604 | */ 605 | 606 | .clearfix:before, 607 | .clearfix:after { 608 | content: " "; /* 1 */ 609 | display: table; /* 2 */ 610 | } 611 | 612 | .clearfix:after { 613 | clear: both; 614 | } 615 | 616 | /* ========================================================================== 617 | EXAMPLE Media Queries for Responsive Design. 618 | These examples override the primary ('mobile first') styles. 619 | Modify as content requires. 620 | ========================================================================== */ 621 | 622 | @media only screen and (min-width: 35em) { 623 | /* Style adjustments for viewports that meet the condition */ 624 | } 625 | 626 | @media print, 627 | (-o-min-device-pixel-ratio: 5/4), 628 | (-webkit-min-device-pixel-ratio: 1.25), 629 | (min-resolution: 120dpi) { 630 | /* Style adjustments for high resolution devices */ 631 | } 632 | 633 | /* ========================================================================== 634 | Print styles. 635 | Inlined to avoid the additional HTTP request: 636 | http://www.phpied.com/delay-loading-your-print-css/ 637 | ========================================================================== */ 638 | 639 | @media print { 640 | *, 641 | *:before, 642 | *:after { 643 | background: transparent !important; 644 | color: #000 !important; /* Black prints faster: 645 | http://www.sanbeiji.com/archives/953 */ 646 | box-shadow: none !important; 647 | text-shadow: none !important; 648 | } 649 | 650 | a, 651 | a:visited { 652 | text-decoration: underline; 653 | } 654 | 655 | a[href]:after { 656 | content: " (" attr(href) ")"; 657 | } 658 | 659 | abbr[title]:after { 660 | content: " (" attr(title) ")"; 661 | } 662 | 663 | /* 664 | * Don't show links that are fragment identifiers, 665 | * or use the `javascript:` pseudo protocol 666 | */ 667 | 668 | a[href^="#"]:after, 669 | a[href^="javascript:"]:after { 670 | content: ""; 671 | } 672 | 673 | pre, 674 | blockquote { 675 | border: 1px solid #999; 676 | page-break-inside: avoid; 677 | } 678 | 679 | /* 680 | * Printing Tables: 681 | * http://css-discuss.incutio.com/wiki/Printing_Tables 682 | */ 683 | 684 | thead { 685 | display: table-header-group; 686 | } 687 | 688 | tr, 689 | img { 690 | page-break-inside: avoid; 691 | } 692 | 693 | img { 694 | max-width: 100% !important; 695 | } 696 | 697 | p, 698 | h2, 699 | h3 { 700 | orphans: 3; 701 | widows: 3; 702 | } 703 | 704 | h2, 705 | h3 { 706 | page-break-after: avoid; 707 | } 708 | } -------------------------------------------------------------------------------- /dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 79 | 80 | 81 |

Press "D" to show debug info

82 |
83 |

Inspiration: bla bla | bla bla

84 |

by @silviopaganini | FLUUUID | fork on github

85 |

tech stack: three.js, glslify, perlin-noise 86 |

87 | 88 | 89 | 90 | 91 | 101 | 102 | 103 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rapid-prototyping", 3 | "version": "1.0.6", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "budo --dir dist/ src/index.js:js/bundle.js -v --live --open -- -t [ babelify --presets [ es2015 ] ] -t glslify", 9 | "build": "browserify -t [ babelify --presets [ es2015 ] ] -t glslify src/index.js | uglifyjs -cm > dist/js/bundle.js" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/silviopaganini/rapid-prototype" 14 | }, 15 | "bugs": { 16 | "url": "https://github.com/silviopaganini/rapid-prototype/issues" 17 | }, 18 | "author": "silvio paganini | @silviopaganini", 19 | "license": "ISC", 20 | "dependencies": { 21 | "dat-gui": "^0.5.0", 22 | "stats-js": "^1.0.0-alpha1", 23 | "three-orbit-controls": "^72.0.0", 24 | "three": "^0.74.0", 25 | "babel-preset-es2015": "^6.3.13", 26 | "babelify": "^7.2.0", 27 | "browserify": "^13.0.0", 28 | "glslify": "^5.0.2" 29 | }, 30 | "devDependencies": { 31 | "budo": "^8.0.3", 32 | "uglifyjs": "^2.4.10" 33 | }, 34 | "engines": { 35 | "node": ">= 5.6.0", 36 | "npm": ">=3.6.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/App.js: -------------------------------------------------------------------------------- 1 | import dat from 'dat-gui' 2 | import Stats from 'stats-js' 3 | import THREE from 'three' 4 | 5 | const OrbitControls = require('three-orbit-controls')(THREE); 6 | const glslify = require('glslify'); 7 | require('./post-processing/EffectComposer')(THREE); 8 | 9 | class App { 10 | 11 | constructor() 12 | { 13 | this.renderer = null; 14 | this.camera = null; 15 | this.scene = null; 16 | this.counter = 0; 17 | this.gui = null; 18 | this.clock = new THREE.Clock(); 19 | this.DEBUG = true; 20 | this.SIZE = { 21 | w : window.innerWidth , 22 | w2 : window.innerWidth / 2, 23 | h : window.innerHeight, 24 | h2 : window.innerHeight / 2 25 | }; 26 | 27 | this.startStats(); 28 | this.createRender(); 29 | this.createScene(); 30 | this.addComposer(); 31 | this.addObjects(); 32 | this.startGUI(); 33 | 34 | this.onResize(); 35 | this.update(); 36 | } 37 | 38 | startStats() 39 | { 40 | this.stats = new Stats(); 41 | this.stats.domElement.style.position = 'absolute'; 42 | this.stats.domElement.style.top = 0; 43 | this.stats.domElement.style.display = this.DEBUG ? 'block' : 'none'; 44 | this.stats.domElement.style.left = 0; 45 | this.stats.domElement.style.zIndex = 50; 46 | document.body.appendChild(this.stats.domElement); 47 | document.querySelector('.help').style.display = this.stats.domElement.style.display == 'block' ? "none" : "block"; 48 | } 49 | 50 | createRender() 51 | { 52 | this.renderer = new THREE.WebGLRenderer( { 53 | antialias : false, 54 | depth : true, 55 | } ); 56 | 57 | this.renderer.setClearColor( 0x000000 ); 58 | this.renderer.setClearAlpha( 0 ); 59 | // this.renderer.setPixelRatio( window.devicePixelRatio || 1 ) 60 | this.renderer.setSize(window.innerWidth, window.innerHeight); 61 | this.renderer.gammaInput = true; 62 | this.renderer.gammaOuput = true; 63 | this.renderer.autoClear = false; 64 | 65 | document.body.appendChild(this.renderer.domElement) 66 | } 67 | 68 | addComposer() 69 | { 70 | this.composer = new THREE.EffectComposer(this.renderer); 71 | 72 | let scenePass = new THREE.RenderPass( this.scene, this.camera, false, 0x000000, 0 ); 73 | 74 | this.gamma = { 75 | uniforms: { 76 | tDiffuse : {type: "t", value: null }, 77 | resolution : {type: 'v2', value: new THREE.Vector2( 78 | window.innerWidth * (window.devicePixelRatio || 1), 79 | window.innerHeight * (window.devicePixelRatio || 1) 80 | )}, 81 | }, 82 | vertexShader : glslify('./post-processing/glsl/screen_vert.glsl'), 83 | fragmentShader : glslify('./post-processing/glsl/gamma.glsl'), 84 | } 85 | 86 | /* 87 | passes 88 | */ 89 | 90 | this.composer.addPass(scenePass); 91 | 92 | let gamma = new THREE.ShaderPass(this.gamma); 93 | gamma.renderToScreen = true; 94 | this.composer.addPass(gamma); 95 | 96 | } 97 | 98 | createScene() 99 | { 100 | // OrthographicCamera 101 | // this.camera = new THREE.OrthographicCamera( this.SIZE.w / - 2, this.SIZE.w / 2, this.SIZE.h / 2, this.SIZE.h / - 2, 1, 1000 ); 102 | 103 | this.camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.01, 4000 ); 104 | this.camera.position.set(0, 40, 200); 105 | 106 | this.controls = new OrbitControls(this.camera, this.renderer.domElement); 107 | this.controls.enabled = this.DEBUG; 108 | this.controls.maxDistance = 500; 109 | this.controls.minDistance = 50; 110 | 111 | this.scene = new THREE.Scene(); 112 | } 113 | 114 | addObjects() 115 | { 116 | let gridHelper = new THREE.GridHelper( 100, 10 ); 117 | this.scene.add( gridHelper ); 118 | 119 | /* 120 | example of shader material using glslify 121 | 122 | this.shader = new THREE.ShaderMaterial({ 123 | vertexShader : glslify('./glsl/basic_vert.glsl'), 124 | fragmentShader : glslify('./glsl/basic_frag.glsl'), 125 | }) 126 | 127 | */ 128 | } 129 | 130 | startGUI() 131 | { 132 | this.gui = new dat.GUI() 133 | this.gui.domElement.style.display = this.DEBUG ? 'block' : 'none'; 134 | 135 | let cameraFolder = this.gui.addFolder('Camera'); 136 | cameraFolder.add(this.camera.position, 'x', -400, 400); 137 | cameraFolder.add(this.camera.position, 'y', -400, 400); 138 | cameraFolder.add(this.camera.position, 'z', -400, 400); 139 | 140 | } 141 | 142 | update() 143 | { 144 | this.stats.begin(); 145 | 146 | let el = this.clock.getElapsedTime() * .05; 147 | let d = this.clock.getDelta(); 148 | 149 | this.renderer.clear(); 150 | 151 | // this.renderer.render(this.scene, this.camera); 152 | this.composer.render(d); 153 | 154 | this.stats.end() 155 | requestAnimationFrame(this.update.bind(this)); 156 | } 157 | 158 | /* 159 | events 160 | */ 161 | 162 | onKeyUp(e) 163 | { 164 | let key = e.which || e.keyCode; 165 | switch(key) 166 | { 167 | // leter D 168 | case 68: 169 | this.DEBUG = !this.DEBUG; 170 | if(this.stats) this.stats.domElement.style.display = !this.DEBUG ? "none" : "block"; 171 | if(this.gui) this.gui.domElement.style.display = !this.DEBUG ? "none" : "block"; 172 | if(this.controls) this.controls.enabled = this.DEBUG; 173 | if(document.querySelector('.help')) document.querySelector('.help').style.display = this.DEBUG ? "none" : "block"; 174 | break; 175 | } 176 | } 177 | 178 | onResize() 179 | { 180 | this.SIZE = { 181 | w : window.innerWidth , 182 | w2 : window.innerWidth / 2, 183 | h : window.innerHeight, 184 | h2 : window.innerHeight / 2 185 | }; 186 | 187 | // OrthographicCamera 188 | // this.camera.left = this.SIZE.w / - 2; 189 | // this.camera.right = this.SIZE.w / 2; 190 | // this.camera.top = this.SIZE.h / 2; 191 | // this.camera.bottom = this.SIZE.h / - 2; 192 | 193 | this.renderer.setSize(this.SIZE.w, this.SIZE.h); 194 | this.camera.aspect = this.SIZE.w / this.SIZE.h; 195 | this.camera.updateProjectionMatrix(); 196 | } 197 | } 198 | 199 | export default App; 200 | -------------------------------------------------------------------------------- /src/glsl/basic_frag.glsl: -------------------------------------------------------------------------------- 1 | uniform vec3 color; 2 | 3 | void main() { 4 | gl_FragColor = vec4( color , 1.0 ); 5 | // gl_FragColor = gl_FragColor * texture2D( texture, vUv ); 6 | } -------------------------------------------------------------------------------- /src/glsl/basic_vert.glsl: -------------------------------------------------------------------------------- 1 | // varying vec2 vUv; 2 | 3 | void main() 4 | { 5 | // vUv = uv; 6 | vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); 7 | gl_Position = projectionMatrix * mvPosition; 8 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import App from './App'; 2 | 3 | const app = new App(); 4 | window.onresize = app.onResize.bind(app); 5 | window.onkeyup = app.onKeyUp.bind(app); -------------------------------------------------------------------------------- /src/post-processing/EffectComposer.js: -------------------------------------------------------------------------------- 1 | module.exports = function(THREE) 2 | { 3 | 4 | /** 5 | * @author alteredq / http://alteredqualia.com/ 6 | * 7 | * Full-screen textured quad shader 8 | */ 9 | 10 | THREE.CopyShader = { 11 | 12 | uniforms: { 13 | 14 | "tDiffuse": { type: "t", value: null }, 15 | "opacity": { type: "f", value: 1.0 } 16 | 17 | }, 18 | 19 | vertexShader: [ 20 | 21 | "varying vec2 vUv;", 22 | 23 | "void main() {", 24 | 25 | "vUv = uv;", 26 | "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", 27 | 28 | "}" 29 | 30 | ].join( "\n" ), 31 | 32 | fragmentShader: [ 33 | 34 | "uniform float opacity;", 35 | 36 | "uniform sampler2D tDiffuse;", 37 | 38 | "varying vec2 vUv;", 39 | 40 | "void main() {", 41 | 42 | "vec4 texel = texture2D( tDiffuse, vUv );", 43 | "gl_FragColor = opacity * texel;", 44 | 45 | "}" 46 | 47 | ].join( "\n" ) 48 | 49 | }; 50 | 51 | THREE.EffectComposer = function ( renderer, renderTarget ) { 52 | 53 | this.renderer = renderer; 54 | 55 | if ( renderTarget === undefined ) { 56 | 57 | var pixelRatio = renderer.getPixelRatio(); 58 | 59 | var width = Math.floor( renderer.context.canvas.width / pixelRatio ) || 1; 60 | var height = Math.floor( renderer.context.canvas.height / pixelRatio ) || 1; 61 | var parameters = { 62 | minFilter: THREE.LinearFilter, 63 | magFilter: THREE.LinearFilter, 64 | stencilBuffer: false , 65 | blending: THREE.CustomBlending, 66 | blendSrc: THREE.SrcAlphaFactor, 67 | blendDst: THREE.OneFactor, 68 | }; 69 | 70 | renderTarget = new THREE.WebGLRenderTarget( width, height, parameters ); 71 | renderTarget.texture.format = THREE.RGBAFormat; 72 | } 73 | 74 | this.renderTarget1 = renderTarget; 75 | this.renderTarget2 = renderTarget.clone(); 76 | 77 | this.writeBuffer = this.renderTarget1; 78 | this.readBuffer = this.renderTarget2; 79 | 80 | this.passes = []; 81 | 82 | if ( THREE.CopyShader === undefined ) 83 | console.error( "THREE.EffectComposer relies on THREE.CopyShader" ); 84 | 85 | this.copyPass = new THREE.ShaderPass( THREE.CopyShader ); 86 | 87 | }; 88 | 89 | THREE.EffectComposer.prototype = { 90 | 91 | swapBuffers: function() { 92 | 93 | var tmp = this.readBuffer; 94 | this.readBuffer = this.writeBuffer; 95 | this.writeBuffer = tmp; 96 | 97 | }, 98 | 99 | addPass: function ( pass ) { 100 | 101 | this.passes.push( pass ); 102 | 103 | }, 104 | 105 | insertPass: function ( pass, index ) { 106 | 107 | this.passes.splice( index, 0, pass ); 108 | 109 | }, 110 | 111 | render: function ( delta ) { 112 | 113 | this.writeBuffer = this.renderTarget1; 114 | this.readBuffer = this.renderTarget2; 115 | 116 | var maskActive = false; 117 | 118 | var pass, i, il = this.passes.length; 119 | 120 | for ( i = 0; i < il; i ++ ) { 121 | 122 | pass = this.passes[ i ]; 123 | // console.log(pass) 124 | 125 | if ( ! pass.enabled ) continue; 126 | 127 | pass.render( this.renderer, this.writeBuffer, this.readBuffer, delta, maskActive ); 128 | 129 | if ( pass.needsSwap ) { 130 | 131 | if ( maskActive ) { 132 | 133 | var context = this.renderer.context; 134 | 135 | context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff ); 136 | 137 | this.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, delta ); 138 | 139 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); 140 | 141 | } 142 | 143 | this.swapBuffers(); 144 | 145 | } 146 | 147 | if ( pass instanceof THREE.MaskPass ) { 148 | 149 | maskActive = true; 150 | 151 | } else if ( pass instanceof THREE.ClearMaskPass ) { 152 | 153 | maskActive = false; 154 | 155 | } 156 | 157 | } 158 | 159 | }, 160 | 161 | reset: function ( renderTarget ) { 162 | 163 | if ( renderTarget === undefined ) { 164 | 165 | renderTarget = this.renderTarget1.clone(); 166 | 167 | var pixelRatio = this.renderer.getPixelRatio(); 168 | 169 | renderTarget.width = Math.floor( this.renderer.context.canvas.width / pixelRatio ); 170 | renderTarget.height = Math.floor( this.renderer.context.canvas.height / pixelRatio ); 171 | 172 | } 173 | 174 | this.renderTarget1.dispose(); 175 | this.renderTarget1 = renderTarget; 176 | this.renderTarget2.dispose(); 177 | this.renderTarget2 = renderTarget.clone(); 178 | 179 | this.writeBuffer = this.renderTarget1; 180 | this.readBuffer = this.renderTarget2; 181 | 182 | }, 183 | 184 | setSize: function ( width, height ) { 185 | 186 | this.renderTarget1.setSize( width, height ); 187 | this.renderTarget2.setSize( width, height ); 188 | 189 | } 190 | 191 | }; 192 | 193 | 194 | THREE.ShaderPass = function ( shader, textureID ) { 195 | 196 | this.textureID = ( textureID !== undefined ) ? textureID : "tDiffuse"; 197 | 198 | this.uniforms = THREE.UniformsUtils.clone( shader.uniforms ); 199 | 200 | this.material = new THREE.ShaderMaterial( { 201 | 202 | defines: shader.defines || {}, 203 | uniforms: this.uniforms, 204 | vertexShader: shader.vertexShader, 205 | fragmentShader: shader.fragmentShader, 206 | 207 | } ); 208 | 209 | this.renderToScreen = false; 210 | 211 | this.enabled = true; 212 | this.needsSwap = true; 213 | this.clear = false; 214 | 215 | 216 | this.camera = new THREE.OrthographicCamera( - 1, 1, 1, - 1, 0, 1 ); 217 | this.scene = new THREE.Scene(); 218 | 219 | this.quad = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), null ); 220 | this.scene.add( this.quad ); 221 | 222 | }; 223 | 224 | THREE.ShaderPass.prototype = { 225 | 226 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 227 | 228 | if ( this.uniforms[ this.textureID ] ) { 229 | 230 | this.uniforms[ this.textureID ].value = readBuffer; 231 | 232 | } 233 | 234 | this.quad.material = this.material; 235 | 236 | if ( this.renderToScreen ) { 237 | 238 | renderer.render( this.scene, this.camera ); 239 | 240 | } else { 241 | 242 | renderer.render( this.scene, this.camera, writeBuffer, this.clear ); 243 | 244 | } 245 | 246 | } 247 | 248 | }; 249 | 250 | /** 251 | * @author alteredq / http://alteredqualia.com/ 252 | */ 253 | 254 | THREE.MaskPass = function ( scene, camera ) { 255 | 256 | this.scene = scene; 257 | this.camera = camera; 258 | 259 | this.enabled = true; 260 | this.clear = true; 261 | this.needsSwap = false; 262 | 263 | this.inverse = false; 264 | 265 | }; 266 | 267 | THREE.MaskPass.prototype = { 268 | 269 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 270 | 271 | var context = renderer.context; 272 | 273 | // don't update color or depth 274 | 275 | context.colorMask( false, false, false, false ); 276 | context.depthMask( false ); 277 | 278 | // set up stencil 279 | 280 | var writeValue, clearValue; 281 | 282 | if ( this.inverse ) { 283 | 284 | writeValue = 0; 285 | clearValue = 1; 286 | 287 | } else { 288 | 289 | writeValue = 1; 290 | clearValue = 0; 291 | 292 | } 293 | 294 | context.enable( context.STENCIL_TEST ); 295 | context.stencilOp( context.REPLACE, context.REPLACE, context.REPLACE ); 296 | context.stencilFunc( context.ALWAYS, writeValue, 0xffffffff ); 297 | context.clearStencil( clearValue ); 298 | 299 | // draw into the stencil buffer 300 | 301 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 302 | renderer.render( this.scene, this.camera, writeBuffer, this.clear ); 303 | 304 | // re-enable update of color and depth 305 | 306 | context.colorMask( true, true, true, true ); 307 | context.depthMask( true ); 308 | 309 | // only render where stencil is set to 1 310 | 311 | context.stencilFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1 312 | context.stencilOp( context.KEEP, context.KEEP, context.KEEP ); 313 | 314 | } 315 | 316 | }; 317 | 318 | 319 | THREE.ClearMaskPass = function () { 320 | 321 | this.enabled = true; 322 | 323 | }; 324 | 325 | THREE.ClearMaskPass.prototype = { 326 | 327 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 328 | 329 | var context = renderer.context; 330 | 331 | context.disable( context.STENCIL_TEST ); 332 | 333 | } 334 | 335 | }; 336 | 337 | /** 338 | * @author alteredq / http://alteredqualia.com/ 339 | */ 340 | 341 | THREE.RenderPass = function ( scene, camera, overrideMaterial, clearColor, clearAlpha ) { 342 | 343 | this.scene = scene; 344 | this.camera = camera; 345 | 346 | this.overrideMaterial = overrideMaterial; 347 | 348 | this.clearColor = clearColor; 349 | this.clearAlpha = ( clearAlpha !== undefined ) ? clearAlpha : 1; 350 | 351 | this.oldClearColor = new THREE.Color(); 352 | this.oldClearAlpha = 1; 353 | 354 | this.enabled = true; 355 | this.clear = true; 356 | this.needsSwap = false; 357 | 358 | }; 359 | 360 | THREE.RenderPass.prototype = { 361 | 362 | render: function ( renderer, writeBuffer, readBuffer, delta ) { 363 | 364 | this.scene.overrideMaterial = this.overrideMaterial; 365 | 366 | if ( this.clearColor ) { 367 | 368 | this.oldClearColor.copy( renderer.getClearColor() ); 369 | this.oldClearAlpha = renderer.getClearAlpha(); 370 | 371 | renderer.setClearColor( this.clearColor, this.clearAlpha ); 372 | renderer.setClearAlpha(0); 373 | 374 | } 375 | 376 | renderer.render( this.scene, this.camera, readBuffer, this.clear ); 377 | 378 | if ( this.clearColor ) { 379 | 380 | renderer.setClearColor( this.oldClearColor, this.oldClearAlpha ); 381 | renderer.setClearAlpha(0); 382 | 383 | } 384 | 385 | this.scene.overrideMaterial = null; 386 | 387 | } 388 | 389 | }; 390 | 391 | 392 | } 393 | -------------------------------------------------------------------------------- /src/post-processing/glsl/fxaa.glsl: -------------------------------------------------------------------------------- 1 | float FXAA_REDUCE_MIN = (1.0/128.0); 2 | float FXAA_REDUCE_MUL = (1.0/8.0); 3 | float FXAA_SPAN_MAX = 8.0; 4 | 5 | vec4 fxaa(sampler2D tDiffuse, vec2 xyFragCoord, vec2 res) { 6 | 7 | vec2 resolution = vec2( 1.0/res.x, 1.0/res.y ); 8 | vec4 color; 9 | 10 | vec3 rgbNW = texture2D( tDiffuse, ( xyFragCoord + vec2( -1.0, -1.0 ) ) * resolution ).xyz; 11 | vec3 rgbNE = texture2D( tDiffuse, ( xyFragCoord + vec2( 1.0, -1.0 ) ) * resolution ).xyz; 12 | vec3 rgbSW = texture2D( tDiffuse, ( xyFragCoord + vec2( -1.0, 1.0 ) ) * resolution ).xyz; 13 | vec3 rgbSE = texture2D( tDiffuse, ( xyFragCoord + vec2( 1.0, 1.0 ) ) * resolution ).xyz; 14 | vec4 rgbaM = texture2D( tDiffuse, xyFragCoord * resolution ); 15 | vec3 rgbM = rgbaM.xyz; 16 | vec3 luma = vec3( 0.299, 0.587, 0.114 ); 17 | 18 | float lumaNW = dot( rgbNW, luma ); 19 | float lumaNE = dot( rgbNE, luma ); 20 | float lumaSW = dot( rgbSW, luma ); 21 | float lumaSE = dot( rgbSE, luma ); 22 | float lumaM = dot( rgbM, luma ); 23 | float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) ); 24 | float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) ); 25 | 26 | vec2 dir; 27 | dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); 28 | dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); 29 | 30 | float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN ); 31 | float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce ); 32 | dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX), max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * resolution; 33 | vec4 rgbA = (1.0/2.0) * ( 34 | texture2D(tDiffuse, xyFragCoord * resolution + dir * (1.0/3.0 - 0.5)) + 35 | texture2D(tDiffuse, xyFragCoord * resolution + dir * (2.0/3.0 - 0.5))); 36 | vec4 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * ( 37 | texture2D(tDiffuse, xyFragCoord * resolution + dir * (0.0/3.0 - 0.5)) + 38 | texture2D(tDiffuse, xyFragCoord * resolution + dir * (3.0/3.0 - 0.5))); 39 | float lumaB = dot(rgbB, vec4(luma, 0.0)); 40 | 41 | if(( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) { 42 | color = rgbA; 43 | }else{ 44 | color = rgbB; 45 | } 46 | 47 | return color; 48 | } 49 | 50 | #pragma glslify: export(fxaa) -------------------------------------------------------------------------------- /src/post-processing/glsl/gamma.glsl: -------------------------------------------------------------------------------- 1 | #pragma glslify: fxaa = require('./fxaa.glsl') 2 | 3 | varying vec2 vUv; 4 | uniform sampler2D tDiffuse; 5 | uniform vec2 resolution; 6 | 7 | void main() { 8 | 9 | vec2 fragCoord = vUv * resolution; 10 | vec4 texel = fxaa(tDiffuse, fragCoord, resolution); 11 | 12 | vec2 res = (gl_FragCoord.xy / resolution.xy) - vec2(0.5); 13 | res.x *= resolution.x / resolution.y; 14 | 15 | // vec4 texel = texture2D( tDiffuse, vUv ); 16 | 17 | // vignette 18 | // float len = length(res); 19 | // float vignette = smoothstep(.85, .5, len); 20 | // texel = pow(texel, vec4(3.)) * vignette; 21 | 22 | gl_FragColor = texel; 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/post-processing/glsl/screen_frag.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | uniform sampler2D tDiffuse; 3 | 4 | void main() { 5 | 6 | gl_FragColor = texture2D( tDiffuse, vUv ); 7 | 8 | } -------------------------------------------------------------------------------- /src/post-processing/glsl/screen_vert.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() { 4 | vUv = uv; 5 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 ); 6 | } --------------------------------------------------------------------------------