From 2885fe9a9ac2576497cc7d357d1ecfc3cb64221e Mon Sep 17 00:00:00 2001 From: copygirl Date: Fri, 23 Feb 2024 13:35:13 +0100 Subject: [PATCH] Render triangles as 3 separate models --- src/main.zig | 96 +++++++++++++++++++++++++++++++++++-------------- src/shader.wgsl | 18 +++++++--- 2 files changed, 83 insertions(+), 31 deletions(-) diff --git a/src/main.zig b/src/main.zig index eb4290e..a77c5c1 100644 --- a/src/main.zig +++ b/src/main.zig @@ -8,6 +8,14 @@ const Mat = zm.Mat; const VertexData = struct { position: [3]f32, +}; + +const SceneUniformBuffer = struct { + view_proj_matrix: zm.Mat, +}; + +const ModelUniformBuffer = struct { + matrix: zm.Mat, color: [3]f32, }; @@ -17,8 +25,10 @@ app_timer: core.Timer, title_timer: core.Timer, pipeline: *gpu.RenderPipeline, -mvp_uniform_buffer: *gpu.Buffer, -mvp_bind_group: *gpu.BindGroup, +scene_uniform_buffer: *gpu.Buffer, +scene_bind_group: *gpu.BindGroup, +model_uniform_buffers: [3]*gpu.Buffer, +model_bind_groups: [3]*gpu.BindGroup, vertex_count: u32, vertex_buffer: *gpu.Buffer, @@ -42,7 +52,6 @@ pub fn init(app: *App) !void { .step_mode = .vertex, .attributes = &.{ .{ .format = .float32x3, .shader_location = 0, .offset = @offsetOf(VertexData, "position") }, - .{ .format = .float32x3, .shader_location = 1, .offset = @offsetOf(VertexData, "color") }, }, }), }, @@ -54,36 +63,58 @@ pub fn init(app: *App) !void { }), }); - // Set up uniform buffer and bind group. - app.mvp_uniform_buffer = core.device.createBuffer(&.{ + // Set up uniform buffers and bind groups. + + // The "scene" uniform contains information for each rendered scene. + app.scene_uniform_buffer = core.device.createBuffer(&.{ .usage = .{ .copy_dst = true, .uniform = true }, - .size = @sizeOf(zm.Mat), + .size = @sizeOf(SceneUniformBuffer), .mapped_at_creation = .false, }); - - app.mvp_bind_group = core.device.createBindGroup( + app.scene_bind_group = core.device.createBindGroup( &gpu.BindGroup.Descriptor.init(.{ .layout = app.pipeline.getBindGroupLayout(0), .entries = &.{ - gpu.BindGroup.Entry.buffer(0, app.mvp_uniform_buffer, 0, @sizeOf(zm.Mat)), + gpu.BindGroup.Entry.buffer(0, app.scene_uniform_buffer, 0, @sizeOf(SceneUniformBuffer)), }, }), ); + // The "model" uniforms contain information about how to render each model. + for (0..3) |i| { + app.model_uniform_buffers[i] = core.device.createBuffer(&.{ + .usage = .{ .copy_dst = true, .uniform = true }, + .size = @sizeOf(ModelUniformBuffer), + .mapped_at_creation = .false, + }); + app.model_bind_groups[i] = core.device.createBindGroup( + &gpu.BindGroup.Descriptor.init(.{ + .layout = app.pipeline.getBindGroupLayout(1), + .entries = &.{ + gpu.BindGroup.Entry.buffer(0, app.model_uniform_buffers[i], 0, @sizeOf(ModelUniformBuffer)), + }, + }), + ); + } + // Upload model render information (matrix + color) to the GPU. + core.queue.writeBuffer(app.model_uniform_buffers[0], 0, &[_]ModelUniformBuffer{.{ + .matrix = zm.transpose(zm.translation(-1.0, 0.25, 0.0)), + .color = .{ 1.0, 0.0, 0.0 }, + }}); + core.queue.writeBuffer(app.model_uniform_buffers[1], 0, &[_]ModelUniformBuffer{.{ + .matrix = zm.transpose(zm.translation(0.0, -0.25, 0.0)), + .color = .{ 0.0, 1.0, 0.0 }, + }}); + core.queue.writeBuffer(app.model_uniform_buffers[2], 0, &[_]ModelUniformBuffer{.{ + .matrix = zm.transpose(zm.translation(1.0, 0.0, 0.0)), + .color = .{ 0.0, 0.0, 1.0 }, + }}); + // Set up vertex buffer, containing the vertex data we want to draw. - // `vertices` contains three separate triangles, each with a different color. const vertices = [_]VertexData{ - .{ .position = .{ -1.0, 0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, - .{ .position = .{ -1.5, -0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, - .{ .position = .{ -0.5, -0.5 + 0.25, 0.0 }, .color = .{ 1.0, 0.0, 0.0 } }, - - .{ .position = .{ 0.0, 0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, - .{ .position = .{ -0.5, -0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, - .{ .position = .{ 0.5, -0.5 - 0.25, 0.0 }, .color = .{ 0.0, 1.0, 0.0 } }, - - .{ .position = .{ 1.0, 0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, - .{ .position = .{ 0.5, -0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, - .{ .position = .{ 1.5, -0.5, 0.0 }, .color = .{ 0.0, 0.0, 1.0 } }, + .{ .position = .{ 0.0, 0.5, 0.0 } }, + .{ .position = .{ -0.5, -0.5, 0.0 } }, + .{ .position = .{ 0.5, -0.5, 0.0 } }, }; app.vertex_count = vertices.len; app.vertex_buffer = core.device.createBuffer(&.{ @@ -100,8 +131,10 @@ pub fn deinit(app: *App) void { // in the order they were created in `init`. defer core.deinit(); defer app.pipeline.release(); - defer app.mvp_uniform_buffer.release(); - defer app.mvp_bind_group.release(); + defer app.scene_uniform_buffer.release(); + defer app.scene_bind_group.release(); + defer for (app.model_uniform_buffers) |b| b.release(); + defer for (app.model_bind_groups) |g| g.release(); defer app.vertex_buffer.release(); } @@ -151,7 +184,12 @@ pub fn update(app: *App) !bool { const encoder = core.device.createCommandEncoder(null); defer encoder.release(); - encoder.writeBuffer(app.mvp_uniform_buffer, 0, &[_]zm.Mat{zm.transpose(view_proj_matrix)}); + // Write to the scene uniform buffer for this set of commands. + encoder.writeBuffer(app.scene_uniform_buffer, 0, &[_]SceneUniformBuffer{.{ + // All matrices the GPU has to work with need to be transposed, + // because WebGPU uses column-major matrices while zmath is row-major. + .view_proj_matrix = zm.transpose(view_proj_matrix), + }}); { const pass = encoder.beginRenderPass(&render_pass_info); @@ -159,11 +197,15 @@ pub fn update(app: *App) !bool { defer pass.end(); pass.setPipeline(app.pipeline); - pass.setBindGroup(0, app.mvp_bind_group, &.{}); + pass.setBindGroup(0, app.scene_bind_group, &.{}); pass.setVertexBuffer(0, app.vertex_buffer, 0, app.vertex_count * @sizeOf(VertexData)); - // Draw the vertices in `vertex_buffer`. - pass.draw(app.vertex_count, 1, 0, 0); + for (app.model_bind_groups) |model_bind_group| { + // Set the model bind group for a specific model we want to render. + pass.setBindGroup(1, model_bind_group, &.{}); + // Draw the vertices in `vertex_buffer`. + pass.draw(app.vertex_count, 1, 0, 0); + } } // Finish recording commands, creating a `WGPUCommandBuffer`. diff --git a/src/shader.wgsl b/src/shader.wgsl index 7350e45..ef54b10 100644 --- a/src/shader.wgsl +++ b/src/shader.wgsl @@ -1,8 +1,17 @@ -@group(0) @binding(0) var mvp_matrix: mat4x4; +struct SceneUniformBuffer { + view_proj_matrix: mat4x4, +}; + +struct ModelUniformBuffer { + matrix: mat4x4, + color: vec3, +}; + +@group(0) @binding(0) var scene: SceneUniformBuffer; +@group(1) @binding(0) var model: ModelUniformBuffer; struct VertexInput { @location(0) position: vec3, - @location(1) color: vec3, }; struct VertexOutput { @@ -16,8 +25,9 @@ struct FragmentOutput { @vertex fn vertex_main(in: VertexInput) -> VertexOutput { var out: VertexOutput; - out.position = vec4(in.position, 1.0) * mvp_matrix; - out.color = vec4(in.color, 1.0); + let mvp = model.matrix * scene.view_proj_matrix; + out.position = vec4(in.position, 1.0) * mvp; + out.color = vec4(model.color, 1.0); return out; }