Load the 3D object properly

This commit is contained in:
Przemyslaw Gasinski 2024-08-19 15:32:08 +02:00
parent d81957a096
commit 2e08987c83
5 changed files with 71 additions and 125 deletions

View file

@ -49,7 +49,7 @@ pub fn new(
self.allocator = allocator; self.allocator = allocator;
try self.createVertexBuffer(transfer_queue, transfer_command_pool, vertices); 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.ubo_model = .{ .model = zm.identity() };
self.tex_id = tex_id; self.tex_id = tex_id;

View file

@ -40,7 +40,7 @@ pub fn getMesh(self: Self, idx: usize) !Mesh {
return self.mesh_list.items[idx]; 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 // Create 1:1 sized list of textures
var texture_list = try std.ArrayList(?[]const u8).initCapacity(allocator, scene.mNumMaterials); 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, null,
null, null,
) != ai.AI_SUCCESS) { ) == ai.AI_SUCCESS) {
// Cut of any directory information already present // Cut of any directory information already present
var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/"); var it = std.mem.splitBackwardsAny(u8, &path.data, "\\/");
if (it.next()) |filename| { if (it.next()) |filename| {
// texture_list.items[i] = filename; texture_list.appendAssumeCapacity(try allocator.dupe(u8, filename));
texture_list.appendAssumeCapacity(filename);
} }
} else { } else {
texture_list.appendAssumeCapacity(null); texture_list.appendAssumeCapacity(null);
@ -128,7 +127,7 @@ pub fn loadNode(
); );
defer new_list.deinit(); defer new_list.deinit();
try mesh_list.appendSlice(try new_list.toOwnedSlice()); try mesh_list.appendSlice(new_list.items[0..]);
} }
return mesh_list; return mesh_list;
@ -171,12 +170,12 @@ pub fn loadMesh(
} }
// Iterate over indices through faces and copy across // Iterate over indices through faces and copy across
for (0..mesh.mNumFaces - 1) |i| { for (0..mesh.mNumFaces) |i| {
// Get a face // Get a face
const face = mesh.mFaces[i]; const face = mesh.mFaces[i];
// Go through face's indices and add to list // 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]); try indices.append(face.mIndices[j]);
} }
} }

View file

@ -70,6 +70,8 @@ pub fn main() !void {
var angle: f32 = 0.0; var angle: f32 = 0.0;
const model_handle = try vulkan_renderer.createMeshModel("tescoPiwo.obj");
mainLoop: while (true) { mainLoop: while (true) {
while (sdl.pollEvent()) |ev| { while (sdl.pollEvent()) |ev| {
switch (ev) { switch (ev) {
@ -91,16 +93,8 @@ pub fn main() !void {
angle -= 360.0; angle -= 360.0;
} }
// var first_model = zm.rotationZ(angle); const rotate = zm.mul(zm.identity(), zm.rotationY(angle));
// var second_model = zm.rotationZ(-angle * 2); try vulkan_renderer.updateModel(model_handle, rotate);
// 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);
try vulkan_renderer.draw(); try vulkan_renderer.draw();

View file

@ -9,6 +9,5 @@ layout(location = 0) out vec4 outColour;
layout(set = 1, binding = 0) uniform sampler2D textureSampler; layout(set = 1, binding = 0) uniform sampler2D textureSampler;
void main() { void main() {
// outColour = texture(textureSampler, fragTex); outColour = texture(textureSampler, fragTex);
outColour = vec4(fragCol, 1.0);
} }

View file

@ -5,7 +5,7 @@ const builtin = @import("builtin");
const shaders = @import("shaders"); const shaders = @import("shaders");
const zm = @import("zmath"); const zm = @import("zmath");
const img = @import("zstbi"); const img = @import("zstbi");
const assimp = @import("assimp.zig").c; const ai = @import("assimp.zig").c;
const StringUtils = @import("string_utils.zig"); const StringUtils = @import("string_utils.zig");
const Utilities = @import("utilities.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 validation_layers = [_][*:0]const u8{"VK_LAYER_KHRONOS_validation"};
const MAX_FRAME_DRAWS: u32 = 2; const MAX_FRAME_DRAWS: u32 = 2;
const MAX_OBJECTS: u32 = 2; const MAX_OBJECTS: u32 = 20;
const apis: []const vk.ApiInfo = &.{ const apis: []const vk.ApiInfo = &.{
vk.features.version_1_0, vk.features.version_1_0,
@ -62,9 +62,6 @@ pub const VulkanRenderer = struct {
current_frame: u32 = 0, current_frame: u32 = 0,
// Scene objects
meshes: std.ArrayList(Mesh),
// Scene settings // Scene settings
ubo_view_projection: UboViewProjection, ubo_view_projection: UboViewProjection,
@ -164,7 +161,6 @@ pub const VulkanRenderer = struct {
try self.createSynchronisation(); try self.createSynchronisation();
self.meshes = std.ArrayList(Mesh).init(self.allocator);
self.image_files = std.ArrayList(img.Image).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_images = std.ArrayList(vk.Image).init(self.allocator);
self.texture_image_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator); self.texture_image_memory = std.ArrayList(vk.DeviceMemory).init(self.allocator);
@ -180,7 +176,7 @@ pub const VulkanRenderer = struct {
100.0, 100.0,
); );
self.ubo_view_projection.view = zm.lookAtRh( 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, 0.0, 0.0, 0.0 },
zm.Vec{ 0.0, 1.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 // Invert y scale
self.ubo_view_projection.projection[1][1] *= -1; self.ubo_view_projection.projection[1][1] *= -1;
// Create meshes _ = try self.createTexture("giraffe.png");
// 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 };
return self; return self;
} }
pub fn updateModel(self: *Self, model_id: u32, new_model: zm.Mat) !void { pub fn updateModel(self: *Self, model_id: usize, new_model: zm.Mat) !void {
if (model_id < self.meshes.items.len) { if (model_id < self.model_list.items.len) {
self.meshes.items[model_id].ubo_model.model = new_model; 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.vp_uniform_buffer_memory);
self.allocator.free(self.descriptor_sets); self.allocator.free(self.descriptor_sets);
for (self.meshes.items) |mesh| {
mesh.destroyBuffers();
}
self.meshes.deinit();
for (0..MAX_FRAME_DRAWS) |i| { for (0..MAX_FRAME_DRAWS) |i| {
self.device.destroySemaphore(self.render_finished[i], null); self.device.destroySemaphore(self.render_finished[i], null);
self.device.destroySemaphore(self.image_available[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) .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 .polygon_mode = .fill, // How to handle filling points between vertices
.line_width = 1.0, // How thick the lines should be when drawn .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 .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_enable = vk.FALSE, // Whether to add depth bias to fragments (good for stopping "shadow acne" in shadow mapping)
.depth_bias_constant_factor = 0, .depth_bias_constant_factor = 0,
@ -1210,48 +1154,49 @@ pub const VulkanRenderer = struct {
command_buffer.setViewport(0, 1, @ptrCast(&self.viewport)); command_buffer.setViewport(0, 1, @ptrCast(&self.viewport));
command_buffer.setScissor(0, 1, @ptrCast(&self.scissor)); command_buffer.setScissor(0, 1, @ptrCast(&self.scissor));
for (self.meshes.items) |mesh| { // Bind pipeline to be used in render pass
// Bind pipeline to be used in render pass command_buffer.bindPipeline(.graphics, self.graphics_pipeline);
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);
for (self.model_list.items) |model| {
// Push constants to given shader stage directly (no buffer) // Push constants to given shader stage directly (no buffer)
command_buffer.pushConstants( command_buffer.pushConstants(
self.pipeline_layout, self.pipeline_layout,
.{ .vertex_bit = true }, // Stage to push constants to .{ .vertex_bit = true }, // Stage to push constants to
0, // Offset of push constants to update 0, // Offset of push constants to update
@sizeOf(Model), // Size of data being pushed @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{ for (model.mesh_list.items) |mesh| {
self.descriptor_sets[current_image], // Buffers to bind
self.sampler_descriptor_sets.items[mesh.tex_id], 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 // Bind mesh index buffer, with 0 offset and using the uint32 type
command_buffer.bindDescriptorSets( command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32);
.graphics,
self.pipeline_layout,
0,
@intCast(descriptor_set_group.len),
&descriptor_set_group,
0,
null,
);
// Execute a pipeline const descriptor_set_group = [_]vk.DescriptorSet{
// command_buffer.drawIndexed(mesh.index_count, 1, 0, 0, 0); self.descriptor_sets[current_image],
command_buffer.draw(mesh.vertex_count, 1, 0, 0); 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 // End render pass
@ -1623,33 +1568,40 @@ pub const VulkanRenderer = struct {
return descriptor_loc; 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); const path = try StringUtils.concat("assets/models/", model_file, self.allocator);
defer self.allocator.free(path); defer self.allocator.free(path);
// Import model scene // Import model scene
const scene = assimp.aiImportFile( const scene = ai.aiImportFile(
path.ptr, 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 // Get array of all materials with 1:1 ID placement
const texture_names = try MeshModel.loadMaterials(self.allocator, scene.*); const texture_names = try MeshModel.loadMaterials(self.allocator, scene);
defer texture_names.deinit(); 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 // 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); var mat_to_tex = try std.ArrayList(u32).initCapacity(self.allocator, texture_names.items.len);
defer mat_to_tex.deinit(); defer mat_to_tex.deinit();
// Loop over texture names and create textures for them // Loop over texture names and create textures for them
for (0..texture_names.items.len) |i| { for (texture_names.items) |texture_name| {
if (texture_names.items[i]) |texture_name| { if (texture_name != null) {
// Create texture and set value to index of new texture // 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 { } else {
// If material had no texture, set to 0 to indicate no texture. Texture 0 will be reserver for a default texture // 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); mat_to_tex.appendAssumeCapacity(0);
} }
} }
@ -1670,6 +1622,8 @@ pub const VulkanRenderer = struct {
// Create a mesh model and add to our list // Create a mesh model and add to our list
const mesh_model = MeshModel.new(self.allocator, model_meshes); const mesh_model = MeshModel.new(self.allocator, model_meshes);
try self.model_list.append(mesh_model); try self.model_list.append(mesh_model);
return self.model_list.items.len - 1;
} }
fn createTextureDescriptor(self: *Self, texture_image: vk.ImageView) !u32 { fn createTextureDescriptor(self: *Self, texture_image: vk.ImageView) !u32 {