├── .gitignore
├── .npmignore
├── LICENSE.md
├── README.md
├── assets
├── elk.json
├── factory.jpg
├── loader.css
├── lut.png
└── road.jpg
├── index.html
├── index.js
├── package.json
└── src
├── add-background.js
├── add-mesh.js
├── load-json-model.js
├── load-texture.js
├── shaders
├── bg.frag
├── bg.vert
├── horse.frag
└── horse.vert
└── viewer.js
/.gitignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | assets/
7 | !assets/elk.json
8 | !assets/lut.png
9 | !assets/factory.jpg
10 | !assets/road.jpg
11 | !assets/loader.css
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower_components
2 | node_modules
3 | *.log
4 | .DS_Store
5 | bundle.js
6 | test
7 | test.js
8 | demo/
9 | .npmignore
10 | LICENSE.md
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 | Copyright (c) 2015 Matt DesLauriers
3 |
4 | Permission is hereby granted, free of charge, to any person obtaining a copy
5 | of this software and associated documentation files (the "Software"), to deal
6 | in the Software without restriction, including without limitation the rights
7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | copies of the Software, and to permit persons to whom the Software is
9 | furnished to do so, subject to the following conditions:
10 |
11 | The above copyright notice and this permission notice shall be included in all
12 | copies or substantial portions of the Software.
13 |
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
20 | OR OTHER DEALINGS IN THE SOFTWARE.
21 |
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # rust
2 |
3 | [](http://github.com/badges/stability-badges)
4 |
5 | [](http://mattdesl.github.io/rust)
6 |
7 | http://mattdesl.github.io/rust
8 |
9 | Experiments with THREE.js and glslify. Some glslify features:
10 |
11 | - vertex animations using glsl-noise and glsl-easings
12 | - color grading with glsl-lut
13 | - background gradient with noise using glsl-film-grain
14 |
15 | ## License
16 |
17 | MIT, see [LICENSE.md](http://github.com/mattdesl/rust/blob/master/LICENSE.md) for details.
18 |
--------------------------------------------------------------------------------
/assets/factory.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/rust/833b9e8c4ebfadb3041ea76099f49a7f2adffe50/assets/factory.jpg
--------------------------------------------------------------------------------
/assets/loader.css:
--------------------------------------------------------------------------------
1 | /* Modified from: http://projects.lukehaas.me/css-loaders/ */
2 | .loader {
3 | margin: 0px auto;
4 | font-size: 10px;
5 | font: sans-serif;
6 | position: relative;
7 | text-indent: -9999em;
8 | border-top: 0.2em solid rgba(0, 0, 0, 0.2);
9 | border-right: 0.2em solid rgba(0, 0, 0, 0.2);
10 | border-bottom: 0.2em solid rgba(0, 0, 0, 0.2);
11 | border-left: 0.2em solid #000;
12 | -webkit-transform: translateZ(0);
13 | -ms-transform: translateZ(0);
14 | transform: translateZ(0);
15 | -webkit-animation: spin 1.1s infinite linear;
16 | animation: spin 1.1s infinite linear;
17 | }
18 | .loader,
19 | .loader:after {
20 | border-radius: 50%;
21 | width: 3em;
22 | height: 3em;
23 | position: absolute;
24 | margin: auto;
25 | top: 0;
26 | left: 0;
27 | right: 0;
28 | bottom: 0;
29 | }
30 | @-webkit-keyframes spin {
31 | 0% {
32 | -webkit-transform: rotate(0deg);
33 | transform: rotate(0deg);
34 | }
35 | 100% {
36 | -webkit-transform: rotate(360deg);
37 | transform: rotate(360deg);
38 | }
39 | }
40 | @keyframes spin {
41 | 0% {
42 | -webkit-transform: rotate(0deg);
43 | transform: rotate(0deg);
44 | }
45 | 100% {
46 | -webkit-transform: rotate(360deg);
47 | transform: rotate(360deg);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/assets/lut.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/rust/833b9e8c4ebfadb3041ea76099f49a7f2adffe50/assets/lut.png
--------------------------------------------------------------------------------
/assets/road.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mattdesl/rust/833b9e8c4ebfadb3041ea76099f49a7f2adffe50/assets/road.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | rust
7 |
8 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | import { polyfill } from 'es6-promise'
2 | polyfill()
3 |
4 | import THREE from 'three'
5 | import domready from 'domready'
6 | import viewer from './src/viewer'
7 | import loadGeometry from './src/load-json-model'
8 | import loadTexture from './src/load-texture'
9 | import assign from 'object-assign'
10 |
11 | import addMesh from './src/add-mesh'
12 | import addBackground from './src/add-background'
13 |
14 | domready(() => {
15 | const app = viewer({
16 | alpha: false,
17 | canvas: document.querySelector('canvas'),
18 | preserveDrawingBuffer: false,
19 | antialias: true
20 | })
21 |
22 | setTimeout(() => app.canvas.style.display = 'block', 10)
23 |
24 | const texOpt = {
25 | minFilter: THREE.LinearFilter,
26 | generateMipmaps: false,
27 | wrapS: THREE.RepeatWrapping,
28 | wrapT: THREE.RepeatWrapping
29 | }
30 |
31 | const loadTextures = Promise.all([
32 | loadTexture('assets/factory.jpg', texOpt),
33 | loadTexture('assets/road.jpg', texOpt)
34 | ])
35 |
36 | Promise.all([
37 | loadGeometry('assets/elk.json'),
38 | loadTextures,
39 | loadTexture('assets/lut.png', {
40 | minFilter: THREE.LinearFilter,
41 | flipY: false,
42 | generateMipmaps: false
43 | })
44 | ])
45 | .then(result => {
46 | let [ geo, textures, lut ] = result
47 | addMesh(app, assign({}, geo, {
48 | textures, lut
49 | }))
50 | })
51 | .then(null, (err) => {
52 | console.error("Got error")
53 | console.error(err.stack)
54 | })
55 | .then(() => {
56 | document.querySelector('.loader').style.display = 'none'
57 | })
58 |
59 | addBackground(app)
60 | app.controls.enabled = false
61 | app.start()
62 | })
63 |
64 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "rust",
3 | "version": "1.0.0",
4 | "description": "experiments",
5 | "main": "index.js",
6 | "license": "MIT",
7 | "private": true,
8 | "author": {
9 | "name": "Matt DesLauriers",
10 | "email": "dave.des@gmail.com",
11 | "url": "https://github.com/mattdesl"
12 | },
13 | "dependencies": {
14 | "canvas-fit": "^1.4.0",
15 | "domready": "^1.0.7",
16 | "eases": "^1.0.6",
17 | "es6-promise": "^2.1.0",
18 | "glsl-easings": "^1.0.0",
19 | "glsl-film-grain": "^1.0.2",
20 | "glsl-lut": "^1.1.0",
21 | "glsl-noise": "0.0.0",
22 | "glslify-hex": "^2.0.1",
23 | "glslify-import": "0.0.1",
24 | "load-json-xhr": "^3.0.1",
25 | "object-assign": "^2.0.0",
26 | "raf-loop": "^1.0.1",
27 | "three": "^0.70.0",
28 | "three-orbit-controls": "^69.0.4",
29 | "three-orbit-viewer": "^69.3.0",
30 | "xtend": "^4.0.0"
31 | },
32 | "devDependencies": {
33 | "babelify": "^6.0.2",
34 | "browserify": "^9.0.8",
35 | "budo": "^3.0.4",
36 | "errorify": "^0.2.4",
37 | "garnish": "^2.1.3",
38 | "glslify": "^2.1.2",
39 | "uglify-js": "^2.4.20",
40 | "watchify": "^3.1.1"
41 | },
42 | "scripts": {
43 | "build": "browserify index.js -t babelify -t glslify | uglifyjs -cm > bundle.js",
44 | "start": "budo index.js:bundle.js --live -v -t babelify -t glslify -p errorify | garnish"
45 | },
46 | "glslify": {
47 | "transform": [
48 | "glslify-hex"
49 | ]
50 | },
51 | "keywords": [],
52 | "repository": {
53 | "type": "git",
54 | "url": "git://github.com/mattdesl/rust.git"
55 | },
56 | "homepage": "https://github.com/mattdesl/rust",
57 | "bugs": {
58 | "url": "https://github.com/mattdesl/rust/issues"
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/add-background.js:
--------------------------------------------------------------------------------
1 | import THREE from 'three'
2 |
3 | var glslify = require('glslify')
4 |
5 | export default function(app) {
6 | const resolution = new THREE.Vector2(app.width, app.height)
7 | const mat = new THREE.ShaderMaterial({
8 | vertexShader: glslify('./shaders/bg.vert'),
9 | fragmentShader: glslify('./shaders/bg.frag'),
10 | uniforms: {
11 | iResolution: { type: 'v2', value: resolution },
12 | iGlobalTime: { type: 'f', value: 0 },
13 | },
14 | depthTest: false,
15 | depthWrite: false,
16 | side: THREE.DoubleSide
17 | })
18 |
19 | const geom = new THREE.PlaneGeometry(500, 500)
20 | const mesh = new THREE.Mesh(geom, mat)
21 | mesh.rotation.y = -Math.PI
22 | app.scene.add(mesh)
23 |
24 | app.on('tick', dt => {
25 | mat.uniforms.iGlobalTime.value += dt/1000
26 | })
27 |
28 | app.on('resize', ({ width, height }) => {
29 | resolution.set(width, height)
30 | })
31 | }
--------------------------------------------------------------------------------
/src/add-mesh.js:
--------------------------------------------------------------------------------
1 | import THREE from 'three'
2 | import assign from 'object-assign'
3 | var glslify = require('glslify')
4 | // var ease = require('eases/sine-in-out')
5 |
6 | export default function(app, assets) {
7 | const resolution = new THREE.Vector2(app.width, app.height)
8 | const mat = new THREE.ShaderMaterial({
9 | vertexShader: glslify('./shaders/horse.vert'),
10 | fragmentShader: glslify('./shaders/horse.frag'),
11 | uniforms: assign({}, THREE.UniformsLib.lights, {
12 | iResolution: { type: 'v2', value: resolution },
13 | iChannel0: { type: 't', value: assets.textures[0] },
14 | iChannel1: { type: 't', value: assets.textures[1] },
15 | iLookup: { type: 't', value: assets.lut },
16 | opacity: { type: 'f', value: 1 },
17 | morphTargetInfluences: { type: 'f', value: 0 },
18 | diffuse: { type: 'c', value: new THREE.Color(0xffffff) },
19 | iGlobalTime: { type: 'f', value: 0 },
20 | }),
21 | shading: THREE.FlatShading,
22 | lights: true,
23 | morphTargets: true,
24 | defines: {
25 | USE_MORPHTARGETS: '',
26 | USE_MAP: ''
27 | }
28 | })
29 |
30 | const directionalLight = new THREE.DirectionalLight(0xffffff, 1);
31 | directionalLight.position.set(6, 10, -10);
32 | app.scene.add(directionalLight);
33 |
34 | app.scene.add(new THREE.HemisphereLight(0xecfbff, 0xb0ddff, 0.75))
35 |
36 | const mesh = new THREE.Mesh(assets.geometry, mat)
37 | mesh.scale.multiplyScalar(0.01)
38 | mesh.position.set(-0.1, -0.6, 0)
39 | // mesh.rotation.y = 140 * Math.PI/180
40 | mesh.rotation.y = 90 * Math.PI/180
41 | app.scene.add(mesh)
42 |
43 | const animation = new THREE.MorphAnimation(mesh)
44 | animation.play()
45 | let time = 0
46 |
47 | app.on('tick', (dt) => {
48 | time += dt/1000
49 | mat.uniforms.iGlobalTime.value = time
50 | animation.update(dt)
51 |
52 | // rotate mesh?
53 | // let rotation = Math.sin(time) * 0.5 + 0.5
54 | // rotation = ease(rotation) * 2 - 1
55 | // rotation = rotation * Math.PI*0.5
56 | // mesh.rotation.y = Math.PI/2 + rotation*0.1
57 | })
58 |
59 | app.on('resize', ({ width, height}) => {
60 | resolution.set(width, height)
61 | })
62 | }
--------------------------------------------------------------------------------
/src/load-json-model.js:
--------------------------------------------------------------------------------
1 | import THREE from 'three'
2 | import json from 'load-json-xhr'
3 |
4 | export default function(path) {
5 | return new Promise((resolve, reject) => {
6 | const loader = new THREE.JSONLoader();
7 | json(path, (err, data) => {
8 | if (err)
9 | reject(err)
10 | else {
11 | resolve(loader.parse(data))
12 | }
13 | })
14 | })
15 | }
--------------------------------------------------------------------------------
/src/load-texture.js:
--------------------------------------------------------------------------------
1 | import THREE from 'three'
2 | import assign from 'object-assign'
3 |
4 | export default function(path, opt={}) {
5 | return new Promise((resolve, reject) => {
6 | THREE.ImageUtils.loadTexture(path, undefined,
7 | tex => {
8 | assign(tex, opt)
9 | resolve(tex)
10 | },
11 | () => {
12 | reject(new Error(`could not load image ${path}`))
13 | })
14 | })
15 | }
--------------------------------------------------------------------------------
/src/shaders/bg.frag:
--------------------------------------------------------------------------------
1 | // varying vec2 vUv;
2 | uniform float iGlobalTime;
3 | uniform vec2 iResolution;
4 |
5 | const vec3 color1 = #fff;
6 | const vec3 color2 = #e1edf7;
7 |
8 | #pragma glslify: grain = require('glsl-film-grain')
9 |
10 | void main() {
11 | vec2 uv = gl_FragCoord.xy / iResolution.xy;
12 |
13 | vec2 aspect = vec2(iResolution.x / iResolution.y, 1.0);
14 | float zoom = 0.5;
15 | float dist = length((uv - 0.5) * aspect * zoom);
16 |
17 | vec3 color = mix(color1, color2, dist);
18 |
19 | float grainSize = 1.0;
20 | float g = grain(uv, iResolution / grainSize, iGlobalTime*2.0);
21 | color -= mix(0.0, g*0.3, dist);
22 |
23 | gl_FragColor.rgb = color;
24 | gl_FragColor.a = 1.0;
25 | }
--------------------------------------------------------------------------------
/src/shaders/bg.vert:
--------------------------------------------------------------------------------
1 | // varying vec2 vUv;
2 | void main() {
3 | gl_Position = projectionMatrix *
4 | modelViewMatrix *
5 | vec4(position, 1.0);
6 | }
--------------------------------------------------------------------------------
/src/shaders/horse.frag:
--------------------------------------------------------------------------------
1 | varying vec2 vUv;
2 | uniform float iGlobalTime;
3 | uniform sampler2D iChannel0;
4 | uniform sampler2D iChannel1;
5 | uniform sampler2D iLookup;
6 | uniform vec3 diffuse;
7 | uniform float opacity;
8 | varying vec3 vLightFront;
9 | varying vec3 vReflect;
10 |
11 | #pragma glslify: lut = require('glsl-lut')
12 |
13 | void main() {
14 | vec4 diffuseColor = vec4(diffuse, opacity);
15 | vec3 outgoingLight = diffuseColor.rgb * vLightFront;
16 |
17 | vec2 uv = vUv * 0.5 + 0.5;
18 | uv.y -= 0.04; //offset coords a bit
19 | // uv.x += -0.0;
20 | vec4 color1 = texture2D(iChannel0, uv);
21 | vec4 color2 = texture2D(iChannel1, uv);
22 |
23 | float fade = smoothstep(0.7, 0.4, uv.y);
24 | //mix two images
25 | vec4 color = mix(color1, color2, fade);
26 | //N% tonemap
27 | vec4 toned = mix(color, lut(color, iLookup), 0.45);
28 | //show some of the model
29 | outgoingLight = mix(outgoingLight, toned.rgb, 0.90);
30 |
31 | gl_FragColor = vec4(outgoingLight, opacity);
32 | }
--------------------------------------------------------------------------------
/src/shaders/horse.vert:
--------------------------------------------------------------------------------
1 | varying vec2 vUv;
2 | varying vec3 vLightFront;
3 |
4 | uniform float iGlobalTime;
5 | uniform vec2 iResolution;
6 | uniform float morphTargetInfluences[ 4 ];
7 |
8 | const float zoom = 2.0;
9 | const vec2 offset = vec2(0.0, -0.5);
10 |
11 | vec3 transformDirection( in vec3 normal, in mat4 matrix ) {
12 | return normalize( ( matrix * vec4( normal, 0.0 ) ).xyz );
13 | }
14 |
15 | //env
16 | varying vec3 vReflect;
17 |
18 | //lighting
19 | uniform vec3 ambientLightColor;
20 | #if MAX_DIR_LIGHTS > 0
21 | uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];
22 | uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];
23 | #endif
24 |
25 | #if MAX_HEMI_LIGHTS > 0
26 | uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];
27 | uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];
28 | uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];
29 | #endif
30 |
31 | vec3 lighting(in vec3 normal) {
32 | vec3 lightColor = vec3(0.0);
33 | vec3 transformedNormal = normalize( normal );
34 |
35 | #if MAX_DIR_LIGHTS > 0
36 | for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {
37 | vec3 dirVector = transformDirection( directionalLightDirection[ i ], viewMatrix );
38 |
39 | float dotProduct = dot( transformedNormal, dirVector );
40 | vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );
41 | lightColor += directionalLightColor[ i ] * directionalLightWeighting;
42 | }
43 | #endif
44 | #if MAX_HEMI_LIGHTS > 0
45 | for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {
46 | vec3 lVector = transformDirection( hemisphereLightDirection[ i ], viewMatrix );
47 |
48 | float dotProduct = dot( transformedNormal, lVector );
49 | float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;
50 | float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;
51 | lightColor += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );
52 | }
53 | #endif
54 | lightColor += ambientLightColor;
55 | return lightColor;
56 | }
57 |
58 | #pragma glslify: noise = require('glsl-noise/simplex/4d')
59 | #pragma glslify: ease = require('glsl-easings/quartic-in-out')
60 | #pragma glslify: circ = require('glsl-easings/sine-in-out')
61 |
62 | void main() {
63 | float anim = ease(sin(iGlobalTime) * 0.5 + 0.5);
64 | vec3 objectNormal = vec3(normalMatrix * normal);
65 |
66 | //morphtargets
67 | vec3 morphed = vec3(0.0);
68 | morphed += (morphTarget0 - position) * morphTargetInfluences[0];
69 | morphed += (morphTarget1 - position) * morphTargetInfluences[1];
70 | morphed += (morphTarget2 - position) * morphTargetInfluences[2];
71 | morphed += (morphTarget3 - position) * morphTargetInfluences[3];
72 | morphed += position;
73 |
74 | vec3 center = vec3(0.0, 60.0, 50.0);
75 | vec3 dir = normalize(position - center);
76 | float spin = circ(sin(iGlobalTime)*0.5+0.5)*2.0-1.0;
77 |
78 |
79 | // float ripple = clamp(distance(position.xyz, center) / (100.0), 0.0, 1.0);
80 | // ripple = smoothstep(1.0, 0.85, ripple);
81 | // spin = mix(spin, ripple, (sin(iGlobalTime)*0.5+0.5));
82 | // spin = mix(spin, spin + ripple, 0.2);
83 |
84 | float n = noise(vec4(normal.xyz * (spin * dir * 8.0), iGlobalTime));
85 | // float explode = circ((sin(iGlobalTime*0.5)*0.5+0.5))*2.0-1.0;
86 | morphed += (n * 4.0);
87 |
88 | vec4 projected = projectionMatrix *
89 | modelViewMatrix *
90 | vec4(morphed, 1.0);
91 |
92 | gl_Position = projected;
93 |
94 | //lighting
95 | vLightFront = lighting(objectNormal);
96 |
97 | //uvs
98 | vec2 screenPos = projected.xy / projected.w;
99 | vUv = screenPos;
100 | vUv.x *= iResolution.x / iResolution.y;
101 | }
--------------------------------------------------------------------------------
/src/viewer.js:
--------------------------------------------------------------------------------
1 | import THREE from 'three'
2 | import loop from 'raf-loop'
3 |
4 | import assign from 'object-assign'
5 | import domready from 'domready'
6 | import fitter from 'canvas-fit'
7 |
8 |
9 | const OrbitControls = require('three-orbit-controls')(THREE)
10 |
11 | export default function(opt) {
12 | opt = assign({}, opt)
13 |
14 | const dpr = Math.min(2, window.devicePixelRatio)
15 | const canvas = opt.canvas || document.createElement('canvas')
16 | const fit = fitter(canvas, window, dpr)
17 |
18 | const renderer = new THREE.WebGLRenderer(assign({
19 | canvas: canvas
20 | }, opt))
21 |
22 | const gl = renderer.getContext()
23 |
24 | const app = loop(draw)
25 | const scene = new THREE.Scene()
26 | const camera = new THREE.OrthographicCamera(-1, 1, 1, -1)
27 | const controls = new OrbitControls(camera, canvas)
28 | camera.position.copy(new THREE.Vector3(0, 0, -1.6))
29 | camera.lookAt(new THREE.Vector3())
30 | updateCamera()
31 |
32 | app.render = renderer.render.bind(renderer, scene, camera)
33 |
34 | //render each frame unless user wants to do it manually
35 | if (opt.rendering !== false)
36 | app.on('render', app.render.bind(app))
37 |
38 | assign(app, {
39 | renderer,
40 | scene,
41 | camera,
42 | controls,
43 | gl,
44 | canvas
45 | })
46 |
47 | window.addEventListener('resize', resize, false)
48 | renderer.setClearColor(0xf7f7f7, 1)
49 | process.nextTick(resize)
50 | return app
51 |
52 | function draw() {
53 | app.emit('render')
54 | }
55 |
56 | function resize() {
57 | fit()
58 | const width = window.innerWidth
59 | const height = window.innerHeight
60 | const size = { width, height }
61 |
62 | renderer.setSize(width, height)
63 | updateCamera()
64 |
65 | // camera.aspect = width / height
66 | assign(app, size)
67 | app.emit('resize', size)
68 | }
69 |
70 | function updateCamera () {
71 | const width = window.innerWidth
72 | const height = window.innerHeight
73 | const aspectX = width > height ? (width / height) : 1
74 | const aspectY = width > height ? 1 : (1 / (width / height))
75 | camera.left = -1 * aspectX
76 | camera.right = 1 * aspectX
77 | camera.top = 1 * aspectY
78 | camera.bottom = -1 * aspectY
79 | camera.updateProjectionMatrix()
80 | }
81 | }
--------------------------------------------------------------------------------