├── examples ├── jsm │ └── libs │ │ └── glslang.js ├── textures │ └── brick_diffuse.jpg ├── models │ ├── gltf │ │ └── DamagedHelmet │ │ │ ├── glTF │ │ │ ├── Default_AO.jpg │ │ │ ├── DamagedHelmet.bin │ │ │ ├── Default_albedo.jpg │ │ │ ├── Default_normal.jpg │ │ │ ├── Default_emissive.jpg │ │ │ ├── Default_metalRoughness.jpg │ │ │ └── DamagedHelmet.gltf │ │ │ ├── glTF-small │ │ │ ├── Default_AO.jpg │ │ │ ├── DamagedHelmet.bin │ │ │ ├── Default_albedo.jpg │ │ │ ├── Default_emissive.jpg │ │ │ ├── Default_normal.jpg │ │ │ ├── Default_metalRoughness.jpg │ │ │ └── DamagedHelmet.gltf │ │ │ └── README.md │ └── json │ │ └── suzanne_buffergeometry.json ├── index.html ├── webgpu_box.html ├── webgpu_gltf.html ├── webgpu_texture.html ├── webgpu_suzanne.html └── webgpu_materials.html ├── README.md ├── LICENSE └── src └── renderers └── WebGPURenderer.js /examples/jsm/libs/glslang.js: -------------------------------------------------------------------------------- 1 | export { default } from 'https://unpkg.com/@webgpu/glslang@0.0.12/dist/web-devel/glslang.js'; 2 | -------------------------------------------------------------------------------- /examples/textures/brick_diffuse.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/textures/brick_diffuse.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/Default_AO.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/Default_AO.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.bin -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/Default_albedo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/Default_albedo.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/Default_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/Default_normal.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/Default_AO.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/Default_AO.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/Default_emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/Default_emissive.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/DamagedHelmet.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/DamagedHelmet.bin -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/Default_albedo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/Default_albedo.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/Default_emissive.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/Default_emissive.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/Default_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/Default_normal.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF/Default_metalRoughness.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/Default_metalRoughness.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/takahirox/THREE.WebGPURenderer/HEAD/examples/models/gltf/DamagedHelmet/glTF-small/Default_metalRoughness.jpg -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/README.md: -------------------------------------------------------------------------------- 1 | # Damaged Helmet 2 | 3 | https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/DamagedHelmet 4 | 5 | ## License Information 6 | 7 | Battle Damaged Sci-fi Helmet - PBR by [theblueturtle_](https://sketchfab.com/theblueturtle_), published under a Creative Commons Attribution-NonCommercial license 8 | 9 | https://sketchfab.com/models/b81008d513954189a063ff901f7abfe4 10 | 11 | ## Modifications 12 | 13 | The original model was built on an early draft of glTF 2.0 that did not become final. This new model has been imported and re-exported from Blender to bring it into alignment with the final release glTF 2.0 specification. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [Three.js official started to work on WebGPU renderer](https://github.com/mrdoob/three.js/tree/dev/examples/jsm/renderers/webgpu) then I may stop to update this project, and contribute to the Three.js official one instead. 2 | 3 | # THREE.WebGPURenderer 4 | Experimental Three.js WebGPU renderer 5 | 6 | [Online Demo](https://takahirox.github.io/THREE.WebGPURenderer/examples/index.html) / [Video](https://twitter.com/superhoge/status/1229591960240832512) 7 | 8 | Turn on #enable-unsafe-webgpu via chrome://flags on Chrome Canary for the demo. 9 | 10 | ## Links 11 | 12 | - [WebGPU specification](https://gpuweb.github.io/gpuweb/) 13 | - [WebGPU Samples](https://github.com/austinEng/webgpu-samples) 14 | - [webgpu-trial](https://github.com/takahirox/webgpu-trial) 15 | - [Three.js](https://threejs.org/) 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Takahiro 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Three.js WebGPURenderer 5 | 18 | 19 | 20 | 21 | 22 |

23 | Three.js WebGPURenderer 24 |

25 | 26 | 33 | 34 | -------------------------------------------------------------------------------- /examples/webgpu_box.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three.js WebGPU Renderer Box 4 | 12 | 13 | 14 | 70 | 71 | -------------------------------------------------------------------------------- /examples/webgpu_gltf.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three.js WebGPU Renderer Box 4 | 12 | 13 | 14 | 76 | 77 | -------------------------------------------------------------------------------- /examples/webgpu_texture.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three.js WebGPU Renderer Box 4 | 12 | 13 | 14 | 78 | 79 | -------------------------------------------------------------------------------- /examples/webgpu_suzanne.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three.js WebGPU Renderer Suzanne 4 | 12 | 13 | 14 | 101 | 102 | -------------------------------------------------------------------------------- /examples/webgpu_materials.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Three.js WebGPU Renderer Materials 4 | 12 | 13 | 14 | 109 | 110 | -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF/DamagedHelmet.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors" : [ 3 | { 4 | "bufferView" : 0, 5 | "componentType" : 5123, 6 | "count" : 46356, 7 | "max" : [ 8 | 14555 9 | ], 10 | "min" : [ 11 | 0 12 | ], 13 | "type" : "SCALAR" 14 | }, 15 | { 16 | "bufferView" : 1, 17 | "componentType" : 5126, 18 | "count" : 14556, 19 | "max" : [ 20 | 0.9424954056739807, 21 | 0.8128451108932495, 22 | 0.900973916053772 23 | ], 24 | "min" : [ 25 | -0.9474585652351379, 26 | -1.18715500831604, 27 | -0.9009949564933777 28 | ], 29 | "type" : "VEC3" 30 | }, 31 | { 32 | "bufferView" : 2, 33 | "componentType" : 5126, 34 | "count" : 14556, 35 | "max" : [ 36 | 1.0, 37 | 1.0, 38 | 1.0 39 | ], 40 | "min" : [ 41 | -1.0, 42 | -1.0, 43 | -1.0 44 | ], 45 | "type" : "VEC3" 46 | }, 47 | { 48 | "bufferView" : 3, 49 | "componentType" : 5126, 50 | "count" : 14556, 51 | "max" : [ 52 | 0.9999759793281555, 53 | 1.998665988445282 54 | ], 55 | "min" : [ 56 | 0.002448640065267682, 57 | 1.0005531199858524 58 | ], 59 | "type" : "VEC2" 60 | } 61 | ], 62 | "asset" : { 63 | "generator" : "Khronos Blender glTF 2.0 exporter", 64 | "version" : "2.0" 65 | }, 66 | "bufferViews" : [ 67 | { 68 | "buffer" : 0, 69 | "byteLength" : 92712, 70 | "byteOffset" : 0, 71 | "target" : 34963 72 | }, 73 | { 74 | "buffer" : 0, 75 | "byteLength" : 174672, 76 | "byteOffset" : 92712, 77 | "target" : 34962 78 | }, 79 | { 80 | "buffer" : 0, 81 | "byteLength" : 174672, 82 | "byteOffset" : 267384, 83 | "target" : 34962 84 | }, 85 | { 86 | "buffer" : 0, 87 | "byteLength" : 116448, 88 | "byteOffset" : 442056, 89 | "target" : 34962 90 | } 91 | ], 92 | "buffers" : [ 93 | { 94 | "byteLength" : 558504, 95 | "uri" : "DamagedHelmet.bin" 96 | } 97 | ], 98 | "images" : [ 99 | { 100 | "uri" : "Default_albedo.jpg" 101 | }, 102 | { 103 | "uri" : "Default_metalRoughness.jpg" 104 | }, 105 | { 106 | "uri" : "Default_emissive.jpg" 107 | }, 108 | { 109 | "uri" : "Default_AO.jpg" 110 | }, 111 | { 112 | "uri" : "Default_normal.jpg" 113 | } 114 | ], 115 | "materials" : [ 116 | { 117 | "emissiveFactor" : [ 118 | 1.0, 119 | 1.0, 120 | 1.0 121 | ], 122 | "emissiveTexture" : { 123 | "index" : 2 124 | }, 125 | "name" : "Material_MR", 126 | "normalTexture" : { 127 | "index" : 4 128 | }, 129 | "occlusionTexture" : { 130 | "index" : 3 131 | }, 132 | "pbrMetallicRoughness" : { 133 | "baseColorTexture" : { 134 | "index" : 0 135 | }, 136 | "metallicRoughnessTexture" : { 137 | "index" : 1 138 | } 139 | } 140 | } 141 | ], 142 | "meshes" : [ 143 | { 144 | "name" : "mesh_helmet_LP_13930damagedHelmet", 145 | "primitives" : [ 146 | { 147 | "attributes" : { 148 | "NORMAL" : 2, 149 | "POSITION" : 1, 150 | "TEXCOORD_0" : 3 151 | }, 152 | "indices" : 0, 153 | "material" : 0 154 | } 155 | ] 156 | } 157 | ], 158 | "nodes" : [ 159 | { 160 | "mesh" : 0, 161 | "name" : "node_damagedHelmet_-6514", 162 | "rotation" : [ 163 | 0.7071068286895752, 164 | 0.0, 165 | -0.0, 166 | 0.7071068286895752 167 | ] 168 | } 169 | ], 170 | "samplers" : [ 171 | {} 172 | ], 173 | "scene" : 0, 174 | "scenes" : [ 175 | { 176 | "name" : "Scene", 177 | "nodes" : [ 178 | 0 179 | ] 180 | } 181 | ], 182 | "textures" : [ 183 | { 184 | "sampler" : 0, 185 | "source" : 0 186 | }, 187 | { 188 | "sampler" : 0, 189 | "source" : 1 190 | }, 191 | { 192 | "sampler" : 0, 193 | "source" : 2 194 | }, 195 | { 196 | "sampler" : 0, 197 | "source" : 3 198 | }, 199 | { 200 | "sampler" : 0, 201 | "source" : 4 202 | } 203 | ] 204 | } 205 | -------------------------------------------------------------------------------- /examples/models/gltf/DamagedHelmet/glTF-small/DamagedHelmet.gltf: -------------------------------------------------------------------------------- 1 | { 2 | "accessors" : [ 3 | { 4 | "bufferView" : 0, 5 | "componentType" : 5123, 6 | "count" : 46356, 7 | "max" : [ 8 | 14555 9 | ], 10 | "min" : [ 11 | 0 12 | ], 13 | "type" : "SCALAR" 14 | }, 15 | { 16 | "bufferView" : 1, 17 | "componentType" : 5126, 18 | "count" : 14556, 19 | "max" : [ 20 | 0.9424954056739807, 21 | 0.8128451108932495, 22 | 0.900973916053772 23 | ], 24 | "min" : [ 25 | -0.9474585652351379, 26 | -1.18715500831604, 27 | -0.9009949564933777 28 | ], 29 | "type" : "VEC3" 30 | }, 31 | { 32 | "bufferView" : 2, 33 | "componentType" : 5126, 34 | "count" : 14556, 35 | "max" : [ 36 | 1.0, 37 | 1.0, 38 | 1.0 39 | ], 40 | "min" : [ 41 | -1.0, 42 | -1.0, 43 | -1.0 44 | ], 45 | "type" : "VEC3" 46 | }, 47 | { 48 | "bufferView" : 3, 49 | "componentType" : 5126, 50 | "count" : 14556, 51 | "max" : [ 52 | 0.9999759793281555, 53 | 1.998665988445282 54 | ], 55 | "min" : [ 56 | 0.002448640065267682, 57 | 1.0005531199858524 58 | ], 59 | "type" : "VEC2" 60 | } 61 | ], 62 | "asset" : { 63 | "generator" : "Khronos Blender glTF 2.0 exporter", 64 | "version" : "2.0" 65 | }, 66 | "bufferViews" : [ 67 | { 68 | "buffer" : 0, 69 | "byteLength" : 92712, 70 | "byteOffset" : 0, 71 | "target" : 34963 72 | }, 73 | { 74 | "buffer" : 0, 75 | "byteLength" : 174672, 76 | "byteOffset" : 92712, 77 | "target" : 34962 78 | }, 79 | { 80 | "buffer" : 0, 81 | "byteLength" : 174672, 82 | "byteOffset" : 267384, 83 | "target" : 34962 84 | }, 85 | { 86 | "buffer" : 0, 87 | "byteLength" : 116448, 88 | "byteOffset" : 442056, 89 | "target" : 34962 90 | } 91 | ], 92 | "buffers" : [ 93 | { 94 | "byteLength" : 558504, 95 | "uri" : "DamagedHelmet.bin" 96 | } 97 | ], 98 | "images" : [ 99 | { 100 | "uri" : "Default_albedo.jpg" 101 | }, 102 | { 103 | "uri" : "Default_metalRoughness.jpg" 104 | }, 105 | { 106 | "uri" : "Default_emissive.jpg" 107 | }, 108 | { 109 | "uri" : "Default_AO.jpg" 110 | }, 111 | { 112 | "uri" : "Default_normal.jpg" 113 | } 114 | ], 115 | "materials" : [ 116 | { 117 | "emissiveFactor" : [ 118 | 1.0, 119 | 1.0, 120 | 1.0 121 | ], 122 | "emissiveTexture" : { 123 | "index" : 2 124 | }, 125 | "name" : "Material_MR", 126 | "normalTexture" : { 127 | "index" : 4 128 | }, 129 | "occlusionTexture" : { 130 | "index" : 3 131 | }, 132 | "pbrMetallicRoughness" : { 133 | "baseColorTexture" : { 134 | "index" : 0 135 | }, 136 | "metallicRoughnessTexture" : { 137 | "index" : 1 138 | } 139 | } 140 | } 141 | ], 142 | "meshes" : [ 143 | { 144 | "name" : "mesh_helmet_LP_13930damagedHelmet", 145 | "primitives" : [ 146 | { 147 | "attributes" : { 148 | "NORMAL" : 2, 149 | "POSITION" : 1, 150 | "TEXCOORD_0" : 3 151 | }, 152 | "indices" : 0, 153 | "material" : 0 154 | } 155 | ] 156 | } 157 | ], 158 | "nodes" : [ 159 | { 160 | "mesh" : 0, 161 | "name" : "node_damagedHelmet_-6514", 162 | "rotation" : [ 163 | 0.7071068286895752, 164 | 0.0, 165 | -0.0, 166 | 0.7071068286895752 167 | ] 168 | } 169 | ], 170 | "samplers" : [ 171 | {} 172 | ], 173 | "scene" : 0, 174 | "scenes" : [ 175 | { 176 | "name" : "Scene", 177 | "nodes" : [ 178 | 0 179 | ] 180 | } 181 | ], 182 | "textures" : [ 183 | { 184 | "sampler" : 0, 185 | "source" : 0 186 | }, 187 | { 188 | "sampler" : 0, 189 | "source" : 1 190 | }, 191 | { 192 | "sampler" : 0, 193 | "source" : 2 194 | }, 195 | { 196 | "sampler" : 0, 197 | "source" : 3 198 | }, 199 | { 200 | "sampler" : 0, 201 | "source" : 4 202 | } 203 | ] 204 | } 205 | -------------------------------------------------------------------------------- /examples/models/json/suzanne_buffergeometry.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata":{ 3 | "position":505, 4 | "type":"BufferGeometry", 5 | "generator":"io_three", 6 | "version":3 7 | }, 8 | "data":{ 9 | "attributes":{ 10 | "position":{ 11 | "itemSize":3, 12 | "type":"Float32Array", 13 | "array":[0.46875,0.242188,0.757812,0.5,0.09375,0.6875,0.5625,0.242188,0.671875,-0.5,0.09375,0.6875,-0.46875,0.242188,0.757812,-0.5625,0.242188,0.671875,0.546875,0.0546875,0.578125,0.625,0.242188,0.5625,-0.546875,0.0546875,0.578125,-0.625,0.242188,0.5625,0.351562,-0.0234375,0.617188,-0.351562,-0.0234375,0.617188,0.4375,0.164063,0.765625,0.351562,0.03125,0.71875,-0.351562,0.03125,0.71875,-0.4375,0.164063,0.765625,0.351562,0.132813,0.78125,0.203125,0.09375,0.742188,-0.203125,0.09375,0.742188,-0.351562,0.132813,0.78125,0.15625,0.0546875,0.648438,-0.15625,0.0546875,0.648438,0.140625,0.242188,0.742188,-0.140625,0.242188,0.742188,-0.078125,0.242188,0.65625,0.242188,0.242188,0.796875,0.273438,0.164063,0.796875,-0.242188,0.242188,0.796875,0.203125,0.390625,0.742188,-0.203125,0.390625,0.742188,0.078125,0.242188,0.65625,-0.15625,0.4375,0.648438,0.351562,0.453125,0.71875,0.15625,0.4375,0.648438,-0.351562,0.453125,0.71875,-0.351562,0.515625,0.617188,0.351562,0.359375,0.78125,0.273438,0.328125,0.796875,-0.351562,0.359375,0.78125,0.4375,0.328125,0.765625,-0.4375,0.328125,0.765625,-0.5,0.390625,0.6875,0.5,0.390625,0.6875,0.351562,0.515625,0.617188,-0.546875,0.4375,0.578125,0.546875,0.4375,0.578125,0.476562,0.242188,0.773438,-0.476562,0.242188,0.773438,-0.445312,0.335938,0.78125,0.445312,0.335938,0.78125,-0.351562,0.375,0.804688,0.351562,0.375,0.804688,-0.273438,0.328125,0.796875,-0.265625,0.335938,0.820312,0.265625,0.335938,0.820312,-0.226562,0.242188,0.820312,0.265625,0.15625,0.820312,0.226562,0.242188,0.820312,-0.265625,0.15625,0.820312,0.351562,0.117188,0.804688,-0.351562,0.117188,0.804688,-0.273438,0.164063,0.796875,0.445312,0.15625,0.78125,-0.445312,0.15625,0.78125,0.351562,0.242188,0.828125,-0.351562,0.242188,0.828125,0.164062,-0.929688,0.632813,0,-0.984375,0.578125,0.179688,-0.96875,0.554688,-0.164062,-0.929688,0.632813,0,-0.945312,0.640625,0.234375,-0.914062,0.632813,0.328125,-0.945312,0.523438,-0.234375,-0.914062,0.632813,-0.179688,-0.96875,0.554688,0.367188,-0.890625,0.53125,-0.367188,-0.890625,0.53125,-0.328125,-0.945312,0.523438,0.351562,-0.695312,0.570313,0.265625,-0.820312,0.664063,-0.265625,-0.820312,0.664063,-0.351562,-0.695312,0.570313,0.3125,-0.4375,0.570312,0.25,-0.703125,0.6875,-0.25,-0.703125,0.6875,-0.3125,-0.4375,0.570312,0.203125,-0.1875,0.5625,0.398438,-0.046875,0.671875,0.125,-0.101562,0.8125,-0.398438,-0.046875,0.671875,-0.203125,-0.1875,0.5625,-0.125,-0.101562,0.8125,0.632812,-0.0390625,0.539062,0.4375,-0.140625,0.53125,-0.632812,-0.0390625,0.539062,-0.617188,0.0546875,0.625,0.726562,0.203125,0.601562,0.617188,0.0546875,0.625,-0.726562,0.203125,0.601562,0.859375,0.429688,0.59375,0.828125,0.148438,0.445312,-0.859375,0.429688,0.59375,-0.742188,0.375,0.65625,0.710938,0.484375,0.625,0.742188,0.375,0.65625,-0.710938,0.484375,0.625,-0.6875,0.414063,0.726562,0.492188,0.601563,0.6875,0.6875,0.414063,0.726562,-0.492188,0.601563,0.6875,-0.4375,0.546875,0.796875,0.3125,0.640625,0.835938,0.4375,0.546875,0.796875,-0.3125,0.640625,0.835938,0.15625,0.71875,0.757812,0.320312,0.757813,0.734375,-0.15625,0.71875,0.757812,-0.203125,0.617188,0.851562,0.0625,0.492188,0.75,0.203125,0.617188,0.851562,-0.0625,0.492188,0.75,-0.101562,0.429688,0.84375,0,0.429688,0.742188,0.101562,0.429688,0.84375,0,0.351563,0.820312,0.25,0.46875,0.757812,0.164062,0.414063,0.773438,-0.25,0.46875,0.757812,0.328125,0.476563,0.742188,0.429688,0.4375,0.71875,-0.328125,0.476563,0.742188,0.601562,0.375,0.664062,-0.429688,0.4375,0.71875,0.640625,0.296875,0.648438,-0.601562,0.375,0.664062,0.625,0.1875,0.648438,-0.640625,0.296875,0.648438,0.492188,0.0625,0.671875,-0.625,0.1875,0.648438,0.375,0.015625,0.703125,-0.492188,0.0625,0.671875,-0.375,0.015625,0.703125,0,0.046875,0.726562,0.125,0.304688,0.765625,-0.125,0.304688,0.765625,0,0.210938,0.765625,0.132812,0.210938,0.757812,-0.132812,0.210938,0.757812,0.164062,0.140625,0.75,-0.164062,0.140625,0.75,0.0625,-0.882812,0.695313,-0.0625,-0.882812,0.695313,0.117188,-0.835937,0.710938,-0.117188,-0.835937,0.710938,0.109375,-0.71875,0.734375,0.210938,-0.445312,0.710938,0.117188,-0.6875,0.734375,-0.117188,-0.6875,0.734375,-0.210938,-0.445312,0.710938,-0.109375,-0.71875,0.734375,0,-0.328125,0.742188,0.078125,-0.445312,0.75,0.0859375,-0.289062,0.742188,-0.078125,-0.445312,0.75,0,-0.445312,0.75,0,-0.679687,0.734375,0,-0.765625,0.734375,0.125,-0.226562,0.75,0.09375,-0.273437,0.78125,-0.09375,-0.273437,0.78125,-0.125,-0.226562,0.75,-0.0859375,-0.289062,0.742188,0.109375,-0.132812,0.78125,0.101562,-0.148437,0.742188,-0.109375,-0.132812,0.78125,-0.132812,-0.226562,0.796875,0.0390625,-0.125,0.78125,0,-0.140625,0.742188,-0.0390625,-0.125,0.78125,-0.101562,-0.148437,0.742188,0,-0.1875,0.796875,0,-0.195312,0.75,0,-0.320312,0.78125,0,-0.289062,0.804688,-0.078125,-0.25,0.804688,0.046875,-0.148437,0.8125,-0.046875,-0.148437,0.8125,0.09375,-0.15625,0.8125,-0.09375,-0.15625,0.8125,0.132812,-0.226562,0.796875,-0.109375,-0.226562,0.828125,0.078125,-0.25,0.804688,0.109375,-0.226562,0.828125,0,-0.203125,0.828125,0.164062,-0.242187,0.710938,-0.164062,-0.242187,0.710938,-0.179688,-0.3125,0.710938,0.179688,-0.3125,0.710938,0.257812,-0.3125,0.554688,-0.257812,-0.3125,0.554688,0.234375,-0.25,0.554688,-0.234375,-0.25,0.554688,0.09375,-0.742187,0.726563,-0.09375,-0.742187,0.726563,0,-0.773437,0.71875,0.09375,-0.820312,0.710938,-0.09375,-0.820312,0.710938,0.046875,-0.867187,0.6875,-0.046875,-0.867187,0.6875,0,-0.890625,0.6875,0,-0.875,0.6875,0,-0.859375,0.632813,-0.046875,-0.851562,0.632813,0.09375,-0.8125,0.640625,0.046875,-0.851562,0.632813,-0.09375,-0.8125,0.640625,0.09375,-0.75,0.664063,-0.09375,-0.75,0.664063,0,-0.78125,0.65625,0.1875,0.15625,0.773438,0.171875,0.21875,0.78125,-0.1875,0.15625,0.773438,-0.171875,0.21875,0.78125,0.179688,0.296875,0.78125,-0.179688,0.296875,0.78125,0.210938,0.375,0.78125,-0.210938,0.375,0.78125,-0.226562,0.109375,0.78125,0.375,0.0625,0.742188,0.226562,0.109375,0.78125,-0.375,0.0625,0.742188,0.476562,0.101563,0.71875,-0.476562,0.101563,0.71875,0.578125,0.195313,0.679688,-0.578125,0.195313,0.679688,0.585938,0.289063,0.6875,-0.585938,0.289063,0.6875,-0.5625,0.351563,0.695312,0.5625,0.351563,0.695312,-0.421875,0.398438,0.773438,0.335938,0.429688,0.757812,0.421875,0.398438,0.773438,-0.335938,0.429688,0.757812,0.273438,0.421875,0.773438,-0.273438,0.421875,0.773438,0.234375,0.359375,0.757812,0.28125,0.398438,0.765625,-0.234375,0.359375,0.757812,-0.28125,0.398438,0.765625,0.335938,0.40625,0.75,-0.335938,0.40625,0.75,0.414062,0.390625,0.75,-0.414062,0.390625,0.75,0.53125,0.335938,0.679688,-0.53125,0.335938,0.679688,0.554688,0.28125,0.671875,-0.554688,0.28125,0.671875,0.546875,0.210938,0.671875,-0.546875,0.210938,0.671875,0.460938,0.117188,0.703125,-0.460938,0.117188,0.703125,0.375,0.0859375,0.726562,-0.375,0.0859375,0.726562,0.242188,0.125,0.757812,-0.242188,0.125,0.757812,0.203125,0.171875,0.75,-0.203125,0.171875,0.75,0.195312,0.296875,0.757812,-0.195312,0.296875,0.757812,0.195312,0.226563,0.75,-0.195312,0.226563,0.75,0.109375,0.460938,0.609375,0,0.40625,0.601562,-0.109375,0.460938,0.609375,0.195312,0.664062,0.617188,-0.195312,0.664062,0.617188,-0.320312,0.757813,0.734375,-0.335938,0.6875,0.59375,0.335938,0.6875,0.59375,-0.484375,0.554688,0.554688,0.484375,0.554688,0.554688,-0.679688,0.453125,0.492187,0.796875,0.40625,0.460937,0.679688,0.453125,0.492187,-0.796875,0.40625,0.460937,-0.828125,0.148438,0.445312,-0.773438,0.164063,0.375,0.601562,1.80992e-08,0.414062,0.773438,0.164063,0.375,-0.601562,1.80992e-08,0.414062,0.4375,-0.09375,0.46875,-0.4375,-0.09375,0.46875,0,-0.484375,0.28125,0.125,-0.539062,0.359375,0,-0.570312,0.320313,-0.125,-0.539062,0.359375,-0.179688,-0.414062,0.257813,0.140625,-0.757812,0.367188,0,-0.804688,0.34375,-0.140625,-0.757812,0.367188,0.164062,-0.945312,0.4375,0,-0.976562,0.460938,-0.164062,-0.945312,0.4375,0.328125,-0.914062,0.398438,-0.328125,-0.914062,0.398438,0.289062,-0.710938,0.382813,-0.289062,-0.710938,0.382813,0.25,-0.5,0.390625,-0.25,-0.5,0.390625,0.179688,-0.414062,0.257813,0.234375,-0.351562,0.40625,-0.234375,-0.351562,0.40625,0.21875,-0.28125,0.429688,-0.21875,-0.28125,0.429688,-0.210938,-0.226562,0.46875,0.203125,-0.171875,0.5,-0.203125,-0.171875,0.5,-0.4375,-0.140625,0.53125,0.335938,0.0546875,-0.664062,0,-0.195313,-0.671875,0,0.0703125,-0.828125,-0.335938,0.0546875,-0.664062,-0.34375,-0.148438,-0.539062,0.34375,-0.148438,-0.539062,0,-0.382813,-0.351562,-0.296875,-0.3125,-0.265625,0.210938,-0.390625,0.164063,0,-0.460938,0.1875,-0.210938,-0.390625,0.164063,0.734375,-0.046875,0.0703125,0.851562,0.234375,0.0546875,-0.734375,-0.046875,0.0703125,-0.851562,0.234375,0.0546875,0.460938,0.4375,-0.703125,0,0.5625,-0.851562,-0.460938,0.4375,-0.703125,0.453125,0.851562,0.234375,0,0.984375,-0.078125,0,0.898438,0.289062,-0.453125,0.851562,0.234375,-0.453125,0.929688,-0.0703125,0.453125,0.867188,-0.382813,0,0.898438,-0.546875,-0.453125,0.867188,-0.382813,0.726562,0.40625,0.335937,0.632812,0.453125,0.28125,-0.726562,0.40625,0.335937,-0.632812,0.453125,0.28125,0.796875,0.5625,0.125,0.640625,0.703125,0.0546875,-0.796875,0.5625,0.125,-0.640625,0.703125,0.0546875,0.796875,0.617188,-0.117188,0.640625,0.75,-0.195313,-0.796875,0.617188,-0.117188,-0.640625,0.75,-0.195313,0.796875,0.539062,-0.359375,0.640625,0.679688,-0.445313,-0.796875,0.539062,-0.359375,-0.640625,0.679688,-0.445313,0.617188,0.328125,-0.585938,0.773438,0.265625,-0.4375,-0.617188,0.328125,-0.585938,0.453125,0.929688,-0.0703125,0.460938,0.523438,0.429687,-0.460938,0.523438,0.429687,0,0.570312,0.570312,0.859375,0.320312,-0.046875,-0.859375,0.320312,-0.046875,0.820312,0.328125,-0.203125,-0.820312,0.328125,-0.203125,0.296875,-0.3125,-0.265625,0.40625,-0.171875,0.148438,-0.40625,-0.171875,0.148438,-0.429688,-0.195313,-0.210937,0.59375,-0.125,-0.164062,-0.59375,-0.125,-0.164062,0.210938,-0.226562,0.46875,0.640625,-0.00781252,-0.429688,-0.640625,-0.00781252,-0.429688,-0.484375,0.0234375,-0.546875,0.429688,-0.195313,-0.210937,0.484375,0.0234375,-0.546875,0.890625,0.40625,-0.234375,1.01562,0.414062,-0.289063,1.02344,0.476562,-0.3125,-0.890625,0.40625,-0.234375,-1.01562,0.414062,-0.289063,-0.921875,0.359375,-0.21875,1.1875,0.4375,-0.390625,1.23438,0.507812,-0.421875,-1.1875,0.4375,-0.390625,-1.02344,0.476562,-0.3125,-1.23438,0.507812,-0.421875,1.35156,0.320312,-0.421875,-1.35156,0.320312,-0.421875,-1.26562,0.289062,-0.40625,1.26562,0.289062,-0.40625,1.28125,0.0546875,-0.429688,-1.28125,0.0546875,-0.429688,-1.21094,0.078125,-0.40625,1.21094,0.078125,-0.40625,1.03906,-0.101563,-0.328125,-1.03906,-0.101563,-0.328125,-1.03125,-0.0390625,-0.304688,0.828125,-0.0703125,-0.132812,0.773438,-0.140625,-0.125,-0.828125,-0.0703125,-0.132812,-0.773438,-0.140625,-0.125,1.03125,-0.0390625,-0.304688,0.882812,-0.0234375,-0.210938,-0.882812,-0.0234375,-0.210938,1.03906,-1.60503e-08,-0.367188,-1.03906,-1.60503e-08,-0.367188,1.23438,0.25,-0.445312,-1.23438,0.25,-0.445312,-1.1875,0.09375,-0.445312,1.17188,0.359375,-0.4375,-1.17188,0.359375,-0.4375,1.02344,0.34375,-0.359375,-1.02344,0.34375,-0.359375,0.945312,0.304688,-0.289062,-0.945312,0.304688,-0.289062,0.726562,-3.07346e-09,-0.0703125,-0.726562,-3.07346e-09,-0.0703125,-0.71875,-0.0234375,-0.171875,0.71875,-0.0234375,-0.171875,0.921875,0.359375,-0.21875,0.8125,-0.015625,-0.273438,-0.8125,-0.015625,-0.273438,0.71875,0.0390625,-0.1875,0.84375,0.015625,-0.273438,-0.71875,0.0390625,-0.1875,0.757812,0.09375,-0.273438,0.820312,0.0859375,-0.273438,-0.84375,0.015625,-0.273438,-0.757812,0.09375,-0.273438,-0.820312,0.0859375,-0.273438,0.796875,0.203125,-0.210938,0.835938,0.171875,-0.273438,-0.796875,0.203125,-0.210938,0.890625,0.242187,-0.265625,0.84375,0.289062,-0.210938,-0.890625,0.242187,-0.265625,-0.835938,0.171875,-0.273438,-0.84375,0.289062,-0.210938,0.890625,0.234375,-0.320312,0.953125,0.289062,-0.34375,-0.890625,0.234375,-0.320312,-0.953125,0.289062,-0.34375,-0.84375,0.171875,-0.320312,0.765625,0.09375,-0.320312,0.84375,0.171875,-0.320312,-0.765625,0.09375,-0.320312,-0.828125,0.078125,-0.320312,0.828125,0.078125,-0.320312,-0.851562,0.015625,-0.320312,0.8125,-0.015625,-0.320312,0.851562,0.015625,-0.320312,-0.8125,-0.015625,-0.320312,0.882812,-0.015625,-0.265625,-0.882812,-0.015625,-0.265625,1.03906,0.328125,-0.414062,-1.03906,0.328125,-0.414062,1.1875,0.34375,-0.484375,-1.1875,0.34375,-0.484375,1.25781,0.242187,-0.492188,-1.25781,0.242187,-0.492188,1.21094,0.0859375,-0.484375,1.1875,0.09375,-0.445312,-1.21094,0.0859375,-0.484375,1.04688,-1.84407e-08,-0.421875,-1.04688,-1.84407e-08,-0.421875,0.890625,0.109375,-0.328125,-0.890625,0.109375,-0.328125,-0.9375,0.0625,-0.335938,0.9375,0.0625,-0.335938,0.960938,0.171875,-0.351562,-0.960938,0.171875,-0.351562,-1,0.125,-0.367188,1.05469,0.1875,-0.382812,1.01562,0.234375,-0.375,-1.05469,0.1875,-0.382812,-1.01562,0.234375,-0.375,1.08594,0.273437,-0.390625,-1.08594,0.273437,-0.390625,-1.10938,0.210937,-0.390625,1.10938,0.210937,-0.390625,0.789062,-0.125,-0.328125,1.03906,-0.0859375,-0.492188,-0.789062,-0.125,-0.328125,-1.03906,-0.0859375,-0.492188,1.3125,0.0546875,-0.53125,-1.3125,0.0546875,-0.53125,1.36719,0.296875,-0.5,-1.36719,0.296875,-0.5,1.25,0.46875,-0.546875,-1.25,0.46875,-0.546875,1.02344,0.4375,-0.484375,-1.02344,0.4375,-0.484375,0.859375,0.382812,-0.382813,-0.859375,0.382812,-0.382813,-0.773438,0.265625,-0.4375,-0.164062,0.414063,0.773438,1,0.125,-0.367188] 14 | } 15 | }, 16 | "index":{ 17 | "itemSize":1, 18 | "type":"Uint16Array", 19 | "array":[0,1,2,3,4,5,2,6,7,8,5,9,1,10,6,11,3,8,12,13,1,14,15,3,16,17,13,18,19,14,13,20,10,21,14,11,22,20,17,23,21,24,25,17,26,27,18,23,25,28,22,29,27,23,28,30,22,29,24,31,32,33,28,34,31,35,36,28,37,38,29,34,39,32,36,40,34,41,42,43,32,41,35,44,2,45,42,5,44,9,0,42,39,4,41,5,39,46,0,40,47,48,36,49,39,38,48,50,37,51,36,52,50,53,25,54,37,27,53,55,25,56,57,58,27,55,26,59,56,60,61,58,16,62,59,63,19,60,12,46,62,47,15,63,64,62,46,47,63,65,59,62,64,65,63,60,64,56,59,60,58,65,64,57,56,58,55,65,64,54,57,55,53,65,64,51,54,53,50,65,64,49,51,50,48,65,64,46,49,48,47,65,66,67,68,69,67,70,71,68,72,73,74,69,75,71,72,73,76,77,78,79,75,80,81,76,82,83,78,84,85,81,86,87,88,89,90,91,92,87,93,94,89,95,92,96,97,98,94,95,99,96,100,101,98,102,103,104,99,105,102,106,107,108,103,109,106,110,107,111,112,113,109,110,114,111,115,116,113,117,118,119,114,120,117,121,122,123,118,122,121,124,125,123,126,127,121,117,125,111,119,113,127,117,112,128,129,110,130,113,108,129,131,106,132,110,104,131,133,102,134,106,96,133,135,98,136,102,97,135,137,95,138,98,87,137,139,89,140,95,17,87,139,89,18,141,17,142,88,142,18,91,123,143,126,121,144,124,143,145,146,145,144,147,148,145,142,149,145,147,150,70,66,70,151,69,152,66,71,69,153,73,152,79,154,153,80,73,155,156,83,157,158,84,154,83,156,84,159,157,160,161,162,160,163,164,161,165,156,163,165,164,154,165,166,159,165,157,167,168,162,169,170,171,172,167,173,174,170,175,176,173,177,178,179,174,180,177,181,180,177,178,162,182,160,171,182,169,168,183,182,169,183,184,180,185,176,186,180,178,176,187,172,188,178,174,187,189,172,188,175,190,189,191,168,184,175,169,192,185,193,190,186,188,193,191,192,184,193,190,177,88,142,91,177,142,173,194,88,195,179,91,162,194,167,171,195,196,161,197,162,163,196,158,198,155,82,199,158,196,200,197,198,201,196,195,86,194,200,195,90,201,166,202,154,166,203,204,152,202,205,203,153,206,150,205,207,206,151,208,209,207,210,208,209,210,207,211,210,208,211,212,207,213,214,215,208,212,205,216,213,217,206,215,204,216,202,204,217,218,218,214,216,212,218,217,216,214,213,215,212,217,146,219,220,221,147,222,143,220,223,222,144,224,143,225,126,144,226,224,17,219,148,18,221,227,17,228,229,230,18,227,139,231,228,232,141,230,137,233,231,234,140,232,135,235,233,236,138,234,131,235,133,134,236,237,129,238,131,132,237,239,129,240,241,242,132,239,128,243,240,244,130,242,125,225,243,226,127,244,243,245,246,247,244,248,240,246,249,248,242,250,240,251,241,242,252,250,241,253,238,239,254,252,235,253,255,254,236,256,235,257,233,236,258,256,231,257,259,258,232,260,231,261,228,232,262,260,228,263,229,230,264,262,219,263,265,264,221,266,225,267,245,268,226,247,223,269,267,270,224,268,220,265,269,266,222,270,122,271,272,273,122,272,118,274,271,275,120,273,115,274,114,276,275,277,107,278,115,109,277,279,103,280,107,105,279,281,103,282,283,284,105,281,100,282,99,285,284,286,100,287,288,289,285,286,92,290,287,291,94,289,292,293,294,292,295,296,294,297,298,294,299,295,298,300,301,298,302,299,68,301,300,301,74,302,72,300,303,302,77,304,75,303,305,304,76,306,78,305,307,306,81,308,305,293,307,295,306,308,303,297,305,304,299,302,307,309,310,308,296,295,82,307,310,308,85,311,312,200,198,313,201,314,310,198,82,311,199,313,200,315,86,201,316,314,315,93,86,316,317,291,318,319,320,321,319,322,323,324,319,322,324,325,324,326,327,328,324,327,327,309,292,296,327,292,309,312,310,296,313,328,288,329,330,331,286,332,333,320,334,335,320,321,336,337,338,339,337,340,337,341,342,343,337,342,342,333,334,335,342,334,283,344,345,346,281,347,345,348,349,350,347,351,349,352,353,354,351,355,353,356,357,358,355,359,360,356,361,362,358,359,333,357,360,359,335,362,341,353,357,355,343,359,363,349,353,351,340,355,336,345,349,347,339,351,283,364,280,281,365,347,364,338,366,365,338,339,274,280,271,275,279,277,271,364,366,365,273,366,272,271,366,366,273,272,288,344,282,286,346,332,330,348,344,350,332,346,367,352,348,354,368,350,356,369,361,358,370,354,371,372,326,325,373,374,372,375,329,373,376,374,287,372,329,373,289,331,290,312,372,313,291,373,312,326,372,373,328,313,290,315,377,314,316,291,378,360,361,379,362,380,360,318,333,362,321,380,381,378,375,374,379,380,323,381,371,322,374,380,318,382,323,322,380,321,383,384,385,386,387,388,385,389,390,391,392,393,389,394,390,391,395,396,397,398,394,396,399,400,401,402,398,400,403,404,402,405,406,407,403,408,409,410,405,411,404,407,401,412,409,413,400,404,414,401,397,415,400,416,417,397,389,418,396,415,419,389,384,420,391,418,384,421,419,422,387,420,375,423,329,376,424,425,406,426,375,408,425,407,330,423,367,424,332,368,369,427,383,388,370,386,405,428,426,429,407,425,430,428,431,432,429,425,433,431,434,435,436,437,438,433,439,440,436,432,438,441,442,440,443,444,442,421,427,445,422,443,438,369,367,440,370,445,423,438,367,424,440,432,423,426,430,432,425,424,421,446,447,448,422,449,439,446,441,444,448,450,439,451,452,453,444,450,434,451,433,437,453,454,431,455,434,435,454,456,431,457,458,459,435,456,428,460,457,461,429,459,419,447,462,449,420,463,417,462,464,463,418,465,414,464,466,465,415,467,414,468,469,415,470,467,469,471,412,416,472,470,412,460,410,413,461,472,458,473,455,456,474,475,476,477,473,475,478,479,477,480,481,482,478,483,480,484,481,482,485,486,462,481,484,483,463,485,477,447,446,478,449,483,452,477,446,450,478,474,455,452,451,450,454,453,460,458,457,461,456,475,471,476,460,475,472,461,480,471,468,482,472,479,487,468,466,486,470,482,464,487,466,486,465,467,462,484,464,465,485,463,402,488,489,490,403,491,398,489,492,491,399,493,398,494,394,399,495,493,394,496,390,395,497,495,390,498,385,393,499,497,385,500,383,392,501,499,489,500,498,491,501,490,498,492,489,493,499,491,496,494,492,493,495,497,369,500,361,370,501,386,361,488,378,490,502,379,375,488,406,490,376,408,0,12,1,3,15,4,2,1,6,8,3,5,1,13,10,11,14,3,12,16,13,14,19,15,16,26,17,18,61,19,13,17,20,21,18,14,22,30,20,23,18,21,25,22,17,27,61,18,25,37,28,29,52,27,28,33,30,29,23,24,32,43,33,34,29,31,36,32,28,38,52,29,39,42,32,40,38,34,42,45,43,41,34,35,2,7,45,5,41,44,0,2,42,4,40,41,39,49,46,40,4,47,36,51,49,38,40,48,37,54,51,52,38,50,25,57,54,27,52,53,25,26,56,58,61,27,26,16,59,60,19,61,16,12,62,63,15,19,12,0,46,47,4,15,66,70,67,69,74,67,71,66,68,73,77,74,75,79,71,73,80,76,78,83,79,80,84,81,82,155,83,84,158,85,86,93,87,89,317,90,92,97,87,94,317,89,92,100,96,98,285,94,99,104,96,101,285,98,103,108,104,105,101,102,107,112,108,109,105,106,107,115,111,113,276,109,114,119,111,116,276,113,118,123,119,120,116,117,122,124,123,122,120,121,125,119,123,127,503,121,125,128,111,113,130,127,112,111,128,110,132,130,108,112,129,106,134,132,104,108,131,102,136,134,96,104,133,98,138,136,97,96,135,95,140,138,87,97,137,89,141,140,17,88,87,89,91,18,17,148,142,142,149,18,123,124,143,121,503,144,143,124,145,145,124,144,148,146,145,149,142,145,150,209,70,70,209,151,152,150,66,69,151,153,152,71,79,153,159,80,155,161,156,157,163,158,154,79,83,84,80,159,160,164,161,160,171,163,161,164,165,163,157,165,154,156,165,159,166,165,167,189,168,169,175,170,172,189,167,174,179,170,176,172,173,178,177,179,180,176,177,162,168,182,171,160,182,168,191,183,169,182,183,180,193,185,186,193,180,176,185,187,188,186,178,187,192,189,188,174,175,189,192,191,184,190,175,192,187,185,190,193,186,193,183,191,184,183,193,177,173,88,91,179,177,173,167,194,195,170,179,162,197,194,171,170,195,161,155,197,163,171,196,198,197,155,199,85,158,200,194,197,201,199,196,86,88,194,195,91,90,166,204,202,166,159,203,152,154,202,203,159,153,150,152,205,206,153,151,209,150,207,208,151,209,207,214,211,208,210,211,207,205,213,215,206,208,205,202,216,217,203,206,204,218,216,204,203,217,218,211,214,212,211,218,146,148,219,221,149,147,143,146,220,222,147,144,143,223,225,144,503,226,17,229,219,18,149,221,17,139,228,230,141,18,139,137,231,232,140,141,137,135,233,234,138,140,135,133,235,236,136,138,131,238,235,134,136,236,129,241,238,132,134,237,129,128,240,242,130,132,128,125,243,244,127,130,125,126,225,226,503,127,243,225,245,247,226,244,240,243,246,248,244,242,240,249,251,242,239,252,241,251,253,239,237,254,235,238,253,254,237,236,235,255,257,236,234,258,231,233,257,258,234,232,231,259,261,232,230,262,228,261,263,230,227,264,219,229,263,264,227,221,225,223,267,268,224,226,223,220,269,270,222,224,220,219,265,266,221,222,122,118,271,273,120,122,118,114,274,275,116,120,115,278,274,276,116,275,107,280,278,109,276,277,103,283,280,105,109,279,103,99,282,284,101,105,100,288,282,285,101,284,100,92,287,289,94,285,92,93,290,291,317,94,292,309,293,292,294,295,294,293,297,294,298,299,298,297,300,298,301,302,68,67,301,301,67,74,72,68,300,302,74,77,75,72,303,304,77,76,78,75,305,306,76,81,305,297,293,295,299,306,303,300,297,304,306,299,307,293,309,308,311,296,82,78,307,308,81,85,312,377,200,313,199,201,310,312,198,311,85,199,200,377,315,201,90,316,315,290,93,316,90,317,318,323,319,321,320,319,323,371,324,322,319,324,324,371,326,328,325,324,327,326,309,296,328,327,309,326,312,296,311,313,288,287,329,331,289,286,333,318,320,335,334,320,336,363,337,339,338,337,337,363,341,343,340,337,342,341,333,335,343,342,283,282,344,346,284,281,345,344,348,350,346,347,349,348,352,354,350,351,353,352,356,358,354,355,360,357,356,362,502,358,333,341,357,359,343,335,341,363,353,355,340,343,363,336,349,351,339,340,336,364,345,347,365,339,283,345,364,281,279,365,364,336,338,365,366,338,274,278,280,275,273,279,271,280,364,365,279,273,288,330,344,286,284,346,330,367,348,350,368,332,367,369,352,354,370,368,356,352,369,358,502,370,371,381,372,325,328,373,372,381,375,373,331,376,287,290,372,373,291,289,290,377,312,313,314,291,378,382,360,379,502,362,360,382,318,362,335,321,381,382,378,374,376,379,323,382,381,322,325,374,383,427,384,386,392,387,385,384,389,391,387,392,389,397,394,391,393,395,397,401,398,396,395,399,401,409,402,400,399,403,402,409,405,407,404,403,409,412,410,411,413,404,401,469,412,413,416,400,414,469,401,415,396,400,417,414,397,418,391,396,419,417,389,420,387,391,384,427,421,422,388,387,375,426,423,376,331,424,406,405,426,408,376,425,330,329,423,424,331,332,369,442,427,388,445,370,405,410,428,429,411,407,430,426,428,432,435,429,433,430,431,435,432,436,438,430,433,440,444,436,438,439,441,440,445,443,442,441,421,445,388,422,438,442,369,440,368,370,423,430,438,424,368,440,421,441,446,448,443,422,439,452,446,444,443,448,439,433,451,453,436,444,434,455,451,437,436,453,431,458,455,435,437,454,431,428,457,459,429,435,428,410,460,461,411,429,419,421,447,449,422,420,417,419,462,463,420,418,414,417,464,465,418,415,414,466,468,415,416,470,469,468,471,416,413,472,412,471,460,413,411,461,458,476,473,456,454,474,476,504,477,475,474,478,477,504,480,482,479,478,480,487,484,482,483,485,462,447,481,483,449,463,477,481,447,478,448,449,452,473,477,450,448,478,455,473,452,450,474,454,460,476,458,461,459,456,471,504,476,475,479,472,480,504,471,482,470,472,487,480,468,486,467,470,464,484,487,486,485,465,402,406,488,490,408,403,398,402,489,491,403,399,398,492,494,399,395,495,394,494,496,395,393,497,390,496,498,393,392,499,385,498,500,392,386,501,489,488,500,491,499,501,498,496,492,493,497,499,369,383,500,370,502,501,361,500,488,490,501,502,375,378,488,490,379,376] 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /src/renderers/WebGPURenderer.js: -------------------------------------------------------------------------------- 1 | import { 2 | BufferAttribute, 3 | Matrix4, 4 | Vector3 5 | } from 'https://raw.githack.com/mrdoob/three.js/r111/build/three.module.js'; 6 | 7 | const painterSort = (a, b) => { 8 | return a.z - b.z; 9 | }; 10 | 11 | const reversePainterSort = (a, b) => { 12 | return b.z - a.z; 13 | }; 14 | 15 | const defaultAttributeDefinitions = [{ 16 | name: 'position', 17 | format: 'float3' 18 | }, { 19 | name: 'normal', 20 | format: 'float3' 21 | }, { 22 | name: 'uv', 23 | format: 'float2' 24 | }]; 25 | 26 | const defaultVertexUniformsDefinitions = [{ 27 | name: 'modelMatrix', 28 | format: 'matrix4' 29 | }, { 30 | name: 'viewMatrix', 31 | format: 'matrix4' 32 | }, { 33 | name: 'projectionMatrix', 34 | format: 'matrix4' 35 | }, { 36 | name: 'normalMatrix', 37 | format: 'matrix3' 38 | }]; 39 | 40 | const defaultFragmentUniformsDefinitions = [{ 41 | name: 'diffuse', 42 | format: 'color' 43 | }, { 44 | name: 'opacity', 45 | format: 'float' 46 | }]; 47 | 48 | const offsetTable = { 49 | 'float': 4, 50 | 'float2': 8, 51 | 'float3': 12, 52 | 'color': 12, 53 | 'float4': 16, 54 | 'matrix3': 12 * 4, 55 | 'matrix4': 16 * 4 56 | }; 57 | 58 | const ShaderLibs = {}; 59 | 60 | // PBR shader code is based on https://github.com/KhronosGroup/glTF-Sample-Viewer/ 61 | ShaderLibs.MeshStandardMaterial = { 62 | vertexUniforms: [], 63 | fragmentUniforms: [{ 64 | name: 'emissive', 65 | format: 'color' 66 | }, { 67 | name: 'roughness', 68 | format: 'float' 69 | }, { 70 | name: 'metalness', 71 | format: 'float' 72 | }], 73 | textures: [{ 74 | name: 'map', 75 | format: 'texture', 76 | define: 'USE_MAP' 77 | }, { 78 | name: 'emissiveMap', 79 | format: 'texture', 80 | define: 'USE_EMISSIVEMAP' 81 | }, { 82 | name: 'normalMap', 83 | format: 'texture', 84 | define: 'USE_NORMALMAP' 85 | }, { 86 | name: 'roughnessMap', 87 | format: 'texture', 88 | define: 'USE_ROUGHNESSMAP' 89 | }, { 90 | name: 'metalnessMap', 91 | format: 'texture', 92 | define: 'USE_METALNESSMAP' 93 | }, { 94 | name: 'aoMap', 95 | format: 'texture', 96 | define: 'USE_AOMAP' 97 | }], 98 | vertexShaderCode: ` 99 | layout(set=0, binding=0) uniform Uniforms { 100 | mat4 modelMatrix; 101 | mat4 viewMatrix; 102 | mat4 projectionMatrix; 103 | mat3 normalMatrix; 104 | } uniforms; 105 | 106 | layout(location = 0) in vec3 position; 107 | layout(location = 1) in vec3 normal; 108 | layout(location = 2) in vec2 uv; 109 | 110 | layout(location = 0) out vec3 fragPosition; 111 | layout(location = 1) out vec3 fragNormal; 112 | layout(location = 2) out vec2 fragUv; 113 | 114 | void main() { 115 | gl_Position = uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix * vec4(position, 1.0); 116 | fragPosition = position; 117 | fragNormal = normalize((uniforms.modelMatrix * vec4(normal, 0.0)).xyz); 118 | fragUv = uv; 119 | }`, 120 | fragmentShaderCode: ` 121 | layout(set=0, binding=1) uniform Uniforms { 122 | vec3 diffuse; 123 | float opacity; 124 | vec3 emissive; 125 | float roughness; 126 | float metalness; 127 | } uniforms; 128 | 129 | // @TODO: Cut off the binding nums of the unused maps 130 | 131 | #ifdef USE_MAP 132 | layout(set=0, binding=MAP_BINDING) uniform sampler mapSampler; 133 | layout(set=0, binding=MAP_SAMPLER_BINDING) uniform texture2D map; 134 | #endif 135 | 136 | #ifdef USE_EMISSIVEMAP 137 | layout(set=0, binding=EMISSIVEMAP_BINDING) uniform sampler emissiveMapSampler; 138 | layout(set=0, binding=EMISSIVEMAP_SAMPLER_BINDING) uniform texture2D emissiveMap; 139 | #endif 140 | 141 | #ifdef USE_NORMALMAP 142 | layout(set=0, binding=NORMALMAP_BINDING) uniform sampler normalMapSampler; 143 | layout(set=0, binding=NORMALMAP_SAMPLER_BINDING) uniform texture2D normalMap; 144 | #endif 145 | 146 | #ifdef USE_ROUGHNESSMAP 147 | layout(set=0, binding=ROUGHNESSMAP_BINDING) uniform sampler roughnessMapSampler; 148 | layout(set=0, binding=ROUGHNESSMAP_SAMPLER_BINDING) uniform texture2D roughnessMap; 149 | #endif 150 | 151 | #ifdef USE_METALNESSMAP 152 | layout(set=0, binding=METALNESSMAP_BINDING) uniform sampler metalnessMapSampler; 153 | layout(set=0, binding=METALNESSMAP_SAMPLER_BINDING) uniform texture2D metalnessMap; 154 | #endif 155 | 156 | #ifdef USE_AOMAP 157 | layout(set=0, binding=AOMAP_BINDING) uniform sampler aoMapSampler; 158 | layout(set=0, binding=AOMAP_SAMPLER_BINDING) uniform texture2D aoMap; 159 | #endif 160 | 161 | layout(location = 0) in vec3 fragPosition; 162 | layout(location = 1) in vec3 fragNormal; 163 | layout(location = 2) in vec2 fragUv; 164 | layout(location = 0) out vec4 outColor; 165 | 166 | const float M_PI = 3.141592653589793; 167 | 168 | struct PBRInfo { 169 | float NdotL; 170 | float NdotV; 171 | float NdotH; 172 | float LdotH; 173 | float VdotH; 174 | float roughness; 175 | float metallic; 176 | vec3 reflectance0; 177 | vec3 reflectance90; 178 | float alphaRoughness; 179 | vec3 diffuseColor; 180 | vec3 specularColor; 181 | }; 182 | 183 | vec3 getNormal() { 184 | #ifdef USE_NORMALMAP 185 | vec3 pos_dx = dFdx(fragPosition); 186 | vec3 pos_dy = dFdy(fragPosition); 187 | vec3 tex_dx = dFdx(vec3(fragUv, 0.0)); 188 | vec3 tex_dy = dFdy(vec3(fragUv, 0.0)); 189 | vec3 t = (tex_dy.t * pos_dx - tex_dx.t * pos_dy) / (tex_dx.s * tex_dy.t - tex_dy.s * tex_dx.t); 190 | 191 | vec3 ng = normalize(fragNormal); 192 | t = normalize(t - ng * dot(ng, t)); 193 | vec3 b = normalize(cross(ng, t)); 194 | mat3 tbn = mat3(t, b, ng); 195 | 196 | vec3 n = texture(sampler2D(normalMap, normalMapSampler), fragUv).rgb; 197 | 198 | float normalScale = 1.0; 199 | n = normalize(tbn * ((2.0 * n - 1.0) * vec3(normalScale, normalScale, 1.0))); 200 | 201 | return n; 202 | #else 203 | // @TODO: Check if this is correct 204 | return normalize(fragNormal); 205 | #endif 206 | } 207 | 208 | vec3 specularReflection(PBRInfo pbrInputs) { 209 | return pbrInputs.reflectance0 210 | + (pbrInputs.reflectance90 - pbrInputs.reflectance0) 211 | * pow(clamp(1.0 - pbrInputs.VdotH, 0.0, 1.0), 5.0); 212 | } 213 | 214 | float geometricOcclusion(PBRInfo pbrInputs) { 215 | float NdotL = pbrInputs.NdotL; 216 | float NdotV = pbrInputs.NdotV; 217 | float r = pbrInputs.alphaRoughness; 218 | 219 | float attenuationL = 2.0 * NdotL / (NdotL + sqrt(r * r + (1.0 - r * r) * (NdotL * NdotL))); 220 | float attenuationV = 2.0 * NdotV / (NdotV + sqrt(r * r + (1.0 - r * r) * (NdotV * NdotV))); 221 | return attenuationL * attenuationV; 222 | } 223 | 224 | float microfacetDistribution(PBRInfo pbrInputs) { 225 | float roughnessSq = pbrInputs.alphaRoughness * pbrInputs.alphaRoughness; 226 | float f = (pbrInputs.NdotH * roughnessSq - pbrInputs.NdotH) * pbrInputs.NdotH + 1.0; 227 | return roughnessSq / (M_PI * f * f); 228 | } 229 | 230 | vec3 diffuse(PBRInfo pbrInputs) { 231 | return pbrInputs.diffuseColor / M_PI; 232 | } 233 | 234 | vec4 sRGBToLinear(in vec4 value) { 235 | return vec4(mix(pow(value.rgb * 0.9478672986 + vec3(0.0521327014), vec3(2.4)), value.rgb * 0.0773993808, vec3(lessThanEqual(value.rgb, vec3(0.04045)))), value.a); 236 | } 237 | 238 | vec4 LinearTosRGB(in vec4 value) { 239 | return vec4(mix(pow(value.rgb, vec3(0.41666)) * 1.055 - vec3(0.055), value.rgb * 12.92, vec3(lessThanEqual(value.rgb, vec3(0.0031308)))), value.a); 240 | } 241 | 242 | void main() { 243 | vec4 baseColor = vec4(uniforms.diffuse, uniforms.opacity); 244 | #ifdef USE_MAP 245 | vec4 texelColor = texture(sampler2D(map, mapSampler), fragUv); 246 | texelColor = sRGBToLinear(texelColor); 247 | baseColor *= texelColor; 248 | #endif 249 | float roughnessFactor = uniforms.roughness; 250 | #ifdef USE_ROUGHNESSMAP 251 | vec4 texelRoughness = texture(sampler2D(roughnessMap, roughnessMapSampler), fragUv); 252 | roughnessFactor *= texelRoughness.g; 253 | #endif 254 | roughnessFactor = clamp(roughnessFactor, 0.04, 1.0); 255 | float metalnessFactor = uniforms.metalness; 256 | #ifdef USE_METALNESSMAP 257 | vec4 texelMetalness = texture(sampler2D(metalnessMap, metalnessMapSampler), fragUv); 258 | metalnessFactor *= texelMetalness.b; 259 | #endif 260 | metalnessFactor = clamp(metalnessFactor, 0.0, 1.0); 261 | 262 | float alphaRoughness = roughnessFactor * roughnessFactor; 263 | 264 | vec3 f0 = vec3(0.04); 265 | vec3 diffuseColor = baseColor.rgb * (vec3(1.0) - f0); 266 | diffuseColor *= 1.0 - metalnessFactor; 267 | vec3 specularColor = mix(f0, baseColor.rgb, metalnessFactor); 268 | 269 | float reflectance = max(max(specularColor.r, specularColor.g), specularColor.b); 270 | float reflectance90 = clamp(reflectance * 25.0, 0.0, 1.0); 271 | vec3 specularEnvironmentR0 = specularColor.rgb; 272 | vec3 specularEnvironmentR90 = vec3(1.0) * reflectance90; 273 | 274 | vec3 camera = vec3(0.0, 0.0, 2.0); // @TODO: Should be from Camera object 275 | vec3 lightDirection = vec3(1.0, 2.0, 2.0); // @TODO: Should be from Light nodes 276 | vec3 n = getNormal(); 277 | vec3 v = normalize(camera - fragPosition); 278 | vec3 l = normalize(lightDirection); 279 | vec3 h = normalize(l + v); 280 | vec3 reflection = -normalize(reflect(v, n)); 281 | 282 | float NdotL = clamp(dot(n, l), 0.001, 1.0); 283 | float NdotV = clamp(abs(dot(n, v)), 0.001, 1.0); 284 | float NdotH = clamp(dot(n, h), 0.0, 1.0); 285 | float LdotH = clamp(dot(l, h), 0.0, 1.0); 286 | float VdotH = clamp(dot(v, h), 0.0, 1.0); 287 | 288 | PBRInfo pbrInputs = PBRInfo( 289 | NdotL, 290 | NdotV, 291 | NdotH, 292 | LdotH, 293 | VdotH, 294 | roughnessFactor, 295 | metalnessFactor, 296 | specularEnvironmentR0, 297 | specularEnvironmentR90, 298 | alphaRoughness, 299 | diffuseColor, 300 | specularColor 301 | ); 302 | 303 | vec3 F = specularReflection(pbrInputs); 304 | float G = geometricOcclusion(pbrInputs); 305 | float D = microfacetDistribution(pbrInputs); 306 | 307 | vec3 diffuseContrib = (1.0 - F) * diffuse(pbrInputs); 308 | vec3 specContrib = F * G * D / (4.0 * NdotL * NdotV); 309 | 310 | // @TODO: Should be configurable 311 | float lightIntensity = 2.0; 312 | vec3 lightColor = vec3(1.0) * lightIntensity; 313 | vec3 color = NdotL * lightColor * (diffuseContrib + specContrib); 314 | 315 | #ifdef USE_AOMAP 316 | float occlusionStrength = 1.0; 317 | float ao = texture(sampler2D(aoMap, aoMapSampler), fragUv).r; 318 | color = mix(color, color * ao, occlusionStrength); 319 | #endif 320 | 321 | vec3 totalEmissiveRadiance = uniforms.emissive; 322 | #ifdef USE_EMISSIVEMAP 323 | vec4 emissiveColor = texture(sampler2D(emissiveMap, emissiveMapSampler), fragUv); 324 | emissiveColor.rgb = sRGBToLinear(emissiveColor).rgb; 325 | totalEmissiveRadiance *= emissiveColor.rgb; 326 | #endif 327 | color += totalEmissiveRadiance; 328 | 329 | outColor = vec4(color, baseColor.a); 330 | outColor = LinearTosRGB(outColor); 331 | }` 332 | }; 333 | 334 | ShaderLibs.MeshBasicMaterial = { 335 | vertexUniforms: [], 336 | fragmentUniforms: [], 337 | textures: [{ 338 | name: 'map', 339 | format: 'texture', 340 | define: 'USE_MAP' 341 | }], 342 | vertexShaderCode: ` 343 | layout(set=0, binding=0) uniform Uniforms { 344 | mat4 modelMatrix; 345 | mat4 viewMatrix; 346 | mat4 projectionMatrix; 347 | mat3 normalMatrix; 348 | } uniforms; 349 | 350 | layout(location = 0) in vec3 position; 351 | layout(location = 1) in vec3 normal; 352 | layout(location = 2) in vec2 uv; 353 | 354 | layout(location = 0) out vec3 fragNormal; 355 | layout(location = 1) out vec2 fragUv; 356 | 357 | void main() { 358 | gl_Position = uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix * vec4(position, 1.0); 359 | fragUv = uv; 360 | fragNormal = normal; 361 | }`, 362 | fragmentShaderCode: ` 363 | layout(set=0, binding=1) uniform Uniforms { 364 | vec3 diffuse; 365 | float opacity; 366 | } uniforms; 367 | 368 | #ifdef USE_MAP 369 | layout(set=0, binding=MAP_BINDING) uniform sampler mapSampler; 370 | layout(set=0, binding=MAP_SAMPLER_BINDING) uniform texture2D map; 371 | #endif 372 | 373 | layout(location = 0) in vec3 fragNormal; 374 | layout(location = 1) in vec2 fragUv; 375 | layout(location = 0) out vec4 outColor; 376 | 377 | void main() { 378 | outColor = vec4(uniforms.diffuse, uniforms.opacity); 379 | #ifdef USE_MAP 380 | outColor *= texture(sampler2D(map, mapSampler), fragUv); 381 | #endif 382 | }` 383 | }; 384 | 385 | ShaderLibs.MeshNormalMaterial = { 386 | vertexUniforms: [], 387 | fragmentUniforms: [], 388 | textures: [], 389 | vertexShaderCode: ` 390 | layout(set=0, binding=0) uniform Uniforms { 391 | mat4 modelMatrix; 392 | mat4 viewMatrix; 393 | mat4 projectionMatrix; 394 | mat3 normalMatrix; 395 | } uniforms; 396 | 397 | layout(location = 0) in vec3 position; 398 | layout(location = 1) in vec3 normal; 399 | layout(location = 2) in vec2 uv; 400 | 401 | layout(location = 0) out vec3 fragNormal; 402 | layout(location = 1) out vec2 fragUv; 403 | 404 | void main() { 405 | gl_Position = uniforms.projectionMatrix * uniforms.viewMatrix * uniforms.modelMatrix * vec4(position, 1.0); 406 | fragUv = uv; 407 | fragNormal = normalize(uniforms.normalMatrix * normal); 408 | }`, 409 | fragmentShaderCode: ` 410 | layout(set=0, binding=1) uniform Uniforms { 411 | vec3 diffuse; 412 | float opacity; 413 | } uniforms; 414 | 415 | layout(location = 0) in vec3 fragNormal; 416 | layout(location = 1) in vec2 fragUv; 417 | layout(location = 0) out vec4 outColor; 418 | 419 | void main() { 420 | // "+ (normalize(fragNormal) * 0.5 + 0.5)" is to check each surface 421 | vec3 normal = normalize(fragNormal); 422 | outColor = vec4((normal * 0.5 + 0.5), uniforms.opacity); 423 | }` 424 | }; 425 | 426 | export default class WebGPURenderer { 427 | constructor(options={}) { 428 | if (!options.device || !options.glslang) { 429 | throw new Error('WebGPURenderer: the constructor must take device and glslang parameters.'); 430 | } 431 | 432 | this.domElement = document.createElement('canvas'); 433 | this.context = this.domElement.getContext('gpupresent'); 434 | 435 | this._device = options.device; 436 | this._glslang = options.glslang; 437 | 438 | this._projScreenMatrix = new Matrix4(); 439 | this._width = 640; 440 | this._height = 480; 441 | this._pixelRatio = 1.0; 442 | 443 | this._format = 'bgra8unorm'; 444 | this._sampleCount = 4; 445 | this._passEncoder = null; 446 | this._commandEncoder = null; 447 | this._colorAttachment = null; 448 | this._depthStencilAttachment = null; 449 | 450 | this._cache = { 451 | currentProgram: null 452 | }; 453 | 454 | this._verticesManager = new WebGPUVerticesManager(); 455 | this._indicesManager = new WebGPUIndicesManager(); 456 | this._uniformsManager = new WebGPUUniformsManager(); 457 | this._textureManager = new WebGPUTextureManager(); 458 | this._programManager = new WebGPUProgramManager(this._glslang, this._textureManager); 459 | this._swapChain = this.context.configureSwapChain({ 460 | device: this._device, 461 | format: this._format 462 | }); 463 | this._setSize(this._width, this._height, this._pixelRatio); 464 | } 465 | 466 | setSize(width, height) { 467 | this._setSize(width, height, this._pixelRatio); 468 | } 469 | 470 | setPixelRatio(pixelRatio) { 471 | this._setSize(this._width, this._height, pixelRatio); 472 | } 473 | 474 | /** 475 | * @param {Scene} scene 476 | * @param {Camera} camera 477 | */ 478 | render(scene, camera) { 479 | this._cache.currentProgram = null; 480 | 481 | scene.updateMatrixWorld(); 482 | if (!camera.parent) { 483 | camera.updateMatrixWorld(); 484 | } 485 | 486 | this._projScreenMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse); 487 | 488 | const renderList = []; 489 | this._projectObject(scene, camera, renderList); 490 | 491 | const opaqueObjects = []; 492 | const transparentObjects = []; 493 | for (const element of renderList) { 494 | if (element.object.material.transparent) { 495 | transparentObjects.push(element); 496 | } else { 497 | opaqueObjects.push(element); 498 | } 499 | } 500 | 501 | transparentObjects.sort(painterSort); 502 | opaqueObjects.sort(reversePainterSort); 503 | 504 | this._setup(); 505 | this._renderObjects(opaqueObjects, camera); 506 | this._renderObjects(transparentObjects, camera); 507 | this._finalize(); 508 | } 509 | 510 | _setSize(width, height, pixelRatio) { 511 | this._width = width; 512 | this._height = height; 513 | this._pixelRatio = pixelRatio; 514 | const canvas = this.domElement; 515 | canvas.width = Math.floor(this._width * this._pixelRatio); 516 | canvas.height = Math.floor(this._height * this._pixelRatio); 517 | canvas.style.width = this._width + 'px'; 518 | canvas.style.height = this._height + 'px'; 519 | const colorTexture = this._device.createTexture({ 520 | size: { 521 | width: Math.floor(this._width * this._pixelRatio), 522 | height: Math.floor(this._height * this._pixelRatio), 523 | depth: 1 524 | }, 525 | sampleCount: this._sampleCount, 526 | format: this._format, 527 | usage: GPUTextureUsage.OUTPUT_ATTACHMENT 528 | }); 529 | this._colorAttachment = colorTexture.createView(); 530 | const depthStencilTexture = this._device.createTexture({ 531 | size: { 532 | width: Math.floor(this._width * this._pixelRatio), 533 | height: Math.floor(this._height * this._pixelRatio), 534 | depth: 1 535 | }, 536 | sampleCount: this._sampleCount, 537 | format: "depth24plus-stencil8", 538 | usage: GPUTextureUsage.OUTPUT_ATTACHMENT 539 | }); 540 | this._depthStencilAttachment = depthStencilTexture.createView(); 541 | 542 | // I don't know why but seems necessary to render... @TODO: resolve 543 | if (canvas.parentElement) { 544 | canvas.parentElement.appendChild(canvas); 545 | } 546 | } 547 | 548 | _projectObject(object, camera, renderList) { 549 | if (!object.visible) { 550 | return; 551 | } 552 | if (object.isMesh) { 553 | if (object.material.visible) { 554 | const vector3 = new Vector3(); 555 | vector3.setFromMatrixPosition(object.matrixWorld) 556 | .applyMatrix4(this._projScreenMatrix); 557 | renderList.push({ 558 | object: object, 559 | z: vector3.z 560 | }); 561 | } 562 | } 563 | for (const child of object.children) { 564 | this._projectObject(child, camera, renderList); 565 | } 566 | } 567 | 568 | _setup() { 569 | this._commandEncoder = this._device.createCommandEncoder({}); 570 | 571 | const renderPassDescriptor = { 572 | colorAttachments: [{ 573 | attachment: this._colorAttachment, 574 | resolveTarget: this._swapChain.getCurrentTexture().createView(), 575 | loadValue: {r: 1.0, g: 1.0, b: 1.0, a: 1.0} 576 | }], 577 | depthStencilAttachment: { 578 | attachment: this._depthStencilAttachment, 579 | depthLoadValue: 1.0, 580 | depthStoreOp: 'store', 581 | stencilLoadValue: 0, 582 | stencilStoreOp: 'store', 583 | } 584 | }; 585 | 586 | this._passEncoder = this._commandEncoder.beginRenderPass(renderPassDescriptor); 587 | } 588 | 589 | _renderObjects(objects, camera) { 590 | for (const object of objects) { 591 | this._renderObject(object.object, camera); 592 | } 593 | } 594 | 595 | _renderObject(object, camera) { 596 | const program = this._programManager.get(object.material, this._device); 597 | 598 | if (this._cache.currentProgram !== program) { 599 | this._passEncoder.setPipeline(program.pipeline); 600 | this._cache.currentProgram = program; 601 | } 602 | 603 | const vertices = this._verticesManager.get(object.geometry, program, this._device); 604 | const uniforms = this._uniformsManager.get(object, camera, program, this._device); 605 | const indexAttribute = object.geometry.getIndex(); 606 | 607 | this._passEncoder.setVertexBuffer(0, vertices.buffer); 608 | this._passEncoder.setBindGroup(0, uniforms.bindGroup); 609 | 610 | if (indexAttribute) { 611 | const indices = this._indicesManager.get(object.geometry, this._device); 612 | this._passEncoder.setIndexBuffer(indices.buffer); 613 | const indexCount = indexAttribute.array.length; 614 | this._passEncoder.drawIndexed(indexCount, 1, 0, 0, 0); 615 | } else { 616 | const vertexCount = object.geometry.getAttribute('position').array.length; 617 | this._passEncoder.draw(vertexCount, 1, 0, 0); 618 | } 619 | } 620 | 621 | _finalize() { 622 | this._passEncoder.endPass(); 623 | this._device.defaultQueue.submit([this._commandEncoder.finish()]); 624 | } 625 | } 626 | 627 | class WebGPUProgramManager { 628 | constructor(glslang, textureManager) { 629 | this.glslang = glslang; 630 | this.textureManager = textureManager; 631 | this.map = new Map(); // material -> program 632 | this.map2 = new Map(); // material type key -> program 633 | } 634 | 635 | get(material, device) { 636 | if (!this.map.has(material)) { 637 | // @TODO: Create key more properly 638 | const key = material.type + ':' + [ 639 | !!material.map, 640 | !!material.emissiveMap, 641 | !!material.normalMap, 642 | !!material.roughnessMap, 643 | !!material.metalnessMap, 644 | !!material.aoMap 645 | ].join(':'); 646 | if (!this.map2.has(key)) { 647 | this.map2.set(key, new WebGPUProgram( 648 | this.glslang, 649 | material, 650 | this.textureManager, 651 | device 652 | )); 653 | } 654 | this.map.set(material, this.map2.get(key)); 655 | } 656 | return this.map.get(material); 657 | } 658 | } 659 | 660 | class WebGPUProgram { 661 | constructor(glslang, material, textureManager, device) { 662 | this.textureManager = textureManager; 663 | const shader = ShaderLibs[material.type]; 664 | 665 | if (!shader) { 666 | throw new Error('This type of material is not supported yet. ' + key); 667 | } 668 | 669 | const entries = [{ 670 | binding: 0, 671 | visibility: GPUShaderStage.VERTEX, 672 | type: 'uniform-buffer' 673 | }, { 674 | binding: 1, 675 | visibility: GPUShaderStage.FRAGMENT, 676 | type: 'uniform-buffer' 677 | }]; 678 | 679 | let binding = 2; 680 | const defines = []; 681 | for (const definition of shader.textures) { 682 | switch (definition.name) { 683 | case 'map': 684 | if (!material.map) { 685 | continue; 686 | } 687 | break; 688 | case 'emissiveMap': 689 | if (!material.emissiveMap) { 690 | continue; 691 | } 692 | break; 693 | case 'normalMap': 694 | if (!material.normalMap) { 695 | continue; 696 | } 697 | break; 698 | case 'roughnessMap': 699 | if (!material.roughnessMap) { 700 | continue; 701 | } 702 | break; 703 | case 'metalnessMap': 704 | if (!material.metalnessMap) { 705 | continue; 706 | } 707 | break; 708 | case 'aoMap': 709 | if (!material.aoMap) { 710 | continue; 711 | } 712 | break; 713 | default: 714 | console.error('Unknown texture ' + definition.name); 715 | continue; 716 | } 717 | entries.push({ 718 | binding: binding, 719 | visibility: GPUShaderStage.FRAGMENT, 720 | type: 'sampler' 721 | }); 722 | entries.push({ 723 | binding: binding + 1, 724 | visibility: GPUShaderStage.FRAGMENT, 725 | type: 'sampled-texture' 726 | }); 727 | if (definition.define) { 728 | defines.push('#define ' + definition.define); 729 | defines.push('#define ' + definition.name.toUpperCase() + '_BINDING ' + binding); 730 | defines.push('#define ' + definition.name.toUpperCase() + '_SAMPLER_BINDING ' + (binding + 1)); 731 | } 732 | binding += 2; 733 | } 734 | 735 | const vertexShaderCode = '#version 450\n' + 736 | defines.join('\n') + '\n' + 737 | shader.vertexShaderCode; 738 | 739 | const fragmentShaderCode = '#version 450\n' + 740 | defines.join('\n') + '\n' + 741 | shader.fragmentShaderCode; 742 | 743 | this.uniformGroupLayout = device.createBindGroupLayout({ 744 | entries: entries, 745 | }); 746 | 747 | this.pipeline = device.createRenderPipeline({ 748 | layout: device.createPipelineLayout({bindGroupLayouts: [this.uniformGroupLayout]}), 749 | vertexStage: { 750 | module: device.createShaderModule({ 751 | code: glslang.compileGLSL(vertexShaderCode, 'vertex'), 752 | source: vertexShaderCode, 753 | transform: source => glslang.compileGLSL(source, 'vertex') 754 | }), 755 | entryPoint: 'main' 756 | }, 757 | fragmentStage: { 758 | module: device.createShaderModule({ 759 | code: glslang.compileGLSL(fragmentShaderCode, 'fragment'), 760 | source: fragmentShaderCode, 761 | transform: source => glslang.compileGLSL(source, 'fragment') 762 | }), 763 | entryPoint: 'main' 764 | }, 765 | primitiveTopology: 'triangle-list', 766 | depthStencilState: { 767 | depthWriteEnabled: true, 768 | depthCompare: 'less', 769 | format: 'depth24plus-stencil8' 770 | }, 771 | vertexState: this._createVertexState(), 772 | colorStates: [{ 773 | format: 'bgra8unorm', 774 | colorBlend: { 775 | srcFactor: 'src-alpha', 776 | dstFactor: 'one-minus-src-alpha', 777 | operation: 'add' 778 | } 779 | }], 780 | sampleCount: 4 // @TODO: Should be configurable 781 | }); 782 | } 783 | 784 | _createVertexState() { 785 | let offset = 0; 786 | const attributes = []; 787 | for (let i = 0; i < defaultAttributeDefinitions.length; i++) { 788 | const definition = defaultAttributeDefinitions[i]; 789 | attributes.push({ 790 | shaderLocation: i, 791 | offset: offset, 792 | format: definition.format 793 | }); 794 | offset += offsetTable[definition.format]; 795 | } 796 | 797 | return { 798 | indexFormat: 'uint16', // @TODO: Should be configurable 799 | vertexBuffers: [{ 800 | arrayStride: offset, 801 | attributes: attributes 802 | }] 803 | }; 804 | } 805 | 806 | createVertices(geometry, device) { 807 | let itemSize = 0; 808 | for (const definition of defaultAttributeDefinitions) { 809 | itemSize += offsetTable[definition.format]; 810 | } 811 | const position = geometry.getAttribute('position'); 812 | return new WebGPUVertices(new Float32Array(itemSize * position.count), device); 813 | } 814 | 815 | createUniforms(device, material) { 816 | const buffers = this._createUniformBuffers(material, device); 817 | const textures = this._createUniformTextures(material, device); 818 | const bindGroup = this._createUniformBindGroup(buffers, textures, device); 819 | return new WebGPUUniforms(buffers, bindGroup); 820 | } 821 | 822 | _createUniformBuffers(material, device) { 823 | const shader = ShaderLibs[material.type]; 824 | 825 | let vertexUniformsSize = 0; 826 | for (const definition of defaultVertexUniformsDefinitions) { 827 | vertexUniformsSize += offsetTable[definition.format]; 828 | } 829 | for (const definition of shader.vertexUniforms) { 830 | vertexUniformsSize += offsetTable[definition.format]; 831 | } 832 | 833 | let fragmentUniformsSize = 0; 834 | for (const definition of defaultFragmentUniformsDefinitions) { 835 | fragmentUniformsSize += offsetTable[definition.format]; 836 | } 837 | for (const definition of shader.fragmentUniforms) { 838 | fragmentUniformsSize += offsetTable[definition.format]; 839 | } 840 | 841 | const buffers = []; 842 | buffers.push(new WebGPUUniformBuffer(vertexUniformsSize, device)); // vertex 843 | buffers.push(new WebGPUUniformBuffer(fragmentUniformsSize, device)); // fragment 844 | return buffers; 845 | } 846 | 847 | _createUniformTextures(material, device) { 848 | const textures = []; 849 | for (const definition of ShaderLibs[material.type].textures) { 850 | switch (definition.name) { 851 | case 'map': 852 | if (material.map) { 853 | textures.push(this.textureManager.get(material.map, device)); 854 | } 855 | break; 856 | case 'emissiveMap': 857 | if (material.emissiveMap) { 858 | textures.push(this.textureManager.get(material.emissiveMap, device)); 859 | } 860 | break; 861 | case 'normalMap': 862 | if (material.normalMap) { 863 | textures.push(this.textureManager.get(material.normalMap, device)); 864 | } 865 | break; 866 | case 'roughnessMap': 867 | if (material.roughnessMap) { 868 | textures.push(this.textureManager.get(material.roughnessMap, device)); 869 | } 870 | break; 871 | case 'metalnessMap': 872 | if (material.metalnessMap) { 873 | textures.push(this.textureManager.get(material.metalnessMap, device)); 874 | } 875 | break; 876 | case 'aoMap': 877 | if (material.aoMap) { 878 | textures.push(this.textureManager.get(material.aoMap, device)); 879 | } 880 | break; 881 | default: 882 | console.error('Unknown texture ' + definition.name); 883 | continue; 884 | } 885 | } 886 | return textures; 887 | } 888 | 889 | _createUniformBindGroup(buffers, textures, device) { 890 | const entries = []; 891 | for (let i = 0; i < buffers.length; i++) { 892 | const buffer = buffers[i]; 893 | entries.push({ 894 | binding: i, 895 | resource: { 896 | buffer: buffer.buffer, 897 | size: buffer.byteLength 898 | } 899 | }); 900 | } 901 | for (let i = 0; i < textures.length; i++) { 902 | entries.push({ 903 | binding: entries.length, 904 | resource: textures[i].sampler.sampler 905 | }); 906 | entries.push({ 907 | binding: entries.length, 908 | resource: textures[i].texture.createView() 909 | }); 910 | } 911 | return device.createBindGroup({ 912 | layout: this.uniformGroupLayout, 913 | entries: entries 914 | }); 915 | } 916 | } 917 | 918 | class WebGPUUniformsManager { 919 | constructor() { 920 | this.map = new Map(); 921 | } 922 | 923 | get(object, camera, program, device) { 924 | if (!this.map.has(object)) { 925 | this.map.set(object, program.createUniforms(device, object.material)); 926 | } 927 | const uniforms = this.map.get(object); 928 | uniforms.update(object, camera, device); 929 | return uniforms; 930 | } 931 | } 932 | 933 | class WebGPUUniforms { 934 | constructor(buffers, bindGroup) { 935 | this.buffers = buffers; 936 | this.bindGroup = bindGroup; 937 | } 938 | 939 | update(object, camera, device) { 940 | object.modelViewMatrix.multiplyMatrices(camera.matrixWorldInverse, object.matrixWorld); 941 | object.normalMatrix.getNormalMatrix(object.modelViewMatrix); 942 | 943 | const shader = ShaderLibs[object.material.type]; 944 | 945 | // for vertex shader 946 | let offset = 0; 947 | const vertexUniformsBuffer = this.buffers[0]; 948 | for (const definition of defaultVertexUniformsDefinitions) { 949 | let value; 950 | switch (definition.name) { 951 | case 'modelMatrix': 952 | value = object.matrixWorld; 953 | break; 954 | case 'viewMatrix': 955 | value = camera.matrixWorldInverse; 956 | break; 957 | case 'projectionMatrix': 958 | value = camera.projectionMatrix; 959 | break; 960 | case 'normalMatrix': 961 | value = object.normalMatrix; 962 | break; 963 | default: 964 | console.error('Unknown uniform ' + definition.name); 965 | continue; 966 | } 967 | if (value) { 968 | this._updateData(vertexUniformsBuffer, definition.format, offset, value); 969 | } 970 | offset += offsetTable[definition.format]; 971 | } 972 | vertexUniformsBuffer.upload(device); 973 | 974 | // for fragment shader 975 | offset = 0; 976 | const fragmentUniformsBuffer = this.buffers[1]; 977 | for (const definition of defaultFragmentUniformsDefinitions) { 978 | let value; 979 | switch (definition.name) { 980 | case 'diffuse': 981 | value = object.material.color; 982 | break; 983 | case 'opacity': 984 | value = object.material.opacity; 985 | break; 986 | default: 987 | console.error('Unknown uniform ' + definition.name); 988 | continue; 989 | } 990 | if (value !== undefined && value !== null) { 991 | this._updateData(fragmentUniformsBuffer, definition.format, offset, value); 992 | } 993 | offset += offsetTable[definition.format]; 994 | } 995 | 996 | for (const definition of shader.fragmentUniforms) { 997 | let value; 998 | switch (definition.name) { 999 | case 'emissive': 1000 | value = object.material.emissive; 1001 | break; 1002 | case 'roughness': 1003 | value = object.material.roughness; 1004 | break; 1005 | case 'metalness': 1006 | value = object.material.metalness; 1007 | break; 1008 | default: 1009 | console.error('Unknown uniform ' + definition.name); 1010 | continue; 1011 | } 1012 | if (value !== undefined && value !== null) { 1013 | this._updateData(fragmentUniformsBuffer, definition.format, offset, value); 1014 | } 1015 | offset += offsetTable[definition.format]; 1016 | } 1017 | fragmentUniformsBuffer.upload(device); 1018 | } 1019 | 1020 | _updateData(buffer, format, offset, value) { 1021 | switch (format) { 1022 | case 'float': 1023 | buffer.updateFloat(offset, value); 1024 | break; 1025 | case 'float3': 1026 | buffer.updateVector3(offset, value); 1027 | break; 1028 | case 'color': 1029 | buffer.updateColor(offset, value); 1030 | break; 1031 | case 'matrix3': 1032 | buffer.updateMatrix3(offset, value); 1033 | break; 1034 | case 'matrix4': 1035 | buffer.updateMatrix4(offset, value); 1036 | break; 1037 | default: 1038 | console.error('Unknown format ' + format); 1039 | break; 1040 | } 1041 | } 1042 | } 1043 | 1044 | class WebGPUUniformBuffer { 1045 | constructor(byteLength, device) { 1046 | this.buffer = device.createBuffer({ 1047 | size: byteLength, 1048 | usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST, 1049 | }); 1050 | this.byteLength = byteLength; 1051 | const arrayBuffer = new ArrayBuffer(byteLength); 1052 | this.float32Array = new Float32Array(arrayBuffer); 1053 | } 1054 | 1055 | upload(device) { 1056 | device.defaultQueue.writeBuffer(this.buffer, 0, this.float32Array.buffer); 1057 | } 1058 | 1059 | updateMatrix4(offset, matrix4) { 1060 | const index = offset / 4; 1061 | for (let i = 0; i < 16; i++) { 1062 | this.float32Array[index + i] = matrix4.elements[i]; 1063 | } 1064 | } 1065 | 1066 | updateMatrix3(offset, matrix3) { 1067 | const index = offset / 4; 1068 | this.float32Array[index + 0] = matrix3.elements[0]; 1069 | this.float32Array[index + 1] = matrix3.elements[1]; 1070 | this.float32Array[index + 2] = matrix3.elements[2]; 1071 | this.float32Array[index + 4] = matrix3.elements[3]; 1072 | this.float32Array[index + 5] = matrix3.elements[4]; 1073 | this.float32Array[index + 6] = matrix3.elements[5]; 1074 | this.float32Array[index + 8] = matrix3.elements[6]; 1075 | this.float32Array[index + 9] = matrix3.elements[7]; 1076 | this.float32Array[index + 10] = matrix3.elements[8]; 1077 | } 1078 | 1079 | updateVector3(offset, vec3) { 1080 | const index = offset / 4; 1081 | this.float32Array[index] = vec3.x; 1082 | this.float32Array[index + 1] = vec3.y; 1083 | this.float32Array[index + 2] = vec3.z; 1084 | } 1085 | 1086 | updateColor(offset, color) { 1087 | const index = offset / 4; 1088 | this.float32Array[index] = color.r; 1089 | this.float32Array[index + 1] = color.g; 1090 | this.float32Array[index + 2] = color.b; 1091 | } 1092 | 1093 | updateFloat(offset, value) { 1094 | this.float32Array[offset / 4] = value; 1095 | } 1096 | } 1097 | 1098 | class WebGPUUniformSampler { 1099 | constructor(device) { 1100 | // @TODO: Should be configurable 1101 | this.sampler = device.createSampler({ 1102 | addressModeU: 'repeat', 1103 | addressModeV: 'repeat', 1104 | magFilter: 'linear', 1105 | minFilter: 'linear' 1106 | }); 1107 | } 1108 | } 1109 | 1110 | class WebGPUTextureManager { 1111 | constructor() { 1112 | this.map = new Map(); 1113 | } 1114 | 1115 | get(texture, device) { 1116 | if (!this.map.has(texture)) { 1117 | const image = texture.image; 1118 | const webgpuTexture = new WebGPUTexture(image.width, image.height, device); 1119 | webgpuTexture.upload(image, device); 1120 | this.map.set(texture, webgpuTexture); 1121 | } 1122 | return this.map.get(texture); 1123 | } 1124 | } 1125 | 1126 | class WebGPUTexture { 1127 | constructor(width, height, device) { 1128 | this.width = width; 1129 | this.height = height; 1130 | this.sampler = new WebGPUUniformSampler(device); 1131 | 1132 | this.texture = device.createTexture({ 1133 | size: { 1134 | width: this.width, 1135 | height: this.height, 1136 | depth: 1 1137 | }, 1138 | format: 'rgba8unorm', 1139 | usage: GPUTextureUsage.SAMPLED | GPUTextureUsage.COPY_DST 1140 | }); 1141 | 1142 | this.buffer = device.createBuffer({ 1143 | size: this.width * this.height * 4, 1144 | usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC 1145 | }); 1146 | } 1147 | 1148 | upload(image, device) { 1149 | const canvas = document.createElement('canvas'); 1150 | canvas.width = this.width; 1151 | canvas.height = this.height; 1152 | const context = canvas.getContext('2d'); 1153 | context.drawImage(image, 0, 0); 1154 | const imageData = context.getImageData(0, 0, this.width, this.height); 1155 | device.defaultQueue.writeBuffer(this.buffer, 0, imageData.data.buffer); 1156 | 1157 | const encoder = device.createCommandEncoder({}); 1158 | encoder.copyBufferToTexture({ 1159 | buffer: this.buffer, 1160 | bytesPerRow: this.width * 4, 1161 | rowsPerImage: 0 1162 | }, { 1163 | texture: this.texture 1164 | }, { 1165 | width: this.width, 1166 | height: this.height, 1167 | depth: 1 1168 | }); 1169 | 1170 | device.defaultQueue.submit([encoder.finish()]); 1171 | } 1172 | } 1173 | 1174 | class WebGPUVerticesManager { 1175 | constructor() { 1176 | this.map = new Map(); 1177 | } 1178 | 1179 | get(geometry, program, device) { 1180 | if (!this.map.has(geometry)) { 1181 | const vertices = program.createVertices(geometry, device); 1182 | vertices.update(geometry); 1183 | vertices.upload(device); 1184 | this.map.set(geometry, vertices); 1185 | } 1186 | return this.map.get(geometry); 1187 | } 1188 | } 1189 | 1190 | class WebGPUVertices { 1191 | constructor(array, device) { 1192 | this.array = array; 1193 | this.buffer = device.createBuffer({ 1194 | size: this.array.byteLength, 1195 | usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST 1196 | }); 1197 | } 1198 | 1199 | update(geometry) { 1200 | const position = geometry.getAttribute('position'); 1201 | 1202 | // @TODO: Remove this temporal workaround 1203 | if (!geometry.getAttribute('uv')) { 1204 | geometry.setAttribute('uv', new BufferAttribute(new Float32Array(position.count * 2), 2)); 1205 | } 1206 | const uv = geometry.getAttribute('uv'); 1207 | 1208 | let dataIndex = 0; 1209 | const indices = {}; 1210 | for (const definition of defaultAttributeDefinitions) { 1211 | indices[definition.name] = 0; 1212 | } 1213 | for (let i = 0; i < position.count; i++) { 1214 | for (const definition of defaultAttributeDefinitions) { 1215 | const attribute = geometry.getAttribute(definition.name); 1216 | for (let j = 0; j < attribute.itemSize; j++) { 1217 | this.array[dataIndex++] = attribute.array[indices[definition.name]++]; 1218 | } 1219 | } 1220 | } 1221 | } 1222 | 1223 | upload(device) { 1224 | device.defaultQueue.writeBuffer(this.buffer, 0, this.array.buffer); 1225 | } 1226 | } 1227 | 1228 | class WebGPUIndicesManager { 1229 | constructor() { 1230 | this.map = new Map(); 1231 | } 1232 | 1233 | get(geometry, device) { 1234 | if (!this.map.has(geometry)) { 1235 | const indices = new WebGPUIndices( 1236 | // Buffer subdata size must be a multiple of 4 bytes 1237 | new Uint16Array(Math.floor((geometry.getIndex().array.byteLength + 3) / 4) * 4), 1238 | device 1239 | ); 1240 | indices.update(geometry); 1241 | indices.upload(device); 1242 | this.map.set(geometry, indices); 1243 | } 1244 | return this.map.get(geometry); 1245 | } 1246 | } 1247 | 1248 | class WebGPUIndices { 1249 | constructor(array, device) { 1250 | this.array = array; 1251 | this.buffer = device.createBuffer({ 1252 | size: this.array.byteLength, 1253 | usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST 1254 | }); 1255 | } 1256 | 1257 | update(geometry) { 1258 | const index = geometry.getIndex(); 1259 | for (let i = 0; i < index.array.length; i++) { 1260 | this.array[i] = index.array[i]; 1261 | } 1262 | } 1263 | 1264 | upload(device) { 1265 | device.defaultQueue.writeBuffer(this.buffer, 0, this.array.buffer); 1266 | } 1267 | } 1268 | --------------------------------------------------------------------------------