|
|
|
@ -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`. |
|
|
|
|