├── 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 |
--------------------------------------------------------------------------------