├── .babelrc ├── .gitignore ├── README.md ├── package.json ├── public ├── assets │ ├── ambient │ │ ├── track1.mp3 │ │ ├── track2.mp3 │ │ └── track3.mp3 │ ├── arc │ │ ├── arc.gltf │ │ ├── arc_data.bin │ │ └── arc_diffuse.png │ ├── char │ │ ├── char_diffuse.png │ │ ├── char_mesh.fbx │ │ ├── char_minmax.json │ │ ├── char_norm.exr │ │ └── char_pos.exr │ ├── cliff │ │ ├── cliff.gltf │ │ └── cliff_data.bin │ ├── cubes │ │ ├── cubes.gltf │ │ └── cubes_data.bin │ ├── dried_body │ │ ├── dried_body.gltf │ │ └── dried_body_data.bin │ ├── dunes │ │ ├── dunes.gltf │ │ └── dunes_data.bin │ ├── favicon.png │ ├── fire │ │ ├── fire_col.exr │ │ ├── fire_mesh.fbx │ │ ├── fire_minmax.json │ │ └── fire_pos.exr │ ├── info.png │ ├── mask │ │ ├── mask.gltf │ │ ├── mask_basecolor.png │ │ └── mask_data.bin │ ├── moon_rock │ │ ├── moon_rock.gltf │ │ └── moon_rock_data.bin │ ├── mountains │ │ ├── mountains.gltf │ │ ├── mountains_data.bin │ │ └── mountains_diff.png │ ├── pendulum │ │ ├── pendulum.gltf │ │ └── pendulum_data.bin │ ├── pendulum_base │ │ ├── pendulum_base.gltf │ │ └── pendulum_base_data.bin │ ├── pyramid │ │ ├── pyramid.gltf │ │ └── pyramid_data.bin │ ├── quest_controller_l │ │ ├── quest_controller_l.gltf │ │ └── quest_controller_l_data.bin │ ├── quest_controller_r │ │ ├── quest_controller_r.gltf │ │ └── quest_controller_r_data.bin │ ├── ruins │ │ ├── pillar_texture.png │ │ ├── ruins.gltf │ │ └── ruins_data.bin │ ├── speech │ │ ├── comment1.mp3 │ │ ├── comment2.mp3 │ │ ├── followMe.mp3 │ │ ├── speech1.mp3 │ │ ├── speech2.mp3 │ │ ├── speech3.mp3 │ │ ├── speech4.mp3 │ │ ├── speech5.mp3 │ │ ├── speech6.mp3 │ │ ├── speech7.mp3 │ │ └── speechWin.mp3 │ ├── star.png │ └── tex_Fern_Lush_Noise.jpg ├── index.html └── js │ └── tinyexr.js ├── src ├── Fire.js ├── JSX.js ├── Utils.js ├── components │ ├── AmbientController.js │ ├── CharacterMover.js │ ├── CharacterStateMachine.js │ ├── Collider.js │ ├── CustomControl.js │ ├── DefaultMaterial.js │ ├── FireManager.js │ ├── FresnelMaterial.js │ ├── GlowMaterial.js │ ├── Intro.js │ ├── Mover.js │ ├── Pendulum.js │ ├── RingOfFire.js │ ├── SetCharacterMaterial.js │ ├── SetGLTFMaterial.js │ ├── Sky.js │ ├── SpeechController.js │ ├── Sun.js │ ├── VertexCacheTextures.js │ └── WebUIController.js ├── index.js ├── libs │ ├── FBXLoader.js │ └── Utils.js ├── shaders │ ├── CharacterSoftFrag.glsl │ ├── ColorCorrection.glsl │ ├── EyeFrag.glsl │ ├── EyeVert.glsl │ ├── FireRingFrag.glsl │ ├── FireRingVert.glsl │ ├── FogReplaceFrag.glsl │ ├── FogReplaceVert.glsl │ ├── FresnelFrag.glsl │ ├── FresnelVert.glsl │ ├── IntroFrag.glsl │ ├── IntroVert.glsl │ ├── LaserFrag.glsl │ ├── LaserVert.glsl │ ├── PendulumFrag.glsl │ ├── PendulumMaterial.js │ ├── PendulumVert.glsl │ ├── PerlinNoise.glsl │ ├── PhongFrag.glsl │ ├── PhongVert.glsl │ ├── SkyFrag.glsl │ ├── SkyVert.glsl │ ├── SunCalibratedMaterial.js │ ├── SunFrag.glsl │ ├── SunVert.glsl │ ├── VertexCacheFluidFrag.glsl │ ├── VertexCacheFluidVert.glsl │ ├── VertexCacheSoftFrag.glsl │ └── VertexCacheSoftVert.glsl ├── style.css └── systems │ ├── PendulumSystem.js │ ├── RaycasterSystem.js │ └── SunSystem.js ├── webpack.config.js ├── yarn-error.log └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env" 4 | ], 5 | "plugins": [ 6 | "transform-regenerator", 7 | [ 8 | "@babel/plugin-transform-react-jsx", 9 | { 10 | "pragma": "JSX.createElement" 11 | } 12 | ] 13 | ] 14 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .vscode/ 3 | .DS_Store 4 | /dist 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A-Frame with Webpack Example 2 | 3 | This project shows: 4 | 5 | - How to use A-Frame with Webpack and JSX for html like syntax withing Java Script similar to React 6 | - How to cleanly use and load custom shaders 7 | 8 | To get started: 9 | 10 | ``` 11 | git clone https://github.com/Kif11/aframe-webpack 12 | cd aframe-webpack 13 | yarn install 14 | yarn start 15 | ``` 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "aframe-webpack", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "private": true, 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build": "webpack --colors", 10 | "start": "webpack-dev-server --open" 11 | }, 12 | "keywords": [], 13 | "author": "", 14 | "license": "ISC", 15 | "devDependencies": { 16 | "@babel/core": "^7.4.3", 17 | "@babel/plugin-transform-react-jsx": "^7.3.0", 18 | "@babel/preset-env": "^7.4.3", 19 | "babel-loader": "^8.0.5", 20 | "babel-plugin-transform-regenerator": "^6.26.0", 21 | "babel-polyfill": "^6.26.0", 22 | "copy-webpack-plugin": "^5.0.2", 23 | "css-loader": "^2.1.1", 24 | "html-webpack-plugin": "^3.2.0", 25 | "style-loader": "^0.23.1", 26 | "webpack": "^4.29.6", 27 | "webpack-cli": "^3.3.0", 28 | "webpack-dev-server": "^3.2.1", 29 | "webpack-glsl-loader": "^1.0.1" 30 | }, 31 | "dependencies": { 32 | "aframe": "^1.0.4", 33 | "aframe-extras": "^6.0.0" 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/assets/ambient/track1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/ambient/track1.mp3 -------------------------------------------------------------------------------- /public/assets/ambient/track2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/ambient/track2.mp3 -------------------------------------------------------------------------------- /public/assets/ambient/track3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/ambient/track3.mp3 -------------------------------------------------------------------------------- /public/assets/arc/arc.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":7434, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[7433 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":7434, 21 | "type":"VEC3", 22 | "min":[-5.06129932,-0.0492868423,-5.41723156 23 | ], 24 | "max":[3.88940859,5.34731483,4.85920954 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":7434, 31 | "type":"VEC2", 32 | "min":[0.0042976439,0.0015797019 33 | ], 34 | "max":[0.994218946,0.994498789 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":7434, 41 | "type":"VEC3", 42 | "min":[-0.99972862,-1,-0.99972862 43 | ], 44 | "max":[0.999836385,0.994760931,0.99972862 45 | ] 46 | } 47 | ], 48 | "buffers":[ 49 | { 50 | "uri":"arc_data.bin", 51 | "byteLength":252756, 52 | "name":"main_buffer" 53 | } 54 | ], 55 | "bufferViews":[ 56 | { 57 | "buffer":0, 58 | "byteLength":14868, 59 | "target":34963 60 | }, 61 | { 62 | "buffer":0, 63 | "byteOffset":14868, 64 | "byteLength":89208, 65 | "target":34962 66 | }, 67 | { 68 | "buffer":0, 69 | "byteOffset":104076, 70 | "byteLength":59472, 71 | "target":34962 72 | }, 73 | { 74 | "buffer":0, 75 | "byteOffset":163548, 76 | "byteLength":89208, 77 | "target":34962 78 | } 79 | ], 80 | "nodes":[ 81 | { 82 | "name":"arc", 83 | "mesh":0 84 | } 85 | ], 86 | "meshes":[ 87 | { 88 | "primitives":[ 89 | { 90 | "attributes":{ 91 | "NORMAL":3, 92 | "TEXCOORD_0":2, 93 | "POSITION":1 94 | }, 95 | "indices":0, 96 | "material":0 97 | } 98 | ] 99 | } 100 | ], 101 | "materials":[ 102 | { 103 | "name":"ArcMat", 104 | "pbrMetallicRoughness":{ 105 | "metallicFactor":0, 106 | "roughnessFactor":0.65200001, 107 | "baseColorTexture":{ 108 | "index":0 109 | } 110 | } 111 | } 112 | ], 113 | "scenes":[ 114 | { 115 | "nodes":[0 116 | ] 117 | } 118 | ], 119 | "textures":[ 120 | { 121 | "source":0 122 | } 123 | ], 124 | "images":[ 125 | { 126 | "uri":"arc_diffuse.png", 127 | "mimeType":"image/png" 128 | } 129 | ], 130 | "scene":0 131 | } 132 | -------------------------------------------------------------------------------- /public/assets/arc/arc_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/arc/arc_data.bin -------------------------------------------------------------------------------- /public/assets/arc/arc_diffuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/arc/arc_diffuse.png -------------------------------------------------------------------------------- /public/assets/char/char_diffuse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/char/char_diffuse.png -------------------------------------------------------------------------------- /public/assets/char/char_minmax.json: -------------------------------------------------------------------------------- 1 | { 2 | "bbox_max": "35.5030059814", 3 | "bbox_min": "-14.0982046127", 4 | "method": 0, 5 | "numframes": "64" 6 | } -------------------------------------------------------------------------------- /public/assets/char/char_norm.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/char/char_norm.exr -------------------------------------------------------------------------------- /public/assets/char/char_pos.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/char/char_pos.exr -------------------------------------------------------------------------------- /public/assets/cliff/cliff.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":1524, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[1523 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":1524, 21 | "type":"SCALAR", 22 | "min":[-6.07285929 23 | ], 24 | "max":[3.27972031 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":1524, 31 | "type":"SCALAR", 32 | "min":[-0.649106443 33 | ], 34 | "max":[3.59843302 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":1524, 41 | "type":"SCALAR", 42 | "min":[0.537069738 43 | ], 44 | "max":[308.893951 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":1524, 51 | "type":"VEC2", 52 | "min":[0.224635035,0.0656962991 53 | ], 54 | "max":[0.909336686,0.807251275 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":1524, 61 | "type":"SCALAR", 62 | "min":[-6.07285929 63 | ], 64 | "max":[3.27972031 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5126, 70 | "count":1524, 71 | "type":"VEC3", 72 | "min":[-18.2457981,4.99803067e-16,-27.4210243 73 | ], 74 | "max":[25.9394417,30.48209,40.6441765 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":1524, 81 | "type":"VEC3", 82 | "min":[0.726913154,0.465999991,0.205086857 83 | ], 84 | "max":[0.726913154,0.465999991,0.205086857 85 | ] 86 | }, 87 | { 88 | "bufferView":8, 89 | "componentType":5126, 90 | "count":1524, 91 | "type":"VEC3", 92 | "min":[-0.999538481,-0.563712358,-0.999824226 93 | ], 94 | "max":[0.993764222,0.999986112,0.999163389 95 | ] 96 | } 97 | ], 98 | "buffers":[ 99 | { 100 | "uri":"cliff_data.bin", 101 | "byteLength":94488, 102 | "name":"main_buffer" 103 | } 104 | ], 105 | "bufferViews":[ 106 | { 107 | "buffer":0, 108 | "byteLength":3048, 109 | "target":34963 110 | }, 111 | { 112 | "buffer":0, 113 | "byteOffset":3048, 114 | "byteLength":6096, 115 | "target":34962 116 | }, 117 | { 118 | "buffer":0, 119 | "byteOffset":9144, 120 | "byteLength":6096, 121 | "target":34962 122 | }, 123 | { 124 | "buffer":0, 125 | "byteOffset":15240, 126 | "byteLength":6096, 127 | "target":34962 128 | }, 129 | { 130 | "buffer":0, 131 | "byteOffset":21336, 132 | "byteLength":12192, 133 | "target":34962 134 | }, 135 | { 136 | "buffer":0, 137 | "byteOffset":33528, 138 | "byteLength":6096, 139 | "target":34962 140 | }, 141 | { 142 | "buffer":0, 143 | "byteOffset":39624, 144 | "byteLength":18288, 145 | "target":34962 146 | }, 147 | { 148 | "buffer":0, 149 | "byteOffset":57912, 150 | "byteLength":18288, 151 | "target":34962 152 | }, 153 | { 154 | "buffer":0, 155 | "byteOffset":76200, 156 | "byteLength":18288, 157 | "target":34962 158 | } 159 | ], 160 | "nodes":[ 161 | { 162 | "name":"cliff", 163 | "mesh":0 164 | } 165 | ], 166 | "meshes":[ 167 | { 168 | "primitives":[ 169 | { 170 | "attributes":{ 171 | "POSITION":6, 172 | "TEXCOORD_0":4, 173 | "_height":3, 174 | "NORMAL":8, 175 | "_cliffs":2, 176 | "COLOR_0":7, 177 | "_mesa":5, 178 | "_mask":1 179 | }, 180 | "indices":0 181 | } 182 | ] 183 | } 184 | ], 185 | "scenes":[ 186 | { 187 | "nodes":[0 188 | ] 189 | } 190 | ], 191 | "scene":0 192 | } 193 | -------------------------------------------------------------------------------- /public/assets/cliff/cliff_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/cliff/cliff_data.bin -------------------------------------------------------------------------------- /public/assets/cubes/cubes.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":576, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[127 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":128, 21 | "type":"VEC3", 22 | "min":[-0.200000003,0,-30.2000008 23 | ], 24 | "max":[0.200000003,10,0.200000003 25 | ] 26 | } 27 | ], 28 | "buffers":[ 29 | { 30 | "uri":"cubes_data.bin", 31 | "byteLength":2688 32 | } 33 | ], 34 | "bufferViews":[ 35 | { 36 | "buffer":0, 37 | "byteLength":1152, 38 | "target":34963 39 | }, 40 | { 41 | "buffer":0, 42 | "byteOffset":1152, 43 | "byteLength":1536, 44 | "target":34962 45 | } 46 | ], 47 | "nodes":[ 48 | { 49 | "mesh":0 50 | } 51 | ], 52 | "meshes":[ 53 | { 54 | "primitives":[ 55 | { 56 | "attributes":{ 57 | "POSITION":1 58 | }, 59 | "indices":0 60 | } 61 | ] 62 | } 63 | ], 64 | "scenes":[ 65 | { 66 | "nodes":[0 67 | ] 68 | } 69 | ], 70 | "scene":0 71 | } 72 | -------------------------------------------------------------------------------- /public/assets/cubes/cubes_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/cubes/cubes_data.bin -------------------------------------------------------------------------------- /public/assets/dried_body/dried_body.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":3186, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[3185 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":3186, 21 | "type":"VEC3", 22 | "min":[-1.11296403,-0.187385768,-0.927352428 23 | ], 24 | "max":[1.0110724,0.499534905,1.91695178 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":3186, 31 | "type":"VEC3", 32 | "min":[-0.999184251,-0.999999642,-0.998448431 33 | ], 34 | "max":[0.998073518,0.998995602,0.991905391 35 | ] 36 | } 37 | ], 38 | "buffers":[ 39 | { 40 | "uri":"dried_body_data.bin", 41 | "byteLength":82836, 42 | "name":"main_buffer" 43 | } 44 | ], 45 | "bufferViews":[ 46 | { 47 | "buffer":0, 48 | "byteLength":6372, 49 | "target":34963 50 | }, 51 | { 52 | "buffer":0, 53 | "byteOffset":6372, 54 | "byteLength":38232, 55 | "target":34962 56 | }, 57 | { 58 | "buffer":0, 59 | "byteOffset":44604, 60 | "byteLength":38232, 61 | "target":34962 62 | } 63 | ], 64 | "nodes":[ 65 | { 66 | "name":"geo1", 67 | "mesh":0 68 | } 69 | ], 70 | "meshes":[ 71 | { 72 | "primitives":[ 73 | { 74 | "attributes":{ 75 | "NORMAL":2, 76 | "POSITION":1 77 | }, 78 | "indices":0 79 | } 80 | ] 81 | } 82 | ], 83 | "scenes":[ 84 | { 85 | "nodes":[0 86 | ] 87 | } 88 | ], 89 | "scene":0 90 | } 91 | -------------------------------------------------------------------------------- /public/assets/dried_body/dried_body_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/dried_body/dried_body_data.bin -------------------------------------------------------------------------------- /public/assets/dunes/dunes.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":24696, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[24695 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":24696, 21 | "type":"VEC3", 22 | "min":[-500,-0.899999976,-500 23 | ], 24 | "max":[500,0.64126575,500 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":24696, 31 | "type":"VEC2", 32 | "min":[-1.87848782e-05,-4.30345535e-05 33 | ], 34 | "max":[1.00006068,1.00004077 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":24696, 41 | "type":"VEC3", 42 | "min":[1,1,1 43 | ], 44 | "max":[1,1,1 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":24696, 51 | "type":"SCALAR", 52 | "min":[-0.275079548 53 | ], 54 | "max":[0.725597441 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":24696, 61 | "type":"SCALAR", 62 | "min":[0 63 | ], 64 | "max":[0 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5126, 70 | "count":24696, 71 | "type":"SCALAR", 72 | "min":[-0.0942563117 73 | ], 74 | "max":[1.01541042 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":24696, 81 | "type":"VEC3", 82 | "min":[-0.978493631,-0.999998391,-0.9935202 83 | ], 84 | "max":[0.968024015,1,0.981351495 85 | ] 86 | } 87 | ], 88 | "buffers":[ 89 | { 90 | "uri":"dunes_data.bin", 91 | "byteLength":1432368, 92 | "name":"main_buffer" 93 | } 94 | ], 95 | "bufferViews":[ 96 | { 97 | "buffer":0, 98 | "byteLength":49392, 99 | "target":34963 100 | }, 101 | { 102 | "buffer":0, 103 | "byteOffset":49392, 104 | "byteLength":296352, 105 | "target":34962 106 | }, 107 | { 108 | "buffer":0, 109 | "byteOffset":345744, 110 | "byteLength":197568, 111 | "target":34962 112 | }, 113 | { 114 | "buffer":0, 115 | "byteOffset":543312, 116 | "byteLength":296352, 117 | "target":34962 118 | }, 119 | { 120 | "buffer":0, 121 | "byteOffset":839664, 122 | "byteLength":98784, 123 | "target":34962 124 | }, 125 | { 126 | "buffer":0, 127 | "byteOffset":938448, 128 | "byteLength":98784, 129 | "target":34962 130 | }, 131 | { 132 | "buffer":0, 133 | "byteOffset":1037232, 134 | "byteLength":98784, 135 | "target":34962 136 | }, 137 | { 138 | "buffer":0, 139 | "byteOffset":1136016, 140 | "byteLength":296352, 141 | "target":34962 142 | } 143 | ], 144 | "nodes":[ 145 | { 146 | "name":"ground1", 147 | "mesh":0 148 | } 149 | ], 150 | "meshes":[ 151 | { 152 | "primitives":[ 153 | { 154 | "attributes":{ 155 | "NORMAL":7, 156 | "_retention":6, 157 | "_mask":5, 158 | "COLOR_0":3, 159 | "_height":4, 160 | "TEXCOORD_0":2, 161 | "POSITION":1 162 | }, 163 | "indices":0, 164 | "material":0 165 | } 166 | ] 167 | } 168 | ], 169 | "materials":[ 170 | { 171 | "name":"principledshader", 172 | "pbrMetallicRoughness":{ 173 | "baseColorFactor":[0.152999997,0.0478023514,0.00823761523,1 174 | ], 175 | "metallicFactor":0, 176 | "roughnessFactor":0.56400001 177 | } 178 | } 179 | ], 180 | "scenes":[ 181 | { 182 | "nodes":[0 183 | ] 184 | } 185 | ], 186 | "scene":0 187 | } 188 | -------------------------------------------------------------------------------- /public/assets/dunes/dunes_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/dunes/dunes_data.bin -------------------------------------------------------------------------------- /public/assets/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/favicon.png -------------------------------------------------------------------------------- /public/assets/fire/fire_col.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/fire/fire_col.exr -------------------------------------------------------------------------------- /public/assets/fire/fire_minmax.json: -------------------------------------------------------------------------------- 1 | { 2 | "bbox_max": "460.051025391", 3 | "bbox_min": "-238.770248413", 4 | "method": 2, 5 | "numframes": "128" 6 | } -------------------------------------------------------------------------------- /public/assets/fire/fire_pos.exr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/fire/fire_pos.exr -------------------------------------------------------------------------------- /public/assets/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/info.png -------------------------------------------------------------------------------- /public/assets/mask/mask.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5121, 10 | "count":66, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[65 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":66, 21 | "type":"VEC3", 22 | "min":[-0.0777116045,2.28727722,0.147622257 23 | ], 24 | "max":[0.0751317441,2.30562258,0.176552892 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":66, 31 | "type":"VEC2", 32 | "min":[0.353801161,0.311060429 33 | ], 34 | "max":[0.87564373,0.933723211 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":66, 41 | "type":"VEC3", 42 | "min":[-0.580672622,-0.028489856,0.81212002 43 | ], 44 | "max":[0.483523577,0.0694093555,0.993618488 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5123, 50 | "count":6000, 51 | "type":"SCALAR", 52 | "min":[0 53 | ], 54 | "max":[5999 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":6000, 61 | "type":"VEC3", 62 | "min":[-0.106135875,2.05905271,0.0980021656 63 | ], 64 | "max":[0.115694694,2.49132752,0.201860026 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5126, 70 | "count":6000, 71 | "type":"VEC2", 72 | "min":[0.000974655326,0.0161061287 73 | ], 74 | "max":[0.997191668,0.999025345 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":6000, 81 | "type":"VEC3", 82 | "min":[-0.986681581,-1,-1 83 | ], 84 | "max":[0.998884618,1,0.999934256 85 | ] 86 | } 87 | ], 88 | "buffers":[ 89 | { 90 | "uri":"mask_data.bin", 91 | "byteLength":206180, 92 | "name":"main_buffer" 93 | } 94 | ], 95 | "bufferViews":[ 96 | { 97 | "buffer":0, 98 | "byteLength":66, 99 | "target":34963 100 | }, 101 | { 102 | "buffer":0, 103 | "byteOffset":68, 104 | "byteLength":792, 105 | "target":34962 106 | }, 107 | { 108 | "buffer":0, 109 | "byteOffset":860, 110 | "byteLength":528, 111 | "target":34962 112 | }, 113 | { 114 | "buffer":0, 115 | "byteOffset":1388, 116 | "byteLength":792, 117 | "target":34962 118 | }, 119 | { 120 | "buffer":0, 121 | "byteOffset":2180, 122 | "byteLength":12000, 123 | "target":34963 124 | }, 125 | { 126 | "buffer":0, 127 | "byteOffset":14180, 128 | "byteLength":72000, 129 | "target":34962 130 | }, 131 | { 132 | "buffer":0, 133 | "byteOffset":86180, 134 | "byteLength":48000, 135 | "target":34962 136 | }, 137 | { 138 | "buffer":0, 139 | "byteOffset":134180, 140 | "byteLength":72000, 141 | "target":34962 142 | } 143 | ], 144 | "nodes":[ 145 | { 146 | "children":[1,2 147 | ], 148 | "name":"Root" 149 | }, 150 | { 151 | "name":"eyes", 152 | "mesh":0 153 | }, 154 | { 155 | "name":"body", 156 | "mesh":1 157 | } 158 | ], 159 | "meshes":[ 160 | { 161 | "primitives":[ 162 | { 163 | "attributes":{ 164 | "NORMAL":3, 165 | "TEXCOORD_0":2, 166 | "POSITION":1 167 | }, 168 | "indices":0, 169 | "material":0 170 | } 171 | ] 172 | }, 173 | { 174 | "primitives":[ 175 | { 176 | "attributes":{ 177 | "NORMAL":7, 178 | "TEXCOORD_0":6, 179 | "POSITION":5 180 | }, 181 | "indices":4, 182 | "material":0 183 | } 184 | ] 185 | } 186 | ], 187 | "materials":[ 188 | { 189 | "name":"MaskMat", 190 | "pbrMetallicRoughness":{ 191 | "metallicFactor":0, 192 | "roughnessFactor":0.65200001, 193 | "baseColorTexture":{ 194 | "index":0 195 | } 196 | } 197 | } 198 | ], 199 | "scenes":[ 200 | { 201 | "nodes":[0 202 | ] 203 | } 204 | ], 205 | "textures":[ 206 | { 207 | "source":0 208 | } 209 | ], 210 | "images":[ 211 | { 212 | "uri":"mask_basecolor.png", 213 | "mimeType":"image/png" 214 | } 215 | ], 216 | "scene":0 217 | } 218 | -------------------------------------------------------------------------------- /public/assets/mask/mask_basecolor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/mask/mask_basecolor.png -------------------------------------------------------------------------------- /public/assets/mask/mask_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/mask/mask_data.bin -------------------------------------------------------------------------------- /public/assets/moon_rock/moon_rock.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":2568, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[2567 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":2568, 21 | "type":"VEC3", 22 | "min":[-54.1655273,0,-16.223877 23 | ], 24 | "max":[56.6383629,54.0221634,25.1934547 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":2568, 31 | "type":"VEC3", 32 | "min":[-0.998280764,-0.944678426,-0.99999404 33 | ], 34 | "max":[0.994417727,0.999697924,0.99999404 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":2568, 41 | "type":"VEC2", 42 | "min":[0.0139118135,0.0313016176 43 | ], 44 | "max":[0.982096791,0.972430587 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":2568, 51 | "type":"VEC4", 52 | "min":[-0.978616953,-0.999268889,-1,1 53 | ], 54 | "max":[1,0.995249152,1,1 55 | ] 56 | } 57 | ], 58 | "buffers":[ 59 | { 60 | "uri":"moon_rock_data.bin", 61 | "byteLength":128400, 62 | "name":"main_buffer" 63 | } 64 | ], 65 | "bufferViews":[ 66 | { 67 | "buffer":0, 68 | "byteLength":5136, 69 | "target":34963 70 | }, 71 | { 72 | "buffer":0, 73 | "byteOffset":5136, 74 | "byteLength":30816, 75 | "target":34962 76 | }, 77 | { 78 | "buffer":0, 79 | "byteOffset":35952, 80 | "byteLength":30816, 81 | "target":34962 82 | }, 83 | { 84 | "buffer":0, 85 | "byteOffset":66768, 86 | "byteLength":20544, 87 | "target":34962 88 | }, 89 | { 90 | "buffer":0, 91 | "byteOffset":87312, 92 | "byteLength":41088, 93 | "target":34962 94 | } 95 | ], 96 | "nodes":[ 97 | { 98 | "name":"moon_rock", 99 | "mesh":0 100 | } 101 | ], 102 | "meshes":[ 103 | { 104 | "primitives":[ 105 | { 106 | "attributes":{ 107 | "TANGENT":4, 108 | "TEXCOORD_0":3, 109 | "NORMAL":2, 110 | "POSITION":1 111 | }, 112 | "indices":0 113 | } 114 | ] 115 | } 116 | ], 117 | "scenes":[ 118 | { 119 | "nodes":[0 120 | ] 121 | } 122 | ], 123 | "scene":0 124 | } 125 | -------------------------------------------------------------------------------- /public/assets/moon_rock/moon_rock_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/moon_rock/moon_rock_data.bin -------------------------------------------------------------------------------- /public/assets/mountains/mountains.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":6021, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[6020 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":6021, 21 | "type":"VEC2", 22 | "min":[0,0.00076675415 23 | ], 24 | "max":[0.999970257,1 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":6021, 31 | "type":"VEC3", 32 | "min":[-498.883545,-2.02634907,-499.676056 33 | ], 34 | "max":[499.108582,51.3202438,499.258392 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":6021, 41 | "type":"VEC3", 42 | "min":[1,1,1 43 | ], 44 | "max":[1,1,1 45 | ] 46 | } 47 | ], 48 | "buffers":[ 49 | { 50 | "uri":"mountains_data.bin", 51 | "byteLength":204716 52 | } 53 | ], 54 | "bufferViews":[ 55 | { 56 | "buffer":0, 57 | "byteLength":12042, 58 | "target":34963 59 | }, 60 | { 61 | "buffer":0, 62 | "byteOffset":12044, 63 | "byteLength":48168, 64 | "target":34962 65 | }, 66 | { 67 | "buffer":0, 68 | "byteOffset":60212, 69 | "byteLength":72252, 70 | "target":34962 71 | }, 72 | { 73 | "buffer":0, 74 | "byteOffset":132464, 75 | "byteLength":72252, 76 | "target":34962 77 | } 78 | ], 79 | "nodes":[ 80 | { 81 | "mesh":0 82 | } 83 | ], 84 | "meshes":[ 85 | { 86 | "primitives":[ 87 | { 88 | "attributes":{ 89 | "COLOR_0":3, 90 | "POSITION":2, 91 | "TEXCOORD_0":1 92 | }, 93 | "indices":0 94 | } 95 | ] 96 | } 97 | ], 98 | "scenes":[ 99 | { 100 | "nodes":[0 101 | ] 102 | } 103 | ], 104 | "scene":0 105 | } 106 | -------------------------------------------------------------------------------- /public/assets/mountains/mountains_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/mountains/mountains_data.bin -------------------------------------------------------------------------------- /public/assets/mountains/mountains_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/mountains/mountains_diff.png -------------------------------------------------------------------------------- /public/assets/pendulum/pendulum.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":612, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[611 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":612, 21 | "type":"VEC3", 22 | "min":[-0.476314008,-0.593448222,-17.8166809 23 | ], 24 | "max":[0.476313978,18.1934757,-7.19410181 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":612, 31 | "type":"VEC3", 32 | "min":[1,0,0 33 | ], 34 | "max":[1,0,0 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":612, 41 | "type":"SCALAR", 42 | "min":[0.416666657 43 | ], 44 | "max":[1 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":612, 51 | "type":"VEC2", 52 | "min":[0,-1.85788393 53 | ], 54 | "max":[19.2293053,1 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":612, 61 | "type":"VEC3", 62 | "min":[-0.871984482,-0.711162508,-0.504324496 63 | ], 64 | "max":[0.871984482,0.365786791,1 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5121, 70 | "count":48, 71 | "type":"SCALAR", 72 | "min":[0 73 | ], 74 | "max":[47 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":48, 81 | "type":"VEC3", 82 | "min":[-0.0500000007,1.96656656,-7.44854832 83 | ], 84 | "max":[0.0500000007,18.0665665,-7.34854794 85 | ] 86 | }, 87 | { 88 | "bufferView":8, 89 | "componentType":5126, 90 | "count":48, 91 | "type":"VEC3", 92 | "min":[0,1,0 93 | ], 94 | "max":[0,1,0 95 | ] 96 | }, 97 | { 98 | "bufferView":9, 99 | "componentType":5126, 100 | "count":48, 101 | "type":"SCALAR", 102 | "min":[1 103 | ], 104 | "max":[1 105 | ] 106 | }, 107 | { 108 | "bufferView":10, 109 | "componentType":5126, 110 | "count":48, 111 | "type":"VEC2", 112 | "min":[0,0.693853259 113 | ], 114 | "max":[16.1000004,1 115 | ] 116 | }, 117 | { 118 | "bufferView":11, 119 | "componentType":5126, 120 | "count":48, 121 | "type":"VEC3", 122 | "min":[-1,0,-1 123 | ], 124 | "max":[1,0,1 125 | ] 126 | }, 127 | { 128 | "bufferView":12, 129 | "componentType":5121, 130 | "count":108, 131 | "type":"SCALAR", 132 | "min":[0 133 | ], 134 | "max":[19 135 | ] 136 | }, 137 | { 138 | "bufferView":13, 139 | "componentType":5126, 140 | "count":20, 141 | "type":"VEC3", 142 | "min":[-1.20000005,0.876239538,-8.44050884 143 | ], 144 | "max":[1.20000005,3.27623963,-6.36204767 145 | ] 146 | } 147 | ], 148 | "buffers":[ 149 | { 150 | "uri":"pendulum_data.bin", 151 | "byteLength":33300, 152 | "name":"main_buffer" 153 | } 154 | ], 155 | "bufferViews":[ 156 | { 157 | "buffer":0, 158 | "byteLength":1224, 159 | "target":34963 160 | }, 161 | { 162 | "buffer":0, 163 | "byteOffset":1224, 164 | "byteLength":7344, 165 | "target":34962 166 | }, 167 | { 168 | "buffer":0, 169 | "byteOffset":8568, 170 | "byteLength":7344, 171 | "target":34962 172 | }, 173 | { 174 | "buffer":0, 175 | "byteOffset":15912, 176 | "byteLength":2448, 177 | "target":34962 178 | }, 179 | { 180 | "buffer":0, 181 | "byteOffset":18360, 182 | "byteLength":4896, 183 | "target":34962 184 | }, 185 | { 186 | "buffer":0, 187 | "byteOffset":23256, 188 | "byteLength":7344, 189 | "target":34962 190 | }, 191 | { 192 | "buffer":0, 193 | "byteOffset":30600, 194 | "byteLength":48, 195 | "target":34963 196 | }, 197 | { 198 | "buffer":0, 199 | "byteOffset":30648, 200 | "byteLength":576, 201 | "target":34962 202 | }, 203 | { 204 | "buffer":0, 205 | "byteOffset":31224, 206 | "byteLength":576, 207 | "target":34962 208 | }, 209 | { 210 | "buffer":0, 211 | "byteOffset":31800, 212 | "byteLength":192, 213 | "target":34962 214 | }, 215 | { 216 | "buffer":0, 217 | "byteOffset":31992, 218 | "byteLength":384, 219 | "target":34962 220 | }, 221 | { 222 | "buffer":0, 223 | "byteOffset":32376, 224 | "byteLength":576, 225 | "target":34962 226 | }, 227 | { 228 | "buffer":0, 229 | "byteOffset":32952, 230 | "byteLength":108, 231 | "target":34963 232 | }, 233 | { 234 | "buffer":0, 235 | "byteOffset":33060, 236 | "byteLength":240, 237 | "target":34962 238 | } 239 | ], 240 | "nodes":[ 241 | { 242 | "children":[1,2,3 243 | ], 244 | "name":"Root" 245 | }, 246 | { 247 | "name":"stand", 248 | "mesh":0 249 | }, 250 | { 251 | "name":"rope", 252 | "mesh":1 253 | }, 254 | { 255 | "name":"ball", 256 | "mesh":2 257 | } 258 | ], 259 | "meshes":[ 260 | { 261 | "primitives":[ 262 | { 263 | "attributes":{ 264 | "NORMAL":5, 265 | "TEXCOORD_0":4, 266 | "_up":2, 267 | "_pscale":3, 268 | "POSITION":1 269 | }, 270 | "indices":0 271 | } 272 | ] 273 | }, 274 | { 275 | "primitives":[ 276 | { 277 | "attributes":{ 278 | "NORMAL":11, 279 | "TEXCOORD_0":10, 280 | "_up":8, 281 | "_pscale":9, 282 | "POSITION":7 283 | }, 284 | "indices":6 285 | } 286 | ] 287 | }, 288 | { 289 | "primitives":[ 290 | { 291 | "attributes":{ 292 | "POSITION":13 293 | }, 294 | "indices":12 295 | } 296 | ] 297 | } 298 | ], 299 | "scenes":[ 300 | { 301 | "nodes":[0 302 | ] 303 | } 304 | ], 305 | "scene":0 306 | } 307 | -------------------------------------------------------------------------------- /public/assets/pendulum/pendulum_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/pendulum/pendulum_data.bin -------------------------------------------------------------------------------- /public/assets/pendulum_base/pendulum_base.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":648, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[647 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":648, 21 | "type":"VEC3", 22 | "min":[-16.9431019,-0.660000026,-18.6599712 23 | ], 24 | "max":[16.9375591,0.0899999738,14.9689388 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":648, 31 | "type":"VEC3", 32 | "min":[-1,0,-0.998850107 33 | ], 34 | "max":[0.999936044,1,0.999991894 35 | ] 36 | } 37 | ], 38 | "buffers":[ 39 | { 40 | "uri":"pendulum_base_data.bin", 41 | "byteLength":16848, 42 | "name":"main_buffer" 43 | } 44 | ], 45 | "bufferViews":[ 46 | { 47 | "buffer":0, 48 | "byteLength":1296, 49 | "target":34963 50 | }, 51 | { 52 | "buffer":0, 53 | "byteOffset":1296, 54 | "byteLength":7776, 55 | "target":34962 56 | }, 57 | { 58 | "buffer":0, 59 | "byteOffset":9072, 60 | "byteLength":7776, 61 | "target":34962 62 | } 63 | ], 64 | "nodes":[ 65 | { 66 | "children":[1 67 | ], 68 | "name":"Root" 69 | }, 70 | { 71 | "name":"base", 72 | "mesh":0 73 | } 74 | ], 75 | "meshes":[ 76 | { 77 | "primitives":[ 78 | { 79 | "attributes":{ 80 | "NORMAL":2, 81 | "POSITION":1 82 | }, 83 | "indices":0 84 | } 85 | ] 86 | } 87 | ], 88 | "scenes":[ 89 | { 90 | "nodes":[0 91 | ] 92 | } 93 | ], 94 | "scene":0 95 | } 96 | -------------------------------------------------------------------------------- /public/assets/pendulum_base/pendulum_base_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/pendulum_base/pendulum_base_data.bin -------------------------------------------------------------------------------- /public/assets/pyramid/pyramid.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":1332, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[1331 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":1332, 21 | "type":"VEC3", 22 | "min":[-15.9083557,-0.000132443514,-15.905529 23 | ], 24 | "max":[15.9072971,22.1994743,15.9089441 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":1332, 31 | "type":"VEC2", 32 | "min":[0.00974657014,-8.65678215 33 | ], 34 | "max":[9.97804546,0.990253389 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5126, 40 | "count":1332, 41 | "type":"VEC3", 42 | "min":[-1,-0.997663021,-1 43 | ], 44 | "max":[1,0.997038543,1 45 | ] 46 | } 47 | ], 48 | "buffers":[ 49 | { 50 | "uri":"pyramid_data.bin", 51 | "byteLength":45288, 52 | "name":"main_buffer" 53 | } 54 | ], 55 | "bufferViews":[ 56 | { 57 | "buffer":0, 58 | "byteLength":2664, 59 | "target":34963 60 | }, 61 | { 62 | "buffer":0, 63 | "byteOffset":2664, 64 | "byteLength":15984, 65 | "target":34962 66 | }, 67 | { 68 | "buffer":0, 69 | "byteOffset":18648, 70 | "byteLength":10656, 71 | "target":34962 72 | }, 73 | { 74 | "buffer":0, 75 | "byteOffset":29304, 76 | "byteLength":15984, 77 | "target":34962 78 | } 79 | ], 80 | "nodes":[ 81 | { 82 | "name":"piramid", 83 | "mesh":0 84 | } 85 | ], 86 | "meshes":[ 87 | { 88 | "primitives":[ 89 | { 90 | "attributes":{ 91 | "NORMAL":3, 92 | "TEXCOORD_0":2, 93 | "POSITION":1 94 | }, 95 | "indices":0 96 | } 97 | ] 98 | } 99 | ], 100 | "scenes":[ 101 | { 102 | "nodes":[0 103 | ] 104 | } 105 | ], 106 | "scene":0 107 | } 108 | -------------------------------------------------------------------------------- /public/assets/pyramid/pyramid_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/pyramid/pyramid_data.bin -------------------------------------------------------------------------------- /public/assets/quest_controller_l/quest_controller_l.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5121, 10 | "count":48, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[47 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":48, 21 | "type":"VEC3", 22 | "min":[-0.00654221047,-0.00287701329,0.000634161057 23 | ], 24 | "max":[0.00332787097,0.00425733253,0.0107826553 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":48, 31 | "type":"VEC3", 32 | "min":[-0.995432019,-0.421608537,-0.986988604 33 | ], 34 | "max":[0.914619923,0.87443608,0.846950889 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5121, 40 | "count":48, 41 | "type":"SCALAR", 42 | "min":[0 43 | ], 44 | "max":[47 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":48, 51 | "type":"VEC3", 52 | "min":[-0.0025230844,-0.0100649763,-0.0114104263 53 | ], 54 | "max":[0.00742041925,-0.00276026293,-0.00143229577 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":48, 61 | "type":"VEC3", 62 | "min":[-0.99713999,-0.437907308,-0.940290987 63 | ], 64 | "max":[0.906493187,0.956580341,0.798744321 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5123, 70 | "count":2418, 71 | "type":"SCALAR", 72 | "min":[0 73 | ], 74 | "max":[2417 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":2418, 81 | "type":"VEC3", 82 | "min":[-0.0548305735,-0.036135938,-0.0282036792 83 | ], 84 | "max":[0.035830576,0.0685576499,0.0905904993 85 | ] 86 | }, 87 | { 88 | "bufferView":8, 89 | "componentType":5126, 90 | "count":2418, 91 | "type":"VEC3", 92 | "min":[-0.999905109,-0.999906719,-0.998884499 93 | ], 94 | "max":[0.999976099,0.999981344,0.9848544 95 | ] 96 | }, 97 | { 98 | "bufferView":9, 99 | "componentType":5121, 100 | "count":108, 101 | "type":"SCALAR", 102 | "min":[0 103 | ], 104 | "max":[107 105 | ] 106 | }, 107 | { 108 | "bufferView":10, 109 | "componentType":5126, 110 | "count":108, 111 | "type":"VEC3", 112 | "min":[-0.00293962075,-0.0202691667,0.0259559471 113 | ], 114 | "max":[0.00992851891,0.00378288794,0.045896396 115 | ] 116 | }, 117 | { 118 | "bufferView":11, 119 | "componentType":5126, 120 | "count":108, 121 | "type":"VEC3", 122 | "min":[-0.192015707,-0.995647907,-0.973826647 123 | ], 124 | "max":[0.993348539,0.959720314,0.942871392 125 | ] 126 | }, 127 | { 128 | "bufferView":12, 129 | "componentType":5121, 130 | "count":30, 131 | "type":"SCALAR", 132 | "min":[0 133 | ], 134 | "max":[29 135 | ] 136 | }, 137 | { 138 | "bufferView":13, 139 | "componentType":5126, 140 | "count":30, 141 | "type":"VEC3", 142 | "min":[-0.013914655,0.00673727551,0.0186645072 143 | ], 144 | "max":[-0.00536754541,0.0128973406,0.0254936088 145 | ] 146 | }, 147 | { 148 | "bufferView":14, 149 | "componentType":5126, 150 | "count":30, 151 | "type":"VEC3", 152 | "min":[-0.997852981,-0.633020103,-0.754319966 153 | ], 154 | "max":[0.934634149,0.766091406,0.739575326 155 | ] 156 | }, 157 | { 158 | "bufferView":15, 159 | "componentType":5123, 160 | "count":177, 161 | "type":"SCALAR", 162 | "min":[0 163 | ], 164 | "max":[176 165 | ] 166 | }, 167 | { 168 | "bufferView":16, 169 | "componentType":5126, 170 | "count":177, 171 | "type":"VEC3", 172 | "min":[-0.0265227668,-0.0118251787,-0.0168912113 173 | ], 174 | "max":[-0.00952241477,0.00374192209,0.000873250421 175 | ] 176 | }, 177 | { 178 | "bufferView":17, 179 | "componentType":5126, 180 | "count":177, 181 | "type":"VEC3", 182 | "min":[-0.974404991,-0.874780059,-0.995089352 183 | ], 184 | "max":[0.990759671,0.983626962,0.888638079 185 | ] 186 | }, 187 | { 188 | "bufferView":18, 189 | "componentType":5123, 190 | "count":171, 191 | "type":"SCALAR", 192 | "min":[0 193 | ], 194 | "max":[170 195 | ] 196 | }, 197 | { 198 | "bufferView":19, 199 | "componentType":5126, 200 | "count":171, 201 | "type":"VEC3", 202 | "min":[-0.0225639734,-0.0420421399,-0.0166532602 203 | ], 204 | "max":[0.00356398593,-0.0229955222,0.00985044613 205 | ] 206 | }, 207 | { 208 | "bufferView":20, 209 | "componentType":5126, 210 | "count":171, 211 | "type":"VEC3", 212 | "min":[-0.999799967,-0.881769776,-0.939788997 213 | ], 214 | "max":[0.999799967,0.326179445,0.817227423 215 | ] 216 | } 217 | ], 218 | "buffers":[ 219 | { 220 | "uri":"quest_controller_l_data.bin", 221 | "byteLength":77772, 222 | "name":"main_buffer" 223 | } 224 | ], 225 | "bufferViews":[ 226 | { 227 | "buffer":0, 228 | "byteLength":48, 229 | "target":34963 230 | }, 231 | { 232 | "buffer":0, 233 | "byteOffset":48, 234 | "byteLength":576, 235 | "target":34962 236 | }, 237 | { 238 | "buffer":0, 239 | "byteOffset":624, 240 | "byteLength":576, 241 | "target":34962 242 | }, 243 | { 244 | "buffer":0, 245 | "byteOffset":1200, 246 | "byteLength":48, 247 | "target":34963 248 | }, 249 | { 250 | "buffer":0, 251 | "byteOffset":1248, 252 | "byteLength":576, 253 | "target":34962 254 | }, 255 | { 256 | "buffer":0, 257 | "byteOffset":1824, 258 | "byteLength":576, 259 | "target":34962 260 | }, 261 | { 262 | "buffer":0, 263 | "byteOffset":2400, 264 | "byteLength":4836, 265 | "target":34963 266 | }, 267 | { 268 | "buffer":0, 269 | "byteOffset":7236, 270 | "byteLength":29016, 271 | "target":34962 272 | }, 273 | { 274 | "buffer":0, 275 | "byteOffset":36252, 276 | "byteLength":29016, 277 | "target":34962 278 | }, 279 | { 280 | "buffer":0, 281 | "byteOffset":65268, 282 | "byteLength":108, 283 | "target":34963 284 | }, 285 | { 286 | "buffer":0, 287 | "byteOffset":65376, 288 | "byteLength":1296, 289 | "target":34962 290 | }, 291 | { 292 | "buffer":0, 293 | "byteOffset":66672, 294 | "byteLength":1296, 295 | "target":34962 296 | }, 297 | { 298 | "buffer":0, 299 | "byteOffset":67968, 300 | "byteLength":30, 301 | "target":34963 302 | }, 303 | { 304 | "buffer":0, 305 | "byteOffset":68000, 306 | "byteLength":360, 307 | "target":34962 308 | }, 309 | { 310 | "buffer":0, 311 | "byteOffset":68360, 312 | "byteLength":360, 313 | "target":34962 314 | }, 315 | { 316 | "buffer":0, 317 | "byteOffset":68720, 318 | "byteLength":354, 319 | "target":34963 320 | }, 321 | { 322 | "buffer":0, 323 | "byteOffset":69076, 324 | "byteLength":2124, 325 | "target":34962 326 | }, 327 | { 328 | "buffer":0, 329 | "byteOffset":71200, 330 | "byteLength":2124, 331 | "target":34962 332 | }, 333 | { 334 | "buffer":0, 335 | "byteOffset":73324, 336 | "byteLength":342, 337 | "target":34963 338 | }, 339 | { 340 | "buffer":0, 341 | "byteOffset":73668, 342 | "byteLength":2052, 343 | "target":34962 344 | }, 345 | { 346 | "buffer":0, 347 | "byteOffset":75720, 348 | "byteLength":2052, 349 | "target":34962 350 | } 351 | ], 352 | "nodes":[ 353 | { 354 | "children":[1,2,3,4,5,6,7 355 | ], 356 | "name":"quest_controller_L" 357 | }, 358 | { 359 | "name":"x_button", 360 | "mesh":0 361 | }, 362 | { 363 | "name":"y_button", 364 | "mesh":1 365 | }, 366 | { 367 | "name":"body", 368 | "mesh":2 369 | }, 370 | { 371 | "name":"grip_button", 372 | "mesh":3 373 | }, 374 | { 375 | "name":"menu_button", 376 | "mesh":4 377 | }, 378 | { 379 | "name":"thumbstick", 380 | "mesh":5 381 | }, 382 | { 383 | "name":"trigger", 384 | "mesh":6 385 | } 386 | ], 387 | "meshes":[ 388 | { 389 | "primitives":[ 390 | { 391 | "attributes":{ 392 | "NORMAL":2, 393 | "POSITION":1 394 | }, 395 | "indices":0 396 | } 397 | ] 398 | }, 399 | { 400 | "primitives":[ 401 | { 402 | "attributes":{ 403 | "NORMAL":5, 404 | "POSITION":4 405 | }, 406 | "indices":3 407 | } 408 | ] 409 | }, 410 | { 411 | "primitives":[ 412 | { 413 | "attributes":{ 414 | "NORMAL":8, 415 | "POSITION":7 416 | }, 417 | "indices":6 418 | } 419 | ] 420 | }, 421 | { 422 | "primitives":[ 423 | { 424 | "attributes":{ 425 | "NORMAL":11, 426 | "POSITION":10 427 | }, 428 | "indices":9 429 | } 430 | ] 431 | }, 432 | { 433 | "primitives":[ 434 | { 435 | "attributes":{ 436 | "NORMAL":14, 437 | "POSITION":13 438 | }, 439 | "indices":12 440 | } 441 | ] 442 | }, 443 | { 444 | "primitives":[ 445 | { 446 | "attributes":{ 447 | "NORMAL":17, 448 | "POSITION":16 449 | }, 450 | "indices":15 451 | } 452 | ] 453 | }, 454 | { 455 | "primitives":[ 456 | { 457 | "attributes":{ 458 | "NORMAL":20, 459 | "POSITION":19 460 | }, 461 | "indices":18 462 | } 463 | ] 464 | } 465 | ], 466 | "scenes":[ 467 | { 468 | "nodes":[0 469 | ] 470 | } 471 | ], 472 | "scene":0 473 | } 474 | -------------------------------------------------------------------------------- /public/assets/quest_controller_l/quest_controller_l_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/quest_controller_l/quest_controller_l_data.bin -------------------------------------------------------------------------------- /public/assets/quest_controller_r/quest_controller_r.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5121, 10 | "count":48, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[47 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":48, 21 | "type":"VEC3", 22 | "min":[-0.00332787097,-0.00287701329,0.000634161057 23 | ], 24 | "max":[0.00654221047,0.00425733253,0.0107826553 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":48, 31 | "type":"VEC3", 32 | "min":[-0.914619923,-0.421608537,-0.986988604 33 | ], 34 | "max":[0.995432019,0.87443608,0.846950889 35 | ] 36 | }, 37 | { 38 | "bufferView":3, 39 | "componentType":5121, 40 | "count":48, 41 | "type":"SCALAR", 42 | "min":[0 43 | ], 44 | "max":[47 45 | ] 46 | }, 47 | { 48 | "bufferView":4, 49 | "componentType":5126, 50 | "count":48, 51 | "type":"VEC3", 52 | "min":[-0.00742041925,-0.0100649763,-0.0114104263 53 | ], 54 | "max":[0.0025230844,-0.00276026293,-0.00143229577 55 | ] 56 | }, 57 | { 58 | "bufferView":5, 59 | "componentType":5126, 60 | "count":48, 61 | "type":"VEC3", 62 | "min":[-0.906493187,-0.437907308,-0.940290987 63 | ], 64 | "max":[0.99713999,0.956580341,0.798744321 65 | ] 66 | }, 67 | { 68 | "bufferView":6, 69 | "componentType":5123, 70 | "count":2418, 71 | "type":"SCALAR", 72 | "min":[0 73 | ], 74 | "max":[2417 75 | ] 76 | }, 77 | { 78 | "bufferView":7, 79 | "componentType":5126, 80 | "count":2418, 81 | "type":"VEC3", 82 | "min":[-0.035830576,-0.036135938,-0.0282036792 83 | ], 84 | "max":[0.0548305735,0.0685576499,0.0905904993 85 | ] 86 | }, 87 | { 88 | "bufferView":8, 89 | "componentType":5126, 90 | "count":2418, 91 | "type":"VEC3", 92 | "min":[-0.999976099,-0.999906719,-0.998884499 93 | ], 94 | "max":[0.999905109,0.999981344,0.9848544 95 | ] 96 | }, 97 | { 98 | "bufferView":9, 99 | "componentType":5121, 100 | "count":108, 101 | "type":"SCALAR", 102 | "min":[0 103 | ], 104 | "max":[107 105 | ] 106 | }, 107 | { 108 | "bufferView":10, 109 | "componentType":5126, 110 | "count":108, 111 | "type":"VEC3", 112 | "min":[-0.00992851891,-0.0202691667,0.0259559471 113 | ], 114 | "max":[0.00293962075,0.00378288794,0.045896396 115 | ] 116 | }, 117 | { 118 | "bufferView":11, 119 | "componentType":5126, 120 | "count":108, 121 | "type":"VEC3", 122 | "min":[-0.993348539,-0.995647907,-0.973826647 123 | ], 124 | "max":[0.192015707,0.959720314,0.942871392 125 | ] 126 | }, 127 | { 128 | "bufferView":12, 129 | "componentType":5121, 130 | "count":30, 131 | "type":"SCALAR", 132 | "min":[0 133 | ], 134 | "max":[29 135 | ] 136 | }, 137 | { 138 | "bufferView":13, 139 | "componentType":5126, 140 | "count":30, 141 | "type":"VEC3", 142 | "min":[0.00536754541,0.00673727551,0.0186645072 143 | ], 144 | "max":[0.013914655,0.0128973406,0.0254936088 145 | ] 146 | }, 147 | { 148 | "bufferView":14, 149 | "componentType":5126, 150 | "count":30, 151 | "type":"VEC3", 152 | "min":[-0.934634149,-0.633020103,-0.754319966 153 | ], 154 | "max":[0.997852981,0.766091406,0.739575326 155 | ] 156 | }, 157 | { 158 | "bufferView":15, 159 | "componentType":5123, 160 | "count":177, 161 | "type":"SCALAR", 162 | "min":[0 163 | ], 164 | "max":[176 165 | ] 166 | }, 167 | { 168 | "bufferView":16, 169 | "componentType":5126, 170 | "count":177, 171 | "type":"VEC3", 172 | "min":[0.00952241477,-0.0118251787,-0.0168912113 173 | ], 174 | "max":[0.0265227668,0.00374192209,0.000873250421 175 | ] 176 | }, 177 | { 178 | "bufferView":17, 179 | "componentType":5126, 180 | "count":177, 181 | "type":"VEC3", 182 | "min":[-0.990759671,-0.874780059,-0.995089352 183 | ], 184 | "max":[0.974404991,0.983626962,0.888638079 185 | ] 186 | }, 187 | { 188 | "bufferView":18, 189 | "componentType":5123, 190 | "count":171, 191 | "type":"SCALAR", 192 | "min":[0 193 | ], 194 | "max":[170 195 | ] 196 | }, 197 | { 198 | "bufferView":19, 199 | "componentType":5126, 200 | "count":171, 201 | "type":"VEC3", 202 | "min":[-0.00356398593,-0.0420421399,-0.0166532602 203 | ], 204 | "max":[0.0225639734,-0.0229955222,0.00985044613 205 | ] 206 | }, 207 | { 208 | "bufferView":20, 209 | "componentType":5126, 210 | "count":171, 211 | "type":"VEC3", 212 | "min":[-0.999799967,-0.881769776,-0.939788997 213 | ], 214 | "max":[0.999799967,0.326179445,0.817227423 215 | ] 216 | } 217 | ], 218 | "buffers":[ 219 | { 220 | "uri":"quest_controller_r_data.bin", 221 | "byteLength":77772, 222 | "name":"main_buffer" 223 | } 224 | ], 225 | "bufferViews":[ 226 | { 227 | "buffer":0, 228 | "byteLength":48, 229 | "target":34963 230 | }, 231 | { 232 | "buffer":0, 233 | "byteOffset":48, 234 | "byteLength":576, 235 | "target":34962 236 | }, 237 | { 238 | "buffer":0, 239 | "byteOffset":624, 240 | "byteLength":576, 241 | "target":34962 242 | }, 243 | { 244 | "buffer":0, 245 | "byteOffset":1200, 246 | "byteLength":48, 247 | "target":34963 248 | }, 249 | { 250 | "buffer":0, 251 | "byteOffset":1248, 252 | "byteLength":576, 253 | "target":34962 254 | }, 255 | { 256 | "buffer":0, 257 | "byteOffset":1824, 258 | "byteLength":576, 259 | "target":34962 260 | }, 261 | { 262 | "buffer":0, 263 | "byteOffset":2400, 264 | "byteLength":4836, 265 | "target":34963 266 | }, 267 | { 268 | "buffer":0, 269 | "byteOffset":7236, 270 | "byteLength":29016, 271 | "target":34962 272 | }, 273 | { 274 | "buffer":0, 275 | "byteOffset":36252, 276 | "byteLength":29016, 277 | "target":34962 278 | }, 279 | { 280 | "buffer":0, 281 | "byteOffset":65268, 282 | "byteLength":108, 283 | "target":34963 284 | }, 285 | { 286 | "buffer":0, 287 | "byteOffset":65376, 288 | "byteLength":1296, 289 | "target":34962 290 | }, 291 | { 292 | "buffer":0, 293 | "byteOffset":66672, 294 | "byteLength":1296, 295 | "target":34962 296 | }, 297 | { 298 | "buffer":0, 299 | "byteOffset":67968, 300 | "byteLength":30, 301 | "target":34963 302 | }, 303 | { 304 | "buffer":0, 305 | "byteOffset":68000, 306 | "byteLength":360, 307 | "target":34962 308 | }, 309 | { 310 | "buffer":0, 311 | "byteOffset":68360, 312 | "byteLength":360, 313 | "target":34962 314 | }, 315 | { 316 | "buffer":0, 317 | "byteOffset":68720, 318 | "byteLength":354, 319 | "target":34963 320 | }, 321 | { 322 | "buffer":0, 323 | "byteOffset":69076, 324 | "byteLength":2124, 325 | "target":34962 326 | }, 327 | { 328 | "buffer":0, 329 | "byteOffset":71200, 330 | "byteLength":2124, 331 | "target":34962 332 | }, 333 | { 334 | "buffer":0, 335 | "byteOffset":73324, 336 | "byteLength":342, 337 | "target":34963 338 | }, 339 | { 340 | "buffer":0, 341 | "byteOffset":73668, 342 | "byteLength":2052, 343 | "target":34962 344 | }, 345 | { 346 | "buffer":0, 347 | "byteOffset":75720, 348 | "byteLength":2052, 349 | "target":34962 350 | } 351 | ], 352 | "nodes":[ 353 | { 354 | "children":[1,2,3,4,5,6,7 355 | ], 356 | "name":"quest_controller_R" 357 | }, 358 | { 359 | "name":"a_button", 360 | "mesh":0 361 | }, 362 | { 363 | "name":"b_button", 364 | "mesh":1 365 | }, 366 | { 367 | "name":"body", 368 | "mesh":2 369 | }, 370 | { 371 | "name":"grip_button", 372 | "mesh":3 373 | }, 374 | { 375 | "name":"menu_button", 376 | "mesh":4 377 | }, 378 | { 379 | "name":"thumbstick", 380 | "mesh":5 381 | }, 382 | { 383 | "name":"trigger", 384 | "mesh":6 385 | } 386 | ], 387 | "meshes":[ 388 | { 389 | "primitives":[ 390 | { 391 | "attributes":{ 392 | "NORMAL":2, 393 | "POSITION":1 394 | }, 395 | "indices":0 396 | } 397 | ] 398 | }, 399 | { 400 | "primitives":[ 401 | { 402 | "attributes":{ 403 | "NORMAL":5, 404 | "POSITION":4 405 | }, 406 | "indices":3 407 | } 408 | ] 409 | }, 410 | { 411 | "primitives":[ 412 | { 413 | "attributes":{ 414 | "NORMAL":8, 415 | "POSITION":7 416 | }, 417 | "indices":6 418 | } 419 | ] 420 | }, 421 | { 422 | "primitives":[ 423 | { 424 | "attributes":{ 425 | "NORMAL":11, 426 | "POSITION":10 427 | }, 428 | "indices":9 429 | } 430 | ] 431 | }, 432 | { 433 | "primitives":[ 434 | { 435 | "attributes":{ 436 | "NORMAL":14, 437 | "POSITION":13 438 | }, 439 | "indices":12 440 | } 441 | ] 442 | }, 443 | { 444 | "primitives":[ 445 | { 446 | "attributes":{ 447 | "NORMAL":17, 448 | "POSITION":16 449 | }, 450 | "indices":15 451 | } 452 | ] 453 | }, 454 | { 455 | "primitives":[ 456 | { 457 | "attributes":{ 458 | "NORMAL":20, 459 | "POSITION":19 460 | }, 461 | "indices":18 462 | } 463 | ] 464 | } 465 | ], 466 | "scenes":[ 467 | { 468 | "nodes":[0 469 | ] 470 | } 471 | ], 472 | "scene":0 473 | } 474 | -------------------------------------------------------------------------------- /public/assets/quest_controller_r/quest_controller_r_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/quest_controller_r/quest_controller_r_data.bin -------------------------------------------------------------------------------- /public/assets/ruins/pillar_texture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/ruins/pillar_texture.png -------------------------------------------------------------------------------- /public/assets/ruins/ruins.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "asset":{ 3 | "version":"2.0", 4 | "generator":"Houdini GLTF 2.0 Exporter" 5 | }, 6 | "accessors":[ 7 | { 8 | "bufferView":0, 9 | "componentType":5123, 10 | "count":6756, 11 | "type":"SCALAR", 12 | "min":[0 13 | ], 14 | "max":[6755 15 | ] 16 | }, 17 | { 18 | "bufferView":1, 19 | "componentType":5126, 20 | "count":6756, 21 | "type":"VEC3", 22 | "min":[-2.32521033,-0.0851265416,-2.11756158 23 | ], 24 | "max":[4.73573494,1.32957149,4.43106556 25 | ] 26 | }, 27 | { 28 | "bufferView":2, 29 | "componentType":5126, 30 | "count":6756, 31 | "type":"VEC2", 32 | "min":[0.00460512983,0.000924170017 33 | ], 34 | "max":[0.997475863,1.00460517 35 | ] 36 | } 37 | ], 38 | "buffers":[ 39 | { 40 | "uri":"ruins_data.bin", 41 | "byteLength":148632, 42 | "name":"main_buffer" 43 | } 44 | ], 45 | "bufferViews":[ 46 | { 47 | "buffer":0, 48 | "byteLength":13512, 49 | "target":34963 50 | }, 51 | { 52 | "buffer":0, 53 | "byteOffset":13512, 54 | "byteLength":81072, 55 | "target":34962 56 | }, 57 | { 58 | "buffer":0, 59 | "byteOffset":94584, 60 | "byteLength":54048, 61 | "target":34962 62 | } 63 | ], 64 | "nodes":[ 65 | { 66 | "name":"pillar", 67 | "mesh":0 68 | } 69 | ], 70 | "meshes":[ 71 | { 72 | "primitives":[ 73 | { 74 | "attributes":{ 75 | "TEXCOORD_0":2, 76 | "POSITION":1 77 | }, 78 | "indices":0, 79 | "material":0 80 | } 81 | ] 82 | } 83 | ], 84 | "materials":[ 85 | { 86 | "name":"ruinMat", 87 | "pbrMetallicRoughness":{ 88 | "metallicFactor":0, 89 | "roughnessFactor":0.65200001, 90 | "baseColorTexture":{ 91 | "index":0 92 | } 93 | } 94 | } 95 | ], 96 | "scenes":[ 97 | { 98 | "nodes":[0 99 | ] 100 | } 101 | ], 102 | "textures":[ 103 | { 104 | "source":0 105 | } 106 | ], 107 | "images":[ 108 | { 109 | "uri":"pillar_texture.png", 110 | "mimeType":"image/png" 111 | } 112 | ], 113 | "scene":0 114 | } 115 | -------------------------------------------------------------------------------- /public/assets/ruins/ruins_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/ruins/ruins_data.bin -------------------------------------------------------------------------------- /public/assets/speech/comment1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/comment1.mp3 -------------------------------------------------------------------------------- /public/assets/speech/comment2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/comment2.mp3 -------------------------------------------------------------------------------- /public/assets/speech/followMe.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/followMe.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech1.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech1.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech2.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech2.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech3.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech3.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech4.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech4.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech5.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech5.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech6.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech6.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speech7.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speech7.mp3 -------------------------------------------------------------------------------- /public/assets/speech/speechWin.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/speech/speechWin.mp3 -------------------------------------------------------------------------------- /public/assets/star.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/star.png -------------------------------------------------------------------------------- /public/assets/tex_Fern_Lush_Noise.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kif11/three-body/37396e371e6fb04c699881352291710346d281c1/public/assets/tex_Fern_Lush_Noise.jpg -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three Body 4 | 5 | 6 | 7 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Fire.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | import JSX from './JSX'; 3 | 4 | const Fire = (id, position, rotation, scale, offset, fps) => ( 5 | 50 | ) 51 | 52 | export default Fire; 53 | -------------------------------------------------------------------------------- /src/JSX.js: -------------------------------------------------------------------------------- 1 | const JSX = { 2 | /** 3 | * Convert JSX tags into JS createElement 4 | */ 5 | createElement: (tag, attrs, ...children) => { 6 | let element = document.createElement(tag); 7 | 8 | for (let name in attrs) { 9 | if (name && attrs.hasOwnProperty(name)) { 10 | let value = attrs[name]; 11 | if (value === true) { 12 | element.setAttribute(name, ""); 13 | } else if (value !== false && value != null) { 14 | element.setAttribute(name, value.toString()); 15 | } 16 | } 17 | } 18 | 19 | for (let i = 0; i < children.length; i++) { 20 | let child = children[i]; 21 | element.appendChild( 22 | child.nodeType == null ? 23 | document.createTextNode(child.toString()) : child); 24 | } 25 | 26 | return element; 27 | } 28 | }; 29 | 30 | export default JSX; 31 | -------------------------------------------------------------------------------- /src/Utils.js: -------------------------------------------------------------------------------- 1 | async function getHeadsetType() { 2 | const displays = await navigator.getVRDisplays(); 3 | for (let i = 0; i < displays.length; i += 1) { 4 | const d = displays[i]; 5 | if (d.displayName === "Oculus Quest") { 6 | return "Oculus Quest"; 7 | } else if (d.displayName === "Oculus Go") { 8 | return "Oculus Go"; 9 | } 10 | } 11 | return null 12 | } 13 | 14 | export { getHeadsetType }; 15 | -------------------------------------------------------------------------------- /src/components/AmbientController.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerComponent('ambient-controller', { 2 | init: function() { 3 | this.easingIn = {}; 4 | this.easingOut = {}; 5 | this.targetVolume = 0.5; 6 | 7 | this.el.sceneEl.addEventListener('begin-game', () => { 8 | this.el.components.sound__1.playSound(); 9 | this.el.components.sound__2.playSound(); 10 | this.el.components.sound__3.playSound(); 11 | this.el.components.sound__1.pool.children[0].setVolume(this.targetVolume); 12 | }); 13 | 14 | this.el.sceneEl.addEventListener('speech4-ended', () => { 15 | this.easingIn['2'] = this.el.components.sound__2.pool.children[0]; 16 | }); 17 | 18 | this.el.sceneEl.addEventListener('speech6-ended', () => { 19 | window.setTimeout(() => { 20 | this.easingIn['3'] = this.el.components.sound__3.pool.children[0]; 21 | }, 2000); 22 | }); 23 | 24 | this.el.sceneEl.addEventListener('win', () => { 25 | this.easingOut['2'] = this.el.components.sound__2.pool.children[0]; 26 | this.easingOut['3'] = this.el.components.sound__3.pool.children[0]; 27 | }); 28 | }, 29 | 30 | tick: function(time, timeDelta) { 31 | for(var key in this.easingIn) { 32 | var value = this.easingIn[key]; 33 | var curVolume = value.getVolume(); 34 | curVolume += 0.0000625*timeDelta; 35 | if (curVolume > this.targetVolume){ 36 | delete this.easingIn[key]; 37 | } else { 38 | value.setVolume(curVolume); 39 | } 40 | } 41 | for(var key in this.easingOut) { 42 | var value = this.easingOut[key]; 43 | var curVolume = value.getVolume(); 44 | curVolume -= 0.0000625*timeDelta; 45 | if(curVolume <= 0){ 46 | delete this.easingOut[key]; 47 | } else { 48 | value.setVolume(curVolume); 49 | } 50 | } 51 | } 52 | }) 53 | -------------------------------------------------------------------------------- /src/components/CharacterMover.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | import { setQuaternionFromDirection } from '../libs/Utils'; 4 | 5 | import SunCalibratedMaterial from '../shaders/SunCalibratedMaterial'; 6 | import CharacterStateMachine from '../components/CharacterStateMachine'; 7 | 8 | //CONSTANTS 9 | const CHARACTER_HEIGHT = -1; 10 | const DEHYDRATED_BODY_POS = new THREE.Vector3(5.8, CHARACTER_HEIGHT, 15.8); 11 | const PYRAMID_ENTRANCE_POS = new THREE.Vector3(32.25, CHARACTER_HEIGHT, 54.42); 12 | const PENDULUM_POS = new THREE.Vector3(34, CHARACTER_HEIGHT, -19); 13 | 14 | const UP = new THREE.Vector3(0,1,0); 15 | 16 | AFRAME.registerComponent('character-mover', { 17 | schema: { 18 | }, 19 | 20 | init: function () { 21 | const system = document.querySelector('a-scene').systems['sunSystem']; 22 | this.cameraEl = document.querySelector('#camera'); 23 | 24 | this.targetPos = new THREE.Vector3(0, 1, -40); 25 | this.characterPos = new THREE.Vector3(0, CHARACTER_HEIGHT, -40); 26 | this.el.setAttribute('position', this.characterPos); 27 | this.targetQuat = new THREE.Quaternion(); 28 | this.lookAtDir = new THREE.Vector3(); 29 | 30 | this.walkingSpeed = 0.00208; 31 | this.reachedCharacter = true; 32 | 33 | this.stateMachine = new CharacterStateMachine(); 34 | 35 | // EVENT CHAIN 36 | this.el.sceneEl.addEventListener('fade-in-complete', (event) => { 37 | this.reachedCharacter = false; 38 | }); 39 | this.el.sceneEl.addEventListener('speech1-ended', (event) => { 40 | window.setTimeout(() => { 41 | this.el.sceneEl.emit('speech2'); 42 | }, 4000); 43 | }); 44 | this.el.sceneEl.addEventListener('speech2-ended', (event) => { 45 | this.targetPos.copy(DEHYDRATED_BODY_POS); 46 | this.reachedCharacter = false; 47 | window.setTimeout(() => { 48 | this.el.sceneEl.emit('comment1'); 49 | }, 4000); 50 | }); 51 | this.el.sceneEl.addEventListener('comment1-ended', (event) => { 52 | this.commentOver = true; 53 | }); 54 | this.el.sceneEl.addEventListener('speech3-ended', (event) => { 55 | this.targetPos.copy(PENDULUM_POS); 56 | this.reachedCharacter = false; 57 | }); 58 | this.el.sceneEl.addEventListener('speech4-ended', (event) => { 59 | //START THE PACING CYCLE 60 | this.walkingSpeed = 0.000125; 61 | this.targetPos.copy(PENDULUM_POS); 62 | this.targetPos.x += 4*(Math.random()-0.5); 63 | this.reachedCharacter = false; 64 | window.setTimeout(() => { 65 | //TELLS USER TO RUN 66 | this.stateMachine.state = -1; 67 | this.el.sceneEl.emit('speech6'); 68 | }, 69000); 69 | window.setTimeout(() => { 70 | //LOOK AT THE SKY 71 | this.stateMachine.state = 4; 72 | this.targetPos.set(this.characterPos.x ,CHARACTER_HEIGHT, PENDULUM_POS.z - 3); 73 | }, 67000); 74 | window.setTimeout(() => { 75 | const psystem = document.querySelector('a-scene').systems['pendulum']; 76 | const synch = psystem.getSynchStatus(); 77 | if(synch) { 78 | this.el.sceneEl.emit('speech5'); 79 | } else { 80 | this.el.sceneEl.emit('speech7'); 81 | } 82 | //speech 5 83 | }, 40000); 84 | }); 85 | 86 | this.el.sceneEl.addEventListener('speech6-ended', (event) => { 87 | this.walkingSpeed = 0.003515; 88 | window.setTimeout(() => { 89 | this.stateMachine.state = 5; 90 | this.targetPos.copy(PYRAMID_ENTRANCE_POS); 91 | this.reachedCharacter = false; 92 | }, 3000); 93 | window.setTimeout(() => { 94 | this.el.sceneEl.emit('comment2'); 95 | this.commentOver = false; 96 | document.querySelectorAll('.fire').forEach(el => el.emit('start-char-fire')) 97 | }, 6000); 98 | }); 99 | this.el.sceneEl.addEventListener('speechWin-ended', (event) => { 100 | window.setTimeout(() => { 101 | this.el.sceneEl.emit('gameWin'); 102 | }, 30000); 103 | }); 104 | this.el.sceneEl.addEventListener('comment2-ended', (event) => { 105 | this.commentOver = true; 106 | }); 107 | this.el.sceneEl.addEventListener('win', (event) => { 108 | window.setTimeout(() => { 109 | this.el.sceneEl.emit('speechWin'); 110 | }, 3000); 111 | window.setTimeout(() => { 112 | document.querySelectorAll('.fire').forEach(el => el.emit('stop-char-fire')) 113 | }, 7000); 114 | }); 115 | }, 116 | 117 | updateTargetPos: function (timeDelta) { 118 | this.characterPos.y = CHARACTER_HEIGHT; 119 | 120 | if(!this.reachedCharacter){ 121 | this.stateMachine.getTargetPos(this.targetPos); 122 | this.lookAtDir.subVectors(this.targetPos, this.characterPos); 123 | //always face facePos 124 | setQuaternionFromDirection(this.lookAtDir.clone().normalize(), UP, this.targetQuat); 125 | var dist = this.lookAtDir.length(); 126 | if(dist < 1) { 127 | this.reachedCharacter = true; 128 | this.stateMachine.updateState(this); 129 | return; 130 | } 131 | this.lookAtDir.multiplyScalar(this.walkingSpeed*timeDelta/dist); 132 | this.characterPos.add(this.lookAtDir) 133 | this.el.object3D.quaternion.slerp(this.targetQuat, 0.00625*timeDelta); 134 | } else { 135 | //rotate to face user, when not facing a target 136 | var camWorldPos = new THREE.Vector3(); 137 | camWorldPos.setFromMatrixPosition(this.cameraEl.object3D.matrixWorld); 138 | camWorldPos.y = CHARACTER_HEIGHT; 139 | this.lookAtDir.subVectors(camWorldPos, this.characterPos); 140 | 141 | setQuaternionFromDirection(this.lookAtDir.normalize(), UP, this.targetQuat); 142 | this.el.object3D.quaternion.slerp(this.targetQuat, 0.00625*timeDelta); 143 | } 144 | 145 | }, 146 | 147 | tick: function (time, timeDelta) { 148 | this.updateTargetPos(timeDelta); 149 | 150 | // move character up and down 151 | var idx = 10*Math.sin(time/3000); 152 | this.characterPos.y = CHARACTER_HEIGHT + 1 + 0.1*Math.sin(idx)/idx; 153 | this.el.setAttribute('position', this.characterPos); 154 | } 155 | }); 156 | -------------------------------------------------------------------------------- /src/components/CharacterStateMachine.js: -------------------------------------------------------------------------------- 1 | const THREE = AFRAME.THREE; 2 | /** SEQUENCER BASED ON EVENTS 3 | REACH USER 4 | BEGIN SPEECH 1 (greeting) 5 | BEGIN SPEECH 2 (history) AND TRIGGER FOLLOW 6 | REACH DEHYDRATED BODY 7 | BEGIN SPEECH 3 (dehydration) AND TRIGGER FOLLOW 8 | REACH SUN DIAL 9 | BEGIN SPEECH 4 (prediction) 10 | BEGIN SPEECH 5 (find shade) 11 | REACH SHELTER, OR BURN 12 | **/ 13 | 14 | //CONSTANTS 15 | const CHARACTER_HEIGHT = -1; 16 | const PENDULUM_POS = new THREE.Vector3(34, CHARACTER_HEIGHT, -19); 17 | const WIN_POS = new THREE.Vector3(60.74943, CHARACTER_HEIGHT, 52.90357); 18 | 19 | export default class CharacterStateMachine { 20 | constructor(){ 21 | this.state = 0; 22 | this.camera = document.querySelector('#camera'); 23 | this.tmps = { 24 | v1: new THREE.Vector3(), 25 | v2: new THREE.Vector3(), 26 | } 27 | } 28 | getTargetPos(targetPos) { 29 | switch(this.state){ 30 | case 0: 31 | //REACH USER 32 | var worldPos = this.tmps.v1.setFromMatrixPosition(this.camera.object3D.matrixWorld); 33 | var forward = this.tmps.v2.set(0,0,1).transformDirection(this.camera.object3D.matrixWorld) 34 | worldPos.sub(forward.normalize().multiplyScalar(1.5)); 35 | targetPos.set(worldPos.x,-1,worldPos.z); 36 | break; 37 | case 1: 38 | break; 39 | case 3: 40 | break; 41 | } 42 | } 43 | updateState(ref) { 44 | switch(this.state){ 45 | case 0: 46 | ref.el.sceneEl.emit('speech1'); 47 | this.state += 1; 48 | break; 49 | 50 | case 1: 51 | //if comment 1 is over then start speech3 52 | if(ref.commentOver){ 53 | window.setTimeout(() => { 54 | ref.el.sceneEl.emit('speech3'); 55 | }, 5000); 56 | window.setTimeout(() => { 57 | ref.el.sceneEl.emit('start-sun-animation'); 58 | }, 10); 59 | this.state += 1; 60 | } else { 61 | //try again 62 | ref.reachedCharacter = false; 63 | } 64 | break; 65 | 66 | case 2: 67 | window.setTimeout(() => { 68 | ref.el.sceneEl.emit('speech4'); 69 | }, 5000); 70 | this.state += 1; 71 | break; 72 | 73 | case 3: 74 | //keep generating new targets, never update state 75 | ref.targetPos.copy(PENDULUM_POS); 76 | ref.targetPos.x += 4*(Math.random()-0.5); 77 | ref.reachedCharacter = false; 78 | break; 79 | 80 | case 4: 81 | break; 82 | 83 | case 5: 84 | ref.targetPos.set(60.74943, CHARACTER_HEIGHT, 52.90357); 85 | ref.reachedCharacter = false; 86 | this.state += 1; 87 | break; 88 | 89 | case 6: 90 | ref.targetPos.set(55.74943, CHARACTER_HEIGHT, 53.1357); 91 | ref.reachedCharacter = false; 92 | this.state += 1; 93 | break; 94 | case 7: 95 | //should be inside... 96 | if(ref.commentOver){ 97 | ref.reachedCharacter = false; 98 | var camWorldPos = this.tmps.v1.setFromMatrixPosition(this.camera.object3D.matrixWorld); 99 | camWorldPos.setFromMatrixPosition(this.camera.object3D.matrixWorld); 100 | var distanceToShade = camWorldPos.distanceTo(WIN_POS); 101 | if(distanceToShade < 10){ 102 | ref.el.sceneEl.emit('win'); 103 | ref.reachedCharacter = true; 104 | } 105 | } else { 106 | ref.reachedCharacter = false; 107 | } 108 | break; 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/components/Collider.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | AFRAME.registerComponent('collider', { 5 | schema: { 6 | camera: { 7 | type: 'boolean', 8 | default: 'false' 9 | } 10 | }, 11 | 12 | init: function () { 13 | this.raycaster = new THREE.Raycaster(); 14 | if(this.data.camera){ 15 | this.raycastingEl = document.querySelector('#camera'); 16 | } else { 17 | this.raycastingEl = this.el; 18 | } 19 | 20 | }, 21 | 22 | collide: function(forward) { 23 | var dir = (forward)? -1 : 1; 24 | //global collider entities ............ 25 | this.colliders = this.el.sceneEl.object3D.colliders; 26 | var worldPos = new THREE.Vector3(); 27 | worldPos.setFromMatrixPosition(this.raycastingEl.object3D.matrixWorld); 28 | var forward = new THREE.Vector3(0,0,dir).transformDirection(this.raycastingEl.object3D.matrixWorld); 29 | 30 | this.raycaster.set(worldPos, forward.normalize()); 31 | var closestPoint = this.raycaster.intersectObjects( this.colliders, true )[0]; 32 | if(closestPoint){ 33 | //do not move camera! 34 | if(closestPoint.distance < 1){ 35 | return true; 36 | } 37 | } 38 | return false; 39 | }, 40 | }); 41 | -------------------------------------------------------------------------------- /src/components/CustomControl.js: -------------------------------------------------------------------------------- 1 | 2 | import AFRAME from 'aframe'; 3 | import { fresnelMaterial } from './FresnelMaterial'; 4 | import { getHeadsetType } from '../Utils.js' 5 | 6 | AFRAME.registerComponent('custom-control', { 7 | schema: { 8 | hand: { default: '' }, 9 | modelL: { default: 'assets/quest_controller_l/quest_controller_l.gltf' }, 10 | modelR: { default: 'assets/quest_controller_r/quest_controller_r.gltf' } 11 | }, 12 | 13 | update: async function () { 14 | const headsetType = await getHeadsetType(); 15 | 16 | var hand = this.data.hand; 17 | var controlConfiguration = { 18 | hand: hand, 19 | model: headsetType !== 'Oculus Quest', 20 | }; 21 | 22 | // Build on top of controller components. 23 | this.el.setAttribute('oculus-go-controls', controlConfiguration); 24 | this.el.setAttribute('vive-controls', controlConfiguration); 25 | this.el.setAttribute('oculus-touch-controls', controlConfiguration); 26 | this.el.setAttribute('daydream-controls', controlConfiguration); 27 | this.el.setAttribute('gearvr-controls', controlConfiguration); 28 | this.el.setAttribute('windows-motion-controls', controlConfiguration); 29 | 30 | // Add controller when entering VR 31 | if (headsetType === 'Oculus Quest') { 32 | this.el.sceneEl.addEventListener('enter-vr', (ent) => { 33 | this.el.setAttribute('visible', true); 34 | 35 | // Set a model. 36 | if (hand === 'left') { 37 | this.el.setAttribute('gltf-model', this.data.modelL); 38 | } else { 39 | this.el.setAttribute('gltf-model', this.data.modelR); 40 | } 41 | 42 | const activeMaterial = new THREE.MeshBasicMaterial({ 43 | color: new THREE.Color("#289683"), 44 | }); 45 | 46 | const buttons = { 47 | 'thumbstick': { 48 | down: 'thumbsticktouchstart', 49 | up: 'thumbsticktouchend', 50 | }, 51 | 'a_button': { 52 | down: 'abuttondown', 53 | up: 'abuttonup', 54 | }, 55 | 'b_button': { 56 | down: 'bbuttondown', 57 | up: 'bbuttonup', 58 | }, 59 | 'x_button': { 60 | down: 'xbuttondown', 61 | up: 'xbuttonup', 62 | }, 63 | 'y_button': { 64 | down: 'ybuttondown', 65 | up: 'ybuttonup', 66 | }, 67 | 'grip_button': { 68 | down: 'gripdown', 69 | up: 'gripup', 70 | }, 71 | 'trigger': { 72 | down: 'triggerdown', 73 | up: 'triggerup', 74 | }, 75 | } 76 | 77 | this.el.addEventListener('model-loaded', (event) => { 78 | const scene = event.detail.model.children[0].children; 79 | 80 | for (let i = 0; i < scene.length; i += 1) { 81 | const child = scene[i]; 82 | child.material = fresnelMaterial; 83 | 84 | // Register events for changing buttons material when pressed 85 | if (child.name in buttons) { 86 | const btn = buttons[child.name] 87 | this.el.addEventListener(btn.down, () => { 88 | child.material = activeMaterial; 89 | }) 90 | this.el.addEventListener(btn.up, () => { 91 | child.material = fresnelMaterial; 92 | }) 93 | } 94 | } 95 | }); 96 | }); 97 | 98 | // Remove controllers 99 | this.el.sceneEl.addEventListener('exit-vr', (ent) => { 100 | this.el.setAttribute('visible', false); 101 | }); 102 | } 103 | 104 | } 105 | }); -------------------------------------------------------------------------------- /src/components/DefaultMaterial.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | import SunCalibratedMaterial from '../shaders/SunCalibratedMaterial'; 3 | const THREE = AFRAME.THREE; 4 | 5 | AFRAME.registerComponent('default-material', { 6 | schema: { 7 | color: { 8 | type: 'color' 9 | }, 10 | depthWrite: { 11 | type: 'boolean', 12 | default: 'true' 13 | } 14 | }, 15 | init: function () { 16 | const mesh = this.el.object3D.children[0]; 17 | mesh.material = new THREE.SunCalibratedMaterial(); 18 | mesh.material.color = new THREE.Color(this.data.color); 19 | }, 20 | 21 | tick: function (time, timeDelta) { 22 | } 23 | }); 24 | -------------------------------------------------------------------------------- /src/components/FireManager.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | AFRAME.registerComponent('fire-manager', { 5 | init: function () { 6 | this.el.addEventListener('vertex-cache-loaded', (evt) => { 7 | this.model = this.el.object3D.children[0]; 8 | this.model.visible = false; 9 | }); 10 | 11 | this.el.sceneEl.addEventListener('start-char-fire', (evt) => { 12 | this.el.emit('start-vertex-animation'); // vertex cache texture waits for this event to start the animation 13 | this.animateScale = true; 14 | this.model.visible = true; 15 | }); 16 | 17 | this.el.sceneEl.addEventListener('stop-char-fire', (evt) => { 18 | this.el.emit('stop-vertex-animation'); 19 | this.animateScale = true; 20 | this.model.visible = false; 21 | }); 22 | 23 | this.animateScale = false; 24 | this.scaleIncrement = new THREE.Vector3(0.00002, 0.00002, 0.00002); //per second 25 | this.scaleMax = 0.02; 26 | }, 27 | 28 | tick: function (time, timeDelta) { 29 | if (this.animateScale) { 30 | let scale = this.el.getAttribute('scale'); 31 | 32 | scale.add(this.scaleIncrement.clone().multiplyScalar(time / 10000)); 33 | if (scale.x > this.scaleMax){ 34 | this.animateScale = false; 35 | } 36 | this.el.setAttribute('scale', scale); 37 | } 38 | } 39 | }); 40 | -------------------------------------------------------------------------------- /src/components/FresnelMaterial.js: -------------------------------------------------------------------------------- 1 | 2 | import FresnelFrag from '../shaders/FresnelFrag.glsl' 3 | import FresnelVert from '../shaders/FresnelVert.glsl' 4 | 5 | export const fresnelMaterial = new THREE.ShaderMaterial({ 6 | uniforms: { 7 | mRefractionRatio: { value: 1.02 }, 8 | mFresnelBias: { value: 0.1 }, 9 | mFresnelPower: { value: 2.0 }, 10 | mFresnelScale: { value: 1.0 } 11 | }, 12 | vertexShader: FresnelVert, 13 | fragmentShader: FresnelFrag, 14 | }); 15 | -------------------------------------------------------------------------------- /src/components/GlowMaterial.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | import GlowFrag from '../shaders/GlowFrag.glsl'; 3 | import GlowVert from '../shaders/GlowVert.glsl'; 4 | 5 | AFRAME.registerComponent('glow-material', { 6 | init: function () { 7 | const noiseTexture = new THREE.TextureLoader().load('/assets/tex_Fern_Lush_Noise.jpg'); 8 | this.glowMaterial = new THREE.ShaderMaterial({ 9 | uniforms: { 10 | noise: { 11 | value: noiseTexture 12 | }, 13 | time: { 14 | value: 0 15 | } 16 | }, 17 | vertexShader: GlowVert, 18 | fragmentShader: GlowFrag, 19 | }); 20 | 21 | const mesh = this.el.object3D.children[0]; 22 | mesh.material = this.glowMaterial; 23 | }, 24 | 25 | tick: function (time, timeDelta) { 26 | this.glowMaterial.uniforms.time.value = time; 27 | } 28 | }); 29 | -------------------------------------------------------------------------------- /src/components/Intro.js: -------------------------------------------------------------------------------- 1 | import IntroFrag from '../shaders/IntroFrag.glsl'; 2 | import IntroVert from '../shaders/IntroVert.glsl'; 3 | 4 | import AFRAME from 'aframe'; 5 | const THREE = AFRAME.THREE; 6 | 7 | AFRAME.registerComponent('intro', { 8 | init: function () { 9 | const planeMat = new THREE.ShaderMaterial({ 10 | uniforms: { 11 | time: { value: 0 }, 12 | color1: { value: new THREE.Color("#000319") }, 13 | }, 14 | vertexShader: IntroVert, //lol 15 | fragmentShader: IntroFrag, 16 | }); 17 | 18 | const planeGeo = new THREE.PlaneGeometry(20,20); 19 | const introPlane = new THREE.Mesh(planeGeo, planeMat); 20 | this.el.object3D.add(introPlane) 21 | this.introPlane = introPlane; 22 | }, 23 | 24 | tick: function (time, timeDelta) { 25 | this.introPlane.material.uniforms.time.value = time; 26 | } 27 | }); 28 | -------------------------------------------------------------------------------- /src/components/Mover.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | const PENDULUM_POS = new THREE.Vector3(34, -1, -19); 5 | 6 | AFRAME.registerComponent('mover', { 7 | schema: { 8 | speed: { 9 | type: 'int', 10 | default: 65 11 | } 12 | }, 13 | 14 | init: function () { 15 | this.pressed = false; 16 | this.pressedQuest = false; 17 | this.lastAxis = new THREE.Vector2(); 18 | this.vrMovingSpeed = 0.0039; 19 | 20 | const rig = document.querySelector('#cameraRig'); 21 | this.rig = rig.object3D; 22 | 23 | const camera = document.querySelector('#camera'); 24 | this.collider = this.el.components.collider; 25 | 26 | this.wasd = camera.getAttribute('wasd-controls'); 27 | this.camera = camera.object3D; 28 | 29 | this.wasd.acceleration = this.data.speed; 30 | this.forward = true; 31 | 32 | const system = document.querySelector('a-scene').systems['sunSystem']; 33 | system.registerMainCharacter(this.camera); 34 | 35 | this.raycasterSystem = document.querySelector('a-scene').systems['raycasterSystem']; 36 | 37 | this.el.addEventListener('trackpaddown', () => { 38 | this.pressed = true; 39 | }); 40 | this.el.addEventListener('trackpadup', () => { 41 | this.pressed = false; 42 | }); 43 | 44 | this.el.addEventListener('axismove', (evt) => { 45 | this.lastAxis.x = evt.detail.axis[0]; 46 | this.lastAxis.y = evt.detail.axis[1]; 47 | }); 48 | 49 | window.addEventListener('keydown', (evt) => { 50 | if(evt.key == 'w'){ 51 | this.forward = true; 52 | } 53 | if(evt.key == 's'){ 54 | this.forward = false; 55 | } 56 | }); 57 | 58 | /* 59 | Oculus touch controller events 60 | */ 61 | this.el.addEventListener('thumbsticktouchstart', (evt) => { 62 | this.pressedQuest = true; 63 | }) 64 | this.el.addEventListener('thumbsticktouchend', (evt) => { 65 | this.pressedQuest = false; 66 | }) 67 | }, 68 | 69 | tick: function (time, timeDelta) { 70 | if(this.pressed){ 71 | const tweenForward = new THREE.Vector3(0, 0, 1).applyQuaternion(this.camera.quaternion); 72 | this.handleMove(tweenForward, timeDelta); 73 | } else if (this.pressedQuest){ 74 | const tweenForward = new THREE.Vector3(-this.lastAxis.x, 0, -this.lastAxis.y).applyQuaternion(this.camera.quaternion); 75 | this.handleMove(tweenForward, timeDelta); 76 | } else { 77 | //handle web 78 | const collided = this.collider.collide(this.forward); 79 | this.wasd.enabled = !collided; 80 | } 81 | }, 82 | 83 | handleMove: function (move, timeDelta){ 84 | move.y = 0; 85 | const collided = this.collider.collide(true); 86 | if (!collided) { 87 | this.rig.position.sub(move.multiplyScalar(this.vrMovingSpeed * timeDelta)) 88 | } 89 | const dist = this.rig.position.distanceTo(PENDULUM_POS); 90 | if (dist < 20) { 91 | debugger; 92 | // enable laser 93 | this.raycasterSystem.laserPlane.visible = true; 94 | } else { 95 | // disable laser 96 | this.raycasterSystem.laserPlane.visible = false; 97 | } 98 | } 99 | }); 100 | -------------------------------------------------------------------------------- /src/components/Pendulum.js: -------------------------------------------------------------------------------- 1 | import PendulumMaterial from '../shaders/PendulumMaterial'; 2 | import SunCalibratedMaterial from '../shaders/SunCalibratedMaterial'; 3 | 4 | import PendulumFrag from '../shaders/PendulumFrag.glsl'; 5 | import PendulumVert from '../shaders/PendulumVert.glsl'; 6 | 7 | import AFRAME from 'aframe'; 8 | const THREE = AFRAME.THREE; 9 | 10 | AFRAME.registerComponent('pendulum', { 11 | schema: { 12 | height: { 13 | type: 'int', 14 | default: 16.1 15 | }, 16 | radius: { 17 | type: 'int', 18 | default: 1 19 | }, 20 | color: { 21 | type: 'color', 22 | default: null 23 | }, 24 | }, 25 | 26 | init: function () { 27 | const system = document.querySelector('a-scene').systems['sunSystem']; 28 | this.material = new SunCalibratedMaterial(system, new THREE.Color(this.data.color)); 29 | 30 | const camera = document.querySelector('#camera'); 31 | this.lookControls = camera.getAttribute('look-controls'); 32 | 33 | this.el.addEventListener('model-loaded', () => { 34 | const scene = this.el.getObject3D('mesh'); 35 | this.ball = scene.children[0].children[2] 36 | this.el.object3D.add(this.ball); 37 | 38 | this.ball.material = new PendulumMaterial(system, new THREE.Color(this.data.color)); 39 | this.ball.geometry.computeVertexNormals(); 40 | 41 | this.rope = scene.children[0].children[1]; 42 | this.rope.material = this.material; 43 | this.rope.geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -18.1, 0 ) ); 44 | this.rope.position.y = 18.1; 45 | 46 | this.stand = scene.children[0].children[0]; 47 | this.stand.material = this.material; 48 | }); 49 | 50 | this.ball = new THREE.Object3D() 51 | this.ball.material = {}; 52 | 53 | this.root = new THREE.Vector3(0,this.data.height,0); 54 | this.offsetRoot = new THREE.Vector3(0, this.data.height, -7.4); 55 | 56 | this.axis = new THREE.Vector3(0, -1, 0); 57 | this.rotAxis = new THREE.Vector3(0, 0, -1); 58 | this.quat = new THREE.Quaternion(); 59 | this.length = this.data.height - this.data.radius/2; 60 | 61 | var planeGeo = new THREE.PlaneGeometry( this.data.height,this.data.height ); 62 | const planeMat = new THREE.MeshBasicMaterial({ 63 | color: new THREE.Color("#ff00ff"), 64 | wireframe: true, 65 | side: THREE.DoubleSide, 66 | alphaTest: 0, 67 | visible: false 68 | }) 69 | this.plane = new THREE.Mesh(planeGeo, planeMat); 70 | this.plane.position.z = -7.4; 71 | this.el.object3D.add(this.plane); 72 | 73 | this.force = 2; 74 | this.curTime = 0; 75 | this.startingAngle = 0; 76 | this.curAngle = 0; 77 | 78 | this.raycasterSystem = document.querySelector('a-scene').systems['raycasterSystem']; 79 | 80 | this.el.sceneEl.addEventListener( 'raycast-active-onset', (event) => { 81 | var t = this.raycasterSystem.intersectObject(this.ball); 82 | if(t[0]){ 83 | this.lookControls.enabled = false; 84 | this.raycasting = true; 85 | } 86 | }, false ); 87 | 88 | this.el.sceneEl.addEventListener( 'raycast-active', (event) => { 89 | var t = this.raycasterSystem.intersectObject(this.ball); 90 | var m = this.raycasterSystem.intersectObject(this.plane); 91 | 92 | if(m[0]&&t[0]){ 93 | this.el.object3D.worldToLocal(m[0].point); 94 | m[0].point.sub(this.offsetRoot).normalize().multiplyScalar(this.length).add(this.offsetRoot); 95 | this.startingAngle = m[0].point.clone().sub(this.offsetRoot).angleTo(this.axis); 96 | this.force = 1; 97 | if(m[0].point.x > 0){ 98 | this.startingAngle *= -1; 99 | } 100 | this.curTime = 0; 101 | m[0].point.z = 0; 102 | this.ball.position.copy(m[0].point); 103 | if(this.rope){ 104 | this.quat.setFromAxisAngle(this.rotAxis, this.startingAngle); 105 | this.rope.quaternion.copy(this.quat); 106 | } 107 | } 108 | }, false ); 109 | 110 | this.el.sceneEl.addEventListener( 'raycast-finished', (event) => { 111 | this.raycasting = false; 112 | this.lookControls.enabled = true; 113 | }, false ); 114 | 115 | this.system.registerPendulum(this); 116 | }, 117 | brighten: function (coef) { 118 | if(!this.ball.material.shader) return; 119 | this.ball.material.shader.uniforms.glow.value = coef; 120 | }, 121 | tick: function (time, timeDelta) { 122 | 123 | if(this.raycasting) return; 124 | if(!this.ball) return; 125 | 126 | // this.force *= 0.998; 127 | this.dampeningFactor = this.startingAngle * this.force; 128 | this.curAngle = this.dampeningFactor*Math.cos(this.curTime); 129 | this.quat.setFromAxisAngle(this.rotAxis, this.curAngle); 130 | 131 | if(this.rope){ 132 | this.rope.quaternion.copy(this.quat); 133 | } 134 | var newAxis = this.axis.clone().applyQuaternion(this.quat).multiplyScalar(this.length); 135 | var newPos = this.root.clone().add(newAxis); 136 | if(this.startingAngle < 0 ) { 137 | this.curTime -= 0.0015*timeDelta; 138 | } else { 139 | this.curTime += 0.0015*timeDelta; 140 | } 141 | this.ball.position.copy(newPos); 142 | } 143 | }); 144 | -------------------------------------------------------------------------------- /src/components/RingOfFire.js: -------------------------------------------------------------------------------- 1 | import FireRingFrag from '../shaders/FireRingFrag.glsl'; 2 | import FireRingVert from '../shaders/FireRingVert.glsl'; 3 | 4 | import AFRAME from 'aframe'; 5 | const THREE = AFRAME.THREE; 6 | 7 | AFRAME.registerComponent('ring-of-fire', { 8 | schema: { 9 | }, 10 | 11 | init: function () { 12 | //add ring of fire cylinder 13 | var fireRingMat = new THREE.ShaderMaterial({ 14 | uniforms: { 15 | sunCentroid: {value: new THREE.Vector3(0,0,0)}, 16 | fadeOutTime: {value: -1}, 17 | fireRingColor2: {value: new THREE.Color("#f7f5e7")}, 18 | fireRingColor1: {value: new THREE.Color("#ffcc00")}, 19 | time: {value: 0}, 20 | }, 21 | side:THREE.DoubleSide, 22 | transparent: true, 23 | vertexShader: FireRingVert, 24 | fragmentShader: FireRingFrag, 25 | depthWrite: false, 26 | }); 27 | 28 | var fireRingGeo = new THREE.CylinderGeometry( 100, 100, 30, 32, null, true ); 29 | var fireRing = new THREE.Mesh(fireRingGeo, fireRingMat); 30 | fireRing.frustumCulled = false; 31 | fireRing.position.set(0,15,0); 32 | fireRing.scale.set(1,1,1); 33 | this.el.object3D.add(fireRing); 34 | 35 | //register to be synced with sun parameters 36 | const system = document.querySelector('a-scene').systems['sunSystem']; 37 | system.registerMaterial(fireRingMat); 38 | }, 39 | tick: function (time, timeDelta) { 40 | } 41 | }); 42 | -------------------------------------------------------------------------------- /src/components/SetCharacterMaterial.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | 3 | import SunCalibratedMaterial from '../shaders/SunCalibratedMaterial'; 4 | import EyeFrag from '../shaders/EyeFrag.glsl'; 5 | import EyeVert from '../shaders/EyeVert.glsl'; 6 | 7 | const THREE = AFRAME.THREE; 8 | 9 | AFRAME.registerComponent('set-character-material', { 10 | schema: { 11 | color: { 12 | type: 'color', 13 | default: null 14 | } 15 | }, 16 | init: function () { 17 | 18 | const system = document.querySelector('a-scene').systems['sunSystem']; 19 | 20 | this.eyeMaterial = new THREE.ShaderMaterial({ 21 | uniforms: { 22 | time: { value: 0 }, 23 | }, 24 | vertexShader: EyeVert, 25 | fragmentShader: EyeFrag, 26 | }); 27 | 28 | this.material = new SunCalibratedMaterial(system); 29 | const { color } = this.data; 30 | this.el.addEventListener('model-loaded', () => { 31 | const scene = this.el.getObject3D('mesh'); 32 | const eyeMesh = scene.getObjectByName('eyes'); 33 | const bodyMesh = scene.getObjectByName('body'); 34 | if (eyeMesh) { 35 | eyeMesh.material = this.eyeMaterial; 36 | } 37 | if (bodyMesh) { 38 | const { map: diffTexture } = bodyMesh.material; 39 | 40 | if (diffTexture) { 41 | this.material.map = diffTexture; 42 | } 43 | bodyMesh.geometry.computeVertexNormals(); 44 | bodyMesh.material = this.material; 45 | } 46 | }); 47 | }, 48 | 49 | tick: function (time) { 50 | this.eyeMaterial.uniforms.time.value = time/1000; 51 | } 52 | }); 53 | -------------------------------------------------------------------------------- /src/components/SetGLTFMaterial.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | 3 | import SunCalibratedMaterial from '../shaders/SunCalibratedMaterial'; 4 | 5 | const THREE = AFRAME.THREE; 6 | 7 | AFRAME.registerComponent('set-gltf-material', { 8 | schema: { 9 | color: { 10 | type: 'color', 11 | default: null 12 | }, 13 | castShadow: { 14 | type: 'boolean', 15 | default: false 16 | }, 17 | receiveShadow: { 18 | type: 'boolean', 19 | default: false 20 | }, 21 | collideWith: { 22 | type: 'boolean', 23 | default: false 24 | }, 25 | }, 26 | 27 | applyMaterialToMesh: function (mesh) { 28 | const system = document.querySelector('a-scene').systems['sunSystem']; 29 | this.material = new SunCalibratedMaterial(system); 30 | const { color, collideWith } = this.data; 31 | 32 | mesh.castShadow = this.data.castShadow; 33 | mesh.receiveShadow = this.data.receiveShadow; 34 | mesh.geometry.computeVertexNormals() 35 | 36 | const { map: diffTexture } = mesh.material; 37 | 38 | if (diffTexture) { 39 | this.material.map = diffTexture; 40 | } 41 | 42 | mesh.material = this.material; 43 | 44 | if (color) { 45 | mesh.material.color = new THREE.Color(color); 46 | } 47 | 48 | // grab colliders from gltfs from kiko 49 | if (collideWith) { 50 | if (!this.el.sceneEl.object3D.colliders) { 51 | this.el.sceneEl.object3D.colliders = []; 52 | } 53 | this.el.sceneEl.object3D.colliders.push(mesh); 54 | } 55 | }, 56 | 57 | applyMaterial: function (mesh) { 58 | if (mesh.geometry){ 59 | this.applyMaterialToMesh(mesh); 60 | } 61 | mesh.children.forEach(child => { 62 | this.applyMaterial(child); 63 | }); 64 | }, 65 | 66 | init: function () { 67 | this.el.addEventListener('model-loaded', () => { 68 | const scene = this.el.getObject3D('mesh'); 69 | this.applyMaterial(scene); 70 | }); 71 | }, 72 | 73 | tick: function (time) { 74 | } 75 | }); 76 | -------------------------------------------------------------------------------- /src/components/Sky.js: -------------------------------------------------------------------------------- 1 | import SkyFrag from '../shaders/SkyFrag.glsl'; 2 | import SkyVert from '../shaders/SkyVert.glsl'; 3 | 4 | import AFRAME from 'aframe'; 5 | const THREE = AFRAME.THREE; 6 | 7 | AFRAME.registerComponent('sky', { 8 | schema: { 9 | }, 10 | 11 | init: function () { 12 | const system = document.querySelector('a-scene').systems['sunSystem']; 13 | const { widthSegments, heightSegments } = this.data; 14 | 15 | var sphereGeo = new THREE.IcosahedronGeometry( 16 | system.data.skyRadius, 17 | 3 //effectively makes a sphere 18 | ); 19 | 20 | var noiseTex = new THREE.TextureLoader().load('assets/star.png', (tex) => { 21 | tex.wrapS = tex.wrapT = THREE.RepeatWrapping; 22 | }); 23 | 24 | var sphereMat = new THREE.ShaderMaterial({ 25 | uniforms: { 26 | sunPos1: { value: new THREE.Vector3(0,1,0) }, 27 | sunPos2: { value: new THREE.Vector3(0,1,0) }, 28 | sunPos3: { value: new THREE.Vector3(0,1,0) }, 29 | sunCentroid: {value: new THREE.Vector3(0,0,0)}, 30 | sunRadius1: { value: 0 }, 31 | sunRadius2: { value: 0 }, 32 | sunRadius3: { value: 0 }, 33 | skyRadius: { value: 0 }, 34 | time: { value: 0 }, 35 | fadeOutTime: { value: -1 }, 36 | env_c1: {value: new THREE.Color("#ecd8ab")}, 37 | env_c2: {value: new THREE.Color("#f7dbb6")}, 38 | heat_c1: {value: new THREE.Color("#f95c35")}, 39 | heat_c2: {value: new THREE.Color("#f78f64")}, 40 | night_c1: {value: new THREE.Color("#0d1a2f")}, 41 | fogColor: {value: new THREE.Color("#000000")}, 42 | fogDensity: {value: 0}, 43 | perlinNoiseTex: {value: noiseTex}, 44 | }, 45 | vertexShader: SkyVert, 46 | fragmentShader: SkyFrag, 47 | depthWrite: false, 48 | side: THREE.DoubleSide, 49 | fog: true, 50 | }); 51 | 52 | var sky = new THREE.Mesh(sphereGeo, sphereMat); 53 | this.el.object3D.add(sky) 54 | this.sky = sky; 55 | system.registerSky(this.el); 56 | system.registerMaterial(this.sky.material); 57 | }, 58 | tick: function (time, timeDelta) { 59 | this.sky.material.uniforms.time.value = time/1000; 60 | } 61 | }); 62 | -------------------------------------------------------------------------------- /src/components/SpeechController.js: -------------------------------------------------------------------------------- 1 | AFRAME.registerComponent('speech-controller', { 2 | init:function() { 3 | this.el.sceneEl.addEventListener('speech1', (event) => { 4 | this.el.components.sound__1.playSound(); 5 | }); 6 | 7 | this.el.sceneEl.addEventListener('speech2', (event) => { 8 | this.el.components.sound__2.playSound(); 9 | }); 10 | 11 | this.el.sceneEl.addEventListener('speech3', (event) => { 12 | this.el.components.sound__3.playSound(); 13 | }); 14 | 15 | this.el.sceneEl.addEventListener('speech4', (event) => { 16 | this.el.components.sound__4.playSound(); 17 | }); 18 | this.el.sceneEl.addEventListener('speech5', (event) => { 19 | this.el.components.sound__5.playSound(); 20 | }); 21 | this.el.sceneEl.addEventListener('speech6', (event) => { 22 | this.el.components.sound__6.playSound(); 23 | }); 24 | this.el.sceneEl.addEventListener('speech7', (event) => { 25 | this.el.components.sound__7.playSound(); 26 | }); 27 | this.el.sceneEl.addEventListener('speechWin', (event) => { 28 | this.el.components.sound__8.playSound(); 29 | }); 30 | 31 | this.el.sceneEl.addEventListener('comment1', (event) => { 32 | this.el.components.sound__9.playSound(); 33 | }); 34 | 35 | this.el.sceneEl.addEventListener('comment2', (event) => { 36 | this.el.components.sound__10.playSound(); 37 | }); 38 | 39 | this.el.addEventListener('sound-ended', (event) => { 40 | if(event.detail.id == 1){ 41 | this.el.sceneEl.emit('speech1-ended'); 42 | } else if(event.detail.id == 2){ 43 | this.el.sceneEl.emit('speech2-ended'); 44 | } else if(event.detail.id == 3){ 45 | this.el.sceneEl.emit('speech3-ended'); 46 | } else if(event.detail.id == 4){ 47 | this.el.sceneEl.emit('speech4-ended'); 48 | } else if(event.detail.id == 5){ 49 | this.el.sceneEl.emit('speech5-ended'); 50 | } else if(event.detail.id == 6){ 51 | this.el.sceneEl.emit('speech6-ended'); 52 | } else if(event.detail.id == 7){ 53 | this.el.sceneEl.emit('speech7-ended'); 54 | } else if(event.detail.id == 8){ 55 | this.el.sceneEl.emit('speechWin-ended'); 56 | }else if(event.detail.id == 9){ 57 | this.el.sceneEl.emit('comment1-ended'); 58 | }else if(event.detail.id == 10){ 59 | this.el.sceneEl.emit('comment2-ended'); 60 | } 61 | }); 62 | 63 | } 64 | }) 65 | -------------------------------------------------------------------------------- /src/components/Sun.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | import SunFrag from '../shaders/SunFrag.glsl'; 5 | import SunVert from '../shaders/SunVert.glsl'; 6 | 7 | AFRAME.registerComponent('sun', { 8 | schema: { 9 | sunRadius: { 10 | type: 'float', 11 | default: 0.2 12 | }, 13 | pathRadius: { 14 | type: 'float', 15 | default: 0.8 16 | }, 17 | speed: { 18 | type: 'float', 19 | default: -0.0002 20 | }, 21 | offset: { 22 | type: 'float', 23 | default: 0.2 24 | } 25 | }, 26 | init: function () { 27 | const system = document.querySelector('a-scene').systems['sunSystem']; 28 | 29 | const sphereMat = new THREE.ShaderMaterial({ 30 | uniforms: { 31 | fadeOutTime: { value: 0 }, 32 | sunCentroid: { value: 0 }, 33 | time: { value: 0 }, 34 | }, 35 | vertexShader: SunVert, 36 | fragmentShader: SunFrag, 37 | }); 38 | 39 | var sphereGeo = new THREE.SphereBufferGeometry(this.data.sunRadius * system.data.skyRadius, 100, 100); 40 | var sun = new THREE.Mesh(sphereGeo, sphereMat); 41 | this.el.object3D.add(sun) 42 | 43 | system.registerSun(this.el, this.data); 44 | system.registerMaterial(sphereMat); 45 | 46 | }, 47 | }); 48 | -------------------------------------------------------------------------------- /src/components/VertexCacheTextures.js: -------------------------------------------------------------------------------- 1 | import VertexCacheSoftFrag from '../shaders/VertexCacheSoftFrag.glsl'; 2 | import VertexCacheSoftVert from '../shaders/VertexCacheSoftVert.glsl'; 3 | import VertexCacheFluidFrag from '../shaders/VertexCacheFluidFrag.glsl'; 4 | import VertexCacheFluidVert from '../shaders/VertexCacheFluidVert.glsl'; 5 | import CharacterSoftFrag from '../shaders/CharacterSoftFrag.glsl'; 6 | 7 | THREE.FBXLoader = require('../libs/FBXLoader'); 8 | 9 | AFRAME.registerComponent('vertex-cache-textures', { 10 | schema: { 11 | posTex: { type: 'asset' }, 12 | colorTex: { type: 'asset', default: 'none' }, 13 | normalTex: { type: 'asset', default: 'none' }, 14 | diffuseTex: { type: 'asset', default: 'none' }, 15 | fbxModel: { type: 'asset' }, 16 | params: { type: 'asset' }, 17 | fps: { type: 'int', default: 30 }, 18 | offset: { type: 'int', default: 0 }, 19 | mode: { type: 'string', default: 'fluid' }, 20 | fragmentShader: { type: 'string' } 21 | }, 22 | 23 | init: function () { 24 | this.posTex = null; 25 | this.colorTex = null; 26 | this.normalTex = null; 27 | this.diffuseTex = null; 28 | this.fbxModel = null; 29 | this.params = null; 30 | this.load = this.load.bind(this); 31 | this.animating = true; 32 | this.el.addEventListener('start-vertex-animation', (evt) => { 33 | this.animating = true; 34 | }); 35 | }, 36 | 37 | update: function () { 38 | const data = this.data; 39 | if (!data.posTex || !data.colorTex || !data.colorTex || !data.fbxModel || !data.params || !data.diffuseTex ) return; 40 | 41 | const fbxLoader = new THREE.FBXLoader(); 42 | fbxLoader.load(data.fbxModel, (response) => this.load(response, 'fbx') ); 43 | 44 | const loader = new THREE.FileLoader(); 45 | loader.load(data.posTex, (response) => this.load(response, 'pos') ); 46 | if(data.colorTex !== 'none'){ 47 | loader.load(data.colorTex, (response) => this.load(response, 'color') ); 48 | } else { 49 | this.colorTex = 'none'; 50 | } 51 | if(data.normalTex !== 'none'){ 52 | loader.load(data.normalTex, (response) => this.load(response, 'normals') ); 53 | } else { 54 | this.normalTex = 'none'; 55 | } 56 | loader.load(data.params, (response) => this.load(response, 'params') ); 57 | 58 | }, 59 | 60 | load: function (response, type) { 61 | if (type == 'fbx'){ 62 | this.fbxModel = response; 63 | } else if (type == 'pos') { 64 | this.posTex = response; 65 | } else if (type == 'color') { 66 | this.colorTex = response; 67 | } else if (type == 'normals') { 68 | this.normalTex = response; 69 | } else if (type == 'params') { 70 | this.params = response; 71 | } 72 | if (this.posTex && this.colorTex && this.normalTex && this.fbxModel && this.params) { 73 | this.buildModel(); 74 | } 75 | }, 76 | 77 | handleFbxModel: function () { 78 | const triangleCloud = this.fbxModel.children[0]; 79 | 80 | if(this.data.diffuseTex !== 'none'){ 81 | this.diffuseTex = new THREE.TextureLoader().load(this.data.diffuseTex.src, (tex) => { 82 | this.model.material.uniforms.diffuseTex.value = tex; 83 | }); 84 | } 85 | 86 | const uniforms = ({ 87 | bbox_max: { value: this.params.bbox_max }, 88 | bbox_min: { value: this.params.bbox_min }, 89 | numFrames: { value: this.params.numframes }, 90 | posTex: { value: 0 }, 91 | colorTex: { value: 0 }, 92 | normalTex: { value: 0 }, 93 | diffuseTex: { value: this.diffuseTex }, 94 | timeInFrames: { value: 0 }, 95 | sunCentroid: { value: 0 }, 96 | fadeOutTime: { value: -1 }, 97 | time: { value: 0 } 98 | }); 99 | const phongShader = THREE.ShaderLib.phong; 100 | const mUniforms = THREE.UniformsUtils.merge([phongShader.uniforms, uniforms]); 101 | 102 | let fragmentShader; 103 | if (this.data.fragmentShader) { 104 | fragmentShader = CharacterSoftFrag; 105 | } else { 106 | fragmentShader = (this.data.mode === 'fluid') ? VertexCacheFluidFrag: VertexCacheSoftFrag; 107 | } 108 | // ANIMATION PARAMETERS 109 | const material = new THREE.ShaderMaterial({ 110 | uniforms: mUniforms, 111 | vertexShader: (this.data.mode === 'fluid') ? VertexCacheFluidVert: VertexCacheSoftVert, 112 | fragmentShader: fragmentShader, 113 | side: THREE.DoubleSide, 114 | lights: true, 115 | extensions: { 116 | derivatives: true, // set to use derivatives 117 | } 118 | }); 119 | this.model = new THREE.Mesh(triangleCloud.geometry, material); 120 | this.model.scale.set(0.01, 0.01, 0.01); //houdini tool scales mesh up by 100 121 | this.model.frustumCulled = false; 122 | this.model.castShadow = true; 123 | 124 | const system = document.querySelector('a-scene').systems['sunSystem']; 125 | system.registerMaterial(material); 126 | this.el.setObject3D('vertex-cache', this.model); 127 | }, 128 | 129 | handleEXRTextures: function () { 130 | let exrPos = new Module.EXRLoader(this.posTex); 131 | let exrColor = new Module.EXRLoader(this.colorTex); 132 | let exrNormal = new Module.EXRLoader(this.normalTex); 133 | 134 | // Cache image data to this variables to avoid call 135 | // to this member functions in the render for loop 136 | const exrPosBytes = exrPos.getBytes(); 137 | const exrColorBytes = exrColor.getBytes(); 138 | const exrNormalBytes = exrNormal.getBytes(); 139 | const texWidth = exrPos.width(); 140 | const texHeight = exrPos.height(); 141 | 142 | // javascript code must explicitly delete any C++ object handles, 143 | // to clear the emscripten heap 144 | exrPos.delete(); 145 | exrColor.delete(); 146 | exrNormal.delete(); 147 | 148 | const posTexture = new THREE.DataTexture( exrPosBytes, texWidth, texHeight, THREE.RGBAFormat, THREE.FloatType ); 149 | posTexture.magFilter = THREE.NearestFilter; 150 | posTexture.minFilter = THREE.NearestFilter; 151 | posTexture.wrapT = posTexture.wrapS =THREE.RepeatWrapping; 152 | posTexture.needsUpdate = true 153 | this.model.material.uniforms.posTex.value = posTexture; 154 | 155 | const colorTexture = new THREE.DataTexture( exrColorBytes, texWidth, texHeight, THREE.RGBAFormat, THREE.FloatType ); 156 | colorTexture.magFilter = THREE.NearestFilter; 157 | colorTexture.minFilter = THREE.NearestFilter; 158 | colorTexture.wrapT = colorTexture.wrapS =THREE.RepeatWrapping; 159 | colorTexture.needsUpdate = true 160 | this.model.material.uniforms.colorTex.value = colorTexture; 161 | 162 | // const normalTexture = new THREE.DataTexture( exrNormalBytes, texWidth, texHeight, THREE.RGBAFormat, THREE.FloatType ); 163 | // normalTexture.magFilter = THREE.NearestFilter; 164 | // normalTexture.minFilter = THREE.NearestFilter; 165 | // normalTexture.wrapT = normalTexture.wrapS =THREE.RepeatWrapping; 166 | // normalTexture.needsUpdate = true 167 | // this.model.material.uniforms.normalTex.value = normalTexture; 168 | }, 169 | 170 | buildModel: function () { 171 | this.handleFbxModel(); 172 | this.handleEXRTextures(); 173 | 174 | this.time = this.data.offset * this.data.fps; 175 | 176 | this.el.emit('vertex-cache-loaded'); 177 | }, 178 | 179 | remove: function () { 180 | if (this.model) this.el.removeObject3D('vertex-cache'); 181 | }, 182 | 183 | tick: function (time, timeDelta) { 184 | if (!this.model) return; 185 | if (!this.animating) return; 186 | const currentFrame = Math.ceil(this.time / this.data.fps); 187 | if (currentFrame >= this.params.numframes) { 188 | this.time = 0 189 | } 190 | this.model.material.uniforms.timeInFrames.value = currentFrame; 191 | this.model.material.uniforms.time.value = time / 1000; 192 | this.time += timeDelta; 193 | } 194 | }); 195 | -------------------------------------------------------------------------------- /src/components/WebUIController.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | 3 | AFRAME.registerComponent('web-ui-controller', { 4 | init: function () { 5 | const { sceneEl } = this.el; 6 | const startBtnEl = document.getElementById('startBtn'); 7 | const mainScene = document.getElementById('mainScene'); 8 | const introScreen = document.getElementById('introScreen'); 9 | const enterVRButton = document.querySelector('.VRButton'); 10 | const introText = document.getElementById('introText'); 11 | const winningText = document.getElementById('winningText'); 12 | const losingText = document.getElementById('losingText'); 13 | const creditText = document.getElementById('creditText'); 14 | const mainCamera = document.getElementById('camera'); 15 | 16 | sceneEl.addEventListener('loaded', (event) => { 17 | // all game assets loaded 18 | introScreen.classList.remove('hidden'); 19 | }); 20 | 21 | sceneEl.addEventListener('fade-in-complete', (event) => { 22 | introText.emit('hide-intro-text'); 23 | }); 24 | 25 | startBtnEl.addEventListener('click', event => { 26 | sceneEl.enterVR(); 27 | mainScene.setAttribute('visible', 'true'); 28 | introScreen.setAttribute('style', 'visibility: hidden'); 29 | introScreen.setAttribute('visible', 'false'); 30 | enterVRButton.classList.add('visible'); 31 | 32 | mainCamera.setAttribute('active', true); 33 | 34 | this.el.emit('begin-game'); 35 | introText.emit('show-intro-text'); 36 | }) 37 | 38 | sceneEl.addEventListener('gameLose', event => { 39 | losingText.emit('show-lose-text'); 40 | this.setFrontOfCamera(losingText); 41 | document.querySelectorAll('.fire').forEach(el => el.emit('stop-char-fire')); 42 | window.setTimeout(() => { 43 | losingText.emit('hide-lose-text'); 44 | }, 22000); 45 | window.setTimeout(() => { 46 | this.setFrontOfCamera(creditText); 47 | creditText.setAttribute('color', 'black'); 48 | creditText.emit('show-credit-text'); 49 | }, 27000); 50 | }) 51 | 52 | sceneEl.addEventListener('gameWin', event => { 53 | winningText.emit('show-win-text'); 54 | this.setFrontOfCamera(winningText); 55 | window.setTimeout(() => { 56 | winningText.emit('hide-win-text'); 57 | }, 22000); 58 | window.setTimeout(() => { 59 | this.setFrontOfCamera(creditText); 60 | creditText.setAttribute('color', 'white'); 61 | creditText.emit('show-credit-text'); 62 | }, 27000); 63 | }) 64 | }, 65 | 66 | setFrontOfCamera: function(entity) { 67 | const camera = document.querySelector('#camera'); 68 | const left = new THREE.Vector3().set(-1,0,0).transformDirection(camera.object3D.matrixWorld); 69 | const worldPos = new THREE.Vector3().setFromMatrixPosition(camera.object3D.matrixWorld).add(left.multiplyScalar(4.5)); 70 | worldPos.y = 3; 71 | const forward = new THREE.Vector3().set(0,0,-1).transformDirection(camera.object3D.matrixWorld); 72 | forward.y = 0; 73 | entity.object3D.position.copy(worldPos).add(forward.multiplyScalar(10)); 74 | entity.object3D.lookAt(worldPos); 75 | } 76 | }); 77 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | 3 | import JSX from './JSX'; 4 | import './style.css'; 5 | 6 | import './components/SetGLTFMaterial'; 7 | import './components/SetCharacterMaterial'; 8 | import './components/DefaultMaterial'; 9 | import './components/Sun'; 10 | import './components/Sky'; 11 | import './components/RingOfFire'; 12 | import './components/Pendulum'; 13 | import './components/CharacterMover'; 14 | import './components/SpeechController'; 15 | import './components/AmbientController'; 16 | import './components/VertexCacheTextures'; 17 | import './components/WebUIController'; 18 | import './components/Intro'; 19 | 20 | import './systems/SunSystem'; 21 | import './systems/RaycasterSystem'; 22 | import './systems/PendulumSystem'; 23 | 24 | import './components/Mover'; 25 | import './components/Collider'; 26 | import './components/CustomControl'; 27 | 28 | import Fire from './Fire'; 29 | 30 | // Good sky setting 31 | // sunSystem="speed: 0.02; skyRadius: 500; timeOffset: 174000; color: #ffe4aa;" 32 | 33 | const App = () => ( 34 | 48 |
49 | 50 | 51 | {/* Audio */} 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | {/* Environment */} 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | {/* Character */} 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | {/* Vertex cache */} 88 | 89 | 90 | 91 | 92 | 93 | 94 | {/* Character hight is 1.6 + cameraRig.z position */} 95 | 96 | 97 | 102 | {Fire("fire1", "0 0 0.05", "0 0 0", "0.05 0.05 0.05", 0, 45)} 103 | 104 | 110 | {Fire("fire1", "0 0 0.05", "0 0 0", "0.05 0.05 0.05", 0, 45)} 111 | 112 | 113 | 114 | 115 | 116 |
420 | ); 421 | 422 | document.querySelector('body').appendChild(App()); 423 | -------------------------------------------------------------------------------- /src/libs/Utils.js: -------------------------------------------------------------------------------- 1 | const THREE = AFRAME.THREE; 2 | 3 | const t1 = new THREE.Vector3(); 4 | const t2 = new THREE.Vector3(); 5 | const t3 = new THREE.Vector3(); 6 | const m1 = new THREE.Matrix4(); 7 | const UP = new THREE.Vector3(0,1,0); 8 | //util 9 | export function setQuaternionFromDirection(direction, up, target) { 10 | const x = t1; 11 | const y = t2; 12 | const z = t3; 13 | const m = m1; 14 | const el = m1.elements; 15 | 16 | z.copy(direction); 17 | x.crossVectors(up, z); 18 | 19 | 20 | if (x.lengthSq() === 0) { 21 | // parallel 22 | if (Math.abs(up.z) === 1) { 23 | z.x += 0.0001; 24 | } else { 25 | z.z += 0.0001; 26 | } 27 | z.normalize(); 28 | x.crossVectors(up, z); 29 | } 30 | 31 | x.normalize(); 32 | y.crossVectors(z, x); 33 | 34 | el[0] = x.x; el[4] = y.x; el[8] = z.x; 35 | el[1] = x.y; el[5] = y.y; el[9] = z.y; 36 | el[2] = x.z; el[6] = y.z; el[10] = z.z; 37 | 38 | target.setFromRotationMatrix(m); 39 | } 40 | -------------------------------------------------------------------------------- /src/shaders/CharacterSoftFrag.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define PHONG 3 | #define FLAT_SHADED 4 | 5 | 6 | uniform vec3 diffuse; 7 | uniform vec3 emissive; 8 | uniform vec3 specular; 9 | uniform vec3 sunCentroid; 10 | uniform float shininess; 11 | uniform float opacity; 12 | uniform float time; 13 | varying vec2 vUv; 14 | uniform sampler2D diffuseTex; 15 | uniform float fadeOutTime; 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | varying vec3 vViewPosition; 35 | varying vec3 vNormal; 36 | 37 | #ifndef FLAT_SHADED 38 | 39 | varying vec3 vNormal; 40 | 41 | #endif 42 | #define whiteCompliment(a) ( 1.0 - saturate( a ) ) 43 | 44 | struct BlinnPhongMaterial { 45 | 46 | vec3 diffuseColor; 47 | vec3 specularColor; 48 | float specularShininess; 49 | float specularStrength; 50 | 51 | }; 52 | 53 | void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 54 | 55 | 56 | float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); 57 | // dotNL = (dotNL < 0.5)? 0.0: 1.0; 58 | vec3 irradiance = dotNL * directLight.color; 59 | 60 | #ifndef PHYSICALLY_CORRECT_LIGHTS 61 | 62 | irradiance *= PI; // punctual light 63 | 64 | #endif 65 | 66 | reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 67 | // reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength; 68 | } 69 | 70 | void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 71 | float fogDepth = vViewPosition.z; 72 | float fogDensity = 0.1; 73 | 74 | float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) ); 75 | reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 76 | 77 | } 78 | 79 | #define RE_Direct RE_Direct_BlinnPhong 80 | #define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong 81 | 82 | #define Material_LightProbeLOD( material ) (0) 83 | 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | 91 | #undef USE_SHADOWMAP 92 | 93 | void main() { 94 | 95 | #include 96 | 97 | vec4 diffuseColor = texture2D(diffuseTex, vUv); 98 | vec3 yellow = vec3(241.0/255.0, 161.0/255.0, 0.0); 99 | vec3 red = vec3(161.0/255.0, 37.0/255.0, 45.0/255.0); 100 | 101 | float d = length(yellow - diffuseColor.xyz); 102 | float r = length(red - diffuseColor.xyz); 103 | 104 | float pulse = 10.0*sin(time/2.0); 105 | float glow = 0.0; 106 | if(d < 0.3){ 107 | glow = 0.5 + 0.8*abs(sin(pulse)/pulse); 108 | } else if (r < 0.3){ 109 | glow = 0.1 ; 110 | } 111 | diffuseColor.x = pow(diffuseColor.x,2.2); 112 | diffuseColor.y = pow(diffuseColor.y,2.2); 113 | diffuseColor.z = pow(diffuseColor.z,2.2); 114 | 115 | 116 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 117 | vec3 totalEmissiveRadiance = emissive; 118 | 119 | #include 120 | #include 121 | #include 122 | #include 123 | #include 124 | #include 125 | #include 126 | #include 127 | #include 128 | 129 | // accumulation 130 | #include 131 | #include 132 | #include 133 | #include 134 | 135 | // modulation 136 | #include 137 | 138 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 139 | 140 | #include 141 | 142 | gl_FragColor = vec4( glow*diffuseColor.xyz + outgoingLight, diffuseColor.a ); 143 | 144 | #include 145 | #include 146 | #include 147 | #include 148 | #include 149 | 150 | @import ./ColorCorrection; 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/shaders/ColorCorrection.glsl: -------------------------------------------------------------------------------- 1 | float distHoriz = sunCentroid.y/1000.0; 2 | 3 | gl_FragColor.r = clamp(clamp(4.0*(distHoriz),1.0,4.0) * pow( gl_FragColor.r, clamp(distHoriz,1.0,3.0)),0.0,1.0); 4 | gl_FragColor.rgb = mix(gl_FragColor.rgb, vec3(255.0/255.0, 198.0/255.0, 85.0/255.0), clamp(distHoriz,0.0,0.3)); 5 | 6 | gl_FragColor.rgb += fadeOutTime/abs(fadeOutTime)*pow(abs(fadeOutTime),2.0); 7 | -------------------------------------------------------------------------------- /src/shaders/EyeFrag.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | 3 | void main() { 4 | gl_FragColor = vec4(0.8+0.5*sin(time),0.1,0.0,1.0); 5 | } 6 | -------------------------------------------------------------------------------- /src/shaders/EyeVert.glsl: -------------------------------------------------------------------------------- 1 | void main() { 2 | vec4 modelViewPosition = modelViewMatrix * vec4( position, 1.0 ); 3 | gl_Position = projectionMatrix * modelViewPosition; 4 | } 5 | -------------------------------------------------------------------------------- /src/shaders/FireRingFrag.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | uniform float fadeOutTime; 3 | uniform vec3 fireRingColor2; 4 | uniform vec3 fireRingColor1; 5 | uniform vec3 sunCentroid; 6 | 7 | varying vec2 vUv; 8 | varying vec3 vPos; 9 | 10 | @import ./PerlinNoise; 11 | 12 | void main() { 13 | vec3 scrollingPos = vec3(vPos.x, vPos.y*4.0, vPos.z+time); 14 | vec3 scrollingPos2 = vec3(vPos.x, vPos.y, vPos.z+4.0*time); 15 | 16 | float dist2Horiz = clamp(sunCentroid.y/1000.0, 0.0, 1.0); 17 | 18 | float noise = cnoise(vec3(0.01*scrollingPos)); 19 | 20 | noise *= dist2Horiz*5.0*(pow(clamp(1.0-vUv.y,0.0,1.0),2.0)); 21 | // noise *= sin(0.04*time+0.05*vPos.x); 22 | noise= 6.0*pow(noise,2.0) + dist2Horiz*pow((1.0-vUv.y),4.0)*cnoise(vec3(0.2*scrollingPos2)); 23 | vec3 finalColor = mix(fireRingColor1, fireRingColor2, clamp(noise, 0.0, 1.0)); 24 | gl_FragColor = vec4(finalColor, noise); 25 | 26 | @import ./ColorCorrection; 27 | } 28 | -------------------------------------------------------------------------------- /src/shaders/FireRingVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec3 vPos; 2 | varying vec2 vUv; 3 | 4 | void main() { 5 | vPos = position; 6 | vUv = uv; 7 | vec4 modelViewPosition = modelViewMatrix * vec4( vPos, 1.0 ); 8 | gl_Position = projectionMatrix * modelViewPosition; 9 | } 10 | -------------------------------------------------------------------------------- /src/shaders/FogReplaceFrag.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define whiteCompliment(a) ( 1.0 - saturate( a ) ) 3 | 4 | #ifdef USE_FOG 5 | #ifdef FOG_EXP2 6 | float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) ); 7 | #else 8 | float fogFactor = smoothstep( fogNear, fogFar, fogDepth ); 9 | #endif 10 | gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor/2.0 ); 11 | #endif 12 | -------------------------------------------------------------------------------- /src/shaders/FogReplaceVert.glsl: -------------------------------------------------------------------------------- 1 | #ifdef USE_FOG 2 | vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); 3 | // float noise = 20.0*cnoise( mod(opacity/5000.0, 6000.0) + 4000.0*worldPosition.xyz); 4 | float noise = 0.0; 5 | // fogDepth = - mvPosition.z; 6 | fogDepth = -(mvPosition.z*1.5); 7 | fogDepth = max(fogDepth - pow(worldPosition.y,1.2), 0.0); 8 | // fogDepth -= noise; 9 | #endif 10 | -------------------------------------------------------------------------------- /src/shaders/FresnelFrag.glsl: -------------------------------------------------------------------------------- 1 | varying float vReflectionFactor; 2 | 3 | void main() { 4 | vec4 refractedColor = vec4( 0.019, 0.192, 0.231, 1.0 ); 5 | vec4 reflectedColor = vec4( 0.847, 0.925, 0.933, 1.0 ); 6 | 7 | gl_FragColor = 0.3 * mix( refractedColor, reflectedColor, clamp( vReflectionFactor, 0.0, 1.0 ) ); 8 | } 9 | -------------------------------------------------------------------------------- /src/shaders/FresnelVert.glsl: -------------------------------------------------------------------------------- 1 | uniform float mRefractionRatio; 2 | uniform float mFresnelBias; 3 | uniform float mFresnelScale; 4 | uniform float mFresnelPower; 5 | 6 | varying vec3 vReflect; 7 | varying vec3 vRefract[3]; 8 | varying float vReflectionFactor; 9 | 10 | void main() { 11 | vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 ); 12 | vec4 worldPosition = modelMatrix * vec4( position, 1.0 ); 13 | 14 | vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal ); 15 | 16 | vec3 I = worldPosition.xyz - cameraPosition; 17 | vReflectionFactor = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( I ), worldNormal ), mFresnelPower ); 18 | 19 | gl_Position = projectionMatrix * mvPosition; 20 | } 21 | -------------------------------------------------------------------------------- /src/shaders/IntroFrag.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | uniform vec3 color1; 3 | varying vec2 vUv; 4 | 5 | void main() { 6 | float r = 0.12; 7 | float c = pow(vUv.x - 0.5, 2.0) + pow(vUv.y - 0.5, 2.0); 8 | float z = 1.5 * pow(abs(c - r * r), 0.01 * sin(0.001 * time) + 0.115); 9 | 10 | gl_FragColor = z * vec4(color1 * 1.5, 1.0); 11 | } 12 | -------------------------------------------------------------------------------- /src/shaders/IntroVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() { 4 | vUv = uv; 5 | vec4 modelViewPosition = modelViewMatrix * vec4( position, 1.0 ); 6 | gl_Position = projectionMatrix * modelViewPosition; 7 | } 8 | -------------------------------------------------------------------------------- /src/shaders/LaserFrag.glsl: -------------------------------------------------------------------------------- 1 | uniform float time; 2 | uniform float fadeOutTime; 3 | uniform vec3 sunCentroid; 4 | 5 | varying vec2 vUv; 6 | 7 | @import ./PerlinNoise; 8 | 9 | void main() { 10 | vec3 scrollingPos = vec3(.5*vUv.x, 3.0*vUv.y+0.5*time, 1.0); 11 | 12 | float noise = cnoise(vec3(scrollingPos)); 13 | 14 | float m = abs(vUv.x - 0.5); 15 | float n = 1.0 - vUv.y; 16 | 17 | vec3 color1 = vec3 (0.5, 0.5, 0.5); 18 | vec3 color2 = vec3 (1.0, 1.0, 1.0); 19 | 20 | gl_FragColor = vec4(color1+abs(noise)*color2, 0.8*(n - 0.2*m)); 21 | } 22 | -------------------------------------------------------------------------------- /src/shaders/LaserVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec2 vUv; 2 | 3 | void main() { 4 | vUv = uv; 5 | vec4 modelViewPosition = modelViewMatrix * vec4( position, 1.0 ); 6 | gl_Position = projectionMatrix * modelViewPosition; 7 | } 8 | -------------------------------------------------------------------------------- /src/shaders/PendulumFrag.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define PHONG 3 | 4 | uniform vec3 diffuse; 5 | uniform vec3 emissive; 6 | uniform vec3 specular; 7 | uniform vec3 sunCentroid; 8 | uniform float shininess; 9 | uniform float opacity; 10 | uniform float time; 11 | uniform float fadeOutTime; 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | 30 | varying vec3 vViewPosition; 31 | varying float vReflectionFactor; 32 | uniform float glow; 33 | 34 | #ifndef FLAT_SHADED 35 | 36 | varying vec3 vNormal; 37 | 38 | #endif 39 | 40 | 41 | struct BlinnPhongMaterial { 42 | 43 | vec3 diffuseColor; 44 | vec3 specularColor; 45 | float specularShininess; 46 | float specularStrength; 47 | 48 | }; 49 | 50 | void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 51 | 52 | 53 | float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); 54 | // dotNL = (dotNL < 0.5)? 0.0: 1.0; 55 | vec3 irradiance = dotNL * directLight.color; 56 | 57 | #ifndef PHYSICALLY_CORRECT_LIGHTS 58 | 59 | irradiance *= PI; // punctual light 60 | 61 | #endif 62 | 63 | reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 64 | // reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength; 65 | } 66 | #define whiteCompliment(a) ( 1.0 - saturate( a ) ) 67 | 68 | void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 69 | float fogDepth = vViewPosition.z; 70 | float fogDensity = 0.1; 71 | 72 | float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) ); 73 | reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 74 | 75 | } 76 | 77 | #define RE_Direct RE_Direct_BlinnPhong 78 | #define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong 79 | 80 | #define Material_LightProbeLOD( material ) (0) 81 | 82 | 83 | #include 84 | #include 85 | #include 86 | #include 87 | #include 88 | #include 89 | 90 | void main() { 91 | 92 | #include 93 | 94 | vec4 diffuseColor = vec4( diffuse, opacity ); 95 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 96 | vec3 totalEmissiveRadiance = emissive; 97 | 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | 108 | // accumulation 109 | #include 110 | #include 111 | #include 112 | #include 113 | 114 | // modulation 115 | #include 116 | 117 | 118 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 119 | 120 | #include 121 | 122 | gl_FragColor = 30.0*clamp(pow(vReflectionFactor,2.0)*glow,0.0,1.0)*vec4(outgoingLight,1.0) + vec4( outgoingLight, diffuseColor.a ); 123 | 124 | #include 125 | #include 126 | #include 127 | #include 128 | #include 129 | 130 | @import ./ColorCorrection; 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/shaders/PendulumMaterial.js: -------------------------------------------------------------------------------- 1 | const THREE = AFRAME.THREE; 2 | import fogReplace from './FogReplaceFrag.glsl'; 3 | import fogVertReplace from './FogReplaceVert.glsl'; 4 | 5 | import phongFrag from './PendulumFrag.glsl'; 6 | import phongVert from './PendulumVert.glsl'; 7 | 8 | // sun calibrated materials need to have access to the sun system in order to properly update 9 | // the sunCentroid parameter. must include sunCentroid and time uniform to work properly. 10 | export default class PendulumMaterial extends THREE.MeshPhongMaterial { 11 | constructor(system, color){ 12 | super(); 13 | if(color){ 14 | this.color = color; 15 | } 16 | this.onBeforeCompile = (shader) => { 17 | shader.uniforms.time = { value: 0 }; 18 | shader.uniforms.sunCentroid = { value: new THREE.Vector3() }; 19 | shader.uniforms.fadeOutTime = { value: -1 }; 20 | shader.uniforms.glow = { value: 0 }; 21 | 22 | shader.vertexShader = phongVert; 23 | shader.fragmentShader = phongFrag; 24 | this.shader = shader; 25 | system.registerMaterial(this.shader); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/shaders/PendulumVert.glsl: -------------------------------------------------------------------------------- 1 | #define PHONG 2 | 3 | varying vec3 vViewPosition; 4 | 5 | #ifndef FLAT_SHADED 6 | 7 | varying vec3 vNormal; 8 | 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | varying float vReflectionFactor; 25 | 26 | void main() { 27 | 28 | #include 29 | #include 30 | #include 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED 39 | 40 | vNormal = normalize( transformedNormal ); 41 | 42 | #endif 43 | 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | vViewPosition = - mvPosition.xyz; 53 | #include 54 | #include 55 | #include 56 | #include 57 | 58 | vec4 worldPos = modelMatrix * vec4( position, 1.0 ); 59 | vec3 worldNormal = normalize( mat3( modelMatrix[0].xyz, modelMatrix[1].xyz, modelMatrix[2].xyz ) * normal ); 60 | vec3 I = worldPos.xyz - cameraPosition; 61 | vReflectionFactor = 1.0 + dot( normalize( I ), worldNormal ); 62 | } 63 | -------------------------------------------------------------------------------- /src/shaders/PerlinNoise.glsl: -------------------------------------------------------------------------------- 1 | // Classic Perlin 3D Noise 2 | // by Stefan Gustavson 3 | // 4 | // Source https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83 5 | // 6 | vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);} 7 | vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;} 8 | vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);} 9 | 10 | float cnoise(vec3 P){ 11 | vec3 Pi0 = floor(P); // Integer part for indexing 12 | vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1 13 | Pi0 = mod(Pi0, 289.0); 14 | Pi1 = mod(Pi1, 289.0); 15 | vec3 Pf0 = fract(P); // Fractional part for interpolation 16 | vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0 17 | vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x); 18 | vec4 iy = vec4(Pi0.yy, Pi1.yy); 19 | vec4 iz0 = Pi0.zzzz; 20 | vec4 iz1 = Pi1.zzzz; 21 | 22 | vec4 ixy = permute(permute(ix) + iy); 23 | vec4 ixy0 = permute(ixy + iz0); 24 | vec4 ixy1 = permute(ixy + iz1); 25 | 26 | vec4 gx0 = ixy0 / 7.0; 27 | vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5; 28 | gx0 = fract(gx0); 29 | vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0); 30 | vec4 sz0 = step(gz0, vec4(0.0)); 31 | gx0 -= sz0 * (step(0.0, gx0) - 0.5); 32 | gy0 -= sz0 * (step(0.0, gy0) - 0.5); 33 | 34 | vec4 gx1 = ixy1 / 7.0; 35 | vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5; 36 | gx1 = fract(gx1); 37 | vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1); 38 | vec4 sz1 = step(gz1, vec4(0.0)); 39 | gx1 -= sz1 * (step(0.0, gx1) - 0.5); 40 | gy1 -= sz1 * (step(0.0, gy1) - 0.5); 41 | 42 | vec3 g000 = vec3(gx0.x,gy0.x,gz0.x); 43 | vec3 g100 = vec3(gx0.y,gy0.y,gz0.y); 44 | vec3 g010 = vec3(gx0.z,gy0.z,gz0.z); 45 | vec3 g110 = vec3(gx0.w,gy0.w,gz0.w); 46 | vec3 g001 = vec3(gx1.x,gy1.x,gz1.x); 47 | vec3 g101 = vec3(gx1.y,gy1.y,gz1.y); 48 | vec3 g011 = vec3(gx1.z,gy1.z,gz1.z); 49 | vec3 g111 = vec3(gx1.w,gy1.w,gz1.w); 50 | 51 | vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110))); 52 | g000 *= norm0.x; 53 | g010 *= norm0.y; 54 | g100 *= norm0.z; 55 | g110 *= norm0.w; 56 | vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111))); 57 | g001 *= norm1.x; 58 | g011 *= norm1.y; 59 | g101 *= norm1.z; 60 | g111 *= norm1.w; 61 | 62 | float n000 = dot(g000, Pf0); 63 | float n100 = dot(g100, vec3(Pf1.x, Pf0.yz)); 64 | float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z)); 65 | float n110 = dot(g110, vec3(Pf1.xy, Pf0.z)); 66 | float n001 = dot(g001, vec3(Pf0.xy, Pf1.z)); 67 | float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z)); 68 | float n011 = dot(g011, vec3(Pf0.x, Pf1.yz)); 69 | float n111 = dot(g111, Pf1); 70 | 71 | vec3 fade_xyz = fade(Pf0); 72 | vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z); 73 | vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y); 74 | float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 75 | return 2.2 * n_xyz; 76 | } 77 | -------------------------------------------------------------------------------- /src/shaders/PhongFrag.glsl: -------------------------------------------------------------------------------- 1 | #define PHONG 2 | 3 | uniform vec3 diffuse; 4 | uniform vec3 emissive; 5 | uniform vec3 specular; 6 | uniform vec3 sunCentroid; 7 | uniform float shininess; 8 | uniform float opacity; 9 | uniform float time; 10 | uniform float fadeOutTime; 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | varying vec3 vViewPosition; 30 | 31 | #ifndef FLAT_SHADED 32 | 33 | varying vec3 vNormal; 34 | 35 | #endif 36 | 37 | 38 | struct BlinnPhongMaterial { 39 | 40 | vec3 diffuseColor; 41 | vec3 specularColor; 42 | float specularShininess; 43 | float specularStrength; 44 | 45 | }; 46 | 47 | void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 48 | 49 | 50 | float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); 51 | // dotNL = (dotNL < 0.5)? 0.0: 1.0; 52 | vec3 irradiance = dotNL * directLight.color; 53 | 54 | #ifndef PHYSICALLY_CORRECT_LIGHTS 55 | 56 | irradiance *= PI; // punctual light 57 | 58 | #endif 59 | 60 | reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 61 | // reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength; 62 | } 63 | #define whiteCompliment(a) ( 1.0 - saturate( a ) ) 64 | 65 | void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 66 | float fogDepth = vViewPosition.z; 67 | float fogDensity = 0.1; 68 | 69 | float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) ); 70 | reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 71 | 72 | } 73 | 74 | #define RE_Direct RE_Direct_BlinnPhong 75 | #define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong 76 | 77 | #define Material_LightProbeLOD( material ) (0) 78 | 79 | 80 | #include 81 | #include 82 | #include 83 | #include 84 | #include 85 | #include 86 | 87 | void main() { 88 | 89 | #include 90 | 91 | vec4 diffuseColor = vec4( diffuse, opacity ); 92 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 93 | vec3 totalEmissiveRadiance = emissive; 94 | 95 | #include 96 | #include 97 | #include 98 | #include 99 | #include 100 | #include 101 | #include 102 | #include 103 | #include 104 | 105 | // accumulation 106 | #include 107 | #include 108 | #include 109 | #include 110 | 111 | // modulation 112 | #include 113 | 114 | 115 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 116 | 117 | #include 118 | 119 | gl_FragColor = vec4( outgoingLight, diffuseColor.a ); 120 | 121 | #include 122 | #include 123 | #include 124 | #include 125 | #include 126 | 127 | @import ./ColorCorrection; 128 | 129 | } 130 | -------------------------------------------------------------------------------- /src/shaders/PhongVert.glsl: -------------------------------------------------------------------------------- 1 | #define PHONG 2 | 3 | varying vec3 vViewPosition; 4 | 5 | #ifndef FLAT_SHADED 6 | 7 | varying vec3 vNormal; 8 | 9 | #endif 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | void main() { 26 | 27 | #include 28 | #include 29 | #include 30 | 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #ifndef FLAT_SHADED // Normal computed with derivatives when FLAT_SHADED 38 | 39 | vNormal = normalize( transformedNormal ); 40 | 41 | #endif 42 | 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | 51 | vViewPosition = - mvPosition.xyz; 52 | #include 53 | #include 54 | #include 55 | #include 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/shaders/SkyFrag.glsl: -------------------------------------------------------------------------------- 1 | @import ./PerlinNoise; 2 | uniform float time; 3 | uniform vec3 sunPos1; 4 | uniform vec3 sunPos2; 5 | uniform vec3 sunPos3; 6 | uniform vec3 sunCentroid; 7 | uniform float sunRadius1; 8 | uniform float sunRadius2; 9 | uniform float sunRadius3; 10 | uniform float skyRadius; 11 | uniform vec3 env_c1; 12 | uniform vec3 env_c2; 13 | uniform vec3 heat_c1; 14 | uniform vec3 heat_c2; 15 | uniform vec3 night_c1; 16 | uniform float fadeOutTime; 17 | 18 | uniform sampler2D perlinNoiseTex; 19 | varying vec2 vUv; 20 | varying vec3 vPos; 21 | 22 | #include 23 | #include 24 | 25 | void main() { 26 | 27 | float freq = 1.1/(0.01 + skyRadius); 28 | 29 | vec3 scrollingPos = vec3(vPos.x, vPos.y, vPos.z + 100.0*time); 30 | float noise = cnoise(scrollingPos * freq) + 0.2; 31 | 32 | vec4 backgroundColor = vec4(mix(env_c1, env_c2, noise), 1.0); 33 | float noise2 = cnoise(scrollingPos*freq*1.0); 34 | 35 | vec4 heatColor = vec4(mix(heat_c1, heat_c2, noise2), 1.0); 36 | 37 | float l = length(vPos - sunPos1); 38 | float l2 = length(vPos - sunPos2); 39 | float l3 = length(vPos - sunPos3); 40 | 41 | float distHorizon = sunCentroid.y/(0.01 + skyRadius); 42 | 43 | backgroundColor = vec4(mix(night_c1.xyz, backgroundColor.xyz, clamp(distHorizon, 0.0, 1.0)), 1.0); 44 | 45 | float magnitude = (length(sunPos1 - sunCentroid) + length(sunPos3 - sunCentroid) + length(sunPos2 - sunCentroid))/6.0/(0.01 + skyRadius); 46 | float magnitudeS = (l + l2 + l3)/6.0/(0.01 + skyRadius); 47 | backgroundColor = mix(backgroundColor, heatColor, clamp(pow(1.0 - clamp(magnitudeS, .0, 1.0),2.0) * (1.5+pow(1.0 - clamp(magnitude, .0, 1.0),2.0)),0.0,1.0) ); 48 | 49 | 50 | l = clamp((l-sunRadius1)/(4.0*sunRadius1), 0.0, 1.0); 51 | l2 = clamp((l2-sunRadius2)/(4.0*sunRadius2), 0.0, 1.0); 52 | l3 = clamp((l3-sunRadius3)/(4.0*sunRadius3), 0.0, 1.0); 53 | 54 | vec4 c1 = vec4(0.999, 0.999, 1.0, 1.0); 55 | 56 | //stars 57 | vec4 b1 = texture2D(perlinNoiseTex, 7.0*vUv); 58 | float cs = b1.r; 59 | float ss =clamp(pow(cs,3.0),0.0,1.0); 60 | vec4 starColor = abs(clamp(distHorizon, -1.0, .0))*(vPos.y/(0.01 + skyRadius))*1.5*vec4(ss, ss, ss, 1.0); 61 | 62 | gl_FragColor = backgroundColor; 63 | @import ./ColorCorrection; 64 | @import ./FogReplaceFrag; 65 | 66 | gl_FragColor = mix(gl_FragColor, c1, clamp(pow(1.0 - l, 5.0) + pow(1.0 - l3, 5.0)+ pow(1.0 - l2, 5.0), 0.0, 1.0)); 67 | gl_FragColor += starColor; 68 | 69 | gl_FragColor.rgb += (fadeOutTime+0.001)/(abs(fadeOutTime+0.001))*pow(abs(fadeOutTime),2.0); 70 | } 71 | -------------------------------------------------------------------------------- /src/shaders/SkyVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec3 vPos; 2 | varying vec2 vUv; 3 | 4 | #include 5 | 6 | void main() { 7 | vPos = position; 8 | vUv = uv; 9 | 10 | vec4 mvPosition = modelViewMatrix * vec4( vPos, 1.0 ); 11 | gl_Position = projectionMatrix * mvPosition; 12 | 13 | @import ./FogReplaceVert; 14 | } 15 | -------------------------------------------------------------------------------- /src/shaders/SunCalibratedMaterial.js: -------------------------------------------------------------------------------- 1 | const THREE = AFRAME.THREE; 2 | import fogReplace from './FogReplaceFrag.glsl'; 3 | import fogVertReplace from './FogReplaceVert.glsl'; 4 | 5 | import phongFrag from './PhongFrag.glsl'; 6 | import phongVert from './PhongVert.glsl'; 7 | import perlin from './PerlinNoise.glsl'; 8 | 9 | // sun calibrated materials need to have access to the sun system in order to properly update 10 | // the sunCentroid parameter. must include sunCentroid and time uniform to work properly. 11 | export default class SunCalibratedMaterial extends THREE.MeshPhongMaterial { 12 | constructor(system, color){ 13 | super(); 14 | if(color){ 15 | this.color = color; 16 | } 17 | this.onBeforeCompile = (shader) => { 18 | shader.uniforms.time = { value: 0 }; 19 | shader.uniforms.sunCentroid = { value: new THREE.Vector3() }; 20 | shader.uniforms.fadeOutTime = { value: -1 }; 21 | shader.vertexShader = phongVert; 22 | shader.fragmentShader = phongFrag; 23 | this.shader = shader; 24 | system.registerMaterial(this.shader); 25 | // shader.vertexShader = perlin + shader.vertexShader; 26 | // shader.vertexShader = "uniform float opacity;\n" + shader.vertexShader; 27 | 28 | // shader.fragmentShader = shader.fragmentShader.replace( 29 | // `#include `, 30 | // fogReplace 31 | // ); 32 | // shader.vertexShader = shader.vertexShader.replace( 33 | // `#include `, 34 | // fogVertReplace 35 | // ); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/shaders/SunFrag.glsl: -------------------------------------------------------------------------------- 1 | uniform float fadeOutTime; 2 | 3 | void main() { 4 | gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); 5 | gl_FragColor.rgb += fadeOutTime/abs(fadeOutTime)*pow(abs(fadeOutTime),2.0); 6 | } 7 | -------------------------------------------------------------------------------- /src/shaders/SunVert.glsl: -------------------------------------------------------------------------------- 1 | void main() { 2 | vec4 modelViewPosition = modelViewMatrix * vec4( position, 1.0 ); 3 | gl_Position = projectionMatrix * modelViewPosition; 4 | } 5 | -------------------------------------------------------------------------------- /src/shaders/VertexCacheFluidFrag.glsl: -------------------------------------------------------------------------------- 1 | varying vec3 vColor; 2 | uniform vec3 sunCentroid; 3 | uniform float fadeOutTime; 4 | 5 | void main() { 6 | gl_FragColor = vec4(1.15 * pow(vColor, vec3(0.44, 0.44, 0.44)), 1.0); 7 | @import ./ColorCorrection; 8 | } 9 | -------------------------------------------------------------------------------- /src/shaders/VertexCacheFluidVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec3 vColor; 2 | 3 | uniform float bbox_max; 4 | uniform float bbox_min; 5 | uniform float timeInFrames; 6 | uniform float numFrames; 7 | 8 | uniform sampler2D posTex; 9 | uniform sampler2D colorTex; 10 | 11 | void main() { 12 | float tt = timeInFrames/numFrames + 1.0/numFrames; 13 | vec4 texPos = texture2D(posTex, vec2(uv.x, uv.y + tt - .25/numFrames)); 14 | vec4 texColor = texture2D(colorTex, vec2(uv.x, uv.y + tt - .25/numFrames)); 15 | vColor = texColor.xyz; 16 | 17 | vec3 texturePos = texPos.xyz; 18 | float expand = bbox_max - bbox_min; //bbmax - bbmin 19 | texturePos.xyz *= expand; 20 | texturePos.xyz += bbox_min; 21 | vec3 p = texturePos.xzy; //swizzle y and z because textures are exported with z-up 22 | vec4 modelViewPosition = modelViewMatrix * vec4(p, 1.0); 23 | gl_Position = projectionMatrix * modelViewPosition; 24 | } 25 | -------------------------------------------------------------------------------- /src/shaders/VertexCacheSoftFrag.glsl: -------------------------------------------------------------------------------- 1 | 2 | #define PHONG 3 | #define FLAT_SHADED 4 | 5 | 6 | uniform vec3 diffuse; 7 | uniform vec3 emissive; 8 | uniform vec3 specular; 9 | uniform vec3 sunCentroid; 10 | uniform float shininess; 11 | uniform float opacity; 12 | uniform float time; 13 | uniform float fadeOutTime; 14 | varying vec2 vUv; 15 | uniform sampler2D diffuseTex; 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | varying vec3 vViewPosition; 35 | varying vec3 vNormal; 36 | 37 | #ifndef FLAT_SHADED 38 | 39 | varying vec3 vNormal; 40 | 41 | #endif 42 | 43 | 44 | struct BlinnPhongMaterial { 45 | 46 | vec3 diffuseColor; 47 | vec3 specularColor; 48 | float specularShininess; 49 | float specularStrength; 50 | 51 | }; 52 | 53 | void RE_Direct_BlinnPhong( const in IncidentLight directLight, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 54 | 55 | 56 | float dotNL = saturate( dot( geometry.normal, directLight.direction ) ); 57 | // dotNL = (dotNL < 0.5)? 0.0: 1.0; 58 | vec3 irradiance = dotNL * directLight.color; 59 | 60 | #ifndef PHYSICALLY_CORRECT_LIGHTS 61 | 62 | irradiance *= PI; // punctual light 63 | 64 | #endif 65 | 66 | reflectedLight.directDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 67 | // reflectedLight.directSpecular += irradiance * BRDF_Specular_BlinnPhong( directLight, geometry, material.specularColor, material.specularShininess ) * material.specularStrength; 68 | } 69 | #define whiteCompliment(a) ( 1.0 - saturate( a ) ) 70 | 71 | void RE_IndirectDiffuse_BlinnPhong( const in vec3 irradiance, const in GeometricContext geometry, const in BlinnPhongMaterial material, inout ReflectedLight reflectedLight ) { 72 | float fogDepth = vViewPosition.z; 73 | float fogDensity = 0.1; 74 | 75 | float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) ); 76 | reflectedLight.indirectDiffuse += irradiance * BRDF_Diffuse_Lambert( material.diffuseColor ); 77 | 78 | } 79 | 80 | #define RE_Direct RE_Direct_BlinnPhong 81 | #define RE_IndirectDiffuse RE_IndirectDiffuse_BlinnPhong 82 | 83 | #define Material_LightProbeLOD( material ) (0) 84 | 85 | #include 86 | #include 87 | #include 88 | #include 89 | #include 90 | #include 91 | 92 | void main() { 93 | 94 | #include 95 | 96 | vec4 diffuseColor = texture2D(diffuseTex, vUv); 97 | 98 | ReflectedLight reflectedLight = ReflectedLight( vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ), vec3( 0.0 ) ); 99 | vec3 totalEmissiveRadiance = emissive; 100 | 101 | #include 102 | #include 103 | #include 104 | #include 105 | #include 106 | #include 107 | #include 108 | #include 109 | #include 110 | 111 | // accumulation 112 | #include 113 | #include 114 | #include 115 | #include 116 | 117 | // modulation 118 | #include 119 | 120 | vec3 outgoingLight = reflectedLight.directDiffuse + reflectedLight.indirectDiffuse + reflectedLight.directSpecular + reflectedLight.indirectSpecular + totalEmissiveRadiance; 121 | 122 | #include 123 | 124 | gl_FragColor = vec4( diffuseColor.xyz + outgoingLight, diffuseColor.a ); 125 | 126 | #include 127 | #include 128 | #include 129 | #include 130 | #include 131 | 132 | @import ./ColorCorrection; 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/shaders/VertexCacheSoftVert.glsl: -------------------------------------------------------------------------------- 1 | varying vec3 vViewPosition; 2 | varying vec3 vNormal; 3 | varying vec2 vUv; 4 | 5 | attribute vec2 uv2; 6 | 7 | uniform float bbox_max; 8 | uniform float bbox_min; 9 | uniform float timeInFrames; 10 | uniform float numFrames; 11 | 12 | uniform sampler2D posTex; 13 | uniform sampler2D normalTex; 14 | 15 | void main() { 16 | vUv = uv; 17 | float tt = timeInFrames/numFrames + 1.0/numFrames; 18 | vec4 texPos = texture2D(posTex, vec2(uv2.x, uv2.y + tt - 1.0)); //repeat wrapping does not work for custom attributes? 19 | vec4 texNormal = texture2D(normalTex, vec2(uv2.x, uv2.y + tt - 1.0)); 20 | // vColor = texColor.xyz; 21 | // 22 | vec3 texturePos = texPos.xyz; 23 | float expand = bbox_max - bbox_min; //bbmax - bbmin 24 | texturePos.xyz *= expand; 25 | texturePos.xyz += bbox_min; 26 | vec3 p = position + texturePos.xzy; //swizzle y and z because textures are exported with z-up 27 | 28 | texNormal *= 2.0; 29 | texNormal -= 1.0; 30 | vNormal = normalMatrix * texNormal.xzy; 31 | 32 | vec4 modelViewPosition = modelViewMatrix * vec4(p, 1.0); 33 | vViewPosition = -modelViewPosition.xyz; 34 | gl_Position = projectionMatrix * modelViewPosition; 35 | } 36 | -------------------------------------------------------------------------------- /src/style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Nanum+Gothic|Nanum+Gothic+Coding|Questrial&display=swap'); 2 | 3 | html, body { 4 | color: white; 5 | font-size: 145%; 6 | font-family: 'Questrial', sans-serif; 7 | font-weight: 80; 8 | } 9 | 10 | .a-loader-title { 11 | color: black; 12 | } 13 | 14 | .screenContainer { 15 | display: flex; 16 | flex-direction: column; 17 | position: absolute; 18 | align-items: center; 19 | justify-content: center; 20 | width: 100%; 21 | height: 100%; 22 | z-index: 999; 23 | } 24 | 25 | .screenText { 26 | width: 60%; 27 | text-align: justify; 28 | opacity: 0.5; 29 | line-height: 80%; 30 | } 31 | 32 | #buttonsContainer { 33 | display: flex; 34 | position: absolute; 35 | top: 20px; 36 | left: 20px; 37 | width: 50px; 38 | height: 50px; 39 | z-index: 999; 40 | } 41 | 42 | #buttonsContainer .btnImage { 43 | display: flex; 44 | width: 50px; 45 | opacity: 0.6; 46 | } 47 | 48 | #buttonsContainer .btnImage:hover { 49 | cursor: pointer; 50 | opacity: 0.8; 51 | } 52 | 53 | #introScreen .screenContainer { 54 | /* background-color: #001427; */ 55 | } 56 | 57 | #loseScreen .screenContainer { 58 | background-color: #8D0801; 59 | } 60 | 61 | #winScreen .screenContainer { 62 | background-color: #b8541b; 63 | } 64 | 65 | #startBtn { 66 | display: flex; 67 | align-items: center; 68 | justify-content: center; 69 | opacity: 0.6; 70 | text-shadow: 0 0 30px white; 71 | } 72 | 73 | #startBtn:hover { 74 | cursor: pointer; 75 | opacity: 0.8; 76 | } 77 | 78 | .VRButton { 79 | visibility: hidden; 80 | position: absolute; 81 | bottom: 20px; 82 | right: 20px; 83 | min-width: 50px; 84 | min-height: 50px; 85 | background: url(data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%20245.82%20141.73%22%3E%3Cdefs%3E%3Cstyle%3E.a%7Bfill%3A%23fff%3Bfill-rule%3Aevenodd%3B%7D%3C%2Fstyle%3E%3C%2Fdefs%3E%3Ctitle%3Emask%3C%2Ftitle%3E%3Cpath%20class%3D%22a%22%20d%3D%22M175.56%2C111.37c-22.52%2C0-40.77-18.84-40.77-42.07S153%2C27.24%2C175.56%2C27.24s40.77%2C18.84%2C40.77%2C42.07S198.08%2C111.37%2C175.56%2C111.37ZM26.84%2C69.31c0-23.23%2C18.25-42.07%2C40.77-42.07s40.77%2C18.84%2C40.77%2C42.07-18.26%2C42.07-40.77%2C42.07S26.84%2C92.54%2C26.84%2C69.31ZM27.27%2C0C11.54%2C0%2C0%2C12.34%2C0%2C28.58V110.9c0%2C16.24%2C11.54%2C30.83%2C27.27%2C30.83H99.57c2.17%2C0%2C4.19-1.83%2C5.4-3.7L116.47%2C118a8%2C8%2C0%2C0%2C1%2C12.52-.18l11.51%2C20.34c1.2%2C1.86%2C3.22%2C3.61%2C5.39%2C3.61h72.29c15.74%2C0%2C27.63-14.6%2C27.63-30.83V28.58C245.82%2C12.34%2C233.93%2C0%2C218.19%2C0H27.27Z%22%2F%3E%3C%2Fsvg%3E) 50% 50%/70% 70% no-repeat rgba(0,0,0,.35); 86 | z-index: 999; 87 | } 88 | 89 | .VRButton:hover { 90 | cursor: pointer; 91 | } 92 | 93 | .visible { 94 | visibility: visible; 95 | } 96 | 97 | .hidden { 98 | visibility: hidden; 99 | } 100 | -------------------------------------------------------------------------------- /src/systems/PendulumSystem.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | //keeps track of all pendulums, and colors them all when in sync 5 | AFRAME.registerSystem('pendulum', { 6 | schema: { 7 | }, 8 | init: function () { 9 | this.pendulums = []; 10 | this.totalDist = 10; 11 | }, 12 | registerPendulum: function(pendulum) { 13 | this.pendulums.push(pendulum); 14 | }, 15 | getSynchStatus: function() { 16 | return (this.totalDist < 1)? true : false; 17 | }, 18 | tick: function (time, timeDelta) { 19 | if( Math.abs(this.pendulums[0].dampeningFactor) < 0.1 || Math.abs(this.pendulums[1].dampeningFactor) < 0.1 || Math.abs(this.pendulums[2].dampeningFactor) < 0.1 ){ 20 | this.totalDist = 10; 21 | this.pendulums.forEach((p) => { 22 | p.brighten(0); 23 | }) 24 | return; 25 | } 26 | //assume we have 3 pendulums . 27 | var dist1 = Math.abs(this.pendulums[0].curAngle-this.pendulums[1].curAngle); 28 | var dist2 = Math.abs(this.pendulums[0].curAngle-this.pendulums[2].curAngle); 29 | var dist3 = Math.abs(this.pendulums[1].curAngle-this.pendulums[2].curAngle); 30 | 31 | this.totalDist = (dist1 + dist2 + dist3)/3; 32 | this.pendulums.forEach((p) => { 33 | p.brighten(1/this.totalDist/100); 34 | }) 35 | } 36 | }); 37 | -------------------------------------------------------------------------------- /src/systems/RaycasterSystem.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | import LaserFrag from '../shaders/LaserFrag.glsl'; 5 | import LaserVert from '../shaders/LaserVert.glsl'; 6 | 7 | import { setQuaternionFromDirection } from '../libs/Utils'; 8 | 9 | AFRAME.registerSystem('raycasterSystem', { 10 | schema: { 11 | }, 12 | 13 | init: function () { 14 | this.raycaster = new THREE.Raycaster(); 15 | this.mouse = new THREE.Vector2(); 16 | 17 | this.triggerDown = false; 18 | this.mouseDown = false; 19 | 20 | this.tmps = { 21 | v1: new THREE.Vector3(), 22 | v2: new THREE.Vector3() 23 | }; 24 | 25 | const controller = document.querySelector('#controller'); 26 | this.controllerObject = controller.object3D; 27 | 28 | var planeGeo = new THREE.PlaneGeometry( 0.01,10 ); 29 | var m1 = new THREE.Matrix4().makeRotationX(Math.PI/2) 30 | var m2 = new THREE.Matrix4().makeTranslation(0,0,5) 31 | planeGeo.applyMatrix(m2.multiply(m1)) 32 | var planeMat = new THREE.ShaderMaterial({ 33 | uniforms: { 34 | sunCentroid: {value: new THREE.Vector3(0,0,0)}, 35 | fadeOutTime: {value: -1}, 36 | time: {value: 0}, 37 | }, 38 | side:THREE.DoubleSide, 39 | transparent: true, 40 | vertexShader: LaserVert, 41 | fragmentShader: LaserFrag, 42 | depthWrite: false, 43 | }); 44 | this.laserPlane = new THREE.Mesh(planeGeo, planeMat); 45 | this.sceneEl.object3D.add(this.laserPlane); 46 | this.laserPlane.visible = false; 47 | 48 | const system = document.querySelector('a-scene').systems['sunSystem']; 49 | system.registerMaterial(planeMat); 50 | 51 | window.addEventListener( 'mousedown', (event) => { 52 | this.mouseDown = true; 53 | 54 | this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; 55 | this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; 56 | this.raycaster.setFromCamera( this.mouse, this.sceneEl.camera ); 57 | this.sceneEl.emit('raycast-active-onset'); 58 | }, false ); 59 | 60 | window.addEventListener( 'mousemove', (event) => { 61 | if(!this.mouseDown) return; 62 | this.mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1; 63 | this.mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1; 64 | this.raycaster.setFromCamera( this.mouse, this.sceneEl.camera ); 65 | this.sceneEl.emit('raycast-active'); 66 | }, false ); 67 | 68 | window.addEventListener( 'mouseup', (event) => { 69 | this.mouseDown = false; 70 | this.sceneEl.emit('raycast-finished'); 71 | }, false ); 72 | 73 | 74 | window.addEventListener( 'triggerdown', (event) => { 75 | this.triggerDown = true; 76 | var origin = this.tmps.v1.setFromMatrixPosition(this.controllerObject.matrixWorld); 77 | var forward = this.tmps.v2.set(0,0,-1).transformDirection(this.controllerObject.matrixWorld); 78 | this.raycaster.set(origin, forward); 79 | this.sceneEl.emit('raycast-active-onset'); 80 | }, false ); 81 | 82 | window.addEventListener( 'triggerup', (event) => { 83 | this.triggerDown = false; 84 | this.sceneEl.emit('raycast-finished'); 85 | }, false ); 86 | }, 87 | 88 | updateTriggerRay: function() { 89 | var origin = this.tmps.v1.setFromMatrixPosition(this.controllerObject.matrixWorld); 90 | var forward = this.tmps.v2.set(0,0,-1).transformDirection(this.controllerObject.matrixWorld); 91 | 92 | setQuaternionFromDirection(forward, new THREE.Vector3(0,1,0), this.laserPlane.quaternion) 93 | this.laserPlane.position.copy(origin) 94 | 95 | if(!this.triggerDown) return; 96 | this.raycaster.set(origin, forward); 97 | this.sceneEl.emit('raycast-active'); 98 | }, 99 | 100 | intersectObject: function(obj3d) { 101 | return this.raycaster.intersectObject(obj3d); 102 | }, 103 | 104 | tick: function (time, timeDelta) { 105 | this.updateTriggerRay(); 106 | } 107 | }); 108 | -------------------------------------------------------------------------------- /src/systems/SunSystem.js: -------------------------------------------------------------------------------- 1 | import AFRAME from 'aframe'; 2 | const THREE = AFRAME.THREE; 3 | 4 | AFRAME.registerSystem('sunSystem', { 5 | schema: { 6 | speed: { 7 | type: 'float' 8 | }, 9 | skyRadius: { 10 | type: 'float' 11 | }, 12 | timeOffset: { 13 | type: 'float', 14 | default: 0 15 | }, 16 | fogColor: { 17 | type: 'color', 18 | default: '#ffffff' 19 | }, 20 | }, 21 | 22 | init: function () { 23 | this.entities = []; 24 | this.materials = []; 25 | this.center = new THREE.Object3D(); 26 | this.center.up = new THREE.Vector3(1,0,1) 27 | this.sphere = new THREE.Sphere(new THREE.Vector3(0,0,0), this.data.skyRadius); 28 | this.ray = new THREE.Ray(); 29 | 30 | //sun system is in charge of the three directional lights 31 | this.sunLight1 = new THREE.DirectionalLight(0xffffff, 0.5); 32 | this.sunLight1.castShadow = true; 33 | this.sunLight1.shadow.camera.far = 2*this.data.skyRadius; 34 | this.sunLight1.shadow.camera.left = -10; 35 | this.sunLight1.shadow.camera.bottom = -10; 36 | this.sunLight1.shadow.camera.right = 10; 37 | this.sunLight1.shadow.camera.top = 10; 38 | this.sunLight1.shadow.mapSize.width = 2*1024; 39 | this.sunLight1.shadow.mapSize.height = 2*1024; 40 | 41 | // this.sceneEl.object3D.add(new THREE.CameraHelper(this.sunLight1.shadow.camera)) 42 | 43 | this.sunLight2 = new THREE.DirectionalLight(0xffffff, 0.5); 44 | // this.sunLight2.castShadow = true; 45 | // this.sunLight2.shadow.camera.far = 2*this.data.skyRadius; 46 | 47 | this.sunLight3 = new THREE.DirectionalLight(0xffffff, 0.5); 48 | // this.sunLight3.castShadow = true; 49 | // this.sunLight3.shadow.camera.far = 2*this.data.skyRadius; 50 | 51 | this.fogColor = new THREE.Color(this.data.fogColor); 52 | this.fogNightColor = new THREE.Color("#ffffff"); 53 | 54 | this.sceneEl.object3D.add(this.sunLight1) 55 | this.sceneEl.object3D.add(this.sunLight2) 56 | this.sceneEl.object3D.add(this.sunLight3) 57 | 58 | this.startAnimation = false; 59 | this.fadingOutWhite = false; 60 | this.fadingOutBlack = false; 61 | this.fadingIn = false; 62 | this.gameOver = false; 63 | 64 | this.animationTime = this.data.timeOffset; 65 | this.sceneEl.addEventListener('begin-game', () => { 66 | this.fadingIn = true; 67 | this.materials.forEach((mat) => { 68 | mat.uniforms.fadeOutTime.value = -1; 69 | }) 70 | }); 71 | this.sceneEl.addEventListener('start-sun-animation', () => { 72 | this.startAnimation = true; 73 | }); 74 | this.sceneEl.addEventListener('speech6-ended', () => { 75 | window.setTimeout(() => { 76 | if(!this.gameOver){ 77 | this.fadingOutWhite = true; 78 | } 79 | }, 40000); 80 | }); 81 | this.sceneEl.addEventListener('speechWin-ended', (event) => { 82 | window.setTimeout(() => { 83 | this.fadingOutBlack = true; 84 | }, 10000); 85 | }); 86 | this.sceneEl.addEventListener('win', () => { 87 | this.fadingOutWhite = false; 88 | this.gameOver = true; 89 | }); 90 | }, 91 | 92 | registerSun: function (el, initData) { 93 | //TODO; WHY 94 | initData.sunRadius = this.data.skyRadius*parseFloat(initData.sunRadius); 95 | initData.pathRadius = this.data.skyRadius*parseFloat(initData.pathRadius); 96 | initData.speed = parseFloat(initData.speed); 97 | initData.offset = parseFloat(initData.offset); 98 | this.entities.push({el, initData}); 99 | this.updateSkyUniforms(); 100 | }, 101 | 102 | updateSkyUniforms: function () { 103 | this.sky.material.uniforms["skyRadius"].value = this.data.skyRadius; 104 | this.entities.forEach((sun, index) => { 105 | const uniName = 'sunRadius' + (index+1).toString(); 106 | this.sky.material.uniforms[uniName].value = sun.initData.sunRadius; 107 | }) 108 | }, 109 | 110 | registerSky: function (el) { 111 | this.sky = el.object3D.children[0]; 112 | }, 113 | 114 | registerMaterial: function(mat) { 115 | this.materials.push(mat); 116 | }, 117 | 118 | registerMainCharacter: function(char) { 119 | this.sunLight1.target = char; 120 | }, 121 | 122 | tick: function (time, timeDelta) { 123 | 124 | var center; 125 | if(this.startAnimation){ 126 | if(this.animationTime < 350122){ 127 | this.animationTime += timeDelta; 128 | } else { 129 | this.animationTime += 0.5*timeDelta; //slow down the ending 130 | } 131 | } 132 | center = new THREE.Vector3(0, this.data.skyRadius*Math.sin(this.animationTime/-2000*this.data.speed), this.data.skyRadius*Math.cos(this.animationTime/-2000*this.data.speed)); 133 | 134 | this.center.position.copy(center); 135 | this.center.updateMatrixWorld(); 136 | 137 | this.center.lookAt(new THREE.Vector3(0,0,0)); 138 | var newX = new THREE.Vector3(1,0,0).applyQuaternion(this.center.quaternion); 139 | var newY = new THREE.Vector3(0,1,0).applyQuaternion(this.center.quaternion); 140 | 141 | var sunCentroid = new THREE.Vector3(0,0,0); 142 | this.entities.forEach((sun, index) => { 143 | const curSun = sun.el.object3D.children[0]; 144 | var pos = new THREE.Vector3().add( 145 | newX.clone().multiplyScalar(sun.initData.pathRadius*Math.cos(this.animationTime*sun.initData.speed*this.data.speed + sun.initData.offset))).add( 146 | newY.clone().multiplyScalar(sun.initData.pathRadius*Math.sin(this.animationTime*sun.initData.speed*this.data.speed + sun.initData.offset))) 147 | pos.add(center); 148 | this.ray.origin.copy(pos); 149 | this.ray.direction.copy(pos.normalize().multiplyScalar(-1)); 150 | this.ray.intersectSphere(this.sphere, curSun.position); 151 | const uniName = 'sunPos' + (index+1).toString(); 152 | this.sky.material.uniforms[uniName].value.copy(curSun.position); 153 | const lightName = 'sunLight' + (index+1).toString(); 154 | this[lightName].position.copy(curSun.position); 155 | this[lightName].intensity = Math.max(curSun.position.y/this.data.skyRadius, 0); 156 | sunCentroid.add(curSun.position) 157 | }) 158 | 159 | sunCentroid.multiplyScalar(1/3); 160 | var t = sunCentroid.y/this.data.skyRadius; 161 | 162 | t = Math.min(Math.max(t, 0), 1); 163 | this.sceneEl.object3D.fog.density = Math.min(t+0.1,1)*0.005; 164 | this.sceneEl.object3D.fog.color = this.fogNightColor.lerp(this.fogColor, t); 165 | 166 | 167 | var fadeOutTime = this.materials[0].uniforms.fadeOutTime.value; 168 | if(this.fadingOutWhite){ 169 | fadeOutTime += 0.00006523*timeDelta; 170 | if (fadeOutTime > 1.002){ 171 | } else if(fadeOutTime > 1.0){ 172 | this.sceneEl.emit('gameLose') 173 | } 174 | } else if(this.fadingIn){ 175 | fadeOutTime += 0.00005078*timeDelta; 176 | if(fadeOutTime >= -0.0001){ 177 | this.fadingIn = false; 178 | this.sceneEl.emit('fade-in-complete'); 179 | } 180 | } else if (this.fadingOutBlack) { 181 | if (fadeOutTime > -1){ 182 | fadeOutTime -= 0.00006523*timeDelta; 183 | } 184 | } else { 185 | fadeOutTime = Math.max(fadeOutTime-0.0006523*timeDelta, 0.0001); 186 | } 187 | 188 | this.materials.forEach((mat) => { 189 | mat.uniforms.sunCentroid.value = sunCentroid; 190 | mat.uniforms.time.value = time/1000; 191 | mat.uniforms.fadeOutTime.value = fadeOutTime; 192 | }) 193 | } 194 | }); 195 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const CopyPlugin = require('copy-webpack-plugin'); 3 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 4 | 5 | module.exports = { 6 | entry: ['babel-polyfill', './src/index.js'], 7 | output: { 8 | filename: 'bundle.js', 9 | path: path.resolve(__dirname, 'dist') 10 | }, 11 | module: { 12 | rules: [ 13 | { 14 | test: /\.js$/, 15 | exclude: /node_modules/, 16 | loader: 'babel-loader' 17 | }, 18 | { 19 | test: /\.css$/, 20 | use: [ 21 | 'style-loader', 22 | 'css-loader' 23 | ] 24 | }, 25 | { 26 | test: /\.glsl$/, 27 | loader: 'webpack-glsl-loader' 28 | } 29 | ] 30 | }, 31 | plugins: [ 32 | new HtmlWebpackPlugin({ 33 | inject: true, 34 | template: 'public/index.html', 35 | }), 36 | new CopyPlugin([ 37 | { 38 | from: 'public/assets', 39 | to: 'assets', 40 | }, 41 | { 42 | from: 'public/js', 43 | to: 'js', 44 | } 45 | ]), 46 | ], 47 | devServer: { 48 | contentBase: './dist', 49 | compress: true, 50 | disableHostCheck: true, 51 | hot: true, 52 | inline: true, 53 | port: 3000, 54 | host: '0.0.0.0', 55 | }, 56 | }; 57 | --------------------------------------------------------------------------------