Add perspective projection

main
copygirl 9 months ago
parent 4796ff6de5
commit c7a56745a7
  1. 52
      src/main.zig
  2. 46
      src/shader.wgsl

@ -2,10 +2,18 @@ const std = @import("std");
const core = @import("mach-core"); const core = @import("mach-core");
const gpu = core.gpu; const gpu = core.gpu;
const zm = @import("zmath");
const vec = zm.f32x4;
const Mat = zm.Mat;
pub const App = @This(); pub const App = @This();
app_timer: core.Timer,
title_timer: core.Timer, title_timer: core.Timer,
pipeline: *gpu.RenderPipeline, pipeline: *gpu.RenderPipeline,
mvp_uniform_buffer: *gpu.Buffer,
mvp_bind_group: *gpu.BindGroup,
pub fn init(app: *App) !void { pub fn init(app: *App) !void {
try core.init(.{}); try core.init(.{});
@ -32,13 +40,32 @@ pub fn init(app: *App) !void {
.fragment = &fragment, .fragment = &fragment,
}; };
app.app_timer = try core.Timer.start();
app.title_timer = try core.Timer.start(); app.title_timer = try core.Timer.start();
app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor); app.pipeline = core.device.createRenderPipeline(&pipeline_descriptor);
app.mvp_uniform_buffer = core.device.createBuffer(&.{
.usage = .{ .copy_dst = true, .uniform = true },
.size = @sizeOf(zm.Mat),
.mapped_at_creation = .false,
});
app.mvp_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)),
},
}),
);
} }
pub fn deinit(app: *App) void { pub fn deinit(app: *App) void {
defer core.deinit(); defer core.deinit();
defer app.pipeline.release(); defer app.pipeline.release();
defer app.mvp_uniform_buffer.release();
defer app.mvp_bind_group.release();
} }
pub fn update(app: *App) !bool { pub fn update(app: *App) !bool {
@ -50,6 +77,24 @@ pub fn update(app: *App) !bool {
} }
} }
// Set up a view matrix from the camera transform.
// This moves everything to be relative to the camera.
// TODO: Actually implement camera transform instead of hardcoding a look-at matrix.
// const view_matrix = zm.inverse(app.camera_transform);
const time = app.app_timer.read();
const x = @cos(time * std.math.tau / 10);
const y = @sin(time * std.math.tau / 10);
const view_matrix = zm.lookAtLh(vec(x, y, -2, 1), vec(0, 0, 0, 1), vec(0, 1, 0, 1));
// Set up a projection matrix using the size of the window.
// The perspective projection will make things further away appear smaller.
const width: f32 = @floatFromInt(core.descriptor.width);
const height: f32 = @floatFromInt(core.descriptor.height);
const field_of_view = std.math.degreesToRadians(f32, 45.0);
const proj_matrix = zm.perspectiveFovLh(field_of_view, width / height, 0.1, 10);
const view_proj_matrix = zm.mul(view_matrix, proj_matrix);
// Get back buffer texture to render to. // Get back buffer texture to render to.
const back_buffer_view = core.swap_chain.getCurrentTextureView().?; const back_buffer_view = core.swap_chain.getCurrentTextureView().?;
defer back_buffer_view.release(); defer back_buffer_view.release();
@ -70,15 +115,18 @@ pub fn update(app: *App) !bool {
const encoder = core.device.createCommandEncoder(null); const encoder = core.device.createCommandEncoder(null);
defer encoder.release(); defer encoder.release();
encoder.writeBuffer(app.mvp_uniform_buffer, 0, &[_]zm.Mat{zm.transpose(view_proj_matrix)});
{ {
const pass = encoder.beginRenderPass(&render_pass_info); const pass = encoder.beginRenderPass(&render_pass_info);
defer pass.release(); defer pass.release();
defer pass.end(); defer pass.end();
pass.setPipeline(app.pipeline); pass.setPipeline(app.pipeline);
pass.setBindGroup(0, app.mvp_bind_group, &.{});
// Draw a triangle with the help of a specialized shader. // Draw three triangles with the help of a specialized shader.
pass.draw(3, 1, 0, 0); pass.draw(9, 1, 0, 0);
} }
// Finish recording commands, creating a `WGPUCommandBuffer`. // Finish recording commands, creating a `WGPUCommandBuffer`.

@ -1,14 +1,44 @@
@group(0) @binding(0) var<uniform> mvp_matrix: mat4x4<f32>;
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) color: vec4<f32>,
};
struct FragmentOutput {
@location(0) pixel_color: vec4<f32>
};
@vertex fn vertex_main( @vertex fn vertex_main(
@builtin(vertex_index) index: u32 @builtin(vertex_index) index: u32
) -> @builtin(position) vec4<f32> { ) -> VertexOutput {
let pos = array<vec2<f32>, 3>( let color = array<vec3<f32>, 3>(
vec2<f32>( 0.0, 0.5), vec3<f32>(1.0, 0.0, 0.0),
vec2<f32>(-0.5, -0.5), vec3<f32>(0.0, 1.0, 0.0),
vec2<f32>( 0.5, -0.5) vec3<f32>(0.0, 0.0, 1.0),
); );
return vec4<f32>(pos[index], 0.0, 1.0); let pos = array<vec2<f32>, 9>(
vec2<f32>(-1.0, 0.5 + 0.25),
vec2<f32>(-1.5, -0.5 + 0.25),
vec2<f32>(-0.5, -0.5 + 0.25),
vec2<f32>( 0.0, 0.5 - 0.25),
vec2<f32>(-0.5, -0.5 - 0.25),
vec2<f32>( 0.5, -0.5 - 0.25),
vec2<f32>( 1.0, 0.5),
vec2<f32>( 0.5, -0.5),
vec2<f32>( 1.5, -0.5),
);
var out: VertexOutput;
out.position = vec4<f32>(pos[index], 0.0, 1.0) * mvp_matrix;
out.color = vec4<f32>(color[index / 3], 1.0);
return out;
} }
@fragment fn frag_main() -> @location(0) vec4<f32> { @fragment fn frag_main(in: VertexOutput) -> FragmentOutput {
return vec4<f32>(1.0, 0.0, 0.0, 1.0); var out: FragmentOutput;
out.pixel_color = in.color;
return out;
} }

Loading…
Cancel
Save