Quaternion rotation!
This commit is contained in:
@@ -7,8 +7,8 @@ layout(location = 0) out vec4 fragColor;
|
|||||||
void main() {
|
void main() {
|
||||||
fragColor = vec4(
|
fragColor = vec4(
|
||||||
depth,
|
depth,
|
||||||
0.0,
|
cos(vertexIndex * 0.5) * 0.25 + 0.75,
|
||||||
0.0,
|
sin(vertexIndex * 0.5) * 0.25 + 0.75,
|
||||||
1.0
|
1.0
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
13
src/game.zig
13
src/game.zig
@@ -80,9 +80,20 @@ fn processEvents(graphics: *Graphics, run_info: *RunInfo) GameError!void {
|
|||||||
run_info.running = false;
|
run_info.running = false;
|
||||||
},
|
},
|
||||||
sdl.EVENT_WINDOW_RESIZED => {
|
sdl.EVENT_WINDOW_RESIZED => {
|
||||||
if (event.window.windowID != sdl.GetWindowID(graphics.window)) return;
|
if (event.window.windowID != sdl.GetWindowID(graphics.window)) continue;
|
||||||
graphics.resize(@intCast(event.window.data1), @intCast(event.window.data2));
|
graphics.resize(@intCast(event.window.data1), @intCast(event.window.data2));
|
||||||
},
|
},
|
||||||
|
sdl.EVENT_MOUSE_MOTION => {
|
||||||
|
if (event.motion.windowID != sdl.GetWindowID(graphics.window)) continue;
|
||||||
|
if (@abs(event.motion.xrel) < 0.01 and @abs(event.motion.yrel) < 0.01) continue;
|
||||||
|
const Transform = @import("graphics/transform.zig");
|
||||||
|
const delta, const length = Transform.extractNormal(.{ -event.motion.yrel, -event.motion.xrel, 0.0 });
|
||||||
|
const rot = Transform.rotationByAxis(
|
||||||
|
delta,
|
||||||
|
length * std.math.pi / @as(f32, @floatFromInt(graphics.window_size[1])) * 2.0,
|
||||||
|
);
|
||||||
|
graphics.mesh_transform.rotate(rot);
|
||||||
|
},
|
||||||
else => {},
|
else => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -19,23 +19,52 @@ depth_texture: *sdl.GPUTexture,
|
|||||||
msaa_resolve: *sdl.GPUTexture,
|
msaa_resolve: *sdl.GPUTexture,
|
||||||
pipeline: *sdl.GPUGraphicsPipeline,
|
pipeline: *sdl.GPUGraphicsPipeline,
|
||||||
|
|
||||||
to_resize: ?struct { u32, u32 } = null,
|
window_size: [2]u32,
|
||||||
|
|
||||||
|
camera: Camera,
|
||||||
|
mesh_transform: Transform,
|
||||||
|
|
||||||
|
to_resize: ?[2]u32 = null,
|
||||||
|
|
||||||
const MESH_BYTES = MESH.len * 4;
|
const MESH_BYTES = MESH.len * 4;
|
||||||
const MESH_VERTS = @divExact(MESH.len, 3);
|
const MESH_VERTS = @divExact(MESH.len, 3);
|
||||||
const MESH = [_]f32{
|
const MESH = [_]f32{
|
||||||
-1, 0, 4,
|
-1, 1, -1,
|
||||||
0, 1, 4,
|
1, 1, -1,
|
||||||
1, -1, 6,
|
-1, -1, -1,
|
||||||
1, 0, 4,
|
1, -1, -1,
|
||||||
0, -1, 4,
|
-1, -1, -1,
|
||||||
-1, 1, 6,
|
1, 1, -1,
|
||||||
-1, 1, 6,
|
1, 1, -1,
|
||||||
1, 1, 6,
|
1, 1, 1,
|
||||||
-1, -1, 6,
|
1, -1, -1,
|
||||||
1, -1, 6,
|
1, -1, 1,
|
||||||
-1, -1, 6,
|
1, -1, -1,
|
||||||
1, 1, 6,
|
1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
-1, 1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
-1, -1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
-1, 1, 1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, -1,
|
||||||
|
-1, 1, -1,
|
||||||
|
1, 1, 1,
|
||||||
|
-1, -1, -1,
|
||||||
|
1, -1, -1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, 1,
|
||||||
|
-1, -1, 1,
|
||||||
|
1, -1, -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
const Self = @This();
|
const Self = @This();
|
||||||
@@ -189,6 +218,16 @@ pub fn create() GameError!Self {
|
|||||||
.depth_texture = depth_texture,
|
.depth_texture = depth_texture,
|
||||||
.msaa_resolve = msaa_resolve,
|
.msaa_resolve = msaa_resolve,
|
||||||
.pipeline = pipeline,
|
.pipeline = pipeline,
|
||||||
|
.window_size = .{ 1600, 900 },
|
||||||
|
.camera = Camera{
|
||||||
|
.transform = Transform{
|
||||||
|
.position = .{ 0.0, 0.0, -6.0 },
|
||||||
|
},
|
||||||
|
.near = 1.0,
|
||||||
|
.far = 1024.0,
|
||||||
|
.lens = .{ 0.5 * 16.0 / 9.0, 0.5 },
|
||||||
|
},
|
||||||
|
.mesh_transform = Transform{},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,6 +255,8 @@ pub fn beginDraw(self: *Self) GameError!void {
|
|||||||
self.command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
self.command_buffer = sdl.AcquireGPUCommandBuffer(self.device) orelse return GameError.SdlError;
|
||||||
if (self.to_resize) |new_size| {
|
if (self.to_resize) |new_size| {
|
||||||
try self.resetTextures(new_size[0], new_size[1]);
|
try self.resetTextures(new_size[0], new_size[1]);
|
||||||
|
self.camera.lens[0] = self.camera.lens[1] * @as(f32, @floatFromInt(new_size[0])) / @as(f32, @floatFromInt(new_size[1]));
|
||||||
|
self.window_size = new_size;
|
||||||
self.to_resize = null;
|
self.to_resize = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +270,7 @@ pub fn drawDebug(self: *Self) GameError!void {
|
|||||||
if (render_target == null) return;
|
if (render_target == null) return;
|
||||||
|
|
||||||
const render_pass = sdl.BeginGPURenderPass(self.command_buffer, &.{
|
const render_pass = sdl.BeginGPURenderPass(self.command_buffer, &.{
|
||||||
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 1.0, .a = 1.0 },
|
.clear_color = .{ .r = 0.0, .g = 0.0, .b = 0.0, .a = 1.0 },
|
||||||
.cycle = false,
|
.cycle = false,
|
||||||
.load_op = sdl.GPU_LOADOP_CLEAR,
|
.load_op = sdl.GPU_LOADOP_CLEAR,
|
||||||
.store_op = sdl.GPU_STOREOP_RESOLVE,
|
.store_op = sdl.GPU_STOREOP_RESOLVE,
|
||||||
@@ -248,17 +289,8 @@ pub fn drawDebug(self: *Self) GameError!void {
|
|||||||
|
|
||||||
sdl.BindGPUGraphicsPipeline(render_pass, self.pipeline);
|
sdl.BindGPUGraphicsPipeline(render_pass, self.pipeline);
|
||||||
sdl.BindGPUVertexBuffers(render_pass, 0, &.{ .offset = 0, .buffer = self.vertex_buffer }, 1);
|
sdl.BindGPUVertexBuffers(render_pass, 0, &.{ .offset = 0, .buffer = self.vertex_buffer }, 1);
|
||||||
const transform = Transform{};
|
sdl.PushGPUVertexUniformData(self.command_buffer, 0, &self.camera.matrix(), 16 * 4);
|
||||||
const camera = Camera{
|
sdl.PushGPUVertexUniformData(self.command_buffer, 1, &self.mesh_transform.matrix(), 16 * 4);
|
||||||
.transform = Transform{
|
|
||||||
.position = .{ 0.0, 0.0, -1.0 },
|
|
||||||
},
|
|
||||||
.near = 1.0,
|
|
||||||
.far = 1024.0,
|
|
||||||
.lens = .{ 0.25 * 16.0 / 9.0, 0.25 },
|
|
||||||
};
|
|
||||||
sdl.PushGPUVertexUniformData(self.command_buffer, 0, &camera.matrix(), 16 * 4);
|
|
||||||
sdl.PushGPUVertexUniformData(self.command_buffer, 1, &transform.matrix(), 16 * 4);
|
|
||||||
sdl.DrawGPUPrimitives(render_pass, MESH_VERTS, 1, 0, 0);
|
sdl.DrawGPUPrimitives(render_pass, MESH_VERTS, 1, 0, 0);
|
||||||
|
|
||||||
sdl.EndGPURenderPass(render_pass);
|
sdl.EndGPURenderPass(render_pass);
|
||||||
|
@@ -1,47 +1,124 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const Transform = @This();
|
const Transform = @This();
|
||||||
|
|
||||||
// TODO: Rotation
|
// TODO: Scale
|
||||||
|
|
||||||
position: @Vector(3, f32) = @splat(0.0),
|
pub const TMatrix = @Vector(16, f32);
|
||||||
rotation: @Vector(3, f32) = @splat(0.0),
|
|
||||||
scale: @Vector(3, f32) = @splat(1.0),
|
|
||||||
|
|
||||||
pub fn matrix(transform: Transform) @Vector(16, f32) {
|
pub const Position = @Vector(3, f32);
|
||||||
|
pub const Rotation = @Vector(4, f32);
|
||||||
|
pub const Scale = @Vector(3, f32);
|
||||||
|
|
||||||
|
position: Position = @splat(0.0),
|
||||||
|
rotation: Rotation = .{ 1.0, 0.0, 0.0, 0.0 },
|
||||||
|
scale: Scale = @splat(1.0),
|
||||||
|
|
||||||
|
pub fn matrix(transform: Transform) TMatrix {
|
||||||
|
const r = rotationMatrix(transform.rotation);
|
||||||
return .{
|
return .{
|
||||||
1.0, 0.0, 0.0, transform.position[0],
|
r[0], r[1], r[2], transform.position[0],
|
||||||
0.0, 1.0, 0.0, transform.position[1],
|
r[3], r[4], r[5], transform.position[1],
|
||||||
0.0, 0.0, 1.0, transform.position[2],
|
r[6], r[7], r[8], transform.position[2],
|
||||||
0.0, 0.0, 0.0, 1.0,
|
0.0, 0.0, 0.0, 1.0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn inverse(transform: Transform) @Vector(16, f32) {
|
pub fn inverse(transform: Transform) TMatrix {
|
||||||
// TODO: Could we just translate, rotate and scale back instead of relying on matrix math?
|
// TODO: Could we just translate, rotate and scale back instead of relying on matrix math?
|
||||||
return invertMatrix(transform.matrix());
|
return invertMatrix(transform.matrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invertMatrix(a: @Vector(16, f32)) @Vector(16, f32) {
|
pub fn rotate(transform: *Transform, rotation: Rotation) void {
|
||||||
|
transform.rotation = normalizeRotation(combineRotations(transform.rotation, rotation));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn normalizeRotation(r: Rotation) Rotation {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
const length = @sqrt(r[0] * r[0] + r[1] * r[1] + r[2] * r[2] + r[3] * r[3]);
|
||||||
|
return r / @as(Rotation, @splat(length));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn combineRotations(a: Rotation, b: Rotation) Rotation {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
return .{
|
||||||
|
a[0] * b[0] - a[1] * b[1] - a[2] * b[2] - a[3] * b[3],
|
||||||
|
a[1] * b[0] + a[0] * b[1] + a[3] * b[2] - a[2] * b[3],
|
||||||
|
a[2] * b[0] + a[0] * b[2] + a[1] * b[3] - a[3] * b[1],
|
||||||
|
a[3] * b[0] + a[0] * b[3] + a[2] * b[1] - a[1] * b[2],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rotationByAxis(axis: Position, rotation: f32) Rotation {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
const cos = std.math.cos(rotation * 0.5);
|
||||||
|
const sin = std.math.sin(rotation * 0.5);
|
||||||
|
|
||||||
|
return .{ cos, sin * axis[0], sin * axis[1], sin * axis[2] };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extractNormal(vector: Position) struct { Position, f32 } {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
const length = vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2];
|
||||||
|
return .{ vector / @as(Position, @splat(length)), length };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn rotationMatrix(quaternion: Rotation) @Vector(9, f32) {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
const a = quaternion[0];
|
||||||
|
const b = quaternion[1];
|
||||||
|
const c = quaternion[2];
|
||||||
|
const d = quaternion[3];
|
||||||
|
|
||||||
|
const s = 2.0 / (a * a + b * b + c * c + d * d);
|
||||||
|
const bs = b * s;
|
||||||
|
const cs = c * s;
|
||||||
|
const ds = d * s;
|
||||||
|
|
||||||
|
const ab = a * bs;
|
||||||
|
const ac = a * cs;
|
||||||
|
const ad = a * ds;
|
||||||
|
const bb = b * bs;
|
||||||
|
const bc = b * cs;
|
||||||
|
const bd = b * ds;
|
||||||
|
const cc = c * cs;
|
||||||
|
const cd = c * ds;
|
||||||
|
const dd = d * ds;
|
||||||
|
|
||||||
|
return .{
|
||||||
|
1 - cc - dd, bc - ad, bd + ac,
|
||||||
|
bc + ad, 1 - bb - dd, cd - ab,
|
||||||
|
bd - ac, cd + ab, 1 - bb - cc,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invertMatrix(a: TMatrix) TMatrix {
|
||||||
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
const MOD: f32 = 1.0 / 16.0;
|
const MOD: f32 = 1.0 / 16.0;
|
||||||
const ID = @Vector(16, f32){
|
const ID = TMatrix{
|
||||||
1, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, 1, 0, 0,
|
0, 1, 0, 0,
|
||||||
0, 0, 1, 0,
|
0, 0, 1, 0,
|
||||||
0, 0, 0, 1,
|
0, 0, 0, 1,
|
||||||
};
|
};
|
||||||
var p = ID - @as(@Vector(16, f32), @splat(MOD)) * a;
|
var p = ID - @as(TMatrix, @splat(MOD)) * a;
|
||||||
var output = ID + p;
|
var output = ID + p;
|
||||||
inline for (0..8) |_| {
|
inline for (0..8) |_| {
|
||||||
p = multiplyMatrix(p, p);
|
p = multiplyMatrix(p, p);
|
||||||
output = multiplyMatrix(output, ID + p);
|
output = multiplyMatrix(output, ID + p);
|
||||||
}
|
}
|
||||||
return output * @as(@Vector(16, f32), @splat(MOD));
|
return output * @as(TMatrix, @splat(MOD));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn multiplyMatrix(a: @Vector(16, f32), b: @Vector(16, f32)) @Vector(16, f32) {
|
pub fn multiplyMatrix(a: TMatrix, b: TMatrix) TMatrix {
|
||||||
var output: @Vector(16, f32) = [1]f32{0.0} ** 16;
|
|
||||||
|
|
||||||
@setFloatMode(.optimized);
|
@setFloatMode(.optimized);
|
||||||
|
|
||||||
|
var output: TMatrix = [1]f32{0.0} ** 16;
|
||||||
for (0..4) |row| {
|
for (0..4) |row| {
|
||||||
for (0..4) |col| {
|
for (0..4) |col| {
|
||||||
for (0..4) |i| {
|
for (0..4) |i| {
|
||||||
|
Reference in New Issue
Block a user