diff --git a/src/Mesh.zig b/src/Mesh.zig index 1625803..74e52d4 100644 --- a/src/Mesh.zig +++ b/src/Mesh.zig @@ -49,7 +49,7 @@ pub fn new( self.allocator = allocator; try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices); - // try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices); + try self.createIndexBuffer(transfer_queue, transfer_command_pool, indices); self.ubo_model = .{ .model = zm.identity() }; self.tex_id = tex_id; diff --git a/src/MeshModel.zig b/src/MeshModel.zig index d6df60d..4e7ca77 100644 --- a/src/MeshModel.zig +++ b/src/MeshModel.zig @@ -40,7 +40,7 @@ pub fn getMesh(self: Self, idx: usize) !Mesh { return self.mesh_list.items[idx]; } -pub fn loadMaterials(allocator: std.mem.Allocator, scene: ai.aiScene) !std.ArrayList(?[]const u8) { +pub fn loadMaterials(allocator: std.mem.Allocator, scene: *const ai.aiScene) !std.ArrayList(?[]const u8) { // Create 1:1 sized list of textures var texture_list = try std.ArrayList(?[]const u8).initCapacity(allocator, scene.mNumMaterials); @@ -67,12 +67,11 @@ pub fn loadMaterials(allocator: std.mem.Allocator, scene: ai.aiScene) !std.Array null, null, null, - ) != ai.AI_SUCCESS) { + ) == ai.AI_SUCCESS) { // Cut of any directory information already present var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/"); if (it.next()) |filename| { - // texture_list.items[i] = filename; - texture_list.appendAssumeCapacity(filename); + texture_list.appendAssumeCapacity(try allocator.dupe(u8, filename)); } } else { texture_list.appendAssumeCapacity(null); @@ -128,7 +127,7 @@ pub fn loadNode( ); defer new_list.deinit(); - try mesh_list.appendSlice(try new_list.toOwnedSlice()); + try mesh_list.appendSlice(new_list.items[0..]); } return mesh_list; @@ -171,12 +170,12 @@ pub fn loadMesh( } // Iterate over indices through faces and copy across - for (0..mesh.mNumFaces - 1) |i| { + for (0..mesh.mNumFaces) |i| { // Get a face const face = mesh.mFaces[i]; // Go through face's indices and add to list - for (0..face.mNumIndices - 1) |j| { + for (0..face.mNumIndices) |j| { try indices.append(face.mIndices[j]); } } diff --git a/src/main.zig b/src/main.zig index e6538d5..7deaab8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -70,6 +70,8 @@ pub fn main() !void { var angle: f32 = 0.0; + const model_handle = try vulkan_renderer.createMeshModel("tescoPiwo.obj"); + mainLoop: while (true) { while (sdl.pollEvent()) |ev| { switch (ev) { @@ -91,16 +93,8 @@ pub fn main() !void { angle -= 360.0; } - // var first_model = zm.rotationZ(angle); - // var second_model = zm.rotationZ(-angle * 2); - - // first_model = zm.mul(first_model, zm.translation(1.0, 0.0, -2.5)); - // second_model = zm.mul(second_model, zm.translation(-1.0, 0.0, -4.5)); - - // const first_model = zm.scaling(2.0, 2.0, 0.0); - - // try vulkan_renderer.updateModel(0, first_model); - // try vulkan_renderer.updateModel(1, second_model); + const rotate = zm.mul(zm.identity(), zm.rotationY(angle)); + try vulkan_renderer.updateModel(model_handle, rotate); try vulkan_renderer.draw(); diff --git a/src/shaders/shader.frag b/src/shaders/shader.frag index 8a57d5b..3c347a6 100644 --- a/src/shaders/shader.frag +++ b/src/shaders/shader.frag @@ -9,6 +9,5 @@ layout(location = 0) out vec4 outColour; layout(set = 1, binding = 0) uniform sampler2D textureSampler; void main() { - // outColour = texture(textureSampler, fragTex); - outColour = vec4(fragCol, 1.0); + outColour = texture(textureSampler, fragTex); } diff --git a/src/vulkan_renderer.zig b/src/vulkan_renderer.zig index 3d189ae..f6b8b8f 100644 --- a/src/vulkan_renderer.zig +++ b/src/vulkan_renderer.zig @@ -5,7 +5,7 @@ const builtin = @import("builtin"); const shaders = @import("shaders"); const zm = @import("zmath"); const img = @import("zstbi"); -const assimp = @import("assimp.zig").c; +const ai = @import("assimp.zig").c; const StringUtils = @import("string_utils.zig"); const Utilities = @import("utilities.zig"); @@ -21,7 +21,7 @@ const enable_validation_layers = builtin.mode == .Debug; const validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"}; const MAX_FRAME_DRAWS: u32 = 2; -const MAX_OBJECTS: u32 = 2; +const MAX_OBJECTS: u32 = 20; const apis: []const vk.ApiInfo = &.{ vk.features.version_1_0, @@ -62,9 +62,6 @@ pub const VulkanRenderer = struct { current_frame: u32 = 0, - // Scene objects - meshes: std.ArrayList(Mesh), - // Scene settings ubo_view_projection: UboViewProjection, @@ -164,7 +161,6 @@ pub const VulkanRenderer = struct { try self.createSynchronisation(); - self.meshes = std.ArrayList(Mesh).init(self.allocator); self.image_files = std.ArrayList(img.Image).init(self.allocator); self.texture_images = std.ArrayList(vk.Image).init(self.allocator); self.texture_image_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator); @@ -180,7 +176,7 @@ pub const VulkanRenderer = struct { 100.0, ); self.ubo_view_projection.view = zm.lookAtRh( - zm.Vec{ 0.0, 0.0, 2.0, 0.0 }, + zm.Vec{ 0.0, 2.0, 2.0, 0.0 }, zm.Vec{ 0.0, 0.0, 0.0, 0.0 }, zm.Vec{ 0.0, 1.0, 0.0, 0.0 }, ); @@ -188,61 +184,14 @@ pub const VulkanRenderer = struct { // Invert y scale self.ubo_view_projection.projection[1][1] *= -1; - // Create meshes - // Vertex Data - // var mesh_vertices = [_]Vertex{ - // .{ .pos = .{ -0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 }, .tex = .{ 1.0, 1.0 } }, // 0 - // .{ .pos = .{ -0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 }, .tex = .{ 1.0, 0.0 } }, // 1 - // .{ .pos = .{ 0.4, -0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 }, .tex = .{ 0.0, 0.0 } }, // 2 - // .{ .pos = .{ 0.4, 0.4, 0.0 }, .col = .{ 1.0, 0.0, 0.0 }, .tex = .{ 0.0, 1.0 } }, // 3 - // }; - // var mesh_vertices2 = [_]Vertex{ - // .{ .pos = .{ -0.25, 0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 }, .tex = .{ 1.0, 1.0 } }, // 0 - // .{ .pos = .{ -0.25, -0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 }, .tex = .{ 1.0, 0.0 } }, // 1 - // .{ .pos = .{ 0.25, -0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 }, .tex = .{ 0.0, 0.0 } }, // 2 - // .{ .pos = .{ 0.25, 0.6, 0.0 }, .col = .{ 0.0, 0.0, 1.0 }, .tex = .{ 0.0, 1.0 } }, // 3 - // }; - - try self.createMeshModel("cornell_box.obj"); - - // Index Data - // const mesh_indices = [_]u32{ - // 0, 1, 2, - // 2, 3, 0, - // }; - - // const first_mesh = try Mesh.new( - // self.instance, - // self.physical_device, - // self.device, - // self.graphics_queue.handle, - // self.graphics_command_pool, - // &mesh_vertices, - // &mesh_indices, - // try self.createTexture("test.png"), - // self.allocator, - // ); - - // const second_mesh = try Mesh.new( - // self.instance, - // self.physical_device, - // self.device, - // self.graphics_queue.handle, - // self.graphics_command_pool, - // &mesh_vertices2, - // &mesh_indices, - // try self.createTexture("giraffe.png"), - // self.allocator, - // ); - - // self.meshes = [_]Mesh{ first_mesh, second_mesh }; + _ = try self.createTexture("giraffe.png"); return self; } - pub fn updateModel(self: *Self, model_id: u32, new_model: zm.Mat) !void { - if (model_id < self.meshes.items.len) { - self.meshes.items[model_id].ubo_model.model = new_model; + pub fn updateModel(self: *Self, model_id: usize, new_model: zm.Mat) !void { + if (model_id < self.model_list.items.len) { + self.model_list.items[model_id].model = new_model; } } @@ -353,11 +302,6 @@ pub const VulkanRenderer = struct { self.allocator.free(self.vp_uniform_buffer_memory); self.allocator.free(self.descriptor_sets); - for (self.meshes.items) |mesh| { - mesh.destroyBuffers(); - } - self.meshes.deinit(); - for (0..MAX_FRAME_DRAWS) |i| { self.device.destroySemaphore(self.render_finished[i], null); self.device.destroySemaphore(self.image_available[i], null); @@ -860,7 +804,7 @@ pub const VulkanRenderer = struct { .rasterizer_discard_enable = vk.FALSE, // Whether to discard data and skip rasterizer (never creates fragments) .polygon_mode = .fill, // How to handle filling points between vertices .line_width = 1.0, // How thick the lines should be when drawn - .cull_mode = .{ .back_bit = true }, // Which face of a triangle to cull + .cull_mode = .{ .back_bit = false }, // Which face of a triangle to cull .front_face = .counter_clockwise, // Winding to determine which side is front .depth_bias_enable = vk.FALSE, // Whether to add depth bias to fragments (good for stopping "shadow acne" in shadow mapping) .depth_bias_constant_factor = 0, @@ -1210,48 +1154,49 @@ pub const VulkanRenderer = struct { command_buffer.setViewport(0, 1, @ptrCast(&self.viewport)); command_buffer.setScissor(0, 1, @ptrCast(&self.scissor)); - for (self.meshes.items) |mesh| { - // Bind pipeline to be used in render pass - command_buffer.bindPipeline(.graphics, self.graphics_pipeline); - - // Buffers to bind - const vertex_buffers = [_]vk.Buffer{mesh.vertex_buffer}; - // Offsets into buffers being bound - const offsets = [_]vk.DeviceSize{0}; - // Command to bind vertex buffer before drawing with them - command_buffer.bindVertexBuffers(0, 1, &vertex_buffers, &offsets); - - // Bind mesh index buffer, with 0 offset and using the uint32 type - // command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32); + // Bind pipeline to be used in render pass + command_buffer.bindPipeline(.graphics, self.graphics_pipeline); + for (self.model_list.items) |model| { // Push constants to given shader stage directly (no buffer) command_buffer.pushConstants( self.pipeline_layout, .{ .vertex_bit = true }, // Stage to push constants to 0, // Offset of push constants to update @sizeOf(Model), // Size of data being pushed - @ptrCast(&mesh.ubo_model.model), // Actual data being pushed (can be array) + @ptrCast(&model.model), // Actual data being pushed (can be array) ); - const descriptor_set_group = [_]vk.DescriptorSet{ - self.descriptor_sets[current_image], - self.sampler_descriptor_sets.items[mesh.tex_id], - }; + for (model.mesh_list.items) |mesh| { + // Buffers to bind + const vertex_buffers = [_]vk.Buffer{mesh.vertex_buffer}; + // Offsets into buffers being bound + const offsets = [_]vk.DeviceSize{0}; + // Command to bind vertex buffer before drawing with them + command_buffer.bindVertexBuffers(0, 1, &vertex_buffers, &offsets); - // Bind descriptor sets - command_buffer.bindDescriptorSets( - .graphics, - self.pipeline_layout, - 0, - @intCast(descriptor_set_group.len), - &descriptor_set_group, - 0, - null, - ); + // Bind mesh index buffer, with 0 offset and using the uint32 type + command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32); - // Execute a pipeline - // command_buffer.drawIndexed(mesh.index_count, 1, 0, 0, 0); - command_buffer.draw(mesh.vertex_count, 1, 0, 0); + const descriptor_set_group = [_]vk.DescriptorSet{ + self.descriptor_sets[current_image], + self.sampler_descriptor_sets.items[mesh.tex_id], + }; + + // Bind descriptor sets + command_buffer.bindDescriptorSets( + .graphics, + self.pipeline_layout, + 0, + @intCast(descriptor_set_group.len), + &descriptor_set_group, + 0, + null, + ); + + // Execute a pipeline + command_buffer.drawIndexed(mesh.index_count, 1, 0, 0, 0); + } } // End render pass @@ -1623,33 +1568,40 @@ pub const VulkanRenderer = struct { return descriptor_loc; } - fn createMeshModel(self: *Self, model_file: []const u8) !void { + pub fn createMeshModel(self: *Self, model_file: []const u8) !usize { const path = try StringUtils.concat("assets/models/", model_file, self.allocator); defer self.allocator.free(path); // Import model scene - const scene = assimp.aiImportFile( + const scene = ai.aiImportFile( path.ptr, - assimp.aiProcess_Triangulate | assimp.aiProcess_FlipUVs | assimp.aiProcess_JoinIdenticalVertices, + ai.aiProcess_Triangulate | ai.aiProcess_FlipUVs | ai.aiProcess_JoinIdenticalVertices, ); + defer ai.aiReleaseImport(scene); // Get array of all materials with 1:1 ID placement - const texture_names = try MeshModel.loadMaterials(self.allocator, scene.*); - defer texture_names.deinit(); + const texture_names = try MeshModel.loadMaterials(self.allocator, scene); + defer { + for (0..texture_names.items.len) |i| { + if (texture_names.items[i]) |texture_name| { + self.allocator.free(texture_name); + } + } + texture_names.deinit(); + } // Conversion from the material list IDs to our descriptor array IDs var mat_to_tex = try std.ArrayList(u32).initCapacity(self.allocator, texture_names.items.len); defer mat_to_tex.deinit(); // Loop over texture names and create textures for them - for (0..texture_names.items.len) |i| { - if (texture_names.items[i]) |texture_name| { + for (texture_names.items) |texture_name| { + if (texture_name != null) { // Create texture and set value to index of new texture - // mat_to_tex.items[i] = try self.createTexture(texture_name); - mat_to_tex.appendAssumeCapacity(try self.createTexture(texture_name)); + mat_to_tex.appendAssumeCapacity(try self.createTexture(texture_name.?)); } else { + // If material had no texture, set to 0 to indicate no texture. Texture 0 will be reserver for a default texture - // mat_to_tex.items[i] = 0; mat_to_tex.appendAssumeCapacity(0); } } @@ -1670,6 +1622,8 @@ pub const VulkanRenderer = struct { // Create a mesh model and add to our list const mesh_model = MeshModel.new(self.allocator, model_meshes); try self.model_list.append(mesh_model); + + return self.model_list.items.len - 1; } fn createTextureDescriptor(self: *Self, texture_image: vk.ImageView) !u32 {