Implemented transformations

This commit is contained in:
Lorenzo Torres 2025-08-06 15:32:32 +02:00
parent 00d51fc970
commit 6b948f6718
6 changed files with 250 additions and 30 deletions

View file

@ -12,13 +12,18 @@ layout (binding = 1) uniform ViewUniform {
mat4 view; mat4 view;
} view; } view;
layout (binding = 4) uniform TransformUniform {
mat4 translation;
mat4 scale;
} transform;
layout(location = 2) out vec3 Normal; layout(location = 2) out vec3 Normal;
layout(location = 3) out vec3 FragPos; layout(location = 3) out vec3 FragPos;
layout(location = 4) out vec2 TexCoords; layout(location = 4) out vec2 TexCoords;
void main() { void main() {
mat4 transformation = transform.translation * transform.scale;
vec4 out_vec = proj.proj * view.view * vec4(vertPos, 1.0); vec4 out_vec = proj.proj * view.view * vec4(vertPos, 1.0);
//vec4 out_vec = proj.proj * vec4(vertPos, 1.0);
FragPos = vec3(vec4(vertPos, 1.0)); FragPos = vec3(vec4(vertPos, 1.0));
Normal = normal; Normal = normal;
TexCoords = uv; TexCoords = uv;

View file

@ -3,23 +3,60 @@ pub const tan = std.math.tan;
pub const cos = std.math.cos; pub const cos = std.math.cos;
pub const sin = std.math.sin; pub const sin = std.math.sin;
pub const rad = std.math.degreesToRadians; pub const rad = std.math.degreesToRadians;
pub const sqrt = std.math.sqrt;
pub const Axis = struct {
pub const x: [3]f32 = .{1.0, 0.0, 0.0};
pub const y: [3]f32 = .{0.0, 1.0, 0.0};
pub const z: [3]f32 = .{0.0, 0.0, 1.0};
};
pub const Transform = struct {
translation: Matrix,
scale: Matrix,
rotation: Quaternion,
pub fn init(position: [3]f32, scale: [3]f32, rotation: [3]f32) Transform {
var translation = Matrix.identity();
translation.translate(position);
return .{
.translation = translation,
.rotation = Quaternion.fromEulerAngles(rotation),
.scale = Matrix.scale(scale),
};
}
pub fn translate(self: *Transform, delta: [3]f32) void {
self.translation.translate(delta);
}
pub fn rotate(self: *Transform, angle: f32, axis: [3]f32) void {
const delta = Quaternion.fromAxisAngle(axis, angle);
self.rotation = self.rotation.mul(delta);
self.rotation = self.rotation.normalize();
}
};
pub const Matrix = struct { pub const Matrix = struct {
rows: [4]@Vector(4, f32), rows: [4][4]f32,
pub fn lookAt(eye: @Vector(3, f32), target: @Vector(3, f32), arbitrary_up: @Vector(3, f32)) Matrix { pub fn lookAt(eye: [3]f32, target: [3]f32, arbitrary_up: [3]f32) Matrix {
const forward = normalize(target - eye); const t: @Vector(3, f32) = target;
const right = normalize(cross(forward, arbitrary_up)); const e: @Vector(3, f32) = eye;
const u: @Vector(3, f32) = arbitrary_up;
const forward = normalize(t - e);
const right = normalize(cross(forward, u));
const up = cross(right, forward); const up = cross(right, forward);
const view = [_]@Vector(4, f32){ const view = [4][4]f32{
@Vector(4, f32){ right[0], up[0], -forward[0], 0.0 }, [4]f32{ right[0], up[0], -forward[0], 0.0 },
@Vector(4, f32){ right[1], up[1], -forward[1], 0.0 }, [4]f32{ right[1], up[1], -forward[1], 0.0 },
@Vector(4, f32){ right[2], up[2], -forward[2], 0.0 }, [4]f32{ right[2], up[2], -forward[2], 0.0 },
@Vector(4, f32){ -dot(eye, right), -dot(eye, up), -dot(eye, forward), 1.0 }, [4]f32{ -dot(e, right), -dot(e, up), -dot(e, forward), 1.0 },
}; };
return Matrix{ return .{
.rows = view, .rows = view,
}; };
} }
@ -31,28 +68,161 @@ pub const Matrix = struct {
const a = near / (far - near); const a = near / (far - near);
const b = far * a; const b = far * a;
const projection = [_]@Vector(4, f32){ const projection = [4][4]f32{
@Vector(4, f32){ x, 0.0, 0.0, 0.0 }, [4]f32{ x, 0.0, 0.0, 0.0 },
@Vector(4, f32){ 0.0, y, 0.0, 0.0 }, [4]f32{ 0.0, y, 0.0, 0.0 },
@Vector(4, f32){ 0.0, 0.0, a, b }, [4]f32{ 0.0, 0.0, a, b },
@Vector(4, f32){ 0.0, 0.0, 1.0, 0.0 }, [4]f32{ 0.0, 0.0, 1.0, 0.0 },
}; };
return Matrix{ return .{
.rows = projection, .rows = projection,
}; };
} }
pub fn identity() Matrix { pub inline fn identity() Matrix {
const view = [_]@Vector(4, f32){ return .{
@Vector(4, f32){ 1.0, 0.0, 0.0, 0.0 }, .rows = .{
@Vector(4, f32){ 0.0, 1.0, 0.0, 0.0 }, [4]f32{ 1.0, 0.0, 0.0, 0.0 },
@Vector(4, f32){ 0.0, 0.0, 1.0, 0.0 }, [4]f32{ 0.0, 1.0, 0.0, 0.0 },
@Vector(4, f32){ 0.0, 0.0, 0.0, 1.0 }, [4]f32{ 0.0, 0.0, 1.0, 0.0 },
[4]f32{ 0.0, 0.0, 0.0, 1.0 },
},
};
}
pub fn mul(a: Matrix, b: Matrix) Matrix {
var result = [4][4]f32{
[4]f32{ 0.0, 0.0, 0.0, 0.0 },
[4]f32{ 0.0, 0.0, 0.0, 0.0 },
[4]f32{ 0.0, 0.0, 0.0, 0.0 },
[4]f32{ 0.0, 0.0, 0.0, 0.0 },
}; };
return Matrix{ for (0..4) |i| {
.rows = view, for (0..4) |j| {
for (0..4) |k| {
result[i][j] += a.rows[i][k] * b.rows[k][j];
}
}
}
return .{
.rows = result,
};
}
pub inline fn translate(a: *Matrix, pos: [3]f32) void {
a.rows[3][0] += pos[0];
a.rows[3][1] += pos[1];
a.rows[3][2] += pos[2];
}
pub inline fn scale(s: [3]f32) Matrix {
return .{
.rows = [4][4]f32{
[4]f32{ s[0], 0.0, 0.0, 0.0 },
[4]f32{ 0.0, s[1], 0.0, 0.0 },
[4]f32{ 0.0, 0.0, s[2], 0.0 },
[4]f32{ 0.0, 0.0, 0.0, 1.0 },
},
};
}
pub fn transform(pos: [3]f32, s: [3]f32) Matrix {
var translation = Matrix.identity();
translation.translate(pos);
return translation.mul(Matrix.scale(s));
}
};
const Quaternion = struct {
w: f32,
x: f32,
y: f32,
z: f32,
pub const identity: Quaternion = .{ .w = 1.0, .x = 0.0, .y = 0.0, .z = 0.0 };
pub fn fromAxisAngle(axis: [3]f32, angle: f32) Quaternion {
const half_angle = angle / 2.0;
const s = sin(half_angle);
return .{
.w = cos(half_angle),
.x = axis[0] * s,
.y = axis[1] * s,
.z = axis[3] * s,
};
}
fn fromEulerAngles(rotation: [3]f32) Quaternion {
const pitch = rotation[0];
const yaw = rotation[1];
const roll = rotation[2];
const half_pitch = pitch / 2.0;
const half_yaw = yaw / 2.0;
const half_roll = roll / 2.0;
const sin_pitch = sin(half_pitch);
const cos_pitch = cos(half_pitch);
const sin_yaw = sin(half_yaw);
const cos_yaw = cos(half_yaw);
const sin_roll = sin(half_roll);
const cos_roll = cos(half_roll);
return .{
.w = cos_yaw * cos_pitch * cos_roll + sin_yaw * sin_pitch * sin_roll,
.x = cos_yaw * sin_pitch * cos_roll + sin_yaw * cos_pitch * sin_roll,
.y = sin_yaw * cos_pitch * cos_roll - cos_yaw * sin_pitch * sin_roll,
.z = cos_yaw * cos_pitch * sin_roll - sin_yaw * sin_pitch * cos_roll,
};
}
inline fn mul(a: Quaternion, b: Quaternion) Quaternion {
return .{
.w = a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,
.x = a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,
.y = a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,
.z = a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,
};
}
fn normalize(q: Quaternion) Quaternion {
const mag = sqrt(q.w*q.w + q.x*q.x + q.y*q.y + q.z*q.z);
return Quaternion{
.w = q.w / mag,
.x = q.x / mag,
.y = q.y / mag,
.z = q.z / mag,
};
}
fn matrix(q: Quaternion) Matrix {
const x2 = q.x + q.x;
const y2 = q.y + q.y;
const z2 = q.z + q.z;
const xx = q.x * x2;
const yy = q.y * y2;
const zz = q.z * z2;
const xy = q.x * y2;
const xz = q.x * z2;
const yz = q.y * z2;
const wx = q.w * x2;
const wy = q.w * y2;
const wz = q.w * z2;
return .{
.rows = .{
.{ 1.0 - (yy + zz), xy - wz, xz + wy, 0.0 },
.{ xy + wz, 1.0 - (xx + zz), yz - wx, 0.0 },
.{ xz - wy, yz + wx, 1.0 - (xx + yy), 0.0 },
.{ 0.0, 0.0, 0.0, 1.0 },
}
}; };
} }
}; };

View file

@ -18,7 +18,7 @@ up: @Vector(3, f32) = .{ 0.0, 1.0, 0.0 },
speed: f32 = 2.5, speed: f32 = 2.5,
pub fn getProjection(width: usize, height: usize) math.Matrix { 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, 100.0); return math.Matrix.perspective(math.rad(40.0), (@as(f32, @floatFromInt(width)) / @as(f32, @floatFromInt(height))), 0.1, 100.0);
} }
pub fn getView(self: Camera) math.Matrix { pub fn getView(self: Camera) math.Matrix {

View file

@ -19,6 +19,7 @@ graphics_pipeline: vk.GraphicsPipeline(2),
current_frame: u32, current_frame: u32,
vertex_buffer: vk.Buffer, vertex_buffer: vk.Buffer,
index_buffer: vk.Buffer, index_buffer: vk.Buffer,
transform: math.Transform,
pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Renderer { pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_handle: vk.c.VkSurfaceKHR) !Renderer {
const instance: vk.Instance = .{ .handle = instance_handle }; const instance: vk.Instance = .{ .handle = instance_handle };
@ -67,6 +68,7 @@ pub fn init(allocator: Allocator, instance_handle: vk.c.VkInstance, surface_hand
// TODO: Why are we storing the buffer and not the Mesh? // TODO: Why are we storing the buffer and not the Mesh?
.vertex_buffer = triangle.vertex_buffer, .vertex_buffer = triangle.vertex_buffer,
.index_buffer = triangle.index_buffer, .index_buffer = triangle.index_buffer,
.transform = math.Transform.init(.{0.0, 0.0, 0.0}, .{1.0, 1.0, 1.0}, .{0.0, 0.0, 0.0}),
}; };
} }
@ -94,6 +96,9 @@ pub fn render(pool: *ecs.Pool) anyerror!void {
view_pos[1] = camera.position[1]; view_pos[1] = camera.position[1];
view_pos[2] = camera.position[2]; view_pos[2] = camera.position[2];
const transform_memory = renderer.graphics_pipeline.transform_memory;
@memcpy(transform_memory[0..@sizeOf(math.Transform)], std.mem.asBytes(&renderer.transform));
try renderer.device.waitFence(renderer.current_frame); try renderer.device.waitFence(renderer.current_frame);
const image = try renderer.swapchain.nextImage(renderer.device, renderer.current_frame); const image = try renderer.swapchain.nextImage(renderer.device, renderer.current_frame);
try renderer.device.resetCommand(renderer.current_frame); try renderer.device.resetCommand(renderer.current_frame);

View file

@ -237,6 +237,7 @@ pub fn GraphicsPipeline(comptime n: usize) type {
light_buffer: Buffer, light_buffer: Buffer,
view_buffer: Buffer, view_buffer: Buffer,
view_memory: [*c]u8, view_memory: [*c]u8,
transform_memory: [*c]u8,
view_pos_memory: [*c]u8, view_pos_memory: [*c]u8,
texture_sampler: Sampler, texture_sampler: Sampler,
diffuse_sampler: Sampler, diffuse_sampler: Sampler,
@ -356,6 +357,13 @@ pub fn GraphicsPipeline(comptime n: usize) type {
.stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT, .stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT,
}; };
const transform_binding = c.VkDescriptorSetLayoutBinding{
.binding = 4,
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 1,
.stageFlags = c.VK_SHADER_STAGE_VERTEX_BIT,
};
const light_binding = c.VkDescriptorSetLayoutBinding{ const light_binding = c.VkDescriptorSetLayoutBinding{
.binding = 2, .binding = 2,
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
@ -384,7 +392,7 @@ pub fn GraphicsPipeline(comptime n: usize) type {
.stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT, .stageFlags = c.VK_SHADER_STAGE_FRAGMENT_BIT,
}; };
const bindings = [_]c.VkDescriptorSetLayoutBinding{projection_binding, view_binding, light_binding, view_pos_binding}; const bindings = [_]c.VkDescriptorSetLayoutBinding{projection_binding, view_binding, transform_binding, light_binding, view_pos_binding};
const texture_bindings = [_]c.VkDescriptorSetLayoutBinding{texture_sampler_binding, diffuse_sampler_binding}; const texture_bindings = [_]c.VkDescriptorSetLayoutBinding{texture_sampler_binding, diffuse_sampler_binding};
var descriptor_set_layout: c.VkDescriptorSetLayout = undefined; var descriptor_set_layout: c.VkDescriptorSetLayout = undefined;
@ -392,7 +400,7 @@ pub fn GraphicsPipeline(comptime n: usize) type {
const descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{ const descriptor_set_layout_info = c.VkDescriptorSetLayoutCreateInfo{
.sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, .sType = c.VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = 4, .bindingCount = 5,
.pBindings = bindings[0..].ptr, .pBindings = bindings[0..].ptr,
}; };
@ -444,7 +452,7 @@ pub fn GraphicsPipeline(comptime n: usize) type {
const size = c.VkDescriptorPoolSize{ const size = c.VkDescriptorPoolSize{
.type = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, .type = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.descriptorCount = 4, .descriptorCount = 5,
}; };
const sampler_size = c.VkDescriptorPoolSize{ const sampler_size = c.VkDescriptorPoolSize{
@ -540,6 +548,37 @@ pub fn GraphicsPipeline(comptime n: usize) type {
c.vkUpdateDescriptorSets(device.handle, 1, &write_view_descriptor_set, 0, null); c.vkUpdateDescriptorSets(device.handle, 1, &write_view_descriptor_set, 0, null);
const transform_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf(math.Transform));
var transform_data: [*c]u8 = undefined;
try mapError(c.vkMapMemory(
device.handle,
transform_buffer.memory,
0,
transform_buffer.size,
0,
@ptrCast(&transform_data),
));
const transform_descriptor_buffer_info = c.VkDescriptorBufferInfo{
.buffer = transform_buffer.handle,
.offset = 0,
.range = transform_buffer.size,
};
const write_transform_descriptor_set = c.VkWriteDescriptorSet{
.sType = c.VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET,
.dstSet = descriptor_set,
.dstBinding = 4,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = c.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
.pBufferInfo = &transform_descriptor_buffer_info,
};
c.vkUpdateDescriptorSets(device.handle, 1, &write_transform_descriptor_set, 0, null);
const light_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf([3]f32)); const light_buffer = try device.createBuffer(BufferUsage{ .uniform_buffer = true, .transfer_dst = true }, BufferFlags{ .device_local = true }, @sizeOf([3]f32));
var light_data: [*c]u8 = undefined; var light_data: [*c]u8 = undefined;
@ -616,6 +655,7 @@ pub fn GraphicsPipeline(comptime n: usize) type {
.view_memory = view_data, .view_memory = view_data,
.light_buffer = light_buffer, .light_buffer = light_buffer,
.view_pos_memory = view_pos_data, .view_pos_memory = view_pos_data,
.transform_memory = transform_data,
.texture_sampler = try Sampler.init(device), .texture_sampler = try Sampler.init(device),
.diffuse_sampler = try Sampler.init(device), .diffuse_sampler = try Sampler.init(device),
.textures = std.ArrayList(c.VkDescriptorSet).init(allocator), .textures = std.ArrayList(c.VkDescriptorSet).init(allocator),

View file

@ -15,7 +15,7 @@ var renderer: Renderer = undefined;
export fn sideros_init(init: api.GameInit) callconv(.c) void { export fn sideros_init(init: api.GameInit) callconv(.c) void {
pool = ecs.Pool.init(allocator, .{ pool = ecs.Pool.init(allocator, .{
.camera = .{ .camera = .{
.position = .{ 30.0, 30.0, 30.0 }, .position = .{ 0.0, 0.0, 40.0 },
.target = .{ 0.0, 0.0, 0.0 }, .target = .{ 0.0, 0.0, 0.0 },
}, },
.renderer = undefined, .renderer = undefined,