├── README.md
├── assets
├── env-blur.jpg
├── env.jpg
├── normal.jpg
├── track.mp3
└── track.ogg
├── css
└── styles.css
├── facebook.jpg
├── index.html
├── main.js
├── modules
├── easings.js
├── fbo.js
├── gift-box.js
├── maf.js
├── paper.js
├── paper1.js
├── paper10.js
├── paper11.js
├── paper12.js
├── paper13.js
├── paper14.js
├── paper15.js
├── paper16.js
├── paper17.js
├── paper18.js
├── paper19.js
├── paper2.js
├── paper20.js
├── paper3.js
├── paper4.js
├── paper5.js
├── paper6.js
├── paper7.js
├── paper8.js
├── paper9.js
├── post.js
├── scene.js
├── shader-pass.js
├── shader-ping-pong-pass.js
└── wrapping-paper.js
├── paper.html
├── preview.jpg
├── shaders
├── blur-fs.js
├── combine-fs.js
├── depth-fs.js
├── depth-vs.js
├── dof-fs.js
├── fast-separable-gaussian-blur.js
├── final-color-fs.js
├── final-fs.js
├── fxaa.js
├── grayscale.js
├── highlight-fs.js
├── levels.js
├── ortho.js
├── overlay.js
├── random.js
├── rgb-shift.js
├── screen.js
├── smootherstep.js
├── soft-light.js
└── vignette.js
├── test.js
├── third_party
├── THREE.OrbitControls.js
├── UpdatableTexture.js
├── WebXR.js
├── equirectangular-to-cubemap.js
└── three.module.js
└── twitter.jpg
/README.md:
--------------------------------------------------------------------------------
1 | # Infinite Gift · Christmas Experiments 2018
2 |
3 | A never-ending gift in your browser.
4 | https://christmasexperiments.com/2018/24/infinite-gift/
5 |
6 | Music by Bent Stamnes (https://twitter.com/gloom303)
7 |
8 | Code by Jaume Sanchez (https://twitter.com/thespite)
9 |
10 | Original wrapping paper generation utils by Roger Pujol (https://twitter.com/rogerpjg)
11 |
12 | Made with three.js. Based on an idea with Roger Pujol (https://twitter.com/rogerpjg) from a few years ago
13 | Supports WebVR/WebXR if available.
14 |
15 | # License to code
16 |
17 | [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/)
18 |
19 | This license lets others remix, tweak, and build upon your work even for commercial purposes, as long as they credit you and license their new creations under the identical terms. This license is often compared to “copyleft” free and open source software licenses. All new works based on yours will carry the same license, so any derivatives will also allow commercial use. This is the license used by Wikipedia, and is recommended for materials that would benefit from incorporating content from Wikipedia and similarly licensed projects.
20 |
21 | # License to music
22 |
23 | [CC BY-NC-SA](https://creativecommons.org/licenses/by-nc-sa/4.0/)
24 |
25 | This license lets others remix, tweak, and build upon your work non-commercially, as long as they credit you and license their new creations under the identical terms.
26 |
--------------------------------------------------------------------------------
/assets/env-blur.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/assets/env-blur.jpg
--------------------------------------------------------------------------------
/assets/env.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/assets/env.jpg
--------------------------------------------------------------------------------
/assets/normal.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/assets/normal.jpg
--------------------------------------------------------------------------------
/assets/track.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/assets/track.mp3
--------------------------------------------------------------------------------
/assets/track.ogg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/assets/track.ogg
--------------------------------------------------------------------------------
/css/styles.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | box-sizing: border-box;
5 | }
6 |
7 | body {
8 | position: absolute;
9 | display: block;
10 | width: 100%;
11 | height: 100%;
12 | background: black;
13 | }
14 |
15 | #disclaimer {
16 | font-size: 13px;
17 | text-align: center;
18 | font-family: 'Roboto', sans-serif;
19 | line-height: 1.4em;
20 | position: absolute;
21 | left: 0;
22 | right: 0;
23 | bottom: 0;
24 | width: 100%;
25 | padding: 40px;
26 | color: #aaa;
27 | }
28 |
29 | #disclaimer p {
30 | white-space: nowrap;
31 | }
32 |
33 | #disclaimer b {
34 | font-weight: bold;
35 | color: white;
36 | }
37 |
38 | .render {
39 | position: absolute;
40 | left: 0;
41 | top: 0;
42 | right: 0;
43 | bottom: 0;
44 | width: 100%;
45 | height: 100%;
46 | }
47 |
48 | #options {
49 | font-size: 20px;
50 | font-family: 'Berkshire Swash', cursive;
51 | position: absolute;
52 | z-index: 10;
53 | color: white;
54 | left: 0;
55 | top: 0;
56 | right: 0;
57 | bottom: 0;
58 | width: 100%;
59 | height: 100%;
60 | transition: opacity 1s ease-out;
61 | }
62 |
63 | #options #webxr {
64 | display: none;
65 | }
66 |
67 | #presets,
68 | #loading {
69 | text-align: center;
70 | position: absolute;
71 | left: 50%;
72 | top: 50%;
73 | transform: translate3d(-50%, -50%, 0);
74 | }
75 |
76 | #options h1 {
77 | font-size: 80px;
78 | white-space: nowrap;
79 | text-align: center;
80 | position: absolute;
81 | left: 50%;
82 | top: calc(50% - 1em);
83 | transform: translate3d(-50%, -50%, 0);
84 | }
85 |
86 | #options h2 {
87 | font-size: 20px;
88 | white-space: nowrap;
89 | text-align: center;
90 | position: absolute;
91 | left: 50%;
92 | top: calc(50% - 8em);
93 | transform: translate3d(-50%, -50%, 0);
94 | }
95 |
96 | .hidden {
97 | pointer-events: none;
98 | opacity: 0;
99 | }
100 |
101 | .visible {
102 | pointer-events: auto;
103 | opacity: 1;
104 | }
105 |
106 | #presets {
107 | display: none;
108 | margin-top: 3em;
109 | }
110 |
111 | #options a {
112 | color: white;
113 | text-decoration: none;
114 | padding: 1em;
115 | display: inline-block;
116 | transition: color 250ms ease-out;
117 | }
118 |
119 | #options span {
120 | display: block;
121 | }
122 |
123 | #options a:hover {
124 | color: red;
125 | }
126 |
127 | #start {
128 | display: none;
129 | }
130 |
131 | #canvas {
132 | position: absolute;
133 | left: 0;
134 | top: 80px;
135 | transition: opacity 1s ease-out;
136 | }
137 |
138 | @media only screen and (max-width: 600px) {
139 | #options {
140 | font-size: 5vw;
141 | }
142 |
143 | #options h1 {
144 | font-size: 10vw;
145 | }
146 |
147 | #options h2 {
148 | font-size: 4vw;
149 | }
150 |
151 | #presets {
152 | margin-top: 20vw;
153 | }
154 |
155 | #options a {
156 | padding: 3vw;
157 | display: inline-block;
158 | }
159 |
160 | #options span {
161 | white-space: nowrap;
162 | }
163 | }
--------------------------------------------------------------------------------
/facebook.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/facebook.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Infinite Gift · Christmas Experiments 2018
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
spite · gloom | christmas experiments
26 |
Infinite Gift
27 |
Loading...
28 |
Low · Standard · High VR Low · High
29 |
30 |
This is a WebGL ES6 experience. Make sure your browser is updated. Make sure WebXR is supported in order to access the VR experience. Images can cause dizziness .
31 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | import {
2 | renderer,
3 | setSize,
4 | animate,
5 | render,
6 | init,
7 | loadAssets
8 | } from "./modules/scene.js";
9 | import { detectWebXR, startWebXR } from "./third_party/WebXR.js";
10 |
11 | const padding = 80;
12 | const presets = document.getElementById("presets");
13 | const options = document.getElementById("options");
14 | const loading = document.getElementById("loading");
15 |
16 | if (!Element.prototype.requestFullscreen) {
17 | Element.prototype.requestFullscreen =
18 | Element.prototype.mozRequestFullScreen ||
19 | Element.prototype.webkitRequestFullScreen;
20 | }
21 |
22 | async function start() {
23 | document.body.appendChild(renderer.domElement);
24 | renderer.domElement.className = "hidden render";
25 | renderer.domElement.id = "canvas";
26 | resize();
27 |
28 | let isWebXRSupported = false;
29 | /*try {
30 | await detectWebXR(renderer);
31 | isWebXRSupported = true;
32 | } catch (e) {}*/
33 | if (isWebXRSupported) {
34 | document.getElementById("webxr").style.display = "block";
35 | }
36 | await loadAssets();
37 | loading.style.display = "none";
38 | presets.style.display = "block";
39 | const options = presets.querySelectorAll("a");
40 | for (let option of options) {
41 | option.addEventListener("click", e => {
42 | run(
43 | option.id,
44 | option.id === "vrlow" || option.id === "vrhigh"
45 | ? isWebXRSupported
46 | : null
47 | );
48 | });
49 | }
50 | }
51 |
52 | async function run(preset, device) {
53 | if (device) {
54 | renderer.xr.enabled = true;
55 | }
56 | await init(preset);
57 | options.className = "hidden";
58 | if (device) {
59 | startWebXR(device, renderer);
60 | }
61 | await renderer.domElement.requestFullscreen();
62 | animate();
63 | }
64 |
65 | window.addEventListener("resize", e => resize());
66 |
67 | function resize() {
68 | let w = document.body.clientWidth;
69 | let h = document.body.clientHeight;
70 | h -= 2 * padding;
71 | setSize(w, h);
72 | }
73 |
74 | window.addEventListener("load", start);
75 |
--------------------------------------------------------------------------------
/modules/easings.js:
--------------------------------------------------------------------------------
1 | const Easings = {
2 | Linear: function(t) {
3 | return t;
4 | },
5 | InQuad: function(t) {
6 | return t * t;
7 | },
8 | OutQuad: function(t) {
9 | return t * (2 - t);
10 | },
11 | InOutQuad: function(t) {
12 | if ((t *= 2) < 1) {
13 | return 0.5 * t * t;
14 | }
15 | return -0.5 * (--t * (t - 2) - 1);
16 | },
17 | InCubic: function(t) {
18 | return t * t * t;
19 | },
20 | OutCubic: function(t) {
21 | return --t * t * t + 1;
22 | },
23 | InOutCubic: function(t) {
24 | if ((t *= 2) < 1) {
25 | return 0.5 * t * t * t;
26 | }
27 | return 0.5 * ((t -= 2) * t * t + 2);
28 | },
29 | InQuart: function(t) {
30 | return t * t * t * t;
31 | },
32 | OutQuart: function(t) {
33 | return 1 - --t * t * t * t;
34 | },
35 | InOutQuart: function(t) {
36 | if ((t *= 2) < 1) {
37 | return 0.5 * t * t * t * t;
38 | }
39 | return 0.5 * ((t -= 2) * t * t * t - 2);
40 | },
41 | InQuint: function(t) {
42 | return t * t * t * t * t;
43 | },
44 | OutQuint: function(t) {
45 | return --t * t * t * t * t + 1;
46 | },
47 | InOutQuint: function(t) {
48 | if ((t *= 2) < 1) return 0.5 * t * t * t * t * t;
49 | return 0.5 * ((t -= 2) * t * t * t * t + 2);
50 | },
51 | InSine: function(t) {
52 | return 1 - Math.cos((t * Math.PI) / 2);
53 | },
54 | OutSine: function(t) {
55 | return Math.sin((t * Math.PI) / 2);
56 | },
57 | InOutSine: function(t) {
58 | return 0.5 * (1 - Math.cos(Math.PI * t));
59 | },
60 | InBounce: function(t) {
61 | return 1 - outBounce(1 - t);
62 | },
63 | OutBounce: function(t) {
64 | if (t < 0.36363636363636365) {
65 | return 7.5625 * t * t;
66 | } else if (t < 0.7272727272727273) {
67 | t = t - 0.5454545454545454;
68 | return 7.5625 * t * t + 0.75;
69 | } else if (t < 0.9090909090909091) {
70 | t = t - 0.8181818181818182;
71 | return 7.5625 * t * t + 0.9375;
72 | } else {
73 | t = t - 0.9545454545454546;
74 | return 7.5625 * t * t + 0.984375;
75 | }
76 | },
77 | InOutBounce: function(t) {
78 | if (t < 0.5) {
79 | return Easings.InBounce(t * 2) * 0.5;
80 | }
81 | return Easings.OutBounce(t * 2 - 1) * 0.5 + 1 * 0.5;
82 | },
83 | InElastic: function(t, amplitude, period) {
84 | if (typeof period == "undefined") {
85 | period = 0;
86 | }
87 | if (typeof amplitude == "undefined") {
88 | amplitude = 1;
89 | }
90 | var offset = 1.70158;
91 |
92 | if (t == 0) return 0;
93 | if (t == 1) return 1;
94 |
95 | if (!period) {
96 | period = 0.3;
97 | }
98 |
99 | if (amplitude < 1) {
100 | amplitude = 1;
101 | offset = period / 4;
102 | } else {
103 | offset = (period / (2 * Math.PI)) * Math.asin(1 / amplitude);
104 | }
105 |
106 | return -(
107 | amplitude *
108 | Math.pow(2, 10 * (t -= 1)) *
109 | Math.sin(((t - offset) * (Math.PI * 2)) / period)
110 | );
111 | },
112 | OutElastic: function(t, amplitude, period) {
113 | if (typeof period == "undefined") {
114 | period = 0;
115 | }
116 | if (typeof amplitude == "undefined") {
117 | amplitude = 1;
118 | }
119 | var offset = 1.70158;
120 |
121 | if (t == 0) return 0;
122 | if (t == 1) return 1;
123 |
124 | if (!period) {
125 | period = 0.3;
126 | }
127 |
128 | if (amplitude < 1) {
129 | amplitude = 1;
130 | offset = period / 4;
131 | } else {
132 | offset = (period / (2 * Math.PI)) * Math.asin(1 / amplitude);
133 | }
134 |
135 | return (
136 | amplitude *
137 | Math.pow(2, -10 * t) *
138 | Math.sin(((t - offset) * (Math.PI * 2)) / period) +
139 | 1
140 | );
141 | },
142 | InOutElastic: function(t, amplitude, period) {
143 | var offset;
144 | t = t / 2 - 1;
145 | // escape early for 0 and 1
146 | if (t === 0 || t === 1) {
147 | return t;
148 | }
149 | if (!period) {
150 | period = 0.44999999999999996;
151 | }
152 | if (!amplitude) {
153 | amplitude = 1;
154 | offset = period / 4;
155 | } else {
156 | offset = (period / (Math.PI * 2.0)) * Math.asin(1 / amplitude);
157 | }
158 | return (
159 | (amplitude *
160 | Math.pow(2, 10 * t) *
161 | Math.sin(((t - offset) * (Math.PI * 2)) / period)) /
162 | -2
163 | );
164 | },
165 | InExpo: function(t) {
166 | return Math.pow(2, 10 * (t - 1));
167 | },
168 | OutExpo: function(t) {
169 | return -Math.pow(2, -10 * t) + 1;
170 | },
171 | InOutExpo: function(t) {
172 | if (t == 0) return 0;
173 | if (t == 1) return 1;
174 | if ((t /= 0.5) < 1) return 0.5 * Math.pow(2, 10 * (t - 1));
175 | return 0.5 * (-Math.pow(2, -10 * --t) + 2);
176 | },
177 | InCirc: function(t) {
178 | return -1 * (Math.sqrt(1 - t * t) - 1);
179 | },
180 | OutCirc: function(t) {
181 | t = t - 1;
182 | return Math.sqrt(1 - t * t);
183 | },
184 | InOutCirc: function(t) {
185 | var c = 1;
186 | if ((t /= 0.5) < 1) return -0.5 * (Math.sqrt(1 - t * t) - 1);
187 | return 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1);
188 | },
189 | InBack: function(t, overshoot) {
190 | if (!overshoot && overshoot !== 0) {
191 | overshoot = 1.70158;
192 | }
193 | return 1 * t * t * ((overshoot + 1) * t - overshoot);
194 | },
195 | OutBack: function(t, overshoot) {
196 | if (!overshoot && overshoot !== 0) {
197 | overshoot = 1.70158;
198 | }
199 | t = t - 1;
200 | return t * t * ((overshoot + 1) * t + overshoot) + 1;
201 | },
202 | InOutBack: function(t, overshoot) {
203 | if (overshoot == undefined) overshoot = 1.70158;
204 | if ((t /= 0.5) < 1)
205 | return 0.5 * (t * t * (((overshoot *= 1.525) + 1) * t - overshoot));
206 | return (
207 | 0.5 * ((t -= 2) * t * (((overshoot *= 1.525) + 1) * t + overshoot) + 2)
208 | );
209 | }
210 | };
211 |
212 | const outBounce = Easings.OutBounce;
213 |
214 | export default Easings;
215 |
--------------------------------------------------------------------------------
/modules/fbo.js:
--------------------------------------------------------------------------------
1 | import {
2 | WebGLRenderTarget,
3 | ClampToEdgeWrapping,
4 | LinearFilter,
5 | RGBAFormat,
6 | UnsignedByteType
7 | } from "../third_party/three.module.js";
8 |
9 | function getFBO(w, h, options = {}) {
10 | const fbo = new WebGLRenderTarget(w, h, {
11 | wrapS: options.wrapS || ClampToEdgeWrapping,
12 | wrapT: options.wrapT || ClampToEdgeWrapping,
13 | minFilter: options.minFilter || LinearFilter,
14 | magFilter: options.magFilter || LinearFilter,
15 | format: options.format || RGBAFormat,
16 | type: options.type || UnsignedByteType,
17 | stencilBuffer: options.stencilBuffer || false,
18 | depthBuffer: options.depthBuffer || true
19 | });
20 | return fbo;
21 | }
22 |
23 | export { getFBO };
24 |
--------------------------------------------------------------------------------
/modules/gift-box.js:
--------------------------------------------------------------------------------
1 | import {
2 | Mesh,
3 | Group,
4 | DoubleSide,
5 | PlaneGeometry,
6 | BufferAttribute,
7 | BufferGeometry,
8 | MeshBasicMaterial,
9 | Geometry,
10 | MeshNormalMaterial,
11 | MeshPhongMaterial,
12 | MeshPhysicalMaterial,
13 | Vector3,
14 | Vector2,
15 | Face3,
16 | Matrix4,
17 | RawShaderMaterial
18 | } from "../third_party/three.module.js";
19 | import { Maf } from "./maf.js";
20 |
21 | import { vs as depthVertexShader } from "../shaders/depth-vs.js";
22 | import { fs as depthFragmentShader } from "../shaders/depth-fs.js";
23 |
24 | function merge() {
25 | const total = [...arguments].reduce(
26 | (accumulator, geometry) => accumulator + geometry.attributes.position.count,
27 | 0
28 | );
29 | const res = new BufferGeometry();
30 | res.setAttribute(
31 | "position",
32 | new BufferAttribute(new Float32Array(total * 3), 3)
33 | );
34 | res.setAttribute(
35 | "normal",
36 | new BufferAttribute(new Float32Array(total * 3), 3)
37 | );
38 | res.setAttribute("uv", new BufferAttribute(new Float32Array(total * 2), 2));
39 | let ptr = 0;
40 | [...arguments].forEach((geometry, id) => {
41 | res.merge(geometry, ptr);
42 | ptr += geometry.attributes.position.count;
43 | });
44 | return res;
45 | }
46 |
47 | function quad(
48 | x0,
49 | y0,
50 | z0,
51 | x1,
52 | y1,
53 | z1,
54 | x2,
55 | y2,
56 | z2,
57 | x3,
58 | y3,
59 | z3,
60 | u0,
61 | v0,
62 | u1,
63 | v1,
64 | u2,
65 | v2,
66 | u3,
67 | v3,
68 | u,
69 | v
70 | ) {
71 | const geometry = new BufferGeometry().fromGeometry(new PlaneGeometry(1, 1));
72 | const pos = geometry.attributes.position.array;
73 | pos[0] = x0;
74 | pos[1] = y0;
75 | pos[2] = z0;
76 | pos[3] = pos[9] = x1;
77 | pos[4] = pos[10] = y1;
78 | pos[5] = pos[11] = z1;
79 | pos[6] = pos[15] = x3;
80 | pos[7] = pos[16] = y3;
81 | pos[8] = pos[17] = z3;
82 | pos[12] = x2;
83 | pos[13] = y2;
84 | pos[14] = z2;
85 | geometry.computeVertexNormals();
86 | const uvs = geometry.attributes.uv.array;
87 | const ratio = v / u;
88 | uvs[0] = u0;
89 | uvs[1] = v0 * ratio;
90 | uvs[2] = u1;
91 | uvs[3] = v1 * ratio;
92 | uvs[4] = u3;
93 | uvs[5] = v3 * ratio;
94 | uvs[6] = u1;
95 | uvs[7] = v1 * ratio;
96 | uvs[8] = u2;
97 | uvs[9] = v2 * ratio;
98 | uvs[10] = u3;
99 | uvs[11] = v3 * ratio;
100 | return geometry;
101 | }
102 |
103 | class GiftBox extends Group {
104 | constructor(material) {
105 | super();
106 |
107 | this.padding = 0.01;
108 |
109 | this.colorMaterial =
110 | material === "phong"
111 | ? new MeshPhongMaterial({})
112 | : new MeshPhysicalMaterial({
113 | color: 0xffffff,
114 | roughness: 0.5,
115 | metalness: 0.5,
116 | emissive: 0x202020
117 | });
118 | this.material = this.colorMaterial;
119 |
120 | this.rimMaterial = new MeshBasicMaterial({ color: 0xffffff });
121 |
122 | this.depthMaterial = new RawShaderMaterial({
123 | vertexShader: depthVertexShader,
124 | fragmentShader: depthFragmentShader
125 | });
126 |
127 | const parts = 8;
128 | const w = ~~(Maf.randomInRange(0.75, 1) * parts) / parts;
129 | const d = ~~(Maf.randomInRange(0.75, 1) * parts) / parts;
130 | const h = ~~(Maf.randomInRange(0.5, 0.75) * 16) / 16;
131 | const p = this.padding;
132 |
133 | const { boxGeometry, rimGeometry } = this.getGeometry(w, h, d, p);
134 | boxGeometry.applyMatrix(new Matrix4().makeRotationX(Maf.PI / 2));
135 | this.box = new Mesh(boxGeometry, this.material);
136 | this.box.castShadow = true;
137 | this.box.receiveShadow = true;
138 | this.add(this.box);
139 |
140 | this.rim = new Mesh(rimGeometry, this.rimMaterial);
141 | this.rim.castShadow = true;
142 | this.rim.receiveShadow = true;
143 | this.add(this.rim);
144 |
145 | this.pivot = new Group();
146 | const {
147 | boxGeometry: lidBoxGeometry,
148 | rimGeometry: lidRimGeometry
149 | } = this.getGeometry(w + 2 * p, 0.25 * h, d + 2 * p, p);
150 | lidBoxGeometry.applyMatrix(new Matrix4().makeRotationX(-Maf.PI / 2));
151 | lidBoxGeometry.applyMatrix(new Matrix4().makeTranslation(0, 0, 0.5 * h));
152 | this.lid = new Mesh(lidBoxGeometry, this.material);
153 | this.lid.castShadow = true;
154 | this.lid.receiveShadow = true;
155 | this.lid.position.x = -1;
156 | this.pivot.add(this.lid);
157 | this.lidRim = new Mesh(lidRimGeometry, this.rimMaterial);
158 | this.lidRim.castShadow = true;
159 | this.lidRim.receiveShadow = true;
160 | this.lidRim.position.x = -1;
161 | this.pivot.add(this.lidRim);
162 | this.pivot.rotation.y = 0;
163 | this.add(this.pivot);
164 | }
165 |
166 | orientateLid() {
167 | this.pivot.position.x = 1;
168 | }
169 |
170 | refresh() {
171 | const parts = 4;
172 | const w = ~~(Maf.randomInRange(0.75, 1) * parts) / parts;
173 | const d = ~~(Maf.randomInRange(0.75, 1) * parts) / parts;
174 | const h = ~~(Maf.randomInRange(0.5, 0.75) * parts) / parts;
175 | const p = this.padding;
176 |
177 | const { boxGeometry, rimGeometry } = this.getGeometry(w, h, d, p);
178 | boxGeometry.applyMatrix(new Matrix4().makeRotationX(Maf.PI / 2));
179 | this.box.geometry = boxGeometry;
180 | this.box.geometry.needsUpdate = true;
181 | rimGeometry.applyMatrix(new Matrix4().makeRotationX(Maf.PI / 2));
182 | this.rim.geometry = rimGeometry;
183 | this.rim.geometry.needsUpdate = true;
184 |
185 | const {
186 | boxGeometry: lidBoxGeometry,
187 | rimGeometry: lidRimGeometry
188 | } = this.getGeometry(w + 2 * p, 0.25 * h, d + 2 * p, p);
189 | lidBoxGeometry.applyMatrix(new Matrix4().makeRotationX(-Maf.PI / 2));
190 | lidBoxGeometry.applyMatrix(new Matrix4().makeTranslation(0, 0, 0.5 * h));
191 | this.lid.geometry = lidBoxGeometry;
192 | this.lid.geometry.needsUpdate = true;
193 | lidRimGeometry.applyMatrix(new Matrix4().makeRotationX(-Maf.PI / 2));
194 | lidRimGeometry.applyMatrix(new Matrix4().makeTranslation(0, 0, 0.5 * h));
195 | this.lidRim.geometry = lidRimGeometry;
196 | this.lidRim.geometry.needsUpdate = true;
197 | }
198 |
199 | getGeometry(w, h, d, p) {
200 | const hw = 0.5 * w;
201 | const hh = 0.5 * h;
202 | const hd = 0.5 * d;
203 |
204 | const boxGeometry = merge(
205 | quad(
206 | -hw,
207 | -hh,
208 | -hd,
209 | hw,
210 | -hh,
211 | -hd,
212 | hw,
213 | -hh,
214 | hd,
215 | -hw,
216 | -hh,
217 | hd,
218 | 0,
219 | 0,
220 | 1,
221 | 0,
222 | 1,
223 | 1,
224 | 0,
225 | 1,
226 | d,
227 | w
228 | ),
229 |
230 | quad(
231 | -hw,
232 | -hh,
233 | -hd,
234 | -hw,
235 | -hh,
236 | hd,
237 | -hw,
238 | hh,
239 | hd,
240 | -hw,
241 | hh,
242 | -hd,
243 | 0,
244 | 0,
245 | 1,
246 | 0,
247 | 1,
248 | 1,
249 | 0,
250 | 1,
251 | d,
252 | h
253 | ),
254 | quad(
255 | hw,
256 | -hh,
257 | hd,
258 | hw,
259 | -hh,
260 | -hd,
261 | hw,
262 | hh,
263 | -hd,
264 | hw,
265 | hh,
266 | hd,
267 | 0,
268 | 0,
269 | 1,
270 | 0,
271 | 1,
272 | 1,
273 | 0,
274 | 1,
275 | d,
276 | h
277 | ),
278 | quad(
279 | hw,
280 | -hh,
281 | -hd,
282 | -hw,
283 | -hh,
284 | -hd,
285 | -hw,
286 | hh,
287 | -hd,
288 | hw,
289 | hh,
290 | -hd,
291 | 0,
292 | 0,
293 | 1,
294 | 0,
295 | 1,
296 | 1,
297 | 0,
298 | 1,
299 | w,
300 | h
301 | ),
302 | quad(
303 | -hw,
304 | -hh,
305 | hd,
306 | hw,
307 | -hh,
308 | hd,
309 | hw,
310 | hh,
311 | hd,
312 | -hw,
313 | hh,
314 | hd,
315 | 0,
316 | 0,
317 | 1,
318 | 0,
319 | 1,
320 | 1,
321 | 0,
322 | 1,
323 | w,
324 | h
325 | ),
326 |
327 | quad(
328 | hw - p,
329 | -(hh - p),
330 | -(hd - p),
331 | -(hw - p),
332 | -(hh - p),
333 | -(hd - p),
334 | -(hw - p),
335 | -(hh - p),
336 | hd - p,
337 | hw - p,
338 | -(hh - p),
339 | hd - p,
340 | 0,
341 | 0,
342 | 1,
343 | 0,
344 | 1,
345 | 1,
346 | 0,
347 | 1,
348 | w - 2 * p,
349 | d - 2 * p
350 | ),
351 |
352 | quad(
353 | -(hw - p),
354 | -(hh - p),
355 | hd - p,
356 | -(hw - p),
357 | -(hh - p),
358 | -(hd - p),
359 | -(hw - p),
360 | hh,
361 | -(hd - p),
362 | -(hw - p),
363 | hh,
364 | hd - p,
365 | 0,
366 | 0,
367 | 1,
368 | 0,
369 | 1,
370 | 1,
371 | 0,
372 | 1,
373 | d - 2 * p,
374 | h - 2 * p
375 | ),
376 | quad(
377 | hw - p,
378 | -(hh - p),
379 | -(hd - p),
380 | hw - p,
381 | -(hh - p),
382 | hd - p,
383 | hw - p,
384 | hh,
385 | hd - p,
386 | hw - p,
387 | hh,
388 | -(hd - p),
389 | 0,
390 | 0,
391 | 1,
392 | 0,
393 | 1,
394 | 1,
395 | 0,
396 | 1,
397 | d - 2 * p,
398 | h - 2 * p
399 | ),
400 | quad(
401 | hw - p,
402 | -(hh - p),
403 | hd - p,
404 | -(hw - p),
405 | -(hh - p),
406 | hd - p,
407 | -(hw - p),
408 | hh,
409 | hd - p,
410 | hw - p,
411 | hh,
412 | hd - p,
413 | 0,
414 | 0,
415 | 1,
416 | 0,
417 | 1,
418 | 1,
419 | 0,
420 | 1,
421 | w - 2 * p,
422 | h - 2 * p
423 | ),
424 | quad(
425 | -(hw - p),
426 | -(hh - p),
427 | -(hd - p),
428 | hw - p,
429 | -(hh - p),
430 | -(hd - p),
431 | hw - p,
432 | hh,
433 | -(hd - p),
434 | -(hw - p),
435 | hh,
436 | -(hd - p),
437 | 0,
438 | 0,
439 | 1,
440 | 0,
441 | 1,
442 | 1,
443 | 0,
444 | 1,
445 | w - 2 * p,
446 | h - 2 * p
447 | )
448 | );
449 |
450 | const rimGeometry = merge(
451 | quad(
452 | hw,
453 | hh,
454 | -hd,
455 | -hw,
456 | hh,
457 | -hd,
458 | -(hw - p),
459 | hh,
460 | -(hd - p),
461 | hw - p,
462 | hh,
463 | -(hd - p),
464 | 0,
465 | 0,
466 | 0,
467 | 0,
468 | 0,
469 | 0,
470 | 0,
471 | 0,
472 | w,
473 | d
474 | ),
475 | quad(
476 | -hw,
477 | hh,
478 | hd,
479 | hw,
480 | hh,
481 | hd,
482 | hw - p,
483 | hh,
484 | hd - p,
485 | -(hw - p),
486 | hh,
487 | hd - p,
488 | 0,
489 | 0,
490 | 0,
491 | 0,
492 | 0,
493 | 0,
494 | 0,
495 | 0,
496 | w,
497 | d
498 | ),
499 | quad(
500 | -hw,
501 | hh,
502 | -hd,
503 | -hw,
504 | hh,
505 | hd,
506 | -(hw - p),
507 | hh,
508 | hd - p,
509 | -(hw - p),
510 | hh,
511 | -(hd - p),
512 | 0,
513 | 0,
514 | 0,
515 | 0,
516 | 0,
517 | 0,
518 | 0,
519 | 0,
520 | w,
521 | d
522 | ),
523 | quad(
524 | hw,
525 | hh,
526 | hd,
527 | hw,
528 | hh,
529 | -hd,
530 | hw - p,
531 | hh,
532 | -(hd - p),
533 | hw - p,
534 | hh,
535 | hd - p,
536 | 0,
537 | 0,
538 | 0,
539 | 0,
540 | 0,
541 | 0,
542 | 0,
543 | 0,
544 | w,
545 | d
546 | )
547 | );
548 |
549 | return { boxGeometry, rimGeometry };
550 | }
551 | }
552 |
553 | export { GiftBox };
554 |
--------------------------------------------------------------------------------
/modules/maf.js:
--------------------------------------------------------------------------------
1 | const Maf = {};
2 |
3 | // Current version.
4 | Maf.VERSION = "1.0.0";
5 |
6 | Maf.PI = Math.PI;
7 | Maf.TAU = 2 * Maf.PI;
8 |
9 | // https://www.opengl.org/sdk/docs/man/html/clamp.xhtml
10 |
11 | Maf.clamp = function(v, minVal, maxVal) {
12 | return Math.min(maxVal, Math.max(minVal, v));
13 | };
14 |
15 | // https://www.opengl.org/sdk/docs/man/html/step.xhtml
16 |
17 | Maf.step = function(edge, v) {
18 | return v < edge ? 0 : 1;
19 | };
20 |
21 | // https://www.opengl.org/sdk/docs/man/html/smoothstep.xhtml
22 |
23 | Maf.smoothStep = function(edge0, edge1, v) {
24 | var t = Maf.clamp((v - edge0) / (edge1 - edge0), 0.0, 1.0);
25 | return t * t * (3.0 - 2.0 * t);
26 | };
27 |
28 | // http://docs.unity3d.com/ScriptReference/Mathf.html
29 | // http://www.shaderific.com/glsl-functions/
30 | // https://www.opengl.org/sdk/docs/man4/html/
31 | // https://msdn.microsoft.com/en-us/library/windows/desktop/ff471376(v=vs.85).aspx
32 | // http://moutjs.com/docs/v0.11/math.html#map
33 | // https://code.google.com/p/kuda/source/browse/public/js/hemi/utils/mathUtils.js?r=8d581c02651077c4ac3f5fc4725323210b6b13cc
34 |
35 | // Converts from degrees to radians.
36 | Maf.deg2Rad = function(degrees) {
37 | return (degrees * Math.PI) / 180;
38 | };
39 |
40 | Maf.toRadians = Maf.deg2Rad;
41 |
42 | // Converts from radians to degrees.
43 | Maf.rad2Deg = function(radians) {
44 | return (radians * 180) / Math.PI;
45 | };
46 |
47 | Maf.toDegrees = Maf.rad2Deg;
48 |
49 | Maf.clamp01 = function(v) {
50 | return Maf.clamp(v, 0, 1);
51 | };
52 |
53 | // https://www.opengl.org/sdk/docs/man/html/mix.xhtml
54 |
55 | Maf.mix = function(x, y, a) {
56 | if (a <= 0) return x;
57 | if (a >= 1) return y;
58 | return x + a * (y - x);
59 | };
60 |
61 | Maf.lerp = Maf.mix;
62 |
63 | Maf.inverseMix = function(a, b, v) {
64 | return (v - a) / (b - a);
65 | };
66 |
67 | Maf.inverseLerp = Maf.inverseMix;
68 |
69 | Maf.mixUnclamped = function(x, y, a) {
70 | if (a <= 0) return x;
71 | if (a >= 1) return y;
72 | return x + a * (y - x);
73 | };
74 |
75 | Maf.lerpUnclamped = Maf.mixUnclamped;
76 |
77 | // https://www.opengl.org/sdk/docs/man/html/fract.xhtml
78 |
79 | Maf.fract = function(v) {
80 | return v - Math.floor(v);
81 | };
82 |
83 | Maf.frac = Maf.fract;
84 |
85 | // http://stackoverflow.com/questions/4965301/finding-if-a-number-is-a-power-of-2
86 |
87 | Maf.isPowerOfTwo = function(v) {
88 | return ((v - 1) & v) == 0;
89 | };
90 |
91 | // https://bocoup.com/weblog/find-the-closest-power-of-2-with-javascript
92 |
93 | Maf.closestPowerOfTwo = function(v) {
94 | return Math.pow(2, Math.round(Math.log(v) / Math.log(2)));
95 | };
96 |
97 | Maf.nextPowerOfTwo = function(v) {
98 | return Math.pow(2, Math.ceil(Math.log(v) / Math.log(2)));
99 | };
100 |
101 | // http://stackoverflow.com/questions/1878907/the-smallest-difference-between-2-angles
102 |
103 | //function mod(a, n) { return a - Math.floor(a/n) * n; }
104 | Maf.mod = function(a, n) {
105 | return ((a % n) + n) % n;
106 | };
107 |
108 | Maf.deltaAngle = function(a, b) {
109 | var d = Maf.mod(b - a, 360);
110 | if (d > 180) d = Math.abs(d - 360);
111 | return d;
112 | };
113 |
114 | Maf.deltaAngleDeg = Maf.deltaAngle;
115 |
116 | Maf.deltaAngleRad = function(a, b) {
117 | return Maf.toRadians(Maf.deltaAngle(Maf.toDegrees(a), Maf.toDegrees(b)));
118 | };
119 |
120 | Maf.lerpAngle = function(a, b, t) {
121 | var angle = Maf.deltaAngle(a, b);
122 | return Maf.mod(a + Maf.lerp(0, angle, t), 360);
123 | };
124 |
125 | Maf.lerpAngleDeg = Maf.lerpAngle;
126 |
127 | Maf.lerpAngleRad = function(a, b, t) {
128 | return Maf.toRadians(Maf.lerpAngleDeg(Maf.toDegrees(a), Maf.toDegrees(b), t));
129 | };
130 |
131 | // http://gamedev.stackexchange.com/questions/74324/gamma-space-and-linear-space-with-shader
132 |
133 | Maf.gammaToLinearSpace = function(v) {
134 | return Math.pow(v, 2.2);
135 | };
136 |
137 | Maf.linearToGammaSpace = function(v) {
138 | return Math.pow(v, 1 / 2.2);
139 | };
140 |
141 | Maf.map = function(from1, to1, from2, to2, v) {
142 | return from2 + ((v - from1) * (to2 - from2)) / (to1 - from1);
143 | };
144 |
145 | Maf.scale = Maf.map;
146 |
147 | // http://www.iquilezles.org/www/articles/functions/functions.htm
148 |
149 | Maf.almostIdentity = function(x, m, n) {
150 | if (x > m) return x;
151 |
152 | var a = 2 * n - m;
153 | var b = 2 * m - 3 * n;
154 | var t = x / m;
155 |
156 | return (a * t + b) * t * t + n;
157 | };
158 |
159 | Maf.impulse = function(k, x) {
160 | var h = k * x;
161 | return h * Math.exp(1 - h);
162 | };
163 |
164 | Maf.cubicPulse = function(c, w, x) {
165 | x = Math.abs(x - c);
166 | if (x > w) return 0;
167 | x /= w;
168 | return 1 - x * x * (3 - 2 * x);
169 | };
170 |
171 | Maf.expStep = function(x, k, n) {
172 | return Math.exp(-k * Math.pow(x, n));
173 | };
174 |
175 | Maf.parabola = function(x, k) {
176 | return Math.pow(4 * x * (1 - x), k);
177 | };
178 |
179 | Maf.powerCurve = function(x, a, b) {
180 | var k = Math.pow(a + b, a + b) / (Math.pow(a, a) * Math.pow(b, b));
181 | return k * Math.pow(x, a) * Math.pow(1 - x, b);
182 | };
183 |
184 | // http://iquilezles.org/www/articles/smin/smin.htm ?
185 |
186 | Maf.latLonToCartesian = function(lat, lon) {
187 | lon += 180;
188 | lat = Maf.clamp(lat, -85, 85);
189 | var phi = Maf.toRadians(90 - lat);
190 | var theta = Maf.toRadians(180 - lon);
191 | var x = Math.sin(phi) * Math.cos(theta);
192 | var y = Math.cos(phi);
193 | var z = Math.sin(phi) * Math.sin(theta);
194 |
195 | return { x: x, y: y, z: z };
196 | };
197 |
198 | Maf.cartesianToLatLon = function(x, y, z) {
199 | var n = Math.sqrt(x * x + y * y + z * z);
200 | return { lat: Math.asin(z / n), lon: Math.atan2(y, x) };
201 | };
202 |
203 | Maf.randomInRange = function(min, max) {
204 | return min + Math.random() * (max - min);
205 | };
206 |
207 | Maf.norm = function(v, minVal, maxVal) {
208 | return (v - minVal) / (maxVal - minVal);
209 | };
210 |
211 | Maf.hash = function(n) {
212 | return Maf.fract((1.0 + Math.cos(n)) * 415.92653);
213 | };
214 |
215 | Maf.noise2d = function(x, y) {
216 | var xhash = Maf.hash(x * 37.0);
217 | var yhash = Maf.hash(y * 57.0);
218 | return Maf.fract(xhash + yhash);
219 | };
220 |
221 | // http://iquilezles.org/www/articles/smin/smin.htm
222 |
223 | Maf.smoothMin = function(a, b, k) {
224 | var res = Math.exp(-k * a) + Math.exp(-k * b);
225 | return -Math.log(res) / k;
226 | };
227 |
228 | Maf.smoothMax = function(a, b, k) {
229 | return Math.log(Math.exp(a) + Math.exp(b)) / k;
230 | };
231 |
232 | Maf.almost = function(a, b) {
233 | return Math.abs(a - b) < 0.0001;
234 | };
235 |
236 | export { Maf };
237 |
--------------------------------------------------------------------------------
/modules/paper.js:
--------------------------------------------------------------------------------
1 | console.log("PAPER WORKER");
2 |
3 | let papers;
4 |
5 | onmessage = function(e) {
6 | console.log("Message received from main script", e.data);
7 | if (e.data.fn) {
8 | const f = eval(JSON.parse(e.data.fn));
9 | f.render();
10 | debugger;
11 | }
12 | /*var workerResult = 'Result: ' + (e.data[0] * e.data[1]);
13 | console.log('Posting message back to main script');
14 | postMessage(workerResult);*/
15 | };
16 |
--------------------------------------------------------------------------------
/modules/paper1.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | var colorPalette = ["#ebe9e4", "#f56f34", "#ee4537", "#372c2c"];
8 |
9 | const line = "#c5c5c5";
10 |
11 | this.drawRect(0, 0, w, h, "#fff", "#000");
12 |
13 | function d(x, y, r, c) {
14 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
15 | this.drawCircle(x, y, r, colorPalette[paletteIndex], {
16 | specularColor: "#fff"
17 | });
18 | this.colorCtx.beginPath();
19 | this.colorCtx.lineWidth = 0.5;
20 | this.colorCtx.strokeStyle = 0xc5c5c5;
21 | this.colorCtx.arc(x, y, r, 0, 2 * Math.PI);
22 | this.colorCtx.stroke();
23 | }
24 |
25 | const _d = d.bind(this);
26 | const f = w / 64;
27 |
28 | for (var i = 0; i < f; i++) {
29 | for (var j = 0; j < f; j++) {
30 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
31 | var x = i * (w / f),
32 | y = j * (h / f),
33 | r = (0.5 * w) / f,
34 | m = Math.floor(Math.random() * 3);
35 | switch (m) {
36 | case 0:
37 | _d(x + (0.5 * w) / f, y + (0.5 * h) / f, r);
38 | break;
39 | case 1:
40 | var rr = r / 2;
41 | for (var ii = 0; ii < 2; ii++) {
42 | for (var jj = 0; jj < 2; jj++) {
43 | _d(x + rr + 2 * ii * rr, y + rr + jj * 2 * rr, rr);
44 | }
45 | }
46 | break;
47 | case 2:
48 | var rr = r / 3;
49 | for (var ii = 0; ii < 3; ii++) {
50 | for (var jj = 0; jj < 3; jj++) {
51 | var paletteIndex = Math.floor(
52 | Math.random() * colorPalette.length
53 | );
54 | _d(x + rr + 2 * ii * rr, y + rr + jj * 2 * rr, rr);
55 | }
56 | }
57 | break;
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
64 | export { Paper };
65 |
--------------------------------------------------------------------------------
/modules/paper10.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | const opts1 = { specularColor: "#000" };
8 |
9 | const colorPalette1 = [
10 | "#d88559",
11 | "#dda8c4",
12 | "#c1454d",
13 | "#8cc6dc",
14 | "#ead562",
15 | "#fefff8"
16 | ];
17 |
18 | const colorPalette2 = [
19 | "#f97a4d",
20 | "#4199bd",
21 | "#455b69",
22 | "#c33a4e",
23 | "#eaeaec",
24 | "#e2e5de"
25 | ];
26 |
27 | const palettes = [colorPalette1, colorPalette2];
28 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
29 |
30 | const width = 32;
31 | const height = 32;
32 |
33 | this.drawRect(0, 0, w, h, "#fff", opts1);
34 | for (let y = -1; y < h / height + 1; y++) {
35 | for (let x = -1; x < w / width + 1; x++) {
36 | const path1 = new Path2D();
37 | const path2 = new Path2D();
38 | if ((x + y) % 2) {
39 | path1.moveTo(x * width, y * height);
40 | path1.lineTo((x + 1) * width, y * height);
41 | path1.lineTo(x * width, (y + 1) * height);
42 | path2.moveTo((x + 1) * width, y * height);
43 | path2.lineTo((x + 1) * width, (y + 1) * height);
44 | path2.lineTo(x * width, (y + 1) * height);
45 | } else {
46 | path1.moveTo(x * width, y * height);
47 | path1.lineTo((x + 1) * width, y * height);
48 | path1.lineTo((x + 1) * width, (y + 1) * height);
49 | path2.moveTo(x * width, y * height);
50 | path2.lineTo(x * width, (y + 1) * height);
51 | path2.lineTo((x + 1) * width, (y + 1) * height);
52 | }
53 |
54 | const id = ~~(Math.random() * colorPalette.length);
55 | this.colorCtx.fillStyle = colorPalette[id];
56 | this.colorCtx.fill(path1);
57 | let id2 = id;
58 | while (id2 === id) {
59 | id2 = ~~(Math.random() * colorPalette.length);
60 | }
61 | this.colorCtx.fillStyle = colorPalette[id2];
62 | this.colorCtx.fill(path2);
63 |
64 | let c = ~~(Math.random() * 255);
65 | this.roughnessCtx.fillStyle = `rgb(${c},${c},${c})`;
66 | this.roughnessCtx.fill(path1);
67 | c = ~~(Math.random() * 255);
68 | this.roughnessCtx.fillStyle = `rgb(${c},${c},${c})`;
69 | this.roughnessCtx.fill(path2);
70 | }
71 | }
72 | }
73 | }
74 |
75 | export { Paper };
76 |
--------------------------------------------------------------------------------
/modules/paper11.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const colorRim = "#4f919b";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = ["#d24b58", "#c34e55", "#cbe2ee", "#ecf0f3"];
13 |
14 | var colorPalette2 = ["#f6f6f6", "#ff9b00", "#ff3200", "#02827a"];
15 |
16 | const palettes = [colorPalette1, colorPalette2];
17 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
18 |
19 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
20 |
21 | this.drawRect(0, 0, w, h, "#340a2d", "#000");
22 |
23 | const width = 4 * 48;
24 | const height = 4 * 32;
25 |
26 | const path = new Path2D();
27 | path.moveTo(0, 0.5 * height);
28 | path.lineTo(0.25 * width, 0);
29 | path.lineTo(0.5 * width, 0);
30 | path.lineTo(0.75 * width, 0.5 * height);
31 | path.lineTo(0.5 * width, height);
32 | path.lineTo(0.25 * width, height);
33 | path.lineTo(0, 0.5 * height);
34 |
35 | function draw(x, y) {
36 | this.colorCtx.save();
37 | this.colorCtx.translate(x * width, y * height);
38 | this.colorCtx.fillStyle = colorRim;
39 | this.colorCtx.fill(path);
40 | this.colorCtx.restore();
41 | this.colorCtx.save();
42 | this.colorCtx.translate((x + 1) * width, (y + 1) * height);
43 | this.colorCtx.fillStyle = colorRim;
44 | this.colorCtx.fill(path);
45 | this.colorCtx.restore();
46 | const colors = colorPalette.sort((a, b) =>
47 | Math.random() > 0.5 ? 1 : -1
48 | );
49 | let inc = 0.5 * 0.25;
50 | let scale = 0.75;
51 | const aspect = width / height;
52 | for (let c of colors) {
53 | this.colorCtx.save();
54 | this.colorCtx.translate(
55 | (x + inc) * width,
56 | (y + 0.95 * inc * aspect) * height
57 | );
58 | this.colorCtx.scale(scale, scale);
59 | this.colorCtx.fillStyle = c;
60 | this.colorCtx.fill(path);
61 | this.colorCtx.restore();
62 | inc += 0.75 * 0.125 * scale;
63 | scale *= 0.75;
64 | }
65 | this.roughnessCtx.save();
66 | this.roughnessCtx.translate(x * width, y * height);
67 | this.roughnessCtx.fillStyle = specColorRim;
68 | this.roughnessCtx.fill(path);
69 | this.roughnessCtx.restore();
70 | this.roughnessCtx.save();
71 | this.roughnessCtx.translate((x + 1) * width, (y + 1) * height);
72 | this.roughnessCtx.fillStyle = specColorRim;
73 | this.roughnessCtx.fill(path);
74 | this.roughnessCtx.restore();
75 | const colors2 = specPalette.sort((a, b) =>
76 | Math.random() > 0.5 ? 1 : -1
77 | );
78 | inc = 0.5 * 0.25;
79 | scale = 0.75;
80 | for (let c of colors2) {
81 | this.roughnessCtx.save();
82 | this.roughnessCtx.translate(
83 | (x + inc) * width,
84 | (y + 0.95 * inc * aspect) * height
85 | );
86 | this.roughnessCtx.scale(scale, scale);
87 | this.roughnessCtx.fillStyle = c;
88 | this.roughnessCtx.fill(path);
89 | this.roughnessCtx.restore();
90 | inc += 0.75 * 0.125 * scale;
91 | scale *= 0.75;
92 | }
93 | }
94 |
95 | const _d = draw.bind(this);
96 |
97 | let id;
98 | for (let y = -1; y < h / height; y++) {
99 | for (let x = -1; x < w / width; x++) {
100 | _d(x, y);
101 | _d(x + 0.5, y + 0.5);
102 | }
103 | }
104 | }
105 | }
106 | export { Paper };
107 |
--------------------------------------------------------------------------------
/modules/paper12.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const colorRim = "#4f919b";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#e4943b",
14 | "#f1d244",
15 | "#e0cce9",
16 | "#97ccf7",
17 | "#e0e5fa",
18 | "#e24377",
19 | "#b7bb4b",
20 | "#e15c4b",
21 | "#57ab8d"
22 | ];
23 |
24 | var colorPalette2 = ["#f6f6f6", "#ff9b00", "#ff3200", "#02827a"];
25 |
26 | const palettes = [colorPalette1];
27 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
28 |
29 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
30 |
31 | this.drawRect(0, 0, w, h, "#340a2d", "#000");
32 |
33 | const width = 32;
34 | const height = 32;
35 | const p = 0.5;
36 |
37 | const path1 = new Path2D();
38 | path1.moveTo(0.5 * width, 0 + p);
39 | path1.lineTo(width - p, height - p);
40 | path1.lineTo(0 + p, height - p);
41 | path1.lineTo(0.5 * width, 0 + p);
42 |
43 | const path2 = new Path2D();
44 | path2.moveTo(0.5 * width, height - p);
45 | path2.lineTo(width - p, 0 + p);
46 | path2.lineTo(0 + p, 0 + p);
47 | path2.lineTo(0.5 * width, height - p);
48 |
49 | function draw(x, y) {
50 | this.colorCtx.save();
51 | this.colorCtx.translate(x * width, y * height);
52 | this.colorCtx.fillStyle =
53 | colorPalette[~~(Math.random() * colorPalette.length)];
54 | this.colorCtx.fill(path1);
55 | this.colorCtx.restore();
56 |
57 | this.colorCtx.save();
58 | this.colorCtx.translate((x + 0.5) * width, y * height);
59 | this.colorCtx.fillStyle =
60 | colorPalette[~~(Math.random() * colorPalette.length)];
61 | this.colorCtx.fill(path2);
62 | this.colorCtx.restore();
63 |
64 | this.roughnessCtx.save();
65 | this.roughnessCtx.translate(x * width, y * height);
66 | this.roughnessCtx.fillStyle =
67 | specPalette[~~(Math.random() * specPalette.length)];
68 | this.roughnessCtx.fill(path1);
69 | this.roughnessCtx.restore();
70 |
71 | this.roughnessCtx.save();
72 | this.roughnessCtx.translate((x + 0.5) * width, y * height);
73 | this.roughnessCtx.fillStyle =
74 | specPalette[~~(Math.random() * specPalette.length)];
75 | this.roughnessCtx.fill(path2);
76 | this.roughnessCtx.restore();
77 | }
78 |
79 | const _d = draw.bind(this);
80 |
81 | let id;
82 | for (let y = -1; y < h / height; y++) {
83 | for (let x = -1; x < w / width; x++) {
84 | _d(x + (y % 2 ? 0.5 : 0), y);
85 | }
86 | }
87 | }
88 | }
89 | export { Paper };
90 |
--------------------------------------------------------------------------------
/modules/paper13.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#4a4041";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#eed33d",
14 | "#db4543",
15 | "#7cb2c1",
16 | "#6a5241",
17 | "#e07f34",
18 | "#84858a",
19 | "#e8d2be",
20 | "#dfe5cd",
21 | "#e7cc36"
22 | ];
23 |
24 | var colorPalette2 = ["#f6f6f6", "#ff9b00", "#ff3200", "#02827a"];
25 |
26 | const palettes = [colorPalette1];
27 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
28 |
29 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
30 |
31 | this.colorCtx.strokeStyle = "#fff";
32 | this.roughnessCtx.strokeStyle = "#fff";
33 |
34 | this.drawRect(0, 0, w, h, backgroundColor, "#000");
35 |
36 | const width = 32;
37 | const height = 32;
38 | const p = 4;
39 |
40 | const path1 = new Path2D();
41 | path1.moveTo(0.5 * width, 0 + p);
42 | path1.lineTo(width - p, height - p);
43 | path1.lineTo(0 + p, height - p);
44 | path1.lineTo(0.5 * width, 0 + p);
45 |
46 | const path2 = new Path2D();
47 | path2.moveTo(0.5 * width, height - p);
48 | path2.lineTo(width - p, 0 + p);
49 | path2.lineTo(0 + p, 0 + p);
50 | path2.lineTo(0.5 * width, height - p);
51 |
52 | function draw(x, y) {
53 | this.colorCtx.save();
54 | this.colorCtx.translate(x * width, y * height + 2 * p);
55 | this.colorCtx.fillStyle =
56 | colorPalette[~~(Math.random() * colorPalette.length)];
57 | this.colorCtx.fill(path1);
58 | this.colorCtx.stroke(path1);
59 | this.colorCtx.restore();
60 |
61 | this.colorCtx.save();
62 | this.colorCtx.translate((x + 0.5) * width, y * height);
63 | this.colorCtx.fillStyle =
64 | colorPalette[~~(Math.random() * colorPalette.length)];
65 | this.colorCtx.fill(path2);
66 | this.colorCtx.stroke(path2);
67 | this.colorCtx.restore();
68 |
69 | this.roughnessCtx.save();
70 | this.roughnessCtx.translate(x * width, y * height + 2 * p);
71 | this.roughnessCtx.fillStyle =
72 | specPalette[~~(Math.random() * specPalette.length)];
73 | this.roughnessCtx.fill(path1);
74 | this.roughnessCtx.stroke(path1);
75 | this.roughnessCtx.restore();
76 |
77 | this.roughnessCtx.save();
78 | this.roughnessCtx.translate((x + 0.5) * width, y * height);
79 | this.roughnessCtx.fillStyle =
80 | specPalette[~~(Math.random() * specPalette.length)];
81 | this.roughnessCtx.fill(path2);
82 | this.roughnessCtx.stroke(path2);
83 | this.roughnessCtx.restore();
84 | }
85 |
86 | const _d = draw.bind(this);
87 |
88 | let id;
89 | for (let y = -1; y < h / height; y++) {
90 | for (let x = -1; x < w / width; x++) {
91 | _d(x + (y % 2 ? 0.5 : 0), y);
92 | }
93 | }
94 | }
95 | }
96 | export { Paper };
97 |
--------------------------------------------------------------------------------
/modules/paper14.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#efe8cc";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#a39f8a",
14 | "#5d697a",
15 | "#c0cb3c",
16 | "#fea43b",
17 | "#90d6cf",
18 | "#efe8cc"
19 | ];
20 |
21 | const palettes = [colorPalette1];
22 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
23 |
24 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
25 |
26 | this.roughnessCtx.strokeStyle = "#fff";
27 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
28 |
29 | const width = 32;
30 | const height = 32;
31 | const p = 4;
32 |
33 | const path1 = new Path2D();
34 | path1.moveTo(-0.5 * width, -0.5 * height);
35 | path1.lineTo(0.5 * width, -0.5 * height);
36 | path1.arcTo(0.5 * width, 0.5 * height, -0.5 * width, 0.5 * height, width);
37 | path1.lineTo(-0.5 * width, -0.5 * height);
38 |
39 | function draw(x, y) {
40 | const a = (~~(Math.random() * 4) * Math.PI) / 2;
41 | this.colorCtx.save();
42 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
43 | this.colorCtx.rotate(a);
44 | this.colorCtx.fillStyle =
45 | colorPalette[~~(Math.random() * colorPalette.length)];
46 | this.colorCtx.fill(path1);
47 | this.colorCtx.restore();
48 |
49 | this.roughnessCtx.save();
50 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
51 | this.roughnessCtx.rotate(a);
52 | this.roughnessCtx.fillStyle =
53 | specPalette[~~(Math.random() * specPalette.length)];
54 | this.roughnessCtx.fill(path1);
55 | this.roughnessCtx.stroke(path1);
56 | this.roughnessCtx.restore();
57 | }
58 |
59 | const _d = draw.bind(this);
60 |
61 | let id;
62 | for (let y = -1; y < h / height; y++) {
63 | for (let x = -1; x < w / width; x++) {
64 | _d(x, y);
65 | }
66 | }
67 | }
68 | }
69 | export { Paper };
70 |
--------------------------------------------------------------------------------
/modules/paper15.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#efe8cc";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#eed33d",
14 | "#db4543",
15 | "#7cb2c1",
16 | "#6a5241",
17 | "#e07f34",
18 | "#84858a",
19 | "#e8d2be",
20 | "#dfe5cd",
21 | "#e7cc36"
22 | ];
23 |
24 | const palettes = [colorPalette1];
25 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
26 |
27 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
28 |
29 | this.roughnessCtx.strokeStyle = "#fff";
30 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
31 |
32 | const width = 32;
33 | const height = 32;
34 | const p = 4;
35 |
36 | const path1 = new Path2D();
37 | path1.moveTo(-0.5 * width, -0.5 * height);
38 | path1.lineTo(0.5 * width, -0.5 * height);
39 | path1.arcTo(0.5 * width, 0.5 * height, -0.5 * width, 0.5 * height, width);
40 | path1.lineTo(-0.5 * width, -0.5 * height);
41 |
42 | function draw(x, y) {
43 | const a = ((x % 2) * Math.PI) / 2 + (y % 2) * Math.PI;
44 | this.colorCtx.save();
45 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
46 | this.colorCtx.rotate(a);
47 | this.colorCtx.fillStyle =
48 | colorPalette[~~(Math.random() * colorPalette.length)];
49 | this.colorCtx.fill(path1);
50 | this.colorCtx.restore();
51 |
52 | this.roughnessCtx.save();
53 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
54 | this.roughnessCtx.rotate(a);
55 | this.roughnessCtx.fillStyle =
56 | specPalette[~~(Math.random() * specPalette.length)];
57 | this.roughnessCtx.fill(path1);
58 | this.roughnessCtx.stroke(path1);
59 | this.roughnessCtx.restore();
60 | }
61 |
62 | const _d = draw.bind(this);
63 |
64 | let id;
65 | for (let y = -1; y < h / height; y++) {
66 | for (let x = -1; x < w / width; x++) {
67 | _d(x, y);
68 | }
69 | }
70 | }
71 | }
72 | export { Paper };
73 |
--------------------------------------------------------------------------------
/modules/paper16.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | function getWeightedRandom(inputs) {
4 | const total = inputs.reduce((ac, v) => (ac += v), 0);
5 | return function() {
6 | const r = Math.random() * total;
7 | let ac = 0;
8 | let c = 0;
9 | for (const v of inputs) {
10 | const n = ac + v;
11 | if (r > +ac && r < n) {
12 | return c;
13 | }
14 | c++;
15 | ac = n;
16 | }
17 | };
18 | }
19 |
20 | const rnd = getWeightedRandom([1, 2, 1, 8]);
21 |
22 | class Paper extends WrappingPaper {
23 | constructor(w, h) {
24 | super(w, h);
25 |
26 | //object that defines the specular level for the specular image
27 | const opts1 = { specularColor: "#fff" };
28 |
29 | const backgroundColor = "#bbe6fc";
30 | const specColorRim = "#ddd";
31 | const colorPalette1 = [
32 | "#fef4b5",
33 | "#ffee5a",
34 | "#68cafb",
35 | "#f6ba94",
36 | "#f18547"
37 | ];
38 |
39 | const palettes = [colorPalette1];
40 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
41 |
42 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
43 |
44 | this.roughnessCtx.strokeStyle = "#fff";
45 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
46 |
47 | const width = 32;
48 | const height = 32;
49 | const p = 4;
50 |
51 | const path1 = new Path2D();
52 | path1.moveTo(-0.5 * width, -0.5 * height);
53 | path1.lineTo(0.5 * width, -0.5 * height);
54 | path1.arcTo(0.5 * width, 0.5 * height, -0.5 * width, 0.5 * height, width);
55 | path1.lineTo(-0.5 * width, -0.5 * height);
56 |
57 | function draw(x, y) {
58 | const type = rnd();
59 | switch (type) {
60 | case 0: // empty
61 | break;
62 | case 1: // big circle
63 | this.colorCtx.save();
64 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
65 | this.colorCtx.fillStyle =
66 | colorPalette[~~(Math.random() * colorPalette.length)];
67 | this.colorCtx.beginPath();
68 | this.colorCtx.arc(0, 0, 0.5 * width, 0, 2 * Math.PI);
69 | this.colorCtx.fill();
70 | this.colorCtx.restore();
71 |
72 | this.roughnessCtx.save();
73 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
74 | this.roughnessCtx.fillStyle =
75 | specPalette[~~(Math.random() * specPalette.length)];
76 | this.roughnessCtx.beginPath();
77 | this.roughnessCtx.arc(0, 0, 0.5 * width, 0, 2 * Math.PI);
78 | this.roughnessCtx.fill();
79 | this.roughnessCtx.restore();
80 | break;
81 | case 2: // small circle
82 | this.colorCtx.save();
83 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
84 | this.colorCtx.fillStyle =
85 | colorPalette[~~(Math.random() * colorPalette.length)];
86 | this.colorCtx.beginPath();
87 | this.colorCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
88 | this.colorCtx.fill();
89 | this.colorCtx.restore();
90 |
91 | this.roughnessCtx.save();
92 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
93 | this.roughnessCtx.fillStyle =
94 | specPalette[~~(Math.random() * specPalette.length)];
95 | this.roughnessCtx.beginPath();
96 | this.roughnessCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
97 | this.roughnessCtx.fill();
98 | this.roughnessCtx.restore();
99 | break;
100 | case 3: // quarter
101 | const a = 0.5 * ~~(Math.random() * 4) * Math.PI;
102 | this.colorCtx.save();
103 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
104 | this.colorCtx.rotate(a);
105 | this.colorCtx.fillStyle =
106 | colorPalette[~~(Math.random() * colorPalette.length)];
107 | this.colorCtx.fill(path1);
108 | this.colorCtx.restore();
109 |
110 | this.roughnessCtx.save();
111 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
112 | this.roughnessCtx.rotate(a);
113 | this.roughnessCtx.fillStyle =
114 | specPalette[~~(Math.random() * specPalette.length)];
115 | this.roughnessCtx.fill(path1);
116 | this.roughnessCtx.restore();
117 | break;
118 | }
119 | }
120 |
121 | const _d = draw.bind(this);
122 |
123 | let id;
124 | for (let y = -1; y < h / height; y++) {
125 | for (let x = -1; x < w / width; x++) {
126 | _d(x, y);
127 | }
128 | }
129 | }
130 | }
131 | export { Paper };
132 |
--------------------------------------------------------------------------------
/modules/paper17.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | function getWeightedRandom(inputs) {
4 | const total = inputs.reduce((ac, v) => (ac += v), 0);
5 | return function() {
6 | const r = Math.random() * total;
7 | let ac = 0;
8 | let c = 0;
9 | for (const v of inputs) {
10 | const n = ac + v;
11 | if (r > +ac && r < n) {
12 | return c;
13 | }
14 | c++;
15 | ac = n;
16 | }
17 | };
18 | }
19 |
20 | const rnd = getWeightedRandom([1, 2, 1, 8]);
21 |
22 | class Paper extends WrappingPaper {
23 | constructor(w, h) {
24 | super(w, h);
25 |
26 | //object that defines the specular level for the specular image
27 | const opts1 = { specularColor: "#fff" };
28 |
29 | const backgroundColor = "#ef6660";
30 | const specColorRim = "#ddd";
31 | const colorPalette1 = [
32 | "#ef6660",
33 | "#f29b9b",
34 | "#68cafb",
35 | "#bbe6fc",
36 | "#fef4b5",
37 | "#ffee5a"
38 | ];
39 |
40 | const palettes = [colorPalette1];
41 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
42 |
43 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
44 |
45 | this.roughnessCtx.strokeStyle = "#fff";
46 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
47 |
48 | const width = 32;
49 | const height = 32;
50 | const p = 4;
51 |
52 | const path1 = new Path2D();
53 | path1.moveTo(-0.5 * width, -0.5 * height);
54 | path1.lineTo(0.5 * width, -0.5 * height);
55 | path1.arcTo(0.5 * width, 0.5 * height, -0.5 * width, 0.5 * height, width);
56 | path1.lineTo(-0.5 * width, -0.5 * height);
57 |
58 | function draw(x, y) {
59 | const type = rnd();
60 | switch (type) {
61 | case 0: // empty
62 | break;
63 | case 1: // big circle
64 | this.colorCtx.save();
65 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
66 | this.colorCtx.fillStyle =
67 | colorPalette[~~(Math.random() * colorPalette.length)];
68 | this.colorCtx.beginPath();
69 | this.colorCtx.arc(0, 0, 0.5 * width, 0, 2 * Math.PI);
70 | this.colorCtx.fill();
71 | this.colorCtx.restore();
72 |
73 | this.roughnessCtx.save();
74 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
75 | this.roughnessCtx.fillStyle =
76 | specPalette[~~(Math.random() * specPalette.length)];
77 | this.roughnessCtx.beginPath();
78 | this.roughnessCtx.arc(0, 0, 0.5 * width, 0, 2 * Math.PI);
79 | this.roughnessCtx.fill();
80 | this.roughnessCtx.restore();
81 | break;
82 | case 2: // small circle
83 | this.colorCtx.save();
84 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
85 | this.colorCtx.fillStyle =
86 | colorPalette[~~(Math.random() * colorPalette.length)];
87 | this.colorCtx.beginPath();
88 | this.colorCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
89 | this.colorCtx.fill();
90 | this.colorCtx.restore();
91 |
92 | this.roughnessCtx.save();
93 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
94 | this.roughnessCtx.fillStyle =
95 | specPalette[~~(Math.random() * specPalette.length)];
96 | this.roughnessCtx.beginPath();
97 | this.roughnessCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
98 | this.roughnessCtx.fill();
99 | this.roughnessCtx.restore();
100 | break;
101 | case 3: // quarter
102 | const a = 0.5 * ~~(Math.random() * 4) * Math.PI;
103 | this.colorCtx.save();
104 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
105 | this.colorCtx.rotate(a);
106 | this.colorCtx.fillStyle =
107 | colorPalette[~~(Math.random() * colorPalette.length)];
108 | this.colorCtx.fill(path1);
109 | this.colorCtx.restore();
110 |
111 | this.roughnessCtx.save();
112 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
113 | this.roughnessCtx.rotate(a);
114 | this.roughnessCtx.fillStyle =
115 | specPalette[~~(Math.random() * specPalette.length)];
116 | this.roughnessCtx.fill(path1);
117 | this.roughnessCtx.restore();
118 | break;
119 | }
120 | }
121 |
122 | const _d = draw.bind(this);
123 |
124 | let id;
125 | for (let y = -1; y < h / height; y++) {
126 | for (let x = -1; x < w / width; x++) {
127 | _d(x, y);
128 | }
129 | }
130 | }
131 | }
132 | export { Paper };
133 |
--------------------------------------------------------------------------------
/modules/paper18.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#bbe6fc";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#fef4b5",
14 | "#ffec5f",
15 | "#f29b9e",
16 | "#ef6660",
17 | "#6d7db8",
18 | "#162661"
19 | ];
20 |
21 | const palettes = [colorPalette1];
22 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
23 |
24 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
25 |
26 | this.roughnessCtx.strokeStyle = "#fff";
27 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
28 |
29 | const width = 32;
30 | const height = 32;
31 |
32 | function draw(x, y) {
33 | const hasDot = Math.random() > 0.75;
34 |
35 | this.colorCtx.lineWidth = 0.25 * width;
36 | this.colorCtx.save();
37 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
38 | this.colorCtx.fillStyle =
39 | colorPalette[~~(Math.random() * colorPalette.length)];
40 | this.colorCtx.fillRect(
41 | -0.5 * width,
42 | -0.5 * height,
43 | 2 * width,
44 | 2 * height
45 | );
46 | if (hasDot) {
47 | this.colorCtx.fillStyle =
48 | colorPalette[~~(Math.random() * colorPalette.length)];
49 | this.colorCtx.beginPath();
50 | this.colorCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
51 | this.colorCtx.fill();
52 | }
53 | this.colorCtx.restore();
54 |
55 | this.roughnessCtx.save();
56 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
57 | this.roughnessCtx.fillStyle =
58 | specPalette[~~(Math.random() * specPalette.length)];
59 | this.roughnessCtx.fillRect(
60 | -0.5 * width,
61 | -0.5 * height,
62 | 2 * width,
63 | 2 * height
64 | );
65 | if (hasDot) {
66 | this.roughnessCtx.fillStyle =
67 | specPalette[~~(Math.random() * colorPalette.length)];
68 | this.roughnessCtx.beginPath();
69 | this.roughnessCtx.arc(0, 0, 0.25 * width, 0, 2 * Math.PI);
70 | this.roughnessCtx.fill();
71 | }
72 | this.roughnessCtx.restore();
73 | }
74 |
75 | const _d = draw.bind(this);
76 |
77 | let id;
78 | for (let y = -1; y < h / height; y++) {
79 | for (let x = -1; x < w / width; x++) {
80 | _d(x, y);
81 | }
82 | }
83 | }
84 | }
85 | export { Paper };
86 |
--------------------------------------------------------------------------------
/modules/paper19.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#bbe6fc";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#fef4b5",
14 | "#ffec5f",
15 | "#f29b9e",
16 | "#ef6660",
17 | "#6d7db8",
18 | "#162661"
19 | ];
20 |
21 | const palettes = [colorPalette1];
22 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
23 |
24 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
25 |
26 | this.roughnessCtx.strokeStyle = "#fff";
27 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
28 |
29 | const width = 32;
30 | const height = 32;
31 |
32 | function draw(x, y) {
33 | const a = Math.random() * 2 * Math.PI;
34 |
35 | this.colorCtx.lineWidth = 0.25 * width;
36 | this.colorCtx.save();
37 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
38 | this.colorCtx.rotate(a);
39 | this.colorCtx.fillStyle =
40 | colorPalette[~~(Math.random() * colorPalette.length)];
41 | this.colorCtx.fillRect(
42 | -0.25 * width,
43 | -0.25 * height,
44 | 0.5 * width,
45 | 0.5 * height
46 | );
47 | this.colorCtx.restore();
48 |
49 | this.roughnessCtx.lineWidth = 0.25 * width;
50 | this.roughnessCtx.save();
51 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
52 | this.roughnessCtx.rotate(a);
53 | this.roughnessCtx.fillStyle =
54 | specPalette[~~(Math.random() * specPalette.length)];
55 | this.roughnessCtx.fillRect(
56 | -0.3 * width,
57 | -0.3 * height,
58 | 0.6 * width,
59 | 0.6 * height
60 | );
61 | this.roughnessCtx.restore();
62 | }
63 |
64 | const _d = draw.bind(this);
65 |
66 | let id;
67 | for (let y = -1; y < h / height; y++) {
68 | for (let x = -1; x < w / width; x++) {
69 | _d(x, y);
70 | }
71 | }
72 | }
73 | }
74 | export { Paper };
75 |
--------------------------------------------------------------------------------
/modules/paper2.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | const colorPalette = [
8 | "#f0f0f0",
9 | "#ff8b00",
10 | "#ff2b00",
11 | "#d90a00",
12 | "#02756e",
13 | "#2c0826",
14 | "#2d0826"
15 | ];
16 |
17 | const line = "#c5c5c5";
18 | const f = w / 32;
19 |
20 | this.drawRect(0, 0, w, h, "#fff", "#000");
21 |
22 | for (var i = 0; i < 8; i++) {
23 | for (var j = 0; j < 8; j++) {
24 | var x = i * (w / 8),
25 | y = j * (h / 8),
26 | rr = (0.5 * w) / 8;
27 |
28 | x += rr;
29 | y += rr;
30 | var r = Math.random() * rr;
31 | if (r < f) r = f;
32 | //while (r > 0) {
33 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
34 | this.drawCircle(x, y, r, colorPalette[paletteIndex], {
35 | specularColor: "#fff"
36 | });
37 | //r -= 2 * f + Math.random() * 5 * f;
38 | //}
39 | }
40 | }
41 | }
42 | }
43 |
44 | export { Paper };
45 |
--------------------------------------------------------------------------------
/modules/paper20.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | const backgroundColor = "#bbe6fc";
11 | const specColorRim = "#ddd";
12 | const colorPalette1 = [
13 | "#fef4b5",
14 | "#ffec5f",
15 | "#f29b9e",
16 | "#ef6660",
17 | "#6d7db8",
18 | "#162661"
19 | ];
20 |
21 | const palettes = [colorPalette1];
22 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
23 |
24 | const specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
25 |
26 | this.roughnessCtx.strokeStyle = "#fff";
27 | this.drawRect(0, 0, w, h, backgroundColor, backgroundColor);
28 |
29 | const width = 64;
30 | const height = 64;
31 |
32 | function draw(x, y) {
33 | const count = ~~(Math.random() * 2);
34 | this.colorCtx.save();
35 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
36 | const bkg = colorPalette[~~(Math.random() * colorPalette.length)];
37 | this.colorCtx.fillStyle = bkg;
38 | this.colorCtx.fillRect(-0.5 * width, -0.5 * height, width, height);
39 | let c;
40 | do {
41 | c = colorPalette[~~(Math.random() * colorPalette.length)];
42 | } while (c === bkg);
43 | this.colorCtx.strokeStyle = c;
44 | this.colorCtx.fillStyle = c;
45 | this.colorCtx.lineWidth = width / 3;
46 | if (count == 0) {
47 | this.colorCtx.beginPath();
48 | this.colorCtx.arc(
49 | -0.5 * width,
50 | -0.5 * height,
51 | 0.5 * width,
52 | 0,
53 | Math.PI / 2
54 | );
55 | this.colorCtx.stroke();
56 | this.colorCtx.rotate(Math.PI);
57 | this.colorCtx.beginPath();
58 | this.colorCtx.arc(
59 | -0.5 * width,
60 | -0.5 * height,
61 | 0.5 * width,
62 | 0,
63 | Math.PI / 2
64 | );
65 | this.colorCtx.stroke();
66 | }
67 | if (count == 1) {
68 | for (let a = 0; a < 4; a++) {
69 | this.colorCtx.save();
70 | this.colorCtx.rotate((a * Math.PI) / 2);
71 | this.colorCtx.beginPath();
72 | this.colorCtx.arc(
73 | -0.5 * width,
74 | -0.5 * height,
75 | 0.5 * width,
76 | 0,
77 | Math.PI / 2
78 | );
79 | this.colorCtx.stroke();
80 | this.colorCtx.fillRect(
81 | -0.1 * width,
82 | -0.1 * height,
83 | 0.2 * width,
84 | 0.2 * height
85 | );
86 | this.colorCtx.restore();
87 | }
88 | }
89 | this.colorCtx.restore();
90 |
91 | this.roughnessCtx.save();
92 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
93 | this.roughnessCtx.fillStyle =
94 | specPalette[~~(Math.random() * specPalette.length)];
95 | this.roughnessCtx.fillRect(-0.5 * width, -0.5 * height, width, height);
96 | this.roughnessCtx.strokeStyle =
97 | specPalette[~~(Math.random() * specPalette.length)];
98 | this.roughnessCtx.fillStyle = this.roughnessCtx.strokeStyle;
99 | this.roughnessCtx.lineWidth = width / 2.5;
100 | if (count == 0) {
101 | this.roughnessCtx.beginPath();
102 | this.roughnessCtx.arc(
103 | -0.5 * width,
104 | -0.5 * height,
105 | 0.5 * width,
106 | 0,
107 | Math.PI / 2
108 | );
109 | this.roughnessCtx.stroke();
110 | this.roughnessCtx.rotate(Math.PI);
111 | this.roughnessCtx.beginPath();
112 | this.roughnessCtx.arc(
113 | -0.5 * width,
114 | -0.5 * height,
115 | 0.5 * width,
116 | 0,
117 | Math.PI / 2
118 | );
119 | this.roughnessCtx.stroke();
120 | }
121 | if (count == 1) {
122 | for (let a = 0; a < 4; a++) {
123 | this.roughnessCtx.save();
124 | this.roughnessCtx.rotate((a * Math.PI) / 2);
125 | this.roughnessCtx.beginPath();
126 | this.roughnessCtx.arc(
127 | -0.5 * width,
128 | -0.5 * height,
129 | 0.5 * width,
130 | 0,
131 | Math.PI / 2
132 | );
133 | this.roughnessCtx.stroke();
134 | this.roughnessCtx.fillRect(
135 | -0.1 * width,
136 | -0.1 * height,
137 | 0.2 * width,
138 | 0.2 * height
139 | );
140 | this.roughnessCtx.restore();
141 | }
142 | }
143 | this.roughnessCtx.restore();
144 | }
145 |
146 | const _d = draw.bind(this);
147 |
148 | let id;
149 | for (let y = -1; y < h / height; y++) {
150 | for (let x = -1; x < w / width; x++) {
151 | _d(x, y);
152 | }
153 | }
154 | }
155 | }
156 | export { Paper };
157 |
--------------------------------------------------------------------------------
/modules/paper3.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | const colorPalette = [];
8 | colorPalette.push("#f0f0f0");
9 | colorPalette.push("#ff8b00");
10 | colorPalette.push("#ff2b00");
11 | colorPalette.push("#d90a00");
12 | colorPalette.push("#02756e");
13 | colorPalette.push("#2c0826");
14 | colorPalette.push("#2d0826");
15 |
16 | const specPalette = [];
17 | specPalette.push("#ddd");
18 | specPalette.push("#ccc");
19 | specPalette.push("#bbb");
20 | specPalette.push("#aaa");
21 | specPalette.push("#999");
22 | specPalette.push("#888");
23 | specPalette.push("#777");
24 |
25 | this.drawRect(0, 0, w, h, "#fff", "#000");
26 | const f = w / 512;
27 |
28 | for (let i = 0; i < 2000; i++) {
29 | const paletteIndex = Math.floor(Math.random() * colorPalette.length);
30 | const x = Math.random() * w;
31 | const y = Math.random() * h;
32 | const r = 2 * f + Math.random() * 10 * f;
33 | const op = { specularColor: specPalette[paletteIndex] };
34 | this.drawCircle(x, y, r, colorPalette[paletteIndex], op);
35 | this.drawCircle(x + w, y, r, colorPalette[paletteIndex], op);
36 | this.drawCircle(x - w, y, r, colorPalette[paletteIndex], op);
37 | this.drawCircle(x, y + h, r, colorPalette[paletteIndex], op);
38 | this.drawCircle(x, y - h, r, colorPalette[paletteIndex], op);
39 | }
40 | }
41 | }
42 |
43 | export { Paper };
44 |
--------------------------------------------------------------------------------
/modules/paper4.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#000" };
9 | const opts2 = { specularColor: "#fff" };
10 |
11 | var colorPalette = [];
12 | colorPalette.push("#89d5da");
13 | colorPalette.push("#4f4f41");
14 | colorPalette.push("#f6bd1f");
15 | colorPalette.push("#b1a881");
16 | colorPalette.push("#fbd66c");
17 |
18 | const f = 512 / w;
19 | const v = (w * 16) / 512;
20 |
21 | for (var i = 0; i < v; i++) {
22 | for (var j = 0; j < v; j++) {
23 | //Draw background
24 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
25 | this.drawRect(
26 | i * (w / v),
27 | j * (h / v),
28 | w / v,
29 | h / v,
30 | colorPalette[paletteIndex],
31 | opts1
32 | );
33 | }
34 | }
35 |
36 | var sourceTmpCanvas = document.createElement("canvas");
37 | var destinationTmpCanvas = document.createElement("canvas");
38 | destinationTmpCanvas.setAttribute("width", w);
39 | destinationTmpCanvas.setAttribute("height", h);
40 | sourceTmpCanvas.setAttribute("width", w);
41 | sourceTmpCanvas.setAttribute("height", h);
42 | var srcCtx = sourceTmpCanvas.getContext("2d");
43 | var dstCtx = destinationTmpCanvas.getContext("2d");
44 |
45 | srcCtx.drawImage(this.colorCanvas, 0, 0);
46 |
47 | this.colorCtx.clearRect(0, 0, w, h);
48 | for (var i = 0; i <= v; i++) {
49 | for (var j = 0; j <= v; j++) {
50 | //Draw arcs inside the arcs
51 | var startAngle = Math.floor(Math.random() * 4) * (Math.PI / 2);
52 | var arcRadians = Math.ceil(Math.random() * 4) * (Math.PI / 2);
53 | //this.drawArc((i * (512 / v)) + ((512 / v / 2)), (j * (512 / v)) + ((512 / v / 2)), (512 / v / 2), startAngle, arcRadians, "#aaa", opts2);
54 | this.drawArc(
55 | i * (w / v),
56 | j * (h / v),
57 | w / v / 2,
58 | startAngle,
59 | arcRadians,
60 | "#aaa",
61 | opts2
62 | );
63 | }
64 | }
65 |
66 | dstCtx.drawImage(this.colorCanvas, 0, 0);
67 |
68 | this.colorCtx.clearRect(0, 0, w, h);
69 |
70 | this.colorCtx.drawImage(sourceTmpCanvas, 0, 0, w, h);
71 | this.colorCtx.globalCompositeOperation = "destination-in";
72 | this.colorCtx.drawImage(destinationTmpCanvas, 0, 0, w, h);
73 | this.colorCtx.globalCompositeOperation = "destination-over";
74 | this.drawRect(0, 0, w, h, "#fff");
75 | this.colorCtx.globalCompositeOperation = "source-over";
76 | //Draw circles inside the arcs
77 | for (var i = 0; i <= v; i++) {
78 | for (var j = 0; j <= v; j++) {
79 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
80 | var circleWidth = Math.max(
81 | Math.ceil(Math.random() * (w / v / 2 - 10 * f)),
82 | 0
83 | );
84 | this.drawCircle(
85 | i * (w / v),
86 | j * (h / v),
87 | circleWidth,
88 | colorPalette[paletteIndex],
89 | opts2
90 | );
91 | }
92 | }
93 | }
94 | }
95 |
96 | export { Paper };
97 |
--------------------------------------------------------------------------------
/modules/paper5.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | const opts1 = { specularColor: "#000" };
8 |
9 | const colorPalette1 = [
10 | "#f1c12f",
11 | "#c6c6c6",
12 | "#fefefe",
13 | "#20bfd2",
14 | "#6c6c6c",
15 | "#484148"
16 | ];
17 | const colorPalette11 = [
18 | "#fefefe",
19 | "#c6c6c6",
20 | "#484148",
21 | "#6c6c6c",
22 | "#f1c12f",
23 | "#20bfd2"
24 | ];
25 | const colorPalette2 = ["#d23177", "#ffffff", "#ef562d", "#ffe156"];
26 | const colorPalette21 = ["#ffffff", "#d23177", "#ef562d", "#ffe156"];
27 | const colorPalette3 = ["#d71e75", "#ef562d", "#98d6e1", "#f6d258"];
28 | const colorPalette31 = ["#d71e75", "#ef562d", "#f6d258", "#98d6e1"];
29 |
30 | const palettes = [
31 | colorPalette1,
32 | colorPalette11,
33 | colorPalette2,
34 | colorPalette21,
35 | colorPalette3,
36 | colorPalette31
37 | ];
38 | const colorPalette = palettes[~~(Math.random() * palettes.length)];
39 |
40 | colorPalette.sort((a, b) => Math.random() * 2 - 1);
41 |
42 | const width = 32;
43 | const height = 32;
44 |
45 | this.drawRect(0, 0, w, h, "#fff", opts1);
46 | for (let y = -1; y < h / height + 1; y++) {
47 | for (let x = -1; x < w / width + 1; x++) {
48 | const path = new Path2D();
49 | if (x % 2) {
50 | path.moveTo(x * width, y * height);
51 | path.lineTo((x + 1) * width, (y + 1) * height);
52 | path.lineTo((x + 1) * width, (y + 2) * height);
53 | path.lineTo(x * width, (y + 1) * height);
54 | path.lineTo(x * width, y * height);
55 | } else {
56 | path.moveTo(x * width, (y + 1) * height);
57 | path.lineTo(x * width, (y + 2) * height);
58 | path.lineTo((x + 1) * width, (y + 1) * height);
59 | path.lineTo((x + 1) * width, y * height);
60 | path.lineTo(x * width, (y + 1) * height);
61 | }
62 |
63 | this.colorCtx.fillStyle =
64 | colorPalette[((2 * (y + 1)) % colorPalette.length) + (x % 2)];
65 | this.colorCtx.fill(path);
66 |
67 | const c = ~~(Math.random() * 255);
68 | this.roughnessCtx.fillStyle = `rgb(${c},${c},${c})`;
69 | this.roughnessCtx.fill(path);
70 | }
71 | }
72 | }
73 | }
74 |
75 | export { Paper };
76 |
--------------------------------------------------------------------------------
/modules/paper6.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | var colorPalette = [];
11 | colorPalette.push("#edece8");
12 | colorPalette.push("#db6644");
13 | colorPalette.push("#b44137");
14 | colorPalette.push("#4c7b7f");
15 | colorPalette.push("#0a0a0f");
16 |
17 | var specPalette = [];
18 | specPalette.push("#eee");
19 | specPalette.push("#aaa");
20 | specPalette.push("#888");
21 | specPalette.push("#666");
22 | specPalette.push("#444");
23 |
24 | this.drawRect(0, 0, 512, 512, "#fff", "#000");
25 |
26 | function draw(x, y, w, h, s, depth, l) {
27 | l++;
28 |
29 | for (var i = 0; i < s; i++) {
30 | for (var j = 0; j < s; j++) {
31 | var xx = x + i * (w / s),
32 | yy = y + j * (h / s),
33 | d = w / s;
34 |
35 | if (l == 1) {
36 | depth = Math.floor(Math.random() * 4);
37 | }
38 |
39 | if (l < depth) {
40 | _d(xx, yy, d, d, depth, l);
41 | } else {
42 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
43 | this.drawRect(xx, yy, d, d, colorPalette[paletteIndex], {
44 | specularColor: specPalette[paletteIndex]
45 | });
46 | }
47 | }
48 | }
49 | }
50 | const _d = draw.bind(this);
51 |
52 | _d(0, 0, 512, 512, 15, Math.floor(Math.random() * 3), 0);
53 | }
54 | }
55 |
56 | export { Paper };
57 |
--------------------------------------------------------------------------------
/modules/paper7.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | var colorPalette = ["#f6f6f6", "#ff9b00", "#ff3200", "#02827a", "#330a2d"];
11 |
12 | var specPalette = ["#eee", "#aaa", "#888", "#666", "#444"];
13 |
14 | this.drawRect(0, 0, w, h, "#340a2d", "#000");
15 |
16 | const width = 48;
17 | const height = 32;
18 |
19 | const path = new Path2D();
20 | path.moveTo(0, 0.5 * height);
21 | path.lineTo(0.25 * width, 0);
22 | path.lineTo(0.5 * width, 0);
23 | path.lineTo(0.75 * width, 0.5 * height);
24 | path.lineTo(0.5 * width, height);
25 | path.lineTo(0.25 * width, height);
26 | path.lineTo(0, 0.5 * height);
27 |
28 | let id;
29 | for (let y = -1; y < h / height + 1; y++) {
30 | for (let x = -1; x < w / width + 1; x++) {
31 | this.colorCtx.save();
32 | this.colorCtx.translate(x * width, y * height);
33 | id = ~~(Math.random() * colorPalette.length);
34 | this.colorCtx.fillStyle = colorPalette[id];
35 | this.colorCtx.fill(path);
36 | this.colorCtx.restore();
37 | this.colorCtx.save();
38 | this.colorCtx.translate((x + 0.5) * width, (y + 0.5) * height);
39 | id = ~~(Math.random() * colorPalette.length);
40 | this.colorCtx.fillStyle = colorPalette[id];
41 | this.colorCtx.fill(path);
42 | this.colorCtx.restore();
43 | this.colorCtx.save();
44 | this.colorCtx.translate((x + 0.25 * 0.75) * width, (y + 0.25) * height);
45 | this.colorCtx.scale(0.5, 0.5);
46 | id = ~~(Math.random() * colorPalette.length);
47 | this.colorCtx.fillStyle = colorPalette[id];
48 | this.colorCtx.fill(path);
49 | this.colorCtx.restore();
50 | this.colorCtx.save();
51 | this.colorCtx.translate(
52 | (x + 0.5 + 0.75 * 0.25) * width,
53 | (y + 0.75) * height
54 | );
55 | this.colorCtx.scale(0.5, 0.5);
56 | id = ~~(Math.random() * colorPalette.length);
57 | this.colorCtx.fillStyle = colorPalette[id];
58 | this.colorCtx.fill(path);
59 | this.colorCtx.restore();
60 | this.roughnessCtx.save();
61 | this.roughnessCtx.translate(x * width, y * height);
62 | id = ~~(Math.random() * specPalette.length);
63 | this.roughnessCtx.fillStyle = specPalette[id];
64 | this.roughnessCtx.fill(path);
65 | this.roughnessCtx.restore();
66 | this.roughnessCtx.save();
67 | this.roughnessCtx.translate((x + 0.5) * width, (y + 0.5) * height);
68 | id = ~~(Math.random() * specPalette.length);
69 | this.roughnessCtx.fillStyle = specPalette[id];
70 | this.roughnessCtx.fill(path);
71 | this.roughnessCtx.restore();
72 | this.roughnessCtx.save();
73 | this.roughnessCtx.translate(
74 | (x + 0.25 * 0.75) * width,
75 | (y + 0.25) * height
76 | );
77 | this.roughnessCtx.scale(0.5, 0.5);
78 | id = ~~(Math.random() * specPalette.length);
79 | this.roughnessCtx.fillStyle = specPalette[id];
80 | this.roughnessCtx.fill(path);
81 | this.roughnessCtx.restore();
82 | this.roughnessCtx.save();
83 | this.roughnessCtx.translate(
84 | (x + 0.5 + 0.75 * 0.25) * width,
85 | (y + 0.75) * height
86 | );
87 | this.roughnessCtx.scale(0.5, 0.5);
88 | id = ~~(Math.random() * specPalette.length);
89 | this.roughnessCtx.fillStyle = specPalette[id];
90 | this.roughnessCtx.fill(path);
91 | this.roughnessCtx.restore();
92 | }
93 | }
94 | }
95 | }
96 |
97 | export { Paper };
98 |
--------------------------------------------------------------------------------
/modules/paper8.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | var colorPalette = [];
11 | colorPalette.push("#ffffdd");
12 | colorPalette.push("#f4c361");
13 | colorPalette.push("#efad1c");
14 | colorPalette.push("#badfd9");
15 | colorPalette.push("#80cacd");
16 | colorPalette.push("#a29c7c");
17 | colorPalette.push("#574f40");
18 |
19 | var specPalette = [];
20 | specPalette.push("#eee");
21 | specPalette.push("#aaa");
22 | specPalette.push("#888");
23 | specPalette.push("#666");
24 | specPalette.push("#444");
25 |
26 | this.drawRect(0, 0, 512, 512, "#fff", "#000");
27 |
28 | var s = 512 / 15;
29 | for (var y = 0; y < 512; y += s) {
30 | for (var x = 0; x < 512; x += s) {
31 | var steps = Math.ceil(Math.random() * 8);
32 | var dir = Math.random() > 0.5;
33 | for (var i = 0; i < s; i += s / steps) {
34 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
35 | var opts = { specularColor: specPalette[paletteIndex] };
36 | if (dir) {
37 | this.drawRect(
38 | x + i,
39 | y,
40 | s / steps,
41 | s,
42 | colorPalette[paletteIndex],
43 | opts
44 | );
45 | } else {
46 | this.drawRect(
47 | x,
48 | y + i,
49 | s,
50 | s / steps,
51 | colorPalette[paletteIndex],
52 | opts
53 | );
54 | }
55 | }
56 | }
57 | }
58 | }
59 | }
60 |
61 | export { Paper };
62 |
--------------------------------------------------------------------------------
/modules/paper9.js:
--------------------------------------------------------------------------------
1 | import { WrappingPaper } from "./wrapping-paper.js";
2 |
3 | class Paper extends WrappingPaper {
4 | constructor(w, h) {
5 | super(w, h);
6 |
7 | //object that defines the specular level for the specular image
8 | const opts1 = { specularColor: "#fff" };
9 |
10 | var colorPalette = [];
11 |
12 | if (Math.random() > 0.5) {
13 | colorPalette.push("#dfd8d4");
14 | colorPalette.push("#adabb7");
15 | colorPalette.push("#d41a2e");
16 | colorPalette.push("#230c41");
17 | colorPalette.push("#17080e");
18 | } else {
19 | colorPalette.push("#ffffdd");
20 | colorPalette.push("#f4c361");
21 | colorPalette.push("#efad1c");
22 | colorPalette.push("#badfd9");
23 | colorPalette.push("#80cacd");
24 | colorPalette.push("#a29c7c");
25 | colorPalette.push("#574f40");
26 | }
27 |
28 | var specPalette = [];
29 | specPalette.push("#eee");
30 | specPalette.push("#aaa");
31 | specPalette.push("#888");
32 | specPalette.push("#777");
33 | specPalette.push("#666");
34 | specPalette.push("#555");
35 | specPalette.push("#444");
36 |
37 | this.drawRect(0, 0, 512, 512, "#fff", "#000");
38 |
39 | var s = 512;
40 | var steps = 5 + Math.ceil(Math.random() * 10);
41 | var dir = Math.random() > 0.5;
42 | for (var i = 0; i < s; i += s / steps) {
43 | var paletteIndex = Math.floor(Math.random() * colorPalette.length);
44 | var opts = { specularColor: specPalette[paletteIndex] };
45 | if (dir) {
46 | this.drawRect(i, 0, s / steps, s, colorPalette[paletteIndex], opts);
47 | } else {
48 | this.drawRect(0, i, s, s / steps, colorPalette[paletteIndex], opts);
49 | }
50 | }
51 | }
52 | }
53 |
54 | export { Paper };
55 |
--------------------------------------------------------------------------------
/modules/post.js:
--------------------------------------------------------------------------------
1 | import {
2 | RawShaderMaterial,
3 | Vector2,
4 | RGBAFormat,
5 | UnsignedByteType,
6 | LinearFilter,
7 | ClampToEdgeWrapping
8 | } from "../third_party/three.module.js";
9 | import { Maf } from "./maf.js";
10 |
11 | import { getFBO } from "./fbo.js";
12 | import orthoVertexShader from "../shaders/ortho.js";
13 | import { ShaderPass } from "./shader-pass.js";
14 | import { ShaderPingPongPass } from "./shader-ping-pong-pass.js";
15 |
16 | import { fs as highlightFragmentShader } from "../shaders/highlight-fs.js";
17 | import { fs as dofFragmentShader } from "../shaders/dof-fs.js";
18 | import { fs as combineFragmentShader } from "../shaders/combine-fs.js";
19 | import { fs as finalFragmentShader } from "../shaders/final-fs.js";
20 | import { fs as blurFragmentShader } from "../shaders/blur-fs.js";
21 | import { fs as finalColorFragmentShader } from "../shaders/final-color-fs.js";
22 |
23 | function Post(renderer, params = {}) {
24 | const size = new Vector2();
25 | renderer.getSize(size);
26 | const w = size.x;
27 | const h = size.y;
28 |
29 | const colorFBO = getFBO(w, h);
30 | const depthFBO = getFBO(w, h);
31 | const resolution = new Vector2(w, h);
32 |
33 | const dofShader = new RawShaderMaterial({
34 | uniforms: {
35 | inputTexture: { value: colorFBO.texture },
36 | depthTexture: { value: depthFBO.texture },
37 | resolution: { value: resolution },
38 | direction: { value: new Vector2(0, 1) }
39 | },
40 | vertexShader: orthoVertexShader,
41 | fragmentShader: dofFragmentShader
42 | });
43 | const dofPass = new ShaderPingPongPass(
44 | renderer,
45 | dofShader,
46 | w,
47 | h,
48 | RGBAFormat,
49 | UnsignedByteType,
50 | LinearFilter,
51 | LinearFilter,
52 | ClampToEdgeWrapping,
53 | ClampToEdgeWrapping
54 | );
55 |
56 | const highlightShader = new RawShaderMaterial({
57 | uniforms: {
58 | inputTexture: { value: dofPass.fbo.texture }
59 | },
60 | vertexShader: orthoVertexShader,
61 | fragmentShader: highlightFragmentShader
62 | });
63 | const highlightPass = new ShaderPass(
64 | renderer,
65 | highlightShader,
66 | w,
67 | h,
68 | RGBAFormat,
69 | UnsignedByteType,
70 | LinearFilter,
71 | LinearFilter,
72 | ClampToEdgeWrapping,
73 | ClampToEdgeWrapping
74 | );
75 |
76 | const blurPasses = [];
77 | const levels = 5;
78 | const blurShader = new RawShaderMaterial({
79 | uniforms: {
80 | inputTexture: { value: null },
81 | resolution: { value: new Vector2(1, 1) },
82 | direction: { value: new Vector2(0, 1) }
83 | },
84 | vertexShader: orthoVertexShader,
85 | fragmentShader: blurFragmentShader
86 | });
87 | let tw = 1;
88 | let th = 1;
89 | for (let i = 0; i < levels; i++) {
90 | const blurPass = new ShaderPingPongPass(
91 | renderer,
92 | blurShader,
93 | tw,
94 | th,
95 | RGBAFormat,
96 | UnsignedByteType,
97 | LinearFilter,
98 | LinearFilter,
99 | ClampToEdgeWrapping,
100 | ClampToEdgeWrapping
101 | );
102 | blurPasses.push(blurPass);
103 | }
104 |
105 | const combineShader = new RawShaderMaterial({
106 | uniforms: {
107 | resolution: { value: resolution },
108 | inputTexture: { value: dofPass.fbo.texture },
109 | blur1Texture: { value: blurPasses[0].fbo.texture },
110 | blur2Texture: { value: blurPasses[1].fbo.texture },
111 | blur3Texture: { value: blurPasses[2].fbo.texture },
112 | blur4Texture: { value: blurPasses[3].fbo.texture },
113 | blur5Texture: { value: blurPasses[4].fbo.texture },
114 | time: { value: 0 }
115 | },
116 | vertexShader: orthoVertexShader,
117 | fragmentShader: combineFragmentShader
118 | });
119 | const combinePass = new ShaderPass(
120 | renderer,
121 | combineShader,
122 | w,
123 | h,
124 | RGBAFormat,
125 | UnsignedByteType,
126 | LinearFilter,
127 | LinearFilter,
128 | ClampToEdgeWrapping,
129 | ClampToEdgeWrapping
130 | );
131 |
132 | const finalShader = new RawShaderMaterial({
133 | uniforms: {
134 | resolution: { value: resolution },
135 | vignetteBoost: { value: 0.5 },
136 | vignetteReduction: { value: 0.75 },
137 | inputTexture: { value: combinePass.fbo.texture }
138 | },
139 | vertexShader: orthoVertexShader,
140 | fragmentShader: finalFragmentShader
141 | });
142 | const finalPass = new ShaderPass(
143 | renderer,
144 | finalShader,
145 | w,
146 | h,
147 | RGBAFormat,
148 | UnsignedByteType,
149 | LinearFilter,
150 | LinearFilter,
151 | ClampToEdgeWrapping,
152 | ClampToEdgeWrapping
153 | );
154 |
155 | const finalColorShader = new RawShaderMaterial({
156 | uniforms: {
157 | resolution: { value: resolution },
158 | time: { value: 0 },
159 | inputTexture: { value: finalPass.fbo.texture }
160 | },
161 | vertexShader: orthoVertexShader,
162 | fragmentShader: finalColorFragmentShader
163 | });
164 | const finalColorPass = new ShaderPass(
165 | renderer,
166 | finalColorShader,
167 | w,
168 | h,
169 | RGBAFormat,
170 | UnsignedByteType,
171 | LinearFilter,
172 | LinearFilter,
173 | ClampToEdgeWrapping,
174 | ClampToEdgeWrapping
175 | );
176 |
177 | function render(scene, camera, boxes) {
178 | renderer.setClearColor(0xffffff, 1);
179 | boxes.forEach(b => {
180 | b.mesh.box.material = b.mesh.colorMaterial;
181 | b.mesh.lid.material = b.mesh.colorMaterial;
182 | });
183 | renderer.setRenderTarget(colorFBO);
184 | renderer.render(scene, camera);
185 |
186 | renderer.setClearColor(0, 0);
187 | boxes.forEach(b => {
188 | b.mesh.box.material = b.mesh.depthMaterial;
189 | b.mesh.lid.material = b.mesh.depthMaterial;
190 | });
191 | renderer.setRenderTarget(depthFBO);
192 | renderer.render(scene, camera);
193 |
194 | renderer.setRenderTarget(null);
195 | dofPass.shader.uniforms.inputTexture.value = colorFBO.texture;
196 | for (let j = 0; j < 4; j++) {
197 | dofPass.shader.uniforms.direction.value.set(1, 0);
198 | dofPass.render();
199 | dofPass.shader.uniforms.inputTexture.value =
200 | dofPass.fbos[dofPass.currentFBO].texture;
201 | dofPass.shader.uniforms.direction.value.set(0, 1);
202 | dofPass.render();
203 | dofPass.shader.uniforms.inputTexture.value =
204 | dofPass.fbos[dofPass.currentFBO].texture;
205 | }
206 | highlightPass.render();
207 |
208 | let offset = 1;
209 | blurShader.uniforms.inputTexture.value = highlightPass.fbo.texture;
210 | for (let j = 0; j < levels; j++) {
211 | const blurPass = blurPasses[j];
212 | blurShader.uniforms.direction.value.set(offset, 0);
213 | blurShader.uniforms.resolution.value.set(
214 | blurPass.width * 2,
215 | blurPass.height * 2
216 | );
217 | blurPass.render();
218 | blurShader.uniforms.inputTexture.value =
219 | blurPass.fbos[blurPass.currentFBO].texture;
220 | blurShader.uniforms.direction.value.set(0, offset);
221 | blurPass.render();
222 | blurShader.uniforms.inputTexture.value =
223 | blurPass.fbos[blurPass.currentFBO].texture;
224 | }
225 |
226 | combinePass.render();
227 | finalPass.render();
228 | finalColorPass.shader.uniforms.time.value = performance.now();
229 | finalColorPass.render(true);
230 | }
231 |
232 | function setSize(w, h) {
233 | resolution.set(w, h);
234 | colorFBO.setSize(w, h);
235 | depthFBO.setSize(w, h);
236 | dofPass.setSize(w, h);
237 | combinePass.setSize(w, h);
238 | highlightPass.setSize(w, h);
239 | finalPass.setSize(w, h);
240 | finalColorPass.setSize(w, h);
241 |
242 | let tw = w; //Maf.nextPowerOfTwo(w) / 2;
243 | let th = h; //Maf.nextPowerOfTwo(h) / 2;
244 | blurPasses.forEach((pass, i) => {
245 | pass.shader.uniforms.resolution.value.set(tw, th);
246 | tw /= 2;
247 | th /= 2;
248 | pass.setSize(tw, th);
249 | });
250 | }
251 |
252 | return {
253 | render,
254 | setSize
255 | };
256 | }
257 |
258 | export { Post };
259 |
--------------------------------------------------------------------------------
/modules/scene.js:
--------------------------------------------------------------------------------
1 | import {
2 | PCFShadowMap,
3 | PCFSoftShadowMap,
4 | SpotLight,
5 | Scene,
6 | Group,
7 | Vector3,
8 | Matrix4,
9 | Object3D,
10 | Quaternion,
11 | PerspectiveCamera,
12 | WebGLRenderer,
13 | PointLight,
14 | CanvasTexture,
15 | Mesh,
16 | BoxBufferGeometry,
17 | TextureLoader,
18 | MeshBasicMaterial,
19 | FogExp2,
20 | AmbientLight,
21 | RepeatWrapping,
22 | PlaneBufferGeometry,
23 | MeshNormalMaterial,
24 | Color
25 | } from "../third_party/three.module.js";
26 | import OrbitControls from "../third_party/THREE.OrbitControls.js";
27 | import { EquirectangularToCubemap } from "../third_party/equirectangular-to-cubemap.js";
28 | import { UpdatableTexture } from "../third_party/UpdatableTexture.js";
29 |
30 | import { GiftBox } from "./gift-box.js";
31 | import { Maf } from "./maf.js";
32 | import easings from "./easings.js";
33 | import { Post } from "./post.js";
34 |
35 | import { Paper as Paper1 } from "./paper1.js";
36 | import { Paper as Paper2 } from "./paper2.js";
37 | import { Paper as Paper3 } from "./paper3.js";
38 | import { Paper as Paper4 } from "./paper4.js";
39 | import { Paper as Paper5 } from "./paper5.js";
40 | import { Paper as Paper6 } from "./paper6.js";
41 | import { Paper as Paper7 } from "./paper7.js";
42 | import { Paper as Paper8 } from "./paper8.js";
43 | import { Paper as Paper9 } from "./paper9.js";
44 | import { Paper as Paper10 } from "./paper10.js";
45 | import { Paper as Paper11 } from "./paper11.js";
46 | import { Paper as Paper12 } from "./paper12.js";
47 | import { Paper as Paper13 } from "./paper13.js";
48 | import { Paper as Paper14 } from "./paper14.js";
49 | import { Paper as Paper15 } from "./paper15.js";
50 | import { Paper as Paper16 } from "./paper16.js";
51 | import { Paper as Paper17 } from "./paper17.js";
52 | import { Paper as Paper18 } from "./paper18.js";
53 | import { Paper as Paper19 } from "./paper19.js";
54 | import { Paper as Paper20 } from "./paper20.js";
55 |
56 | const configs = {
57 | low: {
58 | textureSize: 256,
59 | tileSize: 32,
60 | pixelRatio: 0.5,
61 | shadow: PCFShadowMap,
62 | material: "phong",
63 | post: false
64 | },
65 | std: {
66 | textureSize: 512,
67 | tileSize: 64,
68 | pixelRatio: 0.5,
69 | shadow: PCFSoftShadowMap,
70 | material: "pbr",
71 | post: true
72 | },
73 | high: {
74 | textureSize: 512,
75 | tileSize: 64,
76 | pixelRatio: 1,
77 | shadow: PCFSoftShadowMap,
78 | material: "pbr",
79 | post: true
80 | },
81 | vrlow: {
82 | textureSize: 512,
83 | tileSize: 32,
84 | pixelRatio: 1,
85 | shadow: PCFShadowMap,
86 | material: "phong",
87 | post: false
88 | },
89 | vrhigh: {
90 | textureSize: 512,
91 | tileSize: 32,
92 | pixelRatio: 1,
93 | shadow: PCFShadowMap,
94 | material: "phong",
95 | post: false
96 | }
97 | };
98 |
99 | let config;
100 |
101 | const papers = [
102 | Paper1,
103 | Paper2,
104 | Paper3,
105 | Paper4,
106 | Paper5,
107 | Paper6,
108 | Paper7,
109 | Paper8,
110 | Paper9,
111 | Paper10,
112 | Paper11,
113 | Paper12,
114 | Paper13,
115 | Paper14,
116 | Paper15,
117 | Paper16,
118 | Paper17,
119 | Paper18,
120 | Paper19,
121 | Paper20
122 | ];
123 |
124 | const renderer = new WebGLRenderer({ antialias: true });
125 | renderer.setClearColor(0xffffff, 1);
126 | renderer.shadowMap.enabled = true;
127 |
128 | const post = new Post(renderer);
129 |
130 | const factor = 2;
131 |
132 | const scene = new Scene();
133 | scene.fog = new FogExp2(0xffffff, 0.01);
134 | const camera = new PerspectiveCamera(60, 1, 0.01, 30 * factor);
135 | //camera.lookAt(scene.position);
136 | const cameraDummy = new Group();
137 | cameraDummy.position.set(0, 0, 1.5 * factor);
138 | cameraDummy.add(camera);
139 | scene.add(cameraDummy);
140 | /*camera.position.set(0, 0, 1.6 * factor);
141 | scene.add(camera);*/
142 |
143 | const ambient = new AmbientLight(0x808080);
144 | scene.add(ambient);
145 |
146 | //const controls = new OrbitControls(camera, renderer.domElement);
147 | //controls.screenSpacePanning = true;
148 |
149 | const cameraLight = new SpotLight(
150 | 0xffffff,
151 | 0.5,
152 | 20 * factor,
153 | Math.PI / 3,
154 | 0.5,
155 | 0.1
156 | );
157 | cameraLight.castShadow = true;
158 | cameraLight.shadow.mapSize.width = 512;
159 | cameraLight.shadow.mapSize.height = 512;
160 | cameraLight.shadow.camera.near = 0.01 * factor;
161 | cameraLight.shadow.camera.far = 1.5 * factor;
162 | //cameraLight.shadow.bias = -.005;
163 | scene.add(cameraLight);
164 |
165 | let startTime;
166 |
167 | function animate() {
168 | renderer.domElement.className = "visible render";
169 | audio.loop = true;
170 | audio.playbackRate = 1;
171 | audio.play();
172 | startTime = performance.now();
173 | renderer.setAnimationLoop(render);
174 | }
175 |
176 | function setSize(w, h) {
177 | renderer.setSize(w, h);
178 | camera.aspect = w / h;
179 | camera.updateProjectionMatrix();
180 | const dPR = renderer.getPixelRatio();
181 | post.setSize(w * dPR, h * dPR);
182 | }
183 |
184 | const duration = 0.5 * 2 * 7.385;
185 | let envMap;
186 | let normalMap;
187 | let audio;
188 |
189 | function loadAssets() {
190 | const texLoader = new TextureLoader();
191 | return Promise.all([
192 | new Promise((resolve, reject) => {
193 | audio = document.createElement("audio");
194 | audio.addEventListener("canplay", e => {
195 | resolve();
196 | });
197 | if (audio.canPlayType('video/ogg; codecs="theora"')) {
198 | audio.src = "./assets/track.ogg";
199 | } else {
200 | audio.src = "./assets/track.mp3";
201 | }
202 | }),
203 | new Promise((resolve, reject) => {
204 | normalMap = texLoader.load("./assets/normal.jpg", res => resolve());
205 | normalMap.wrapS = normalMap.wrapT = RepeatWrapping;
206 | }),
207 | new Promise((resolve, reject) => {
208 | texLoader.load("./assets/env.jpg", res => {
209 | const equiToCube = new EquirectangularToCubemap(renderer);
210 | envMap = equiToCube.convert(res, 512);
211 | envMap.needsUpdate = true;
212 | resolve();
213 | });
214 | })
215 | ]);
216 | }
217 |
218 | const updateCanvas = document.createElement("canvas");
219 | const updateCtx = updateCanvas.getContext("2d");
220 |
221 | async function init(preset) {
222 | config = configs[preset];
223 |
224 | renderer.setPixelRatio(window.devicePixelRatio * config.pixelRatio);
225 | renderer.shadowMap.type = config.shadow;
226 |
227 | paperSize = config.textureSize;
228 | tileSize = config.tileSize;
229 | updateCanvas.width = updateCanvas.height = tileSize;
230 |
231 | initScene();
232 | updateBox(0, 0);
233 | updateWrappingPaper(0);
234 | }
235 |
236 | const target = new Vector3();
237 | const m = new Matrix4();
238 | const q = new Quaternion();
239 | const group = new Group();
240 | const boxes = [];
241 | const cards = [];
242 | const queue = [];
243 | let paperSize;
244 | let tileSize;
245 |
246 | let depth = 0;
247 | let prevTargetBox = null;
248 |
249 | function initScene() {
250 | for (let j = 0; j < 3; j++) {
251 | const card = new Mesh(
252 | new PlaneBufferGeometry(0.1, 0.2),
253 | new MeshNormalMaterial()
254 | );
255 | //group.add(card);
256 | cards.push({
257 | mesh: card,
258 | quaternion: new Quaternion()
259 | });
260 | const box = new GiftBox(config.material);
261 | box.orientateLid();
262 | box.scale.setScalar(1 / Math.exp(factor * j));
263 | target
264 | .set(
265 | Maf.randomInRange(-1, 1),
266 | Maf.randomInRange(-1, 1),
267 | Maf.randomInRange(-1, 1)
268 | )
269 | .normalize();
270 | m.lookAt(box.position, target, Object3D.DefaultUp);
271 | q.setFromRotationMatrix(m);
272 | box.quaternion.copy(q);
273 | q.setFromRotationMatrix(m.getInverse(m));
274 | group.add(box);
275 | boxes.push({
276 | mesh: box,
277 | quaternion: q.clone()
278 | });
279 | box.material.map = new UpdatableTexture();
280 | box.material.map.anisotropy = renderer.capabilities.getMaxAnisotropy();
281 | box.material.map.setRenderer(renderer);
282 | box.material.map.wrapS = box.material.map.wrapT = RepeatWrapping;
283 | if (config.material === "phong") {
284 | box.material.specularMap = new UpdatableTexture();
285 | box.material.specularMap.anisotropy = renderer.capabilities.getMaxAnisotropy();
286 | box.material.specularMap.setRenderer(renderer);
287 | box.material.specularMap.wrapS = box.material.specularMap.wrapT = RepeatWrapping;
288 | } else {
289 | box.material.roughnessMap = new UpdatableTexture();
290 | box.material.map.roughnessMap = renderer.capabilities.getMaxAnisotropy();
291 | box.material.roughnessMap.setRenderer(renderer);
292 | box.material.roughnessMap.wrapS = box.material.roughnessMap.wrapT = RepeatWrapping;
293 | box.material.metalnessMap = box.material.map;
294 | }
295 | box.material.normalMap = normalMap;
296 | box.material.normalMap.wrapS = box.material.normalMap.wrapT = RepeatWrapping;
297 | box.material.normalScale.set(0.05, 0.05);
298 | box.material.envMap = envMap;
299 | box.material.envMapIntensity = 0.8;
300 | box.material.needsUpdate = true;
301 | }
302 | scene.add(group);
303 | renderer.render(scene, camera);
304 | boxes.forEach(b => {
305 | const emptyCanvas = document.createElement("canvas");
306 | emptyCanvas.width = emptyCanvas.height = paperSize;
307 | b.mesh.material.map.setSize(paperSize, paperSize);
308 | b.mesh.material.map.update(emptyCanvas, 0, 0);
309 | if (config.material === "phong") {
310 | b.mesh.material.specularMap.setSize(paperSize, paperSize);
311 | b.mesh.material.specularMap.update(emptyCanvas, 0, 0);
312 | } else {
313 | b.mesh.material.roughnessMap.setSize(paperSize, paperSize);
314 | b.mesh.material.roughnessMap.update(emptyCanvas, 0, 0);
315 | }
316 | });
317 | }
318 |
319 | function updateBox(ptr, count) {
320 | const box = boxes[ptr];
321 | box.mesh.refresh();
322 | box.mesh.scale.setScalar(1 / Math.exp(factor * count));
323 | target
324 | .set(
325 | Maf.randomInRange(-1, 1),
326 | Maf.randomInRange(-1, 1),
327 | Maf.randomInRange(-1, 1)
328 | )
329 | .normalize();
330 | m.lookAt(box.mesh.position, target, Object3D.DefaultUp);
331 | q.setFromRotationMatrix(m);
332 | box.mesh.quaternion.copy(q);
333 | q.setFromRotationMatrix(m.getInverse(m));
334 | box.quaternion.copy(q);
335 | const card = cards[ptr];
336 | card.mesh.scale.setScalar(1 / Math.exp(factor * count));
337 | card.mesh.quaternion.copy(box.mesh.quaternion);
338 | }
339 |
340 | let sequence = [1];
341 | let paperCounter = 0;
342 |
343 | function buildSequence() {
344 | const lastOne = sequence[sequence.length - 1];
345 | sequence = [];
346 | for (let j = 0; j < papers.length; j++) {
347 | sequence.push(j);
348 | }
349 | do {
350 | sequence.sort((a, b) => Maf.randomInRange(-1, 1));
351 | } while (lastOne === sequence[0]);
352 | }
353 | buildSequence();
354 |
355 | function updateWrappingPaper(ptr) {
356 | const box = boxes[ptr];
357 | const Paper = papers[sequence[paperCounter]];
358 | const p = new Paper(paperSize, paperSize);
359 | paperCounter++;
360 | if (paperCounter > sequence.length - 1) {
361 | buildSequence();
362 | paperCounter = 0;
363 | }
364 | for (let y = 0; y < p.colorCanvas.height; y += tileSize) {
365 | for (let x = 0; x < p.colorCanvas.width; x += tileSize) {
366 | queue.push({
367 | target: box.mesh.material.map,
368 | source: p.colorCanvas,
369 | x,
370 | y,
371 | width: tileSize,
372 | height: tileSize
373 | });
374 | }
375 | }
376 | for (let y = 0; y < p.roughnessCanvas.height; y += tileSize) {
377 | for (let x = 0; x < p.roughnessCanvas.width; x += tileSize) {
378 | queue.push({
379 | target:
380 | config.material === "phong"
381 | ? box.mesh.material.specularMap
382 | : box.mesh.material.roughnessMap,
383 | source: p.roughnessCanvas,
384 | x,
385 | y,
386 | width: tileSize,
387 | height: tileSize
388 | });
389 | }
390 | }
391 | }
392 |
393 | /*requestIdleCallback(processQueue);
394 |
395 | function processQueue(deadline) {
396 | while (deadline.timeRemaining()) {
397 | const task = queue.shift();
398 | if (task) {
399 | updateCtx.drawImage(task.source, task.x, task.y, tileSize, tileSize, 0, 0, tileSize, tileSize);
400 | task.target.update(updateCanvas, task.x, task.y);
401 | }
402 | }
403 | requestIdleCallback(processQueue);
404 | }*/
405 |
406 | function render() {
407 | const delta = Math.max(
408 | (1 * (performance.now() - startTime)) / (duration * 1000),
409 | 0
410 | );
411 | const targetBox = Math.max(~~delta, 0) % boxes.length;
412 | const prevBox = Maf.mod(targetBox - 1, boxes.length);
413 | const nextBox = Maf.mod(targetBox + 1, boxes.length);
414 | if (targetBox !== prevTargetBox) {
415 | depth++;
416 | updateBox(nextBox, depth);
417 | updateWrappingPaper(Maf.mod(nextBox, boxes.length));
418 | prevTargetBox = targetBox;
419 | }
420 |
421 | const qTo = boxes[targetBox].quaternion;
422 | const qFrom = boxes[prevBox].quaternion;
423 |
424 | boxes[prevBox].mesh.pivot.rotation.y =
425 | Maf.PI - Maf.clamp(3 * (delta % 1) * Maf.PI, 0, Maf.PI);
426 | boxes[targetBox].mesh.pivot.rotation.y = (delta % 1) * Maf.PI;
427 | boxes[nextBox].mesh.pivot.rotation.y = 0;
428 | group.quaternion.copy(qFrom).slerp(qTo, easings.InOutQuad(delta % 1));
429 | group.scale.setScalar(Math.exp(factor * delta));
430 | target.copy(scene.position);
431 | const t = 0.0001 * performance.now();
432 | target.x += 0.5 * Math.cos(t);
433 | target.y += 0.5 * Math.sin(t);
434 | camera.lookAt(target);
435 | camera.rotation.z = 0.5 * delta * Maf.TAU;
436 | cameraLight.position.copy(cameraDummy.position);
437 | cameraLight.position.y += 0.5;
438 | cameraLight.position.z -= 1;
439 |
440 | if (renderer.xr.enabled || config.post === false) {
441 | renderer.render(scene, camera);
442 | } else {
443 | post.render(scene, camera, boxes);
444 | }
445 |
446 | for (let j = 0; j < 8; j++) {
447 | const task = queue.shift();
448 | if (task) {
449 | updateCtx.drawImage(
450 | task.source,
451 | task.x,
452 | task.y,
453 | tileSize,
454 | tileSize,
455 | 0,
456 | 0,
457 | tileSize,
458 | tileSize
459 | );
460 | task.target.update(updateCanvas, task.x, task.y);
461 | }
462 | }
463 | }
464 |
465 | export { renderer, setSize, render, animate, init, loadAssets };
466 |
--------------------------------------------------------------------------------
/modules/shader-pass.js:
--------------------------------------------------------------------------------
1 | import {
2 | Scene,
3 | WebGLRenderTarget,
4 | RepeatWrapping,
5 | LinearFilter,
6 | LinearMipMapLinearFilter,
7 | RGBAFormat,
8 | UnsignedByteType,
9 | OrthographicCamera,
10 | PlaneBufferGeometry,
11 | Mesh
12 | } from "../third_party/three.module.js";
13 |
14 | class ShaderPass {
15 | constructor(
16 | renderer,
17 | shader,
18 | width,
19 | height,
20 | format,
21 | type,
22 | minFilter,
23 | magFilter,
24 | wrapS,
25 | wrapT
26 | ) {
27 | this.renderer = renderer;
28 | this.shader = shader;
29 | this.orthoScene = new Scene();
30 | this.fbo = new WebGLRenderTarget(width, height, {
31 | wrapS: wrapS || RepeatWrapping,
32 | wrapT: wrapT || RepeatWrapping,
33 | minFilter: minFilter || LinearMipMapLinearFilter,
34 | magFilter: magFilter || LinearFilter,
35 | format: format || RGBAFormat,
36 | type: type || UnsignedByteType
37 | });
38 | this.orthoCamera = new OrthographicCamera(
39 | width / -2,
40 | width / 2,
41 | height / 2,
42 | height / -2,
43 | 0.00001,
44 | 1000
45 | );
46 | this.orthoQuad = new Mesh(new PlaneBufferGeometry(1, 1), this.shader);
47 | this.orthoQuad.scale.set(width, height, 1);
48 | this.orthoScene.add(this.orthoQuad);
49 | this.texture = this.fbo.texture;
50 | }
51 |
52 | render(final) {
53 | this.renderer.setRenderTarget(final ? null : this.fbo);
54 | this.renderer.render(this.orthoScene, this.orthoCamera);
55 | }
56 |
57 | setSize(width, height) {
58 | this.orthoQuad.scale.set(width, height, 1);
59 |
60 | this.fbo.setSize(width, height);
61 |
62 | this.orthoQuad.scale.set(width, height, 1);
63 |
64 | this.orthoCamera.left = -width / 2;
65 | this.orthoCamera.right = width / 2;
66 | this.orthoCamera.top = height / 2;
67 | this.orthoCamera.bottom = -height / 2;
68 | this.orthoCamera.updateProjectionMatrix();
69 | }
70 | }
71 |
72 | export { ShaderPass };
73 |
--------------------------------------------------------------------------------
/modules/shader-ping-pong-pass.js:
--------------------------------------------------------------------------------
1 | import {
2 | Scene,
3 | WebGLRenderTarget,
4 | RepeatWrapping,
5 | LinearFilter,
6 | LinearMipMapLinearFilter,
7 | RGBAFormat,
8 | UnsignedByteType,
9 | OrthographicCamera,
10 | PlaneBufferGeometry,
11 | Mesh
12 | } from "../third_party/three.module.js";
13 |
14 | class ShaderPingPongPass {
15 | constructor(
16 | renderer,
17 | shader,
18 | width,
19 | height,
20 | format,
21 | type,
22 | minFilter,
23 | magFilter,
24 | wrapS,
25 | wrapT
26 | ) {
27 | this.renderer = renderer;
28 | this.shader = shader;
29 | this.orthoScene = new Scene();
30 | this.fbo = new WebGLRenderTarget(width, height, {
31 | wrapS: wrapS || RepeatWrapping,
32 | wrapT: wrapT || RepeatWrapping,
33 | minFilter: minFilter || LinearMipMapLinearFilter,
34 | magFilter: magFilter || LinearFilter,
35 | format: format || RGBAFormat,
36 | type: type || UnsignedByteType
37 | });
38 | this.fbos = [this.fbo, this.fbo.clone()];
39 | this.currentFBO = 0;
40 | this.orthoCamera = new OrthographicCamera(
41 | width / -2,
42 | width / 2,
43 | height / 2,
44 | height / -2,
45 | 0.00001,
46 | 1000
47 | );
48 | this.orthoQuad = new Mesh(new PlaneBufferGeometry(1, 1), this.shader);
49 | this.orthoQuad.scale.set(width, height, 1);
50 | this.orthoScene.add(this.orthoQuad);
51 | this.texture = this.fbo.texture;
52 | this.width = 1;
53 | this.height = 1;
54 | }
55 |
56 | render(final) {
57 | this.renderer.setRenderTarget(
58 | final ? null : this.fbos[1 - this.currentFBO]
59 | );
60 | this.renderer.render(this.orthoScene, this.orthoCamera);
61 | this.currentFBO = 1 - this.currentFBO;
62 | }
63 |
64 | setSize(width, height) {
65 | this.orthoQuad.scale.set(width, height, 1);
66 |
67 | this.fbos[0].setSize(width, height);
68 | this.fbos[1].setSize(width, height);
69 |
70 | this.orthoQuad.scale.set(width, height, 1);
71 |
72 | this.orthoCamera.left = -width / 2;
73 | this.orthoCamera.right = width / 2;
74 | this.orthoCamera.top = height / 2;
75 | this.orthoCamera.bottom = -height / 2;
76 | this.orthoCamera.updateProjectionMatrix();
77 |
78 | this.width = width;
79 | this.height = height;
80 | }
81 | }
82 |
83 | export { ShaderPingPongPass };
84 |
--------------------------------------------------------------------------------
/modules/wrapping-paper.js:
--------------------------------------------------------------------------------
1 | import { Maf } from "./maf.js";
2 |
3 | class WrappingPaper {
4 | constructor(w = 1024, h = 1024) {
5 | this.width = w;
6 | this.height = h;
7 |
8 | this.colorCanvas = document.createElement("canvas");
9 | this.colorCanvas.width = w;
10 | this.colorCanvas.height = h;
11 | this.colorCtx = this.colorCanvas.getContext("2d");
12 | this.roughnessCanvas = document.createElement("canvas");
13 | this.roughnessCanvas.width = w;
14 | this.roughnessCanvas.height = h;
15 | this.roughnessCtx = this.roughnessCanvas.getContext("2d");
16 | this.metalnessCanvas = document.createElement("canvas");
17 | this.metalnessCanvas.width = w;
18 | this.metalnessCanvas.height = h;
19 | this.metalnessCtx = this.metalnessCanvas.getContext("2d");
20 |
21 | // document.body.appendChild(this.colorCanvas);
22 | // document.body.appendChild(this.roughnessCanvas);
23 |
24 | this.contexts = [this.colorCtx, this.roughnessCtx, this.metalnessCtx];
25 | }
26 |
27 | clearRect(originX, originY, width, height) {
28 | for (var i = 0; i < this.contexts.length; i++) {
29 | this.contexts[i].clearRect(originX, originY, width, height);
30 | }
31 | }
32 |
33 | drawRect(originX, originY, width, height, color, opts) {
34 | /* opts example
35 | opts = {
36 | strokeColor: "#fff",
37 | lineWidth: 10,
38 | specularColor: "#000",
39 | specularContext: ctxs
40 | };
41 | */
42 | var contexts = [this.colorCtx];
43 | var colors = [];
44 | if (color) colors[0] = color;
45 | else colors[0] = "#000";
46 | if (opts && this.roughnessCtx) {
47 | contexts[1] = this.roughnessCtx;
48 | if (opts.specularColor) colors[1] = opts.specularColor;
49 | else colors[1] = "#000";
50 | }
51 |
52 | for (var i = 0; i < contexts.length; i++) {
53 | contexts[i].fillStyle = colors[i];
54 | contexts[i].fillRect(originX, originY, width, height);
55 | }
56 | }
57 |
58 | drawArc(centerX, centerY, radius, start_radians, radians, color, opts) {
59 | var contexts = [this.colorCtx];
60 | var colors = [];
61 | if (color) colors[0] = this.hexToRgb(color);
62 | else colors[0] = this.hexToRgb("#000");
63 | var lineWidth = 10;
64 | if (radians === undefined) var radians = Math.PI / 2;
65 | if (opts && this.roughnessCtx) {
66 | contexts[1] = this.roughnessCtx;
67 | if (opts.specularColor) colors[1] = this.hexToRgb(opts.specularColor);
68 | else colors[1] = this.hexToRgb("#000");
69 | if (opts.lineWidth) lineWidth = opts.lineWidth;
70 | else lineWidth = 10;
71 | }
72 |
73 | for (var i = 0; i < contexts.length; i++) {
74 | contexts[i].beginPath();
75 | contexts[i].lineWidth = lineWidth;
76 | contexts[i].lineCap = "round";
77 | contexts[i].arc(centerX, centerY, radius, start_radians, radians, false);
78 | contexts[i].strokeStyle =
79 | "rgba(" + colors[i].r + "," + colors[i].g + "," + colors[i].b + ",1)";
80 | contexts[i].stroke();
81 | }
82 | }
83 |
84 | drawCircle(centerX, centerY, radius, color, opts) {
85 | var colors = [];
86 | var alpha = 1.0;
87 | if (color) colors[0] = this.hexToRgb(color);
88 | else colors[0] = this.hexToRgb("#000");
89 | const contexts = [this.colorCtx];
90 | if (opts) {
91 | contexts.push(this.roughnessCtx);
92 | if (opts.specularColor) colors[1] = this.hexToRgb(opts.specularColor);
93 | else colors[1] = this.hexToRgb("#000");
94 | if (opts.alpha) alpha = opts.alpha;
95 | else alpha = 1.0;
96 | }
97 |
98 | for (var i = 0; i < contexts.length; i++) {
99 | contexts[i].beginPath();
100 | contexts[i].arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
101 | contexts[i].fillStyle =
102 | "rgba(" +
103 | colors[i].r +
104 | "," +
105 | colors[i].g +
106 | "," +
107 | colors[i].b +
108 | "," +
109 | alpha +
110 | ")";
111 | contexts[i].fill();
112 | }
113 | }
114 |
115 | hexToRgb(hex) {
116 | // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
117 | var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
118 | hex = hex.replace(shorthandRegex, function(m, r, g, b) {
119 | return r + r + g + g + b + b;
120 | });
121 |
122 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
123 | return result
124 | ? {
125 | r: parseInt(result[1], 16),
126 | g: parseInt(result[2], 16),
127 | b: parseInt(result[3], 16)
128 | }
129 | : null;
130 | }
131 | }
132 |
133 | export { WrappingPaper };
134 |
--------------------------------------------------------------------------------
/paper.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | XMasXP 2018
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/preview.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/preview.jpg
--------------------------------------------------------------------------------
/shaders/blur-fs.js:
--------------------------------------------------------------------------------
1 | import { blur5 } from "./fast-separable-gaussian-blur.js";
2 |
3 | const fs = `
4 | precision highp float;
5 |
6 | uniform vec2 resolution;
7 | uniform sampler2D inputTexture;
8 | uniform vec2 direction;
9 |
10 | varying vec2 vUv;
11 |
12 | ${blur5}
13 |
14 | void main() {
15 | gl_FragColor = blur5(inputTexture, vUv, resolution, direction);
16 | }`;
17 |
18 | export { fs };
19 |
--------------------------------------------------------------------------------
/shaders/combine-fs.js:
--------------------------------------------------------------------------------
1 | import screen from './screen.js';
2 | import softLight from './soft-light.js';
3 |
4 | const fs = `
5 | precision highp float;
6 |
7 | uniform vec2 resolution;
8 |
9 | uniform sampler2D inputTexture;
10 | uniform sampler2D blur1Texture;
11 | uniform sampler2D blur2Texture;
12 | uniform sampler2D blur3Texture;
13 | uniform sampler2D blur4Texture;
14 | uniform sampler2D blur5Texture;
15 | uniform sampler2D depthTexture;
16 |
17 | varying vec2 vUv;
18 |
19 | ${screen}
20 | ${softLight}
21 |
22 | void main() {
23 | vec4 color = texture2D(inputTexture, vUv);
24 | vec4 bloom = vec4(0.);
25 | bloom += 1. *texture2D( blur1Texture, vUv );
26 | bloom += 1.2 * texture2D( blur2Texture, vUv );
27 | bloom += 1.4 * texture2D( blur3Texture, vUv );
28 | bloom += 1.6 * texture2D( blur4Texture, vUv );
29 | bloom += 1.8 * texture2D( blur5Texture, vUv );
30 |
31 | vec4 finalColor = color;
32 | //finalColor = finalColor + .25 * bloom;
33 | finalColor = screen(finalColor,bloom,.25);
34 | gl_FragColor = finalColor;
35 | }
36 | `;
37 |
38 | export { fs };
--------------------------------------------------------------------------------
/shaders/depth-fs.js:
--------------------------------------------------------------------------------
1 | const fs = `
2 | precision highp float;
3 |
4 | varying float vDepth;
5 |
6 | void main() {
7 | gl_FragColor = vec4(vDepth);
8 | }
9 | `;
10 |
11 | export { fs };
--------------------------------------------------------------------------------
/shaders/depth-vs.js:
--------------------------------------------------------------------------------
1 | const vs = `
2 | precision highp float;
3 | attribute vec3 position;
4 |
5 | uniform mat4 modelViewMatrix;
6 | uniform mat4 projectionMatrix;
7 | uniform vec3 cameraPosition;
8 |
9 | varying float vDepth;
10 |
11 | void main() {
12 | vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
13 | float l = length(cameraPosition);
14 | vDepth = abs(-mvPosition.z-l) / abs(l);
15 | vDepth = .1+ .9*vDepth;
16 | gl_Position = projectionMatrix * mvPosition;
17 | }
18 | `;
19 |
20 | export { vs };
--------------------------------------------------------------------------------
/shaders/dof-fs.js:
--------------------------------------------------------------------------------
1 | import { blur5 } from './fast-separable-gaussian-blur.js';
2 |
3 | const fs = `
4 | precision highp float;
5 |
6 | uniform sampler2D inputTexture;
7 | uniform sampler2D depthTexture;
8 |
9 | uniform vec2 resolution;
10 | uniform vec2 direction;
11 |
12 | varying vec2 vUv;
13 |
14 | ${blur5}
15 |
16 | void main() {
17 | float depth = texture2D(depthTexture, vUv).r;
18 | float r = 2. * clamp(smoothstep(.25,.75,clamp(abs(depth-.25),0.,1.)), 0., 1.);
19 | if(r>1.) {
20 | gl_FragColor = blur5(inputTexture, vUv, resolution, r * direction);
21 | } else {
22 | gl_FragColor = texture2D(inputTexture, vUv);
23 | }
24 | }`;
25 |
26 | export { fs };
--------------------------------------------------------------------------------
/shaders/fast-separable-gaussian-blur.js:
--------------------------------------------------------------------------------
1 | const blur5 = `
2 | vec4 blur5(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
3 | vec4 color = vec4(0.0);
4 | vec2 off1 = vec2(1.3333333333333333) * direction;
5 | color += texture2D(image, uv) * 0.29411764705882354;
6 | color += texture2D(image, uv + (off1 / resolution)) * 0.35294117647058826;
7 | color += texture2D(image, uv - (off1 / resolution)) * 0.35294117647058826;
8 | return color;
9 | }`;
10 |
11 | const blur9 = `
12 | vec4 blur9(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
13 | vec4 color = vec4(0.0);
14 | vec2 off1 = vec2(1.3846153846) * direction;
15 | vec2 off2 = vec2(3.2307692308) * direction;
16 | color += texture2D(image, uv) * 0.2270270270;
17 | color += texture2D(image, uv + (off1 / resolution)) * 0.3162162162;
18 | color += texture2D(image, uv - (off1 / resolution)) * 0.3162162162;
19 | color += texture2D(image, uv + (off2 / resolution)) * 0.0702702703;
20 | color += texture2D(image, uv - (off2 / resolution)) * 0.0702702703;
21 | return color;
22 | }`;
23 |
24 | const blur13 = `
25 | vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
26 | vec4 color = vec4(0.0);
27 | vec2 off1 = vec2(1.411764705882353) * direction;
28 | vec2 off2 = vec2(3.2941176470588234) * direction;
29 | vec2 off3 = vec2(5.176470588235294) * direction;
30 | color += texture2D(image, uv) * 0.1964825501511404;
31 | color += texture2D(image, uv + (off1 / resolution)) * 0.2969069646728344;
32 | color += texture2D(image, uv - (off1 / resolution)) * 0.2969069646728344;
33 | color += texture2D(image, uv + (off2 / resolution)) * 0.09447039785044732;
34 | color += texture2D(image, uv - (off2 / resolution)) * 0.09447039785044732;
35 | color += texture2D(image, uv + (off3 / resolution)) * 0.010381362401148057;
36 | color += texture2D(image, uv - (off3 / resolution)) * 0.010381362401148057;
37 | return color;
38 | }
39 | `;
40 |
41 | export {blur5, blur9, blur13};
42 |
--------------------------------------------------------------------------------
/shaders/final-color-fs.js:
--------------------------------------------------------------------------------
1 | import fxaa from './fxaa.js';
2 | import grayscale from './grayscale.js';
3 | import overlay from './overlay.js';
4 | import random from './random.js';
5 |
6 | const fs = `
7 | precision highp float;
8 |
9 | uniform vec2 resolution;
10 | uniform float time;
11 |
12 | uniform sampler2D inputTexture;
13 |
14 | varying vec2 vUv;
15 | ${fxaa}
16 | ${grayscale}
17 | ${overlay}
18 | ${random}
19 |
20 | void main() {
21 | vec4 color = fxaa(inputTexture, vUv);
22 | color = overlay(color,vec4(random(vec3(vUv,0.),time)),.1);
23 | gl_FragColor = color;//vec4(grayscale(color));
24 | }
25 | `;
26 |
27 | export { fs };
--------------------------------------------------------------------------------
/shaders/final-fs.js:
--------------------------------------------------------------------------------
1 | import vignette from './vignette.js';
2 | import softLight from './soft-light.js';
3 | import screen from './screen.js';
4 | import { gammaCorrect, levelRange, finalLevels } from './levels.js';
5 | import fxaa from './fxaa.js';
6 | import rgbShift from './rgb-shift.js';
7 |
8 | const fs = `
9 | precision highp float;
10 |
11 | uniform vec2 resolution;
12 |
13 | uniform sampler2D inputTexture;
14 | uniform float vignetteBoost;
15 | uniform float vignetteReduction;
16 |
17 | varying vec2 vUv;
18 | ${vignette}
19 | ${softLight}
20 | ${screen}
21 | ${gammaCorrect}
22 | ${levelRange}
23 | ${finalLevels}
24 | ${rgbShift}
25 |
26 | void main() {
27 | vec4 color = rgbShift(inputTexture, vUv, resolution/80.);
28 | vec4 v = vec4(vec3(vignette(vUv, vignetteBoost, vignetteReduction)),1.);
29 | vec4 finalColor = softLight(color, v);
30 | finalColor.rgb = finalLevels(finalColor.rgb, vec3(20.) / 255., vec3(1.), vec3(235.)/ 255.);
31 | gl_FragColor = finalColor;
32 | }
33 | `;
34 |
35 | export { fs };
--------------------------------------------------------------------------------
/shaders/fxaa.js:
--------------------------------------------------------------------------------
1 | const fxaa = `
2 |
3 | #define FXAA_REDUCE_MIN (1.0/128.0)
4 | #define FXAA_REDUCE_MUL (1.0/8.0)
5 | #define FXAA_SPAN_MAX 8.0
6 |
7 | vec4 fxaa(sampler2D tex, vec2 uv) {
8 |
9 | vec2 res = 1. / resolution;
10 |
11 | vec3 rgbNW = texture2D( tex, ( uv.xy + vec2( -1.0, -1.0 ) * res ) ).xyz;
12 | vec3 rgbNE = texture2D( tex, ( uv.xy + vec2( 1.0, -1.0 ) * res ) ).xyz;
13 | vec3 rgbSW = texture2D( tex, ( uv.xy + vec2( -1.0, 1.0 ) * res ) ).xyz;
14 | vec3 rgbSE = texture2D( tex, ( uv.xy + vec2( 1.0, 1.0 ) * res ) ).xyz;
15 | vec4 rgbaM = texture2D( tex, uv.xy * res );
16 | vec3 rgbM = rgbaM.xyz;
17 | vec3 luma = vec3( 0.299, 0.587, 0.114 );
18 |
19 | float lumaNW = dot( rgbNW, luma );
20 | float lumaNE = dot( rgbNE, luma );
21 | float lumaSW = dot( rgbSW, luma );
22 | float lumaSE = dot( rgbSE, luma );
23 | float lumaM = dot( rgbM, luma );
24 | float lumaMin = min( lumaM, min( min( lumaNW, lumaNE ), min( lumaSW, lumaSE ) ) );
25 | float lumaMax = max( lumaM, max( max( lumaNW, lumaNE) , max( lumaSW, lumaSE ) ) );
26 |
27 | vec2 dir;
28 | dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
29 | dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
30 |
31 | float dirReduce = max( ( lumaNW + lumaNE + lumaSW + lumaSE ) * ( 0.25 * FXAA_REDUCE_MUL ), FXAA_REDUCE_MIN );
32 |
33 | float rcpDirMin = 1.0 / ( min( abs( dir.x ), abs( dir.y ) ) + dirReduce );
34 | dir = min( vec2( FXAA_SPAN_MAX, FXAA_SPAN_MAX),
35 | max( vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
36 | dir * rcpDirMin)) * res;
37 | vec4 rgbA = (1.0/2.0) * (
38 | texture2D(tex, uv.xy + dir * (1.0/3.0 - 0.5)) +
39 | texture2D(tex, uv.xy + dir * (2.0/3.0 - 0.5)));
40 | vec4 rgbB = rgbA * (1.0/2.0) + (1.0/4.0) * (
41 | texture2D(tex, uv.xy + dir * (0.0/3.0 - 0.5)) +
42 | texture2D(tex, uv.xy + dir * (3.0/3.0 - 0.5)));
43 | float lumaB = dot(rgbB, vec4(luma, 0.0));
44 |
45 | if ( ( lumaB < lumaMin ) || ( lumaB > lumaMax ) ) {
46 | return rgbA;
47 | } else {
48 | return rgbB;
49 | }
50 |
51 | }
52 | `;
53 |
54 | export default fxaa;
55 |
--------------------------------------------------------------------------------
/shaders/grayscale.js:
--------------------------------------------------------------------------------
1 | const grayscale = `
2 | float grayscale(vec3 color) {
3 | return dot(color.rgb, vec3(0.299, 0.587, 0.114));
4 | }
5 |
6 | float grayscale(vec4 color) {
7 | return dot(color.rgb, vec3(0.299, 0.587, 0.114));
8 | }`;
9 |
10 | export default grayscale;
--------------------------------------------------------------------------------
/shaders/highlight-fs.js:
--------------------------------------------------------------------------------
1 | import grayscale from './grayscale.js';
2 |
3 | const fs = `
4 | precision highp float;
5 |
6 | uniform sampler2D inputTexture;
7 |
8 | varying vec2 vUv;
9 |
10 | ${grayscale}
11 |
12 | void main() {
13 | vec4 color = texture2D(inputTexture, vUv);
14 | gl_FragColor = vec4(smoothstep(.7, 1., grayscale(color)));
15 | }
16 | `;
17 |
18 | export { fs };
--------------------------------------------------------------------------------
/shaders/levels.js:
--------------------------------------------------------------------------------
1 | const gammaCorrect = `
2 | vec3 gammaCorrect(vec3 color, vec3 gamma){
3 | return pow(color, 1.0/gamma);
4 | }`;
5 |
6 | const levelRange = `
7 | vec3 levelRange(vec3 color, vec3 minInput, vec3 maxInput){
8 | return min(max(color - minInput, vec3(0.0)) / (maxInput - minInput), vec3(1.0));
9 | }`;
10 |
11 | const finalLevels = `
12 | vec3 finalLevels(vec3 color, vec3 minInput, vec3 gamma, vec3 maxInput){
13 | return gammaCorrect(levelRange(color, minInput, maxInput), gamma);
14 | }`;
15 |
16 | export { gammaCorrect, levelRange, finalLevels };
--------------------------------------------------------------------------------
/shaders/ortho.js:
--------------------------------------------------------------------------------
1 | const turbulence = `
2 | precision highp float;
3 |
4 | attribute vec3 position;
5 | attribute vec2 uv;
6 |
7 | uniform mat4 modelViewMatrix;
8 | uniform mat4 projectionMatrix;
9 |
10 | varying vec2 vUv;
11 |
12 | void main() {
13 | vUv = uv;
14 | gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1. );
15 | }`;
16 |
17 | export default turbulence;
18 |
--------------------------------------------------------------------------------
/shaders/overlay.js:
--------------------------------------------------------------------------------
1 | const overlay = `
2 | float applyOverlayToChannel( float base, float blend ) {
3 | return (base < 0.5 ? (2.0 * base * blend) : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend)));
4 | }
5 |
6 | vec4 overlay(vec4 base, vec4 blend, float opacity) {
7 | vec4 color = vec4(
8 | applyOverlayToChannel( base.r, blend.r ),
9 | applyOverlayToChannel( base.g, blend.g ),
10 | applyOverlayToChannel( base.b, blend.b ),
11 | applyOverlayToChannel( base.a, blend.a )
12 | );
13 | return color * opacity + base * ( 1. - opacity );
14 | }
15 |
16 | `;
17 |
18 | export default overlay;
19 |
--------------------------------------------------------------------------------
/shaders/random.js:
--------------------------------------------------------------------------------
1 | const random = `
2 | float random(vec3 scale,float seed){
3 | return fract(sin(dot(gl_FragCoord.xyz+seed,scale))*43758.5453+seed);
4 | }
5 | `;
6 |
7 | export default random;
--------------------------------------------------------------------------------
/shaders/rgb-shift.js:
--------------------------------------------------------------------------------
1 | import smootherstep from './smootherstep.js';
2 |
3 | const rgbShift = `
4 | ${smootherstep}
5 |
6 | vec4 rgbShift(sampler2D inputTexture, vec2 uv, vec2 delta){
7 |
8 | vec2 dir = uv - vec2( .5 );
9 | float d = .7 * length( dir );
10 | normalize( dir );
11 | vec2 value = d * dir * delta;
12 |
13 | vec4 c1 = texture2D( inputTexture, uv - value / resolution.x );
14 | vec4 c2 = texture2D( inputTexture, uv );
15 | vec4 c3 = texture2D( inputTexture, uv + value / resolution.y );
16 |
17 | return vec4( c1.r, c2.g, c3.b, c1.a + c2.a + c3.b );
18 |
19 | }
20 | `;
21 |
22 | export default rgbShift;
--------------------------------------------------------------------------------
/shaders/screen.js:
--------------------------------------------------------------------------------
1 | const screen = `
2 | vec4 screen(vec4 base, vec4 blend, float opacity) {
3 | vec4 color = 1. - (1.-base) * (1.-blend);
4 | color = color * opacity + base * ( 1. - opacity );
5 | return color;
6 | }`;
7 |
8 | export default screen;
--------------------------------------------------------------------------------
/shaders/smootherstep.js:
--------------------------------------------------------------------------------
1 | const smootherstep = `
2 | float smootherstep(float edge0, float edge1, float x) {
3 | x = clamp((x - edge0)/(edge1 - edge0), 0.0, 1.0);
4 | return x*x*x*(x*(x*6. - 15.) + 10.);
5 | }
6 | `;
7 |
8 | export default smootherstep;
9 |
--------------------------------------------------------------------------------
/shaders/soft-light.js:
--------------------------------------------------------------------------------
1 | const softLight = `
2 | float applySoftLightToChannel( float base, float blend ) {
3 | return ((blend < 0.5) ? (2.0 * base * blend + base * base * (1.0 - 2.0 * blend)) : (sqrt(base) * (2.0 * blend - 1.0) + 2.0 * base * (1.0 - blend)));
4 | }
5 |
6 | vec4 softLight(vec4 base, vec4 blend) {
7 | vec4 color = vec4(
8 | applySoftLightToChannel( base.r, blend.r ),
9 | applySoftLightToChannel( base.g, blend.g ),
10 | applySoftLightToChannel( base.b, blend.b ),
11 | applySoftLightToChannel( base.a, blend.a )
12 | );
13 | return color;
14 | }`;
15 |
16 | export default softLight;
17 |
--------------------------------------------------------------------------------
/shaders/vignette.js:
--------------------------------------------------------------------------------
1 | const vignette = `
2 | float vignette(vec2 uv, float boost, float reduction) {
3 | vec2 position = vUv - .5;
4 | return boost - length(position) * reduction;
5 | }
6 | `;
7 |
8 | export default vignette;
9 |
--------------------------------------------------------------------------------
/test.js:
--------------------------------------------------------------------------------
1 | import { Paper } from './modules/paper15.js';
2 |
3 | const paper = new Paper(512, 512);
4 | document.body.appendChild(paper.colorCanvas);
5 | document.body.appendChild(paper.roughnessCanvas);
--------------------------------------------------------------------------------
/third_party/THREE.OrbitControls.js:
--------------------------------------------------------------------------------
1 | import * as THREE from './three.module.js';
2 |
3 | /**
4 | * @author qiao / https://github.com/qiao
5 | * @author mrdoob / http://mrdoob.com
6 | * @author alteredq / http://alteredqualia.com/
7 | * @author WestLangley / http://github.com/WestLangley
8 | * @author erich666 / http://erichaines.com
9 | */
10 |
11 | // This set of controls performs orbiting, dollying (zooming), and panning.
12 | // Unlike TrackballControls, it maintains the "up" direction object.up (+Y by default).
13 | //
14 | // Orbit - left mouse / touch: one-finger move
15 | // Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish
16 | // Pan - right mouse, or left mouse + ctrl/metaKey, or arrow keys / touch: two-finger move
17 |
18 | const OrbitControls = function(object, domElement) {
19 |
20 | this.object = object;
21 |
22 | this.domElement = (domElement !== undefined) ? domElement : document;
23 |
24 | // Set to false to disable this control
25 | this.enabled = true;
26 |
27 | // "target" sets the location of focus, where the object orbits around
28 | this.target = new THREE.Vector3();
29 |
30 | // How far you can dolly in and out ( PerspectiveCamera only )
31 | this.minDistance = 0;
32 | this.maxDistance = Infinity;
33 |
34 | // How far you can zoom in and out ( OrthographicCamera only )
35 | this.minZoom = 0;
36 | this.maxZoom = Infinity;
37 |
38 | // How far you can orbit vertically, upper and lower limits.
39 | // Range is 0 to Math.PI radians.
40 | this.minPolarAngle = 0; // radians
41 | this.maxPolarAngle = Math.PI; // radians
42 |
43 | // How far you can orbit horizontally, upper and lower limits.
44 | // If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
45 | this.minAzimuthAngle = -Infinity; // radians
46 | this.maxAzimuthAngle = Infinity; // radians
47 |
48 | // Set to true to enable damping (inertia)
49 | // If damping is enabled, you must call controls.update() in your animation loop
50 | this.enableDamping = false;
51 | this.dampingFactor = 0.25;
52 |
53 | // This option actually enables dollying in and out; left as "zoom" for backwards compatibility.
54 | // Set to false to disable zooming
55 | this.enableZoom = true;
56 | this.zoomSpeed = 1.0;
57 |
58 | // Set to false to disable rotating
59 | this.enableRotate = true;
60 | this.rotateSpeed = 1.0;
61 |
62 | // Set to false to disable panning
63 | this.enablePan = true;
64 | this.panSpeed = 1.0;
65 | this.screenSpacePanning = false; // if true, pan in screen-space
66 | this.keyPanSpeed = 7.0; // pixels moved per arrow key push
67 |
68 | // Set to true to automatically rotate around the target
69 | // If auto-rotate is enabled, you must call controls.update() in your animation loop
70 | this.autoRotate = false;
71 | this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
72 |
73 | // Set to false to disable use of the keys
74 | this.enableKeys = true;
75 |
76 | // The four arrow keys
77 | this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
78 |
79 | // Mouse buttons
80 | this.mouseButtons = { LEFT: THREE.MOUSE.LEFT, MIDDLE: THREE.MOUSE.MIDDLE, RIGHT: THREE.MOUSE.RIGHT };
81 |
82 | // for reset
83 | this.target0 = this.target.clone();
84 | this.position0 = this.object.position.clone();
85 | this.zoom0 = this.object.zoom;
86 |
87 | //
88 | // public methods
89 | //
90 |
91 | this.getPolarAngle = function() {
92 |
93 | return spherical.phi;
94 |
95 | };
96 |
97 | this.getAzimuthalAngle = function() {
98 |
99 | return spherical.theta;
100 |
101 | };
102 |
103 | this.saveState = function() {
104 |
105 | scope.target0.copy(scope.target);
106 | scope.position0.copy(scope.object.position);
107 | scope.zoom0 = scope.object.zoom;
108 |
109 | };
110 |
111 | this.reset = function() {
112 |
113 | scope.target.copy(scope.target0);
114 | scope.object.position.copy(scope.position0);
115 | scope.object.zoom = scope.zoom0;
116 |
117 | scope.object.updateProjectionMatrix();
118 | scope.dispatchEvent(changeEvent);
119 |
120 | scope.update();
121 |
122 | state = STATE.NONE;
123 |
124 | };
125 |
126 | // this method is exposed, but perhaps it would be better if we can make it private...
127 | this.update = function() {
128 |
129 | var offset = new THREE.Vector3();
130 |
131 | // so camera.up is the orbit axis
132 | var quat = new THREE.Quaternion().setFromUnitVectors(object.up, new THREE.Vector3(0, 1, 0));
133 | var quatInverse = quat.clone().inverse();
134 |
135 | var lastPosition = new THREE.Vector3();
136 | var lastQuaternion = new THREE.Quaternion();
137 |
138 | return function update() {
139 |
140 | var position = scope.object.position;
141 |
142 | offset.copy(position).sub(scope.target);
143 |
144 | // rotate offset to "y-axis-is-up" space
145 | offset.applyQuaternion(quat);
146 |
147 | // angle from z-axis around y-axis
148 | spherical.setFromVector3(offset);
149 |
150 | if (scope.autoRotate && state === STATE.NONE) {
151 |
152 | rotateLeft(getAutoRotationAngle());
153 |
154 | }
155 |
156 | spherical.theta += sphericalDelta.theta;
157 | spherical.phi += sphericalDelta.phi;
158 |
159 | // restrict theta to be between desired limits
160 | spherical.theta = Math.max(scope.minAzimuthAngle, Math.min(scope.maxAzimuthAngle, spherical.theta));
161 |
162 | // restrict phi to be between desired limits
163 | spherical.phi = Math.max(scope.minPolarAngle, Math.min(scope.maxPolarAngle, spherical.phi));
164 |
165 | spherical.makeSafe();
166 |
167 |
168 | spherical.radius *= scale;
169 |
170 | // restrict radius to be between desired limits
171 | spherical.radius = Math.max(scope.minDistance, Math.min(scope.maxDistance, spherical.radius));
172 |
173 | // move target to panned location
174 | scope.target.add(panOffset);
175 |
176 | offset.setFromSpherical(spherical);
177 |
178 | // rotate offset back to "camera-up-vector-is-up" space
179 | offset.applyQuaternion(quatInverse);
180 |
181 | position.copy(scope.target).add(offset);
182 |
183 | scope.object.lookAt(scope.target);
184 |
185 | if (scope.enableDamping === true) {
186 |
187 | sphericalDelta.theta *= (1 - scope.dampingFactor);
188 | sphericalDelta.phi *= (1 - scope.dampingFactor);
189 |
190 | panOffset.multiplyScalar(1 - scope.dampingFactor);
191 |
192 | } else {
193 |
194 | sphericalDelta.set(0, 0, 0);
195 |
196 | panOffset.set(0, 0, 0);
197 |
198 | }
199 |
200 | scale = 1;
201 |
202 | // update condition is:
203 | // min(camera displacement, camera rotation in radians)^2 > EPS
204 | // using small-angle approximation cos(x/2) = 1 - x^2 / 8
205 |
206 | if (zoomChanged ||
207 | lastPosition.distanceToSquared(scope.object.position) > EPS ||
208 | 8 * (1 - lastQuaternion.dot(scope.object.quaternion)) > EPS) {
209 |
210 | scope.dispatchEvent(changeEvent);
211 |
212 | lastPosition.copy(scope.object.position);
213 | lastQuaternion.copy(scope.object.quaternion);
214 | zoomChanged = false;
215 |
216 | return true;
217 |
218 | }
219 |
220 | return false;
221 |
222 | };
223 |
224 | }();
225 |
226 | this.dispose = function() {
227 |
228 | scope.domElement.removeEventListener('contextmenu', onContextMenu, false);
229 | scope.domElement.removeEventListener('mousedown', onMouseDown, false);
230 | scope.domElement.removeEventListener('wheel', onMouseWheel, false);
231 |
232 | scope.domElement.removeEventListener('touchstart', onTouchStart, false);
233 | scope.domElement.removeEventListener('touchend', onTouchEnd, false);
234 | scope.domElement.removeEventListener('touchmove', onTouchMove, false);
235 |
236 | document.removeEventListener('mousemove', onMouseMove, false);
237 | document.removeEventListener('mouseup', onMouseUp, false);
238 |
239 | window.removeEventListener('keydown', onKeyDown, false);
240 |
241 | //scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?
242 |
243 | };
244 |
245 | //
246 | // internals
247 | //
248 |
249 | var scope = this;
250 |
251 | var changeEvent = { type: 'change' };
252 | var startEvent = { type: 'start' };
253 | var endEvent = { type: 'end' };
254 |
255 | var STATE = { NONE: -1, ROTATE: 0, DOLLY: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_DOLLY_PAN: 4 };
256 |
257 | var state = STATE.NONE;
258 |
259 | var EPS = 0.000001;
260 |
261 | // current position in spherical coordinates
262 | var spherical = new THREE.Spherical();
263 | var sphericalDelta = new THREE.Spherical();
264 |
265 | var scale = 1;
266 | var panOffset = new THREE.Vector3();
267 | var zoomChanged = false;
268 |
269 | var rotateStart = new THREE.Vector2();
270 | var rotateEnd = new THREE.Vector2();
271 | var rotateDelta = new THREE.Vector2();
272 |
273 | var panStart = new THREE.Vector2();
274 | var panEnd = new THREE.Vector2();
275 | var panDelta = new THREE.Vector2();
276 |
277 | var dollyStart = new THREE.Vector2();
278 | var dollyEnd = new THREE.Vector2();
279 | var dollyDelta = new THREE.Vector2();
280 |
281 | function getAutoRotationAngle() {
282 |
283 | return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
284 |
285 | }
286 |
287 | function getZoomScale() {
288 |
289 | return Math.pow(0.95, scope.zoomSpeed);
290 |
291 | }
292 |
293 | function rotateLeft(angle) {
294 |
295 | sphericalDelta.theta -= angle;
296 |
297 | }
298 |
299 | function rotateUp(angle) {
300 |
301 | sphericalDelta.phi -= angle;
302 |
303 | }
304 |
305 | var panLeft = function() {
306 |
307 | var v = new THREE.Vector3();
308 |
309 | return function panLeft(distance, objectMatrix) {
310 |
311 | v.setFromMatrixColumn(objectMatrix, 0); // get X column of objectMatrix
312 | v.multiplyScalar(-distance);
313 |
314 | panOffset.add(v);
315 |
316 | };
317 |
318 | }();
319 |
320 | var panUp = function() {
321 |
322 | var v = new THREE.Vector3();
323 |
324 | return function panUp(distance, objectMatrix) {
325 |
326 | if (scope.screenSpacePanning === true) {
327 |
328 | v.setFromMatrixColumn(objectMatrix, 1);
329 |
330 | } else {
331 |
332 | v.setFromMatrixColumn(objectMatrix, 0);
333 | v.crossVectors(scope.object.up, v);
334 |
335 | }
336 |
337 | v.multiplyScalar(distance);
338 |
339 | panOffset.add(v);
340 |
341 | };
342 |
343 | }();
344 |
345 | // deltaX and deltaY are in pixels; right and down are positive
346 | var pan = function() {
347 |
348 | var offset = new THREE.Vector3();
349 |
350 | return function pan(deltaX, deltaY) {
351 |
352 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
353 |
354 | if (scope.object.isPerspectiveCamera) {
355 |
356 | // perspective
357 | var position = scope.object.position;
358 | offset.copy(position).sub(scope.target);
359 | var targetDistance = offset.length();
360 |
361 | // half of the fov is center to top of screen
362 | targetDistance *= Math.tan((scope.object.fov / 2) * Math.PI / 180.0);
363 |
364 | // we use only clientHeight here so aspect ratio does not distort speed
365 | panLeft(2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix);
366 | panUp(2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix);
367 |
368 | } else if (scope.object.isOrthographicCamera) {
369 |
370 | // orthographic
371 | panLeft(deltaX * (scope.object.right - scope.object.left) / scope.object.zoom / element.clientWidth, scope.object.matrix);
372 | panUp(deltaY * (scope.object.top - scope.object.bottom) / scope.object.zoom / element.clientHeight, scope.object.matrix);
373 |
374 | } else {
375 |
376 | // camera neither orthographic nor perspective
377 | console.warn('WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.');
378 | scope.enablePan = false;
379 |
380 | }
381 |
382 | };
383 |
384 | }();
385 |
386 | function dollyIn(dollyScale) {
387 |
388 | if (scope.object.isPerspectiveCamera) {
389 |
390 | scale /= dollyScale;
391 |
392 | } else if (scope.object.isOrthographicCamera) {
393 |
394 | scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom * dollyScale));
395 | scope.object.updateProjectionMatrix();
396 | zoomChanged = true;
397 |
398 | } else {
399 |
400 | console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
401 | scope.enableZoom = false;
402 |
403 | }
404 |
405 | }
406 |
407 | function dollyOut(dollyScale) {
408 |
409 | if (scope.object.isPerspectiveCamera) {
410 |
411 | scale *= dollyScale;
412 |
413 | } else if (scope.object.isOrthographicCamera) {
414 |
415 | scope.object.zoom = Math.max(scope.minZoom, Math.min(scope.maxZoom, scope.object.zoom / dollyScale));
416 | scope.object.updateProjectionMatrix();
417 | zoomChanged = true;
418 |
419 | } else {
420 |
421 | console.warn('WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.');
422 | scope.enableZoom = false;
423 |
424 | }
425 |
426 | }
427 |
428 | //
429 | // event callbacks - update the object state
430 | //
431 |
432 | function handleMouseDownRotate(event) {
433 |
434 | //console.log( 'handleMouseDownRotate' );
435 |
436 | rotateStart.set(event.clientX, event.clientY);
437 |
438 | }
439 |
440 | function handleMouseDownDolly(event) {
441 |
442 | //console.log( 'handleMouseDownDolly' );
443 |
444 | dollyStart.set(event.clientX, event.clientY);
445 |
446 | }
447 |
448 | function handleMouseDownPan(event) {
449 |
450 | //console.log( 'handleMouseDownPan' );
451 |
452 | panStart.set(event.clientX, event.clientY);
453 |
454 | }
455 |
456 | function handleMouseMoveRotate(event) {
457 |
458 | //console.log( 'handleMouseMoveRotate' );
459 |
460 | rotateEnd.set(event.clientX, event.clientY);
461 |
462 | rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
463 |
464 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
465 |
466 | rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height
467 |
468 | rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
469 |
470 | rotateStart.copy(rotateEnd);
471 |
472 | scope.update();
473 |
474 | }
475 |
476 | function handleMouseMoveDolly(event) {
477 |
478 | //console.log( 'handleMouseMoveDolly' );
479 |
480 | dollyEnd.set(event.clientX, event.clientY);
481 |
482 | dollyDelta.subVectors(dollyEnd, dollyStart);
483 |
484 | if (dollyDelta.y > 0) {
485 |
486 | dollyIn(getZoomScale());
487 |
488 | } else if (dollyDelta.y < 0) {
489 |
490 | dollyOut(getZoomScale());
491 |
492 | }
493 |
494 | dollyStart.copy(dollyEnd);
495 |
496 | scope.update();
497 |
498 | }
499 |
500 | function handleMouseMovePan(event) {
501 |
502 | //console.log( 'handleMouseMovePan' );
503 |
504 | panEnd.set(event.clientX, event.clientY);
505 |
506 | panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
507 |
508 | pan(panDelta.x, panDelta.y);
509 |
510 | panStart.copy(panEnd);
511 |
512 | scope.update();
513 |
514 | }
515 |
516 | function handleMouseUp(event) {
517 |
518 | // console.log( 'handleMouseUp' );
519 |
520 | }
521 |
522 | function handleMouseWheel(event) {
523 |
524 | // console.log( 'handleMouseWheel' );
525 |
526 | if (event.deltaY < 0) {
527 |
528 | dollyOut(getZoomScale());
529 |
530 | } else if (event.deltaY > 0) {
531 |
532 | dollyIn(getZoomScale());
533 |
534 | }
535 |
536 | scope.update();
537 |
538 | }
539 |
540 | function handleKeyDown(event) {
541 |
542 | //console.log( 'handleKeyDown' );
543 |
544 | switch (event.keyCode) {
545 |
546 | case scope.keys.UP:
547 | pan(0, scope.keyPanSpeed);
548 | scope.update();
549 | break;
550 |
551 | case scope.keys.BOTTOM:
552 | pan(0, -scope.keyPanSpeed);
553 | scope.update();
554 | break;
555 |
556 | case scope.keys.LEFT:
557 | pan(scope.keyPanSpeed, 0);
558 | scope.update();
559 | break;
560 |
561 | case scope.keys.RIGHT:
562 | pan(-scope.keyPanSpeed, 0);
563 | scope.update();
564 | break;
565 |
566 | }
567 |
568 | }
569 |
570 | function handleTouchStartRotate(event) {
571 |
572 | //console.log( 'handleTouchStartRotate' );
573 |
574 | rotateStart.set(event.touches[0].pageX, event.touches[0].pageY);
575 |
576 | }
577 |
578 | function handleTouchStartDollyPan(event) {
579 |
580 | //console.log( 'handleTouchStartDollyPan' );
581 |
582 | if (scope.enableZoom) {
583 |
584 | var dx = event.touches[0].pageX - event.touches[1].pageX;
585 | var dy = event.touches[0].pageY - event.touches[1].pageY;
586 |
587 | var distance = Math.sqrt(dx * dx + dy * dy);
588 |
589 | dollyStart.set(0, distance);
590 |
591 | }
592 |
593 | if (scope.enablePan) {
594 |
595 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
596 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
597 |
598 | panStart.set(x, y);
599 |
600 | }
601 |
602 | }
603 |
604 | function handleTouchMoveRotate(event) {
605 |
606 | //console.log( 'handleTouchMoveRotate' );
607 |
608 | rotateEnd.set(event.touches[0].pageX, event.touches[0].pageY);
609 |
610 | rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(scope.rotateSpeed);
611 |
612 | var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
613 |
614 | rotateLeft(2 * Math.PI * rotateDelta.x / element.clientHeight); // yes, height
615 |
616 | rotateUp(2 * Math.PI * rotateDelta.y / element.clientHeight);
617 |
618 | rotateStart.copy(rotateEnd);
619 |
620 | scope.update();
621 |
622 | }
623 |
624 | function handleTouchMoveDollyPan(event) {
625 |
626 | //console.log( 'handleTouchMoveDollyPan' );
627 |
628 | if (scope.enableZoom) {
629 |
630 | var dx = event.touches[0].pageX - event.touches[1].pageX;
631 | var dy = event.touches[0].pageY - event.touches[1].pageY;
632 |
633 | var distance = Math.sqrt(dx * dx + dy * dy);
634 |
635 | dollyEnd.set(0, distance);
636 |
637 | dollyDelta.set(0, Math.pow(dollyEnd.y / dollyStart.y, scope.zoomSpeed));
638 |
639 | dollyIn(dollyDelta.y);
640 |
641 | dollyStart.copy(dollyEnd);
642 |
643 | }
644 |
645 | if (scope.enablePan) {
646 |
647 | var x = 0.5 * (event.touches[0].pageX + event.touches[1].pageX);
648 | var y = 0.5 * (event.touches[0].pageY + event.touches[1].pageY);
649 |
650 | panEnd.set(x, y);
651 |
652 | panDelta.subVectors(panEnd, panStart).multiplyScalar(scope.panSpeed);
653 |
654 | pan(panDelta.x, panDelta.y);
655 |
656 | panStart.copy(panEnd);
657 |
658 | }
659 |
660 | scope.update();
661 |
662 | }
663 |
664 | function handleTouchEnd(event) {
665 |
666 | //console.log( 'handleTouchEnd' );
667 |
668 | }
669 |
670 | //
671 | // event handlers - FSM: listen for events and reset state
672 | //
673 |
674 | function onMouseDown(event) {
675 |
676 | if (scope.enabled === false) return;
677 |
678 | event.preventDefault();
679 |
680 | switch (event.button) {
681 |
682 | case scope.mouseButtons.LEFT:
683 |
684 | if (event.ctrlKey || event.metaKey) {
685 |
686 | if (scope.enablePan === false) return;
687 |
688 | handleMouseDownPan(event);
689 |
690 | state = STATE.PAN;
691 |
692 | } else {
693 |
694 | if (scope.enableRotate === false) return;
695 |
696 | handleMouseDownRotate(event);
697 |
698 | state = STATE.ROTATE;
699 |
700 | }
701 |
702 | break;
703 |
704 | case scope.mouseButtons.MIDDLE:
705 |
706 | if (scope.enableZoom === false) return;
707 |
708 | handleMouseDownDolly(event);
709 |
710 | state = STATE.DOLLY;
711 |
712 | break;
713 |
714 | case scope.mouseButtons.RIGHT:
715 |
716 | if (scope.enablePan === false) return;
717 |
718 | handleMouseDownPan(event);
719 |
720 | state = STATE.PAN;
721 |
722 | break;
723 |
724 | }
725 |
726 | if (state !== STATE.NONE) {
727 |
728 | document.addEventListener('mousemove', onMouseMove, false);
729 | document.addEventListener('mouseup', onMouseUp, false);
730 |
731 | scope.dispatchEvent(startEvent);
732 |
733 | }
734 |
735 | }
736 |
737 | function onMouseMove(event) {
738 |
739 | if (scope.enabled === false) return;
740 |
741 | event.preventDefault();
742 |
743 | switch (state) {
744 |
745 | case STATE.ROTATE:
746 |
747 | if (scope.enableRotate === false) return;
748 |
749 | handleMouseMoveRotate(event);
750 |
751 | break;
752 |
753 | case STATE.DOLLY:
754 |
755 | if (scope.enableZoom === false) return;
756 |
757 | handleMouseMoveDolly(event);
758 |
759 | break;
760 |
761 | case STATE.PAN:
762 |
763 | if (scope.enablePan === false) return;
764 |
765 | handleMouseMovePan(event);
766 |
767 | break;
768 |
769 | }
770 |
771 | }
772 |
773 | function onMouseUp(event) {
774 |
775 | if (scope.enabled === false) return;
776 |
777 | handleMouseUp(event);
778 |
779 | document.removeEventListener('mousemove', onMouseMove, false);
780 | document.removeEventListener('mouseup', onMouseUp, false);
781 |
782 | scope.dispatchEvent(endEvent);
783 |
784 | state = STATE.NONE;
785 |
786 | }
787 |
788 | function onMouseWheel(event) {
789 |
790 | if (scope.enabled === false || scope.enableZoom === false || (state !== STATE.NONE && state !== STATE.ROTATE)) return;
791 |
792 | event.preventDefault();
793 | event.stopPropagation();
794 |
795 | scope.dispatchEvent(startEvent);
796 |
797 | handleMouseWheel(event);
798 |
799 | scope.dispatchEvent(endEvent);
800 |
801 | }
802 |
803 | function onKeyDown(event) {
804 |
805 | if (scope.enabled === false || scope.enableKeys === false || scope.enablePan === false) return;
806 |
807 | handleKeyDown(event);
808 |
809 | }
810 |
811 | function onTouchStart(event) {
812 |
813 | if (scope.enabled === false) return;
814 |
815 | event.preventDefault();
816 |
817 | switch (event.touches.length) {
818 |
819 | case 1: // one-fingered touch: rotate
820 |
821 | if (scope.enableRotate === false) return;
822 |
823 | handleTouchStartRotate(event);
824 |
825 | state = STATE.TOUCH_ROTATE;
826 |
827 | break;
828 |
829 | case 2: // two-fingered touch: dolly-pan
830 |
831 | if (scope.enableZoom === false && scope.enablePan === false) return;
832 |
833 | handleTouchStartDollyPan(event);
834 |
835 | state = STATE.TOUCH_DOLLY_PAN;
836 |
837 | break;
838 |
839 | default:
840 |
841 | state = STATE.NONE;
842 |
843 | }
844 |
845 | if (state !== STATE.NONE) {
846 |
847 | scope.dispatchEvent(startEvent);
848 |
849 | }
850 |
851 | }
852 |
853 | function onTouchMove(event) {
854 |
855 | if (scope.enabled === false) return;
856 |
857 | event.preventDefault();
858 | event.stopPropagation();
859 |
860 | switch (event.touches.length) {
861 |
862 | case 1: // one-fingered touch: rotate
863 |
864 | if (scope.enableRotate === false) return;
865 | if (state !== STATE.TOUCH_ROTATE) return; // is this needed?
866 |
867 | handleTouchMoveRotate(event);
868 |
869 | break;
870 |
871 | case 2: // two-fingered touch: dolly-pan
872 |
873 | if (scope.enableZoom === false && scope.enablePan === false) return;
874 | if (state !== STATE.TOUCH_DOLLY_PAN) return; // is this needed?
875 |
876 | handleTouchMoveDollyPan(event);
877 |
878 | break;
879 |
880 | default:
881 |
882 | state = STATE.NONE;
883 |
884 | }
885 |
886 | }
887 |
888 | function onTouchEnd(event) {
889 |
890 | if (scope.enabled === false) return;
891 |
892 | handleTouchEnd(event);
893 |
894 | scope.dispatchEvent(endEvent);
895 |
896 | state = STATE.NONE;
897 |
898 | }
899 |
900 | function onContextMenu(event) {
901 |
902 | if (scope.enabled === false) return;
903 |
904 | event.preventDefault();
905 |
906 | }
907 |
908 | //
909 |
910 | scope.domElement.addEventListener('contextmenu', onContextMenu, false);
911 |
912 | scope.domElement.addEventListener('mousedown', onMouseDown, false);
913 | scope.domElement.addEventListener('wheel', onMouseWheel, false);
914 |
915 | scope.domElement.addEventListener('touchstart', onTouchStart, false);
916 | scope.domElement.addEventListener('touchend', onTouchEnd, false);
917 | scope.domElement.addEventListener('touchmove', onTouchMove, false);
918 |
919 | window.addEventListener('keydown', onKeyDown, false);
920 |
921 | // force an update at start
922 |
923 | this.update();
924 |
925 | };
926 |
927 | OrbitControls.prototype = Object.create(THREE.EventDispatcher.prototype);
928 | OrbitControls.prototype.constructor = OrbitControls;
929 |
930 | Object.defineProperties(OrbitControls.prototype, {
931 |
932 | center: {
933 |
934 | get: function() {
935 |
936 | console.warn('OrbitControls: .center has been renamed to .target');
937 | return this.target;
938 |
939 | }
940 |
941 | },
942 |
943 | // backward compatibility
944 |
945 | noZoom: {
946 |
947 | get: function() {
948 |
949 | console.warn('OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.');
950 | return !this.enableZoom;
951 |
952 | },
953 |
954 | set: function(value) {
955 |
956 | console.warn('OrbitControls: .noZoom has been deprecated. Use .enableZoom instead.');
957 | this.enableZoom = !value;
958 |
959 | }
960 |
961 | },
962 |
963 | noRotate: {
964 |
965 | get: function() {
966 |
967 | console.warn('OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.');
968 | return !this.enableRotate;
969 |
970 | },
971 |
972 | set: function(value) {
973 |
974 | console.warn('OrbitControls: .noRotate has been deprecated. Use .enableRotate instead.');
975 | this.enableRotate = !value;
976 |
977 | }
978 |
979 | },
980 |
981 | noPan: {
982 |
983 | get: function() {
984 |
985 | console.warn('OrbitControls: .noPan has been deprecated. Use .enablePan instead.');
986 | return !this.enablePan;
987 |
988 | },
989 |
990 | set: function(value) {
991 |
992 | console.warn('OrbitControls: .noPan has been deprecated. Use .enablePan instead.');
993 | this.enablePan = !value;
994 |
995 | }
996 |
997 | },
998 |
999 | noKeys: {
1000 |
1001 | get: function() {
1002 |
1003 | console.warn('OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.');
1004 | return !this.enableKeys;
1005 |
1006 | },
1007 |
1008 | set: function(value) {
1009 |
1010 | console.warn('OrbitControls: .noKeys has been deprecated. Use .enableKeys instead.');
1011 | this.enableKeys = !value;
1012 |
1013 | }
1014 |
1015 | },
1016 |
1017 | staticMoving: {
1018 |
1019 | get: function() {
1020 |
1021 | console.warn('OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.');
1022 | return !this.enableDamping;
1023 |
1024 | },
1025 |
1026 | set: function(value) {
1027 |
1028 | console.warn('OrbitControls: .staticMoving has been deprecated. Use .enableDamping instead.');
1029 | this.enableDamping = !value;
1030 |
1031 | }
1032 |
1033 | },
1034 |
1035 | dynamicDampingFactor: {
1036 |
1037 | get: function() {
1038 |
1039 | console.warn('OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.');
1040 | return this.dampingFactor;
1041 |
1042 | },
1043 |
1044 | set: function(value) {
1045 |
1046 | console.warn('OrbitControls: .dynamicDampingFactor has been renamed. Use .dampingFactor instead.');
1047 | this.dampingFactor = value;
1048 |
1049 | }
1050 |
1051 | }
1052 |
1053 | });
1054 |
1055 | export default OrbitControls;
--------------------------------------------------------------------------------
/third_party/UpdatableTexture.js:
--------------------------------------------------------------------------------
1 | import {
2 | Texture,
3 | LinearFilter,
4 | LinearMipMapLinearFilter,
5 | WebGLUtils
6 | } from "./three.module.js";
7 |
8 | function UpdatableTexture(
9 | format,
10 | type,
11 | mapping,
12 | wrapS,
13 | wrapT,
14 | magFilter,
15 | minFilter,
16 | anisotropy,
17 | encoding
18 | ) {
19 | Texture.call(
20 | this,
21 | null,
22 | mapping,
23 | wrapS,
24 | wrapT,
25 | magFilter,
26 | minFilter,
27 | format,
28 | type,
29 | anisotropy,
30 | encoding
31 | );
32 |
33 | var canvas = document.createElement("canvas");
34 | canvas.width = 1;
35 | canvas.height = 1;
36 | var ctx = canvas.getContext("2d");
37 | var imageData = ctx.createImageData(1, 1);
38 |
39 | this.image = imageData;
40 |
41 | this.magFilter = magFilter !== undefined ? magFilter : LinearFilter;
42 | this.minFilter =
43 | minFilter !== undefined ? minFilter : LinearMipMapLinearFilter;
44 |
45 | this.generateMipmaps = true;
46 | this.flipY = true;
47 | this.unpackAlignment = 1;
48 | this.needsUpdate = true;
49 | }
50 |
51 | UpdatableTexture.prototype = Object.create(Texture.prototype);
52 | UpdatableTexture.prototype.constructor = UpdatableTexture;
53 |
54 | UpdatableTexture.prototype.isUpdatableTexture = true;
55 |
56 | UpdatableTexture.prototype.setRenderer = function(renderer) {
57 | this.renderer = renderer;
58 | this.gl = this.renderer.getContext();
59 | this.utils = WebGLUtils(
60 | this.gl,
61 | this.renderer.extensions,
62 | this.renderer.capabilities
63 | );
64 | };
65 |
66 | UpdatableTexture.prototype.setSize = function(width, height) {
67 | if (width === this.width && height === this.height) return;
68 |
69 | var textureProperties = this.renderer.properties.get(this);
70 | if (!textureProperties.__webglTexture) return;
71 |
72 | this.width = width;
73 | this.height = height;
74 |
75 | var activeTexture = this.gl.getParameter(this.gl.TEXTURE_BINDING_2D);
76 | this.gl.bindTexture(this.gl.TEXTURE_2D, textureProperties.__webglTexture);
77 | if (!textureProperties.__webglTexture) this.width = null;
78 | this.gl.texImage2D(
79 | this.gl.TEXTURE_2D,
80 | 0,
81 | this.utils.convert(this.format),
82 | width,
83 | height,
84 | 0,
85 | this.utils.convert(this.format),
86 | this.utils.convert(this.type),
87 | null
88 | );
89 | this.gl.bindTexture(this.gl.TEXTURE_2D, activeTexture);
90 | };
91 |
92 | UpdatableTexture.prototype.update = function(src, x, y) {
93 | var textureProperties = this.renderer.properties.get(this);
94 | if (!textureProperties.__webglTexture) return;
95 |
96 | var activeTexture = this.gl.getParameter(this.gl.TEXTURE_BINDING_2D);
97 | this.gl.bindTexture(this.gl.TEXTURE_2D, textureProperties.__webglTexture);
98 | this.gl.texSubImage2D(
99 | this.gl.TEXTURE_2D,
100 | 0,
101 | x,
102 | this.height - y - src.height,
103 | this.utils.convert(this.format),
104 | this.utils.convert(this.type),
105 | src
106 | );
107 | this.gl.generateMipmap(this.gl.TEXTURE_2D);
108 | this.gl.bindTexture(this.gl.TEXTURE_2D, activeTexture);
109 | };
110 |
111 | export { UpdatableTexture };
112 |
--------------------------------------------------------------------------------
/third_party/WebXR.js:
--------------------------------------------------------------------------------
1 | function detectWebXR() {
2 | if ("xr" in navigator) {
3 | return new Promise((resolve, reject) => {
4 | navigator.xr
5 | .isSessionSupported("immersive-vr")
6 | .then(supported => {
7 | resolve();
8 | })
9 | .catch(() => reject());
10 | });
11 | }
12 |
13 | throw new Error("No WebXR support.");
14 | }
15 |
16 | function startWebXR(device, renderer, options) {
17 | if (options && options.frameOfReferenceType) {
18 | renderer.vr.setFrameOfReferenceType(options.frameOfReferenceType);
19 | }
20 |
21 | let currentSession = null;
22 |
23 | function onSessionStarted(session) {
24 | session.addEventListener("end", onSessionEnded);
25 | renderer.vr.setSession(session);
26 | currentSession = session;
27 | }
28 |
29 | function onSessionEnded(event) {
30 | currentSession.removeEventListener("end", onSessionEnded);
31 | renderer.vr.setSession(null);
32 | currentSession = null;
33 | }
34 |
35 | var sessionInit = { optionalFeatures: ["local-floor", "bounded-floor"] };
36 | navigator.xr
37 | .requestSession("immersive-vr", sessionInit)
38 | .then(onSessionStarted);
39 |
40 | //renderer.vr.setDevice(device);
41 | }
42 |
43 | export { detectWebXR, startWebXR };
44 |
--------------------------------------------------------------------------------
/third_party/equirectangular-to-cubemap.js:
--------------------------------------------------------------------------------
1 | import {
2 | Scene,
3 | CubeCamera,
4 | MeshBasicMaterial,
5 | Mesh,
6 | IcosahedronGeometry,
7 | BackSide
8 | } from "./three.module.js";
9 |
10 | class EquirectangularToCubemap {
11 | constructor(renderer) {
12 | this.renderer = renderer;
13 | this.scene = new Scene();
14 |
15 | var gl = this.renderer.getContext();
16 | this.maxSize = gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE);
17 |
18 | this.camera = new CubeCamera(1, 100000, 1);
19 |
20 | this.material = new MeshBasicMaterial({
21 | map: null,
22 | side: BackSide
23 | });
24 |
25 | this.mesh = new Mesh(new IcosahedronGeometry(100, 4), this.material);
26 | this.scene.add(this.mesh);
27 | }
28 |
29 | convert(source, size) {
30 | var mapSize = Math.min(size, this.maxSize);
31 | this.camera = new CubeCamera(1, 100000, mapSize);
32 | this.material.map = source;
33 |
34 | this.camera.update(this.renderer, this.scene);
35 |
36 | return this.camera.renderTarget.texture;
37 | }
38 | }
39 |
40 | export { EquirectangularToCubemap };
41 |
--------------------------------------------------------------------------------
/twitter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spite/infinite-gift/eba6257d277a94d4c3d7ac702547394f09da78a5/twitter.jpg
--------------------------------------------------------------------------------