@woosh/meep-engine 2.33.60 → 2.33.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/core/geom/3d/SurfacePoint3.js +44 -5
  2. package/core/geom/Vector2.d.ts +2 -0
  3. package/core/geom/packing/MaxRectangles.js +13 -4
  4. package/core/math/hash/murmur3_32.js +3 -3
  5. package/engine/asset/loaders/material/computeTextureHash.js +7 -13
  6. package/engine/ecs/attachment/AttachmentSystem.js +18 -17
  7. package/engine/ecs/grid/HeightMap2NormalMap.js +1 -1
  8. package/engine/ecs/grid/NormalMap2AOMap.js +1 -1
  9. package/engine/ecs/gui/position/ViewportPositionSystem.js +5 -5
  10. package/engine/ecs/parent/EntityNode.d.ts +20 -0
  11. package/engine/ecs/parent/EntityNode.js +284 -0
  12. package/engine/ecs/parent/FaceEditor.js +137 -0
  13. package/engine/ecs/parent/testCompositionEntityNode.js +153 -0
  14. package/engine/ecs/parent/testHuDPerf.js +123 -0
  15. package/engine/ecs/terrain/ecs/Terrain.js +14 -5
  16. package/engine/graphics/GraphicsEngine.js +1 -2
  17. package/engine/graphics/camera/testClippingPlaneComputation.js +0 -4
  18. package/engine/graphics/ecs/light/LightSystem.js +1 -1
  19. package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +29 -0
  20. package/engine/graphics/ecs/mesh-v2/ShadedGeometrySystem.js +158 -1
  21. package/engine/graphics/ecs/path/testPathDisplaySystem.js +0 -2
  22. package/engine/graphics/geometry/buffered/query/GeometrySpatialQueryAccelerator.js +55 -11
  23. package/engine/graphics/micron/render/v1/MaterialContext.js +1 -0
  24. package/engine/graphics/particles/particular/engine/simulator/SimulationStepFixedPhysics.js +19 -3
  25. package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +0 -2
  26. package/engine/graphics/render/buffer/buffers/prototypeNormalFrameBuffer.js +0 -2
  27. package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +0 -2
  28. package/engine/graphics/render/frame_graph/FrameGraphBuilder.js +36 -0
  29. package/engine/graphics/render/frame_graph/IRenderContext.js +8 -0
  30. package/engine/graphics/render/frame_graph/RenderPass.js +32 -0
  31. package/engine/graphics/render/frame_graph/RenderPassFlags.js +6 -0
  32. package/engine/graphics/render/frame_graph/RenderPassResources.js +15 -0
  33. package/engine/graphics/render/frame_graph/Resource.js +21 -0
  34. package/engine/graphics/render/frame_graph/ResourceReference.js +14 -0
  35. package/engine/graphics/render/frame_graph/TextureDescriptor.js +30 -0
  36. package/engine/graphics/render/frame_graph/UsageModeType.js +5 -0
  37. package/engine/graphics/render/frame_graph/sample/deferred/GBufferDrawPass.js +27 -0
  38. package/engine/graphics/render/frame_graph/sample/deferred/PresentPass.js +17 -0
  39. package/engine/graphics/render/visibility/hiz/prototypeHiZ.js +0 -2
  40. package/engine/graphics/render/webgpu/sample/_main.ts +650 -0
  41. package/engine/graphics/render/webgpu/sample/fragmentDeferredRendering.wgsl +67 -0
  42. package/engine/graphics/render/webgpu/sample/fragmentGBuffersDebugView.wgsl +38 -0
  43. package/engine/graphics/render/webgpu/sample/fragmentWriteGBuffers.wgsl +21 -0
  44. package/engine/graphics/render/webgpu/sample/lightUpdate.wgsl +34 -0
  45. package/engine/graphics/render/webgpu/sample/main.js +566 -0
  46. package/engine/graphics/render/webgpu/sample/vertexTextureQuad.wgsl +9 -0
  47. package/engine/graphics/render/webgpu/sample/vertexWriteGBuffers.wgsl +28 -0
  48. package/engine/graphics/shadows/testShadowMapRendering.js +0 -2
  49. package/engine/{ecs/grid → graphics/texture/sampler}/sampler2DToFloat32Texture.js +1 -1
  50. package/package.json +1 -1
  51. package/samples/terrain/main.js +117 -0
  52. package/engine/ecs/sockets/AttachmentSocketsSystem.js +0 -10
@@ -0,0 +1,38 @@
1
+ [[group(0), binding(0)]] var gBufferPosition: texture_2d<f32>;
2
+ [[group(0), binding(1)]] var gBufferNormal: texture_2d<f32>;
3
+ [[group(0), binding(2)]] var gBufferAlbedo: texture_2d<f32>;
4
+
5
+ [[block]] struct CanvasConstants {
6
+ size: vec2<f32>;
7
+ };
8
+ [[group(1), binding(0)]] var<uniform> canvas : CanvasConstants;
9
+
10
+ [[stage(fragment)]]
11
+ fn main([[builtin(position)]] coord : vec4<f32>)
12
+ -> [[location(0)]] vec4<f32> {
13
+ var result : vec4<f32>;
14
+ let c = coord.xy / canvas.size;
15
+ if (c.x < 0.33333) {
16
+ result = textureLoad(
17
+ gBufferPosition,
18
+ vec2<i32>(floor(coord.xy)),
19
+ 0
20
+ );
21
+ } elseif (c.x < 0.66667) {
22
+ result = textureLoad(
23
+ gBufferNormal,
24
+ vec2<i32>(floor(coord.xy)),
25
+ 0
26
+ );
27
+ result.x = (result.x + 1.0) * 0.5;
28
+ result.y = (result.y + 1.0) * 0.5;
29
+ result.z = (result.z + 1.0) * 0.5;
30
+ } else {
31
+ result = textureLoad(
32
+ gBufferAlbedo,
33
+ vec2<i32>(floor(coord.xy)),
34
+ 0
35
+ );
36
+ }
37
+ return result;
38
+ }
@@ -0,0 +1,21 @@
1
+ struct GBufferOutput {
2
+ [[location(0)]] position : vec4<f32>;
3
+ [[location(1)]] normal : vec4<f32>;
4
+
5
+ // Textures: diffuse color, specular color, smoothness, emissive etc. could go here
6
+ [[location(2)]] albedo : vec4<f32>;
7
+ };
8
+
9
+ [[stage(fragment)]]
10
+ fn main([[location(0)]] fragPosition: vec3<f32>,
11
+ [[location(1)]] fragNormal: vec3<f32>,
12
+ [[location(2)]] fragUV : vec2<f32>) -> GBufferOutput {
13
+ var output : GBufferOutput;
14
+ output.position = vec4<f32>(fragPosition, 1.0);
15
+ output.normal = vec4<f32>(fragNormal, 1.0);
16
+ // faking some kind of checkerboard texture
17
+ let uv = floor(30.0 * fragUV);
18
+ let c = 0.2 + 0.5 * ((uv.x + uv.y) - 2.0 * floor((uv.x + uv.y) / 2.0));
19
+ output.albedo = vec4<f32>(c, c, c, 1.0);
20
+ return output;
21
+ }
@@ -0,0 +1,34 @@
1
+ struct LightData {
2
+ position : vec4<f32>;
3
+ color : vec3<f32>;
4
+ radius : f32;
5
+ };
6
+ [[block]] struct LightsBuffer {
7
+ lights: array<LightData>;
8
+ };
9
+ [[group(0), binding(0)]] var<storage, read_write> lightsBuffer: LightsBuffer;
10
+
11
+ [[block]] struct Config {
12
+ numLights : u32;
13
+ };
14
+ [[group(0), binding(1)]] var<uniform> config: Config;
15
+
16
+ [[block]] struct LightExtent {
17
+ min : vec4<f32>;
18
+ max : vec4<f32>;
19
+ };
20
+ [[group(0), binding(2)]] var<uniform> lightExtent: LightExtent;
21
+
22
+ [[stage(compute), workgroup_size(64, 1, 1)]]
23
+ fn main([[builtin(global_invocation_id)]] GlobalInvocationID : vec3<u32>) {
24
+ var index = GlobalInvocationID.x;
25
+ if (index >= config.numLights) {
26
+ return;
27
+ }
28
+
29
+ lightsBuffer.lights[index].position.y = lightsBuffer.lights[index].position.y - 0.5 - 0.003 * (f32(index) - 64.0 * floor(f32(index) / 64.0));
30
+
31
+ if (lightsBuffer.lights[index].position.y < lightExtent.min.y) {
32
+ lightsBuffer.lights[index].position.y = lightExtent.max.y;
33
+ }
34
+ }
@@ -0,0 +1,566 @@
1
+ import { mat4, vec3, vec4 } from 'gl-matrix';
2
+ import lightUpdate from './lightUpdate.wgsl';
3
+ import vertexWriteGBuffers from './vertexWriteGBuffers.wgsl';
4
+ import fragmentWriteGBuffers from './fragmentWriteGBuffers.wgsl';
5
+ import vertexTextureQuad from './vertexTextureQuad.wgsl';
6
+ import fragmentGBuffersDebugView from './fragmentGBuffersDebugView.wgsl';
7
+ import fragmentDeferredRendering from './fragmentDeferredRendering.wgsl';
8
+ import { GUI } from "dat.gui";
9
+
10
+ const kMaxNumLights = 1024;
11
+ const lightExtentMin = vec3.fromValues(-50, -30, -50);
12
+ const lightExtentMax = vec3.fromValues(50, 50, 50);
13
+ const mesh = [];
14
+
15
+ const init = async ({ canvasRef, gui }) => {
16
+ const adapter = await navigator.gpu.requestAdapter();
17
+ const device = await adapter.requestDevice();
18
+ if (canvasRef.current === null)
19
+ return;
20
+ const context = canvasRef.current.getContext('webgpu');
21
+ const devicePixelRatio = window.devicePixelRatio || 1;
22
+ const presentationSize = [
23
+ canvasRef.current.clientWidth * devicePixelRatio,
24
+ canvasRef.current.clientHeight * devicePixelRatio,
25
+ ];
26
+ const aspect = presentationSize[0] / presentationSize[1];
27
+ const presentationFormat = context.getPreferredFormat(adapter);
28
+ context.configure({
29
+ device,
30
+ format: presentationFormat,
31
+ size: presentationSize,
32
+ });
33
+ // Create the model vertex buffer.
34
+ const kVertexStride = 8;
35
+ const vertexBuffer = device.createBuffer({
36
+ // position: vec3, normal: vec3, uv: vec2
37
+ size: mesh.positions.length * kVertexStride * Float32Array.BYTES_PER_ELEMENT,
38
+ usage: GPUBufferUsage.VERTEX,
39
+ mappedAtCreation: true,
40
+ });
41
+ {
42
+ const mapping = new Float32Array(vertexBuffer.getMappedRange());
43
+ for (let i = 0; i < mesh.positions.length; ++i) {
44
+ mapping.set(mesh.positions[i], kVertexStride * i);
45
+ mapping.set(mesh.normals[i], kVertexStride * i + 3);
46
+ mapping.set(mesh.uvs[i], kVertexStride * i + 6);
47
+ }
48
+ vertexBuffer.unmap();
49
+ }
50
+ // Create the model index buffer.
51
+ const indexCount = mesh.triangles.length * 3;
52
+ const indexBuffer = device.createBuffer({
53
+ size: indexCount * Uint16Array.BYTES_PER_ELEMENT,
54
+ usage: GPUBufferUsage.INDEX,
55
+ mappedAtCreation: true,
56
+ });
57
+ {
58
+ const mapping = new Uint16Array(indexBuffer.getMappedRange());
59
+ for (let i = 0; i < mesh.triangles.length; ++i) {
60
+ mapping.set(mesh.triangles[i], 3 * i);
61
+ }
62
+ indexBuffer.unmap();
63
+ }
64
+ // GBuffer texture render targets
65
+ const gBufferTexture2DFloat = device.createTexture({
66
+ size: [...presentationSize, 3],
67
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
68
+ format: 'rgba32float',
69
+ });
70
+ const gBufferTextureAlbedo = device.createTexture({
71
+ size: presentationSize,
72
+ usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.TEXTURE_BINDING,
73
+ format: 'bgra8unorm',
74
+ });
75
+ const gBufferTextureViews = [
76
+ gBufferTexture2DFloat.createView({ baseArrayLayer: 0, arrayLayerCount: 1 }),
77
+ gBufferTexture2DFloat.createView({ baseArrayLayer: 1, arrayLayerCount: 1 }),
78
+ gBufferTextureAlbedo.createView(),
79
+ ];
80
+ const vertexBuffers = [
81
+ {
82
+ arrayStride: Float32Array.BYTES_PER_ELEMENT * 8,
83
+ attributes: [
84
+ {
85
+ // position
86
+ shaderLocation: 0,
87
+ offset: 0,
88
+ format: 'float32x3',
89
+ },
90
+ {
91
+ // normal
92
+ shaderLocation: 1,
93
+ offset: Float32Array.BYTES_PER_ELEMENT * 3,
94
+ format: 'float32x3',
95
+ },
96
+ {
97
+ // uv
98
+ shaderLocation: 2,
99
+ offset: Float32Array.BYTES_PER_ELEMENT * 6,
100
+ format: 'float32x2',
101
+ },
102
+ ],
103
+ },
104
+ ];
105
+ const primitive = {
106
+ topology: 'triangle-list',
107
+ cullMode: 'back',
108
+ };
109
+ const writeGBuffersPipeline = device.createRenderPipeline({
110
+ vertex: {
111
+ module: device.createShaderModule({
112
+ code: vertexWriteGBuffers,
113
+ }),
114
+ entryPoint: 'main',
115
+ buffers: vertexBuffers,
116
+ },
117
+ fragment: {
118
+ module: device.createShaderModule({
119
+ code: fragmentWriteGBuffers,
120
+ }),
121
+ entryPoint: 'main',
122
+ targets: [
123
+ // position
124
+ { format: 'rgba32float' },
125
+ // normal
126
+ { format: 'rgba32float' },
127
+ // albedo
128
+ { format: 'bgra8unorm' },
129
+ ],
130
+ },
131
+ depthStencil: {
132
+ depthWriteEnabled: true,
133
+ depthCompare: 'less',
134
+ format: 'depth24plus',
135
+ },
136
+ primitive,
137
+ });
138
+ const gBufferTexturesBindGroupLayout = device.createBindGroupLayout({
139
+ entries: [
140
+ {
141
+ binding: 0,
142
+ visibility: GPUShaderStage.FRAGMENT,
143
+ texture: {
144
+ sampleType: 'unfilterable-float',
145
+ },
146
+ },
147
+ {
148
+ binding: 1,
149
+ visibility: GPUShaderStage.FRAGMENT,
150
+ texture: {
151
+ sampleType: 'unfilterable-float',
152
+ },
153
+ },
154
+ {
155
+ binding: 2,
156
+ visibility: GPUShaderStage.FRAGMENT,
157
+ texture: {
158
+ sampleType: 'unfilterable-float',
159
+ },
160
+ },
161
+ ],
162
+ });
163
+ const lightsBufferBindGroupLayout = device.createBindGroupLayout({
164
+ entries: [
165
+ {
166
+ binding: 0,
167
+ visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
168
+ buffer: {
169
+ type: 'storage',
170
+ },
171
+ },
172
+ {
173
+ binding: 1,
174
+ visibility: GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
175
+ buffer: {
176
+ type: 'uniform',
177
+ },
178
+ },
179
+ ],
180
+ });
181
+ const canvasSizeUniformBindGroupLayout = device.createBindGroupLayout({
182
+ entries: [
183
+ {
184
+ binding: 0,
185
+ visibility: GPUShaderStage.FRAGMENT,
186
+ buffer: {
187
+ type: 'uniform',
188
+ },
189
+ },
190
+ ],
191
+ });
192
+ const gBuffersDebugViewPipeline = device.createRenderPipeline({
193
+ layout: device.createPipelineLayout({
194
+ bindGroupLayouts: [
195
+ gBufferTexturesBindGroupLayout,
196
+ canvasSizeUniformBindGroupLayout,
197
+ ],
198
+ }),
199
+ vertex: {
200
+ module: device.createShaderModule({
201
+ code: vertexTextureQuad,
202
+ }),
203
+ entryPoint: 'main',
204
+ },
205
+ fragment: {
206
+ module: device.createShaderModule({
207
+ code: fragmentGBuffersDebugView,
208
+ }),
209
+ entryPoint: 'main',
210
+ targets: [
211
+ {
212
+ format: presentationFormat,
213
+ },
214
+ ],
215
+ },
216
+ primitive,
217
+ });
218
+ const deferredRenderPipeline = device.createRenderPipeline({
219
+ layout: device.createPipelineLayout({
220
+ bindGroupLayouts: [
221
+ gBufferTexturesBindGroupLayout,
222
+ lightsBufferBindGroupLayout,
223
+ canvasSizeUniformBindGroupLayout,
224
+ ],
225
+ }),
226
+ vertex: {
227
+ module: device.createShaderModule({
228
+ code: vertexTextureQuad,
229
+ }),
230
+ entryPoint: 'main',
231
+ },
232
+ fragment: {
233
+ module: device.createShaderModule({
234
+ code: fragmentDeferredRendering,
235
+ }),
236
+ entryPoint: 'main',
237
+ targets: [
238
+ {
239
+ format: presentationFormat,
240
+ },
241
+ ],
242
+ },
243
+ primitive,
244
+ });
245
+ const depthTexture = device.createTexture({
246
+ size: presentationSize,
247
+ format: 'depth24plus',
248
+ usage: GPUTextureUsage.RENDER_ATTACHMENT,
249
+ });
250
+ const writeGBufferPassDescriptor = {
251
+ colorAttachments: [
252
+ {
253
+ view: gBufferTextureViews[0],
254
+ loadValue: {
255
+ r: Number.MAX_VALUE,
256
+ g: Number.MAX_VALUE,
257
+ b: Number.MAX_VALUE,
258
+ a: 1.0,
259
+ },
260
+ storeOp: 'store',
261
+ },
262
+ {
263
+ view: gBufferTextureViews[1],
264
+ loadValue: { r: 0.0, g: 0.0, b: 1.0, a: 1.0 },
265
+ storeOp: 'store',
266
+ },
267
+ {
268
+ view: gBufferTextureViews[2],
269
+ loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
270
+ storeOp: 'store',
271
+ },
272
+ ],
273
+ depthStencilAttachment: {
274
+ view: depthTexture.createView(),
275
+ depthLoadValue: 1.0,
276
+ depthStoreOp: 'store',
277
+ stencilLoadValue: 0,
278
+ stencilStoreOp: 'store',
279
+ },
280
+ };
281
+ const textureQuadPassDescriptor = {
282
+ colorAttachments: [
283
+ {
284
+ // view is acquired and set in render loop.
285
+ view: undefined,
286
+ loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
287
+ storeOp: 'store',
288
+ },
289
+ ],
290
+ };
291
+ const settings = {
292
+ mode: 'rendering',
293
+ numLights: 128,
294
+ };
295
+ const configUniformBuffer = (() => {
296
+ const buffer = device.createBuffer({
297
+ size: Uint32Array.BYTES_PER_ELEMENT,
298
+ mappedAtCreation: true,
299
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
300
+ });
301
+ new Uint32Array(buffer.getMappedRange())[0] = settings.numLights;
302
+ buffer.unmap();
303
+ return buffer;
304
+ })();
305
+ gui.add(settings, 'mode', ['rendering', 'gBuffers view']);
306
+ gui
307
+ .add(settings, 'numLights', 1, kMaxNumLights)
308
+ .step(1)
309
+ .onChange(() => {
310
+ device.queue.writeBuffer(configUniformBuffer, 0, new Uint32Array([settings.numLights]));
311
+ });
312
+ const modelUniformBuffer = device.createBuffer({
313
+ size: 4 * 16 * 2,
314
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
315
+ });
316
+ const cameraUniformBuffer = device.createBuffer({
317
+ size: 4 * 16,
318
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
319
+ });
320
+ const sceneUniformBindGroup = device.createBindGroup({
321
+ layout: writeGBuffersPipeline.getBindGroupLayout(0),
322
+ entries: [
323
+ {
324
+ binding: 0,
325
+ resource: {
326
+ buffer: modelUniformBuffer,
327
+ },
328
+ },
329
+ {
330
+ binding: 1,
331
+ resource: {
332
+ buffer: cameraUniformBuffer,
333
+ },
334
+ },
335
+ ],
336
+ });
337
+ const canvasSizeUniformBuffer = device.createBuffer({
338
+ size: 4 * 2,
339
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
340
+ });
341
+ const canvasSizeUniformBindGroup = device.createBindGroup({
342
+ layout: canvasSizeUniformBindGroupLayout,
343
+ entries: [
344
+ {
345
+ binding: 0,
346
+ resource: {
347
+ buffer: canvasSizeUniformBuffer,
348
+ },
349
+ },
350
+ ],
351
+ });
352
+ const gBufferTexturesBindGroup = device.createBindGroup({
353
+ layout: gBufferTexturesBindGroupLayout,
354
+ entries: [
355
+ {
356
+ binding: 0,
357
+ resource: gBufferTextureViews[0],
358
+ },
359
+ {
360
+ binding: 1,
361
+ resource: gBufferTextureViews[1],
362
+ },
363
+ {
364
+ binding: 2,
365
+ resource: gBufferTextureViews[2],
366
+ },
367
+ ],
368
+ });
369
+ // Lights data are uploaded in a storage buffer
370
+ // which could be updated/culled/etc. with a compute shader
371
+ const extent = vec3.create();
372
+ vec3.sub(extent, lightExtentMax, lightExtentMin);
373
+ const lightDataStride = 8;
374
+ const bufferSizeInByte = Float32Array.BYTES_PER_ELEMENT * lightDataStride * kMaxNumLights;
375
+ const lightsBuffer = device.createBuffer({
376
+ size: bufferSizeInByte,
377
+ usage: GPUBufferUsage.STORAGE,
378
+ mappedAtCreation: true,
379
+ });
380
+ // We randomaly populate lights randomly in a box range
381
+ // And simply move them along y-axis per frame to show they are
382
+ // dynamic lightings
383
+ const lightData = new Float32Array(lightsBuffer.getMappedRange());
384
+ const tmpVec4 = vec4.create();
385
+ let offset = 0;
386
+ for (let i = 0; i < kMaxNumLights; i++) {
387
+ offset = lightDataStride * i;
388
+ // position
389
+ for (let i = 0; i < 3; i++) {
390
+ tmpVec4[i] = Math.random() * extent[i] + lightExtentMin[i];
391
+ }
392
+ tmpVec4[3] = 1;
393
+ lightData.set(tmpVec4, offset);
394
+ // color
395
+ tmpVec4[0] = Math.random() * 2;
396
+ tmpVec4[1] = Math.random() * 2;
397
+ tmpVec4[2] = Math.random() * 2;
398
+ // radius
399
+ tmpVec4[3] = 20.0;
400
+ lightData.set(tmpVec4, offset + 4);
401
+ }
402
+ lightsBuffer.unmap();
403
+ const lightExtentBuffer = device.createBuffer({
404
+ size: 4 * 8,
405
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
406
+ });
407
+ const lightExtentData = new Float32Array(8);
408
+ lightExtentData.set(lightExtentMin, 0);
409
+ lightExtentData.set(lightExtentMax, 4);
410
+ device.queue.writeBuffer(lightExtentBuffer, 0, lightExtentData.buffer, lightExtentData.byteOffset, lightExtentData.byteLength);
411
+ const lightUpdateComputePipeline = device.createComputePipeline({
412
+ compute: {
413
+ module: device.createShaderModule({
414
+ code: lightUpdate,
415
+ }),
416
+ entryPoint: 'main',
417
+ },
418
+ });
419
+ const lightsBufferBindGroup = device.createBindGroup({
420
+ layout: lightsBufferBindGroupLayout,
421
+ entries: [
422
+ {
423
+ binding: 0,
424
+ resource: {
425
+ buffer: lightsBuffer,
426
+ },
427
+ },
428
+ {
429
+ binding: 1,
430
+ resource: {
431
+ buffer: configUniformBuffer,
432
+ },
433
+ },
434
+ ],
435
+ });
436
+ const lightsBufferComputeBindGroup = device.createBindGroup({
437
+ layout: lightUpdateComputePipeline.getBindGroupLayout(0),
438
+ entries: [
439
+ {
440
+ binding: 0,
441
+ resource: {
442
+ buffer: lightsBuffer,
443
+ },
444
+ },
445
+ {
446
+ binding: 1,
447
+ resource: {
448
+ buffer: configUniformBuffer,
449
+ },
450
+ },
451
+ {
452
+ binding: 2,
453
+ resource: {
454
+ buffer: lightExtentBuffer,
455
+ },
456
+ },
457
+ ],
458
+ });
459
+ //--------------------
460
+ // Scene matrices
461
+ const eyePosition = vec3.fromValues(0, 50, -100);
462
+ const upVector = vec3.fromValues(0, 1, 0);
463
+ const origin = vec3.fromValues(0, 0, 0);
464
+ const projectionMatrix = mat4.create();
465
+ mat4.perspective(projectionMatrix, (2 * Math.PI) / 5, aspect, 1, 2000.0);
466
+ const viewMatrix = mat4.create();
467
+ mat4.lookAt(viewMatrix, eyePosition, origin, upVector);
468
+ const viewProjMatrix = mat4.create();
469
+ mat4.multiply(viewProjMatrix, projectionMatrix, viewMatrix);
470
+ // Move the model so it's centered.
471
+ const modelMatrix = mat4.create();
472
+ mat4.translate(modelMatrix, modelMatrix, vec3.fromValues(0, -5, 0));
473
+ mat4.translate(modelMatrix, modelMatrix, vec3.fromValues(0, -40, 0));
474
+ const cameraMatrixData = viewProjMatrix;
475
+ device.queue.writeBuffer(cameraUniformBuffer, 0, cameraMatrixData.buffer, cameraMatrixData.byteOffset, cameraMatrixData.byteLength);
476
+ const modelData = modelMatrix;
477
+ device.queue.writeBuffer(modelUniformBuffer, 0, modelData.buffer, modelData.byteOffset, modelData.byteLength);
478
+ const invertTransposeModelMatrix = mat4.create();
479
+ mat4.invert(invertTransposeModelMatrix, modelMatrix);
480
+ mat4.transpose(invertTransposeModelMatrix, invertTransposeModelMatrix);
481
+ const normalModelData = invertTransposeModelMatrix;
482
+ device.queue.writeBuffer(modelUniformBuffer, 64, normalModelData.buffer, normalModelData.byteOffset, normalModelData.byteLength);
483
+ // Pass the canvas size to shader to help sample from gBuffer textures using coord
484
+ const canvasSizeData = new Float32Array(presentationSize);
485
+ device.queue.writeBuffer(canvasSizeUniformBuffer, 0, canvasSizeData.buffer, canvasSizeData.byteOffset, canvasSizeData.byteLength);
486
+
487
+ // Rotates the camera around the origin based on time.
488
+ function getCameraViewProjMatrix() {
489
+ const eyePosition = vec3.fromValues(0, 50, -100);
490
+ const rad = Math.PI * (Date.now() / 5000);
491
+ vec3.rotateY(eyePosition, eyePosition, origin, rad);
492
+ const viewMatrix = mat4.create();
493
+ mat4.lookAt(viewMatrix, eyePosition, origin, upVector);
494
+ mat4.multiply(viewProjMatrix, projectionMatrix, viewMatrix);
495
+ return viewProjMatrix;
496
+ }
497
+
498
+ function frame() {
499
+ // Sample is no longer the active page.
500
+ if (!canvasRef.current)
501
+ return;
502
+ const cameraViewProj = getCameraViewProjMatrix();
503
+ device.queue.writeBuffer(cameraUniformBuffer, 0, cameraViewProj.buffer, cameraViewProj.byteOffset, cameraViewProj.byteLength);
504
+ const commandEncoder = device.createCommandEncoder();
505
+ {
506
+ // Write position, normal, albedo etc. data to gBuffers
507
+ const gBufferPass = commandEncoder.beginRenderPass(writeGBufferPassDescriptor);
508
+ gBufferPass.setPipeline(writeGBuffersPipeline);
509
+ gBufferPass.setBindGroup(0, sceneUniformBindGroup);
510
+ gBufferPass.setVertexBuffer(0, vertexBuffer);
511
+ gBufferPass.setIndexBuffer(indexBuffer, 'uint16');
512
+ gBufferPass.drawIndexed(indexCount);
513
+ gBufferPass.endPass();
514
+ }
515
+ {
516
+ // Update lights position
517
+ const lightPass = commandEncoder.beginComputePass();
518
+ lightPass.setPipeline(lightUpdateComputePipeline);
519
+ lightPass.setBindGroup(0, lightsBufferComputeBindGroup);
520
+ lightPass.dispatch(Math.ceil(kMaxNumLights / 64));
521
+ lightPass.endPass();
522
+ }
523
+ {
524
+ if (settings.mode === 'gBuffers view') {
525
+ // GBuffers debug view
526
+ // Left: position
527
+ // Middle: normal
528
+ // Right: albedo (use uv to mimic a checkerboard texture)
529
+ textureQuadPassDescriptor.colorAttachments[0].view = context
530
+ .getCurrentTexture()
531
+ .createView();
532
+ const debugViewPass = commandEncoder.beginRenderPass(textureQuadPassDescriptor);
533
+ debugViewPass.setPipeline(gBuffersDebugViewPipeline);
534
+ debugViewPass.setBindGroup(0, gBufferTexturesBindGroup);
535
+ debugViewPass.setBindGroup(1, canvasSizeUniformBindGroup);
536
+ debugViewPass.draw(6);
537
+ debugViewPass.endPass();
538
+ } else {
539
+ // Deferred rendering
540
+ textureQuadPassDescriptor.colorAttachments[0].view = context
541
+ .getCurrentTexture()
542
+ .createView();
543
+ const deferredRenderingPass = commandEncoder.beginRenderPass(textureQuadPassDescriptor);
544
+ deferredRenderingPass.setPipeline(deferredRenderPipeline);
545
+ deferredRenderingPass.setBindGroup(0, gBufferTexturesBindGroup);
546
+ deferredRenderingPass.setBindGroup(1, lightsBufferBindGroup);
547
+ deferredRenderingPass.setBindGroup(2, canvasSizeUniformBindGroup);
548
+ deferredRenderingPass.draw(6);
549
+ deferredRenderingPass.endPass();
550
+ }
551
+ }
552
+ device.queue.submit([commandEncoder.finish()]);
553
+ requestAnimationFrame(frame);
554
+ }
555
+
556
+ requestAnimationFrame(frame);
557
+ };
558
+
559
+ const canvas_el = document.createElement('canvas');
560
+
561
+ init({
562
+ canvasRef: {
563
+ current: canvas_el,
564
+ gui: new GUI()
565
+ }
566
+ });
@@ -0,0 +1,9 @@
1
+ [[stage(vertex)]]
2
+ fn main([[builtin(vertex_index)]] VertexIndex : u32)
3
+ -> [[builtin(position)]] vec4<f32> {
4
+ var pos = array<vec2<f32>, 6>(
5
+ vec2<f32>(-1.0, -1.0), vec2<f32>(1.0, -1.0), vec2<f32>(-1.0, 1.0),
6
+ vec2<f32>(-1.0, 1.0), vec2<f32>(1.0, -1.0), vec2<f32>(1.0, 1.0));
7
+
8
+ return vec4<f32>(pos[VertexIndex], 0.0, 1.0);
9
+ }
@@ -0,0 +1,28 @@
1
+ [[block]] struct Uniforms {
2
+ modelMatrix : mat4x4<f32>;
3
+ normalModelMatrix : mat4x4<f32>;
4
+ };
5
+ [[block]] struct Camera {
6
+ viewProjectionMatrix : mat4x4<f32>;
7
+ };
8
+ [[group(0), binding(0)]] var<uniform> uniforms : Uniforms;
9
+ [[group(0), binding(1)]] var<uniform> camera : Camera;
10
+
11
+ struct VertexOutput {
12
+ [[builtin(position)]] Position : vec4<f32>;
13
+ [[location(0)]] fragPosition: vec3<f32>; // position in world space
14
+ [[location(1)]] fragNormal: vec3<f32>; // normal in world space
15
+ [[location(2)]] fragUV: vec2<f32>;
16
+ };
17
+
18
+ [[stage(vertex)]]
19
+ fn main([[location(0)]] position : vec3<f32>,
20
+ [[location(1)]] normal : vec3<f32>,
21
+ [[location(2)]] uv : vec2<f32>) -> VertexOutput {
22
+ var output : VertexOutput;
23
+ output.fragPosition = (uniforms.modelMatrix * vec4<f32>(position, 1.0)).xyz;
24
+ output.Position = camera.viewProjectionMatrix * vec4<f32>(output.fragPosition, 1.0);
25
+ output.fragNormal = normalize((uniforms.normalModelMatrix * vec4<f32>(normal, 1.0)).xyz);
26
+ output.fragUV = uv;
27
+ return output;
28
+ }