Load the 3D object properly
This commit is contained in:
parent
d81957a096
commit
2e08987c83
5 changed files with 71 additions and 125 deletions
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
|
14
src/main.zig
14
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();
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue