render-zig

A 3D rendering engine written in Zig
git clone git://git.christianermann.dev/render-zig
Log | Files | Refs

commit dd54785a418716cb14026d20e4089d4da1690a8a
parent 520f7e4d8ff0e3eee977a6c32d3a37e1b499338f
Author: Christian Ermann <christianermann@gmail.com>
Date:   Fri,  6 Dec 2024 16:22:18 -0800

Add transforms

Diffstat:
Msrc/main.zig | 91++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
Asrc/transform.zig | 29+++++++++++++++++++++++++++++
2 files changed, 84 insertions(+), 36 deletions(-)

diff --git a/src/main.zig b/src/main.zig @@ -16,6 +16,7 @@ const Mesh = @import("mesh.zig"); const Camera = @import("camera.zig"); const input = @import("input.zig"); +const Transform = @import("transform.zig"); const load_obj = @import("load_obj.zig"); @@ -383,8 +384,7 @@ pub const MeshBufferOptions = struct { }; pub const MeshOptions = struct { - scale: f32 = 1.0, - offset: f32x3 = .{ 0, 0, 0 }, + transform: *Transform, data: *const Mesh, }; @@ -477,6 +477,12 @@ pub const MeshBuffer = struct { .{ .indirect = true, .copy_dst = true }, false, ), + .lines_instances = Buffer(MeshInstanceData).init( + options.n_meshes, + device, + .{ .storage = true, .copy_dst = true }, + false, + ), .meshes = std.ArrayList(RenderMesh).init(options.allocator), .lines = std.ArrayList(RenderLines).init(options.allocator), }; @@ -486,6 +492,7 @@ pub const MeshBuffer = struct { self: *MeshBuffer, positions: []const f32x4, indices: []const u32, + transform: *Transform, ) !*RenderLines { const num_vertices = positions.len; const num_indices = indices.len; @@ -493,7 +500,7 @@ pub const MeshBuffer = struct { const offset_p = try self.positions.allocWrite(positions, self.queue); const offset_i = try self.indices.allocWrite(indices, self.queue); - const instance_id = self.indirect.count(); + const instance_id = self.lines_indirect.count(); const indirect_args = [_][5]u32{.{ @intCast(num_indices), 1, @@ -506,8 +513,14 @@ pub const MeshBuffer = struct { const lines = RenderLines{ .num_vertices = num_vertices, .num_indices = num_indices, + .transform = transform, }; + const instances = [_]MeshInstanceData{ + lines.instanceData(), + }; + _ = try self.lines_instances.allocWrite(&instances, self.queue); + try self.lines.append(lines); return &self.lines.items[0]; } @@ -536,8 +549,7 @@ pub const MeshBuffer = struct { const mesh = RenderMesh{ .num_vertices = num_vertices, .num_indices = num_indices, - .scale = options.scale, - .offset = options.offset, + .transform = options.transform, }; const instances = [_]MeshInstanceData{ @@ -602,34 +614,39 @@ pub const MeshBuffer = struct { mesh.dirty = false; } } + + pub fn updateLines(self: *MeshBuffer) void { + for (self.lines.items, 0..) |*line, i| { + if (!line.dirty) { + continue; + } + const instances = [_]MeshInstanceData{line.instanceData()}; + self.lines_instances.write(&instances, self.queue, @intCast(i)); + line.dirty = false; + } + } }; pub const RenderLines = struct { num_vertices: usize, num_indices: usize, - scale: f32 = 1.0, - offset: f32x3 = .{ 0.0, 0.0, 0.0 }, + transform: *Transform, dirty: bool = false, - pub fn instanceData(self: *const RenderLines) InstanceData { - return InstanceData{ - .model_matrix = .{ - .{ self.scale, 0, 0, 0 }, - .{ 0, self.scale, 0, 0 }, - .{ 0, 0, self.scale, 0 }, - .{ self.offset[0], self.offset[1], self.offset[2], 1 }, - }, + pub fn instanceData(self: *const RenderLines) MeshInstanceData { + return MeshInstanceData{ + .model_matrix = self.transform.matrix(), .material = undefined, }; } pub fn setScale(self: *RenderMesh, scale: f32) void { - self.scale = scale; + self.transform.scale = .{ scale, scale, scale }; self.dirty = true; } pub fn setOffset(self: *RenderMesh, offset: f32x3) void { - self.offset = offset; + self.transform.offset = offset; self.dirty = true; } }; @@ -637,30 +654,24 @@ pub const RenderLines = struct { pub const RenderMesh = struct { num_vertices: usize, num_indices: usize, - scale: f32 = 1.0, - offset: f32x3 = .{ 0.0, 0.0, 0.0 }, + transform: *Transform, material: Material = undefined, dirty: bool = false, - pub fn instanceData(self: *const RenderMesh) InstanceData { - return InstanceData{ - .model_matrix = .{ - .{ self.scale, 0, 0, 0 }, - .{ 0, self.scale, 0, 0 }, - .{ 0, 0, self.scale, 0 }, - .{ self.offset[0], self.offset[1], self.offset[2], 1 }, - }, + pub fn instanceData(self: *const RenderMesh) MeshInstanceData { + return MeshInstanceData{ + .model_matrix = self.transform.matrix(), .material = self.material, }; } pub fn setScale(self: *RenderMesh, scale: f32) void { - self.scale = scale; + self.transform.scale = .{ scale, scale, scale }; self.dirty = true; } pub fn setOffset(self: *RenderMesh, offset: f32x3) void { - self.offset = offset; + self.transform.offset = offset; self.dirty = true; } @@ -729,22 +740,23 @@ pub fn main() !void { const cbunny_mesh = try buildClusters(allocator, &bunny_mesh, 64, 126); std.log.info("num clusters: {}", .{cluster_mesh.descriptors.?.len}); + var transform_1 = Transform{}; + var transform_2 = Transform{}; + var render_mesh = try mesh_buffer.initMesh(&.{ .data = &cluster_mesh, - .scale = 1, - .offset = .{ 0, 0, 0 }, + .transform = &transform_1, }, allocator); _ = try mesh_buffer.initMesh(&.{ .data = &cbunny_mesh, - .scale = 1, - .offset = .{ 0, 0, 0 }, + .transform = &transform_2, }, allocator); const corners = mesh.bboxVertices(); - const indices = Mesh.bboxIndices(); + const bbox_indices = Mesh.bboxIndices(); - _ = try mesh_buffer.initLines(&corners, &indices); + var lines = try mesh_buffer.initLines(&corners, &bbox_indices, &transform_1); var rp = try MeshRenderPipeline.init(&app, &mesh_buffer, &textures, "shaders/mesh_clusters.wgsl"); @@ -753,7 +765,7 @@ pub fn main() !void { .{ .positions = &mesh_buffer.positions, .indices = &mesh_buffer.indices, - .instances = &mesh_buffer.instances, + .instances = &mesh_buffer.lines_instances, .indirect = &mesh_buffer.lines_indirect, }, "shaders/lines.wgsl", @@ -807,6 +819,13 @@ pub fn main() !void { camera.invProj(&skybox_uniform.inv_proj); app.queue.writeBuffer(skybox.uniform_buffer, 0, &[1]SkyBoxRenderPipeline.UniformData{skybox_uniform}); + transform_1.translate(.{ 0.01, 0, 0 }); + render_mesh.dirty = true; + lines.dirty = true; + + mesh_buffer.updateMeshes(); + mesh_buffer.updateLines(); + try app.frame(&passes); } } diff --git a/src/transform.zig b/src/transform.zig @@ -0,0 +1,29 @@ +const std = @import("std"); +const gpu = @import("mach_gpu"); + +const f32x3 = @import("main.zig").f32x3; +const mat4 = @import("main.zig").mat4; + +const Self = @This(); + +scale: f32x3 = .{ 1, 1, 1 }, +offset: f32x3 = .{ 0, 0, 0 }, +dirty: bool = false, + +pub fn dirty(self: *const Self) bool { + return self.dirty; +} + +pub fn matrix(self: *const Self) mat4 { + return .{ + .{ self.scale[0], 0, 0, 0 }, + .{ 0, self.scale[1], 0, 0 }, + .{ 0, 0, self.scale[2], 0 }, + .{ self.offset[0], self.offset[1], self.offset[2], 1 }, + }; +} + +pub fn translate(self: *Self, translation: f32x3) void { + self.offset += translation; + self.dirty = true; +}