render-zig

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

commit 54f8213cf6fe2f6650294d54ab5697dcc3bf31b1
parent aa6b89c4a2fc1b1bb51d7c182486abe07b22e1c9
Author: Christian Ermann <christianermann@gmail.com>
Date:   Sat, 20 Jul 2024 11:22:47 -0400

Unify mesh types

Diffstat:
Msrc/main.zig | 120++++++++++++++++++++++++++++++-------------------------------------------------
Msrc/mesh.zig | 7+++++++
Msrc/meshlets.zig | 21+++------------------
3 files changed, 55 insertions(+), 93 deletions(-)

diff --git a/src/main.zig b/src/main.zig @@ -15,7 +15,6 @@ const Mesh = @import("mesh.zig"); const Camera = @import("camera.zig"); const input = @import("input.zig"); -const ClusterMesh = @import("meshlets.zig").ClusterMesh; const load_obj = @import("load_obj.zig"); @@ -384,12 +383,6 @@ pub const MeshOptions = struct { data: *const Mesh, }; -pub const ClusterMeshOptions = struct { - scale: f32 = 1.0, - offset: f32x3 = .{ 0, 0, 0 }, - data: *const ClusterMesh, -}; - pub const MeshBuffer = struct { device: *gpu.Device, queue: *gpu.Queue, @@ -466,62 +459,17 @@ pub const MeshBuffer = struct { }; } - pub fn initMesh(self: *MeshBuffer, options: *const MeshOptions) !*RenderMesh { - const mesh_data = options.data; - const num_vertices = mesh_data.positions.len; - const num_indices = mesh_data.indices.len; - std.log.info("init mesh with {} vertices, {} indices", .{ num_vertices, num_indices }); - - const offset_p = try self.positions.allocWrite(mesh_data.positions, self.queue); - const offset_n = try self.normals.allocWrite(mesh_data.normals, self.queue); - const offset_t = try self.tex_coords.allocWrite(mesh_data.tex_coords, self.queue); - _ = try self.tangents.allocWrite(mesh_data.tangents, self.queue); - _ = try self.bitangents.allocWrite(mesh_data.bitangents, self.queue); - std.log.info("pnt offsets: {}, {}, {} bytes", .{ offset_p, offset_n, offset_t }); - - const offset_i = try self.indices.allocWrite(mesh_data.indices, self.queue); - std.log.info("idx offset: {} bytes", .{offset_i}); - - const mesh = RenderMesh{ - .num_vertices = num_vertices, - .num_indices = num_indices, - .scale = options.scale, - .offset = options.offset, - }; - - const instances = [_]InstanceData{ - mesh.instanceData(), - }; - const offset_u = try self.instances.allocWrite(&instances, self.queue); - std.log.info("uniform offset: {} bytes", .{offset_u}); - - const mesh_id: u32 = @intCast(self.meshes.items.len); - const indirect_args = [1][5]u32{.{ - @intCast(num_indices), - 1, - offset_i / self.indices.attrib_size, - offset_p / self.positions.attrib_size, - mesh_id, - }}; - std.log.info("indirect: {any}", .{indirect_args}); - _ = try self.indirect.allocWrite(&indirect_args, self.queue); - - try self.meshes.append(mesh); - return &self.meshes.items[0]; - } - - pub fn initClusterMesh( + pub fn initMesh( self: *MeshBuffer, - options: *const ClusterMeshOptions, + options: *const MeshOptions, allocator: std.mem.Allocator, ) !*RenderMesh { const mesh_data = options.data; const num_vertices = mesh_data.positions.len; const num_indices = mesh_data.indices.len; - const num_clusters = mesh_data.descriptors.len; std.log.info( - "init mesh with {} vertices, {} indices, {} clusters", - .{ num_vertices, num_indices, num_clusters }, + "init mesh with {} vertices, {} indices", + .{ num_vertices, num_indices }, ); const offset_p = try self.positions.allocWrite(mesh_data.positions, self.queue); @@ -544,21 +492,35 @@ pub const MeshBuffer = struct { }; _ = try self.instances.allocWrite(&instances, self.queue); - const indirect_args = try allocator.alloc([5]u32, num_clusters); - defer allocator.free(indirect_args); - - var mesh_id: u32 = @intCast(self.meshes.items.len); - for (mesh_data.descriptors, 0..) |descriptor, i| { - indirect_args[i] = .{ - @intCast(descriptor.num_triangles * 3), + if (mesh_data.descriptors != null) { + const descriptors = mesh_data.descriptors.?; + const num_clusters = descriptors.len; + const indirect_args = try allocator.alloc([5]u32, num_clusters); + defer allocator.free(indirect_args); + + var instance_id = self.indirect.count(); + for (descriptors, 0..) |descriptor, i| { + indirect_args[i] = .{ + @intCast(descriptor.num_triangles * 3), + 1, + offset_i + descriptor.offset, + offset_p, + instance_id, + }; + instance_id += 1; + } + _ = try self.indirect.allocWrite(indirect_args, self.queue); + } else { + const instance_id = self.indirect.count(); + const indirect_args = [_][5]u32{.{ + @intCast(num_indices), 1, - offset_i + descriptor.offset, + offset_i, offset_p, - mesh_id, - }; - mesh_id += 1; + instance_id, + }}; + _ = try self.indirect.allocWrite(&indirect_args, self.queue); } - _ = try self.indirect.allocWrite(indirect_args, self.queue); try self.meshes.append(mesh); return &self.meshes.items[0]; @@ -646,7 +608,7 @@ pub fn main() !void { var mesh_buffer = MeshBuffer.init(.{ .device = app.device, .queue = app.queue, - .n_meshes = 200, + .n_meshes = 500, .n_vertices = 60000, .n_indices = 60000, .allocator = allocator, @@ -657,24 +619,32 @@ pub fn main() !void { .path = "Cottage_Clean/cottage.obj", }); - //var bunny_mesh = try load_obj.loadFile(.{ - // .allocator = allocator, - // .path = "bunny-fixed.obj", - //}); + var bunny_mesh = try load_obj.loadFile(.{ + .allocator = allocator, + .path = "teapot.obj", + }); const optimizeMesh = @import("forsyth_optimize.zig").optimize; try optimizeMesh(allocator, &mesh, 32, .{}); + try optimizeMesh(allocator, &bunny_mesh, 32, .{}); const buildClusters = @import("meshlets.zig").buildClusters; const cluster_mesh = try buildClusters(allocator, &mesh, 64, 126); - std.log.info("num clusters: {}", .{cluster_mesh.descriptors.len}); + const cbunny_mesh = try buildClusters(allocator, &bunny_mesh, 64, 126); + std.log.info("num clusters: {}", .{cluster_mesh.descriptors.?.len}); - var render_mesh = try mesh_buffer.initClusterMesh(&.{ + var render_mesh = try mesh_buffer.initMesh(&.{ .data = &cluster_mesh, .scale = 1, .offset = .{ 0, 0, 0 }, }, allocator); + _ = try mesh_buffer.initMesh(&.{ + .data = &cbunny_mesh, + .scale = 1, + .offset = .{ 0, 0, 0 }, + }, allocator); + var rp = try MeshRenderPipeline.init(&app, &mesh_buffer, &textures, "shaders/mesh_clusters.wgsl"); const material = try Material.init( diff --git a/src/mesh.zig b/src/mesh.zig @@ -9,3 +9,10 @@ tex_coords: []f32x3, tangents: []f32x3, bitangents: []f32x3, indices: []u32, +descriptors: ?[]MeshletDescriptor = null, + +pub const MeshletDescriptor = struct { + offset: u32, + num_vertices: u32, + num_triangles: u32, +}; diff --git a/src/meshlets.zig b/src/meshlets.zig @@ -2,32 +2,17 @@ const std = @import("std"); const assert = std.debug.assert; const Mesh = @import("mesh.zig"); +const MeshletDescriptor = Mesh.MeshletDescriptor; const f32x3 = @Vector(3, f32); const f32x4 = @Vector(4, f32); -pub const ClusterDescriptor = struct { - offset: u32, - num_vertices: u32, - num_triangles: u32, -}; - -pub const ClusterMesh = struct { - positions: []f32x4, - normals: []f32x3, - tex_coords: []f32x3, - tangents: []f32x3, - bitangents: []f32x3, - indices: []u32, - descriptors: []ClusterDescriptor, -}; - pub fn buildClusters( allocator: std.mem.Allocator, mesh: *const Mesh, max_vertices: u32, max_triangles: u32, -) !ClusterMesh { +) !Mesh { // Only triangle meshes are supported assert(mesh.indices.len % 3 == 0); // Must have at least one triangle @@ -42,7 +27,7 @@ pub fn buildClusters( @memset(unused, 1); const indices = try allocator.alloc(u32, mesh.indices.len); - var descriptors = std.ArrayList(ClusterDescriptor).init(allocator); + var descriptors = std.ArrayList(MeshletDescriptor).init(allocator); defer descriptors.deinit(); var num_vertices: u32 = 0;