From dcb2ee0584bd6817e17d1f510e893a6ac742be9e Mon Sep 17 00:00:00 2001 From: Lorenzo Torres Date: Mon, 4 Aug 2025 17:23:00 +0200 Subject: [PATCH] Added camera uniforms for projection and view matrix --- assets/shaders/shader.vert | 13 ++++++--- src/ecs/entities.zig | 2 ++ src/main.zig | 4 +++ src/math.zig | 28 ++++++++++++-------- src/renderer/Camera.zig | 13 ++++----- src/renderer/Renderer.zig | 6 +++++ src/renderer/vulkan.zig | 54 ++++++++++++++++++++++++++++++++++---- 7 files changed, 92 insertions(+), 28 deletions(-) diff --git a/assets/shaders/shader.vert b/assets/shaders/shader.vert index 368d2e2..9b35d0c 100644 --- a/assets/shaders/shader.vert +++ b/assets/shaders/shader.vert @@ -2,11 +2,16 @@ layout(location = 0) in vec3 vertPos; -layout (binding = 0) uniform Uniform { +layout (binding = 0) uniform ProjUniform { mat4 proj; -} ubo; +} proj; + +layout (binding = 1) uniform ViewUniform { + mat4 view; +} view; void main() { - vec4 out_vec = ubo.proj * vec4(vertPos, 1.0); - gl_Position = vec4(out_vec.x, out_vec.y, 0.5, out_vec.w); + vec4 out_vec = proj.proj * view.view * vec4(vertPos, 1.0); + //vec4 out_vec = proj.proj * vec4(vertPos, 1.0); + gl_Position = vec4(out_vec.x, out_vec.y, out_vec.z, out_vec.w); } diff --git a/src/ecs/entities.zig b/src/ecs/entities.zig index d5ef236..a6fc6af 100644 --- a/src/ecs/entities.zig +++ b/src/ecs/entities.zig @@ -3,6 +3,7 @@ const Allocator = std.mem.Allocator; const components = @import("components.zig"); const sparse = @import("sparse.zig"); const Renderer = @import("renderer"); +const Camera = @import("renderer").Camera; const Input = @import("sideros").Input; const ecs = @import("ecs.zig"); @@ -11,6 +12,7 @@ pub const SystemGroup = []const System; pub const SyncGroup = []const System; pub const Resources = struct { + camera: Camera, renderer: Renderer, input: Input, delta_time: f64 = 0.0, diff --git a/src/main.zig b/src/main.zig index ec4367b..a810ba2 100644 --- a/src/main.zig +++ b/src/main.zig @@ -45,6 +45,10 @@ pub fn main() !void { //defer w.destroy(); const resources = ecs.Resources{ + .camera = .{ + .position = .{0.0, 0.0, 100}, + .target = .{0.0, 0.0, 0.0}, + }, .renderer = undefined, .input = .{ .key_pressed = .{false} ** @intFromEnum(Input.KeyCode.menu) }, }; diff --git a/src/math.zig b/src/math.zig index a2cbcd2..93854a0 100644 --- a/src/math.zig +++ b/src/math.zig @@ -8,15 +8,15 @@ pub const Matrix = struct { rows: [4]@Vector(4, f32), pub fn lookAt(eye: @Vector(3, f32), target: @Vector(3, f32), arbitrary_up: @Vector(3, f32)) Matrix { - const forward = normalize(eye - target); - const right = normalize(cross(arbitrary_up, forward)); - const up = cross(forward, right); + const forward = normalize(target - eye); + const right = normalize(cross(forward, arbitrary_up)); + const up = cross(right, forward); const view = [_]@Vector(4, f32){ - @Vector(4, f32){ right[0], right[1], right[2], 0.0 }, - @Vector(4, f32){ up[0], up[1], up[2], 0.0 }, - @Vector(4, f32){ forward[0], forward[1], forward[2], 0.0 }, - @Vector(4, f32){ 0.0, 0.0, 1.0, eye[2] }, + @Vector(4, f32){ right[0], up[0], -forward[0], 0.0 }, + @Vector(4, f32){ right[1], up[1], -forward[1], 0.0 }, + @Vector(4, f32){ right[2], up[2], -forward[2], 0.0 }, + @Vector(4, f32){ -dot(eye, right), -dot(eye, up), -dot(eye, forward), 1.0 }, }; return Matrix{ @@ -25,11 +25,17 @@ pub const Matrix = struct { } pub fn perspective(fov: f32, aspect: f32, near: f32, far: f32) Matrix { + const focal_length = 1.0 / tan(fov / 2.0); + const x = focal_length / aspect; + const y = -focal_length; + const a = near / (far - near); + const b = far * a; + const projection = [_]@Vector(4, f32){ - @Vector(4, f32){ 1.0 / (aspect * tan(fov / 2.0)), 0.0, 0.0, 0.0 }, - @Vector(4, f32){ 0.0, 1.0 / tan(fov / 2.0), 0.0, 0.0 }, - @Vector(4, f32){ 0.0, 0.0, -((far + near) / (far - near)), -((2 * far * near) / (far - near)) }, - @Vector(4, f32){ 0.0, 0.0, -1.0, 1.0 }, + @Vector(4, f32){ x, 0.0, 0.0, 0.0 }, + @Vector(4, f32){ 0.0, y, 0.0, 0.0 }, + @Vector(4, f32){ 0.0, 0.0, a, b }, + @Vector(4, f32){ 0.0, 0.0, 1.0, 0.0 }, }; return Matrix{ diff --git a/src/renderer/Camera.zig b/src/renderer/Camera.zig index 31620e8..b4c0cef 100644 --- a/src/renderer/Camera.zig +++ b/src/renderer/Camera.zig @@ -12,21 +12,18 @@ pub const Uniform = struct { model: math.Matrix, }; -uniform: Uniform, position: @Vector(3, f32), -target: @Vector(3, f32), -direction: @Vector(3, f32), -right: @Vector(3, f32), -front: @Vector(3, f32), -up: @Vector(3, f32), +target: @Vector(3, f32) = .{0.0, 0.0, 0.0}, +front: @Vector(3, f32) = .{0.0, 0.0, 1.0 }, +up: @Vector(3, f32) = .{0.0, 1.0, 0.0 }, speed: f32 = 2.5, pub fn getProjection(width: usize, height: usize) math.Matrix { - return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 10.0); + return math.Matrix.perspective(math.rad(45.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 100.0); } pub fn getView(self: Camera) math.Matrix { - math.lookAt(self.position, self.position + self.front, self.up); + return math.Matrix.lookAt(self.position, self.target, self.up); } pub fn moveCamera(pool: *ecs.Pool) void { diff --git a/src/renderer/Renderer.zig b/src/renderer/Renderer.zig index 14bfa89..c806a94 100644 --- a/src/renderer/Renderer.zig +++ b/src/renderer/Renderer.zig @@ -1,8 +1,10 @@ const c = @import("sideros").c; +const math = @import("sideros").math; const ecs = @import("ecs"); const std = @import("std"); const vk = @import("vulkan.zig"); pub const Mesh = @import("Mesh.zig"); +pub const Camera = @import("Camera.zig"); const Allocator = std.mem.Allocator; const Renderer = @This(); @@ -76,6 +78,10 @@ pub fn deinit(self: Renderer) void { // TODO: render is maybe a bad name? something like present() or submit() is better? pub fn render(pool: *ecs.Pool) anyerror!void { var renderer = pool.resources.renderer; + var camera = pool.resources.camera; + + const view_memory = renderer.graphics_pipeline.view_memory; + @memcpy(view_memory[0..@sizeOf(math.Matrix)], std.mem.asBytes(&camera.getView())); try renderer.device.waitFence(renderer.current_frame); const image = try renderer.swapchain.nextImage(renderer.device, renderer.current_frame); diff --git a/src/renderer/vulkan.zig b/src/renderer/vulkan.zig index 882c824..bb97d3c 100644 --- a/src/renderer/vulkan.zig +++ b/src/renderer/vulkan.zig @@ -304,6 +304,8 @@ pub fn GraphicsPipeline(comptime n: usize) type { descriptor_set: c.VkDescriptorSet, descriptor_set_layout: c.VkDescriptorSetLayout, projection_buffer: Buffer, + view_buffer: Buffer, + view_memory: [*c]u8, const Self = @This(); @@ -373,7 +375,8 @@ pub fn GraphicsPipeline(comptime n: usize) type { .rasterizerDiscardEnable = c.VK_FALSE, .polygonMode = c.VK_POLYGON_MODE_FILL, .lineWidth = 1.0, - .cullMode = c.VK_CULL_MODE_BACK_BIT, + //.cullMode = c.VK_CULL_MODE_BACK_BIT, + .cullMode = c.VK_CULL_MODE_NONE, .frontFace = c.VK_FRONT_FACE_COUNTER_CLOCKWISE, .depthBiasEnable = c.VK_FALSE, }; @@ -404,20 +407,27 @@ pub fn GraphicsPipeline(comptime n: usize) type { .blendConstants = .{ 0.0, 0.0, 0.0, 0.0 }, }; - const set_binding = c.VkDescriptorSetLayoutBinding{ + const projection_binding = c.VkDescriptorSetLayoutBinding{ .binding = 0, .descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorCount = 1, .stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT, }; - const bindings = [_]c.VkDescriptorSetLayoutBinding{set_binding}; + const view_binding = c.VkDescriptorSetLayoutBinding{ + .binding = 1, + .descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .descriptorCount = 1, + .stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT, + }; + + const bindings = [_]c.VkDescriptorSetLayoutBinding{projection_binding, view_binding}; var descriptor_set_layout: c.VkDescriptorSetLayout = undefined; const descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{ .sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = 1, + .bindingCount = 2, .pBindings = bindings[0..].ptr, }; @@ -462,7 +472,7 @@ pub fn GraphicsPipeline(comptime n: usize) type { var size = c.VkDescriptorPoolSize{ .type = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, + .descriptorCount = 2, }; const descriptor_pool_info = c.VkDescriptorPoolCreateInfo{ @@ -520,6 +530,38 @@ pub fn GraphicsPipeline(comptime n: usize) type { c.vkUpdateDescriptorSets(device.handle, 1, &write_descriptor_set, 0, null); + const view_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf(math.Matrix)); + + var view_data: [*c]u8 = undefined; + + try mapError(c.vkMapMemory( + device.handle, + view_buffer.memory, + 0, + view_buffer.size, + 0, + @ptrCast(&view_data), + )); + + + const view_descriptor_buffer_info = c.VkDescriptorBufferInfo{ + .buffer = view_buffer.handle, + .offset = 0, + .range = view_buffer.size, + }; + + const write_view_descriptor_set = c.VkWriteDescriptorSet{ + .sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + .dstSet = descriptor_set, + .dstBinding = 1, + .dstArrayElement = 0, + .descriptorCount = 1, + .descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + .pBufferInfo = &view_descriptor_buffer_info, + }; + + c.vkUpdateDescriptorSets(device.handle, 1, &write_view_descriptor_set, 0, null); + return Self{ .layout = layout, .handle = pipeline, @@ -527,6 +569,8 @@ pub fn GraphicsPipeline(comptime n: usize) type { .descriptor_set = descriptor_set, .descriptor_set_layout = descriptor_set_layout, .projection_buffer = projection_buffer, + .view_buffer = view_buffer, + .view_memory = view_data, }; }