├── .gitignore
├── README.md
├── article.html
├── css
└── base.css
├── favicon.ico
├── img
├── disp1.jpg
├── disp3.jpg
├── img11.jpg
├── img12.jpg
├── img13.jpg
├── img21.jpg
├── img22.jpg
├── img23.jpg
├── img31.jpg
├── img32.jpg
├── img33.jpg
├── img41.jpg
├── img42.jpg
├── img43.jpg
├── img51.jpg
├── img52.jpg
├── img53.jpg
├── img61.jpg
├── img62.jpg
├── img63.jpg
├── img64.jpg
├── img71.jpg
├── img72.jpg
├── img73.jpg
├── img81.jpg
├── img82.jpg
└── img83.jpg
├── index.html
├── index2.html
├── index3.html
├── index4.html
├── index5.html
├── index6.html
├── index7.html
├── index8.html
└── js
├── dat-gui.js
├── demo1.js
├── demo2.js
├── demo3.js
├── demo4.js
├── demo5.js
├── demo6.js
├── demo7.js
├── demo8.js
├── gsap.js
├── orbit.js
├── sketch.js
└── three.js
/.gitignore:
--------------------------------------------------------------------------------
1 | *.DS_Store
2 | work/
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Creative WebGL Image Transitions
2 |
3 | A set of interesting looking image transitions including distortion and warp effects made with WebGL.
4 |
5 | 
6 |
7 | [Article on Codrops](https://tympanus.net/codrops/?p=44490)
8 |
9 | [Demo](http://tympanus.net/Development/webGLImageTransitions/)
10 |
11 | ## Credits
12 |
13 | * [three.js](https://threejs.org/)
14 | * [GL Transitions](https://gl-transitions.com/)
15 | * Images from [Unsplash](https://unsplash.com/)
16 |
17 | ## License
18 | This resource can be used freely if integrated or build upon in personal or commercial projects such as websites, web apps and web templates intended for sale. It is not allowed to take the resource "as-is" and sell it, redistribute, re-publish it, or sell "pluginized" versions of it. Free plugins built using this resource should have a visible mention and link to the original work. Always consider the licenses of all included libraries, scripts and images used.
19 |
20 | ## Misc
21 |
22 | Follow Codrops: [Twitter](http://www.twitter.com/codrops), [Facebook](http://www.facebook.com/codrops), [Google+](https://plus.google.com/101095823814290637419), [GitHub](https://github.com/codrops), [Pinterest](http://www.pinterest.com/codrops/), [Instagram](https://www.instagram.com/codropsss/)
23 |
24 |
25 | [© Codrops 2019](http://www.codrops.com)
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/article.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | After introductory paragraph:
7 |
8 |
9 |
10 | The demo is kindly sponsored by . If you would like to sponsor one of our demos, find out more here .
11 |
12 |
13 |
14 |
15 |
16 | Everybody loves images. They are bright, colorful, they might be dog, cat, or a person. Even text sometimes strives to be an image.
17 |
18 | |\_/|
19 | | @ @ Woof!
20 | | <> _
21 | | _/\------____ ((| |))
22 | | `--' |
23 | ____|_ ___| |___.'
24 | /_/_____/____/_______|
25 |
26 | But once you have more than one image, you can't help making a transition between them. Or is it just me? 🤔
27 | Jokes aside, image transitions are all over the web. They can be animated with CSS, SVG, WebGL. But of course, the most efficient way to work with graphics in the browser – is using Graphics Processor, or GPU. And the the best way to do this is WebGL, with shaders written in GLSL.
28 |
29 | Set up
30 | I will be using THREE.js framework for my transitions. It doesnt really matter what library to use, it could have been amazing Pixi.js, or simple (but not so straightforward) native WebGL. I've used native WebGL in my previous tutorial , so this time i will try THREE.js. It also seems most beginner friendly to me. So dont blame me for overhead size.
31 | Three.js uses concepts of Camera, Scene and Objects. We will create a simple Plane object, add it to Scene and put it in front of Camera, so that it is the only thing that you can see. There is a template for that kind of object PlaneBufferGeometry :
32 |
33 | To cover the whole screen with a plane you need a little bit of geometry. Camera has a fov(field of view), and plane has a size. So with some calculations you can get it to fill your whole screen:
34 |
35 | camera.fov = 2*(180/Math.PI)*Math.atan(PlaneSize/(2*CameraDistance));
36 |
37 | Looks complicated, but its just getting the angle(fov), knowing all the distances here:
38 |
39 | That is actually the end of 3D part, everything else will be happening in 2D.
40 |
41 | GLSL
42 | In case you are not yet familiar with this language i highly advise you to check out wonderful Book Of Shaders .
43 | So, we have a plane and we have a fragment shader attached to it, that calculates each pixels color.
44 | How do we make a transition? The simplest one done with shader looks like this:
45 |
46 | void main() {
47 | vec4 image1 = texture2D(texture1,uv);
48 | vec4 image2 = texture2D(texture2,uv);
49 | gl_FragColor = mix(image1, image2, progress);
50 | }
51 | Where progress
, is some number between 0 and 1, indicating progress of animation.
52 | With that kind code you will get the simplest fade transition between images. But that's not that cool, right?
53 | Cool transition
54 | Usually all transitions are based on changing so called UVs, or the way texture is wrapped on plane. So for instance multiplying UV: scales the image. Adding some number: just shifts image on a plane.
55 | UVs are nothing magical, think of it as a coordinate system for pixels on a plane:
56 |
57 | Let's start with a basic code:
58 |
59 | gl_FragColor = texture2D(texture,uv);
60 |
61 |
62 | Which just shows an image on a screen. Now what if we change that a bit:
63 |
64 | gl_FragColor = texture2D(texture,fract(uv + uv));
65 |
66 | By taking fractional part, we make sure, all the values stay within 0-1 range. And if UV was from 0 to 1, doubled it is from 0 to 2, so we should see fractional part chaning from 0 to 1, and from 0 to 1 again!
67 |
68 | And thats what you get, repeated image. Now lets try something different, substracting UV and using progress for animation:
69 |
70 | gl_FragColor = texture2D(texture, uv - uv * vec2(1.,0) * progress * 0.5);
71 |
72 | First, we make sure we are only chaning one axis of UV, by multplying it with vec2(1.,0). So when progress is 0, it should be default image, let's see:
73 |
74 | So now we can stretch the image!
75 | Now let's combine those two effects into one.
76 |
77 | gl_FragColor = texture2D(uTextureOne, uv - fract(uv * vec2(5.,0.)) * progress * 0.1 );
78 |
79 | So basically, we do stretching repeated 5 times now. And we could use any number instead of 5.
80 |
81 | Much better! Now if we add another image, we could get one of my demos!
82 |
83 | Cool isnt it? Just two simple arithmetic operations, and you have a cool transition effect.
84 | That's just one way of changing UVs, check out all the other demos, and try to guess whats the math behind them! And try to come up with your own unique animation, share it with me! And have a nice day =).
85 |
86 |
87 |
88 | -----------------------------------------------------------------------------
89 |
90 |
91 |
92 |
93 |
94 | References and Credits
95 |
--------------------------------------------------------------------------------
/css/base.css:
--------------------------------------------------------------------------------
1 | *,
2 | *::after,
3 | *::before {
4 | box-sizing: border-box;
5 | }
6 |
7 | :root {
8 | font-size: 16px;
9 | }
10 |
11 | body {
12 | margin: 0;
13 | --color-text: #000;
14 | --color-bg: #fff;
15 | --color-link: #4b4b4b;
16 | --color-link-hover: #000;
17 | color: var(--color-text);
18 | background-color: var(--color-bg);
19 | font-family: ivymode, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial, sans-serif;
20 | -webkit-font-smoothing: antialiased;
21 | -moz-osx-font-smoothing: grayscale;
22 | }
23 |
24 | .demo-1 {
25 | --color-text: #ffffff;
26 | --color-link: #1c4a62;
27 | --color-link-hover: #fff;
28 | }
29 |
30 | .demo-3 {
31 | --color-text: #3ca5c7;
32 | --color-link: #d29021;
33 | --color-link-hover: #b97a0e;
34 | }
35 |
36 | .demo-4 {
37 | --color-text: #b9735d;
38 | --color-link: #fff;
39 | --color-link-hover: #b9735d;
40 | }
41 |
42 | .demo-5 {
43 | --color-text: #01a19c;
44 | --color-link: #fff;
45 | --color-link-hover: #01a19c;
46 | }
47 |
48 | .demo-6 {
49 | --color-text: #e8a770;
50 | --color-link: #fff;
51 | --color-link-hover: #e8a770;
52 | }
53 |
54 | .demo-7 {
55 | --color-link: #fff;
56 | --color-link-hover: #000;
57 | }
58 |
59 | .demo-8 {
60 | --color-text: #fff;
61 | --color-link: #000;
62 | --color-link-hover: #fff;
63 | }
64 |
65 | /* Page Loader */
66 | .js .loading::before,
67 | .js .loading::after {
68 | content: '';
69 | position: fixed;
70 | z-index: 1000;
71 | }
72 |
73 | .js .loading::before {
74 | top: 0;
75 | left: 0;
76 | width: 100%;
77 | height: 100%;
78 | background: var(--color-bg);
79 | }
80 |
81 | .js .loading::after {
82 | top: 50%;
83 | left: 50%;
84 | width: 60px;
85 | height: 60px;
86 | margin: -30px 0 0 -30px;
87 | border-radius: 50%;
88 | opacity: 0.4;
89 | background: var(--color-link);
90 | animation: loaderAnim 0.7s linear infinite alternate forwards;
91 |
92 | }
93 |
94 | @keyframes loaderAnim {
95 | to {
96 | opacity: 1;
97 | transform: scale3d(0.5,0.5,1);
98 | }
99 | }
100 |
101 | a {
102 | text-decoration: none;
103 | color: var(--color-link);
104 | outline: none;
105 | }
106 |
107 | a:hover,
108 | a:focus {
109 | color: var(--color-link-hover);
110 | outline: none;
111 | text-decoration: underline;
112 | }
113 |
114 | .message {
115 | background: var(--color-text);
116 | color: var(--color-bg);
117 | padding: 1rem;
118 | text-align: center;
119 | }
120 |
121 | .frame {
122 | padding: 3rem 5vw;
123 | text-align: center;
124 | position: relative;
125 | z-index: 1000;
126 | }
127 |
128 | .frame__title {
129 | font-size: 1rem;
130 | margin: 0 0 1rem;
131 | font-weight: normal;
132 | }
133 |
134 | .frame__links {
135 | display: inline;
136 | }
137 |
138 | .frame__links a:not(:last-child) {
139 | margin-right: 1rem;
140 | }
141 |
142 | .frame__demos a:not(:last-child) {
143 | margin-right: 2rem;
144 | }
145 |
146 | .frame__demos {
147 | margin: 1rem 0;
148 | }
149 |
150 | .frame__demo {
151 | white-space: nowrap;
152 | }
153 |
154 | .frame__demo--current,
155 | .frame__demo--current:hover {
156 | color: var(--color-text);
157 | }
158 |
159 | .content {
160 | display: flex;
161 | flex-direction: column;
162 | width: 100vw;
163 | height: calc(100vh - 13rem);
164 | position: relative;
165 | justify-content: flex-start;
166 | align-items: center;
167 | cursor: pointer;
168 | }
169 |
170 | @media screen and (min-width: 53em) {
171 | .message {
172 | display: none;
173 | }
174 | .frame {
175 | position: fixed;
176 | text-align: left;
177 | z-index: 100;
178 | top: 0;
179 | left: 0;
180 | display: grid;
181 | align-content: space-between;
182 | width: 100%;
183 | max-width: none;
184 | height: 100vh;
185 | padding: 2rem;
186 | grid-gap: 3rem;
187 | pointer-events: none;
188 | -webkit-touch-callout: none;
189 | -webkit-user-select: none;
190 | -moz-user-select: none;
191 | -ms-user-select: none;
192 | user-select: none;
193 | grid-template-columns: min-content min-content auto 300px;
194 | grid-template-rows: auto auto auto;
195 | grid-template-areas: 'title links info ...'
196 | '... ... ... ...'
197 | '... ... demos demos';
198 | }
199 | .frame__title-wrap {
200 | grid-area: title;
201 | display: flex;
202 | }
203 | .frame__title {
204 | margin: 0;
205 | white-space: nowrap;
206 | }
207 | .frame__info {
208 | grid-area: info;
209 | }
210 | .frame__demos {
211 | margin: 0;
212 | grid-area: demos;
213 | justify-self: end;
214 | }
215 | .frame__links {
216 | grid-area: links;
217 | padding: 0;
218 | white-space: nowrap;
219 | margin: 0 1rem;
220 | }
221 | .frame a {
222 | pointer-events: auto;
223 | }
224 | .content {
225 | height: 100vh;
226 | justify-content: center;
227 | }
228 | }
229 |
230 | #slider {
231 | position: fixed;
232 | top: 0;
233 | left: 0;
234 | width: 100%;
235 | height: 100%;
236 | z-index: -1;
237 | }
238 |
239 | .dg {
240 | z-index: 100 !important;
241 | }
242 |
--------------------------------------------------------------------------------
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/favicon.ico
--------------------------------------------------------------------------------
/img/disp1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/disp1.jpg
--------------------------------------------------------------------------------
/img/disp3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/disp3.jpg
--------------------------------------------------------------------------------
/img/img11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img11.jpg
--------------------------------------------------------------------------------
/img/img12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img12.jpg
--------------------------------------------------------------------------------
/img/img13.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img13.jpg
--------------------------------------------------------------------------------
/img/img21.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img21.jpg
--------------------------------------------------------------------------------
/img/img22.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img22.jpg
--------------------------------------------------------------------------------
/img/img23.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img23.jpg
--------------------------------------------------------------------------------
/img/img31.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img31.jpg
--------------------------------------------------------------------------------
/img/img32.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img32.jpg
--------------------------------------------------------------------------------
/img/img33.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img33.jpg
--------------------------------------------------------------------------------
/img/img41.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img41.jpg
--------------------------------------------------------------------------------
/img/img42.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img42.jpg
--------------------------------------------------------------------------------
/img/img43.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img43.jpg
--------------------------------------------------------------------------------
/img/img51.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img51.jpg
--------------------------------------------------------------------------------
/img/img52.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img52.jpg
--------------------------------------------------------------------------------
/img/img53.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img53.jpg
--------------------------------------------------------------------------------
/img/img61.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img61.jpg
--------------------------------------------------------------------------------
/img/img62.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img62.jpg
--------------------------------------------------------------------------------
/img/img63.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img63.jpg
--------------------------------------------------------------------------------
/img/img64.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img64.jpg
--------------------------------------------------------------------------------
/img/img71.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img71.jpg
--------------------------------------------------------------------------------
/img/img72.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img72.jpg
--------------------------------------------------------------------------------
/img/img73.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img73.jpg
--------------------------------------------------------------------------------
/img/img81.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img81.jpg
--------------------------------------------------------------------------------
/img/img82.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img82.jpg
--------------------------------------------------------------------------------
/img/img83.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/akella/webGLImageTransitions/498d8fb48426de0a82fc5f6ad06736efc875a75b/img/img83.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 1 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index2.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 2 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index3.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 3 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index4.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 4 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index5.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 5 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index6.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 6 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index7.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 7 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/index8.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | WebGL Image Transitions | Demo 8 | Codrops
8 |
9 |
10 |
11 |
12 |
13 |
14 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
WebGL Image Transitions
27 |
28 |
33 |
Click the image
34 |
44 |
45 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/js/dat-gui.js:
--------------------------------------------------------------------------------
1 | /**
2 | * dat-gui JavaScript Controller Library
3 | * http://code.google.com/p/dat-gui
4 | *
5 | * Copyright 2011 Data Arts Team, Google Creative Lab
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | */
13 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t(e.dat={})}(this,function(e){"use strict";function t(e,t){var n=e.__state.conversionName.toString(),o=Math.round(e.r),i=Math.round(e.g),r=Math.round(e.b),s=e.a,a=Math.round(e.h),l=e.s.toFixed(1),d=e.v.toFixed(1);if(t||"THREE_CHAR_HEX"===n||"SIX_CHAR_HEX"===n){for(var c=e.hex.toString(16);c.length<6;)c="0"+c;return"#"+c}return"CSS_RGB"===n?"rgb("+o+","+i+","+r+")":"CSS_RGBA"===n?"rgba("+o+","+i+","+r+","+s+")":"HEX"===n?"0x"+e.hex.toString(16):"RGB_ARRAY"===n?"["+o+","+i+","+r+"]":"RGBA_ARRAY"===n?"["+o+","+i+","+r+","+s+"]":"RGB_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+"}":"RGBA_OBJ"===n?"{r:"+o+",g:"+i+",b:"+r+",a:"+s+"}":"HSV_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+"}":"HSVA_OBJ"===n?"{h:"+a+",s:"+l+",v:"+d+",a:"+s+"}":"unknown format"}function n(e,t,n){Object.defineProperty(e,t,{get:function(){return"RGB"===this.__state.space?this.__state[t]:(I.recalculateRGB(this,t,n),this.__state[t])},set:function(e){"RGB"!==this.__state.space&&(I.recalculateRGB(this,t,n),this.__state.space="RGB"),this.__state[t]=e}})}function o(e,t){Object.defineProperty(e,t,{get:function(){return"HSV"===this.__state.space?this.__state[t]:(I.recalculateHSV(this),this.__state[t])},set:function(e){"HSV"!==this.__state.space&&(I.recalculateHSV(this),this.__state.space="HSV"),this.__state[t]=e}})}function i(e){if("0"===e||S.isUndefined(e))return 0;var t=e.match(U);return S.isNull(t)?0:parseFloat(t[1])}function r(e){var t=e.toString();return t.indexOf(".")>-1?t.length-t.indexOf(".")-1:0}function s(e,t){var n=Math.pow(10,t);return Math.round(e*n)/n}function a(e,t,n,o,i){return o+(e-t)/(n-t)*(i-o)}function l(e,t,n,o){e.style.background="",S.each(ee,function(i){e.style.cssText+="background: "+i+"linear-gradient("+t+", "+n+" 0%, "+o+" 100%); "})}function d(e){e.style.background="",e.style.cssText+="background: -moz-linear-gradient(top, #ff0000 0%, #ff00ff 17%, #0000ff 34%, #00ffff 50%, #00ff00 67%, #ffff00 84%, #ff0000 100%);",e.style.cssText+="background: -webkit-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -o-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: -ms-linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);",e.style.cssText+="background: linear-gradient(top, #ff0000 0%,#ff00ff 17%,#0000ff 34%,#00ffff 50%,#00ff00 67%,#ffff00 84%,#ff0000 100%);"}function c(e,t,n){var o=document.createElement("li");return t&&o.appendChild(t),n?e.__ul.insertBefore(o,n):e.__ul.appendChild(o),e.onResize(),o}function u(e){X.unbind(window,"resize",e.__resizeHandler),e.saveToLocalStorageIfPossible&&X.unbind(window,"unload",e.saveToLocalStorageIfPossible)}function _(e,t){var n=e.__preset_select[e.__preset_select.selectedIndex];n.innerHTML=t?n.value+"*":n.value}function h(e,t,n){if(n.__li=t,n.__gui=e,S.extend(n,{options:function(t){if(arguments.length>1){var o=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:o,factoryArgs:[S.toArray(arguments)]})}if(S.isArray(t)||S.isObject(t)){var i=n.__li.nextElementSibling;return n.remove(),f(e,n.object,n.property,{before:i,factoryArgs:[t]})}},name:function(e){return n.__li.firstElementChild.firstElementChild.innerHTML=e,n},listen:function(){return n.__gui.listen(n),n},remove:function(){return n.__gui.remove(n),n}}),n instanceof q){var o=new Q(n.object,n.property,{min:n.__min,max:n.__max,step:n.__step});S.each(["updateDisplay","onChange","onFinishChange","step","min","max"],function(e){var t=n[e],i=o[e];n[e]=o[e]=function(){var e=Array.prototype.slice.call(arguments);return i.apply(o,e),t.apply(n,e)}}),X.addClass(t,"has-slider"),n.domElement.insertBefore(o.domElement,n.domElement.firstElementChild)}else if(n instanceof Q){var i=function(t){if(S.isNumber(n.__min)&&S.isNumber(n.__max)){var o=n.__li.firstElementChild.firstElementChild.innerHTML,i=n.__gui.__listening.indexOf(n)>-1;n.remove();var r=f(e,n.object,n.property,{before:n.__li.nextElementSibling,factoryArgs:[n.__min,n.__max,n.__step]});return r.name(o),i&&r.listen(),r}return t};n.min=S.compose(i,n.min),n.max=S.compose(i,n.max)}else n instanceof K?(X.bind(t,"click",function(){X.fakeEvent(n.__checkbox,"click")}),X.bind(n.__checkbox,"click",function(e){e.stopPropagation()})):n instanceof Z?(X.bind(t,"click",function(){X.fakeEvent(n.__button,"click")}),X.bind(t,"mouseover",function(){X.addClass(n.__button,"hover")}),X.bind(t,"mouseout",function(){X.removeClass(n.__button,"hover")})):n instanceof $&&(X.addClass(t,"color"),n.updateDisplay=S.compose(function(e){return t.style.borderLeftColor=n.__color.toString(),e},n.updateDisplay),n.updateDisplay());n.setValue=S.compose(function(t){return e.getRoot().__preset_select&&n.isModified()&&_(e.getRoot(),!0),t},n.setValue)}function p(e,t){var n=e.getRoot(),o=n.__rememberedObjects.indexOf(t.object);if(-1!==o){var i=n.__rememberedObjectIndecesToControllers[o];if(void 0===i&&(i={},n.__rememberedObjectIndecesToControllers[o]=i),i[t.property]=t,n.load&&n.load.remembered){var r=n.load.remembered,s=void 0;if(r[e.preset])s=r[e.preset];else{if(!r[se])return;s=r[se]}if(s[o]&&void 0!==s[o][t.property]){var a=s[o][t.property];t.initialValue=a,t.setValue(a)}}}}function f(e,t,n,o){if(void 0===t[n])throw new Error('Object "'+t+'" has no property "'+n+'"');var i=void 0;if(o.color)i=new $(t,n);else{var r=[t,n].concat(o.factoryArgs);i=ne.apply(e,r)}o.before instanceof z&&(o.before=o.before.__li),p(e,i),X.addClass(i.domElement,"c");var s=document.createElement("span");X.addClass(s,"property-name"),s.innerHTML=i.property;var a=document.createElement("div");a.appendChild(s),a.appendChild(i.domElement);var l=c(e,a,o.before);return X.addClass(l,he.CLASS_CONTROLLER_ROW),i instanceof $?X.addClass(l,"color"):X.addClass(l,H(i.getValue())),h(e,l,i),e.__controllers.push(i),i}function m(e,t){return document.location.href+"."+t}function g(e,t,n){var o=document.createElement("option");o.innerHTML=t,o.value=t,e.__preset_select.appendChild(o),n&&(e.__preset_select.selectedIndex=e.__preset_select.length-1)}function b(e,t){t.style.display=e.useLocalStorage?"block":"none"}function v(e){var t=e.__save_row=document.createElement("li");X.addClass(e.domElement,"has-save"),e.__ul.insertBefore(t,e.__ul.firstChild),X.addClass(t,"save-row");var n=document.createElement("span");n.innerHTML=" ",X.addClass(n,"button gears");var o=document.createElement("span");o.innerHTML="Save",X.addClass(o,"button"),X.addClass(o,"save");var i=document.createElement("span");i.innerHTML="New",X.addClass(i,"button"),X.addClass(i,"save-as");var r=document.createElement("span");r.innerHTML="Revert",X.addClass(r,"button"),X.addClass(r,"revert");var s=e.__preset_select=document.createElement("select");if(e.load&&e.load.remembered?S.each(e.load.remembered,function(t,n){g(e,n,n===e.preset)}):g(e,se,!1),X.bind(s,"change",function(){for(var t=0;t=0;n--)t=[e[n].apply(this,t)];return t[0]}},each:function(e,t,n){if(e)if(A&&e.forEach&&e.forEach===A)e.forEach(t,n);else if(e.length===e.length+0){var o=void 0,i=void 0;for(o=0,i=e.length;o1?S.toArray(arguments):arguments[0];return S.each(O,function(t){if(t.litmus(e))return S.each(t.conversions,function(t,n){if(T=t.read(e),!1===L&&!1!==T)return L=T,T.conversionName=n,T.conversion=t,S.BREAK}),S.BREAK}),L},B=void 0,N={hsv_to_rgb:function(e,t,n){var o=Math.floor(e/60)%6,i=e/60-Math.floor(e/60),r=n*(1-t),s=n*(1-i*t),a=n*(1-(1-i)*t),l=[[n,a,r],[s,n,r],[r,n,a],[r,s,n],[a,r,n],[n,r,s]][o];return{r:255*l[0],g:255*l[1],b:255*l[2]}},rgb_to_hsv:function(e,t,n){var o=Math.min(e,t,n),i=Math.max(e,t,n),r=i-o,s=void 0,a=void 0;return 0===i?{h:NaN,s:0,v:0}:(a=r/i,s=e===i?(t-n)/r:t===i?2+(n-e)/r:4+(e-t)/r,(s/=6)<0&&(s+=1),{h:360*s,s:a,v:i/255})},rgb_to_hex:function(e,t,n){var o=this.hex_with_component(0,2,e);return o=this.hex_with_component(o,1,t),o=this.hex_with_component(o,0,n)},component_from_hex:function(e,t){return e>>8*t&255},hex_with_component:function(e,t,n){return n<<(B=8*t)|e&~(255<this.__max&&(n=this.__max),void 0!==this.__step&&n%this.__step!=0&&(n=Math.round(n/this.__step)*this.__step),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"setValue",this).call(this,n)}},{key:"min",value:function(e){return this.__min=e,this}},{key:"max",value:function(e){return this.__max=e,this}},{key:"step",value:function(e){return this.__step=e,this.__impliedStep=e,this.__precision=r(e),this}}]),t}(),Q=function(e){function t(e,n,o){function i(){l.__onFinishChange&&l.__onFinishChange.call(l,l.getValue())}function r(e){var t=d-e.clientY;l.setValue(l.getValue()+t*l.__impliedStep),d=e.clientY}function s(){X.unbind(window,"mousemove",r),X.unbind(window,"mouseup",s),i()}F(this,t);var a=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,o));a.__truncationSuspended=!1;var l=a,d=void 0;return a.__input=document.createElement("input"),a.__input.setAttribute("type","text"),X.bind(a.__input,"change",function(){var e=parseFloat(l.__input.value);S.isNaN(e)||l.setValue(e)}),X.bind(a.__input,"blur",function(){i()}),X.bind(a.__input,"mousedown",function(e){X.bind(window,"mousemove",r),X.bind(window,"mouseup",s),d=e.clientY}),X.bind(a.__input,"keydown",function(e){13===e.keyCode&&(l.__truncationSuspended=!0,this.blur(),l.__truncationSuspended=!1,i())}),a.updateDisplay(),a.domElement.appendChild(a.__input),a}return D(t,W),P(t,[{key:"updateDisplay",value:function(){return this.__input.value=this.__truncationSuspended?this.getValue():s(this.getValue(),this.__precision),j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),q=function(e){function t(e,n,o,i,r){function s(e){e.preventDefault();var t=_.__background.getBoundingClientRect();return _.setValue(a(e.clientX,t.left,t.right,_.__min,_.__max)),!1}function l(){X.unbind(window,"mousemove",s),X.unbind(window,"mouseup",l),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}function d(e){var t=e.touches[0].clientX,n=_.__background.getBoundingClientRect();_.setValue(a(t,n.left,n.right,_.__min,_.__max))}function c(){X.unbind(window,"touchmove",d),X.unbind(window,"touchend",c),_.__onFinishChange&&_.__onFinishChange.call(_,_.getValue())}F(this,t);var u=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n,{min:o,max:i,step:r})),_=u;return u.__background=document.createElement("div"),u.__foreground=document.createElement("div"),X.bind(u.__background,"mousedown",function(e){document.activeElement.blur(),X.bind(window,"mousemove",s),X.bind(window,"mouseup",l),s(e)}),X.bind(u.__background,"touchstart",function(e){1===e.touches.length&&(X.bind(window,"touchmove",d),X.bind(window,"touchend",c),d(e))}),X.addClass(u.__background,"slider"),X.addClass(u.__foreground,"slider-fg"),u.updateDisplay(),u.__background.appendChild(u.__foreground),u.domElement.appendChild(u.__background),u}return D(t,W),P(t,[{key:"updateDisplay",value:function(){var e=(this.getValue()-this.__min)/(this.__max-this.__min);return this.__foreground.style.width=100*e+"%",j(t.prototype.__proto__||Object.getPrototypeOf(t.prototype),"updateDisplay",this).call(this)}}]),t}(),Z=function(e){function t(e,n,o){F(this,t);var i=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n)),r=i;return i.__button=document.createElement("div"),i.__button.innerHTML=void 0===o?"Fire":o,X.bind(i.__button,"click",function(e){return e.preventDefault(),r.fire(),!1}),X.addClass(i.__button,"button"),i.domElement.appendChild(i.__button),i}return D(t,z),P(t,[{key:"fire",value:function(){this.__onChange&&this.__onChange.call(this),this.getValue().call(this.object),this.__onFinishChange&&this.__onFinishChange.call(this,this.getValue())}}]),t}(),$=function(e){function t(e,n){function o(e){u(e),X.bind(window,"mousemove",u),X.bind(window,"touchmove",u),X.bind(window,"mouseup",r),X.bind(window,"touchend",r)}function i(e){_(e),X.bind(window,"mousemove",_),X.bind(window,"touchmove",_),X.bind(window,"mouseup",s),X.bind(window,"touchend",s)}function r(){X.unbind(window,"mousemove",u),X.unbind(window,"touchmove",u),X.unbind(window,"mouseup",r),X.unbind(window,"touchend",r),c()}function s(){X.unbind(window,"mousemove",_),X.unbind(window,"touchmove",_),X.unbind(window,"mouseup",s),X.unbind(window,"touchend",s),c()}function a(){var e=R(this.value);!1!==e?(p.__color.__state=e,p.setValue(p.__color.toOriginal())):this.value=p.__color.toString()}function c(){p.__onFinishChange&&p.__onFinishChange.call(p,p.__color.toOriginal())}function u(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__saturation_field.getBoundingClientRect(),n=e.touches&&e.touches[0]||e,o=n.clientX,i=n.clientY,r=(o-t.left)/(t.right-t.left),s=1-(i-t.top)/(t.bottom-t.top);return s>1?s=1:s<0&&(s=0),r>1?r=1:r<0&&(r=0),p.__color.v=s,p.__color.s=r,p.setValue(p.__color.toOriginal()),!1}function _(e){-1===e.type.indexOf("touch")&&e.preventDefault();var t=p.__hue_field.getBoundingClientRect(),n=1-((e.touches&&e.touches[0]||e).clientY-t.top)/(t.bottom-t.top);return n>1?n=1:n<0&&(n=0),p.__color.h=360*n,p.setValue(p.__color.toOriginal()),!1}F(this,t);var h=V(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e,n));h.__color=new I(h.getValue()),h.__temp=new I(0);var p=h;h.domElement=document.createElement("div"),X.makeSelectable(h.domElement,!1),h.__selector=document.createElement("div"),h.__selector.className="selector",h.__saturation_field=document.createElement("div"),h.__saturation_field.className="saturation-field",h.__field_knob=document.createElement("div"),h.__field_knob.className="field-knob",h.__field_knob_border="2px solid ",h.__hue_knob=document.createElement("div"),h.__hue_knob.className="hue-knob",h.__hue_field=document.createElement("div"),h.__hue_field.className="hue-field",h.__input=document.createElement("input"),h.__input.type="text",h.__input_textShadow="0 1px 1px ",X.bind(h.__input,"keydown",function(e){13===e.keyCode&&a.call(this)}),X.bind(h.__input,"blur",a),X.bind(h.__selector,"mousedown",function(){X.addClass(this,"drag").bind(window,"mouseup",function(){X.removeClass(p.__selector,"drag")})}),X.bind(h.__selector,"touchstart",function(){X.addClass(this,"drag").bind(window,"touchend",function(){X.removeClass(p.__selector,"drag")})});var f=document.createElement("div");return S.extend(h.__selector.style,{width:"122px",height:"102px",padding:"3px",backgroundColor:"#222",boxShadow:"0px 1px 3px rgba(0,0,0,0.3)"}),S.extend(h.__field_knob.style,{position:"absolute",width:"12px",height:"12px",border:h.__field_knob_border+(h.__color.v<.5?"#fff":"#000"),boxShadow:"0px 1px 3px rgba(0,0,0,0.5)",borderRadius:"12px",zIndex:1}),S.extend(h.__hue_knob.style,{position:"absolute",width:"15px",height:"2px",borderRight:"4px solid #fff",zIndex:1}),S.extend(h.__saturation_field.style,{width:"100px",height:"100px",border:"1px solid #555",marginRight:"3px",display:"inline-block",cursor:"pointer"}),S.extend(f.style,{width:"100%",height:"100%",background:"none"}),l(f,"top","rgba(0,0,0,0)","#000"),S.extend(h.__hue_field.style,{width:"15px",height:"100px",border:"1px solid #555",cursor:"ns-resize",position:"absolute",top:"3px",right:"3px"}),d(h.__hue_field),S.extend(h.__input.style,{outline:"none",textAlign:"center",color:"#fff",border:0,fontWeight:"bold",textShadow:h.__input_textShadow+"rgba(0,0,0,0.7)"}),X.bind(h.__saturation_field,"mousedown",o),X.bind(h.__saturation_field,"touchstart",o),X.bind(h.__field_knob,"mousedown",o),X.bind(h.__field_knob,"touchstart",o),X.bind(h.__hue_field,"mousedown",i),X.bind(h.__hue_field,"touchstart",i),h.__saturation_field.appendChild(f),h.__selector.appendChild(h.__field_knob),h.__selector.appendChild(h.__saturation_field),h.__selector.appendChild(h.__hue_field),h.__hue_field.appendChild(h.__hue_knob),h.domElement.appendChild(h.__input),h.domElement.appendChild(h.__selector),h.updateDisplay(),h}return D(t,z),P(t,[{key:"updateDisplay",value:function(){var e=R(this.getValue());if(!1!==e){var t=!1;S.each(I.COMPONENTS,function(n){if(!S.isUndefined(e[n])&&!S.isUndefined(this.__color.__state[n])&&e[n]!==this.__color.__state[n])return t=!0,{}},this),t&&S.extend(this.__color.__state,e)}S.extend(this.__temp.__state,this.__color.__state),this.__temp.a=1;var n=this.__color.v<.5||this.__color.s>.5?255:0,o=255-n;S.extend(this.__field_knob.style,{marginLeft:100*this.__color.s-7+"px",marginTop:100*(1-this.__color.v)-7+"px",backgroundColor:this.__temp.toHexString(),border:this.__field_knob_border+"rgb("+n+","+n+","+n+")"}),this.__hue_knob.style.marginTop=100*(1-this.__color.h/360)+"px",this.__temp.s=1,this.__temp.v=1,l(this.__saturation_field,"left","#fff",this.__temp.toHexString()),this.__input.value=this.__color.toString(),S.extend(this.__input.style,{backgroundColor:this.__color.toHexString(),color:"rgb("+n+","+n+","+n+")",textShadow:this.__input_textShadow+"rgba("+o+","+o+","+o+",.7)"})}}]),t}(),ee=["-moz-","-o-","-webkit-","-ms-",""],te={load:function(e,t){var n=t||document,o=n.createElement("link");o.type="text/css",o.rel="stylesheet",o.href=e,n.getElementsByTagName("head")[0].appendChild(o)},inject:function(e,t){var n=t||document,o=document.createElement("style");o.type="text/css",o.innerHTML=e;var i=n.getElementsByTagName("head")[0];try{i.appendChild(o)}catch(e){}}},ne=function(e,t){var n=e[t];return S.isArray(arguments[2])||S.isObject(arguments[2])?new Y(e,t,arguments[2]):S.isNumber(n)?S.isNumber(arguments[2])&&S.isNumber(arguments[3])?S.isNumber(arguments[4])?new q(e,t,arguments[2],arguments[3],arguments[4]):new q(e,t,arguments[2],arguments[3]):S.isNumber(arguments[4])?new Q(e,t,{min:arguments[2],max:arguments[3],step:arguments[4]}):new Q(e,t,{min:arguments[2],max:arguments[3]}):S.isString(n)?new J(e,t):S.isFunction(n)?new Z(e,t,""):S.isBoolean(n)?new K(e,t):null},oe=window.requestAnimationFrame||window.webkitRequestAnimationFrame||window.mozRequestAnimationFrame||window.oRequestAnimationFrame||window.msRequestAnimationFrame||function(e){setTimeout(e,1e3/60)},ie=function(){function e(){F(this,e),this.backgroundElement=document.createElement("div"),S.extend(this.backgroundElement.style,{backgroundColor:"rgba(0,0,0,0.8)",top:0,left:0,display:"none",zIndex:"1000",opacity:0,WebkitTransition:"opacity 0.2s linear",transition:"opacity 0.2s linear"}),X.makeFullscreen(this.backgroundElement),this.backgroundElement.style.position="fixed",this.domElement=document.createElement("div"),S.extend(this.domElement.style,{position:"fixed",display:"none",zIndex:"1001",opacity:0,WebkitTransition:"-webkit-transform 0.2s ease-out, opacity 0.2s linear",transition:"transform 0.2s ease-out, opacity 0.2s linear"}),document.body.appendChild(this.backgroundElement),document.body.appendChild(this.domElement);var t=this;X.bind(this.backgroundElement,"click",function(){t.hide()})}return P(e,[{key:"show",value:function(){var e=this;this.backgroundElement.style.display="block",this.domElement.style.display="block",this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)",this.layout(),S.defer(function(){e.backgroundElement.style.opacity=1,e.domElement.style.opacity=1,e.domElement.style.webkitTransform="scale(1)"})}},{key:"hide",value:function(){var e=this,t=function t(){e.domElement.style.display="none",e.backgroundElement.style.display="none",X.unbind(e.domElement,"webkitTransitionEnd",t),X.unbind(e.domElement,"transitionend",t),X.unbind(e.domElement,"oTransitionEnd",t)};X.bind(this.domElement,"webkitTransitionEnd",t),X.bind(this.domElement,"transitionend",t),X.bind(this.domElement,"oTransitionEnd",t),this.backgroundElement.style.opacity=0,this.domElement.style.opacity=0,this.domElement.style.webkitTransform="scale(1.1)"}},{key:"layout",value:function(){this.domElement.style.left=window.innerWidth/2-X.getWidth(this.domElement)/2+"px",this.domElement.style.top=window.innerHeight/2-X.getHeight(this.domElement)/2+"px"}}]),e}(),re=function(e){if(e&&"undefined"!=typeof window){var t=document.createElement("style");return t.setAttribute("type","text/css"),t.innerHTML=e,document.head.appendChild(t),e}}(".dg ul{list-style:none;margin:0;padding:0;width:100%;clear:both}.dg.ac{position:fixed;top:0;left:0;right:0;height:0;z-index:0}.dg:not(.ac) .main{overflow:hidden}.dg.main{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear}.dg.main.taller-than-window{overflow-y:auto}.dg.main.taller-than-window .close-button{opacity:1;margin-top:-1px;border-top:1px solid #2c2c2c}.dg.main ul.closed .close-button{opacity:1 !important}.dg.main:hover .close-button,.dg.main .close-button.drag{opacity:1}.dg.main .close-button{-webkit-transition:opacity .1s linear;-o-transition:opacity .1s linear;-moz-transition:opacity .1s linear;transition:opacity .1s linear;border:0;line-height:19px;height:20px;cursor:pointer;text-align:center;background-color:#000}.dg.main .close-button.close-top{position:relative}.dg.main .close-button.close-bottom{position:absolute}.dg.main .close-button:hover{background-color:#111}.dg.a{float:right;margin-right:15px;overflow-y:visible}.dg.a.has-save>ul.close-top{margin-top:0}.dg.a.has-save>ul.close-bottom{margin-top:27px}.dg.a.has-save>ul.closed{margin-top:0}.dg.a .save-row{top:0;z-index:1002}.dg.a .save-row.close-top{position:relative}.dg.a .save-row.close-bottom{position:fixed}.dg li{-webkit-transition:height .1s ease-out;-o-transition:height .1s ease-out;-moz-transition:height .1s ease-out;transition:height .1s ease-out;-webkit-transition:overflow .1s linear;-o-transition:overflow .1s linear;-moz-transition:overflow .1s linear;transition:overflow .1s linear}.dg li:not(.folder){cursor:auto;height:27px;line-height:27px;padding:0 4px 0 5px}.dg li.folder{padding:0;border-left:4px solid rgba(0,0,0,0)}.dg li.title{cursor:pointer;margin-left:-4px}.dg .closed li:not(.title),.dg .closed ul li,.dg .closed ul li>*{height:0;overflow:hidden;border:0}.dg .cr{clear:both;padding-left:3px;height:27px;overflow:hidden}.dg .property-name{cursor:default;float:left;clear:left;width:40%;overflow:hidden;text-overflow:ellipsis}.dg .c{float:left;width:60%;position:relative}.dg .c input[type=text]{border:0;margin-top:4px;padding:3px;width:100%;float:right}.dg .has-slider input[type=text]{width:30%;margin-left:0}.dg .slider{float:left;width:66%;margin-left:-5px;margin-right:0;height:19px;margin-top:4px}.dg .slider-fg{height:100%}.dg .c input[type=checkbox]{margin-top:7px}.dg .c select{margin-top:5px}.dg .cr.function,.dg .cr.function .property-name,.dg .cr.function *,.dg .cr.boolean,.dg .cr.boolean *{cursor:pointer}.dg .cr.color{overflow:visible}.dg .selector{display:none;position:absolute;margin-left:-9px;margin-top:23px;z-index:10}.dg .c:hover .selector,.dg .selector.drag{display:block}.dg li.save-row{padding:0}.dg li.save-row .button{display:inline-block;padding:0px 6px}.dg.dialogue{background-color:#222;width:460px;padding:15px;font-size:13px;line-height:15px}#dg-new-constructor{padding:10px;color:#222;font-family:Monaco, monospace;font-size:10px;border:0;resize:none;box-shadow:inset 1px 1px 1px #888;word-wrap:break-word;margin:12px 0;display:block;width:440px;overflow-y:scroll;height:100px;position:relative}#dg-local-explain{display:none;font-size:11px;line-height:17px;border-radius:3px;background-color:#333;padding:8px;margin-top:10px}#dg-local-explain code{font-size:10px}#dat-gui-save-locally{display:none}.dg{color:#eee;font:11px 'Lucida Grande', sans-serif;text-shadow:0 -1px 0 #111}.dg.main::-webkit-scrollbar{width:5px;background:#1a1a1a}.dg.main::-webkit-scrollbar-corner{height:0;display:none}.dg.main::-webkit-scrollbar-thumb{border-radius:5px;background:#676767}.dg li:not(.folder){background:#1a1a1a;border-bottom:1px solid #2c2c2c}.dg li.save-row{line-height:25px;background:#dad5cb;border:0}.dg li.save-row select{margin-left:5px;width:108px}.dg li.save-row .button{margin-left:5px;margin-top:1px;border-radius:2px;font-size:9px;line-height:7px;padding:4px 4px 5px 4px;background:#c5bdad;color:#fff;text-shadow:0 1px 0 #b0a58f;box-shadow:0 -1px 0 #b0a58f;cursor:pointer}.dg li.save-row .button.gears{background:#c5bdad url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAANCAYAAAB/9ZQ7AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAQJJREFUeNpiYKAU/P//PwGIC/ApCABiBSAW+I8AClAcgKxQ4T9hoMAEUrxx2QSGN6+egDX+/vWT4e7N82AMYoPAx/evwWoYoSYbACX2s7KxCxzcsezDh3evFoDEBYTEEqycggWAzA9AuUSQQgeYPa9fPv6/YWm/Acx5IPb7ty/fw+QZblw67vDs8R0YHyQhgObx+yAJkBqmG5dPPDh1aPOGR/eugW0G4vlIoTIfyFcA+QekhhHJhPdQxbiAIguMBTQZrPD7108M6roWYDFQiIAAv6Aow/1bFwXgis+f2LUAynwoIaNcz8XNx3Dl7MEJUDGQpx9gtQ8YCueB+D26OECAAQDadt7e46D42QAAAABJRU5ErkJggg==) 2px 1px no-repeat;height:7px;width:8px}.dg li.save-row .button:hover{background-color:#bab19e;box-shadow:0 -1px 0 #b0a58f}.dg li.folder{border-bottom:0}.dg li.title{padding-left:16px;background:#000 url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==) 6px 10px no-repeat;cursor:pointer;border-bottom:1px solid rgba(255,255,255,0.2)}.dg .closed li.title{background-image:url(data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlGIWqMCbWAEAOw==)}.dg .cr.boolean{border-left:3px solid #806787}.dg .cr.color{border-left:3px solid}.dg .cr.function{border-left:3px solid #e61d5f}.dg .cr.number{border-left:3px solid #2FA1D6}.dg .cr.number input[type=text]{color:#2FA1D6}.dg .cr.string{border-left:3px solid #1ed36f}.dg .cr.string input[type=text]{color:#1ed36f}.dg .cr.function:hover,.dg .cr.boolean:hover{background:#111}.dg .c input[type=text]{background:#303030;outline:none}.dg .c input[type=text]:hover{background:#3c3c3c}.dg .c input[type=text]:focus{background:#494949;color:#fff}.dg .c .slider{background:#303030;cursor:ew-resize}.dg .c .slider-fg{background:#2FA1D6;max-width:100%}.dg .c .slider:hover{background:#3c3c3c}.dg .c .slider:hover .slider-fg{background:#44abda}\n");te.inject(re);var se="Default",ae=function(){try{return!!window.localStorage}catch(e){return!1}}(),le=void 0,de=!0,ce=void 0,ue=!1,_e=[],he=function e(t){var n=this,o=t||{};this.domElement=document.createElement("div"),this.__ul=document.createElement("ul"),this.domElement.appendChild(this.__ul),X.addClass(this.domElement,"dg"),this.__folders={},this.__controllers=[],this.__rememberedObjects=[],this.__rememberedObjectIndecesToControllers=[],this.__listening=[],o=S.defaults(o,{closeOnTop:!1,autoPlace:!0,width:e.DEFAULT_WIDTH}),o=S.defaults(o,{resizable:o.autoPlace,hideable:o.autoPlace}),S.isUndefined(o.load)?o.load={preset:se}:o.preset&&(o.load.preset=o.preset),S.isUndefined(o.parent)&&o.hideable&&_e.push(this),o.resizable=S.isUndefined(o.parent)&&o.resizable,o.autoPlace&&S.isUndefined(o.scrollable)&&(o.scrollable=!0);var i=ae&&"true"===localStorage.getItem(m(this,"isLocal")),r=void 0,s=void 0;if(Object.defineProperties(this,{parent:{get:function(){return o.parent}},scrollable:{get:function(){return o.scrollable}},autoPlace:{get:function(){return o.autoPlace}},closeOnTop:{get:function(){return o.closeOnTop}},preset:{get:function(){return n.parent?n.getRoot().preset:o.load.preset},set:function(e){n.parent?n.getRoot().preset=e:o.load.preset=e,E(this),n.revert()}},width:{get:function(){return o.width},set:function(e){o.width=e,w(n,e)}},name:{get:function(){return o.name},set:function(e){o.name=e,s&&(s.innerHTML=o.name)}},closed:{get:function(){return o.closed},set:function(t){o.closed=t,o.closed?X.addClass(n.__ul,e.CLASS_CLOSED):X.removeClass(n.__ul,e.CLASS_CLOSED),this.onResize(),n.__closeButton&&(n.__closeButton.innerHTML=t?e.TEXT_OPEN:e.TEXT_CLOSED)}},load:{get:function(){return o.load}},useLocalStorage:{get:function(){return i},set:function(e){ae&&(i=e,e?X.bind(window,"unload",r):X.unbind(window,"unload",r),localStorage.setItem(m(n,"isLocal"),e))}}}),S.isUndefined(o.parent)){if(this.closed=o.closed||!1,X.addClass(this.domElement,e.CLASS_MAIN),X.makeSelectable(this.domElement,!1),ae&&i){n.useLocalStorage=!0;var a=localStorage.getItem(m(this,"gui"));a&&(o.load=JSON.parse(a))}this.__closeButton=document.createElement("div"),this.__closeButton.innerHTML=e.TEXT_CLOSED,X.addClass(this.__closeButton,e.CLASS_CLOSE_BUTTON),o.closeOnTop?(X.addClass(this.__closeButton,e.CLASS_CLOSE_TOP),this.domElement.insertBefore(this.__closeButton,this.domElement.childNodes[0])):(X.addClass(this.__closeButton,e.CLASS_CLOSE_BOTTOM),this.domElement.appendChild(this.__closeButton)),X.bind(this.__closeButton,"click",function(){n.closed=!n.closed})}else{void 0===o.closed&&(o.closed=!0);var l=document.createTextNode(o.name);X.addClass(l,"controller-name"),s=c(n,l);X.addClass(this.__ul,e.CLASS_CLOSED),X.addClass(s,"title"),X.bind(s,"click",function(e){return e.preventDefault(),n.closed=!n.closed,!1}),o.closed||(this.closed=!1)}o.autoPlace&&(S.isUndefined(o.parent)&&(de&&(ce=document.createElement("div"),X.addClass(ce,"dg"),X.addClass(ce,e.CLASS_AUTO_PLACE_CONTAINER),document.body.appendChild(ce),de=!1),ce.appendChild(this.domElement),X.addClass(this.domElement,e.CLASS_AUTO_PLACE)),this.parent||w(n,o.width)),this.__resizeHandler=function(){n.onResizeDebounced()},X.bind(window,"resize",this.__resizeHandler),X.bind(this.__ul,"webkitTransitionEnd",this.__resizeHandler),X.bind(this.__ul,"transitionend",this.__resizeHandler),X.bind(this.__ul,"oTransitionEnd",this.__resizeHandler),this.onResize(),o.resizable&&y(this),r=function(){ae&&"true"===localStorage.getItem(m(n,"isLocal"))&&localStorage.setItem(m(n,"gui"),JSON.stringify(n.getSaveObject()))},this.saveToLocalStorageIfPossible=r,o.parent||function(){var e=n.getRoot();e.width+=1,S.defer(function(){e.width-=1})}()};he.toggleHide=function(){ue=!ue,S.each(_e,function(e){e.domElement.style.display=ue?"none":""})},he.CLASS_AUTO_PLACE="a",he.CLASS_AUTO_PLACE_CONTAINER="ac",he.CLASS_MAIN="main",he.CLASS_CONTROLLER_ROW="cr",he.CLASS_TOO_TALL="taller-than-window",he.CLASS_CLOSED="closed",he.CLASS_CLOSE_BUTTON="close-button",he.CLASS_CLOSE_TOP="close-top",he.CLASS_CLOSE_BOTTOM="close-bottom",he.CLASS_DRAG="drag",he.DEFAULT_WIDTH=245,he.TEXT_CLOSED="Close Controls",he.TEXT_OPEN="Open Controls",he._keydownHandler=function(e){"text"===document.activeElement.type||72!==e.which&&72!==e.keyCode||he.toggleHide()},X.bind(window,"keydown",he._keydownHandler,!1),S.extend(he.prototype,{add:function(e,t){return f(this,e,t,{factoryArgs:Array.prototype.slice.call(arguments,2)})},addColor:function(e,t){return f(this,e,t,{color:!0})},remove:function(e){this.__ul.removeChild(e.__li),this.__controllers.splice(this.__controllers.indexOf(e),1);var t=this;S.defer(function(){t.onResize()})},destroy:function(){if(this.parent)throw new Error("Only the root GUI should be removed with .destroy(). For subfolders, use gui.removeFolder(folder) instead.");this.autoPlace&&ce.removeChild(this.domElement);var e=this;S.each(this.__folders,function(t){e.removeFolder(t)}),X.unbind(window,"keydown",he._keydownHandler,!1),u(this)},addFolder:function(e){if(void 0!==this.__folders[e])throw new Error('You already have a folder in this GUI by the name "'+e+'"');var t={name:e,parent:this};t.autoPlace=this.autoPlace,this.load&&this.load.folders&&this.load.folders[e]&&(t.closed=this.load.folders[e].closed,t.load=this.load.folders[e]);var n=new he(t);this.__folders[e]=n;var o=c(this,n.domElement);return X.addClass(o,"folder"),n},removeFolder:function(e){this.__ul.removeChild(e.domElement.parentElement),delete this.__folders[e.name],this.load&&this.load.folders&&this.load.folders[e.name]&&delete this.load.folders[e.name],u(e);var t=this;S.each(e.__folders,function(t){e.removeFolder(t)}),S.defer(function(){t.onResize()})},open:function(){this.closed=!1},close:function(){this.closed=!0},hide:function(){this.domElement.style.display="none"},show:function(){this.domElement.style.display=""},onResize:function(){var e=this.getRoot();if(e.scrollable){var t=X.getOffset(e.__ul).top,n=0;S.each(e.__ul.childNodes,function(t){e.autoPlace&&t===e.__save_row||(n+=X.getHeight(t))}),window.innerHeight-t-20\n\n Here\'s the new load parameter for your GUI
\'s constructor:\n\n \n\n \n\n
Automatically save\n values to
localStorage
on exit.\n\n
The values saved to localStorage
will\n override those passed to dat.GUI
\'s constructor. This makes it\n easier to work incrementally, but localStorage
is fragile,\n and your friends may not see the same values you do.\n\n
\n\n
\n\n'),this.parent)throw new Error("You can only call remember on a top level GUI.");var e=this;S.each(Array.prototype.slice.call(arguments),function(t){0===e.__rememberedObjects.length&&v(e),-1===e.__rememberedObjects.indexOf(t)&&e.__rememberedObjects.push(t)}),this.autoPlace&&w(this,this.width)},getRoot:function(){for(var e=this;e.parent;)e=e.parent;return e},getSaveObject:function(){var e=this.load;return e.closed=this.closed,this.__rememberedObjects.length>0&&(e.preset=this.preset,e.remembered||(e.remembered={}),e.remembered[this.preset]=x(this)),e.folders={},S.each(this.__folders,function(t,n){e.folders[n]=t.getSaveObject()}),e},save:function(){this.load.remembered||(this.load.remembered={}),this.load.remembered[this.preset]=x(this),_(this,!1),this.saveToLocalStorageIfPossible()},saveAs:function(e){this.load.remembered||(this.load.remembered={},this.load.remembered[se]=x(this,!0)),this.load.remembered[e]=x(this),this.preset=e,g(this,e,!0),this.saveToLocalStorageIfPossible()},revert:function(e){S.each(this.__controllers,function(t){this.getRoot().load.remembered?p(e||this.getRoot(),t):t.setValue(t.initialValue),t.__onFinishChange&&t.__onFinishChange.call(t,t.getValue())},this),S.each(this.__folders,function(e){e.revert(e)}),e||_(this.getRoot(),!1)},listen:function(e){var t=0===this.__listening.length;this.__listening.push(e),t&&C(this.__listening)},updateDisplay:function(){S.each(this.__controllers,function(e){e.updateDisplay()}),S.each(this.__folders,function(e){e.updateDisplay()})}});var pe={Color:I,math:N,interpret:R},fe={Controller:z,BooleanController:K,OptionController:Y,StringController:J,NumberController:W,NumberControllerBox:Q,NumberControllerSlider:q,FunctionController:Z,ColorController:$},me={dom:X},ge={GUI:he},be=he,ve={color:pe,controllers:fe,dom:me,gui:ge,GUI:be};e.color=pe,e.controllers=fe,e.dom=me,e.gui=ge,e.GUI=be,e.default=ve,Object.defineProperty(e,"__esModule",{value:!0})});
--------------------------------------------------------------------------------
/js/demo1.js:
--------------------------------------------------------------------------------
1 |
2 | let sketch = new Sketch({
3 | duration: 1.5,
4 | debug: true,
5 | easing: 'easeOut',
6 | uniforms: {
7 | width: {value: 0.5, type:'f', min:0, max:10},
8 | scaleX: {value: 40, type:'f', min:0.1, max:60},
9 | scaleY: {value: 40, type:'f', min:0.1, max:60},
10 | // border: {value: 1, type:'f', min:0., max:1},
11 | },
12 | fragment: `
13 | uniform float time;
14 | uniform float progress;
15 | uniform float width;
16 | uniform float scaleX;
17 | // uniform float border;
18 | uniform float scaleY;
19 | uniform sampler2D texture1;
20 | uniform sampler2D texture2;
21 | uniform sampler2D displacement;
22 | uniform vec4 resolution;
23 |
24 | varying vec2 vUv;
25 | varying vec4 vPosition;
26 |
27 | // Classic Perlin 3D Noise
28 | // by Stefan Gustavson
29 | //
30 | vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
31 | vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
32 | vec4 fade(vec4 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}
33 |
34 | float cnoise(vec4 P){
35 | ;
36 | vec4 Pi0 = floor(P); // Integer part for indexing
37 | vec4 Pi1 = Pi0 + 1.0; // Integer part + 1
38 | Pi0 = mod(Pi0, 289.0);
39 | Pi1 = mod(Pi1, 289.0);
40 | vec4 Pf0 = fract(P); // Fractional part for interpolation
41 | vec4 Pf1 = Pf0 - 1.0; // Fractional part - 1.0
42 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
43 | vec4 iy = vec4(Pi0.yy, Pi1.yy);
44 | vec4 iz0 = vec4(Pi0.zzzz);
45 | vec4 iz1 = vec4(Pi1.zzzz);
46 | vec4 iw0 = vec4(Pi0.wwww);
47 | vec4 iw1 = vec4(Pi1.wwww);
48 |
49 | vec4 ixy = permute(permute(ix) + iy);
50 | vec4 ixy0 = permute(ixy + iz0);
51 | vec4 ixy1 = permute(ixy + iz1);
52 | vec4 ixy00 = permute(ixy0 + iw0);
53 | vec4 ixy01 = permute(ixy0 + iw1);
54 | vec4 ixy10 = permute(ixy1 + iw0);
55 | vec4 ixy11 = permute(ixy1 + iw1);
56 |
57 | vec4 gx00 = ixy00 / 7.0;
58 | vec4 gy00 = floor(gx00) / 7.0;
59 | vec4 gz00 = floor(gy00) / 6.0;
60 | gx00 = fract(gx00) - 0.5;
61 | gy00 = fract(gy00) - 0.5;
62 | gz00 = fract(gz00) - 0.5;
63 | vec4 gw00 = vec4(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
64 | vec4 sw00 = step(gw00, vec4(0.0));
65 | gx00 -= sw00 * (step(0.0, gx00) - 0.5);
66 | gy00 -= sw00 * (step(0.0, gy00) - 0.5);
67 |
68 | vec4 gx01 = ixy01 / 7.0;
69 | vec4 gy01 = floor(gx01) / 7.0;
70 | vec4 gz01 = floor(gy01) / 6.0;
71 | gx01 = fract(gx01) - 0.5;
72 | gy01 = fract(gy01) - 0.5;
73 | gz01 = fract(gz01) - 0.5;
74 | vec4 gw01 = vec4(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
75 | vec4 sw01 = step(gw01, vec4(0.0));
76 | gx01 -= sw01 * (step(0.0, gx01) - 0.5);
77 | gy01 -= sw01 * (step(0.0, gy01) - 0.5);
78 |
79 | vec4 gx10 = ixy10 / 7.0;
80 | vec4 gy10 = floor(gx10) / 7.0;
81 | vec4 gz10 = floor(gy10) / 6.0;
82 | gx10 = fract(gx10) - 0.5;
83 | gy10 = fract(gy10) - 0.5;
84 | gz10 = fract(gz10) - 0.5;
85 | vec4 gw10 = vec4(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
86 | vec4 sw10 = step(gw10, vec4(0.0));
87 | gx10 -= sw10 * (step(0.0, gx10) - 0.5);
88 | gy10 -= sw10 * (step(0.0, gy10) - 0.5);
89 |
90 | vec4 gx11 = ixy11 / 7.0;
91 | vec4 gy11 = floor(gx11) / 7.0;
92 | vec4 gz11 = floor(gy11) / 6.0;
93 | gx11 = fract(gx11) - 0.5;
94 | gy11 = fract(gy11) - 0.5;
95 | gz11 = fract(gz11) - 0.5;
96 | vec4 gw11 = vec4(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
97 | vec4 sw11 = step(gw11, vec4(0.0));
98 | gx11 -= sw11 * (step(0.0, gx11) - 0.5);
99 | gy11 -= sw11 * (step(0.0, gy11) - 0.5);
100 |
101 | vec4 g0000 = vec4(gx00.x,gy00.x,gz00.x,gw00.x);
102 | vec4 g1000 = vec4(gx00.y,gy00.y,gz00.y,gw00.y);
103 | vec4 g0100 = vec4(gx00.z,gy00.z,gz00.z,gw00.z);
104 | vec4 g1100 = vec4(gx00.w,gy00.w,gz00.w,gw00.w);
105 | vec4 g0010 = vec4(gx10.x,gy10.x,gz10.x,gw10.x);
106 | vec4 g1010 = vec4(gx10.y,gy10.y,gz10.y,gw10.y);
107 | vec4 g0110 = vec4(gx10.z,gy10.z,gz10.z,gw10.z);
108 | vec4 g1110 = vec4(gx10.w,gy10.w,gz10.w,gw10.w);
109 | vec4 g0001 = vec4(gx01.x,gy01.x,gz01.x,gw01.x);
110 | vec4 g1001 = vec4(gx01.y,gy01.y,gz01.y,gw01.y);
111 | vec4 g0101 = vec4(gx01.z,gy01.z,gz01.z,gw01.z);
112 | vec4 g1101 = vec4(gx01.w,gy01.w,gz01.w,gw01.w);
113 | vec4 g0011 = vec4(gx11.x,gy11.x,gz11.x,gw11.x);
114 | vec4 g1011 = vec4(gx11.y,gy11.y,gz11.y,gw11.y);
115 | vec4 g0111 = vec4(gx11.z,gy11.z,gz11.z,gw11.z);
116 | vec4 g1111 = vec4(gx11.w,gy11.w,gz11.w,gw11.w);
117 |
118 | vec4 norm00 = taylorInvSqrt(vec4(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
119 | g0000 *= norm00.x;
120 | g0100 *= norm00.y;
121 | g1000 *= norm00.z;
122 | g1100 *= norm00.w;
123 |
124 | vec4 norm01 = taylorInvSqrt(vec4(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
125 | g0001 *= norm01.x;
126 | g0101 *= norm01.y;
127 | g1001 *= norm01.z;
128 | g1101 *= norm01.w;
129 |
130 | vec4 norm10 = taylorInvSqrt(vec4(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
131 | g0010 *= norm10.x;
132 | g0110 *= norm10.y;
133 | g1010 *= norm10.z;
134 | g1110 *= norm10.w;
135 |
136 | vec4 norm11 = taylorInvSqrt(vec4(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
137 | g0011 *= norm11.x;
138 | g0111 *= norm11.y;
139 | g1011 *= norm11.z;
140 | g1111 *= norm11.w;
141 |
142 | float n0000 = dot(g0000, Pf0);
143 | float n1000 = dot(g1000, vec4(Pf1.x, Pf0.yzw));
144 | float n0100 = dot(g0100, vec4(Pf0.x, Pf1.y, Pf0.zw));
145 | float n1100 = dot(g1100, vec4(Pf1.xy, Pf0.zw));
146 | float n0010 = dot(g0010, vec4(Pf0.xy, Pf1.z, Pf0.w));
147 | float n1010 = dot(g1010, vec4(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
148 | float n0110 = dot(g0110, vec4(Pf0.x, Pf1.yz, Pf0.w));
149 | float n1110 = dot(g1110, vec4(Pf1.xyz, Pf0.w));
150 | float n0001 = dot(g0001, vec4(Pf0.xyz, Pf1.w));
151 | float n1001 = dot(g1001, vec4(Pf1.x, Pf0.yz, Pf1.w));
152 | float n0101 = dot(g0101, vec4(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
153 | float n1101 = dot(g1101, vec4(Pf1.xy, Pf0.z, Pf1.w));
154 | float n0011 = dot(g0011, vec4(Pf0.xy, Pf1.zw));
155 | float n1011 = dot(g1011, vec4(Pf1.x, Pf0.y, Pf1.zw));
156 | float n0111 = dot(g0111, vec4(Pf0.x, Pf1.yzw));
157 | float n1111 = dot(g1111, Pf1);
158 |
159 | vec4 fade_xyzw = fade(Pf0);
160 | vec4 n_0w = mix(vec4(n0000, n1000, n0100, n1100), vec4(n0001, n1001, n0101, n1101), fade_xyzw.w);
161 | vec4 n_1w = mix(vec4(n0010, n1010, n0110, n1110), vec4(n0011, n1011, n0111, n1111), fade_xyzw.w);
162 | vec4 n_zw = mix(n_0w, n_1w, fade_xyzw.z);
163 | vec2 n_yzw = mix(n_zw.xy, n_zw.zw, fade_xyzw.y);
164 | float n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
165 | return 2.2 * n_xyzw;
166 | }
167 |
168 |
169 | float map(float value, float min1, float max1, float min2, float max2) {
170 | return min2 + (value - min1) * (max2 - min2) / (max1 - min1);
171 | }
172 |
173 | float parabola( float x, float k ) {
174 | return pow( 4. * x * ( 1. - x ), k );
175 | }
176 |
177 |
178 | void main() {
179 | float dt = parabola(progress,1.);
180 | float border = 1.;
181 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
182 | vec4 color1 = texture2D(texture1,newUV);
183 | vec4 color2 = texture2D(texture2,newUV);
184 | vec4 d = texture2D(displacement,vec2(newUV.x*scaleX,newUV.y*scaleY));
185 |
186 | float realnoise = 0.5*(cnoise(vec4(newUV.x*scaleX + 0.*time/3., newUV.y*scaleY,0.*time/3.,0.)) +1.);
187 |
188 | float w = width*dt;
189 |
190 | float maskvalue = smoothstep(1. - w,1.,vUv.x + mix(-w/2., 1. - w/2., progress));
191 | float maskvalue0 = smoothstep(1.,1.,vUv.x + progress);
192 |
193 |
194 |
195 | float mask = maskvalue + maskvalue*realnoise;
196 | // float mask = maskvalue;
197 |
198 | float final = smoothstep(border,border+0.01,mask);
199 |
200 | gl_FragColor = mix(color1,color2,final);
201 | // gl_FragColor =vec4(maskvalue0,final,0.,1.);
202 | }
203 | `
204 | });
205 |
206 |
207 |
--------------------------------------------------------------------------------
/js/demo2.js:
--------------------------------------------------------------------------------
1 |
2 | let sketch = new Sketch({
3 | duration: 1.5,
4 | debug: false,
5 | easing: 'easeOut',
6 | uniforms: {
7 | width: {value: 0.5, type:'f', min:0, max:10},
8 | },
9 | fragment: `
10 | uniform float time;
11 | uniform float progress;
12 | uniform sampler2D texture1;
13 | uniform sampler2D texture2;
14 | uniform vec4 resolution;
15 |
16 | varying vec2 vUv;
17 | varying vec4 vPosition;
18 |
19 |
20 | void main() {
21 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
22 | vec2 p = newUV;
23 | float x = progress;
24 | x = smoothstep(.0,1.0,(x*2.0+p.y-1.0));
25 | vec4 f = mix(
26 | texture2D(texture1, (p-.5)*(1.-x)+.5),
27 | texture2D(texture2, (p-.5)*x+.5),
28 | x);
29 | gl_FragColor = f;
30 | }
31 | `
32 | });
33 |
34 |
35 |
--------------------------------------------------------------------------------
/js/demo3.js:
--------------------------------------------------------------------------------
1 |
2 | let sketch = new Sketch({
3 | duration: 1.5,
4 | debug: true,
5 | easing: 'easeOut',
6 | uniforms: {
7 | radius: {value: 0.9, type:'f', min:0.1, max:2},
8 | width: {value: 0.35, type:'f', min:0., max:1},
9 | },
10 | fragment: `
11 | uniform float time;
12 | uniform float progress;
13 | uniform float width;
14 | uniform float scaleX;
15 | uniform float scaleY;
16 | uniform float transition;
17 | uniform float radius;
18 | uniform float swipe;
19 | uniform sampler2D texture1;
20 | uniform sampler2D texture2;
21 | uniform sampler2D displacement;
22 | uniform vec4 resolution;
23 |
24 | varying vec2 vUv;
25 | varying vec4 vPosition;
26 |
27 | float parabola( float x, float k ) {
28 | return pow( 4. * x * ( 1. - x ), k );
29 | }
30 |
31 | void main() {
32 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
33 | vec2 p = newUV;
34 | vec2 start = vec2(0.5,0.5);
35 | vec2 aspect = resolution.wz;
36 |
37 | vec2 uv = newUV;
38 | float dt = parabola(progress, 1.);
39 | vec4 noise = texture2D(displacement, fract(vUv+time*0.04));
40 | float prog = progress*0.66 + noise.g * 0.04;
41 | float circ = 1. - smoothstep(-width, 0.0, radius * distance(start*aspect, uv*aspect) - prog*(1.+width));
42 | float intpl = pow(abs(circ), 1.);
43 | vec4 t1 = texture2D( texture1, (uv - 0.5) * (1.0 - intpl) + 0.5 ) ;
44 | vec4 t2 = texture2D( texture2, (uv - 0.5) * intpl + 0.5 );
45 | gl_FragColor = mix( t1, t2, intpl );
46 |
47 | }
48 |
49 | `
50 | });
51 |
52 |
53 |
--------------------------------------------------------------------------------
/js/demo4.js:
--------------------------------------------------------------------------------
1 |
2 | let sketch = new Sketch({
3 | duration: 1.5,
4 | debug: false,
5 | easing: 'easeOut',
6 | uniforms: {
7 | // width: {value: 0.35, type:'f', min:0., max:1},
8 | },
9 | fragment: `
10 | uniform float time;
11 | uniform float progress;
12 | uniform float width;
13 | uniform float scaleX;
14 | uniform float scaleY;
15 | uniform float transition;
16 | uniform float radius;
17 | uniform float swipe;
18 | uniform sampler2D texture1;
19 | uniform sampler2D texture2;
20 | uniform sampler2D displacement;
21 | uniform vec4 resolution;
22 |
23 | varying vec2 vUv;
24 | varying vec4 vPosition;
25 | vec2 mirrored(vec2 v) {
26 | vec2 m = mod(v,2.);
27 | return mix(m,2.0 - m, step(1.0 ,m));
28 | }
29 |
30 | void main() {
31 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
32 | vec4 noise = texture2D(displacement, mirrored(newUV+time*0.04));
33 | // float prog = 0.6*progress + 0.2 + noise.g * 0.06;
34 | float prog = progress*0.8 -0.05 + noise.g * 0.06;
35 | float intpl = pow(abs(smoothstep(0., 1., (prog*2. - vUv.x + 0.5))), 10.);
36 |
37 | vec4 t1 = texture2D( texture1, (newUV - 0.5) * (1.0 - intpl) + 0.5 ) ;
38 | vec4 t2 = texture2D( texture2, (newUV - 0.5) * intpl + 0.5 );
39 | gl_FragColor = mix( t1, t2, intpl );
40 |
41 | }
42 |
43 | `
44 | });
45 |
46 |
47 |
--------------------------------------------------------------------------------
/js/demo5.js:
--------------------------------------------------------------------------------
1 |
2 | let sketch = new Sketch({
3 | debug: true,
4 | uniforms: {
5 | intensity: {value: 0.3, type:'f', min:0., max:2},
6 | },
7 | fragment: `
8 | uniform float time;
9 | uniform float progress;
10 | uniform float width;
11 | uniform float scaleX;
12 | uniform float scaleY;
13 | uniform float transition;
14 | uniform float radius;
15 | uniform float intensity;
16 | uniform sampler2D texture1;
17 | uniform sampler2D texture2;
18 | uniform sampler2D displacement;
19 | uniform vec4 resolution;
20 | varying vec2 vUv;
21 |
22 | void main() {
23 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
24 |
25 | vec4 d1 = texture2D(texture1, newUV);
26 | vec4 d2 = texture2D(texture2, newUV);
27 |
28 | float displace1 = (d1.r + d1.g + d1.b)*0.33;
29 | float displace2 = (d2.r + d2.g + d2.b)*0.33;
30 |
31 | vec4 t1 = texture2D(texture1, vec2(newUV.x, newUV.y + progress * (displace2 * intensity)));
32 | vec4 t2 = texture2D(texture2, vec2(newUV.x, newUV.y + (1.0 - progress) * (displace1 * intensity)));
33 |
34 | gl_FragColor = mix(t1, t2, progress);
35 |
36 | }
37 |
38 | `
39 | });
40 |
41 |
42 |
--------------------------------------------------------------------------------
/js/demo6.js:
--------------------------------------------------------------------------------
1 | // planetary
2 | let sketch = new Sketch({
3 | debug: true,
4 | uniforms: {
5 | intensity: {value: 1, type:'f', min:0., max:3}
6 | },
7 | fragment: `
8 | uniform float time;
9 | uniform float progress;
10 | uniform float intensity;
11 | uniform float width;
12 | uniform float scaleX;
13 | uniform float scaleY;
14 | uniform float transition;
15 | uniform float radius;
16 | uniform float swipe;
17 | uniform sampler2D texture1;
18 | uniform sampler2D texture2;
19 | uniform sampler2D displacement;
20 | uniform vec4 resolution;
21 | varying vec2 vUv;
22 | mat2 getRotM(float angle) {
23 | float s = sin(angle);
24 | float c = cos(angle);
25 | return mat2(c, -s, s, c);
26 | }
27 | const float PI = 3.1415;
28 | const float angle1 = PI *0.25;
29 | const float angle2 = -PI *0.75;
30 |
31 |
32 | void main() {
33 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
34 |
35 | vec4 disp = texture2D(displacement, newUV);
36 | vec2 dispVec = vec2(disp.r, disp.g);
37 |
38 | vec2 distortedPosition1 = newUV + getRotM(angle1) * dispVec * intensity * progress;
39 | vec4 t1 = texture2D(texture1, distortedPosition1);
40 |
41 | vec2 distortedPosition2 = newUV + getRotM(angle2) * dispVec * intensity * (1.0 - progress);
42 | vec4 t2 = texture2D(texture2, distortedPosition2);
43 |
44 | gl_FragColor = mix(t1, t2, progress);
45 |
46 | }
47 |
48 | `
49 | });
50 |
51 |
52 |
--------------------------------------------------------------------------------
/js/demo7.js:
--------------------------------------------------------------------------------
1 | // planetary
2 | let sketch = new Sketch({
3 | debug: true,
4 | uniforms: {
5 | intensity: {value: 50., type:'f', min:1., max:100}
6 | },
7 | fragment: `
8 | uniform float time;
9 | uniform float progress;
10 | uniform float intensity;
11 | uniform float width;
12 | uniform float scaleX;
13 | uniform float scaleY;
14 | uniform float transition;
15 | uniform float radius;
16 | uniform float swipe;
17 | uniform sampler2D texture1;
18 | uniform sampler2D texture2;
19 | uniform sampler2D displacement;
20 | uniform vec4 resolution;
21 | varying vec2 vUv;
22 | mat2 rotate(float a) {
23 | float s = sin(a);
24 | float c = cos(a);
25 | return mat2(c, -s, s, c);
26 | }
27 | const float PI = 3.1415;
28 | const float angle1 = PI *0.25;
29 | const float angle2 = -PI *0.75;
30 |
31 |
32 | void main() {
33 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
34 |
35 | vec2 uvDivided = fract(newUV*vec2(intensity,1.));
36 |
37 |
38 | vec2 uvDisplaced1 = newUV + rotate(3.1415926/4.)*uvDivided*progress*0.1;
39 | vec2 uvDisplaced2 = newUV + rotate(3.1415926/4.)*uvDivided*(1. - progress)*0.1;
40 |
41 | vec4 t1 = texture2D(texture1,uvDisplaced1);
42 | vec4 t2 = texture2D(texture2,uvDisplaced2);
43 |
44 | gl_FragColor = mix(t1, t2, progress);
45 |
46 | }
47 |
48 | `
49 | });
50 |
51 |
52 |
--------------------------------------------------------------------------------
/js/demo8.js:
--------------------------------------------------------------------------------
1 | // planetary
2 | let sketch = new Sketch({
3 | debug: false,
4 | uniforms: {
5 | intensity: {value: 50., type:'f', min:1., max:100}
6 | },
7 | fragment: `
8 | uniform float time;
9 | uniform float progress;
10 | uniform float intensity;
11 | uniform float width;
12 | uniform float scaleX;
13 | uniform float scaleY;
14 | uniform float transition;
15 | uniform float radius;
16 | uniform float swipe;
17 | uniform sampler2D texture1;
18 | uniform sampler2D texture2;
19 | uniform sampler2D displacement;
20 | uniform vec4 resolution;
21 | varying vec2 vUv;
22 | mat2 rotate(float a) {
23 | float s = sin(a);
24 | float c = cos(a);
25 | return mat2(c, -s, s, c);
26 | }
27 | const float PI = 3.1415;
28 | const float angle1 = PI *0.25;
29 | const float angle2 = -PI *0.75;
30 |
31 | const float noiseSeed = 2.;
32 |
33 | float random() {
34 | return fract(sin(noiseSeed + dot(gl_FragCoord.xy / resolution.xy / 10.0, vec2(12.9898, 4.1414))) * 43758.5453);
35 | }
36 |
37 | float hash(float n) { return fract(sin(n) * 1e4); }
38 | float hash(vec2 p) { return fract(1e4 * sin(17.0 * p.x + p.y * 0.1) * (0.1 + abs(sin(p.y * 13.0 + p.x)))); }
39 |
40 | float hnoise(vec2 x) {
41 | vec2 i = floor(x);
42 | vec2 f = fract(x);
43 |
44 | float a = hash(i);
45 | float b = hash(i + vec2(1.0, 0.0));
46 | float c = hash(i + vec2(0.0, 1.0));
47 | float d = hash(i + vec2(1.0, 1.0));
48 |
49 | vec2 u = f * f * (3.0 - 2.0 * f);
50 | return mix(a, b, u.x) + (c - a) * u.y * (1.0 - u.x) + (d - b) * u.x * u.y;
51 | }
52 |
53 |
54 | void main() {
55 |
56 | vec2 newUV = (vUv - vec2(0.5))*resolution.zw + vec2(0.5);
57 |
58 | float hn = hnoise(newUV.xy * resolution.xy / 100.0);
59 |
60 | vec2 d = vec2(0.,normalize(vec2(0.5,0.5) - newUV.xy).y);
61 |
62 | vec2 uv1 = newUV + d * progress / 5.0 * (1.0 + hn / 2.0);
63 | vec2 uv2 = newUV - d * (1.0 - progress) / 5.0 * (1.0 + hn / 2.0);
64 |
65 | vec4 t1 = texture2D(texture1,uv1);
66 | vec4 t2 = texture2D(texture2,uv2);
67 |
68 | gl_FragColor = mix(t1, t2, progress);
69 |
70 | }
71 |
72 | `
73 | });
74 |
75 |
76 |
--------------------------------------------------------------------------------
/js/orbit.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author qiao / https://github.com/qiao
3 | * @author mrdoob / http://mrdoob.com
4 | * @author alteredq / http://alteredqualia.com/
5 | * @author WestLangley / http://github.com/WestLangley
6 | * @author erich666 / http://erichaines.com
7 | * @author ScieCode / http://github.com/sciecode
8 | */
9 |
10 | // This set of controls performs orbiting, dollying (zooming), and panning.
11 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
12 | //
13 | // Orbit - left mouse / touch: one-finger move
14 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
15 | // Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move
16 |
17 | THREE.OrbitControls = function ( object, domElement ) {
18 |
19 | this.object = object;
20 |
21 | this.domElement = ( domElement !== undefined ) ? domElement : document;
22 |
23 | // Set to false to disable this control
24 | this.enabled = true;
25 |
26 | // "target" sets the location of focus, where the object orbits around
27 | this.target = new THREE.Vector3();
28 |
29 | // How far you can dolly in and out ( PerspectiveCamera only )
30 | this.minDistance = 0;
31 | this.maxDistance = Infinity;
32 |
33 | // How far you can zoom in and out ( OrthographicCamera only )
34 | this.minZoom = 0;
35 | this.maxZoom = Infinity;
36 |
37 | // How far you can orbit vertically, upper and lower limits.
38 | // Range is 0 to Math.PI radians.
39 | this.minPolarAngle = 0; // radians
40 | this.maxPolarAngle = Math.PI; // radians
41 |
42 | // How far you can orbit horizontally, upper and lower limits.
43 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
44 | this.minAzimuthAngle = - Infinity; // radians
45 | this.maxAzimuthAngle = Infinity; // radians
46 |
47 | // Set to true to enable damping (inertia)
48 | // If damping is enabled, you must call controls.update() in your animation loop
49 | this.enableDamping = false;
50 | this.dampingFactor = 0.05;
51 |
52 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
53 | // Set to false to disable zooming
54 | this.enableZoom = true;
55 | this.zoomSpeed = 1.0;
56 |
57 | // Set to false to disable rotating
58 | this.enableRotate = true;
59 | this.rotateSpeed = 1.0;
60 |
61 | // Set to false to disable panning
62 | this.enablePan = true;
63 | this.panSpeed = 1.0;
64 | this.screenSpacePanning = false; // if true, pan in screen-space
65 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
66 |
67 | // Set to true to automatically rotate around the target
68 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
69 | this.autoRotate = false;
70 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
71 |
72 | // Set to false to disable use of the keys
73 | this.enableKeys = true;
74 |
75 | // The four arrow keys
76 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
77 |
78 | // Mouse buttons
79 | this.mouseButtons = { LEFT: THREE.MOUSE.ROTATE, MIDDLE: THREE.MOUSE.DOLLY, RIGHT: THREE.MOUSE.PAN };
80 |
81 | // Touch fingers
82 | this.touches = { ONE: THREE.TOUCH.ROTATE, TWO: THREE.TOUCH.DOLLY_PAN };
83 |
84 | // for reset
85 | this.target0 = this.target.clone();
86 | this.position0 = this.object.position.clone();
87 | this.zoom0 = this.object.zoom;
88 |
89 | //
90 | // public methods
91 | //
92 |
93 | this.getPolarAngle = function () {
94 |
95 | return spherical.phi;
96 |
97 | };
98 |
99 | this.getAzimuthalAngle = function () {
100 |
101 | return spherical.theta;
102 |
103 | };
104 |
105 | this.saveState = function () {
106 |
107 | scope.target0.copy( scope.target );
108 | scope.position0.copy( scope.object.position );
109 | scope.zoom0 = scope.object.zoom;
110 |
111 | };
112 |
113 | this.reset = function () {
114 |
115 | scope.target.copy( scope.target0 );
116 | scope.object.position.copy( scope.position0 );
117 | scope.object.zoom = scope.zoom0;
118 |
119 | scope.object.updateProjectionMatrix();
120 | scope.dispatchEvent( changeEvent );
121 |
122 | scope.update();
123 |
124 | state = STATE.NONE;
125 |
126 | };
127 |
128 | // this method is exposed, but perhaps it would be better if we can make it private...
129 | this.update = function () {
130 |
131 | var offset = new THREE.Vector3();
132 |
133 | // so camera.up is the orbit axis
134 | var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
135 | var quatInverse = quat.clone().inverse();
136 |
137 | var lastPosition = new THREE.Vector3();
138 | var lastQuaternion = new THREE.Quaternion();
139 |
140 | return function update() {
141 |
142 | var position = scope.object.position;
143 |
144 | offset.copy( position ).sub( scope.target );
145 |
146 | // rotate offset to "y-axis-is-up" space
147 | offset.applyQuaternion( quat );
148 |
149 | // angle from z-axis around y-axis
150 | spherical.setFromVector3( offset );
151 |
152 | if ( scope.autoRotate && state === STATE.NONE ) {
153 |
154 | rotateLeft( getAutoRotationAngle() );
155 |
156 | }
157 |
158 | if ( scope.enableDamping ) {
159 |
160 | spherical.theta += sphericalDelta.theta * scope.dampingFactor;
161 | spherical.phi += sphericalDelta.phi * scope.dampingFactor;
162 |
163 | } else {
164 |
165 | spherical.theta += sphericalDelta.theta;
166 | spherical.phi += sphericalDelta.phi;
167 |
168 | }
169 |
170 | // restrict theta to be between desired limits
171 | spherical.theta = Math.max( scope.minAzimuthAngle, Math.min( scope.maxAzimuthAngle, spherical.theta ) );
172 |
173 | // restrict phi to be between desired limits
174 | spherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );
175 |
176 | spherical.makeSafe();
177 |
178 |
179 | spherical.radius *= scale;
180 |
181 | // restrict radius to be between desired limits
182 | spherical.radius = Math.max( scope.minDistance, Math.min( scope.maxDistance, spherical.radius ) );
183 |
184 | // move target to panned location
185 |
186 | if ( scope.enableDamping === true ) {
187 |
188 | scope.target.addScaledVector( panOffset, scope.dampingFactor );
189 |
190 | } else {
191 |
192 | scope.target.add( panOffset );
193 |
194 | }
195 |
196 | offset.setFromSpherical( spherical );
197 |
198 | // rotate offset back to "camera-up-vector-is-up" space
199 | offset.applyQuaternion( quatInverse );
200 |
201 | position.copy( scope.target ).add( offset );
202 |
203 | scope.object.lookAt( scope.target );
204 |
205 | if ( scope.enableDamping === true ) {
206 |
207 | sphericalDelta.theta *= ( 1 - scope.dampingFactor );
208 | sphericalDelta.phi *= ( 1 - scope.dampingFactor );
209 |
210 | panOffset.multiplyScalar( 1 - scope.dampingFactor );
211 |
212 | } else {
213 |
214 | sphericalDelta.set( 0, 0, 0 );
215 |
216 | panOffset.set( 0, 0, 0 );
217 |
218 | }
219 |
220 | scale = 1;
221 |
222 | // update condition is:
223 | // min(camera displacement, camera rotation in radians)^2 > EPS
224 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
225 |
226 | if ( zoomChanged ||
227 | lastPosition.distanceToSquared( scope.object.position ) > EPS ||
228 | 8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ) {
229 |
230 | scope.dispatchEvent( changeEvent );
231 |
232 | lastPosition.copy( scope.object.position );
233 | lastQuaternion.copy( scope.object.quaternion );
234 | zoomChanged = false;
235 |
236 | return true;
237 |
238 | }
239 |
240 | return false;
241 |
242 | };
243 |
244 | }();
245 |
246 | this.dispose = function () {
247 |
248 | scope.domElement.removeEventListener( 'contextmenu', onContextMenu, false );
249 | scope.domElement.removeEventListener( 'mousedown', onMouseDown, false );
250 | scope.domElement.removeEventListener( 'wheel', onMouseWheel, false );
251 |
252 | scope.domElement.removeEventListener( 'touchstart', onTouchStart, false );
253 | scope.domElement.removeEventListener( 'touchend', onTouchEnd, false );
254 | scope.domElement.removeEventListener( 'touchmove', onTouchMove, false );
255 |
256 | document.removeEventListener( 'mousemove', onMouseMove, false );
257 | document.removeEventListener( 'mouseup', onMouseUp, false );
258 |
259 | window.removeEventListener( 'keydown', onKeyDown, false );
260 |
261 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
262 |
263 | };
264 |
265 | //
266 | // internals
267 | //
268 |
269 | var scope = this;
270 |
271 | var changeEvent = { type: 'change' };
272 | var startEvent = { type: 'start' };
273 | var endEvent = { type: 'end' };
274 |
275 | var STATE = {
276 | NONE: - 1,
277 | ROTATE: 0,
278 | DOLLY: 1,
279 | PAN: 2,
280 | TOUCH_ROTATE: 3,
281 | TOUCH_PAN: 4,
282 | TOUCH_DOLLY_PAN: 5,
283 | TOUCH_DOLLY_ROTATE: 6
284 | };
285 |
286 | var state = STATE.NONE;
287 |
288 | var EPS = 0.000001;
289 |
290 | // current position in spherical coordinates
291 | var spherical = new THREE.Spherical();
292 | var sphericalDelta = new THREE.Spherical();
293 |
294 | var scale = 1;
295 | var panOffset = new THREE.Vector3();
296 | var zoomChanged = false;
297 |
298 | var rotateStart = new THREE.Vector2();
299 | var rotateEnd = new THREE.Vector2();
300 | var rotateDelta = new THREE.Vector2();
301 |
302 | var panStart = new THREE.Vector2();
303 | var panEnd = new THREE.Vector2();
304 | var panDelta = new THREE.Vector2();
305 |
306 | var dollyStart = new THREE.Vector2();
307 | var dollyEnd = new THREE.Vector2();
308 | var dollyDelta = new THREE.Vector2();
309 |
310 | function getAutoRotationAngle() {
311 |
312 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
313 |
314 | }
315 |
316 | function getZoomScale() {
317 |
318 | return Math.pow( 0.95, scope.zoomSpeed );
319 |
320 | }
321 |
322 | function rotateLeft( angle ) {
323 |
324 | sphericalDelta.theta -= angle;
325 |
326 | }
327 |
328 | function rotateUp( angle ) {
329 |
330 | sphericalDelta.phi -= angle;
331 |
332 | }
333 |
334 | var panLeft = function () {
335 |
336 | var v = new THREE.Vector3();
337 |
338 | return function panLeft( distance, objectMatrix ) {
339 |
340 | v.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix
341 | v.multiplyScalar( - distance );
342 |
343 | panOffset.add( v );
344 |
345 | };
346 |
347 | }();
348 |
349 | var panUp = function () {
350 |
351 | var v = new THREE.Vector3();
352 |
353 | return function panUp( distance, objectMatrix ) {
354 |
355 | if ( scope.screenSpacePanning === true ) {
356 |
357 | v.setFromMatrixColumn( objectMatrix, 1 );
358 |
359 | } else {
360 |
361 | v.setFromMatrixColumn( objectMatrix, 0 );
362 | v.crossVectors( scope.object.up, v );
363 |
364 | }
365 |
366 | v.multiplyScalar( distance );
367 |
368 | panOffset.add( v );
369 |
370 | };
371 |
372 | }();
373 |
374 | // deltaX and deltaY are in pixels; right and down are positive
375 | var pan = function () {
376 |
377 | var offset = new THREE.Vector3();
378 |
379 | return function pan( deltaX, deltaY ) {
380 |
381 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
382 |
383 | if ( scope.object.isPerspectiveCamera ) {
384 |
385 | // perspective
386 | var position = scope.object.position;
387 | offset.copy( position ).sub( scope.target );
388 | var targetDistance = offset.length();
389 |
390 | // half of the fov is center to top of screen
391 | targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
392 |
393 | // we use only clientHeight here so aspect ratio does not distort speed
394 | panLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );
395 | panUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );
396 |
397 | } else if ( scope.object.isOrthographicCamera ) {
398 |
399 | // orthographic
400 | panLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );
401 | panUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );
402 |
403 | } else {
404 |
405 | // camera neither orthographic nor perspective
406 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
407 | scope.enablePan = false;
408 |
409 | }
410 |
411 | };
412 |
413 | }();
414 |
415 | function dollyIn( dollyScale ) {
416 |
417 | if ( scope.object.isPerspectiveCamera ) {
418 |
419 | scale /= dollyScale;
420 |
421 | } else if ( scope.object.isOrthographicCamera ) {
422 |
423 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom * dollyScale ) );
424 | scope.object.updateProjectionMatrix();
425 | zoomChanged = true;
426 |
427 | } else {
428 |
429 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
430 | scope.enableZoom = false;
431 |
432 | }
433 |
434 | }
435 |
436 | function dollyOut( dollyScale ) {
437 |
438 | if ( scope.object.isPerspectiveCamera ) {
439 |
440 | scale *= dollyScale;
441 |
442 | } else if ( scope.object.isOrthographicCamera ) {
443 |
444 | scope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / dollyScale ) );
445 | scope.object.updateProjectionMatrix();
446 | zoomChanged = true;
447 |
448 | } else {
449 |
450 | console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
451 | scope.enableZoom = false;
452 |
453 | }
454 |
455 | }
456 |
457 | //
458 | // event callbacks - update the object state
459 | //
460 |
461 | function handleMouseDownRotate( event ) {
462 |
463 | rotateStart.set( event.clientX, event.clientY );
464 |
465 | }
466 |
467 | function handleMouseDownDolly( event ) {
468 |
469 | dollyStart.set( event.clientX, event.clientY );
470 |
471 | }
472 |
473 | function handleMouseDownPan( event ) {
474 |
475 | panStart.set( event.clientX, event.clientY );
476 |
477 | }
478 |
479 | function handleMouseMoveRotate( event ) {
480 |
481 | rotateEnd.set( event.clientX, event.clientY );
482 |
483 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
484 |
485 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
486 |
487 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
488 |
489 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
490 |
491 | rotateStart.copy( rotateEnd );
492 |
493 | scope.update();
494 |
495 | }
496 |
497 | function handleMouseMoveDolly( event ) {
498 |
499 | dollyEnd.set( event.clientX, event.clientY );
500 |
501 | dollyDelta.subVectors( dollyEnd, dollyStart );
502 |
503 | if ( dollyDelta.y > 0 ) {
504 |
505 | dollyIn( getZoomScale() );
506 |
507 | } else if ( dollyDelta.y < 0 ) {
508 |
509 | dollyOut( getZoomScale() );
510 |
511 | }
512 |
513 | dollyStart.copy( dollyEnd );
514 |
515 | scope.update();
516 |
517 | }
518 |
519 | function handleMouseMovePan( event ) {
520 |
521 | panEnd.set( event.clientX, event.clientY );
522 |
523 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
524 |
525 | pan( panDelta.x, panDelta.y );
526 |
527 | panStart.copy( panEnd );
528 |
529 | scope.update();
530 |
531 | }
532 |
533 | function handleMouseUp( /*event*/ ) {
534 |
535 | // no-op
536 |
537 | }
538 |
539 | function handleMouseWheel( event ) {
540 |
541 | if ( event.deltaY < 0 ) {
542 |
543 | dollyOut( getZoomScale() );
544 |
545 | } else if ( event.deltaY > 0 ) {
546 |
547 | dollyIn( getZoomScale() );
548 |
549 | }
550 |
551 | scope.update();
552 |
553 | }
554 |
555 | function handleKeyDown( event ) {
556 |
557 | var needsUpdate = false;
558 |
559 | switch ( event.keyCode ) {
560 |
561 | case scope.keys.UP:
562 | pan( 0, scope.keyPanSpeed );
563 | needsUpdate = true;
564 | break;
565 |
566 | case scope.keys.BOTTOM:
567 | pan( 0, - scope.keyPanSpeed );
568 | needsUpdate = true;
569 | break;
570 |
571 | case scope.keys.LEFT:
572 | pan( scope.keyPanSpeed, 0 );
573 | needsUpdate = true;
574 | break;
575 |
576 | case scope.keys.RIGHT:
577 | pan( - scope.keyPanSpeed, 0 );
578 | needsUpdate = true;
579 | break;
580 |
581 | }
582 |
583 | if ( needsUpdate ) {
584 |
585 | // prevent the browser from scrolling on cursor keys
586 | event.preventDefault();
587 |
588 | scope.update();
589 |
590 | }
591 |
592 |
593 | }
594 |
595 | function handleTouchStartRotate( event ) {
596 |
597 | if ( event.touches.length == 1 ) {
598 |
599 | rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
600 |
601 | } else {
602 |
603 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
604 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
605 |
606 | rotateStart.set( x, y );
607 |
608 | }
609 |
610 | }
611 |
612 | function handleTouchStartPan( event ) {
613 |
614 | if ( event.touches.length == 1 ) {
615 |
616 | panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
617 |
618 | } else {
619 |
620 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
621 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
622 |
623 | panStart.set( x, y );
624 |
625 | }
626 |
627 | }
628 |
629 | function handleTouchStartDolly( event ) {
630 |
631 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
632 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
633 |
634 | var distance = Math.sqrt( dx * dx + dy * dy );
635 |
636 | dollyStart.set( 0, distance );
637 |
638 | }
639 |
640 | function handleTouchStartDollyPan( event ) {
641 |
642 | if ( scope.enableZoom ) handleTouchStartDolly( event );
643 |
644 | if ( scope.enablePan ) handleTouchStartPan( event );
645 |
646 | }
647 |
648 | function handleTouchStartDollyRotate( event ) {
649 |
650 | if ( scope.enableZoom ) handleTouchStartDolly( event );
651 |
652 | if ( scope.enableRotate ) handleTouchStartRotate( event );
653 |
654 | }
655 |
656 | function handleTouchMoveRotate( event ) {
657 |
658 | if ( event.touches.length == 1 ) {
659 |
660 | rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
661 |
662 | } else {
663 |
664 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
665 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
666 |
667 | rotateEnd.set( x, y );
668 |
669 | }
670 |
671 | rotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );
672 |
673 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
674 |
675 | rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height
676 |
677 | rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );
678 |
679 | rotateStart.copy( rotateEnd );
680 |
681 | }
682 |
683 | function handleTouchMovePan( event ) {
684 |
685 | if ( event.touches.length == 1 ) {
686 |
687 | panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
688 |
689 | } else {
690 |
691 | var x = 0.5 * ( event.touches[ 0 ].pageX + event.touches[ 1 ].pageX );
692 | var y = 0.5 * ( event.touches[ 0 ].pageY + event.touches[ 1 ].pageY );
693 |
694 | panEnd.set( x, y );
695 |
696 | }
697 |
698 | panDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );
699 |
700 | pan( panDelta.x, panDelta.y );
701 |
702 | panStart.copy( panEnd );
703 |
704 | }
705 |
706 | function handleTouchMoveDolly( event ) {
707 |
708 | var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
709 | var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
710 |
711 | var distance = Math.sqrt( dx * dx + dy * dy );
712 |
713 | dollyEnd.set( 0, distance );
714 |
715 | dollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );
716 |
717 | dollyIn( dollyDelta.y );
718 |
719 | dollyStart.copy( dollyEnd );
720 |
721 | }
722 |
723 | function handleTouchMoveDollyPan( event ) {
724 |
725 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
726 |
727 | if ( scope.enablePan ) handleTouchMovePan( event );
728 |
729 | }
730 |
731 | function handleTouchMoveDollyRotate( event ) {
732 |
733 | if ( scope.enableZoom ) handleTouchMoveDolly( event );
734 |
735 | if ( scope.enableRotate ) handleTouchMoveRotate( event );
736 |
737 | }
738 |
739 | function handleTouchEnd( /*event*/ ) {
740 |
741 | // no-op
742 |
743 | }
744 |
745 | //
746 | // event handlers - FSM: listen for events and reset state
747 | //
748 |
749 | function onMouseDown( event ) {
750 |
751 | if ( scope.enabled === false ) return;
752 |
753 | // Prevent the browser from scrolling.
754 |
755 | event.preventDefault();
756 |
757 | // Manually set the focus since calling preventDefault above
758 | // prevents the browser from setting it automatically.
759 |
760 | scope.domElement.focus ? scope.domElement.focus() : window.focus();
761 |
762 | switch ( event.button ) {
763 |
764 | case 0:
765 |
766 | switch ( scope.mouseButtons.LEFT ) {
767 |
768 | case THREE.MOUSE.ROTATE:
769 |
770 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
771 |
772 | if ( scope.enablePan === false ) return;
773 |
774 | handleMouseDownPan( event );
775 |
776 | state = STATE.PAN;
777 |
778 | } else {
779 |
780 | if ( scope.enableRotate === false ) return;
781 |
782 | handleMouseDownRotate( event );
783 |
784 | state = STATE.ROTATE;
785 |
786 | }
787 |
788 | break;
789 |
790 | case THREE.MOUSE.PAN:
791 |
792 | if ( event.ctrlKey || event.metaKey || event.shiftKey ) {
793 |
794 | if ( scope.enableRotate === false ) return;
795 |
796 | handleMouseDownRotate( event );
797 |
798 | state = STATE.ROTATE;
799 |
800 | } else {
801 |
802 | if ( scope.enablePan === false ) return;
803 |
804 | handleMouseDownPan( event );
805 |
806 | state = STATE.PAN;
807 |
808 | }
809 |
810 | break;
811 |
812 | default:
813 |
814 | state = STATE.NONE;
815 |
816 | }
817 |
818 | break;
819 |
820 |
821 | case 1:
822 |
823 | switch ( scope.mouseButtons.MIDDLE ) {
824 |
825 | case THREE.MOUSE.DOLLY:
826 |
827 | if ( scope.enableZoom === false ) return;
828 |
829 | handleMouseDownDolly( event );
830 |
831 | state = STATE.DOLLY;
832 |
833 | break;
834 |
835 |
836 | default:
837 |
838 | state = STATE.NONE;
839 |
840 | }
841 |
842 | break;
843 |
844 | case 2:
845 |
846 | switch ( scope.mouseButtons.RIGHT ) {
847 |
848 | case THREE.MOUSE.ROTATE:
849 |
850 | if ( scope.enableRotate === false ) return;
851 |
852 | handleMouseDownRotate( event );
853 |
854 | state = STATE.ROTATE;
855 |
856 | break;
857 |
858 | case THREE.MOUSE.PAN:
859 |
860 | if ( scope.enablePan === false ) return;
861 |
862 | handleMouseDownPan( event );
863 |
864 | state = STATE.PAN;
865 |
866 | break;
867 |
868 | default:
869 |
870 | state = STATE.NONE;
871 |
872 | }
873 |
874 | break;
875 |
876 | }
877 |
878 | if ( state !== STATE.NONE ) {
879 |
880 | document.addEventListener( 'mousemove', onMouseMove, false );
881 | document.addEventListener( 'mouseup', onMouseUp, false );
882 |
883 | scope.dispatchEvent( startEvent );
884 |
885 | }
886 |
887 | }
888 |
889 | function onMouseMove( event ) {
890 |
891 | if ( scope.enabled === false ) return;
892 |
893 | event.preventDefault();
894 |
895 | switch ( state ) {
896 |
897 | case STATE.ROTATE:
898 |
899 | if ( scope.enableRotate === false ) return;
900 |
901 | handleMouseMoveRotate( event );
902 |
903 | break;
904 |
905 | case STATE.DOLLY:
906 |
907 | if ( scope.enableZoom === false ) return;
908 |
909 | handleMouseMoveDolly( event );
910 |
911 | break;
912 |
913 | case STATE.PAN:
914 |
915 | if ( scope.enablePan === false ) return;
916 |
917 | handleMouseMovePan( event );
918 |
919 | break;
920 |
921 | }
922 |
923 | }
924 |
925 | function onMouseUp( event ) {
926 |
927 | if ( scope.enabled === false ) return;
928 |
929 | handleMouseUp( event );
930 |
931 | document.removeEventListener( 'mousemove', onMouseMove, false );
932 | document.removeEventListener( 'mouseup', onMouseUp, false );
933 |
934 | scope.dispatchEvent( endEvent );
935 |
936 | state = STATE.NONE;
937 |
938 | }
939 |
940 | function onMouseWheel( event ) {
941 |
942 | if ( scope.enabled === false || scope.enableZoom === false || ( state !== STATE.NONE && state !== STATE.ROTATE ) ) return;
943 |
944 | event.preventDefault();
945 | event.stopPropagation();
946 |
947 | scope.dispatchEvent( startEvent );
948 |
949 | handleMouseWheel( event );
950 |
951 | scope.dispatchEvent( endEvent );
952 |
953 | }
954 |
955 | function onKeyDown( event ) {
956 |
957 | if ( scope.enabled === false || scope.enableKeys === false || scope.enablePan === false ) return;
958 |
959 | handleKeyDown( event );
960 |
961 | }
962 |
963 | function onTouchStart( event ) {
964 |
965 | if ( scope.enabled === false ) return;
966 |
967 | event.preventDefault();
968 |
969 | switch ( event.touches.length ) {
970 |
971 | case 1:
972 |
973 | switch ( scope.touches.ONE ) {
974 |
975 | case THREE.TOUCH.ROTATE:
976 |
977 | if ( scope.enableRotate === false ) return;
978 |
979 | handleTouchStartRotate( event );
980 |
981 | state = STATE.TOUCH_ROTATE;
982 |
983 | break;
984 |
985 | case THREE.TOUCH.PAN:
986 |
987 | if ( scope.enablePan === false ) return;
988 |
989 | handleTouchStartPan( event );
990 |
991 | state = STATE.TOUCH_PAN;
992 |
993 | break;
994 |
995 | default:
996 |
997 | state = STATE.NONE;
998 |
999 | }
1000 |
1001 | break;
1002 |
1003 | case 2:
1004 |
1005 | switch ( scope.touches.TWO ) {
1006 |
1007 | case THREE.TOUCH.DOLLY_PAN:
1008 |
1009 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
1010 |
1011 | handleTouchStartDollyPan( event );
1012 |
1013 | state = STATE.TOUCH_DOLLY_PAN;
1014 |
1015 | break;
1016 |
1017 | case THREE.TOUCH.DOLLY_ROTATE:
1018 |
1019 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
1020 |
1021 | handleTouchStartDollyRotate( event );
1022 |
1023 | state = STATE.TOUCH_DOLLY_ROTATE;
1024 |
1025 | break;
1026 |
1027 | default:
1028 |
1029 | state = STATE.NONE;
1030 |
1031 | }
1032 |
1033 | break;
1034 |
1035 | default:
1036 |
1037 | state = STATE.NONE;
1038 |
1039 | }
1040 |
1041 | if ( state !== STATE.NONE ) {
1042 |
1043 | scope.dispatchEvent( startEvent );
1044 |
1045 | }
1046 |
1047 | }
1048 |
1049 | function onTouchMove( event ) {
1050 |
1051 | if ( scope.enabled === false ) return;
1052 |
1053 | event.preventDefault();
1054 | event.stopPropagation();
1055 |
1056 | switch ( state ) {
1057 |
1058 | case STATE.TOUCH_ROTATE:
1059 |
1060 | if ( scope.enableRotate === false ) return;
1061 |
1062 | handleTouchMoveRotate( event );
1063 |
1064 | scope.update();
1065 |
1066 | break;
1067 |
1068 | case STATE.TOUCH_PAN:
1069 |
1070 | if ( scope.enablePan === false ) return;
1071 |
1072 | handleTouchMovePan( event );
1073 |
1074 | scope.update();
1075 |
1076 | break;
1077 |
1078 | case STATE.TOUCH_DOLLY_PAN:
1079 |
1080 | if ( scope.enableZoom === false && scope.enablePan === false ) return;
1081 |
1082 | handleTouchMoveDollyPan( event );
1083 |
1084 | scope.update();
1085 |
1086 | break;
1087 |
1088 | case STATE.TOUCH_DOLLY_ROTATE:
1089 |
1090 | if ( scope.enableZoom === false && scope.enableRotate === false ) return;
1091 |
1092 | handleTouchMoveDollyRotate( event );
1093 |
1094 | scope.update();
1095 |
1096 | break;
1097 |
1098 | default:
1099 |
1100 | state = STATE.NONE;
1101 |
1102 | }
1103 |
1104 | }
1105 |
1106 | function onTouchEnd( event ) {
1107 |
1108 | if ( scope.enabled === false ) return;
1109 |
1110 | handleTouchEnd( event );
1111 |
1112 | scope.dispatchEvent( endEvent );
1113 |
1114 | state = STATE.NONE;
1115 |
1116 | }
1117 |
1118 | function onContextMenu( event ) {
1119 |
1120 | if ( scope.enabled === false ) return;
1121 |
1122 | event.preventDefault();
1123 |
1124 | }
1125 |
1126 | //
1127 |
1128 | scope.domElement.addEventListener( 'contextmenu', onContextMenu, false );
1129 |
1130 | scope.domElement.addEventListener( 'mousedown', onMouseDown, false );
1131 | scope.domElement.addEventListener( 'wheel', onMouseWheel, false );
1132 |
1133 | scope.domElement.addEventListener( 'touchstart', onTouchStart, false );
1134 | scope.domElement.addEventListener( 'touchend', onTouchEnd, false );
1135 | scope.domElement.addEventListener( 'touchmove', onTouchMove, false );
1136 |
1137 | window.addEventListener( 'keydown', onKeyDown, false );
1138 |
1139 | // force an update at start
1140 |
1141 | this.update();
1142 |
1143 | };
1144 |
1145 | THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
1146 | THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;
1147 |
1148 |
1149 | // This set of controls performs orbiting, dollying (zooming), and panning.
1150 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
1151 | // This is very similar to OrbitControls, another set of touch behavior
1152 | //
1153 | // Orbit - right mouse, or left mouse + ctrl/meta/shiftKey / touch: two-finger rotate
1154 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
1155 | // Pan - left mouse, or arrow keys / touch: one-finger move
1156 |
1157 | THREE.MapControls = function ( object, domElement ) {
1158 |
1159 | THREE.OrbitControls.call( this, object, domElement );
1160 |
1161 | this.mouseButtons.LEFT = THREE.MOUSE.PAN;
1162 | this.mouseButtons.RIGHT = THREE.MOUSE.ROTATE;
1163 |
1164 | this.touches.ONE = THREE.TOUCH.PAN;
1165 | this.touches.TWO = THREE.TOUCH.DOLLY_ROTATE;
1166 |
1167 | };
1168 |
1169 | THREE.MapControls.prototype = Object.create( THREE.EventDispatcher.prototype );
1170 | THREE.MapControls.prototype.constructor = THREE.MapControls;
--------------------------------------------------------------------------------
/js/sketch.js:
--------------------------------------------------------------------------------
1 |
2 | class Sketch {
3 | constructor(opts) {
4 | this.scene = new THREE.Scene();
5 | this.vertex = `varying vec2 vUv;void main() {vUv = uv;gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );}`;
6 | this.fragment = opts.fragment;
7 | this.uniforms = opts.uniforms;
8 | this.renderer = new THREE.WebGLRenderer();
9 | this.width = window.innerWidth;
10 | this.height = window.innerHeight;
11 | this.renderer.setPixelRatio(window.devicePixelRatio);
12 | this.renderer.setSize(this.width, this.height);
13 | this.renderer.setClearColor(0xeeeeee, 1);
14 | this.duration = opts.duration || 1;
15 | this.debug = opts.debug || false
16 | this.easing = opts.easing || 'easeInOut'
17 |
18 | this.clicker = document.getElementById("content");
19 |
20 |
21 | this.container = document.getElementById("slider");
22 | this.images = JSON.parse(this.container.getAttribute('data-images'));
23 | this.width = this.container.offsetWidth;
24 | this.height = this.container.offsetHeight;
25 | this.container.appendChild(this.renderer.domElement);
26 |
27 | this.camera = new THREE.PerspectiveCamera(
28 | 70,
29 | window.innerWidth / window.innerHeight,
30 | 0.001,
31 | 1000
32 | );
33 |
34 | this.camera.position.set(0, 0, 2);
35 | this.time = 0;
36 | this.current = 0;
37 | this.textures = [];
38 |
39 | this.paused = true;
40 | this.initiate(()=>{
41 | console.log(this.textures);
42 | this.setupResize();
43 | this.settings();
44 | this.addObjects();
45 | this.resize();
46 | this.clickEvent();
47 | this.play();
48 | })
49 |
50 |
51 |
52 | }
53 |
54 | initiate(cb){
55 | const promises = [];
56 | let that = this;
57 | this.images.forEach((url,i)=>{
58 | let promise = new Promise(resolve => {
59 | that.textures[i] = new THREE.TextureLoader().load( url, resolve );
60 | });
61 | promises.push(promise);
62 | })
63 |
64 | Promise.all(promises).then(() => {
65 | cb();
66 | });
67 | }
68 |
69 | clickEvent(){
70 | this.clicker.addEventListener('click',()=>{
71 | this.next();
72 | })
73 | }
74 | settings() {
75 | let that = this;
76 | if(this.debug) this.gui = new dat.GUI();
77 | this.settings = {progress:0.5};
78 | // if(this.debug) this.gui.add(this.settings, "progress", 0, 1, 0.01);
79 |
80 | Object.keys(this.uniforms).forEach((item)=> {
81 | this.settings[item] = this.uniforms[item].value;
82 | if(this.debug) this.gui.add(this.settings, item, this.uniforms[item].min, this.uniforms[item].max, 0.01);
83 | })
84 | }
85 |
86 | setupResize() {
87 | window.addEventListener("resize", this.resize.bind(this));
88 | }
89 |
90 | resize() {
91 | this.width = this.container.offsetWidth;
92 | this.height = this.container.offsetHeight;
93 | this.renderer.setSize(this.width, this.height);
94 | this.camera.aspect = this.width / this.height;
95 |
96 |
97 | // image cover
98 | this.imageAspect = this.textures[0].image.height/this.textures[0].image.width;
99 | let a1; let a2;
100 | if(this.height/this.width>this.imageAspect) {
101 | a1 = (this.width/this.height) * this.imageAspect ;
102 | a2 = 1;
103 | } else{
104 | a1 = 1;
105 | a2 = (this.height/this.width) / this.imageAspect;
106 | }
107 |
108 | this.material.uniforms.resolution.value.x = this.width;
109 | this.material.uniforms.resolution.value.y = this.height;
110 | this.material.uniforms.resolution.value.z = a1;
111 | this.material.uniforms.resolution.value.w = a2;
112 |
113 | const dist = this.camera.position.z;
114 | const height = 1;
115 | this.camera.fov = 2*(180/Math.PI)*Math.atan(height/(2*dist));
116 |
117 | this.plane.scale.x = this.camera.aspect;
118 | this.plane.scale.y = 1;
119 |
120 | this.camera.updateProjectionMatrix();
121 |
122 |
123 | }
124 |
125 | addObjects() {
126 | let that = this;
127 | this.material = new THREE.ShaderMaterial({
128 | extensions: {
129 | derivatives: "#extension GL_OES_standard_derivatives : enable"
130 | },
131 | side: THREE.DoubleSide,
132 | uniforms: {
133 | time: { type: "f", value: 0 },
134 | progress: { type: "f", value: 0 },
135 | border: { type: "f", value: 0 },
136 | intensity: { type: "f", value: 0 },
137 | scaleX: { type: "f", value: 40 },
138 | scaleY: { type: "f", value: 40 },
139 | transition: { type: "f", value: 40 },
140 | swipe: { type: "f", value: 0 },
141 | width: { type: "f", value: 0 },
142 | radius: { type: "f", value: 0 },
143 | texture1: { type: "f", value: this.textures[0] },
144 | texture2: { type: "f", value: this.textures[1] },
145 | displacement: { type: "f", value: new THREE.TextureLoader().load('img/disp1.jpg') },
146 | resolution: { type: "v4", value: new THREE.Vector4() },
147 | },
148 | // wireframe: true,
149 | vertexShader: this.vertex,
150 | fragmentShader: this.fragment
151 | });
152 |
153 | this.geometry = new THREE.PlaneGeometry(1, 1, 2, 2);
154 |
155 | this.plane = new THREE.Mesh(this.geometry, this.material);
156 | this.scene.add(this.plane);
157 | }
158 |
159 | stop() {
160 | this.paused = true;
161 | }
162 |
163 | play() {
164 | this.paused = false;
165 | this.render();
166 | }
167 |
168 | next(){
169 | if(this.isRunning) return;
170 | this.isRunning = true;
171 | let len = this.textures.length;
172 | let nextTexture =this.textures[(this.current +1)%len];
173 | this.material.uniforms.texture2.value = nextTexture;
174 | let tl = new TimelineMax();
175 | tl.to(this.material.uniforms.progress,this.duration,{
176 | value:1,
177 | ease: Power2[this.easing],
178 | onComplete:()=>{
179 | console.log('FINISH');
180 | this.current = (this.current +1)%len;
181 | this.material.uniforms.texture1.value = nextTexture;
182 | this.material.uniforms.progress.value = 0;
183 | this.isRunning = false;
184 | }})
185 | }
186 | render() {
187 | if (this.paused) return;
188 | this.time += 0.05;
189 | this.material.uniforms.time.value = this.time;
190 | // this.material.uniforms.progress.value = this.settings.progress;
191 |
192 | Object.keys(this.uniforms).forEach((item)=> {
193 | this.material.uniforms[item].value = this.settings[item];
194 | });
195 |
196 | // this.camera.position.z = 3;
197 | // this.plane.rotation.y = 0.4*Math.sin(this.time)
198 | // this.plane.rotation.x = 0.5*Math.sin(0.4*this.time)
199 |
200 | requestAnimationFrame(this.render.bind(this));
201 | this.renderer.render(this.scene, this.camera);
202 | }
203 | }
204 |
205 |
--------------------------------------------------------------------------------