diff --git a/js/webgpu_main.js b/js/webgpu_main.js index 182521e..ad0f6f4 100644 --- a/js/webgpu_main.js +++ b/js/webgpu_main.js @@ -33,6 +33,7 @@ export default async (canvas, config) => { console.log(config); const NUM_VERTICES_PER_QUAD = 6; + const THIRTY_TWO_BITS = 4; // 4 bytes = 32 bits const numColumns = config.numColumns; const numRows = config.numColumns; @@ -69,30 +70,44 @@ export default async (canvas, config) => { const msdfTexture = await loadTexture(device, config.glyphTexURL); - const uniformBufferSize = 4 * (1 * 1 + 1 * 1); - const uniformBuffer = device.createBuffer({ - size: uniformBufferSize, + const configBufferSize = THIRTY_TWO_BITS * (1 * 1 + 1 * 1); + const configBuffer = device.createBuffer({ + size: configBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, // Which of these are necessary? mappedAtCreation: true, }); - new Int32Array(uniformBuffer.getMappedRange()).set([numColumns, numRows]); - uniformBuffer.unmap(); + new Int32Array(configBuffer.getMappedRange()).set([numColumns, numRows]); + configBuffer.unmap(); - const msdfUniformBufferSize = 4 * (1 * 1); - const msdfUniformBuffer = device.createBuffer({ - size: msdfUniformBufferSize, + const msdfBufferSize = THIRTY_TWO_BITS * (1 * 1); + const msdfBuffer = device.createBuffer({ + size: msdfBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.FRAGMENT | GPUBufferUsage.COPY_DST, // Which of these are necessary? mappedAtCreation: true, }); - new Int32Array(msdfUniformBuffer.getMappedRange()).set([config.glyphTextureColumns]); - msdfUniformBuffer.unmap(); + new Int32Array(msdfBuffer.getMappedRange()).set([config.glyphTextureColumns]); + msdfBuffer.unmap(); - const timeBufferSize = 4 * (1 * 1 + 1 * 1); + const timeBufferSize = THIRTY_TWO_BITS * (1 * 1 + 1 * 1); const timeBuffer = device.createBuffer({ - size: uniformBufferSize, + size: configBufferSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.FRAGMENT | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary? }); + const cameraBufferSize = THIRTY_TWO_BITS * (1 * 2); + const cameraBuffer = device.createBuffer({ + size: configBufferSize, + usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.VERTEX | GPUBufferUsage.COMPUTE | GPUBufferUsage.COPY_DST, // Which of these are necessary? + }); + + const updateCameraBuffer = () => { + const canvasSize = canvasConfig.size; + const aspectRatio = canvasSize[0] / canvasSize[1]; + const screenSize = aspectRatio > 1 ? [1, aspectRatio] : [1 / aspectRatio, 1]; + queue.writeBuffer(cameraBuffer, 0, new Float32Array(screenSize)); + } + updateCameraBuffer(); + const [rainRenderShader] = await Promise.all(["shaders/rainRenderPass.wgsl"].map(async (path) => (await fetch(path)).text())); const rainRenderShaderModule = device.createShaderModule({ code: rainRenderShader }); @@ -130,13 +145,13 @@ export default async (canvas, config) => { }, }); - const uniformBindGroup = device.createBindGroup({ + const configBindGroup = device.createBindGroup({ layout: rainRenderPipeline.getBindGroupLayout(0), entries: [ { binding: 0, resource: { - buffer: uniformBuffer, + buffer: configBuffer, }, }, ], @@ -148,7 +163,7 @@ export default async (canvas, config) => { { binding: 0, resource: { - buffer: msdfUniformBuffer, + buffer: msdfBuffer, }, }, { @@ -174,7 +189,19 @@ export default async (canvas, config) => { ], }); - const rainRenderPipelineBindGroups = [uniformBindGroup, msdfBindGroup, timeBindGroup]; + const cameraBindGroup = device.createBindGroup({ + layout: rainRenderPipeline.getBindGroupLayout(3), + entries: [ + { + binding: 0, + resource: { + buffer: cameraBuffer, + }, + }, + ], + }); + + const rainRenderPipelineBindGroups = [configBindGroup, msdfBindGroup, timeBindGroup, cameraBindGroup]; const bundleEncoder = device.createRenderBundleEncoder({ colorFormats: [presentationFormat], @@ -198,7 +225,7 @@ export default async (canvas, config) => { // TODO: destroy and recreate all screen size textures - // TODO: update camera matrix, screen size, write to queue + updateCameraBuffer(); } queue.writeBuffer(timeBuffer, 0, new Int32Array([now, frame])); diff --git a/shaders/rainRenderPass.wgsl b/shaders/rainRenderPass.wgsl index 8325c77..04e2d5e 100644 --- a/shaders/rainRenderPass.wgsl +++ b/shaders/rainRenderPass.wgsl @@ -21,6 +21,11 @@ let TWO_PI:f32 = 6.28318530718; // No, I'm not using Tau. }; [[group(2), binding(0)]] var timeUniforms:TimeUniforms; +[[block]] struct CameraUniforms { + screenSize: vec2; +}; +[[group(3), binding(0)]] var cameraUniforms:CameraUniforms; + // Vertex shader struct VertexOutput { @@ -38,8 +43,6 @@ struct VertexOutput { f32(((i + 1) % NUM_VERTICES_PER_QUAD / 3)) ); - var x = uniforms.numColumns; - var position = cornerPosition; position = position + vec2( f32(quadIndex % uniforms.numColumns), @@ -50,6 +53,7 @@ struct VertexOutput { f32(uniforms.numRows) ); position = 1.0 - position * 2.0; + position = position * cameraUniforms.screenSize; return VertexOutput( vec4(position, 1.0, 1.0),