├── .gitignore
├── .jshintrc
├── LICENSE.md
├── README.md
├── app
├── css
│ ├── index.css
│ └── normalize.css
├── favicon.ico
├── images
│ ├── diffuse.jpg
│ ├── env.jpg
│ ├── logo.png
│ ├── screenshot.jpg
│ └── share.jpg
├── index.html
├── js
│ └── three.r74.dev.js
└── models
│ ├── LeePerrySmith.json
│ └── horse.json
├── build.js
├── build.sh
├── dev.js
├── dev.sh
├── package.json
└── src
├── 3d
├── fbo.js
├── ground.js
├── head.js
├── lights.js
└── vignette.js
├── controls
└── OrbitControls.js
├── core
└── settings.js
├── fallback
└── mobile.js
├── glsl
├── fbo.vert
├── fboThrough.frag
├── head.frag
├── head.vert
├── headDepth.frag
├── headDepth.vert
├── noise.glsl
├── particle.frag
├── particle.vert
├── position.frag
├── velocity.frag
├── vignette.frag
└── vignette.vert
├── helpers
└── shaderParse.js
├── index.js
├── libs
└── global_three
│ ├── index.js
│ └── package.json
└── utils
├── ease.js
└── math.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 | *.pyc
3 | *.pyo
4 | =======
5 | # Compiled source #
6 | ###################
7 | *.com
8 | *.class
9 | *.dll
10 | *.exe
11 | *.o
12 | *.so
13 | .sass-cache
14 |
15 |
16 | # Packages #
17 | ############
18 | # it's better to unpack these files and commit the raw source
19 | # git has its own built in compression methods
20 | *.7z
21 | *.dmg
22 | *.gz
23 | *.iso
24 | *.jar
25 | *.rar
26 | *.tar
27 | # Logs and databases #
28 | ######################
29 | *.log
30 | #*.sql
31 | *.sqlite
32 |
33 | # OS generated files #
34 | ######################
35 | .DS_Store
36 | .DS_Store?
37 | ._*
38 | .Spotlight-V100
39 | .Trashes
40 | ehthumbs.db
41 | Thumbs.db
42 |
43 | *.sublime-project
44 | *.sublime-workspace
45 |
46 | /node_modules
47 |
--------------------------------------------------------------------------------
/.jshintrc:
--------------------------------------------------------------------------------
1 | {
2 | // JSHint Default Configuration File (as on JSHint website)
3 | // See http://jshint.com/docs/ for more details
4 |
5 | "maxerr" : 50, // {int} Maximum error before stopping
6 |
7 | // Enforcing
8 | "bitwise" : false, // true: Prohibit bitwise operators (&, |, ^, etc.)
9 | "camelcase" : false, // true: Identifiers must be in camelCase
10 | "curly" : false, // true: Require {} for every new block or scope
11 | "eqeqeq" : false, // true: Require triple equals (===) for comparison
12 | "forin" : false, // true: Require filtering for..in loops with obj.hasOwnProperty()
13 | "freeze" : true, // true: prohibits overwriting prototypes of native objects such as Array, Date etc.
14 | "immed" : false, // true: Require immediate invocations to be wrapped in parens e.g. `(function () { } ());`
15 | "indent" : 4, // {int} Number of spaces to use for indentation
16 | "latedef" : false, // true: Require variables/functions to be defined before being used
17 | "newcap" : false, // true: Require capitalization of all constructor functions e.g. `new F()`
18 | "noarg" : true, // true: Prohibit use of `arguments.caller` and `arguments.callee`
19 | "noempty" : true, // true: Prohibit use of empty blocks
20 | "nonbsp" : true, // true: Prohibit "non-breaking whitespace" characters.
21 | "nonew" : false, // true: Prohibit use of constructors for side-effects (without assignment)
22 | "plusplus" : false, // true: Prohibit use of `++` & `--`
23 | "quotmark" : false, // Quotation mark consistency:
24 | // false : do nothing (default)
25 | // true : ensure whatever is used is consistent
26 | // "single" : require single quotes
27 | // "double" : require double quotes
28 | "undef" : true, // true: Require all non-global variables to be declared (prevents global leaks)
29 | "unused" : true, // Unused variables:
30 | // true : all variables, last function parameter
31 | // "vars" : all variables only
32 | // "strict" : all variables, all function parameters
33 | "strict" : false, // true: Requires all functions run in ES5 Strict Mode
34 | "maxparams" : false, // {int} Max number of formal params allowed per function
35 | "maxdepth" : false, // {int} Max depth of nested blocks (within functions)
36 | "maxstatements" : false, // {int} Max number statements per function
37 | "maxcomplexity" : false, // {int} Max cyclomatic complexity per function
38 | "maxlen" : false, // {int} Max number of characters per line
39 |
40 | // Relaxing
41 | "asi" : false, // true: Tolerate Automatic Semicolon Insertion (no semicolons)
42 | "boss" : false, // true: Tolerate assignments where comparisons would be expected
43 | "debug" : false, // true: Allow debugger statements e.g. browser breakpoints.
44 | "eqnull" : false, // true: Tolerate use of `== null`
45 | "es5" : true, // true: Allow ES5 syntax (ex: getters and setters)
46 | "esnext" : true, // true: Allow ES.next (ES6) syntax (ex: `const`)
47 | "moz" : false, // true: Allow Mozilla specific syntax (extends and overrides esnext features)
48 | // (ex: `for each`, multiple try/catch, function expression…)
49 | "evil" : false, // true: Tolerate use of `eval` and `new Function()`
50 | "expr" : false, // true: Tolerate `ExpressionStatement` as Programs
51 | "funcscope" : false, // true: Tolerate defining variables inside control statements
52 | "globalstrict" : false, // true: Allow global "use strict" (also enables 'strict')
53 | "iterator" : false, // true: Tolerate using the `__iterator__` property
54 | "lastsemic" : false, // true: Tolerate omitting a semicolon for the last statement of a 1-line block
55 | "laxbreak" : false, // true: Tolerate possibly unsafe line breakings
56 | "laxcomma" : false, // true: Tolerate comma-first style coding
57 | "loopfunc" : false, // true: Tolerate functions being defined in loops
58 | "multistr" : false, // true: Tolerate multi-line strings
59 | "noyield" : false, // true: Tolerate generator functions with no yield statement in them.
60 | "notypeof" : false, // true: Tolerate invalid typeof operator values
61 | "proto" : false, // true: Tolerate using the `__proto__` property
62 | "scripturl" : false, // true: Tolerate script-targeted URLs
63 | "shadow" : false, // true: Allows re-define variables later in code e.g. `var x=1; x=2;`
64 | "sub" : false, // true: Tolerate using `[]` notation when it can still be expressed in dot notation
65 | "supernew" : false, // true: Tolerate `new function () { ... };` and `new Object;`
66 | "validthis" : true, // true: Tolerate using this in a non-constructor function
67 |
68 | // Environments
69 | "browser" : true, // Web Browser (window, document, etc)
70 | "browserify" : true, // Browserify (node.js code in the browser)
71 | "couch" : false, // CouchDB
72 | "devel" : true, // Development/debugging (alert, confirm, etc)
73 | "dojo" : false, // Dojo Toolkit
74 | "jasmine" : false, // Jasmine
75 | "jquery" : false, // jQuery
76 | "mocha" : true, // Mocha
77 | "mootools" : false, // MooTools
78 | "node" : false, // Node.js
79 | "nonstandard" : false, // Widely adopted globals (escape, unescape, etc)
80 | "phantom" : false, // PhantomJS
81 | "prototypejs" : false, // Prototype and Scriptaculous
82 | "qunit" : false, // QUnit
83 | "rhino" : false, // Rhino
84 | "shelljs" : false, // ShellJS
85 | "typed" : false, // Globals for typed array constructions
86 | "worker" : false, // Web Workers
87 | "wsh" : false, // Windows Scripting Host
88 | "yui" : false, // Yahoo User Interface
89 |
90 | // Custom Globals
91 | "predef" : [
92 | ] // additional predefined global variables
93 | }
94 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Edan Kwan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## SMASHING Mega Scene
2 |
3 | 
4 |
5 | [Live demo](http://www.edankwan.com/experiments/smashing-mega-scene/) | [Video](https://www.youtube.com/watch?v=nR7uJdP_HRk)
6 |
7 | It uses **1024^2(Mega)** particles to form the 3d model and turns it into a **smashable** mesh.
8 |
9 | This repo is for personal demo only and the 3d model was obtained [here](http://graphics.cs.williams.edu/data/meshes.xml#14) and it is owned by its original author.
10 |
11 | ## Development and deployment
12 | - dev: `node dev`
13 | - deploy: `node build`
14 |
15 | ## License
16 | This experiment is under MIT License.
17 |
18 |
--------------------------------------------------------------------------------
/app/css/index.css:
--------------------------------------------------------------------------------
1 | html {
2 | position: absolute;
3 | width: 100%;
4 | height: 100%;
5 | overflow: hidden;
6 | font-family: 'Lato', sans-serif;
7 | background-color: #222;
8 | }
9 |
10 | body {
11 | position: relative;
12 | width: 100%;
13 | height: 100%;
14 | }
15 |
16 | * {
17 | box-sizing: border-box;
18 | }
19 |
20 | .mobile {
21 | display: none;
22 | position: absolute;
23 | width: 100%;
24 | top: 50%;
25 | padding: 0 30px;
26 |
27 | font-size: 14px;
28 | color: #fff;
29 |
30 | transform: translate3d(0, -50%, 0);
31 | }
32 |
33 | .mobile span {
34 | color: #ccc;
35 | text-decoration: underline;
36 | }
37 |
38 | .mobile a {
39 | color: #ccc;
40 | }
41 |
42 | .logo {
43 | position: absolute;
44 | left: 50%;
45 | top: 50%;
46 | width: 400px;
47 | height: 87px;
48 | margin-left: -200px;
49 | margin-top: -43px;
50 | background-size: 400px 87px;
51 | background-image: url(../images/logo.png);
52 | pointer-events: none;
53 | opacity: 0;
54 | }
55 | /*@media (max-width: 960px) {
56 | .logo {
57 | left: 50%;
58 | }
59 | }*/
60 |
61 | .footer {
62 | display: none;
63 | position: absolute;
64 | text-align: right;
65 | left: 0;
66 | width: 100%;
67 | bottom: 20px;
68 | padding-right: 20px;
69 | padding-left: 20px;
70 |
71 | font-size: 16px;
72 | color: #999;
73 | }
74 |
75 | .credit {
76 | float: left;
77 | }
78 |
79 | .footer span {
80 | display: inline-block;
81 | transform: translate3d(0, 50px, 0);
82 | }
83 |
84 | .footer a {
85 | color: #bbb;
86 | }
87 |
88 | html.is-white .footer {
89 | color: #000;
90 | }
91 | html.is-white .footer a {
92 | color: #121212;
93 | }
94 |
--------------------------------------------------------------------------------
/app/css/normalize.css:
--------------------------------------------------------------------------------
1 | /*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
2 |
3 | /**
4 | * 1. Set default font family to sans-serif.
5 | * 2. Prevent iOS and IE text size adjust after device orientation change,
6 | * without disabling 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/10/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 of focused elements when they are also in an
95 | * active/hover state.
96 | */
97 |
98 | a:active,
99 | a:hover {
100 | outline: 0;
101 | }
102 |
103 | /* Text-level semantics
104 | ========================================================================== */
105 |
106 | /**
107 | * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
108 | */
109 |
110 | abbr[title] {
111 | border-bottom: 1px dotted;
112 | }
113 |
114 | /**
115 | * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
116 | */
117 |
118 | b,
119 | strong {
120 | font-weight: bold;
121 | }
122 |
123 | /**
124 | * Address styling not present in Safari and Chrome.
125 | */
126 |
127 | dfn {
128 | font-style: italic;
129 | }
130 |
131 | /**
132 | * Address variable `h1` font-size and margin within `section` and `article`
133 | * contexts in Firefox 4+, Safari, and Chrome.
134 | */
135 |
136 | h1 {
137 | font-size: 2em;
138 | margin: 0.67em 0;
139 | }
140 |
141 | /**
142 | * Address styling not present in IE 8/9.
143 | */
144 |
145 | mark {
146 | background: #ff0;
147 | color: #000;
148 | }
149 |
150 | /**
151 | * Address inconsistent and variable font size in all browsers.
152 | */
153 |
154 | small {
155 | font-size: 80%;
156 | }
157 |
158 | /**
159 | * Prevent `sub` and `sup` affecting `line-height` in all browsers.
160 | */
161 |
162 | sub,
163 | sup {
164 | font-size: 75%;
165 | line-height: 0;
166 | position: relative;
167 | vertical-align: baseline;
168 | }
169 |
170 | sup {
171 | top: -0.5em;
172 | }
173 |
174 | sub {
175 | bottom: -0.25em;
176 | }
177 |
178 | /* Embedded content
179 | ========================================================================== */
180 |
181 | /**
182 | * Remove border when inside `a` element in IE 8/9/10.
183 | */
184 |
185 | img {
186 | border: 0;
187 | }
188 |
189 | /**
190 | * Correct overflow not hidden in IE 9/10/11.
191 | */
192 |
193 | svg:not(:root) {
194 | overflow: hidden;
195 | }
196 |
197 | /* Grouping content
198 | ========================================================================== */
199 |
200 | /**
201 | * Address margin not present in IE 8/9 and Safari.
202 | */
203 |
204 | figure {
205 | margin: 1em 40px;
206 | }
207 |
208 | /**
209 | * Address differences between Firefox and other browsers.
210 | */
211 |
212 | hr {
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 | */
355 |
356 | input[type="search"] {
357 | -webkit-appearance: textfield; /* 1 */
358 | box-sizing: content-box; /* 2 */
359 | }
360 |
361 | /**
362 | * Remove inner padding and search cancel button in Safari and Chrome on OS X.
363 | * Safari (but not Chrome) clips the cancel button when the search input has
364 | * padding (and `textfield` appearance).
365 | */
366 |
367 | input[type="search"]::-webkit-search-cancel-button,
368 | input[type="search"]::-webkit-search-decoration {
369 | -webkit-appearance: none;
370 | }
371 |
372 | /**
373 | * Define consistent border, margin, and padding.
374 | */
375 |
376 | fieldset {
377 | border: 1px solid #c0c0c0;
378 | margin: 0 2px;
379 | padding: 0.35em 0.625em 0.75em;
380 | }
381 |
382 | /**
383 | * 1. Correct `color` not being inherited in IE 8/9/10/11.
384 | * 2. Remove padding so people aren't caught out if they zero out fieldsets.
385 | */
386 |
387 | legend {
388 | border: 0; /* 1 */
389 | padding: 0; /* 2 */
390 | }
391 |
392 | /**
393 | * Remove default vertical scrollbar in IE 8/9/10/11.
394 | */
395 |
396 | textarea {
397 | overflow: auto;
398 | }
399 |
400 | /**
401 | * Don't inherit the `font-weight` (applied by a rule above).
402 | * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
403 | */
404 |
405 | optgroup {
406 | font-weight: bold;
407 | }
408 |
409 | /* Tables
410 | ========================================================================== */
411 |
412 | /**
413 | * Remove most spacing between table cells.
414 | */
415 |
416 | table {
417 | border-collapse: collapse;
418 | border-spacing: 0;
419 | }
420 |
421 | td,
422 | th {
423 | padding: 0;
424 | }
425 |
--------------------------------------------------------------------------------
/app/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/favicon.ico
--------------------------------------------------------------------------------
/app/images/diffuse.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/images/diffuse.jpg
--------------------------------------------------------------------------------
/app/images/env.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/images/env.jpg
--------------------------------------------------------------------------------
/app/images/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/images/logo.png
--------------------------------------------------------------------------------
/app/images/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/images/screenshot.jpg
--------------------------------------------------------------------------------
/app/images/share.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/edankwan/SMASHING-Mega-Scene/dd914d9c380c8841c458cb68e79701f4b98bc39b/app/images/share.jpg
--------------------------------------------------------------------------------
/app/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SMASHING Mega Scene
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
29 |
30 |
31 |
32 |
Sorry, this experiment is not designed for mobile devices. Please check out the video capture of this experiment instead. The source code is also accessible at Github .
33 |
Sorry for any inconvenience caused.
34 |
Cheers,
35 |
Edan Kwan .
36 |
37 |
38 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/build.js:
--------------------------------------------------------------------------------
1 | global.Promise = require('pinkie-promise');
2 | const browserify = require('browserify');
3 | const fs = require('fs');
4 | const UglifyJS = require('uglify-js');
5 |
6 | Promise.all(['index.js'].map(runBuild)).catch(function (err) {
7 | console.error(err);
8 | }).then(function () {
9 | console.log("Finished");
10 | });
11 |
12 | function runBuild (f) {
13 | return new Promise(function (resolve, reject) {
14 | console.log('Bundling', f);
15 | var b = browserify('src/' + f, {
16 | debug: false,
17 | // noparse: [ 'three' ]
18 | });
19 | // b.transform(require('babelify').configure({ presets: 'es2015' }));
20 | b.plugin(require('bundle-collapser/plugin'));
21 | var transforms = [['glslify', { global: true }]];
22 | transforms.forEach(function (t) {
23 | b.transform(t);
24 | });
25 | b.bundle(function (err, src) {
26 | if (err) return reject(err);
27 | console.log('Compressing', f);
28 | var result = UglifyJS.minify(src.toString(), { fromString: true });
29 | console.log('Writing', f);
30 | fs.writeFile('app/js/' + f, result.code, function (err) {
31 | if (err) return reject(err);
32 | resolve();
33 | });
34 | });
35 | });
36 | }
37 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | npm run build
2 |
--------------------------------------------------------------------------------
/dev.js:
--------------------------------------------------------------------------------
1 | const budo = require('budo');
2 | const path = require('path');
3 | const opn = require('opn');
4 | const fs = require('fs');
5 | const simpleHtml = require('simple-html-index');
6 |
7 | var entryPath = path.resolve('src', 'index.js');
8 | budo(entryPath, {
9 | serve: 'js/index.js',
10 | live: true,
11 | dir: __dirname + '/app',
12 | stream: process.stdout,
13 | defaultIndex: function (opt) {
14 | var html = 'index.html';
15 | if (!fs.existsSync(html)) return simpleHtml(opt);
16 | return fs.createReadStream(html);
17 | },
18 | browserify: {
19 | transform: [
20 | [ 'installify', { save: true } ],
21 | ['glslify', { global: true }]
22 | ]
23 | }
24 | }).on('connect', function(ev) {
25 | const uri = ev.uri + 'index.html';
26 | opn(uri);
27 | });
28 |
--------------------------------------------------------------------------------
/dev.sh:
--------------------------------------------------------------------------------
1 | npm run dev
2 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "budo-boilderplate",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "",
6 | "main": "index.js",
7 | "dependencies": {
8 | "computed-style": "0.3.0",
9 | "dat-gui": "0.5.0",
10 | "dom-css": "^1.1.1",
11 | "gl-matrix": "^2.3.1",
12 | "glsl-random": "^0.0.5",
13 | "glsl-noise": "^0.0.0",
14 | "incremental-convex-hull": "^1.0.1",
15 | "min-signal": "^0.0.5",
16 | "mout": "0.11",
17 | "quick-loader": "^0.1.4",
18 | "raf": "3.0.0",
19 | "stats.js": "mrdoob/stats.js",
20 | "three": "file:./src/libs/global_three/",
21 | "underscore": "^1.8.3",
22 | "ws": "^0.8.0"
23 | },
24 | "devDependencies": {
25 | "browserify": "^12.0.1",
26 | "budo": "^6.0.4",
27 | "bundle-collapser": "^1.2.1",
28 | "dirlist": "^1.0.2",
29 | "glslify": "^2.3.1",
30 | "hasha": "^2.0.2",
31 | "installify": "^1.0.2",
32 | "map-limit": "0.0.1",
33 | "minifyify": "^7.1.0",
34 | "minimist": "^1.2.0",
35 | "opn": "^3.0.2",
36 | "pinkie-promise": "^1.0.0",
37 | "simple-html-index": "^1.1.2",
38 | "uglify-js": "^2.5.0"
39 | },
40 | "scripts": {
41 | "dev": "node dev.js",
42 | "build": "node build.js"
43 | },
44 | "author": "",
45 | "license": "MIT"
46 | }
47 |
--------------------------------------------------------------------------------
/src/3d/fbo.js:
--------------------------------------------------------------------------------
1 | var settings = require('../core/settings');
2 | var THREE = require('three');
3 |
4 | var undef;
5 |
6 | var glslify = require('glslify');
7 | var shaderParse = require('../helpers/shaderParse');
8 |
9 | var _copyShader;
10 | var _velocityShader;
11 | var _positionShader;
12 | var _velocityRenderTarget;
13 | var _velocityRenderTarget2;
14 | var _positionRenderTarget;
15 | var _positionRenderTarget2;
16 |
17 | var _renderer;
18 | var _fboMesh;
19 | var _fboScene;
20 | var _fboCamera;
21 |
22 | var TEXTURE_WIDTH = exports.TEXTURE_WIDTH = settings.textureWidth;
23 | var TEXTURE_HEIGHT = exports.TEXTURE_HEIGHT = settings.textureHeight;
24 | var AMOUNT = exports.AMOUNT = TEXTURE_WIDTH * TEXTURE_HEIGHT;
25 |
26 | exports.init = init;
27 | exports.update = update;
28 |
29 | exports.velocityUniforms = undef;
30 |
31 | exports.positionRenderTarget = undef;
32 | var defaultPositionRenderTarget = exports.positionRenderTarget = undef;
33 |
34 | function init(renderer) {
35 |
36 | _renderer = renderer;
37 |
38 | var gl = _renderer.getContext();
39 | if ( !gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS) ) {
40 | alert( 'No support for vertex shader textures!' );
41 | return;
42 | }
43 | if ( !gl.getExtension( 'OES_texture_float' )) {
44 | alert( 'No OES_texture_float support for float textures!' );
45 | return;
46 | }
47 |
48 | _fboScene = new THREE.Scene();
49 | _fboCamera = new THREE.Camera();
50 | _fboCamera.position.z = 1;
51 |
52 | _copyShader = new THREE.ShaderMaterial({
53 | uniforms: {
54 | resolution: { type: 'v2', value: new THREE.Vector2( TEXTURE_WIDTH, TEXTURE_HEIGHT ) },
55 | texture: { type: 't', value: undef }
56 | },
57 | vertexShader: shaderParse(glslify('../glsl/fbo.vert')),
58 | fragmentShader: shaderParse(glslify('../glsl/fboThrough.frag'))
59 | });
60 |
61 | _velocityShader = new THREE.ShaderMaterial({
62 | uniforms: exports.velocityUniforms ={
63 | resolution: { type: 'v2', value: new THREE.Vector2( TEXTURE_WIDTH, TEXTURE_HEIGHT ) },
64 | mouse3d: { type: 'v3', value: new THREE.Vector3() },
65 | mouse3dVelocity: { type: 'v3', value: new THREE.Vector3() },
66 | textureDefaultPosition: { type: 't', value: undef },
67 | texturePosition: { type: 't', value: undef },
68 | textureVelocity: { type: 't', value: undef },
69 | isPhysicsActive: { type: 'f', value: 0 },
70 | mouseForce: { type: 'f', value: 0.2 },
71 | mouseRadius: { type: 'f', value: 120 },
72 | gravity: { type: 'f', value: 0.15 },
73 | resetAnimation: { type: 'f', value: 0 }
74 | },
75 | vertexShader: shaderParse(glslify('../glsl/fbo.vert')),
76 | fragmentShader: shaderParse(glslify('../glsl/velocity.frag')),
77 | blending: THREE.NoBlending,
78 | transparent: false,
79 | depthWrite: false,
80 | depthTest: false
81 | });
82 |
83 | _positionShader = new THREE.ShaderMaterial({
84 | uniforms: {
85 | resolution: { type: 'v2', value: new THREE.Vector2( TEXTURE_WIDTH, TEXTURE_HEIGHT ) },
86 | texturePosition: { type: 't', value: undef },
87 | textureDefaultPosition: { type: 't', value: undef },
88 | textureVelocity: { type: 't', value: undef },
89 | resetAnimation: { type: 'f', value: 0 }
90 | },
91 | vertexShader: shaderParse(glslify('../glsl/fbo.vert')),
92 | fragmentShader: shaderParse(glslify('../glsl/position.frag')),
93 | blending: THREE.NoBlending,
94 | transparent: false,
95 | depthWrite: false,
96 | depthTest: false
97 | });
98 |
99 | _fboMesh = new THREE.Mesh( new THREE.PlaneBufferGeometry( 2, 2 ), _copyShader );
100 | _fboScene.add( _fboMesh );
101 |
102 | _velocityRenderTarget = new THREE.WebGLRenderTarget( TEXTURE_WIDTH, TEXTURE_HEIGHT, {
103 | wrapS: THREE.ClampToEdgeWrapping,
104 | wrapT: THREE.ClampToEdgeWrapping,
105 | minFilter: THREE.NearestFilter,
106 | magFilter: THREE.NearestFilter,
107 | format: THREE.RGBFormat,
108 | type: THREE.FloatType,
109 | depthBuffer: false,
110 | stencilBuffer: false
111 | });
112 | _velocityRenderTarget2 = _velocityRenderTarget.clone();
113 | _copyTexture(_createVelocityTexture(), _velocityRenderTarget);
114 | _copyTexture(_velocityRenderTarget, _velocityRenderTarget2);
115 |
116 | _positionRenderTarget = new THREE.WebGLRenderTarget(TEXTURE_WIDTH, TEXTURE_HEIGHT, {
117 | wrapS: THREE.ClampToEdgeWrapping,
118 | wrapT: THREE.ClampToEdgeWrapping,
119 | minFilter: THREE.NearestFilter,
120 | magFilter: THREE.NearestFilter,
121 | format: THREE.RGBFormat,
122 | type: THREE.FloatType,
123 | depthWrite: false,
124 | depthBuffer: false,
125 | stencilBuffer: false
126 | });
127 | _positionRenderTarget2 = _positionRenderTarget.clone();
128 | defaultPositionRenderTarget = exports.defaultPositionRenderTarget = _positionRenderTarget.clone();
129 |
130 | _copyTexture(_createPositionTexture(), defaultPositionRenderTarget);
131 | _copyTexture(defaultPositionRenderTarget, _positionRenderTarget);
132 | _copyTexture(defaultPositionRenderTarget, _positionRenderTarget2);
133 |
134 | }
135 |
136 | function _updateVelocity(dt) {
137 |
138 | var mouse3dUniformValue = _velocityShader.uniforms.mouse3d.value;
139 | var mouse3dVelocityUniformValue = _velocityShader.uniforms.mouse3dVelocity.value;
140 | if(settings.isMouseActive && settings.isMouseVisible) {
141 | if(mouse3dUniformValue.z < -9000) {
142 | mouse3dVelocityUniformValue.set(0, 0, 0);
143 | } else {
144 | mouse3dVelocityUniformValue.copy(settings.mouse3d).sub(mouse3dUniformValue);
145 | }
146 | mouse3dUniformValue.copy(settings.mouse3d);
147 |
148 | } else {
149 | mouse3dUniformValue.set(0.0, 0.0, -9999);
150 | }
151 |
152 | _velocityShader.uniforms.isPhysicsActive.value = +settings.isPhysicsActive;
153 |
154 | // swap
155 | var tmp = _velocityRenderTarget;
156 | _velocityRenderTarget = _velocityRenderTarget2;
157 | _velocityRenderTarget2 = tmp;
158 |
159 | _fboMesh.material = _velocityShader;
160 | _velocityShader.uniforms.textureDefaultPosition.value = defaultPositionRenderTarget;
161 | _velocityShader.uniforms.textureVelocity.value = _velocityRenderTarget2;
162 | _velocityShader.uniforms.texturePosition.value = _positionRenderTarget;
163 | _velocityShader.uniforms.resetAnimation.value = settings.resetAnimation;
164 | _renderer.render( _fboScene, _fboCamera, _velocityRenderTarget );
165 | }
166 |
167 | function _updatePosition(dt) {
168 |
169 | // swap
170 | var tmp = _positionRenderTarget;
171 | _positionRenderTarget = _positionRenderTarget2;
172 | _positionRenderTarget2 = tmp;
173 |
174 | _fboMesh.material = _positionShader;
175 | _positionShader.uniforms.textureVelocity.value = _velocityRenderTarget;
176 | _positionShader.uniforms.texturePosition.value = _positionRenderTarget2;
177 | _positionShader.uniforms.textureDefaultPosition.value = defaultPositionRenderTarget;
178 | _positionShader.uniforms.resetAnimation.value = settings.resetAnimation;
179 | _renderer.render( _fboScene, _fboCamera, _positionRenderTarget );
180 | }
181 |
182 | function _copyTexture(input, output) {
183 | _fboMesh.material = _copyShader;
184 | _copyShader.uniforms.texture.value = input;
185 | _renderer.render( _fboScene, _fboCamera, output );
186 | }
187 |
188 | function _createVelocityTexture() {
189 | var texture = new THREE.DataTexture( new Float32Array( AMOUNT * 3 ), TEXTURE_WIDTH, TEXTURE_HEIGHT, THREE.RGBFormat, THREE.FloatType );
190 | texture.minFilter = THREE.NearestFilter;
191 | texture.magFilter = THREE.NearestFilter;
192 | texture.needsUpdate = true;
193 | texture.generateMipmaps = false;
194 | texture.flipY = false;
195 | return texture;
196 | }
197 |
198 |
199 | function _createPositionTexture() {
200 | var texture = new THREE.DataTexture( settings.headVertexPositions, TEXTURE_WIDTH, TEXTURE_HEIGHT, THREE.RGBFormat, THREE.FloatType );
201 | texture.minFilter = THREE.NearestFilter;
202 | texture.magFilter = THREE.NearestFilter;
203 | texture.needsUpdate = true;
204 | texture.generateMipmaps = false;
205 | texture.flipY = false;
206 | return texture;
207 | }
208 |
209 | function update(dt) {
210 |
211 | _updateVelocity(dt);
212 | _renderer.autoClearColor = false;
213 | _updatePosition(dt);
214 | _renderer.autoClearColor = true;
215 |
216 | exports.positionRenderTarget = _positionRenderTarget;
217 | }
218 |
219 |
220 |
--------------------------------------------------------------------------------
/src/3d/ground.js:
--------------------------------------------------------------------------------
1 | var settings = require('../core/settings');
2 | var THREE = require('three');
3 |
4 | var undef;
5 |
6 | var mesh = exports.mesh = undef;
7 | exports.init = init;
8 | exports.update = update;
9 |
10 | var _geometry;
11 | var _material;
12 |
13 | var BLACK = new THREE.Color(0x111111);
14 | var WHITE = new THREE.Color(0xcccccc);
15 |
16 | function init() {
17 | _geometry = new THREE.PlaneGeometry( 4000, 4000, 10, 10 );
18 | _material = new THREE.MeshPhongMaterial( {
19 | color: new THREE.Color(0x555555),
20 | transparent: true,
21 | shininess: 5
22 | });
23 |
24 |
25 | mesh = exports.mesh = new THREE.Mesh( _geometry, _material );
26 | mesh.position.y = -200;
27 | mesh.rotation.x = -1.57;
28 | mesh.castShadow = false;
29 | mesh.receiveShadow = true;
30 |
31 | }
32 |
33 | function update() {
34 | mesh.visible = !settings.useReflectedGround;
35 | _material.color.copy(BLACK).lerp(WHITE, settings.whiteRatio);
36 | }
37 |
--------------------------------------------------------------------------------
/src/3d/head.js:
--------------------------------------------------------------------------------
1 | var settings = require('../core/settings');
2 | var THREE = require('three');
3 | var shaderParse = require('../helpers/shaderParse');
4 | var glslify = require('glslify');
5 | var fbo = require('./fbo');
6 |
7 | var undef;
8 |
9 | var mesh = exports.mesh = undef;
10 | exports.init = init;
11 | exports.update = update;
12 | exports.useDiffuse = false;
13 | exports.useEnv = false;
14 | exports.normalNoise = 0.2;
15 |
16 | var _geometry;
17 | var _materials = {};
18 | var _depthMaterial;
19 |
20 | var TEXTURE_WIDTH = settings.textureWidth;
21 | var PARTICLES_AMOUNT = settings.textureWidth * settings.textureHeight;
22 |
23 | function init() {
24 | settings.headData.scale = 1/1000;
25 | var geometry = (new THREE.JSONLoader()).parse(settings.headData).geometry;
26 |
27 | var geometryFaces = geometry.faces;
28 | var geometryVertices = geometry.vertices;
29 | var geometryFaceUVs = geometry.faceVertexUvs[0];
30 | var areaTotal = 0;
31 | var areaThresholds = [];
32 | var face, vertex, area;
33 | var p0x, p0y, p0z;
34 | var p1x, p1y, p1z;
35 | var p2x, p2y, p2z;
36 | var v0x, v0y, v0z;
37 | var v1x, v1y, v1z;
38 | var v2x, v2y, v2z;
39 |
40 | for(var i = 0, len = geometryFaces.length; i < len; i++) {
41 | face = geometryFaces[i];
42 | vertex = geometryVertices[face.a];
43 | p0x = vertex.x;
44 | p0y = vertex.y;
45 | p0z = vertex.z;
46 | vertex = geometryVertices[face.b];
47 | p1x = vertex.x;
48 | p1y = vertex.y;
49 | p1z = vertex.z;
50 | vertex = geometryVertices[face.c];
51 | p2x = vertex.x;
52 | p2y = vertex.y;
53 | p2z = vertex.z;
54 | v0x = p1x - p0x;
55 | v0y = p1y - p0y;
56 | v0z = p1z - p0z;
57 | v1x = p2x - p0x;
58 | v1y = p2y - p0y;
59 | v1z = p2z - p0z;
60 | v2x = v0y * v1z - v0z * v1y;
61 | v2y = v0z * v1x - v0x * v1z;
62 | v2z = v0x * v1y - v0y * v1x;
63 | area = 0.5 * Math.sqrt(v2x*v2x + v2y*v2y + v2z*v2z);
64 | areaTotal += area;
65 | areaThresholds[i] = areaTotal;
66 | }
67 |
68 | // probably not good to ignore the same vertices with different normal
69 | // but it shouldnt look so different... so meh
70 |
71 | var remainder = PARTICLES_AMOUNT - geometryVertices.length;
72 | var areaPerParticle = areaTotal / remainder;
73 | var usedVertexMap = new Int8Array(geometryVertices.length);
74 | var vertices = new Float32Array(PARTICLES_AMOUNT * 3);
75 | var uvs = new Float32Array(PARTICLES_AMOUNT * 2);
76 | var normals = new Float32Array(PARTICLES_AMOUNT * 3);
77 | var index2 = 0;
78 | var index3 = 0;
79 | var uv, normal, areaThreshold, amount;
80 |
81 | var vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy;
82 | var v0, v1, v2, n0, n1, n2, uv0, uv1, uv2;
83 |
84 | var areaSum = 0;
85 |
86 | function addPoint(pointAmount,
87 | v0x, v0y, v0z, n0x, n0y, n0z, uv0x, uv0y,
88 | v1x, v1y, v1z, n1x, n1y, n1z, uv1x, uv1y,
89 | v2x, v2y, v2z, n2x, n2y, n2z, uv2x, uv2y) {
90 | if(pointAmount < 1) return 0;
91 |
92 | vertices[index3] = vcx = (v0x + v1x + v2x) / 3;
93 | vertices[index3 + 1] = vcy = (v0y + v1y + v2y) / 3;
94 | vertices[index3 + 2] = vcz = (v0z + v1z + v2z) / 3;
95 | normals[index3] = ncx = (n0x + n1x + n2x) / 3;
96 | normals[index3 + 1] = ncy = (n0y + n1y + n2y) / 3;
97 | normals[index3 + 2] = ncz = (n0z + n1z + n2z) / 3;
98 | index3 += 3;
99 | uvs[index2] = uvcx = (uv0x + uv1x + uv2x) / 3;
100 | uvs[index2 + 1] = uvcy = (uv0y + uv1y + uv2y) / 3;
101 | index2 += 2;
102 | pointAmount--;
103 |
104 | if(pointAmount % 2) {
105 | var d3 = ~~(pointAmount / 3);
106 | var f3 = pointAmount - d3 * 3;
107 | addPoint(d3 + (f3 > 0 ? 1: 0),
108 | v0x, v0y, v0z, n0x, n0y, n0z, uv0x, uv0y,
109 | v1x, v1y, v1z, n1x, n1y, n1z, uv1x, uv1y,
110 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
111 | addPoint(d3 + (f3 > 1 ? 1: 0),
112 | v1x, v1y, v1z, n1x, n1y, n1z, uv1x, uv1y,
113 | v2x, v2y, v2z, n2x, n2y, n2z, uv2x, uv2y,
114 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
115 | addPoint(d3,
116 | v2x, v2y, v2z, n2x, n2y, n2z, uv2x, uv2y,
117 | v0x, v0y, v0z, n0x, n0y, n0z, uv0x, uv0y,
118 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
119 | } else {
120 |
121 | var d6 = ~~(pointAmount / 6);
122 | var f6 = pointAmount - d6 * 6;
123 |
124 | addPoint(d6 + (f6 > 0 ? 1: 0),
125 | v2x, v2y, v2z, n2x, n2y, n2z, uv2x, uv2y,
126 | (v2x + v0x) / 2, (v2y + v0y) / 2, (v2z + v0z) / 2, (n2x + n0x) / 2, (n2y + n0y) / 2, (n2z + n0z) / 2, (uv2x + uv0x) / 2, (uv2y + uv0y) / 2,
127 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
128 | addPoint(d6 + (f6 > 1 ? 1: 0),
129 | v0x, v0y, v0z, n0x, n0y, n0z, uv0x, uv0y,
130 | (v2x + v0x) / 2, (v2y + v0y) / 2, (v2z + v0z) / 2, (n2x + n0x) / 2, (n2y + n0y) / 2, (n2z + n0z) / 2, (uv2x + uv0x) / 2, (uv2y + uv0y) / 2,
131 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
132 |
133 | addPoint(d6 + (f6 > 2 ? 1: 0),
134 | v1x, v1y, v1z, n1x, n1y, n1z, uv1x, uv1y,
135 | (v1x + v2x) / 2, (v1y + v2y) / 2, (v1z + v2z) / 2, (n1x + n2x) / 2, (n1y + n2y) / 2, (n1z + n2z) / 2, (uv1x + uv2x) / 2, (uv1y + uv2y) / 2,
136 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
137 | addPoint(d6 + (f6 > 3 ? 1: 0),
138 | v2x, v2y, v2z, n2x, n2y, n2z, uv2x, uv2y,
139 | (v1x + v2x) / 2, (v1y + v2y) / 2, (v1z + v2z) / 2, (n1x + n2x) / 2, (n1y + n2y) / 2, (n1z + n2z) / 2, (uv1x + uv2x) / 2, (uv1y + uv2y) / 2,
140 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
141 |
142 | addPoint(d6 + (f6 > 4 ? 1: 0),
143 | v0x, v0y, v0z, n0x, n0y, n0z, uv0x, uv0y,
144 | (v0x + v1x) / 2, (v0y + v1y) / 2, (v0z + v1z) / 2, (n0x + n1x) / 2, (n0y + n1y) / 2, (n0z + n1z) / 2, (uv0x + uv1x) / 2, (uv0y + uv1y) / 2,
145 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
146 | addPoint(d6 + (f6 > 5 ? 1: 0),
147 | v1x, v1y, v1z, n1x, n1y, n1z, uv1x, uv1y,
148 | (v0x + v1x) / 2, (v0y + v1y) / 2, (v0z + v1z) / 2, (n0x + n1x) / 2, (n0y + n1y) / 2, (n0z + n1z) / 2, (uv0x + uv1x) / 2, (uv0y + uv1y) / 2,
149 | vcx, vcy, vcz, ncx, ncy, ncz, uvcx, uvcy);
150 | }
151 |
152 | }
153 | for(i = 0, len = geometryFaces.length; i < len; i++) {
154 |
155 | face = geometryFaces[i];
156 |
157 | if(!usedVertexMap[face.a]) {
158 | usedVertexMap[face.a] = 1;
159 | vertex = geometryVertices[face.a];
160 | vertices[index3] = vertex.x;
161 | vertices[index3 + 1] = vertex.y;
162 | vertices[index3 + 2] = vertex.z;
163 | normal = face.vertexNormals[0];
164 | normals[index3] = normal.x;
165 | normals[index3 + 1] = normal.y;
166 | normals[index3 + 2] = normal.z;
167 | index3 += 3;
168 | uv = geometryFaceUVs[i][0];
169 | uvs[index2] = uv.x;
170 | uvs[index2 + 1] = uv.y;
171 | index2 += 2;
172 | }
173 | if(!usedVertexMap[face.b]) {
174 | usedVertexMap[face.b] = 1;
175 | vertex = geometryVertices[face.b];
176 | vertices[index3] = vertex.x;
177 | vertices[index3 + 1] = vertex.y;
178 | vertices[index3 + 2] = vertex.z;
179 | normal = face.vertexNormals[1];
180 | normals[index3] = normal.x;
181 | normals[index3 + 1] = normal.y;
182 | normals[index3 + 2] = normal.z;
183 | index3 += 3;
184 | uv = geometryFaceUVs[i][1];
185 | uvs[index2] = uv.x;
186 | uvs[index2 + 1] = uv.y;
187 | index2 += 2;
188 | }
189 | if(!usedVertexMap[face.c]) {
190 | usedVertexMap[face.c] = 1;
191 | vertex = geometryVertices[face.c];
192 | vertices[index3] = vertex.x;
193 | vertices[index3 + 1] = vertex.y;
194 | vertices[index3 + 2] = vertex.z;
195 | normal = face.vertexNormals[2];
196 | normals[index3] = normal.x;
197 | normals[index3 + 1] = normal.y;
198 | normals[index3 + 2] = normal.z;
199 | index3 += 3;
200 | uv = geometryFaceUVs[i][2];
201 | uvs[index2] = uv.x;
202 | uvs[index2 + 1] = uv.y;
203 | index2 += 2;
204 | }
205 |
206 | areaThreshold = areaThresholds[i];
207 | amount = 0;
208 | while(((i === len - 1) || (areaSum + areaPerParticle <= areaThreshold)) && remainder > 0) {
209 | areaSum += areaPerParticle;
210 | amount++;
211 | remainder--;
212 | }
213 | if(amount > 0) {
214 | v0 = geometryVertices[face.a];
215 | n0 = face.vertexNormals[0];
216 | uv0 = geometryFaceUVs[i][0];
217 | v1 = geometryVertices[face.b];
218 | n1 = face.vertexNormals[1];
219 | uv1 = geometryFaceUVs[i][1];
220 | v2 = geometryVertices[face.c];
221 | n2 = face.vertexNormals[2];
222 | uv2 = geometryFaceUVs[i][2];
223 | addPoint(amount,
224 | v0.x, v0.y, v0.z, n0.x, n0.y, n0.z, uv0.x, uv0.y,
225 | v1.x, v1.y, v1.z, n1.x, n1.y, n1.z, uv1.x, uv1.y,
226 | v2.x, v2.y, v2.z, n2.x, n2.y, n2.z, uv2.x, uv2.y);
227 | }
228 | }
229 |
230 | settings.headVertexPositions = vertices;
231 |
232 | var position = new Float32Array(PARTICLES_AMOUNT * 3);
233 | var i3;
234 | for( i = 0; i < PARTICLES_AMOUNT; i++ ) {
235 | i3 = i * 3;
236 | position[ i3 + 0] = (i % TEXTURE_WIDTH) / TEXTURE_WIDTH;
237 | position[ i3 + 1 ] = ~~(i / TEXTURE_WIDTH) / TEXTURE_WIDTH;
238 | position[ i3 + 2 ] = Math.random();
239 | }
240 |
241 | _geometry = new THREE.BufferGeometry();
242 | _geometry.addAttribute( 'position', new THREE.BufferAttribute( position, 3 ));
243 | _geometry.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ));
244 | _geometry.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ));
245 |
246 | var diffuseMap = (new THREE.TextureLoader()).load('images/diffuse.jpg');
247 | diffuseMap.wrapS = diffuseMap.wrapT = THREE.RepeatWrapping;
248 | diffuseMap.format = THREE.RGBFormat;
249 |
250 | var material;
251 |
252 | var vs = shaderParse(glslify('../glsl/head.vert'));
253 | var fs = shaderParse(glslify('../glsl/head.frag'));
254 |
255 | function cloneMaterial(useDiffuse, useEnv) {
256 | material = _materials[(+useDiffuse << 1) + (+useEnv)] = new THREE.MeshPhongMaterial();
257 | material.type = 'ShaderMaterial';
258 | material.color.setHex(useDiffuse ? 0x777777 : 0x444444);
259 | material.specular.setHex(useDiffuse ? 0x222222 : 0x555555);
260 | material.shininess = 12;
261 | material.reflectivity = (!useDiffuse && useEnv) ? 0.5 : 0.25;
262 | material.blending = THREE.NoBlending;
263 |
264 | var uniforms = THREE.UniformsUtils.merge( [THREE.ShaderLib.phong.uniforms] );
265 | uniforms.texturePosition = {type: 't', value: undef};
266 | uniforms.textureDefaultPosition = {type: 't', value: undef};
267 | uniforms.normalNoise = {type: 'f', value: exports.normalNoise};
268 | material.uniforms = uniforms;
269 | material.vertexShader = vs;
270 | material.fragmentShader = fs;
271 | material.map = useDiffuse ? diffuseMap : undef;
272 | material.envMap = useEnv ? settings.envMap : undef;
273 | }
274 | for( i = 0; i < 4; i++ ) {
275 | cloneMaterial((i & 2) >> 1, i & 1);
276 | }
277 |
278 | mesh = exports.mesh = new THREE.Points(_geometry, material);
279 | mesh.customDepthMaterial = _depthMaterial = new THREE.ShaderMaterial( {
280 | uniforms: {
281 | time: { type: 'f', value: 0 },
282 | realCameraPosition: { type: 'v3', value: settings.cameraPosition },
283 | texturePosition: { type: 't', value: undef },
284 | textureDefaultPosition: { type: 't', value: undef }
285 | },
286 | vertexShader: shaderParse(glslify('../glsl/headDepth.vert')),
287 | fragmentShader: shaderParse(glslify('../glsl/headDepth.frag')),
288 | blending: THREE.NoBlending,
289 | depthTest: true,
290 | depthWrite: true
291 | });
292 | mesh.castShadow = true;
293 | mesh.receiveShadow = true;
294 |
295 | geometry.dispose();
296 | // var material = new THREE.MeshPhongMaterial( {
297 | // color: 0x666666,
298 | // specular: 0x222222,
299 | // shininess: 12
300 | // });
301 | // var baseMesh = exports.baseMesh = new THREE.Mesh(geometry, material);
302 | // baseMesh.castShadow = true;
303 | // baseMesh.receiveShadow = true;
304 | // baseMesh.visible = false;
305 | // mesh.add(baseMesh);
306 |
307 | }
308 |
309 | function update(dt) {
310 | mesh.material = _materials[(+exports.useDiffuse << 1) + (+exports.useEnv)];
311 | mesh.material.uniforms.textureDefaultPosition.value = fbo.defaultPositionRenderTarget;
312 | mesh.material.uniforms.texturePosition.value = fbo.positionRenderTarget;
313 | mesh.material.uniforms.normalNoise.value = exports.normalNoise;
314 | _depthMaterial.uniforms.textureDefaultPosition.value = fbo.defaultPositionRenderTarget;
315 | _depthMaterial.uniforms.texturePosition.value = fbo.positionRenderTarget;
316 |
317 | }
318 |
--------------------------------------------------------------------------------
/src/3d/lights.js:
--------------------------------------------------------------------------------
1 | var settings = require('../core/settings');
2 | var THREE = require('three');
3 |
4 | var undef;
5 |
6 | var mesh = exports.mesh = undef;
7 | var spot = exports.spot = undef;
8 | exports.init = init;
9 | exports.update = update;
10 |
11 | var _moveTime = 0;
12 |
13 | function init() {
14 |
15 | mesh = exports.mesh = new THREE.Object3D();
16 |
17 | var ambient = new THREE.AmbientLight( 0xcccccc );
18 | mesh.add( ambient );
19 |
20 | spot = exports.spot = new THREE.SpotLight( 0xffffff, 1, 0, Math.PI / 2, 1 );
21 | spot.position.x = 400;
22 | spot.position.y = 700;
23 | spot.position.z = 200;
24 | spot.target.position.set( 0, 0, 0 );
25 |
26 | spot.castShadow = true;
27 |
28 | spot.shadowCameraNear = 100;
29 | spot.shadowCameraFar = 2500;
30 | spot.shadowCameraFov = 120;
31 |
32 | spot.shadowBias = 0.0003;
33 | spot.shadowDarkness = 1;
34 |
35 | spot.shadowMapWidth = 1024;
36 | spot.shadowMapHeight = 2048;
37 |
38 | mesh.add( spot );
39 |
40 | }
41 |
42 | function update(dt, camera) {
43 | _moveTime += 0;//dt * settings.lightSpeed;
44 | var angle = _moveTime * 0.0005 - 0.2;
45 | // mesh.position.x = Math.cos(angle) * 400;
46 | // mesh.position.z = Math.sin(angle) * 400;
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/3d/vignette.js:
--------------------------------------------------------------------------------
1 | var settings = require('../core/settings');
2 | var THREE = require('three');
3 |
4 | var undef;
5 |
6 | var glslify = require('glslify');
7 | var shaderParse = require('../helpers/shaderParse');
8 |
9 | var mesh = exports.mesh = undef;
10 |
11 | exports.init = init;
12 | exports.resize = resize;
13 | exports.update = update;
14 |
15 | var _resolution;
16 | var _uTime;
17 |
18 | function init() {
19 | var geometry = new THREE.PlaneBufferGeometry( 2, 2);
20 | var material = new THREE.ShaderMaterial( {
21 | uniforms: {
22 | uAlpha : exports.alphaUniform = {type : 'f', value: 1 },
23 | uTime : _uTime = {type : 'f', value: 0 },
24 | uResolution : {type : 'v2', value: _resolution = new THREE.Vector2() }
25 | },
26 | vertexShader: shaderParse(glslify('../glsl/vignette.vert')),
27 | fragmentShader: shaderParse(glslify('../glsl/vignette.frag')),
28 | blending: THREE.NormalBlending,
29 | transparent: true,
30 | depthWrite: false,
31 | depthTest: false
32 | });
33 |
34 | mesh = exports.mesh = new THREE.Mesh( geometry, material );
35 | mesh.frustumCulled = false;
36 | mesh.renderOrder = 1024;
37 |
38 | }
39 |
40 | function resize(width, height) {
41 | _resolution.set(width, height);
42 | }
43 |
44 | function update(dt) {
45 | _uTime.value = (_uTime.value + dt) % 1512.21;
46 | }
47 |
--------------------------------------------------------------------------------
/src/controls/OrbitControls.js:
--------------------------------------------------------------------------------
1 | //var THREE = require('three');
2 |
3 | /**
4 | * @author qiao / https://github.com/qiao
5 | * @author mrdoob / http://mrdoob.com
6 | * @author alteredq / http://alteredqualia.com/
7 | * @author WestLangley / http://github.com/WestLangley
8 | * @author erich666 / http://erichaines.com
9 | */
10 | /*global THREE, console */
11 |
12 | // This set of controls performs orbiting, dollying (zooming), and panning. It maintains
13 | // the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
14 | // supported.
15 | //
16 | // Orbit - left mouse / touch: one finger move
17 | // Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
18 | // Pan - right mouse, or arrow keys / touch: three finter swipe
19 |
20 | THREE.OrbitControls = function ( object, domElement ) {
21 |
22 | this.object = object;
23 | this.domElement = ( domElement !== undefined ) ? domElement : document;
24 |
25 | // API
26 |
27 | // Set to false to disable this control
28 | this.enabled = true;
29 |
30 | // "target" sets the location of focus, where the control orbits around
31 | // and where it pans with respect to.
32 | this.target = new THREE.Vector3();
33 |
34 | // center is old, deprecated; use "target" instead
35 | this.center = this.target;
36 |
37 | // This option actually enables dollying in and out; left as "zoom" for
38 | // backwards compatibility
39 | this.noZoom = false;
40 | this.zoomSpeed = 1.0;
41 |
42 | // Limits to how far you can dolly in and out ( PerspectiveCamera only )
43 | this.minDistance = 0;
44 | this.maxDistance = Infinity;
45 |
46 | // Limits to how far you can zoom in and out ( OrthographicCamera only )
47 | this.minZoom = 0;
48 | this.maxZoom = Infinity;
49 |
50 | // Set to true to disable this control
51 | this.noRotate = false;
52 | this.rotateSpeed = 1.0;
53 |
54 | // Set to true to disable this control
55 | this.noPan = false;
56 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
57 |
58 | // Set to true to automatically rotate around the target
59 | this.autoRotate = false;
60 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
61 |
62 | // How far you can orbit vertically, upper and lower limits.
63 | // Range is 0 to Math.PI radians.
64 | this.minPolarAngle = 0; // radians
65 | this.maxPolarAngle = Math.PI; // radians
66 |
67 | // How far you can orbit horizontally, upper and lower limits.
68 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
69 | this.minAzimuthAngle = - Infinity; // radians
70 | this.maxAzimuthAngle = Infinity; // radians
71 |
72 | // Set to true to disable use of the keys
73 | this.noKeys = false;
74 |
75 | // The four arrow keys
76 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
77 |
78 | // Mouse buttons
79 | this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
80 |
81 | ////////////
82 | // internals
83 |
84 | var scope = this;
85 |
86 | var EPS = 0.000001;
87 |
88 | var rotateStart = new THREE.Vector2();
89 | var rotateEnd = new THREE.Vector2();
90 | var rotateDelta = new THREE.Vector2();
91 |
92 | var panStart = new THREE.Vector2();
93 | var panEnd = new THREE.Vector2();
94 | var panDelta = new THREE.Vector2();
95 | var panOffset = new THREE.Vector3();
96 |
97 | var offset = new THREE.Vector3();
98 |
99 | var dollyStart = new THREE.Vector2();
100 | var dollyEnd = new THREE.Vector2();
101 | var dollyDelta = new THREE.Vector2();
102 |
103 | var theta;
104 | var phi;
105 | var phiDelta = 0;
106 | var thetaDelta = 0;
107 | var scale = 1;
108 | var pan = new THREE.Vector3();
109 |
110 | var lastPosition = new THREE.Vector3();
111 | var lastQuaternion = new THREE.Quaternion();
112 |
113 | var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
114 |
115 | var state = STATE.NONE;
116 |
117 | // for reset
118 |
119 | this.target0 = this.target.clone();
120 | this.position0 = this.object.position.clone();
121 | this.zoom0 = this.object.zoom;
122 |
123 | // so camera.up is the orbit axis
124 |
125 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
126 | var quatInverse = quat.clone().inverse();
127 |
128 | // events
129 |
130 | var changeEvent = { type: 'change' };
131 | var startEvent = { type: 'start' };
132 | var endEvent = { type: 'end' };
133 |
134 | this.rotateLeft = function ( angle ) {
135 |
136 | if ( angle === undefined ) {
137 |
138 | angle = getAutoRotationAngle();
139 |
140 | }
141 |
142 | thetaDelta -= angle;
143 |
144 | };
145 |
146 | this.rotateUp = function ( angle ) {
147 |
148 | if ( angle === undefined ) {
149 |
150 | angle = getAutoRotationAngle();
151 |
152 | }
153 |
154 | phiDelta -= angle;
155 |
156 | };
157 |
158 | // pass in distance in world space to move left
159 | this.panLeft = function ( distance ) {
160 |
161 | var te = this.object.matrix.elements;
162 |
163 | // get X column of matrix
164 | panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
165 | panOffset.multiplyScalar( - distance );
166 |
167 | pan.add( panOffset );
168 |
169 | };
170 |
171 | // pass in distance in world space to move up
172 | this.panUp = function ( distance ) {
173 |
174 | var te = this.object.matrix.elements;
175 |
176 | // get Y column of matrix
177 | panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
178 | panOffset.multiplyScalar( distance );
179 |
180 | pan.add( panOffset );
181 |
182 | };
183 |
184 | // pass in x,y of change desired in pixel space,
185 | // right and down are positive
186 | this.pan = function ( deltaX, deltaY ) {
187 |
188 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
189 |
190 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
191 |
192 | // perspective
193 | var position = scope.object.position;
194 | var offset = position.clone().sub( scope.target );
195 | var targetDistance = offset.length();
196 |
197 | // half of the fov is center to top of screen
198 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
199 |
200 | // we actually don't use screenWidth, since perspective camera is fixed to screen height
201 | scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
202 | scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
203 |
204 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
205 |
206 | // orthographic
207 | scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
208 | scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
209 |
210 | } else {
211 |
212 | // camera neither orthographic or perspective
213 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
214 |
215 | }
216 |
217 | };
218 |
219 | this.dollyIn = function ( dollyScale ) {
220 |
221 | if ( dollyScale === undefined ) {
222 |
223 | dollyScale = getZoomScale();
224 |
225 | }
226 |
227 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
228 |
229 | scale /= dollyScale;
230 |
231 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
232 |
233 | scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );
234 | scope.object.updateProjectionMatrix();
235 | scope.dispatchEvent( changeEvent );
236 |
237 | } else {
238 |
239 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
240 |
241 | }
242 |
243 | };
244 |
245 | this.dollyOut = function ( dollyScale ) {
246 |
247 | if ( dollyScale === undefined ) {
248 |
249 | dollyScale = getZoomScale();
250 |
251 | }
252 |
253 | if ( scope.object instanceof THREE.PerspectiveCamera ) {
254 |
255 | scale *= dollyScale;
256 |
257 | } else if ( scope.object instanceof THREE.OrthographicCamera ) {
258 |
259 | scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );
260 | scope.object.updateProjectionMatrix();
261 | scope.dispatchEvent( changeEvent );
262 |
263 | } else {
264 |
265 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
266 |
267 | }
268 |
269 | };
270 |
271 | this.update = function () {
272 |
273 | var position = this.object.position;
274 |
275 | offset.copy( position ).sub( this.target );
276 |
277 | // rotate offset to "y-axis-is-up" space
278 | offset.applyQuaternion( quat );
279 |
280 | // angle from z-axis around y-axis
281 |
282 | theta = Math.atan2( offset.x, offset.z );
283 |
284 | // angle from y-axis
285 |
286 | phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
287 |
288 | if ( this.autoRotate && state === STATE.NONE ) {
289 |
290 | this.rotateLeft( getAutoRotationAngle() );
291 |
292 | }
293 |
294 | theta += thetaDelta;
295 | phi += phiDelta;
296 |
297 | // restrict theta to be between desired limits
298 | theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
299 |
300 | // restrict phi to be between desired limits
301 | phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
302 |
303 | // restrict phi to be betwee EPS and PI-EPS
304 | phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
305 |
306 | var radius = offset.length() * scale;
307 |
308 | // restrict radius to be between desired limits
309 | radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
310 |
311 | // move target to panned location
312 | this.target.add( pan );
313 |
314 | offset.x = radius * Math.sin( phi ) * Math.sin( theta );
315 | offset.y = radius * Math.cos( phi );
316 | offset.z = radius * Math.sin( phi ) * Math.cos( theta );
317 |
318 | // rotate offset back to "camera-up-vector-is-up" space
319 | offset.applyQuaternion( quatInverse );
320 |
321 | position.copy( this.target ).add( offset );
322 |
323 | this.object.lookAt( this.target );
324 |
325 | thetaDelta = 0;
326 | phiDelta = 0;
327 | scale = 1;
328 | pan.set( 0, 0, 0 );
329 |
330 | // update condition is:
331 | // min(camera displacement, camera rotation in radians)^2 > EPS
332 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
333 |
334 | if ( lastPosition.distanceToSquared( this.object.position ) > EPS
335 | || 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) {
336 |
337 | this.dispatchEvent( changeEvent );
338 |
339 | lastPosition.copy( this.object.position );
340 | lastQuaternion.copy (this.object.quaternion );
341 |
342 | }
343 |
344 | };
345 |
346 |
347 | this.reset = function () {
348 |
349 | state = STATE.NONE;
350 |
351 | this.target.copy( this.target0 );
352 | this.object.position.copy( this.position0 );
353 | this.object.zoom = this.zoom0;
354 |
355 | this.object.updateProjectionMatrix();
356 | this.dispatchEvent( changeEvent );
357 |
358 | this.update();
359 |
360 | };
361 |
362 | this.getPolarAngle = function () {
363 |
364 | return phi;
365 |
366 | };
367 |
368 | this.getAzimuthalAngle = function () {
369 |
370 | return theta
371 |
372 | };
373 |
374 | function getAutoRotationAngle() {
375 |
376 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
377 |
378 | }
379 |
380 | function getZoomScale() {
381 |
382 | return Math.pow( 0.95, scope.zoomSpeed );
383 |
384 | }
385 |
386 | function onMouseDown( event ) {
387 |
388 | if ( scope.enabled === false ) return;
389 | event.preventDefault();
390 |
391 | if ( event.button === scope.mouseButtons.ORBIT ) {
392 | if ( scope.noRotate === true ) return;
393 |
394 | state = STATE.ROTATE;
395 |
396 | rotateStart.set( event.clientX, event.clientY );
397 |
398 | } else if ( event.button === scope.mouseButtons.ZOOM ) {
399 | if ( scope.noZoom === true ) return;
400 |
401 | state = STATE.DOLLY;
402 |
403 | dollyStart.set( event.clientX, event.clientY );
404 |
405 | } else if ( event.button === scope.mouseButtons.PAN ) {
406 | if ( scope.noPan === true ) return;
407 |
408 | state = STATE.PAN;
409 |
410 | panStart.set( event.clientX, event.clientY );
411 |
412 | }
413 |
414 | if ( state !== STATE.NONE ) {
415 | document.addEventListener( 'mousemove', onMouseMove, false );
416 | document.addEventListener( 'mouseup', onMouseUp, false );
417 | scope.dispatchEvent( startEvent );
418 | }
419 |
420 | }
421 |
422 | function onMouseMove( event ) {
423 |
424 | if ( scope.enabled === false ) return;
425 |
426 | event.preventDefault();
427 |
428 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
429 |
430 | if ( state === STATE.ROTATE ) {
431 |
432 | if ( scope.noRotate === true ) return;
433 |
434 | rotateEnd.set( event.clientX, event.clientY );
435 | rotateDelta.subVectors( rotateEnd, rotateStart );
436 |
437 | // rotating across whole screen goes 360 degrees around
438 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
439 |
440 | // rotating up and down along whole screen attempts to go 360, but limited to 180
441 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
442 |
443 | rotateStart.copy( rotateEnd );
444 |
445 | } else if ( state === STATE.DOLLY ) {
446 |
447 | if ( scope.noZoom === true ) return;
448 |
449 | dollyEnd.set( event.clientX, event.clientY );
450 | dollyDelta.subVectors( dollyEnd, dollyStart );
451 |
452 | if ( dollyDelta.y > 0 ) {
453 |
454 | scope.dollyIn();
455 |
456 | } else if ( dollyDelta.y < 0 ) {
457 |
458 | scope.dollyOut();
459 |
460 | }
461 |
462 | dollyStart.copy( dollyEnd );
463 |
464 | } else if ( state === STATE.PAN ) {
465 |
466 | if ( scope.noPan === true ) return;
467 |
468 | panEnd.set( event.clientX, event.clientY );
469 | panDelta.subVectors( panEnd, panStart );
470 |
471 | scope.pan( panDelta.x, panDelta.y );
472 |
473 | panStart.copy( panEnd );
474 |
475 | }
476 |
477 | if ( state !== STATE.NONE ) scope.update();
478 |
479 | }
480 |
481 | function onMouseUp( /* event */ ) {
482 |
483 | if ( scope.enabled === false ) return;
484 |
485 | document.removeEventListener( 'mousemove', onMouseMove, false );
486 | document.removeEventListener( 'mouseup', onMouseUp, false );
487 | scope.dispatchEvent( endEvent );
488 | state = STATE.NONE;
489 |
490 | }
491 |
492 | function onMouseWheel( event ) {
493 |
494 | if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return;
495 |
496 | event.preventDefault();
497 | event.stopPropagation();
498 |
499 | var delta = 0;
500 |
501 | if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
502 |
503 | delta = event.wheelDelta;
504 |
505 | } else if ( event.detail !== undefined ) { // Firefox
506 |
507 | delta = - event.detail;
508 |
509 | }
510 |
511 | if ( delta > 0 ) {
512 |
513 | scope.dollyOut();
514 |
515 | } else if ( delta < 0 ) {
516 |
517 | scope.dollyIn();
518 |
519 | }
520 |
521 | scope.update();
522 | scope.dispatchEvent( startEvent );
523 | scope.dispatchEvent( endEvent );
524 |
525 | }
526 |
527 | function onKeyDown( event ) {
528 |
529 | if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
530 |
531 | switch ( event.keyCode ) {
532 |
533 | case scope.keys.UP:
534 | scope.pan( 0, scope.keyPanSpeed );
535 | scope.update();
536 | break;
537 |
538 | case scope.keys.BOTTOM:
539 | scope.pan( 0, - scope.keyPanSpeed );
540 | scope.update();
541 | break;
542 |
543 | case scope.keys.LEFT:
544 | scope.pan( scope.keyPanSpeed, 0 );
545 | scope.update();
546 | break;
547 |
548 | case scope.keys.RIGHT:
549 | scope.pan( - scope.keyPanSpeed, 0 );
550 | scope.update();
551 | break;
552 |
553 | }
554 |
555 | }
556 |
557 | function touchstart( event ) {
558 |
559 | if ( scope.enabled === false ) return;
560 |
561 | switch ( event.touches.length ) {
562 |
563 | case 1: // one-fingered touch: rotate
564 |
565 | if ( scope.noRotate === true ) return;
566 |
567 | state = STATE.TOUCH_ROTATE;
568 |
569 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
570 | break;
571 |
572 | case 2: // two-fingered touch: dolly
573 |
574 | if ( scope.noZoom === true ) return;
575 |
576 | state = STATE.TOUCH_DOLLY;
577 |
578 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
579 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
580 | var distance = Math.sqrt( dx * dx + dy * dy );
581 | dollyStart.set( 0, distance );
582 | break;
583 |
584 | case 3: // three-fingered touch: pan
585 |
586 | if ( scope.noPan === true ) return;
587 |
588 | state = STATE.TOUCH_PAN;
589 |
590 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
591 | break;
592 |
593 | default:
594 |
595 | state = STATE.NONE;
596 |
597 | }
598 |
599 | if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
600 |
601 | }
602 |
603 | function touchmove( event ) {
604 |
605 | if ( scope.enabled === false ) return;
606 |
607 | event.preventDefault();
608 | event.stopPropagation();
609 |
610 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
611 |
612 | switch ( event.touches.length ) {
613 |
614 | case 1: // one-fingered touch: rotate
615 |
616 | if ( scope.noRotate === true ) return;
617 | if ( state !== STATE.TOUCH_ROTATE ) return;
618 |
619 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
620 | rotateDelta.subVectors( rotateEnd, rotateStart );
621 |
622 | // rotating across whole screen goes 360 degrees around
623 | scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
624 | // rotating up and down along whole screen attempts to go 360, but limited to 180
625 | scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
626 |
627 | rotateStart.copy( rotateEnd );
628 |
629 | scope.update();
630 | break;
631 |
632 | case 2: // two-fingered touch: dolly
633 |
634 | if ( scope.noZoom === true ) return;
635 | if ( state !== STATE.TOUCH_DOLLY ) return;
636 |
637 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
638 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
639 | var distance = Math.sqrt( dx * dx + dy * dy );
640 |
641 | dollyEnd.set( 0, distance );
642 | dollyDelta.subVectors( dollyEnd, dollyStart );
643 |
644 | if ( dollyDelta.y > 0 ) {
645 |
646 | scope.dollyOut();
647 |
648 | } else if ( dollyDelta.y < 0 ) {
649 |
650 | scope.dollyIn();
651 |
652 | }
653 |
654 | dollyStart.copy( dollyEnd );
655 |
656 | scope.update();
657 | break;
658 |
659 | case 3: // three-fingered touch: pan
660 |
661 | if ( scope.noPan === true ) return;
662 | if ( state !== STATE.TOUCH_PAN ) return;
663 |
664 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
665 | panDelta.subVectors( panEnd, panStart );
666 |
667 | scope.pan( panDelta.x, panDelta.y );
668 |
669 | panStart.copy( panEnd );
670 |
671 | scope.update();
672 | break;
673 |
674 | default:
675 |
676 | state = STATE.NONE;
677 |
678 | }
679 |
680 | }
681 |
682 | function touchend( /* event */ ) {
683 |
684 | if ( scope.enabled === false ) return;
685 |
686 | scope.dispatchEvent( endEvent );
687 | state = STATE.NONE;
688 |
689 | }
690 |
691 | this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
692 | this.domElement.addEventListener( 'mousedown', onMouseDown, false );
693 | this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
694 | this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
695 |
696 | this.domElement.addEventListener( 'touchstart', touchstart, false );
697 | this.domElement.addEventListener( 'touchend', touchend, false );
698 | this.domElement.addEventListener( 'touchmove', touchmove, false );
699 |
700 | window.addEventListener( 'keydown', onKeyDown, false );
701 |
702 | // force an update at start
703 | this.update();
704 |
705 | };
706 |
707 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
708 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
709 |
710 |
711 | module.exports = THREE.OrbitControls;
712 |
--------------------------------------------------------------------------------
/src/core/settings.js:
--------------------------------------------------------------------------------
1 | // need restart
2 | exports.useStats = false;
3 | exports.textureWidth = 1024;
4 | exports.textureHeight = 1024;
5 | exports.isPhysicsActive = false;
6 | exports.isMouseActive = true;
7 | exports.isMouseVisible = true;
8 | exports.gravityAllOnClick = false;
9 | exports.mouseZRatio = 0.95;
10 | exports.resetAnimation = 0;
11 |
12 |
--------------------------------------------------------------------------------
/src/fallback/mobile.js:
--------------------------------------------------------------------------------
1 | var isMobile = /(iPad|iPhone|Android)/i.test(navigator.userAgent);
2 |
3 | exports.pass = pass;
4 |
5 | var _callback;
6 |
7 | function pass(func) {
8 | if(isMobile) {
9 | _callback = func;
10 | init();
11 | } else {
12 | func();
13 | }
14 | }
15 |
16 | var _container;
17 | var _bypass;
18 |
19 | function init() {
20 | _container = document.querySelector('.mobile');
21 | _container.style.display = 'block';
22 |
23 | _bypass = document.querySelector('.mobile-bypass');
24 | if(_bypass) _bypass.addEventListener('click', _onByPassClick);
25 | }
26 |
27 | function _onByPassClick() {
28 | _container.parentNode.removeChild(_container);
29 | _callback();
30 | }
31 |
--------------------------------------------------------------------------------
/src/glsl/fbo.vert:
--------------------------------------------------------------------------------
1 | void main() {
2 | gl_Position = vec4( position, 1.0 );
3 | }
4 |
--------------------------------------------------------------------------------
/src/glsl/fboThrough.frag:
--------------------------------------------------------------------------------
1 | uniform vec2 resolution;
2 | uniform sampler2D texture;
3 |
4 | void main() {
5 | vec2 uv = gl_FragCoord.xy / resolution.xy;
6 | vec3 color = texture2D( texture, uv ).xyz;
7 | gl_FragColor = vec4( color, 1.0 );
8 | }
9 |
--------------------------------------------------------------------------------
/src/glsl/head.frag:
--------------------------------------------------------------------------------
1 | #define PHONG
2 |
3 | uniform vec3 diffuse;
4 | uniform vec3 emissive;
5 | uniform vec3 specular;
6 | uniform float shininess;
7 | uniform float opacity;
8 | uniform float normalNoise;
9 |
10 | //chunk(common);
11 | //chunk(color_pars_fragment);
12 | //chunk(uv_pars_fragment);
13 | //chunk(uv2_pars_fragment);
14 | //chunk(map_pars_fragment);
15 | //chunk(alphamap_pars_fragment);
16 | //chunk(aomap_pars_fragment);
17 | //chunk(lightmap_pars_fragment);
18 | //chunk(emissivemap_pars_fragment);
19 | //chunk(envmap_pars_fragment);
20 | //chunk(fog_pars_fragment);
21 | //chunk(bsdfs);
22 | //chunk(lights_pars);
23 | //chunk(lights_phong_pars_fragment);
24 | //chunk(shadowmap_pars_fragment);
25 | //chunk(bumpmap_pars_fragment);
26 | //chunk(normalmap_pars_fragment);
27 | //chunk(specularmap_pars_fragment);
28 | //chunk(logdepthbuf_pars_fragment);
29 |
30 | vec3 rotateY(vec3 v, float x)
31 | {
32 | return vec3(
33 | cos(x)*v.x - sin(x)*v.z,
34 | v.y,
35 | sin(x)*v.x + cos(x)*v.z
36 | );
37 | }
38 |
39 | vec3 rotateX(vec3 v, float x)
40 | {
41 | return vec3(
42 | v.x,
43 | v.y*cos(x) - v.z*sin(x),
44 | v.y*sin(x) + v.z*cos(x)
45 | );
46 | }
47 |
48 | vec3 rotateZ(vec3 v, float x)
49 | {
50 | return vec3(
51 | v.x*cos(x) - v.y*sin(x),
52 | v.x*sin(x) + v.y*cos(x),
53 | v.z
54 | );
55 | }
56 |
57 | #pragma glslify: snoise3 = require(glsl-noise/simplex/3d)
58 | #pragma glslify: random = require(glsl-random)
59 |
60 | void main() {
61 |
62 | float d = min(1.0, length(gl_PointCoord.xy - .5) * 2.0);
63 |
64 | vec4 diffuseColor = vec4( diffuse, opacity );
65 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) );
66 | vec3 totalEmissiveLight = emissive;
67 |
68 | //chunk(logdepthbuf_fragment);
69 | //chunk(map_fragment);
70 | //chunk(color_fragment);
71 | //chunk(alphamap_fragment);
72 | //chunk(alphatest_fragment);
73 | //chunk(specularmap_fragment);
74 | //chunk(normal_fragment);
75 |
76 |
77 | normal = rotateZ(normal, (random(gl_PointCoord.xy + 2.0) - 0.5) * normalNoise);
78 | normal = rotateY(normal, (random(gl_PointCoord.yx) - 0.5) * normalNoise);
79 | normal = normalize(normal);
80 |
81 | //chunk(emissivemap_fragment);
82 | //chunk(shadowmap_fragment);
83 |
84 | #ifdef USE_SHADOWMAP
85 | // for ( int i = 0; i < NUM_SHADOWS; i ++ ) {
86 |
87 | // }
88 | #endif
89 |
90 | // accumulation
91 | //chunk(lights_phong_fragment);
92 | //chunk(lights_template);
93 | //_chunk(lightmap_fragment);
94 |
95 | // modulation
96 | //chunk(aomap_fragment);
97 |
98 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveLight;
99 |
100 | //chunk(envmap_fragment);
101 | //chunk(linear_to_gamma_fragment);
102 |
103 | //chunk(fog_fragment);
104 |
105 |
106 |
107 | gl_FragColor = vec4( outgoingLight, diffuseColor.a );
108 |
109 | }
110 |
--------------------------------------------------------------------------------
/src/glsl/head.vert:
--------------------------------------------------------------------------------
1 | #define PHONG
2 |
3 | uniform sampler2D textureDefaultPosition;
4 | uniform sampler2D texturePosition;
5 |
6 | varying vec3 vViewPosition;
7 |
8 | const float EPS = 0.0001;
9 |
10 | vec3 rotateY(vec3 v, float x)
11 | {
12 | return vec3(
13 | cos(x)*v.x - sin(x)*v.z,
14 | v.y,
15 | sin(x)*v.x + cos(x)*v.z
16 | );
17 | }
18 |
19 | vec3 rotateX(vec3 v, float x)
20 | {
21 | return vec3(
22 | v.x,
23 | v.y*cos(x) - v.z*sin(x),
24 | v.y*sin(x) + v.z*cos(x)
25 | );
26 | }
27 |
28 | vec3 rotateZ(vec3 v, float x)
29 | {
30 | return vec3(
31 | v.x*cos(x) - v.y*sin(x),
32 | v.x*sin(x) + v.y*cos(x),
33 | v.z
34 | );
35 | }
36 |
37 |
38 | #ifndef FLAT_SHADED
39 |
40 | varying vec3 vNormal;
41 |
42 | #endif
43 |
44 | //chunk(common);
45 | //chunk(uv_pars_vertex);
46 | //chunk(uv2_pars_vertex);
47 | //chunk(displacementmap_pars_vertex);
48 | //chunk(envmap_pars_vertex);
49 | //chunk(lights_phong_pars_vertex);
50 | //chunk(color_pars_vertex);
51 | //chunk(morphtarget_pars_vertex);
52 | //chunk(skinning_pars_vertex);
53 | //chunk(shadowmap_pars_vertex);
54 | //chunk(logdepthbuf_pars_vertex);
55 |
56 | void main() {
57 |
58 | //chunk(uv_vertex);
59 | //chunk(uv2_vertex);
60 | //chunk(color_vertex);
61 |
62 | //chunk(beginnormal_vertex);
63 | //chunk(morphnormal_vertex);
64 | //chunk(skinbase_vertex);
65 | //chunk(skinnormal_vertex);
66 | //chunk(defaultnormal_vertex);
67 |
68 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED
69 |
70 | vec3 pos = texture2D( texturePosition, position.xy ).xyz;
71 | vec3 defaultPos = texture2D( textureDefaultPosition, position.xy ).xyz;
72 | float offsetDistance = distance(pos, defaultPos);
73 |
74 | pos += normal * 0.5;
75 |
76 | transformedNormal = rotateX(transformedNormal, offsetDistance * 0.02 * sin(fract(position.z * 21321.5125)));
77 | transformedNormal = rotateY(transformedNormal, offsetDistance * 0.02 * sin(fract(position.z * 51211.41)));
78 |
79 | vNormal = normalize( transformedNormal );
80 |
81 | #endif
82 |
83 | //chunk(begin_vertex);
84 | transformed = pos;
85 |
86 | //chunk(displacementmap_vertex);
87 | //chunk(morphtarget_vertex);
88 | //chunk(skinning_vertex);
89 | //chunk(project_vertex);
90 | //chunk(logdepthbuf_vertex);
91 |
92 | vViewPosition = - mvPosition.xyz;
93 |
94 |
95 |
96 | //chunk(worldpos_vertex);
97 | //chunk(envmap_vertex);
98 | //chunk(lights_phong_vertex);
99 | //chunk(shadowmap_vertex);
100 |
101 | gl_PointSize = mix(2600.0, 800.0, smoothstep(EPS, 2.0, offsetDistance)) / length( mvPosition.xyz );
102 | }
103 |
--------------------------------------------------------------------------------
/src/glsl/headDepth.frag:
--------------------------------------------------------------------------------
1 |
2 |
3 | varying float vDepthOffset;
4 |
5 | //chunk(common);
6 | //chunk(logdepthbuf_pars_fragment);
7 |
8 | vec4 pack_depth( const in float depth ) {
9 |
10 | const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );
11 | const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );
12 | vec4 res = mod( depth * bit_shift * vec4( 255 ), vec4( 256 ) ) / vec4( 255 );
13 | res -= res.xxyz * bit_mask;
14 | return res;
15 |
16 | }
17 |
18 | void main() {
19 |
20 | // float d = min(1.0, length(gl_PointCoord.xy - .5) * 2.0);
21 |
22 | //chunk(logdepthbuf_fragment);
23 |
24 | #ifdef USE_LOGDEPTHBUF_EXT
25 |
26 | gl_FragData[ 0 ] = pack_depth( gl_FragDepthEXT );
27 |
28 | #else
29 |
30 | //chunk(skinbase_vertex);
31 | gl_FragData[ 0 ] = pack_depth(gl_FragCoord.z - 1.0);
32 |
33 | #endif
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/glsl/headDepth.vert:
--------------------------------------------------------------------------------
1 |
2 | uniform sampler2D textureDefaultPosition;
3 | uniform sampler2D texturePosition;
4 |
5 | const float EPS = 0.0001;
6 |
7 | //chunk(common);
8 | //chunk(morphtarget_pars_vertex);
9 | //chunk(skinning_pars_vertex);
10 | //chunk(logdepthbuf_pars_vertex);
11 |
12 | void main() {
13 |
14 | //chunk(skinbase_vertex);
15 |
16 | //chunk(begin_vertex);
17 |
18 | vec3 pos = texture2D( texturePosition, position.xy ).xyz;
19 | vec3 defaultPos = texture2D( textureDefaultPosition, position.xy ).xyz;
20 | float offsetDistance = distance(pos, defaultPos);
21 | transformed = pos;
22 |
23 | //chunk(morphtarget_vertex);
24 | //chunk(skinning_vertex);
25 | //chunk(project_vertex);
26 | //chunk(logdepthbuf_vertex);
27 |
28 | gl_PointSize = mix(1800.0, 400.0, smoothstep(EPS, 2.0, offsetDistance)) / length( mvPosition.xyz );
29 | }
30 |
--------------------------------------------------------------------------------
/src/glsl/noise.glsl:
--------------------------------------------------------------------------------
1 | float rand(float n){return fract(sin(n) * 43758.5453123);}
2 |
3 | float noise(float p){
4 | float fl = floor(p);
5 | float fc = fract(p);
6 | return mix(rand(fl), rand(fl + 1.0), fc);
7 | }
8 |
9 |
10 | #pragma glslify: export(noise)
11 |
--------------------------------------------------------------------------------
/src/glsl/particle.frag:
--------------------------------------------------------------------------------
1 |
2 | // chunk(common);
3 | // chunk(fog_pars_fragment);
4 | // chunk(shadowmap_pars_fragment);
5 |
6 | #ifdef USE_BILLBOARD
7 |
8 | #else
9 |
10 | varying float vAlpha;
11 |
12 | #endif
13 |
14 | void main() {
15 |
16 | vec3 outgoingLight = vec3(1.0);
17 |
18 | // chunk(shadowmap_fragment);
19 |
20 | outgoingLight *= 0.1 + pow(shadowMask, vec3(1.5)) * 0.9;
21 |
22 | // chunk(fog_fragment);
23 | // chunk(linear_to_gamma_fragment);
24 |
25 |
26 | #ifdef USE_BILLBOARD
27 |
28 | gl_FragColor = vec4( outgoingLight, 1.0 );
29 |
30 | #else
31 |
32 | float d = length(gl_PointCoord.xy - .5) * 2.0;
33 |
34 | gl_FragColor = vec4( outgoingLight, vAlpha ) * (1.0 - step(1.0, d)) ;
35 |
36 | #endif
37 | }
38 |
--------------------------------------------------------------------------------
/src/glsl/particle.vert:
--------------------------------------------------------------------------------
1 | attribute vec2 fboUV;
2 | uniform sampler2D texturePosition;
3 |
4 | #ifdef USE_BILLBOARD
5 |
6 | attribute vec3 positionFlip;
7 | uniform float flipRatio;
8 |
9 | #else
10 |
11 | varying float vAlpha;
12 |
13 | #endif
14 |
15 | // chunk(shadowmap_pars_vertex);
16 |
17 | void main() {
18 |
19 | vec4 posInfo = texture2D( texturePosition, fboUV );
20 | vec3 pos = posInfo.xyz;
21 |
22 | vec4 worldPosition = modelMatrix * vec4( pos, 1.0 );
23 | vec4 mvPosition = viewMatrix * worldPosition;
24 |
25 | #ifdef USE_BILLBOARD
26 |
27 | vec4 flipOffset = vec4(mix(position, positionFlip, flipRatio) * 0.5, 1.0);
28 | worldPosition += flipOffset;
29 |
30 | #else
31 | gl_PointSize = ( 500.0 / length( mvPosition.xyz ) );
32 | mvPosition.y += gl_PointSize * 0.5;
33 |
34 | #endif
35 |
36 | // chunk(shadowmap_vertex);
37 |
38 |
39 | #ifdef USE_BILLBOARD
40 |
41 | gl_Position = projectionMatrix * (mvPosition + flipOffset);
42 |
43 | #else
44 |
45 | vAlpha = smoothstep(0.0, 0.1, posInfo.w);
46 | gl_Position = projectionMatrix * mvPosition;
47 |
48 | #endif
49 |
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/src/glsl/position.frag:
--------------------------------------------------------------------------------
1 | uniform vec2 resolution;
2 |
3 | uniform sampler2D textureVelocity;
4 | uniform sampler2D texturePosition;
5 | uniform sampler2D textureDefaultPosition;
6 |
7 | const float EPS = 0.0001;
8 |
9 | uniform float resetAnimation;
10 |
11 | void main() {
12 |
13 | vec2 uv = gl_FragCoord.xy / resolution.xy;
14 |
15 | vec3 velocity = texture2D( textureVelocity, uv ).xyz;
16 | vec3 position = texture2D( texturePosition, uv ).xyz;
17 | vec3 defaultPosition = texture2D( textureDefaultPosition, uv ).xyz;
18 |
19 | position += velocity;
20 |
21 | position += (defaultPosition - position) * pow(smoothstep(EPS, 1.0, resetAnimation), 3.0);
22 |
23 | position.y = max(position.y, -200.0);
24 |
25 | gl_FragColor = vec4(position, 1.0);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/src/glsl/velocity.frag:
--------------------------------------------------------------------------------
1 | uniform vec2 resolution;
2 | uniform vec3 mouse3d;
3 | uniform vec3 mouse3dVelocity;
4 | uniform float isPhysicsActive;
5 | uniform float resetAnimation;
6 |
7 | uniform float mouseForce;
8 | uniform float mouseRadius;
9 | uniform float gravity;
10 |
11 | uniform sampler2D textureVelocity;
12 | uniform sampler2D texturePosition;
13 | uniform sampler2D textureDefaultPosition;
14 |
15 | const float EPS = 0.0001;
16 |
17 | #pragma glslify: random = require(glsl-random)
18 |
19 | void main() {
20 |
21 | vec2 uv = gl_FragCoord.xy / resolution.xy;
22 |
23 | vec3 velocity = texture2D( textureVelocity, uv ).xyz;
24 | vec3 defaultPosition = texture2D( textureDefaultPosition, uv ).xyz;
25 | vec3 position = texture2D( texturePosition, uv ).xyz;
26 |
27 | float positionOffset = distance(position, defaultPosition);
28 |
29 | float toMouseStrength = length(position - mouse3d) /mouseRadius;
30 | toMouseStrength = step(-1.0, -toMouseStrength);
31 |
32 | if(position.y + velocity.y < -199.0) {
33 | float strength = abs(velocity.y) * 0.2;
34 | velocity.y *= -0.4 - random(uv + 2.0) * 0.2;
35 | velocity.x += (random(position.xy + strength) - 0.5);
36 | velocity.z += (random(position.zy) - 0.5);
37 | velocity.xz *= strength;
38 | } else {
39 | velocity.xz *= 0.99;
40 | velocity.y -= step(EPS, positionOffset + isPhysicsActive) * ( (1.0 - (defaultPosition.y + 200.0) / 500.0) + random(defaultPosition.xy)) * gravity;
41 | }
42 |
43 | velocity += (normalize(position - mouse3d) + mouse3dVelocity * 0.2) * pow(toMouseStrength, 2.0) * (1.0 + random(vec2(position.x + position.y, position.z)) * 0.3) * mouseForce;
44 | velocity *= 1.0 - step(EPS, resetAnimation);
45 |
46 | gl_FragColor = vec4(velocity, 1.0);
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/src/glsl/vignette.frag:
--------------------------------------------------------------------------------
1 | varying vec2 vUv;
2 | uniform vec2 uResolution;
3 | uniform float uAlpha;
4 | uniform float uTime;
5 |
6 | const float sqrt2 = 1.41421356237309;
7 | #pragma glslify: noise = require(./noise)
8 |
9 | void main() {
10 |
11 | vec2 toCenter = gl_FragCoord.xy / uResolution - 0.5;
12 | float angle = atan(toCenter.y / toCenter.x);
13 |
14 | float a = smoothstep(0.3 + 0.3 * noise(angle * 32313.12513 + uTime) , sqrt2, max(length(toCenter) * 2.0, 0.0));
15 |
16 | gl_FragColor = vec4(0.0, 0.0, 0.0, a * uAlpha);
17 | }
18 |
--------------------------------------------------------------------------------
/src/glsl/vignette.vert:
--------------------------------------------------------------------------------
1 | void main() {
2 | vec2 pos = position.xy;
3 | gl_Position = vec4( pos, 0.0, 1.0 );
4 | }
5 |
--------------------------------------------------------------------------------
/src/helpers/shaderParse.js:
--------------------------------------------------------------------------------
1 | var THREE = require('three');
2 |
3 | var threeChunkReplaceRegExp = /\/\/\s?chunk_replace\s(.+)([\d\D]+)\/\/\s?end_chunk_replace/gm;
4 | var threeChunkRegExp = /\/\/\s?chunk\(\s?(\w+)\s?\);/g;
5 | var glslifyBugFixRegExp = /(_\d+_\d+)(_\d+_\d+)+/g;
6 | var glslifyGlobalRegExp = /GLOBAL_VAR_(.+)(_\d+_\d+)+/g;
7 |
8 | var _chunkReplaceObj;
9 |
10 | function _storeChunkReplaceParse(shader) {
11 | _chunkReplaceObj = {};
12 | return shader.replace(threeChunkReplaceRegExp, _storeChunkReplaceFunc);
13 | }
14 |
15 | function _threeChunkParse(shader) {
16 | return shader.replace(threeChunkRegExp, _replaceThreeChunkFunc);
17 | }
18 |
19 | function _glslifyBugFixParse(shader) {
20 | return shader.replace(glslifyBugFixRegExp, _returnFirst);
21 | }
22 |
23 | function _glslifyGlobalParse(shader) {
24 | return shader.replace(glslifyGlobalRegExp, _returnFirst);
25 | }
26 |
27 | function _storeChunkReplaceFunc(a, b, c) {
28 | _chunkReplaceObj[b.trim()] = c;
29 | return '';
30 | }
31 |
32 | function _replaceThreeChunkFunc(a, b) {
33 | var str = THREE.ShaderChunk[b] + '\n';
34 | for(var id in _chunkReplaceObj) {
35 | str = str.replace(id, _chunkReplaceObj[id]);
36 | }
37 | return str;
38 | }
39 |
40 | function _returnFirst(a, b) {
41 | return b;
42 | }
43 |
44 | function parse(shader) {
45 | shader = _storeChunkReplaceParse(shader);
46 | shader = _threeChunkParse(shader);
47 | shader = _glslifyBugFixParse(shader);
48 | return _glslifyGlobalParse(shader);
49 | }
50 |
51 | module.exports = parse;
52 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | var quickLoader = require('quick-loader');
2 | var dat = require('dat-gui');
3 | var Stats = require('stats.js');
4 | var css = require('dom-css');
5 | var raf = require('raf');
6 |
7 | var THREE = require('three');
8 |
9 | var OrbitControls = require('./controls/OrbitControls');
10 | var settings = require('./core/settings');
11 |
12 | var head = require('./3d/head');
13 | var ground = require('./3d/ground');
14 | var vignette = require('./3d/vignette');
15 | var lights = require('./3d/lights');
16 | var fbo = require('./3d/fbo');
17 |
18 | var math = require('./utils/math');
19 | var ease = require('./utils/ease');
20 | var mobile = require('./fallback/mobile');
21 |
22 | var undef;
23 | var _gui;
24 | var _stats;
25 |
26 | var _width = 0;
27 | var _height = 0;
28 |
29 | var _control;
30 | var _camera;
31 | var _scene;
32 | var _renderer;
33 | var _mouseMesh;
34 |
35 | var _renderingGui;
36 | var _similuationGui;
37 | var _envGui;
38 |
39 | var _time = 0;
40 | var _ray = new THREE.Ray();
41 |
42 | var _initAnimation = 0;
43 | var _hasSetDefault = false;
44 |
45 | var _logo;
46 | var _footerItems;
47 |
48 | var EPS = 0.00001;
49 |
50 | function init() {
51 |
52 | if(settings.useStats) {
53 | _stats = new Stats();
54 | css(_stats.domElement, {
55 | position : 'absolute',
56 | left : '0px',
57 | top : '0px',
58 | zIndex : 2048
59 | });
60 |
61 | document.body.appendChild( _stats.domElement );
62 | }
63 |
64 | settings.mouse = new THREE.Vector2(-9999,0);
65 | settings.mouse3d = _ray.origin;
66 |
67 | _renderer = new THREE.WebGLRenderer({
68 | // antialias : true
69 | });
70 | _renderer.setClearColor(0x444444);
71 | _renderer.shadowMap.type = THREE.PCFSoftShadowMap;
72 | _renderer.shadowMap.enabled = true;
73 | document.body.appendChild(_renderer.domElement);
74 |
75 | _scene = new THREE.Scene();
76 | _scene.fog = new THREE.FogExp2( 0x444444, 0.001 );
77 |
78 | _camera = new THREE.PerspectiveCamera( 45, 1, 200, 3000);
79 | _camera.position.set(134, 5, 800).normalize().multiplyScalar(1500);
80 | settings.cameraPosition = _camera.position;
81 |
82 | _control = new OrbitControls( _camera, _renderer.domElement );
83 | // _control.minDistance = 600;
84 | _control.maxDistance = 1500;
85 | _control.minPolarAngle = 0.3;
86 | _control.maxPolarAngle = Math.PI / 2;
87 | _control.noPan = true;
88 | _control.update();
89 |
90 | lights.init();
91 | _scene.add(lights.mesh);
92 |
93 | var envMap = settings.envMap = (new THREE.TextureLoader()).load('images/env.jpg');
94 | envMap.format = THREE.RGBFormat;
95 | envMap.wrapS = envMap.wrapT = THREE.MirroredRepeatWrapping;
96 | envMap.mapping = THREE.EquirectangularReflectionMapping;
97 | envMap.magFilter = THREE.LinearFilter;
98 | envMap.minFilter = THREE.LinearMipMapLinearFilter;
99 |
100 | head.init();
101 | _scene.add(head.mesh);
102 |
103 | fbo.init(_renderer);
104 |
105 | ground.init();
106 | _scene.add(ground.mesh);
107 |
108 | vignette.init();
109 | _scene.add(vignette.mesh);
110 |
111 | var mouseGeometry = new THREE.IcosahedronGeometry(1, 3);
112 | _mouseMesh = new THREE.Mesh(mouseGeometry, new THREE.MeshPhongMaterial({
113 | side: THREE.BackSide,
114 | color: 0x999999,
115 | specular: 0x444444,
116 | shininess: 20,
117 | envMap: envMap,
118 | transparent: true,
119 | opacity: 0.3
120 | }));
121 | _mouseMesh.add(new THREE.Mesh(mouseGeometry, new THREE.MeshPhongMaterial({
122 | transparent: true,
123 | color: 0x999999,
124 | specular: 0x444444,
125 | shininess: 20,
126 | envMap: envMap,
127 | opacity: 0.05
128 | })));
129 |
130 |
131 | _scene.add(_mouseMesh);
132 |
133 | var guiFunctions = {
134 | resetParticles : _resetParticles
135 | };
136 |
137 | _gui = new dat.GUI();
138 | _renderingGui = _gui.addFolder('rendering');
139 | _renderingGui.add(head, 'normalNoise', 0, 1, 0.001);
140 | _renderingGui.add(head, 'useDiffuse').name('diffuse map');
141 | _renderingGui.add(head, 'useEnv').name('env map');
142 | _similuationGui = _gui.addFolder('similuation');
143 | _similuationGui.add(settings, 'isMouseVisible').name('mouse');
144 | _similuationGui.add(fbo.velocityUniforms.mouseRadius, 'value', 50, 300).name('mouse radius').listen();
145 | _similuationGui.add(fbo.velocityUniforms.mouseForce, 'value', 0.01, 0.5).name('mouse force');
146 | _similuationGui.add(settings, 'mouseZRatio', 0.8, 1.2).name('mouse z ratio');
147 | _similuationGui.add(fbo.velocityUniforms.gravity, 'value', -1, 1).name('gravity');
148 | _similuationGui.add(settings, 'gravityAllOnClick').name('destory on click').listen();
149 | _envGui = _gui.addFolder('env');
150 | _envGui.add(vignette.mesh, 'visible').name('vignette');
151 | _envGui.add(_mouseMesh, 'visible').name('mouse visibility');
152 | _gui.add(guiFunctions, 'resetParticles');
153 |
154 | if(window.screen.width > 480) {
155 | _renderingGui.open();
156 | _similuationGui.open();
157 | _envGui.open();
158 | }
159 |
160 | _logo = document.querySelector('.logo');
161 | document.querySelector('.footer').style.display = 'block';
162 | _footerItems = document.querySelectorAll('.footer span');
163 |
164 | _gui.domElement.addEventListener('mousedown', _stopPropagation);
165 | // _gui.domElement.addEventListener('mousemove', _stopPropagation);
166 | _gui.domElement.addEventListener('touchstart', _stopPropagation);
167 | // _gui.domElement.addEventListener('touchmove', _stopPropagation);
168 |
169 | window.addEventListener('resize', _onResize);
170 | window.addEventListener('mousedown', _onDown);
171 | window.addEventListener('mousemove', _onMove);
172 | // window.addEventListener('mouseup', _onUp);
173 | window.addEventListener('touchstart', _bindTouch(_onDown));
174 | window.addEventListener('touchmove', _bindTouch(_onMove));
175 | // window.addEventListener('touchend', _onUp);
176 |
177 | _time = Date.now();
178 | _onResize();
179 | _loop();
180 |
181 | }
182 |
183 | function _stopPropagation(evt) {
184 | evt.stopPropagation();
185 | }
186 |
187 | function _bindTouch(func) {
188 | return function (evt) {
189 | func(evt.changedTouches[0]);
190 | };
191 | }
192 |
193 | function _onDown(evt) {
194 | settings.isMouseActive = true;
195 | if(settings.gravityAllOnClick) {
196 | settings.isPhysicsActive = true;
197 | }
198 | _onMove(evt);
199 | }
200 |
201 | function _onMove(evt) {
202 | settings.mouse.x = (evt.pageX / _width) * 2 - 1;
203 | settings.mouse.y = -(evt.pageY / _height) * 2 + 1;
204 | }
205 |
206 | function _onResize() {
207 | _width = window.innerWidth;
208 | _height = window.innerHeight;
209 |
210 | vignette.resize(_width, _height);
211 |
212 | _camera.aspect = _width / _height;
213 | _camera.updateProjectionMatrix();
214 | _renderer.setSize(_width, _height);
215 |
216 | }
217 |
218 | function _loop() {
219 | var newTime = Date.now();
220 | raf(_loop);
221 | if(settings.useStats) _stats.begin();
222 | _render(newTime - _time);
223 | if(settings.useStats) _stats.end();
224 | _time = newTime;
225 | }
226 |
227 | function _resetParticles() {
228 | settings.resetAnimation = EPS;
229 | settings.isMouseActive = false;
230 | settings.isPhysicsActive = false;
231 | }
232 |
233 | function _setDefault() {
234 | _hasSetDefault = true;
235 | _resetParticles();
236 | settings.gravityAllOnClick = false;
237 | settings.isPhysicsActive = false;
238 | }
239 |
240 | function _render(dt) {
241 |
242 | var ratio, ratio2, ratio3;
243 | _initAnimation = Math.min(_initAnimation + dt * 0.00015, 1);
244 |
245 | vignette.alphaUniform.value = math.lerp(0.7, 0.3, math.unLerp(0, 0.5, _initAnimation));
246 |
247 | _control.maxDistance = _initAnimation === 1 ? 1500 : math.lerp(1500, 700, ease.easeOutSine(_initAnimation));
248 | if(_initAnimation < 1) {
249 | _control.object.position.y = math.lerp(800, 5, ease.easeOutSine(_initAnimation));
250 | }
251 | _control.update();
252 |
253 | // update mouse3d
254 | _camera.updateMatrixWorld();
255 | _ray.origin.setFromMatrixPosition( _camera.matrixWorld );
256 | _ray.direction.set( settings.mouse.x, settings.mouse.y, 0.5 ).unproject( _camera ).sub( _ray.origin ).normalize();
257 | var distance = _ray.origin.length() / Math.cos(Math.PI - _ray.direction.angleTo(_ray.origin));
258 | _ray.origin.add( _ray.direction.multiplyScalar(distance * settings.mouseZRatio));
259 |
260 | if(_initAnimation < 1) {
261 | ratio = ease.easeInOutBack(math.unLerp(0, 0.4, _initAnimation));
262 | ratio2 = math.unLerp(0.3, 0.9, _initAnimation);
263 | ratio3 = ease.easeOutSine(math.unLerp(0.7, 1, _initAnimation));
264 | _ray.origin.x = math.lerp(Math.sin(ratio2 * Math.PI * 4) * 150, _ray.origin.x, ratio3);
265 | _ray.origin.y = math.lerp((1 - ratio) * 400 + Math.sin(ratio2 * Math.PI * 5) * 150, _ray.origin.y, ratio3);
266 | _ray.origin.z = math.lerp(Math.sin(ratio2 * Math.PI * 6) * 150, _ray.origin.z, ratio3);
267 | fbo.velocityUniforms.mouseRadius.value = (1 - ratio) * 60 + Math.sin(ratio2 * Math.PI * 6) * 90 * ratio3 + 105;
268 | } else {
269 | if(!_hasSetDefault) {
270 | _setDefault();
271 | }
272 | }
273 |
274 | ratio = Math.min((1 - Math.abs(_initAnimation - 0.5) * 2) * 1.2, 1);
275 | var blur = (1 - ratio) * 10;
276 | _logo.style.display = ratio ? 'block' : 'none';
277 | if(ratio) {
278 | _logo.style.opacity = ratio;
279 | _logo.style.webkitFilter = 'blur(' + blur + 'px)';
280 | ratio = (0.8 + Math.pow(_initAnimation, 1.5) * 0.3);
281 | if(_width < 580) ratio *= 0.5;
282 | _logo.style.transform = 'scale3d(' + ratio + ',' + ratio + ',1)';
283 | }
284 |
285 | for(var i = 0, len = _footerItems.length; i < len; i++) {
286 | ratio = math.unLerp(0.5 + i * 0.01, 0.6 + i * 0.01, _initAnimation);
287 | _footerItems[i].style.transform = 'translate3d(0,' + ((1 - Math.pow(ratio, 3)) * 50) + 'px,0)';
288 | }
289 |
290 | if(settings.resetAnimation > 0) {
291 | settings.resetAnimation += dt * 0.0005;
292 | }
293 | fbo.update(dt);
294 |
295 | if(settings.resetAnimation > 1) {
296 | settings.resetAnimation = 0;
297 | }
298 |
299 | head.update(dt);
300 |
301 | vignette.alphaUniform.value = 0.5;
302 | vignette.update(dt);
303 |
304 | // console.log(_camera.position.x, _camera.position.y, _camera.position.z);
305 | var mouseRadius = fbo.velocityUniforms.mouseRadius.value;
306 | _mouseMesh.scale.set(mouseRadius, mouseRadius, mouseRadius);
307 | _mouseMesh.position.copy(_ray.origin);
308 |
309 | _renderer.render(_scene, _camera);
310 | }
311 |
312 | mobile.pass(function() {
313 | // quickLoader.add('images/env.jpg', {
314 | // onLoad: function(img) {
315 | // settings.envMapImg = img;
316 | // }
317 | // });
318 | // quickLoader.add('images/diffuse.jpg', {
319 | // onLoad: function(img) {
320 | // settings.diffuseMapImg = img;
321 | // }
322 | // });
323 |
324 | quickLoader.add('models/LeePerrySmith.json', {
325 | onLoad: function(data) {
326 | settings.headData = data;
327 | }
328 | });
329 | quickLoader.start(function(percent) {
330 | if(percent === 1) {
331 | init();
332 | }
333 | });
334 | });
335 |
--------------------------------------------------------------------------------
/src/libs/global_three/index.js:
--------------------------------------------------------------------------------
1 | module.exports = window.THREE;
2 |
--------------------------------------------------------------------------------
/src/libs/global_three/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "three",
3 | "version": "0.73.0",
4 | "private": true,
5 | "description": "",
6 | "main": "index.js",
7 | "dependencies": {
8 | },
9 | "devDependencies": {
10 | },
11 | "scripts": {
12 | },
13 | "author": "",
14 | "license": "MIT"
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/ease.js:
--------------------------------------------------------------------------------
1 | // from https://github.com/kaelzhang/easing-functions/
2 | var basic = {
3 | Linear: {
4 | None: function(e) {
5 | return e;
6 | }
7 | },
8 | Quad: {
9 | In: function(e) {
10 | return e * e;
11 | },
12 | Out: function(e) {
13 | return e * (2 - e);
14 | },
15 | InOut: function(e) {
16 | if ((e *= 2) < 1) return 0.5 * e * e;
17 | return - 0.5 * (--e * (e - 2) - 1);
18 | }
19 | },
20 | Cubic: {
21 | In: function(e) {
22 | return e * e * e;
23 | },
24 | Out: function(e) {
25 | return --e * e * e + 1;
26 | },
27 | InOut: function(e) {
28 | if ((e *= 2) < 1) return 0.5 * e * e * e;
29 | return 0.5 * ((e -= 2) * e * e + 2);
30 | }
31 | },
32 | Quart: {
33 | In: function(e) {
34 | return e * e * e * e;
35 | },
36 | Out: function(e) {
37 | return 1 - --e * e * e * e;
38 | },
39 | InOut: function(e) {
40 | if ((e *= 2) < 1) return 0.5 * e * e * e * e;
41 | return - 0.5 * ((e -= 2) * e * e * e - 2);
42 | }
43 | },
44 | Quint: {
45 | In: function(e) {
46 | return e * e * e * e * e;
47 | },
48 | Out: function(e) {
49 | return --e * e * e * e * e + 1;
50 | },
51 | InOut: function(e) {
52 | if ((e *= 2) < 1) return 0.5 * e * e * e * e * e;
53 | return 0.5 * ((e -= 2) * e * e * e * e + 2);
54 | }
55 | },
56 | Sine: {
57 | In: function(e) {
58 | return 1 - Math.cos(e * Math.PI / 2);
59 | },
60 | Out: function(e) {
61 | return Math.sin(e * Math.PI / 2);
62 | },
63 | InOut: function(e) {
64 | return 0.5 * (1 - Math.cos(Math.PI * e));
65 | }
66 | },
67 | Expo: {
68 | In: function(e) {
69 | return e === 0 ? 0 : Math.pow(1024, e - 1);
70 | },
71 | Out: function(e) {
72 | return e === 1 ? 1 : 1 - Math.pow(2, -10 * e);
73 | },
74 | InOut: function(e) {
75 | if (e === 0) return 0;
76 | if (e === 1) return 1;
77 | if ((e *= 2) < 1) return 0.5 * Math.pow(1024, e - 1);
78 | return 0.5 * (-Math.pow(2, -10 * (e - 1)) + 2);
79 | }
80 | },
81 | Circ: {
82 | In: function(e) {
83 | return 1 - Math.sqrt(1 - e * e);
84 | },
85 | Out: function(e) {
86 | return Math.sqrt(1 - --e * e);
87 | },
88 | InOut: function(e) {
89 | if ((e *= 2) < 1) return - 0.5 * (Math.sqrt(1 - e * e) - 1);
90 | return 0.5 * (Math.sqrt(1 - (e -= 2) * e) + 1);
91 | }
92 | },
93 | Elastic: {
94 | In: function(e) {
95 | var t, n =0.1,
96 | r =0.4;
97 | if (e === 0) return 0;
98 | if (e === 1) return 1;
99 | if (!n || n < 1) {
100 | n = 1;
101 | t = r / 4;
102 | } else t = r * Math.asin(1 / n) / (2 * Math.PI);
103 | return -(n * Math.pow(2, 10 * (e -= 1)) * Math.sin((e - t) * 2 * Math.PI / r));
104 | },
105 | Out: function(e) {
106 | var t, n =0.1,
107 | r =0.4;
108 | if (e === 0) return 0;
109 | if (e === 1) return 1;
110 | if (!n || n < 1) {
111 | n = 1;
112 | t = r / 4;
113 | } else t = r * Math.asin(1 / n) / (2 * Math.PI);
114 | return n * Math.pow(2, -10 * e) * Math.sin((e - t) * 2 * Math.PI / r) + 1;
115 | },
116 | InOut: function(e) {
117 | var t, n =0.1,
118 | r =0.4;
119 | if (e === 0) return 0;
120 | if (e === 1) return 1;
121 | if (!n || n < 1) {
122 | n = 1;
123 | t = r / 4;
124 | } else {
125 | t = r * Math.asin(1 / n) / (2 * Math.PI);
126 | }
127 | if ((e *= 2) < 1) return - 0.5 * n * Math.pow(2, 10 * (e -= 1)) * Math.sin((e - t) * 2 * Math.PI / r);
128 | return n * Math.pow(2, -10 * (e -= 1)) * Math.sin((e - t) * 2 * Math.PI / r) *0.5 + 1;
129 | }
130 | },
131 | Back: {
132 | In: function(e) {
133 | var t = 1.70158;
134 | return e * e * ((t + 1) * e - t);
135 | },
136 | Out: function(e) {
137 | var t = 1.70158;
138 | return --e * e * ((t + 1) * e + t) + 1;
139 | },
140 | InOut: function(e) {
141 | var t = 1.70158 * 1.525;
142 | if ((e *= 2) < 1) return 0.5 * e * e * ((t + 1) * e - t);
143 | return 0.5 * ((e -= 2) * e * ((t + 1) * e + t) + 2);
144 | }
145 | },
146 | Bounce: {
147 | In: function(e) {
148 | return 1 - basic.Bounce.Out(1 - e);
149 | },
150 | Out: function(e) {
151 | if (e < 1 / 2.75) {
152 | return 7.5625 * e * e;
153 | } else if (e < 2 / 2.75) {
154 | return 7.5625 * (e -= 1.5 / 2.75) * e +0.75;
155 | } else if (e < 2.5 / 2.75) {
156 | return 7.5625 * (e -= 2.25 / 2.75) * e +0.9375;
157 | } else {
158 | return 7.5625 * (e -= 2.625 / 2.75) * e +0.984375;
159 | }
160 | },
161 | InOut: function(e) {
162 | if (e <0.5) return basic.Bounce.In(e * 2) *0.5;
163 | return basic.Bounce.Out(e * 2 - 1) *0.5 +0.5;
164 | }
165 | }
166 | };
167 |
168 | exports.basic = basic;
169 | exports.linear = basic.Linear;
170 |
171 | var id, list;
172 | for(id in basic) {
173 | if(id !== 'Linear') {
174 | list = basic[id];
175 | exports['easeIn' + id] = list.In;
176 | exports['easeOut' + id] = list.Out;
177 | exports['easeInOut' + id] = list.InOut;
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/src/utils/math.js:
--------------------------------------------------------------------------------
1 | for(var id in Math) {
2 | exports[id] = Math[id];
3 | }
4 |
5 | exports.step = step;
6 | exports.smoothstep = smoothstep;
7 | exports.clamp = clamp;
8 | exports.mix = exports.lerp = mix;
9 | exports.unMix = exports.unLerp = unMix;
10 | exports.unClampedMix = exports.unClampedLerp = unClampedMix;
11 | exports.upClampedUnMix = exports.unClampedUnLerp = upClampedUnMix;
12 | exports.fract = fract;
13 | exports.hash = hash;
14 | exports.hash2 = hash2;
15 | exports.sign = sign;
16 |
17 | var PI = Math.PI;
18 | var TAU = exports.TAU = PI * 2;
19 |
20 | function step ( edge, val ) {
21 | return val < edge ? 0 : 1;
22 | }
23 |
24 | function smoothstep ( edge0, edge1, val ) {
25 | val = unMix( edge0, edge1, val );
26 | return val * val ( 3 - val * 2 );
27 | }
28 |
29 | function clamp ( val, min, max ) {
30 | return val < min ? min : val > max ? max : val;
31 | }
32 |
33 | function mix ( min, max, val ) {
34 | return val <= 0 ? min : val >= 1 ? max : min + ( max - min ) * val;
35 | }
36 |
37 | function unMix ( min, max, val ) {
38 | return val <= min ? 0 : val >= max ? 1 : ( val - min ) / ( max - min );
39 | }
40 |
41 | function unClampedMix ( min, max, val ) {
42 | return min + ( max - min ) * val;
43 | }
44 |
45 | function upClampedUnMix ( min, max, val ) {
46 | return ( val - min ) / ( max - min );
47 | }
48 |
49 | function fract ( val ) {
50 | return val - Math.floor( val );
51 | }
52 |
53 | function hash (val) {
54 | return fract( Math.sin( val ) * 43758.5453123 );
55 | }
56 |
57 | function hash2 (val1, val2) {
58 | return fract( Math.sin( val1 * 12.9898 + val2 * 4.1414 ) * 43758.5453 );
59 | }
60 |
61 | function sign (val) {
62 | return val ? val < 0 ? - 1 : 1 : 0;
63 | }
64 |
--------------------------------------------------------------------------------