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;
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;

View file

@ -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]);
}
}

View file

@ -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();

View file

@ -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);
}

View file

@ -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,10 +1154,20 @@ 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);
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(&model.model), // Actual data being pushed (can be array)
);
for (model.mesh_list.items) |mesh| {
// Buffers to bind
const vertex_buffers = [_]vk.Buffer{mesh.vertex_buffer};
// Offsets into buffers being bound
@ -1222,16 +1176,7 @@ pub const VulkanRenderer = struct {
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);
// 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)
);
command_buffer.bindIndexBuffer(mesh.index_buffer, 0, .uint32);
const descriptor_set_group = [_]vk.DescriptorSet{
self.descriptor_sets[current_image],
@ -1250,8 +1195,8 @@ pub const VulkanRenderer = struct {
);
// Execute a pipeline
// command_buffer.drawIndexed(mesh.index_count, 1, 0, 0, 0);
command_buffer.draw(mesh.vertex_count, 1, 0, 0);
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 {